diff --git a/assets/pasted-20260204-135454-c72e44de.png b/assets/pasted-20260204-135454-c72e44de.png new file mode 100644 index 0000000..1aa3dfd Binary files /dev/null and b/assets/pasted-20260204-135454-c72e44de.png differ diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index fa65535..eae1cef 100644 Binary files a/config/__pycache__/settings.cpython-311.pyc and b/config/__pycache__/settings.cpython-311.pyc differ diff --git a/config/settings.py b/config/settings.py index 7c015e4..6d4fdfd 100644 --- a/config/settings.py +++ b/config/settings.py @@ -138,7 +138,7 @@ AUTH_PASSWORD_VALIDATORS = [ # Internationalization # https://docs.djangoproject.com/en/5.2/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = 'ar' TIME_ZONE = 'UTC' @@ -307,4 +307,4 @@ JAZZMIN_SETTINGS = { "use_google_fonts_cdn": True, # Whether to show the UI customizer on the sidebar "show_ui_builder": True, -} +} \ No newline at end of file diff --git a/core/__pycache__/admin.cpython-311.pyc b/core/__pycache__/admin.cpython-311.pyc index f34b19d..066022d 100644 Binary files a/core/__pycache__/admin.cpython-311.pyc and b/core/__pycache__/admin.cpython-311.pyc differ diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc index 7abaee6..0327d5e 100644 Binary files a/core/__pycache__/forms.cpython-311.pyc and b/core/__pycache__/forms.cpython-311.pyc differ diff --git a/core/__pycache__/models.cpython-311.pyc b/core/__pycache__/models.cpython-311.pyc index ebebf1c..258e187 100644 Binary files a/core/__pycache__/models.cpython-311.pyc and b/core/__pycache__/models.cpython-311.pyc differ diff --git a/core/__pycache__/urls.cpython-311.pyc b/core/__pycache__/urls.cpython-311.pyc index 2cb7086..02ad606 100644 Binary files a/core/__pycache__/urls.cpython-311.pyc and b/core/__pycache__/urls.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index bd12b3a..ded796e 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ diff --git a/core/admin.py b/core/admin.py index 7e25da6..df378f7 100644 --- a/core/admin.py +++ b/core/admin.py @@ -17,13 +17,13 @@ class ActionsModelAdmin(admin.ModelAdmin): return format_html( '
' - '' - '' + '' + '' '
', edit_url, delete_url ) - actions_column.short_description = 'Actions' + actions_column.short_description = 'إجراءات' @admin.register(Classroom) class ClassroomAdmin(ActionsModelAdmin): @@ -42,7 +42,7 @@ class SubjectAdmin(ActionsModelAdmin): def get_teachers(self, obj): return ", ".join([str(t) for t in obj.teachers.all()]) - get_teachers.short_description = 'Teachers' + get_teachers.short_description = 'المعلمون' @admin.register(City) class CityAdmin(ActionsModelAdmin): @@ -57,7 +57,7 @@ class ResourceAdminForm(forms.ModelForm): classroom = forms.ModelChoiceField( queryset=Classroom.objects.all(), required=True, - label="Filter by Classroom" + label="تصفية حسب الصف" ) class Meta: @@ -92,4 +92,4 @@ class StudentAdmin(ActionsModelAdmin): form = super().get_form(request, obj, **kwargs) if obj and obj.classroom: form.base_fields['subscribed_subjects'].queryset = Subject.objects.filter(classroom=obj.classroom) - return form \ No newline at end of file + return form diff --git a/core/forms.py b/core/forms.py index 813bec2..4b0fc9f 100644 --- a/core/forms.py +++ b/core/forms.py @@ -1,25 +1,31 @@ from django import forms from django.contrib.auth.models import User -from .models import Student, Subject, Classroom, City, Governorate +from .models import Student, Subject, Classroom, City, Governorate, Teacher, Resource class StudentRegistrationForm(forms.ModelForm): - full_name = forms.CharField(max_length=150, required=True, label="Full Name") - username = forms.CharField(max_length=150, required=True) - email = forms.EmailField(required=True) - password = forms.CharField(widget=forms.PasswordInput, required=True) - password_confirm = forms.CharField(widget=forms.PasswordInput, required=True, label="Confirm Password") + full_name = forms.CharField(max_length=150, required=True, label="الاسم الكامل") + username = forms.CharField(max_length=150, required=True, label="اسم المستخدم") + email = forms.EmailField(required=True, label="البريد الإلكتروني") + password = forms.CharField(widget=forms.PasswordInput, required=True, label="كلمة المرور") + password_confirm = forms.CharField(widget=forms.PasswordInput, required=True, label="تأكيد كلمة المرور") - classroom = forms.ModelChoiceField(queryset=Classroom.objects.all(), required=True, empty_label="Select Classroom") + classroom = forms.ModelChoiceField(queryset=Classroom.objects.all(), required=True, empty_label="اختر الصف", label="الصف الدراسي") subjects = forms.ModelMultipleChoiceField( queryset=Subject.objects.all(), required=False, widget=forms.CheckboxSelectMultiple, - label="Select Subjects" + label="اختر المواد" ) class Meta: model = Student fields = ['mobile_number', 'governorate', 'city', 'avatar'] + labels = { + 'mobile_number': 'رقم الهاتف', + 'governorate': 'المحافظة', + 'city': 'المدينة', + 'avatar': 'الصورة الشخصية' + } widgets = { 'avatar': forms.FileInput(attrs={'accept': 'image/*', 'capture': 'camera'}), } @@ -65,7 +71,7 @@ class StudentRegistrationForm(forms.ModelForm): password_confirm = cleaned_data.get("password_confirm") if password and password_confirm and password != password_confirm: - self.add_error('password_confirm', "Passwords do not match") + self.add_error('password_confirm', "كلمات المرور غير متطابقة") return cleaned_data @@ -91,4 +97,59 @@ class StudentRegistrationForm(forms.ModelForm): if commit: student.save() student.subscribed_subjects.set(self.cleaned_data['subjects']) - return student \ No newline at end of file + return student + +class TeacherProfileForm(forms.ModelForm): + first_name = forms.CharField(max_length=30, required=True, label="الاسم الأول") + last_name = forms.CharField(max_length=150, required=True, label="الاسم الأخير") + email = forms.EmailField(required=True, label="البريد الإلكتروني") + + class Meta: + model = Teacher + fields = ['bio', 'specialization', 'avatar'] + labels = { + 'bio': 'نبذة عني', + 'specialization': 'التخصص', + 'avatar': 'الصورة الشخصية' + } + widgets = { + 'bio': forms.Textarea(attrs={'rows': 4}), + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + if self.instance and self.instance.user: + self.fields['first_name'].initial = self.instance.user.first_name + self.fields['last_name'].initial = self.instance.user.last_name + self.fields['email'].initial = self.instance.user.email + + for field_name, field in self.fields.items(): + field.widget.attrs['class'] = 'form-control' + + def save(self, commit=True): + teacher = super().save(commit=False) + if commit: + user = teacher.user + user.first_name = self.cleaned_data['first_name'] + user.last_name = self.cleaned_data['last_name'] + user.email = self.cleaned_data['email'] + user.save() + teacher.save() + return teacher + +class ResourceForm(forms.ModelForm): + class Meta: + model = Resource + fields = ['title_ar', 'title_en', 'resource_type', 'file', 'link'] + labels = { + 'title_ar': 'العنوان (عربي)', + 'title_en': 'العنوان (إنجليزي)', + 'resource_type': 'نوع المصدر', + 'file': 'الملف', + 'link': 'الرابط' + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + for field_name, field in self.fields.items(): + field.widget.attrs['class'] = 'form-control' diff --git a/core/migrations/0014_alter_city_options_alter_classroom_options_and_more.py b/core/migrations/0014_alter_city_options_alter_classroom_options_and_more.py new file mode 100644 index 0000000..fb778ff --- /dev/null +++ b/core/migrations/0014_alter_city_options_alter_classroom_options_and_more.py @@ -0,0 +1,314 @@ +# Generated by Django 5.2.7 on 2026-02-04 10:25 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0013_resource_resource_type_alter_resource_link'), + ] + + operations = [ + migrations.AlterModelOptions( + name='city', + options={'verbose_name': 'مدينة', 'verbose_name_plural': 'المدن'}, + ), + migrations.AlterModelOptions( + name='classroom', + options={'verbose_name': 'صف دراسي', 'verbose_name_plural': 'الصفوف الدراسية'}, + ), + migrations.AlterModelOptions( + name='governorate', + options={'verbose_name': 'محافظة', 'verbose_name_plural': 'المحافظات'}, + ), + migrations.AlterModelOptions( + name='platformsettings', + options={'verbose_name': 'إعدادات المنصة', 'verbose_name_plural': 'إعدادات المنصة'}, + ), + migrations.AlterModelOptions( + name='resource', + options={'verbose_name': 'مصدر تعليمي', 'verbose_name_plural': 'المصادر التعليمية'}, + ), + migrations.AlterModelOptions( + name='student', + options={'verbose_name': 'طالب', 'verbose_name_plural': 'الطلاب'}, + ), + migrations.AlterModelOptions( + name='subject', + options={'verbose_name': 'مادة دراسية', 'verbose_name_plural': 'المواد الدراسية'}, + ), + migrations.AlterModelOptions( + name='teacher', + options={'verbose_name': 'معلم', 'verbose_name_plural': 'المعلمون'}, + ), + migrations.AlterModelOptions( + name='thawaniconfiguration', + options={'verbose_name': 'إعدادات ثواني', 'verbose_name_plural': 'إعدادات ثواني'}, + ), + migrations.AlterModelOptions( + name='wablasconfiguration', + options={'verbose_name': 'إعدادات Wablas', 'verbose_name_plural': 'إعدادات Wablas'}, + ), + migrations.AlterField( + model_name='city', + name='governorate', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='cities', to='core.governorate', verbose_name='المحافظة'), + ), + migrations.AlterField( + model_name='city', + name='name_ar', + field=models.CharField(default='', max_length=100, verbose_name='الاسم (عربي)'), + ), + migrations.AlterField( + model_name='city', + name='name_en', + field=models.CharField(default='', max_length=100, verbose_name='الاسم (إنجليزي)'), + ), + migrations.AlterField( + model_name='classroom', + name='description', + field=models.TextField(blank=True, verbose_name='الوصف'), + ), + migrations.AlterField( + model_name='classroom', + name='name_ar', + field=models.CharField(max_length=100, verbose_name='الاسم (عربي)'), + ), + migrations.AlterField( + model_name='classroom', + name='name_en', + field=models.CharField(max_length=100, verbose_name='الاسم (إنجليزي)'), + ), + migrations.AlterField( + model_name='governorate', + name='name_ar', + field=models.CharField(default='', max_length=100, verbose_name='الاسم (عربي)'), + ), + migrations.AlterField( + model_name='governorate', + name='name_en', + field=models.CharField(default='', max_length=100, verbose_name='الاسم (إنجليزي)'), + ), + migrations.AlterField( + model_name='platformsettings', + name='address', + field=models.TextField(blank=True, null=True, verbose_name='العنوان'), + ), + migrations.AlterField( + model_name='platformsettings', + name='contact_email', + field=models.EmailField(blank=True, max_length=254, null=True, verbose_name='بريد التواصل'), + ), + migrations.AlterField( + model_name='platformsettings', + name='contact_phone', + field=models.CharField(blank=True, max_length=20, null=True, verbose_name='هاتف التواصل'), + ), + migrations.AlterField( + model_name='platformsettings', + name='description', + field=models.TextField(blank=True, null=True, verbose_name='وصف المنصة'), + ), + migrations.AlterField( + model_name='platformsettings', + name='facebook_link', + field=models.URLField(blank=True, null=True, verbose_name='رابط فيسبوك'), + ), + migrations.AlterField( + model_name='platformsettings', + name='instagram_link', + field=models.URLField(blank=True, null=True, verbose_name='رابط انستغرام'), + ), + migrations.AlterField( + model_name='platformsettings', + name='logo', + field=models.ImageField(blank=True, null=True, upload_to='platform/', verbose_name='الشعار'), + ), + migrations.AlterField( + model_name='platformsettings', + name='name', + field=models.CharField(default='منصتي التعليمية', max_length=100, verbose_name='اسم المنصة'), + ), + migrations.AlterField( + model_name='platformsettings', + name='twitter_link', + field=models.URLField(blank=True, null=True, verbose_name='رابط تويتر'), + ), + migrations.AlterField( + model_name='resource', + name='file', + field=models.FileField(blank=True, null=True, upload_to='resources/', verbose_name='الملف'), + ), + migrations.AlterField( + model_name='resource', + name='link', + field=models.URLField(blank=True, help_text='رابط YouTube للفيديو، أو رابط خارجي.', verbose_name='الرابط'), + ), + migrations.AlterField( + model_name='resource', + name='resource_type', + field=models.CharField(choices=[('FILE', 'ملف (PDF, Doc, إلخ)'), ('VIDEO', 'فيديو (YouTube)'), ('LINK', 'رابط خارجي')], default='FILE', max_length=10, verbose_name='نوع المصدر'), + ), + migrations.AlterField( + model_name='resource', + name='subject', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='resources', to='core.subject', verbose_name='المادة'), + ), + migrations.AlterField( + model_name='resource', + name='title_ar', + field=models.CharField(max_length=200, verbose_name='العنوان (عربي)'), + ), + migrations.AlterField( + model_name='resource', + name='title_en', + field=models.CharField(max_length=200, verbose_name='العنوان (إنجليزي)'), + ), + migrations.AlterField( + model_name='student', + name='avatar', + field=models.ImageField(blank=True, null=True, upload_to='students/', verbose_name='الصورة الشخصية'), + ), + migrations.AlterField( + model_name='student', + name='city', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.city', verbose_name='المدينة'), + ), + migrations.AlterField( + model_name='student', + name='classroom', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='students', to='core.classroom', verbose_name='الصف'), + ), + migrations.AlterField( + model_name='student', + name='email_otp_code', + field=models.CharField(blank=True, max_length=6, null=True, verbose_name='رمز تفعيل البريد'), + ), + migrations.AlterField( + model_name='student', + name='governorate', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.governorate', verbose_name='المحافظة'), + ), + migrations.AlterField( + model_name='student', + name='is_email_verified', + field=models.BooleanField(default=False, verbose_name='هل البريد مفعل؟'), + ), + migrations.AlterField( + model_name='student', + name='mobile_number', + field=models.CharField(blank=True, max_length=20, verbose_name='رقم الجوال'), + ), + migrations.AlterField( + model_name='student', + name='phone_number', + field=models.CharField(blank=True, max_length=20, verbose_name='رقم الهاتف الأرضي'), + ), + migrations.AlterField( + model_name='student', + name='subscribed_subjects', + field=models.ManyToManyField(blank=True, related_name='subscribers', to='core.subject', verbose_name='المواد المسجلة'), + ), + migrations.AlterField( + model_name='subject', + name='classroom', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subjects', to='core.classroom', verbose_name='الصف'), + ), + migrations.AlterField( + model_name='subject', + name='description_ar', + field=models.TextField(blank=True, verbose_name='الوصف (عربي)'), + ), + migrations.AlterField( + model_name='subject', + name='description_en', + field=models.TextField(blank=True, verbose_name='الوصف (إنجليزي)'), + ), + migrations.AlterField( + model_name='subject', + name='google_drive_link', + field=models.URLField(blank=True, verbose_name='رابط Google Drive'), + ), + migrations.AlterField( + model_name='subject', + name='google_meet_link', + field=models.URLField(blank=True, verbose_name='رابط Google Meet'), + ), + migrations.AlterField( + model_name='subject', + name='image', + field=models.ImageField(blank=True, null=True, upload_to='subjects/', verbose_name='الصورة'), + ), + migrations.AlterField( + model_name='subject', + name='name_ar', + field=models.CharField(max_length=200, verbose_name='الاسم (عربي)'), + ), + migrations.AlterField( + model_name='subject', + name='name_en', + field=models.CharField(max_length=200, verbose_name='الاسم (إنجليزي)'), + ), + migrations.AlterField( + model_name='subject', + name='price', + field=models.DecimalField(decimal_places=2, default=0.0, max_digits=10, verbose_name='السعر'), + ), + migrations.AlterField( + model_name='subject', + name='teachers', + field=models.ManyToManyField(blank=True, related_name='subjects', to='core.teacher', verbose_name='المعلمون'), + ), + migrations.AlterField( + model_name='subject', + name='youtube_live_url', + field=models.URLField(blank=True, help_text='ضع رابط بث YouTube هنا للبثوث الكبيرة (500+ طالب).', verbose_name='رابط بث YouTube'), + ), + migrations.AlterField( + model_name='teacher', + name='avatar', + field=models.ImageField(blank=True, null=True, upload_to='teachers/', verbose_name='الصورة الشخصية'), + ), + migrations.AlterField( + model_name='teacher', + name='bio', + field=models.TextField(blank=True, verbose_name='نبذة'), + ), + migrations.AlterField( + model_name='teacher', + name='specialization', + field=models.CharField(blank=True, max_length=255, verbose_name='التخصص'), + ), + migrations.AlterField( + model_name='thawaniconfiguration', + name='api_key', + field=models.CharField(help_text='Thawani Secret Key', max_length=255, verbose_name='API Key'), + ), + migrations.AlterField( + model_name='thawaniconfiguration', + name='is_sandbox', + field=models.BooleanField(default=True, help_text='اختر هذا الخيار لاستخدام بيئة التجربة', verbose_name='وضع التجربة (Sandbox)'), + ), + migrations.AlterField( + model_name='thawaniconfiguration', + name='publishable_key', + field=models.CharField(help_text='Thawani Publishable Key', max_length=255, verbose_name='Publishable Key'), + ), + migrations.AlterField( + model_name='wablasconfiguration', + name='api_token', + field=models.CharField(max_length=255, verbose_name='API Token'), + ), + migrations.AlterField( + model_name='wablasconfiguration', + name='api_url', + field=models.URLField(default='https://texas.wablas.com', verbose_name='رابط API'), + ), + migrations.AlterField( + model_name='wablasconfiguration', + name='secret_key', + field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Secret Key'), + ), + ] diff --git a/core/migrations/__pycache__/0014_alter_city_options_alter_classroom_options_and_more.cpython-311.pyc b/core/migrations/__pycache__/0014_alter_city_options_alter_classroom_options_and_more.cpython-311.pyc new file mode 100644 index 0000000..12f78db Binary files /dev/null and b/core/migrations/__pycache__/0014_alter_city_options_alter_classroom_options_and_more.cpython-311.pyc differ diff --git a/core/models.py b/core/models.py index 989c244..86d6d42 100644 --- a/core/models.py +++ b/core/models.py @@ -18,40 +18,48 @@ class SingletonModel(models.Model): class Teacher(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='teacher_profile') - bio = models.TextField(_("Bio"), blank=True) - avatar = models.ImageField(_("Avatar"), upload_to='teachers/', blank=True, null=True) - specialization = models.CharField(_("Specialization"), max_length=255, blank=True) + bio = models.TextField("نبذة", blank=True) + avatar = models.ImageField("الصورة الشخصية", upload_to='teachers/', blank=True, null=True) + specialization = models.CharField("التخصص", max_length=255, blank=True) + + class Meta: + verbose_name = "معلم" + verbose_name_plural = "المعلمون" def __str__(self): return self.user.get_full_name() or self.user.username class Classroom(models.Model): - name_en = models.CharField(_("Name (English)"), max_length=100) - name_ar = models.CharField(_("Name (Arabic)"), max_length=100) - description = models.TextField(_("Description"), blank=True) + name_en = models.CharField("الاسم (إنجليزي)", max_length=100) + name_ar = models.CharField("الاسم (عربي)", max_length=100) + description = models.TextField("الوصف", blank=True) class Meta: - verbose_name = _("Classroom") - verbose_name_plural = _("Classrooms") + verbose_name = "صف دراسي" + verbose_name_plural = "الصفوف الدراسية" def __str__(self): - return self.name_en + return self.name_ar or self.name_en class Subject(models.Model): - classroom = models.ForeignKey(Classroom, on_delete=models.CASCADE, related_name='subjects') - teachers = models.ManyToManyField(Teacher, blank=True, related_name='subjects') - name_en = models.CharField(_("Name (English)"), max_length=200) - name_ar = models.CharField(_("Name (Arabic)"), max_length=200) - description_en = models.TextField(_("Description (English)"), blank=True) - description_ar = models.TextField(_("Description (Arabic)"), blank=True) - price = models.DecimalField(_("Price"), max_digits=10, decimal_places=2, default=0.00) - image = models.ImageField(_("Image"), upload_to='subjects/', blank=True, null=True) - google_drive_link = models.URLField(_("Google Drive Link"), blank=True) - google_meet_link = models.URLField(_("Google Meet Link"), blank=True) - youtube_live_url = models.URLField(_("YouTube Live URL"), blank=True, help_text=_("Paste the YouTube Live link here for large broadcasts (500+ students).")) + classroom = models.ForeignKey(Classroom, on_delete=models.CASCADE, related_name='subjects', verbose_name="الصف") + teachers = models.ManyToManyField(Teacher, blank=True, related_name='subjects', verbose_name="المعلمون") + name_en = models.CharField("الاسم (إنجليزي)", max_length=200) + name_ar = models.CharField("الاسم (عربي)", max_length=200) + description_en = models.TextField("الوصف (إنجليزي)", blank=True) + description_ar = models.TextField("الوصف (عربي)", blank=True) + price = models.DecimalField("السعر", max_digits=10, decimal_places=2, default=0.00) + image = models.ImageField("الصورة", upload_to='subjects/', blank=True, null=True) + google_drive_link = models.URLField("رابط Google Drive", blank=True) + google_meet_link = models.URLField("رابط Google Meet", blank=True) + youtube_live_url = models.URLField("رابط بث YouTube", blank=True, help_text="ضع رابط بث YouTube هنا للبثوث الكبيرة (500+ طالب).") + + class Meta: + verbose_name = "مادة دراسية" + verbose_name_plural = "المواد الدراسية" def __str__(self): - return self.name_en + return self.name_ar or self.name_en def get_youtube_id(self): """Extracts the video ID from a YouTube URL.""" @@ -75,21 +83,25 @@ class Subject(models.Model): class Resource(models.Model): RESOURCE_TYPES = ( - ('FILE', _('File (PDF, Doc, etc.)')), - ('VIDEO', _('Video Link (YouTube)')), - ('LINK', _('External Link')), + ('FILE', 'ملف (PDF, Doc, إلخ)'), + ('VIDEO', 'فيديو (YouTube)'), + ('LINK', 'رابط خارجي'), ) - subject = models.ForeignKey(Subject, on_delete=models.CASCADE, related_name='resources') - title_en = models.CharField(_("Title (English)"), max_length=200) - title_ar = models.CharField(_("Title (Arabic)"), max_length=200) - resource_type = models.CharField(_("Resource Type"), max_length=10, choices=RESOURCE_TYPES, default='FILE') - file = models.FileField(_("File"), upload_to='resources/', blank=True, null=True) - link = models.URLField(_("Link"), blank=True, help_text=_("YouTube URL for Video type, or external URL for Link type.")) + subject = models.ForeignKey(Subject, on_delete=models.CASCADE, related_name='resources', verbose_name="المادة") + title_en = models.CharField("العنوان (إنجليزي)", max_length=200) + title_ar = models.CharField("العنوان (عربي)", max_length=200) + resource_type = models.CharField("نوع المصدر", max_length=10, choices=RESOURCE_TYPES, default='FILE') + file = models.FileField("الملف", upload_to='resources/', blank=True, null=True) + link = models.URLField("الرابط", blank=True, help_text="رابط YouTube للفيديو، أو رابط خارجي.") created_at = models.DateTimeField(auto_now_add=True) + class Meta: + verbose_name = "مصدر تعليمي" + verbose_name_plural = "المصادر التعليمية" + def __str__(self): - return self.title_en + return self.title_ar or self.title_en def get_youtube_id(self): """Extracts the video ID from the link if it is a YouTube URL.""" @@ -118,42 +130,46 @@ class Resource(models.Model): return False class Governorate(models.Model): - name_en = models.CharField(_("Name (English)"), max_length=100, default="") - name_ar = models.CharField(_("Name (Arabic)"), max_length=100, default="") + name_en = models.CharField("الاسم (إنجليزي)", max_length=100, default="") + name_ar = models.CharField("الاسم (عربي)", max_length=100, default="") class Meta: - verbose_name = _("Governorate") - verbose_name_plural = _("Governorates") + verbose_name = "محافظة" + verbose_name_plural = "المحافظات" def __str__(self): - return f"{self.name_en}" + return self.name_ar or f"{self.name_en}" class City(models.Model): - governorate = models.ForeignKey(Governorate, on_delete=models.CASCADE, related_name='cities', verbose_name=_("Governorate"), null=True, blank=True) - name_en = models.CharField(_("Name (English)"), max_length=100, default="") - name_ar = models.CharField(_("Name (Arabic)"), max_length=100, default="") + governorate = models.ForeignKey(Governorate, on_delete=models.CASCADE, related_name='cities', verbose_name="المحافظة", null=True, blank=True) + name_en = models.CharField("الاسم (إنجليزي)", max_length=100, default="") + name_ar = models.CharField("الاسم (عربي)", max_length=100, default="") class Meta: - verbose_name = _("City") - verbose_name_plural = _("Cities") + verbose_name = "مدينة" + verbose_name_plural = "المدن" def __str__(self): - return f"{self.name_en}" + return self.name_ar or f"{self.name_en}" class Student(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='student_profile') - classroom = models.ForeignKey(Classroom, on_delete=models.SET_NULL, null=True, blank=True, related_name='students') - phone_number = models.CharField(_("Phone Number"), max_length=20, blank=True) - mobile_number = models.CharField(_("Mobile Number"), max_length=20, blank=True) - subscribed_subjects = models.ManyToManyField(Subject, blank=True, related_name='subscribers') + classroom = models.ForeignKey(Classroom, on_delete=models.SET_NULL, null=True, blank=True, related_name='students', verbose_name="الصف") + phone_number = models.CharField("رقم الهاتف الأرضي", max_length=20, blank=True) + mobile_number = models.CharField("رقم الجوال", max_length=20, blank=True) + subscribed_subjects = models.ManyToManyField(Subject, blank=True, related_name='subscribers', verbose_name="المواد المسجلة") - governorate = models.ForeignKey(Governorate, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("Governorate")) - city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True, blank=True, verbose_name=_("City")) - avatar = models.ImageField(_("Picture"), upload_to='students/', blank=True, null=True) + governorate = models.ForeignKey(Governorate, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="المحافظة") + city = models.ForeignKey(City, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="المدينة") + avatar = models.ImageField("الصورة الشخصية", upload_to='students/', blank=True, null=True) # Email Verification - email_otp_code = models.CharField(max_length=6, blank=True, null=True) - is_email_verified = models.BooleanField(default=False) + email_otp_code = models.CharField("رمز تفعيل البريد", max_length=6, blank=True, null=True) + is_email_verified = models.BooleanField("هل البريد مفعل؟", default=False) + + class Meta: + verbose_name = "طالب" + verbose_name_plural = "الطلاب" def __str__(self): return self.user.get_full_name() or self.user.username @@ -161,45 +177,45 @@ class Student(models.Model): # --- Configuration Models --- class WablasConfiguration(SingletonModel): - api_url = models.URLField(default="https://texas.wablas.com") - api_token = models.CharField(max_length=255) - secret_key = models.CharField(max_length=255, blank=True, null=True) + api_url = models.URLField("رابط API", default="https://texas.wablas.com") + api_token = models.CharField("API Token", max_length=255) + secret_key = models.CharField("Secret Key", max_length=255, blank=True, null=True) class Meta: - verbose_name = "Wablas Configuration" - verbose_name_plural = "Wablas Configuration" + verbose_name = "إعدادات Wablas" + verbose_name_plural = "إعدادات Wablas" def __str__(self): - return "Wablas Configuration" + return "إعدادات Wablas" class ThawaniConfiguration(SingletonModel): - api_key = models.CharField(max_length=255, help_text="Thawani Secret Key") - publishable_key = models.CharField(max_length=255, help_text="Thawani Publishable Key") - is_sandbox = models.BooleanField(default=True, help_text="Check to use Sandbox environment") + api_key = models.CharField("API Key", max_length=255, help_text="Thawani Secret Key") + publishable_key = models.CharField("Publishable Key", max_length=255, help_text="Thawani Publishable Key") + is_sandbox = models.BooleanField("وضع التجربة (Sandbox)", default=True, help_text="اختر هذا الخيار لاستخدام بيئة التجربة") class Meta: - verbose_name = "Thawani Configuration" - verbose_name_plural = "Thawani Configuration" + verbose_name = "إعدادات ثواني" + verbose_name_plural = "إعدادات ثواني" def __str__(self): - return "Thawani Configuration" + return "إعدادات ثواني" class PlatformSettings(SingletonModel): - name = models.CharField(max_length=100, default="My School Platform") - logo = models.ImageField(upload_to='platform/', blank=True, null=True) - description = models.TextField(blank=True, null=True) - contact_email = models.EmailField(blank=True, null=True) - contact_phone = models.CharField(max_length=20, blank=True, null=True) - address = models.TextField(blank=True, null=True) + name = models.CharField("اسم المنصة", max_length=100, default="منصتي التعليمية") + logo = models.ImageField("الشعار", upload_to='platform/', blank=True, null=True) + description = models.TextField("وصف المنصة", blank=True, null=True) + contact_email = models.EmailField("بريد التواصل", blank=True, null=True) + contact_phone = models.CharField("هاتف التواصل", max_length=20, blank=True, null=True) + address = models.TextField("العنوان", blank=True, null=True) # Social Media - facebook_link = models.URLField(blank=True, null=True) - twitter_link = models.URLField(blank=True, null=True) - instagram_link = models.URLField(blank=True, null=True) + facebook_link = models.URLField("رابط فيسبوك", blank=True, null=True) + twitter_link = models.URLField("رابط تويتر", blank=True, null=True) + instagram_link = models.URLField("رابط انستغرام", blank=True, null=True) class Meta: - verbose_name = "Platform Profile" - verbose_name_plural = "Platform Profile" + verbose_name = "إعدادات المنصة" + verbose_name_plural = "إعدادات المنصة" def __str__(self): - return "Platform Profile" \ No newline at end of file + return "إعدادات المنصة" diff --git a/core/templates/base.html b/core/templates/base.html index 0cc6e8a..8130aff 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -1,17 +1,14 @@ {% load i18n static %} - + - {% block title %}{% trans "E-Learning Platform" %}{% endblock %} + {% block title %}منصة التعليم الإلكتروني{% endblock %} - - - {% if LANGUAGE_BIDI %} + - {% endif %} @@ -30,7 +27,7 @@ } body { - font-family: 'Outfit', 'Noto Kufi Arabic', sans-serif; + font-family: 'Noto Kufi Arabic', 'Outfit', sans-serif; background-color: var(--bg-light); color: #333; overflow-x: hidden; @@ -88,7 +85,7 @@ content: ''; position: absolute; top: 0; - right: 0; + right: 0; /* RTL adjusted */ width: 300px; height: 300px; background: radial-gradient(circle, rgba(45, 49, 250, 0.1) 0%, transparent 70%); @@ -125,44 +122,35 @@ @@ -173,7 +161,7 @@ diff --git a/core/templates/core/add_resource.html b/core/templates/core/add_resource.html new file mode 100644 index 0000000..eedb66c --- /dev/null +++ b/core/templates/core/add_resource.html @@ -0,0 +1,41 @@ +{% extends 'base.html' %} +{% load i18n static %} + +{% block title %}إضافة مصدر جديد - {{ subject.name_ar }}{% endblock %} + +{% block content %} +
+
+
+
+
+

إضافة مصدر جديد

+

للمادة: {{ subject.name_ar }}

+
+ +
+ {% csrf_token %} + + {% for field in form %} +
+ + {{ field }} + {% if field.help_text %} +
{{ field.help_text }}
+ {% endif %} + {% for error in field.errors %} +
{{ error }}
+ {% endfor %} +
+ {% endfor %} + +
+ + إلغاء +
+
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/core/templates/core/delete_resource.html b/core/templates/core/delete_resource.html new file mode 100644 index 0000000..570a70c --- /dev/null +++ b/core/templates/core/delete_resource.html @@ -0,0 +1,34 @@ +{% extends 'base.html' %} +{% load i18n static %} + +{% block title %}حذف المصدر - {{ resource.title_ar }}{% endblock %} + +{% block content %} +
+
+
+
+
+ + + + +
+ +

هل أنت متأكد؟

+

+ أنت على وشك حذف المصدر "{{ resource.title_ar }}". لا يمكن التراجع عن هذا الإجراء. +

+ +
+ {% csrf_token %} +
+ + إلغاء +
+
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/core/templates/core/edit_resource.html b/core/templates/core/edit_resource.html new file mode 100644 index 0000000..e66b546 --- /dev/null +++ b/core/templates/core/edit_resource.html @@ -0,0 +1,41 @@ +{% extends 'base.html' %} +{% load i18n static %} + +{% block title %}تعديل المصدر - {{ resource.title_ar }}{% endblock %} + +{% block content %} +
+
+
+
+
+

تعديل المصدر

+

المادة: {{ subject.name_ar }}

+
+ +
+ {% csrf_token %} + + {% for field in form %} +
+ + {{ field }} + {% if field.help_text %} +
{{ field.help_text }}
+ {% endif %} + {% for error in field.errors %} +
{{ error }}
+ {% endfor %} +
+ {% endfor %} + +
+ + إلغاء +
+
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/core/templates/core/edit_teacher_profile.html b/core/templates/core/edit_teacher_profile.html new file mode 100644 index 0000000..322878e --- /dev/null +++ b/core/templates/core/edit_teacher_profile.html @@ -0,0 +1,59 @@ +{% extends 'base.html' %} +{% load i18n static %} + +{% block title %}تعديل ملف المعلم - EduPlatform{% endblock %} + +{% block content %} +
+
+
+
+
+

تعديل الملف الشخصي

+ +
+ {% csrf_token %} + + +
+
+ {% if form.instance.avatar %} + Avatar + {% else %} +
+ {{ user.first_name|first|upper }} +
+ {% endif %} +
+
+ + {% for field in form %} +
+ + {{ field }} + {% if field.help_text %} +
{{ field.help_text }}
+ {% endif %} + {% for error in field.errors %} +
+ {{ error }} +
+ {% endfor %} +
+ {% endfor %} + +
+ + + إلغاء + +
+
+
+
+
+
+
+{% endblock %} \ No newline at end of file diff --git a/core/templates/core/error.html b/core/templates/core/error.html index 34dd7a2..55b2220 100644 --- a/core/templates/core/error.html +++ b/core/templates/core/error.html @@ -1,11 +1,12 @@ {% extends 'base.html' %} +{% load i18n static %} {% block content %}
-

Error

+

خطأ

{{ message }}

- Go Back to Profile + العودة للملف الشخصي
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/index.html b/core/templates/core/index.html index ed0ad04..a9620cc 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% load i18n static %} -{% block title %}{% trans "Home" %} | EduPlatform{% endblock %} +{% block title %}الرئيسية | EduPlatform{% endblock %} {% block content %}
@@ -9,22 +9,14 @@

- {% if LANGUAGE_CODE == 'ar' %} تعلم من أفضل المعلمين في أي وقت وأي مكان - {% else %} - Learn from the best teachers anytime, anywhere - {% endif %}

- {% if LANGUAGE_CODE == 'ar' %} منصة تعليمية متكاملة تدعم الطلاب والمعلمين مع دروس حية ومصادر تعليمية متميزة. - {% else %} - A comprehensive educational platform supporting students and teachers with live classes and premium educational resources. - {% endif %}

@@ -32,8 +24,8 @@
-

{% trans "Ready to start?" %}

-

{% trans "Join thousands of students learning today." %}

+

مستعد للبدء؟

+

انضم لآلاف الطلاب اليوم.

@@ -49,8 +41,8 @@
-

{% trans "Our Educational Programs" %}

-

{% trans "Explore subjects tailored for each educational level." %}

+

برامجنا التعليمية

+

استكشف المواد المخصصة لكل مرحلة دراسية.

{% for level in levels %} @@ -60,7 +52,7 @@ {{ forloop.counter }}

- {% if LANGUAGE_CODE == 'ar' %}{{ level.name_ar }}{% else %}{{ level.name_en }}{% endif %} + {{ level.name_ar }}


@@ -78,14 +70,14 @@

- {% if LANGUAGE_CODE == 'ar' %}{{ subject.name_ar }}{% else %}{{ subject.name_en }}{% endif %} + {{ subject.name_ar }}

- {% if LANGUAGE_CODE == 'ar' %}{{ subject.description_ar|truncatewords:15 }}{% else %}{{ subject.description_en|truncatewords:15 }}{% endif %} + {{ subject.description_ar|truncatewords:15 }}

${{ subject.price }} - {% trans "Subscribe" %} + اشتراك
@@ -93,7 +85,7 @@ {% empty %}
- {% trans "No subjects available for this level yet." %} + لا توجد مواد متاحة لهذا المستوى بعد.
{% endfor %} @@ -107,8 +99,8 @@
-

{% trans "Meet Our Teachers" %}

-

{% trans "Learn from our expert instructors." %}

+

تعرف على معلمينا

+

تعلم من نخبة من المعلمين.

@@ -127,20 +119,16 @@
{{ teacher.user.get_full_name|default:teacher.user.username }}
-

{{ teacher.specialization|default:"Teacher" }}

+

{{ teacher.specialization|default:"معلم" }}

- {{ teacher.bio|default:"No bio available."|truncatewords:20 }} + {{ teacher.bio|default:"لا توجد نبذة."|truncatewords:20 }}

- -
- -
{% empty %}
-

{% trans "No teachers found at the moment." %}

+

لا يوجد معلمين حالياً.

{% endfor %} @@ -153,22 +141,22 @@
🎥
-
{% trans "Live Classes" %}
-

{% trans "Join interactive sessions via Google Meet." %}

+
دروس مباشرة
+

انضم لجلسات تفاعلية عبر Google Meet.

📁
-
{% trans "Resources" %}
-

{% trans "Access course materials on Google Drive." %}

+
المصادر
+

الوصول لمواد الدورة عبر Google Drive.

💳
-
{% trans "Easy Payments" %}
-

{% trans "Secure payments with Thawani gateway." %}

+
دفع سهل
+

دفع آمن عبر بوابة ثواني.

diff --git a/core/templates/core/live_classroom.html b/core/templates/core/live_classroom.html index 7cff1d0..41a40e3 100644 --- a/core/templates/core/live_classroom.html +++ b/core/templates/core/live_classroom.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% load i18n static %} -{% block title %}{% trans "Live Classroom" %} - {{ subject.name_en }}{% endblock %} +{% block title %}الفصل المباشر - {{ subject.name_ar }}{% endblock %} {% block content %}
@@ -12,10 +12,10 @@
-

{% trans "Live Class via Google Meet" %}

-

{% trans "This class is being held on Google Meet. Click the button below to join." %}

+

درس مباشر عبر Google Meet

+

يقام هذا الدرس عبر Google Meet. انقر الزر أدناه للانضمام.

- {% trans "Join Google Meet" %} + انضم إلى Google Meet
diff --git a/core/templates/core/login.html b/core/templates/core/login.html index 53d488a..f35bd6c 100644 --- a/core/templates/core/login.html +++ b/core/templates/core/login.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% load i18n static %} -{% block title %}{% trans "Login" %}{% endblock %} +{% block title %}تسجيل الدخول{% endblock %} {% block content %}
@@ -9,8 +9,8 @@
-

{% trans "Welcome Back" %}

-

{% trans "Sign in to continue your learning journey" %}

+

مرحباً بعودتك

+

سجل الدخول لمتابعة رحلتك التعليمية

@@ -18,29 +18,29 @@ {% if form.errors %} {% endif %}
- - + +
- - + +

- {% trans "Don't have an account?" %} - {% trans "Register Here" %} + ليس لديك حساب؟ + سجل هنا

diff --git a/core/templates/core/profile.html b/core/templates/core/profile.html index 3de8d90..ddc0162 100644 --- a/core/templates/core/profile.html +++ b/core/templates/core/profile.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% load i18n static %} -{% block title %}{% trans "My Profile" %} | EduPlatform{% endblock %} +{% block title %}ملفي الشخصي | EduPlatform{% endblock %} {% block content %}
@@ -21,9 +21,9 @@

{{ user.get_full_name|default:user.username }}

{{ user.email }}

{% if student_profile and student_profile.classroom %} - {{ student_profile.classroom.name_en }} + {{ student_profile.classroom.name_ar }} {% elif user.is_staff %} - {% trans "Staff / Admin" %} + طاقم / مسؤول {% endif %}
@@ -31,42 +31,42 @@
{% if student_profile %} -

{% trans "Student Details" %}

+

تفاصيل الطالب

- +

{{ user.username }}

- -

{{ student_profile.city|default:"-" }}

+ +

{{ student_profile.city.name_ar|default:"-" }}

- -

{{ student_profile.governorate|default:"-" }}

+ +

{{ student_profile.governorate.name_ar|default:"-" }}

- +

{{ student_profile.mobile_number|default:"-" }}

-

{% trans "My Subjects" %}

+

موادي

{% if student_profile.subscribed_subjects.all %}
{% for subject in student_profile.subscribed_subjects.all %} - {{ subject.name_en }} - {% trans "View" %} + {{ subject.name_ar }} + عرض {% endfor %}
{% else %} -

{% trans "No subjects subscribed yet." %}

+

لم يتم الاشتراك في أي مواد بعد.

{% endif %} {% else %}
- {% trans "You are logged in as a staff member or user without a student profile." %} + أنت مسجل دخول كعضو طاقم أو مستخدم بدون ملف طالب.
{% endif %}
@@ -74,4 +74,4 @@
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/registration.html b/core/templates/core/registration.html index ffe2c95..e28e4ec 100644 --- a/core/templates/core/registration.html +++ b/core/templates/core/registration.html @@ -1,7 +1,7 @@ {% extends 'base.html' %} {% load i18n static %} -{% block title %}{% trans "Student Registration" %}{% endblock %} +{% block title %}تسجيل الطالب{% endblock %} {% block content %}
@@ -9,8 +9,8 @@
-

{% trans "Create Your Account" %}

-

{% trans "Join our learning platform today" %}

+

أنشئ حسابك

+

انضم إلى منصتنا التعليمية اليوم

@@ -34,34 +34,34 @@
-
{% trans "Personal Information" %}
+
المعلومات الشخصية
{{ form.full_name }} - +
{{ form.username }} - +
{{ form.email }} - +
{{ form.password }} - +
{{ form.password_confirm }} - +
@@ -71,24 +71,24 @@
-
{% trans "Student Profile" %}
+
ملف الطالب
{{ form.mobile_number }} - +
{{ form.governorate }} - +
{{ form.city }} - +
@@ -98,21 +98,21 @@
-
{% trans "Education" %}
+
التعليم
- + {{ form.classroom }}
- +
-

{% trans "Select a classroom first." %}

+

اختر الصف أولاً.

-
{% trans "Total Amount:" %}
+
المبلغ الإجمالي:

0.00

@@ -121,35 +121,35 @@
-
{% trans "Profile Picture" %}
+
الصورة الشخصية
- +
- +
- {% trans "No photo" %} + لا توجد صورة
- + {{ form.avatar }}
@@ -169,7 +169,7 @@ document.addEventListener('DOMContentLoaded', function() { classroomSelect.addEventListener('change', function() { const classroomId = this.value; if (!classroomId) { - subjectsContainer.innerHTML = '

{% trans "Select a classroom first." %}

'; + subjectsContainer.innerHTML = '

اختر الصف أولاً.

'; updateTotal(); return; } @@ -179,7 +179,7 @@ document.addEventListener('DOMContentLoaded', function() { .then(data => { subjectsContainer.innerHTML = ''; if (data.length === 0) { - subjectsContainer.innerHTML = '

{% trans "No subjects found for this classroom." %}

'; + subjectsContainer.innerHTML = '

لا توجد مواد لهذا الصف.

'; } else { data.forEach(subject => { const price = parseFloat(subject.price) || 0; @@ -188,7 +188,7 @@ document.addEventListener('DOMContentLoaded', function() { div.innerHTML = ` `; @@ -199,7 +199,7 @@ document.addEventListener('DOMContentLoaded', function() { }) .catch(err => { console.error('Error fetching subjects:', err); - subjectsContainer.innerHTML = '

{% trans "Error loading subjects." %}

'; + subjectsContainer.innerHTML = '

خطأ في تحميل المواد.

'; }); }); @@ -224,7 +224,7 @@ document.addEventListener('DOMContentLoaded', function() { if (governorateSelect && citySelect) { governorateSelect.addEventListener('change', function() { const governorateId = this.value; - citySelect.innerHTML = ''; + citySelect.innerHTML = ''; if (!governorateId) { citySelect.innerHTML = ''; @@ -235,17 +235,16 @@ document.addEventListener('DOMContentLoaded', function() { .then(response => response.json()) .then(data => { citySelect.innerHTML = ''; - const currentLang = "{{ LANGUAGE_CODE }}"; data.forEach(city => { const option = document.createElement('option'); option.value = city.id; - option.textContent = currentLang === 'ar' ? city.name_ar : city.name_en; + option.textContent = city.name_ar || city.name_en; // Prefer Arabic citySelect.appendChild(option); }); }) .catch(err => { console.error('Error fetching cities:', err); - citySelect.innerHTML = ''; + citySelect.innerHTML = ''; }); }); } @@ -275,10 +274,10 @@ document.addEventListener('DOMContentLoaded', function() { video.play(); }) .catch(function(err) { - showCameraError("{% trans 'Camera access denied or unavailable.' %}"); + showCameraError("تم رفض الوصول للكاميرا أو غير متاحة."); }); } else { - showCameraError("{% trans 'Browser does not support camera.' %}"); + showCameraError("المتصفح لا يدعم الكاميرا."); } if (snap) { @@ -301,4 +300,4 @@ document.addEventListener('DOMContentLoaded', function() { } }); -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/student_dashboard.html b/core/templates/core/student_dashboard.html index ef11fbd..5af9f45 100644 --- a/core/templates/core/student_dashboard.html +++ b/core/templates/core/student_dashboard.html @@ -1,15 +1,15 @@ {% extends 'base.html' %} {% load i18n static %} -{% block title %}{% trans "Student Dashboard" %} - EduPlatform{% endblock %} +{% block title %}لوحة تحكم الطالب - EduPlatform{% endblock %} {% block content %}
-

{% trans "Welcome back," %} {{ user.first_name|default:user.username }}! 👋

-

{% trans "Here is an overview of your learning journey." %}

+

مرحباً بعودتك، {{ user.first_name|default:user.username }}! 👋

+

إليك نظرة عامة على رحلتك التعليمية.

@@ -28,43 +28,43 @@ {% if student_profile.is_mobile_verified and student_profile.is_email_verified %} - Verified + مؤكد {% endif %}

{{ user.get_full_name|default:user.username }}

-

{% trans "Student" %} {% if student_profile.classroom %} • {{ student_profile.classroom.name_en }}{% endif %}

+

طالب {% if student_profile.classroom %} • {{ student_profile.classroom.name_ar }}{% endif %}


- {% trans "Email" %} + البريد الإلكتروني {{ user.email }} {% if student_profile.is_email_verified %} - {% trans "Verified" %} + مؤكد {% else %} - {% trans "Unverified" %} + غير مؤكد {% endif %}
- {% trans "Phone" %} + رقم الهاتف {{ student_profile.mobile_number|default:"-" }} {% if student_profile.is_mobile_verified %} - {% trans "Verified" %} + مؤكد {% else %} - {% trans "Unverified" %} + غير مؤكد {% endif %}
- {% trans "City" %} - {{ student_profile.city.name|default:"-" }} + المدينة + {{ student_profile.city.name_ar|default:"-" }}
@@ -76,7 +76,7 @@
-
{% trans "Enrolled Subjects" %}
+
المواد المسجلة

{{ subscribed_subjects.count }}

@@ -89,8 +89,8 @@
-
{% trans "Classroom" %}
-
{{ student_profile.classroom.name_en|default:"Not assigned" }}
+
الصف الدراسي
+
{{ student_profile.classroom.name_ar|default:"غير معين" }}
@@ -104,7 +104,7 @@
-

{% trans "My Subjects" %}

+

موادي

{% if subscribed_subjects %}
{% for subject in subscribed_subjects %} @@ -116,27 +116,27 @@
{% else %}
- {% trans "No Image" %} + لا توجد صورة
{% endif %}
-
{{ subject.name_en }}
-

{{ subject.description_en }}

+
{{ subject.name_ar }}
+

{{ subject.description_ar }}

{% for teacher in subject.teachers.all %} {{ teacher.user.get_full_name|default:teacher.user.username }}{% if not forloop.last %}, {% endif %} {% empty %} - {% trans "No Teacher" %} + بدون معلم {% endfor %}
@@ -146,14 +146,14 @@
{% else %}
-
{% trans "You haven't enrolled in any subjects yet." %}
+
لم تسجل في أي مادة بعد.
{% endif %}
-

{% trans "Available Subjects" %}

+

المواد المتاحة

{% if available_subjects %}
{% for subject in available_subjects %} @@ -165,15 +165,15 @@
{% else %}
- {% trans "No Image" %} + لا توجد صورة
{% endif %}
-
{{ subject.name_en }}
-

{{ subject.description_en }}

+
{{ subject.name_ar }}
+

{{ subject.description_ar }}

{{ subject.price }} OMR - {% trans "Subscribe" %} + اشتراك
@@ -182,7 +182,7 @@
{% else %}
-
{% trans "No new subjects available." %}
+
لا توجد مواد جديدة متاحة.
{% endif %}
diff --git a/core/templates/core/subject_detail.html b/core/templates/core/subject_detail.html index 5469111..0782b8d 100644 --- a/core/templates/core/subject_detail.html +++ b/core/templates/core/subject_detail.html @@ -2,19 +2,29 @@ {% load i18n static %} {% block title %} - {% if LANGUAGE_CODE == 'ar' %}{{ subject.name_ar }}{% else %}{{ subject.name_en }}{% endif %} | EduPlatform + {{ subject.name_ar }} | EduPlatform {% endblock %} {% block content %}
- +
+ + {% if is_teacher %} + + + + + العودة للوحة التحكم + + {% endif %} +
@@ -27,13 +37,13 @@ {% endif %}
- {% if LANGUAGE_CODE == 'ar' %}{{ subject.classroom.name_ar }}{% else %}{{ subject.classroom.name_en }}{% endif %} + {{ subject.classroom.name_ar }}

- {% if LANGUAGE_CODE == 'ar' %}{{ subject.name_ar }}{% else %}{{ subject.name_en }}{% endif %} + {{ subject.name_ar }}

{% for teacher in subject.teachers.all %} @@ -42,33 +52,71 @@ {{ teacher.user.username|first|upper }}
-

{% trans "Teacher" %}

+

المعلم

{{ teacher }}
{% empty %}
-

{% trans "Teacher" %}

-
{% trans "Not Assigned" %}
+

المعلم

+
غير معين
{% endfor %} -

{% trans "About this Subject" %}

-
- {% if LANGUAGE_CODE == 'ar' %} - {{ subject.description_ar|linebreaks }} - {% else %} - {{ subject.description_en|linebreaks }} - {% endif %} + {% if subject.youtube_live_url %} +
+
+ +
+ {% endif %} + +

عن هذه المادة

+
+ {{ subject.description_ar|linebreaks }} +
+ + + {% if subject.google_drive_link %} + + {% endif %}
-
-

{% trans "Course Resources" %}

- {{ subject.resources.count }} +
+
+

مصادر الدورة

+ {{ subject.resources.count }} +
+ {% if is_teacher %} + + + + + إضافة مصدر + + {% endif %}
{% if subject.resources.all %} @@ -97,28 +145,40 @@
- {% if LANGUAGE_CODE == 'ar' %}{{ resource.title_ar }}{% else %}{{ resource.title_en }}{% endif %} + {{ resource.title_ar }}
{{ resource.get_resource_type_display }}
- +
+ {% if is_teacher %} + تعديل + حذف + {% endif %} + +
{% endfor %}
{% else %}
📂
-
{% trans "No resources available yet." %}
+
لا توجد مصادر متاحة بعد.
+ {% if is_teacher %} + + إضافة أول مصدر + + {% endif %}
{% endif %}
@@ -135,21 +195,21 @@
  • - {% trans "Full lifetime access" %} + وصول كامل مدى الحياة
  • - {% trans "Access on mobile and desktop" %} + دخول من الهاتف والكمبيوتر
  • - {% trans "Certificate of completion" %} + شهادة إتمام

- {% trans "30-Day Money-Back Guarantee" %} + ضمان استرداد الأموال خلال 30 يوم

@@ -160,20 +220,15 @@