update-observations-and-po-file

This commit is contained in:
Marwan Alwali 2026-01-04 11:00:29 +03:00
parent 6e829f1573
commit c2e614ceb7
6 changed files with 904 additions and 36 deletions

View File

@ -35,6 +35,14 @@ from apps.appreciation.models import (
AppreciationStatus,
AppreciationVisibility,
)
from apps.observations.models import (
Observation,
ObservationCategory,
ObservationNote,
ObservationStatusLog,
ObservationSeverity,
ObservationStatus,
)
from apps.complaints.models import Complaint, ComplaintUpdate
from apps.journeys.models import (
PatientJourneyInstance,
@ -182,6 +190,12 @@ def clear_existing_data():
Appreciation.objects.all().delete()
# Categories and Badges are preserved (seeded separately)
print("Deleting observations...")
ObservationStatusLog.objects.all().delete()
ObservationNote.objects.all().delete()
Observation.objects.all().delete()
# ObservationCategory is preserved (seeded separately)
print("Deleting users (except superusers)...")
User.objects.filter(is_superuser=False).delete()
@ -1322,6 +1336,189 @@ def generate_appreciation_stats(users, physicians, hospitals):
return stats
def create_observations(hospitals, departments, users):
"""Create observations with 2 years of historical data"""
print("Creating observations (2 years of data)...")
# Get observation categories (should be seeded)
obs_categories = list(ObservationCategory.objects.filter(is_active=True))
if not obs_categories:
print(" WARNING: No observation categories found. Run: python manage.py seed_observation_categories")
return []
# Observation descriptions
observation_descriptions = [
"Noticed a wet floor near the elevator without any warning signs. This could be a slip hazard for patients and visitors.",
"Observed expired hand sanitizer in the dispenser near the main entrance. The expiration date was 3 months ago.",
"Fire extinguisher in corridor B appears to be missing its inspection tag. Last visible inspection was over a year ago.",
"Patient call button in room 205 is not functioning properly. Patient had to wait for assistance.",
"Medication cart was left unattended in the hallway for approximately 15 minutes during shift change.",
"Emergency exit sign on the 3rd floor is not illuminated. This could be a safety concern during power outages.",
"Observed staff member not wearing proper PPE while handling biohazard materials.",
"Temperature in the medication storage room seems higher than normal. Thermometer shows 28°C.",
"Wheelchair in the lobby has a broken wheel lock mechanism. Could be dangerous for patients.",
"Noticed a strong chemical smell in the laboratory area. Ventilation may not be working properly.",
"Patient identification wristband was found on the floor in the waiting area.",
"Sharps container in treatment room 3 is overfilled and needs immediate replacement.",
"Observed water leak from ceiling tiles in the radiology waiting area.",
"Emergency shower station in the lab has not been tested recently according to the log.",
"Noticed outdated patient safety posters in the pediatric ward.",
]
observation_titles = [
"Wet floor hazard",
"Expired sanitizer",
"Fire safety concern",
"Equipment malfunction",
"Medication security",
"Emergency signage issue",
"PPE compliance",
"Temperature control",
"Equipment maintenance",
"Ventilation concern",
"Patient safety",
"Waste disposal",
"Facility maintenance",
"Safety equipment",
"Signage update needed",
]
locations = [
"Main Entrance", "Emergency Department", "ICU", "Pediatric Ward", "Surgery Floor",
"Radiology Department", "Laboratory", "Pharmacy", "Cafeteria", "Parking Garage",
"Outpatient Clinic", "Rehabilitation Center", "Administration Building", "Staff Lounge",
"Patient Rooms Floor 2", "Patient Rooms Floor 3", "Waiting Area", "Reception",
]
observations = []
now = timezone.now()
# Generate observations over 2 years (730 days)
# Average 1-3 observations per day
for day_offset in range(730):
num_observations = random.choices([0, 1, 2, 3, 4], weights=[20, 35, 30, 10, 5])[0]
for _ in range(num_observations):
hospital = random.choice(hospitals)
hospital_depts = [d for d in departments if d.hospital == hospital]
created_date = now - timedelta(
days=day_offset,
hours=random.randint(0, 23),
minutes=random.randint(0, 59)
)
# Status distribution based on age
if day_offset < 7: # Last week
status = random.choices(
[ObservationStatus.NEW, ObservationStatus.TRIAGED, ObservationStatus.ASSIGNED,
ObservationStatus.IN_PROGRESS, ObservationStatus.RESOLVED, ObservationStatus.CLOSED],
weights=[25, 20, 20, 20, 10, 5]
)[0]
elif day_offset < 30: # Last month
status = random.choices(
[ObservationStatus.NEW, ObservationStatus.TRIAGED, ObservationStatus.ASSIGNED,
ObservationStatus.IN_PROGRESS, ObservationStatus.RESOLVED, ObservationStatus.CLOSED],
weights=[5, 10, 15, 20, 30, 20]
)[0]
else: # Older
status = random.choices(
[ObservationStatus.NEW, ObservationStatus.TRIAGED, ObservationStatus.ASSIGNED,
ObservationStatus.IN_PROGRESS, ObservationStatus.RESOLVED, ObservationStatus.CLOSED,
ObservationStatus.REJECTED, ObservationStatus.DUPLICATE],
weights=[2, 3, 5, 5, 40, 40, 3, 2]
)[0]
# Severity distribution
severity = random.choices(
[ObservationSeverity.LOW, ObservationSeverity.MEDIUM,
ObservationSeverity.HIGH, ObservationSeverity.CRITICAL],
weights=[30, 45, 20, 5]
)[0]
# Anonymous vs identified (60% anonymous)
is_anonymous = random.random() < 0.6
# Generate tracking code
import secrets
tracking_code = f"OBS-{secrets.token_hex(3).upper()}"
observation = Observation(
tracking_code=tracking_code,
category=random.choice(obs_categories),
title=random.choice(observation_titles),
description=random.choice(observation_descriptions),
severity=severity,
location_text=random.choice(locations),
incident_datetime=created_date - timedelta(hours=random.randint(0, 48)),
reporter_staff_id=f"EMP{random.randint(1000, 9999)}" if not is_anonymous else '',
reporter_name=f"{random.choice(ENGLISH_FIRST_NAMES_MALE)} {random.choice(ENGLISH_LAST_NAMES)}" if not is_anonymous else '',
reporter_phone=generate_saudi_phone() if not is_anonymous and random.random() > 0.5 else '',
reporter_email=f"staff{random.randint(100, 999)}@alhammadi.sa" if not is_anonymous and random.random() > 0.5 else '',
status=status,
assigned_department=random.choice(hospital_depts) if hospital_depts and status not in [ObservationStatus.NEW] else None,
assigned_to=random.choice(users) if status in [ObservationStatus.ASSIGNED, ObservationStatus.IN_PROGRESS, ObservationStatus.RESOLVED, ObservationStatus.CLOSED] and random.random() > 0.3 else None,
)
# Set timestamps based on status
if status not in [ObservationStatus.NEW]:
observation.triaged_at = created_date + timedelta(hours=random.randint(1, 24))
observation.triaged_by = random.choice(users)
if status in [ObservationStatus.RESOLVED, ObservationStatus.CLOSED]:
observation.resolved_at = created_date + timedelta(hours=random.randint(24, 168))
if status == ObservationStatus.CLOSED:
observation.closed_at = (observation.resolved_at or created_date) + timedelta(hours=random.randint(1, 48))
observation.save()
# Override created_at
Observation.objects.filter(pk=observation.pk).update(created_at=created_date)
# Add status log entries
if status != ObservationStatus.NEW:
ObservationStatusLog.objects.create(
observation=observation,
from_status=ObservationStatus.NEW,
to_status=ObservationStatus.TRIAGED,
changed_by=random.choice(users),
comment="Observation triaged and categorized."
)
if status in [ObservationStatus.ASSIGNED, ObservationStatus.IN_PROGRESS, ObservationStatus.RESOLVED, ObservationStatus.CLOSED]:
ObservationStatusLog.objects.create(
observation=observation,
from_status=ObservationStatus.TRIAGED,
to_status=ObservationStatus.ASSIGNED,
changed_by=random.choice(users),
comment="Assigned to responsible department."
)
if status in [ObservationStatus.RESOLVED, ObservationStatus.CLOSED]:
ObservationStatusLog.objects.create(
observation=observation,
from_status=ObservationStatus.IN_PROGRESS if status != ObservationStatus.RESOLVED else ObservationStatus.ASSIGNED,
to_status=ObservationStatus.RESOLVED,
changed_by=random.choice(users),
comment="Issue has been addressed and resolved."
)
# Add internal notes for some observations
if random.random() > 0.6:
ObservationNote.objects.create(
observation=observation,
note="Initial assessment completed. Following up with relevant department.",
created_by=random.choice(users),
is_internal=True
)
observations.append(observation)
print(f" Created {len(observations)} observations over 2 years")
return observations
def main():
"""Main data generation function"""
print("\n" + "="*60)
@ -1376,6 +1573,9 @@ def main():
user_badges = []
appreciation_stats = []
# Create observations data
observations = create_observations(hospitals, departments, users)
print("\n" + "="*60)
print("Data Generation Complete!")
print("="*60)
@ -1398,6 +1598,7 @@ def main():
print(f" - {len(appreciations)} Appreciations (2 years)")
print(f" - {len(user_badges)} Badges Awarded")
print(f" - {len(appreciation_stats)} Appreciation Statistics")
print(f" - {len(observations)} Observations (2 years)")
print(f"\nYou can now login with:")
print(f" Username: px_admin")
print(f" Password: admin123")

Binary file not shown.

View File

@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PX360 1.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-01 16:40+0300\n"
"POT-Creation-Date: 2026-01-04 10:41+0300\n"
"PO-Revision-Date: 2025-12-15 12:30+0300\n"
"Last-Translator: PX360 Team\n"
"Language-Team: Arabic\n"
@ -39,36 +39,36 @@ msgstr "الصلاحيات"
msgid "Important dates"
msgstr "التواريخ المهمة"
#: apps/dashboard/views.py:73
#: apps/dashboard/views.py:75
msgid "Active Complaints"
msgstr "الشكاوى النشطة"
#: apps/dashboard/views.py:79 templates/analytics/dashboard.html:43
#: apps/dashboard/views.py:81 templates/analytics/dashboard.html:43
#: templates/complaints/analytics.html:171
msgid "Overdue Complaints"
msgstr "الشكاوى المتأخرة"
#: apps/dashboard/views.py:85
#: apps/dashboard/views.py:87
msgid "Open PX Actions"
msgstr "إجراءات PX المفتوحة"
#: apps/dashboard/views.py:91
#: apps/dashboard/views.py:93
msgid "Overdue Actions"
msgstr "الإجراءات المتأخرة"
#: apps/dashboard/views.py:97
#: apps/dashboard/views.py:99
msgid "Negative Surveys (24h)"
msgstr "الاستبيانات السلبية (24 ساعة)"
#: apps/dashboard/views.py:103
#: apps/dashboard/views.py:105
msgid "Negative Social Mentions"
msgstr "الذكر السلبي في وسائل التواصل الاجتماعي"
#: apps/dashboard/views.py:109
#: apps/dashboard/views.py:111
msgid "Low Call Center Ratings"
msgstr "تقييمات منخفضة لمركز الاتصال"
#: apps/dashboard/views.py:115 templates/analytics/dashboard.html:61
#: apps/dashboard/views.py:117 templates/analytics/dashboard.html:61
msgid "Avg Survey Score"
msgstr "متوسط تقييم الاستبيان"
@ -78,6 +78,7 @@ msgstr "العودة إلى الإجراءات"
#: templates/actions/action_detail.html:227
#: templates/appreciation/appreciation_detail.html:12
#: templates/observations/observation_detail.html:199
msgid "Details"
msgstr "التفاصيل"
@ -110,12 +111,14 @@ msgstr "إجراءات سريعة"
#: templates/complaints/complaint_detail.html:446
#: templates/config/routing_rules.html:33
#: templates/feedback/feedback_detail.html:475
#: templates/observations/observation_detail.html:398
msgid "Assign To"
msgstr "تعيين إلى"
#: templates/actions/action_detail.html:522
#: templates/complaints/complaint_detail.html:466
#: templates/feedback/feedback_detail.html:455
#: templates/observations/observation_detail.html:454
msgid "Change Status"
msgstr "تغيير الحالة"
@ -126,6 +129,8 @@ msgstr "ملاحظة اختيارية..."
#: templates/actions/action_detail.html:549
#: templates/complaints/complaint_detail.html:493
#: templates/observations/observation_detail.html:420
#: templates/observations/observation_detail.html:433
msgid "Add Note"
msgstr "إضافة ملاحظة"
@ -165,11 +170,14 @@ msgstr "اشرح سبب الحاجة إلى تصعيد هذا الإجراء..."
#: templates/callcenter/inquiry_form.html:233
#: templates/complaints/complaint_detail.html:607
#: templates/complaints/inquiry_form.html:108
#: templates/observations/category_form.html:91
#: templates/observations/convert_to_action.html:91
msgid "Cancel"
msgstr "إلغاء"
#: templates/actions/action_list.html:139
#: templates/complaints/inquiry_list.html:26
#: templates/observations/observation_list.html:113
msgid "Total"
msgstr "الإجمالي"
@ -197,6 +205,8 @@ msgstr "مفتوح"
#: templates/complaints/inquiry_list.html:42
#: templates/complaints/inquiry_list.html:73
#: templates/complaints/inquiry_list.html:145
#: templates/observations/observation_list.html:143
#: templates/observations/public_track.html:316
msgid "In Progress"
msgstr "قيد التنفيذ"
@ -225,6 +235,7 @@ msgstr "إجراءاتي"
#: templates/complaints/inquiry_list.html:65
#: templates/feedback/feedback_list.html:191
#: templates/journeys/instance_list.html:127
#: templates/observations/observation_list.html:186
#: templates/physicians/physician_list.html:57
msgid "Search"
msgstr "بحث"
@ -252,6 +263,11 @@ msgstr "العنوان، الوصف..."
#: templates/journeys/instance_list.html:144
#: templates/journeys/instance_list.html:211
#: templates/journeys/template_list.html:29
#: templates/observations/category_list.html:40
#: templates/observations/observation_detail.html:402
#: templates/observations/observation_list.html:194
#: templates/observations/observation_list.html:310
#: templates/observations/public_success.html:228
#: templates/organizations/department_list.html:19
#: templates/organizations/hospital_list.html:19
#: templates/organizations/patient_list.html:20
@ -275,6 +291,12 @@ msgstr "الحالة"
#: templates/complaints/complaint_list.html:201
#: templates/complaints/complaint_list.html:341
#: templates/config/routing_rules.html:31
#: templates/observations/convert_to_action.html:37
#: templates/observations/observation_list.html:207
#: templates/observations/observation_list.html:309
#: templates/observations/public_new.html:244
#: templates/observations/public_success.html:220
#: templates/observations/public_track.html:277
msgid "Severity"
msgstr "الخطورة"
@ -284,6 +306,7 @@ msgstr "الخطورة"
#: templates/complaints/complaint_list.html:213
#: templates/config/routing_rules.html:28
#: templates/feedback/feedback_form.html:230
#: templates/observations/convert_to_action.html:71
msgid "Priority"
msgstr "الأولوية"
@ -306,6 +329,13 @@ msgstr "الأولوية"
#: templates/feedback/feedback_form.html:192
#: templates/feedback/feedback_list.html:225
#: templates/feedback/feedback_list.html:323
#: templates/observations/convert_to_action.html:67
#: templates/observations/observation_detail.html:205
#: templates/observations/observation_list.html:219
#: templates/observations/observation_list.html:307
#: templates/observations/public_new.html:232
#: templates/observations/public_success.html:216
#: templates/observations/public_track.html:273
msgid "Category"
msgstr "الفئة"
@ -370,6 +400,10 @@ msgstr "المستشفى"
#: templates/dashboard/command_center.html:146
#: templates/feedback/feedback_form.html:256
#: templates/journeys/instance_list.html:166
#: templates/observations/observation_detail.html:363
#: templates/observations/observation_detail.html:394
#: templates/observations/observation_list.html:232
#: templates/observations/observation_list.html:312
#: templates/organizations/physician_list.html:19
#: templates/physicians/leaderboard.html:92
#: templates/physicians/leaderboard.html:137
@ -388,6 +422,9 @@ msgstr "القسم"
#: templates/complaints/complaint_list.html:266
#: templates/complaints/complaint_list.html:343
#: templates/complaints/inquiry_detail.html:149
#: templates/observations/observation_detail.html:367
#: templates/observations/observation_list.html:245
#: templates/observations/observation_list.html:313
msgid "Assigned To"
msgstr "تم الإسناد إلى"
@ -395,6 +432,7 @@ msgstr "تم الإسناد إلى"
#: templates/complaints/complaint_list.html:288
#: templates/feedback/feedback_list.html:274
#: templates/journeys/instance_list.html:178
#: templates/observations/observation_list.html:268
msgid "Date From"
msgstr "من التاريخ"
@ -402,6 +440,7 @@ msgstr "من التاريخ"
#: templates/complaints/complaint_list.html:292
#: templates/feedback/feedback_list.html:278
#: templates/journeys/instance_list.html:182
#: templates/observations/observation_list.html:272
msgid "Date To"
msgstr "إلى التاريخ"
@ -424,6 +463,7 @@ msgstr "المعرف"
#: templates/complaints/complaint_list.html:338
#: templates/feedback/feedback_form.html:172
#: templates/feedback/feedback_list.html:322
#: templates/observations/public_new.html:278
msgid "Title"
msgstr "العنوان"
@ -458,6 +498,8 @@ msgstr "تاريخ الإنشاء"
#: templates/feedback/feedback_list.html:329
#: templates/journeys/instance_list.html:213
#: templates/journeys/template_list.html:30
#: templates/observations/category_list.html:41
#: templates/observations/observation_list.html:314
#: templates/physicians/department_overview.html:123
#: templates/physicians/leaderboard.html:142
#: templates/physicians/physician_list.html:118
@ -474,6 +516,7 @@ msgstr "الإجراءات"
#: templates/appreciation/appreciation_list.html:160
#: templates/complaints/complaint_list.html:405
#: templates/feedback/feedback_list.html:400
#: templates/observations/observation_list.html:376
msgid "View"
msgstr "عرض"
@ -495,6 +538,7 @@ msgstr "قم بإجراء تحليل للمشاعر على أي نص"
#: templates/callcenter/inquiry_form.html:61
#: templates/complaints/inquiry_detail.html:16
#: templates/complaints/inquiry_form.html:16
#: templates/observations/observation_detail.html:178
msgid "Back to List"
msgstr "العودة إلى القائمة"
@ -700,6 +744,7 @@ msgstr "المشاعر"
#: templates/ai_engine/sentiment_dashboard.html:237
#: templates/ai_engine/sentiment_list.html:128
#: templates/callcenter/interaction_list.html:60
#: templates/observations/observation_list.html:306
msgid "Date"
msgstr "التاريخ"
@ -776,17 +821,20 @@ msgstr "إجمالي النتائج"
#: templates/ai_engine/sentiment_list.html:69
#: templates/complaints/inquiry_list.html:60
#: templates/observations/observation_list.html:174
msgid "Filters"
msgstr "عوامل التصفية"
#: templates/ai_engine/sentiment_list.html:96
#: templates/appreciation/leaderboard.html:75
#: templates/observations/observation_list.html:279
msgid "Apply Filters"
msgstr "تطبيق الفلاتر"
#: templates/ai_engine/sentiment_list.html:99
#: templates/complaints/inquiry_form.html:209
#: templates/complaints/inquiry_list.html:100
#: templates/observations/observation_list.html:282
#: templates/physicians/leaderboard.html:116
#: templates/physicians/physician_list.html:97
#: templates/physicians/ratings_list.html:84
@ -833,6 +881,7 @@ msgstr "الصفحة"
#: templates/ai_engine/sentiment_list.html:213
#: templates/callcenter/complaint_list.html:233
#: templates/callcenter/inquiry_list.html:225
#: templates/observations/observation_list.html:293
msgid "of"
msgstr "من"
@ -878,6 +927,8 @@ msgstr "إجمالي الإجراءات"
#: templates/complaints/inquiry_detail.html:122
#: templates/config/routing_rules.html:29 templates/config/sla_config.html:28
#: templates/journeys/template_list.html:25
#: templates/observations/observation_detail.html:261
#: templates/observations/public_new.html:356
#: templates/organizations/department_list.html:15
#: templates/organizations/hospital_list.html:15
#: templates/organizations/patient_list.html:15
@ -914,6 +965,7 @@ msgstr "تفاصيل التقدير"
#: templates/appreciation/category_list.html:11
#: templates/appreciation/leaderboard.html:11
#: templates/appreciation/my_badges.html:11
#: templates/layouts/partials/sidebar.html:81
msgid "Appreciation"
msgstr "التقدير"
@ -922,6 +974,9 @@ msgid "From"
msgstr "من"
#: templates/appreciation/appreciation_detail.html:49
#: templates/observations/observation_detail.html:158
#: templates/observations/observation_list.html:158
#: templates/observations/observation_list.html:354
msgid "Anonymous"
msgstr "مجهول"
@ -981,6 +1036,7 @@ msgstr "المعرف:"
#: templates/appreciation/leaderboard.html:25
#: templates/appreciation/leaderboard.html:207
#: templates/appreciation/my_badges.html:25
#: templates/layouts/partials/sidebar.html:97
msgid "Send Appreciation"
msgstr "إرسال تقدير"
@ -995,6 +1051,7 @@ msgstr "عرض قائمة التصنيفات"
#: templates/appreciation/my_badges.html:4
#: templates/appreciation/my_badges.html:12
#: templates/appreciation/my_badges.html:20
#: templates/layouts/partials/sidebar.html:111
msgid "My Badges"
msgstr "شاراتي"
@ -1023,6 +1080,7 @@ msgstr "الشارات المكتسبة"
#: templates/appreciation/appreciation_list.html:88
#: templates/appreciation/appreciation_list.html:111
#: templates/appreciation/leaderboard.html:12
#: templates/layouts/partials/sidebar.html:104
#: templates/physicians/physician_list.html:27
msgid "Leaderboard"
msgstr "قائمة التصنيفات"
@ -1053,6 +1111,7 @@ msgid "All Status"
msgstr "جميع الحالات"
#: templates/appreciation/appreciation_list.html:184
#: templates/observations/observation_list.html:221
msgid "All Categories"
msgstr "جميع الفئات"
@ -1239,6 +1298,7 @@ msgstr "الشارات"
#: templates/appreciation/badge_form.html:13
#: templates/appreciation/badge_list.html:69
#: templates/appreciation/category_form.html:13
#: templates/observations/category_list.html:78
msgid "Edit"
msgstr "تعديل"
@ -1250,12 +1310,16 @@ msgstr "إضافة"
#: templates/appreciation/badge_form.html:34
#: templates/appreciation/category_form.html:34
#: templates/appreciation/category_list.html:37
#: templates/observations/category_form.html:31
#: templates/observations/category_list.html:36
msgid "Name (English)"
msgstr "الاسم (بالإنجليزية)"
#: templates/appreciation/badge_form.html:49
#: templates/appreciation/category_form.html:49
#: templates/appreciation/category_list.html:38
#: templates/observations/category_form.html:39
#: templates/observations/category_list.html:37
msgid "Name (Arabic)"
msgstr "الاسم (بالعربية)"
@ -1272,6 +1336,8 @@ msgstr "الوصف (بالعربية)"
#: templates/appreciation/badge_form.html:87
#: templates/appreciation/category_form.html:87
#: templates/appreciation/category_list.html:36
#: templates/observations/category_form.html:56
#: templates/observations/category_list.html:38
msgid "Icon"
msgstr "الأيقونة"
@ -1295,6 +1361,8 @@ msgstr "عدد التقديرات المطلوبة للحصول على هذه ا
#: templates/appreciation/badge_list.html:61
#: templates/appreciation/category_form.html:124
#: templates/journeys/instance_list.html:85
#: templates/observations/category_form.html:81
#: templates/observations/category_list.html:70
#: templates/physicians/physician_detail.html:26
#: templates/physicians/physician_list.html:88
#: templates/physicians/physician_list.html:154
@ -1304,6 +1372,7 @@ msgstr "نشط"
#: templates/appreciation/badge_form.html:154
#: templates/appreciation/category_form.html:137
#: templates/observations/observation_detail.html:410
msgid "Update"
msgstr "تحديث"
@ -1385,6 +1454,7 @@ msgid "Status:"
msgstr "الحالة:"
#: templates/appreciation/badge_list.html:63
#: templates/observations/category_list.html:72
#: templates/physicians/physician_detail.html:28
#: templates/physicians/physician_list.html:89
#: templates/physicians/physician_list.html:156
@ -1392,6 +1462,7 @@ msgid "Inactive"
msgstr "غير نشط"
#: templates/appreciation/badge_list.html:72
#: templates/observations/category_list.html:86
msgid "Delete"
msgstr "حذف"
@ -1412,11 +1483,14 @@ msgstr "تعديل الفئة"
#: templates/appreciation/category_form.html:24
#: templates/appreciation/category_list.html:24
#: templates/appreciation/category_list.html:78
#: templates/observations/category_list.html:23
msgid "Add Category"
msgstr "إضافة فئة"
#: templates/appreciation/category_form.html:12
#: templates/appreciation/category_list.html:12
#: templates/observations/category_form.html:13
#: templates/observations/observation_list.html:98
msgid "Categories"
msgstr "الفئات"
@ -1464,6 +1538,7 @@ msgid "Count"
msgstr "العدد"
#: templates/appreciation/category_list.html:74
#: templates/observations/category_list.html:98
msgid "No categories found"
msgstr "لم يتم العثور على فئات"
@ -1528,6 +1603,7 @@ msgid "See your earned badges"
msgstr "عرض الشارات التي حصلت عليها"
#: templates/appreciation/leaderboard.html:231
#: templates/layouts/partials/sidebar.html:90
msgid "All Appreciations"
msgstr "جميع رسائل التقدير"
@ -1604,7 +1680,7 @@ msgstr "أظهر الابتكار"
#: templates/callcenter/complaint_form.html:60
#: templates/callcenter/complaint_form.html:271
#: templates/callcenter/complaint_list.html:40
#: templates/layouts/partials/sidebar.html:145
#: templates/layouts/partials/sidebar.html:200
msgid "Create Complaint"
msgstr "إنشاء شكوى"
@ -1614,7 +1690,7 @@ msgstr "إنشاء شكوى"
#: templates/callcenter/inquiry_form.html:5
#: templates/callcenter/inquiry_list.html:5
#: templates/callcenter/inquiry_success.html:5
#: templates/layouts/partials/sidebar.html:129
#: templates/layouts/partials/sidebar.html:184
msgid "Call Center"
msgstr "مركز الاتصال"
@ -1736,6 +1812,12 @@ msgstr "ملخص موجز للشكوى"
#: templates/callcenter/complaint_form.html:179
#: templates/complaints/complaint_form.html:121
#: templates/observations/category_form.html:47
#: templates/observations/convert_to_action.html:46
#: templates/observations/convert_to_action.html:61
#: templates/observations/observation_detail.html:189
#: templates/observations/observation_list.html:308
#: templates/observations/public_new.html:290
msgid "Description"
msgstr "الوصف"
@ -1801,23 +1883,31 @@ msgstr "اختر درجة الخطورة..."
#: templates/callcenter/complaint_form.html:220
#: templates/callcenter/complaint_form.html:234
#: templates/callcenter/complaint_list.html:121
#: templates/observations/observation_list.html:210
#: templates/observations/public_new.html:250
msgid "Low"
msgstr "منخفض"
#: templates/callcenter/complaint_form.html:221
#: templates/callcenter/complaint_form.html:235
#: templates/callcenter/complaint_list.html:120
#: templates/observations/observation_list.html:211
#: templates/observations/public_new.html:256
msgid "Medium"
msgstr "متوسط"
#: templates/callcenter/complaint_form.html:222
#: templates/callcenter/complaint_form.html:236
#: templates/callcenter/complaint_list.html:119
#: templates/observations/observation_list.html:212
#: templates/observations/public_new.html:262
msgid "High"
msgstr "مرتفع"
#: templates/callcenter/complaint_form.html:223
#: templates/callcenter/complaint_list.html:118
#: templates/observations/observation_list.html:213
#: templates/observations/public_new.html:268
msgid "Critical"
msgstr "حرج"
@ -1905,7 +1995,7 @@ msgstr "حدث خطأ أثناء البحث عن المرضى. يرجى المح
#: templates/callcenter/complaint_list.html:5
#: templates/complaints/analytics.html:221
#: templates/layouts/partials/sidebar.html:31
#: templates/layouts/partials/sidebar.html:159
#: templates/layouts/partials/sidebar.html:214
msgid "Complaints"
msgstr "الشكاوى"
@ -1927,6 +2017,7 @@ msgstr "الشكاوى المُقدمة عبر مركز الاتصال"
#: templates/complaints/inquiry_list.html:50
#: templates/complaints/inquiry_list.html:74
#: templates/complaints/inquiry_list.html:147
#: templates/observations/public_track.html:323
msgid "Resolved"
msgstr "تم الحل"
@ -1945,12 +2036,14 @@ msgstr "بحث..."
#: templates/complaints/inquiry_list.html:71
#: templates/complaints/inquiry_list.html:81
#: templates/complaints/inquiry_list.html:92
#: templates/observations/observation_list.html:260
msgid "All"
msgstr "الكل"
#: templates/callcenter/complaint_list.html:110
#: templates/callcenter/inquiry_list.html:106
#: templates/complaints/inquiry_list.html:75
#: templates/observations/public_track.html:330
msgid "Closed"
msgstr "مغلقة"
@ -2061,7 +2154,7 @@ msgstr "عرض جميع الشكاوى"
#: templates/callcenter/inquiry_form.html:230
#: templates/callcenter/inquiry_list.html:36
#: templates/complaints/inquiry_form.html:110
#: templates/layouts/partials/sidebar.html:152
#: templates/layouts/partials/sidebar.html:207
msgid "Create Inquiry"
msgstr "إنشاء استفسار"
@ -2214,7 +2307,7 @@ msgstr "لم يتم العثور على أي مرضى. يرجى إدخال بي
#: templates/complaints/inquiry_list.html:4
#: templates/complaints/inquiry_list.html:11
#: templates/layouts/partials/sidebar.html:48
#: templates/layouts/partials/sidebar.html:166
#: templates/layouts/partials/sidebar.html:221
msgid "Inquiries"
msgstr "الاستفسارات"
@ -2415,6 +2508,8 @@ msgid "Activity Timeline"
msgstr "الجدول الزمني للنشاط"
#: templates/complaints/complaint_detail.html:356
#: templates/observations/observation_detail.html:289
#: templates/observations/public_new.html:326
msgid "Attachments"
msgstr "المرفقات"
@ -2485,6 +2580,8 @@ msgstr "معلومات الاتصال"
#: templates/complaints/inquiry_detail.html:114
#: templates/complaints/inquiry_detail.html:126
#: templates/feedback/feedback_form.html:144
#: templates/observations/observation_detail.html:269
#: templates/observations/public_new.html:360
#: templates/organizations/hospital_list.html:18
#: templates/organizations/patient_list.html:17
#: templates/physicians/physician_detail.html:68
@ -2495,6 +2592,8 @@ msgstr "رقم الهاتف"
#: templates/complaints/inquiry_detail.html:118
#: templates/complaints/inquiry_detail.html:130
#: templates/feedback/feedback_form.html:137
#: templates/observations/observation_detail.html:275
#: templates/observations/public_new.html:364
#: templates/organizations/patient_list.html:18
#: templates/physicians/physician_detail.html:62
msgid "Email"
@ -2646,7 +2745,7 @@ msgid "Specialization"
msgstr "التخصص"
#: templates/dashboard/command_center.html:148
#: templates/layouts/partials/sidebar.html:96
#: templates/layouts/partials/sidebar.html:151
#: templates/physicians/department_overview.html:98
#: templates/physicians/department_overview.html:121
#: templates/physicians/leaderboard.html:139
@ -2825,19 +2924,27 @@ msgid "All Complaints"
msgstr "جميع الشكاوى"
#: templates/layouts/partials/sidebar.html:55
#: templates/layouts/partials/sidebar.html:189
#: templates/layouts/partials/sidebar.html:244
msgid "Analytics"
msgstr "التحليلات"
#: templates/layouts/partials/sidebar.html:77
#: templates/layouts/partials/sidebar.html:123
#: templates/observations/category_form.html:12
#: templates/observations/category_list.html:39
#: templates/observations/convert_to_action.html:12
#: templates/observations/observation_detail.html:140
msgid "Observations"
msgstr "الملاحظات"
#: templates/layouts/partials/sidebar.html:132
msgid "PX Actions"
msgstr "إجراءات تجربة المريض"
#: templates/layouts/partials/sidebar.html:87
#: templates/layouts/partials/sidebar.html:142
msgid "Patient Journeys"
msgstr "رحلات المرضى"
#: templates/layouts/partials/sidebar.html:105
#: templates/layouts/partials/sidebar.html:160
#: templates/organizations/physician_list.html:8
#: templates/physicians/department_overview.html:5
#: templates/physicians/department_overview.html:14
@ -2852,23 +2959,23 @@ msgstr "رحلات المرضى"
msgid "Physicians"
msgstr "الأطباء"
#: templates/layouts/partials/sidebar.html:116
#: templates/layouts/partials/sidebar.html:171
msgid "Organizations"
msgstr "المنظمات"
#: templates/layouts/partials/sidebar.html:138
#: templates/layouts/partials/sidebar.html:193
msgid "Interactions"
msgstr "التفاعلات"
#: templates/layouts/partials/sidebar.html:178
#: templates/layouts/partials/sidebar.html:233
msgid "Social Media"
msgstr "وسائل التواصل الاجتماعي"
#: templates/layouts/partials/sidebar.html:198
#: templates/layouts/partials/sidebar.html:253
msgid "QI Projects"
msgstr "مشاريع تحسين الجودة"
#: templates/layouts/partials/sidebar.html:210
#: templates/layouts/partials/sidebar.html:265
msgid "Configuration"
msgstr "الإعدادات"
@ -2892,6 +2999,311 @@ msgstr "الإعدادات"
msgid "Logout"
msgstr "تسجيل الخروج"
#: templates/observations/category_form.html:5
#: templates/observations/category_list.html:5
#: templates/observations/category_list.html:14
msgid "Observation Categories"
msgstr "فئات الملاحظات"
msgid "Bootstrap icon class, e.g., bi-exclamation-triangle"
msgstr "فئة أيقونة Bootstrap، مثل: bi-exclamation-triangle"
msgid "Browse icons"
msgstr "تصفح الأيقونات"
msgid "Sort Order"
msgstr "ترتيب الفرز"
msgid "Lower numbers appear first"
msgstr "الأرقام الأصغر تظهر أولاً"
msgid "Inactive categories won't appear in the public form"
msgstr "لن تظهر الفئات غير النشطة في النموذج العام"
msgid "Save Category"
msgstr "حفظ الفئة"
msgid "Manage categories for observation classification"
msgstr "إدارة الفئات لتصنيف الملاحظات"
msgid "Back to Observations"
msgstr "العودة إلى الملاحظات"
msgid "Order"
msgstr "الترتيب"
msgid "Are you sure you want to delete this category?"
msgstr "هل أنت متأكد من أنك تريد حذف هذه الفئة؟"
msgid "Add First Category"
msgstr "إضافة أول فئة"
msgid "Convert to Action"
msgstr "تحويل إلى إجراء"
msgid "Convert Observation to PX Action"
msgstr "تحويل الملاحظة إلى إجراء PX"
msgid "Observation Summary"
msgstr "ملخص الملاحظة"
msgid "Tracking Code"
msgstr "رمز التتبع"
msgid "Action Title"
msgstr "عنوان الإجراء"
msgid "A clear, actionable title for the PX Action"
msgstr "عنوان واضح وقابل للتنفيذ للإجراء PX"
msgid "Assign to Department"
msgstr "تعيين إلى القسم"
msgid "Assign to User"
msgstr "تعيين إلى المستخدم"
msgid "Create PX Action"
msgstr "إنشاء إجراء PX"
msgid "Observation Detail"
msgstr "تفاصيل الملاحظة"
msgid "Location"
msgstr "الموقع"
msgid "Incident Date/Time"
msgstr "تاريخ/وقت الحادثة"
msgid "Submitted"
msgstr "تم الإرسال"
msgid "Last Updated"
msgstr "آخر تحديث"
msgid "Triaged"
msgstr "تم الفرز"
msgid "Reporter Information"
msgstr "معلومات المبلّغ"
msgid "This observation was submitted anonymously"
msgstr "تم إرسال هذه الملاحظة بشكل مجهول"
msgid "Staff ID"
msgstr "معرّف الموظف"
msgid "Timeline"
msgstr "الجدول الزمني"
msgid "Status Changed"
msgstr "تم تغيير الحالة"
msgid "Note Added"
msgstr "تمت إضافة ملاحظة"
msgid "No timeline entries yet"
msgstr "لا توجد إدخالات في الجدول الزمني بعد"
msgid "Assignment"
msgstr "التعيين"
#: templates/observations/observation_detail.html:376
msgid "Linked PX Action"
msgstr "الإجراء المرتبط بـ PX"
msgid "View Action"
msgstr "عرض الإجراء"
msgid "Triage"
msgstr "فرز"
msgid "Note"
msgstr "ملاحظة"
msgid "Internal note (not visible to public)"
msgstr "ملاحظة داخلية (غير مرئية للعامة)"
msgid "Quick Status Change"
msgstr "تغيير سريع للحالة"
msgid "Observations Console"
msgstr "لوحة تحكم الملاحظات"
msgid "Manage and triage staff-reported observations"
msgstr "إدارة وفرز الملاحظات المُبلّغ عنها من قِبل الموظفين"
msgid "Public Form"
msgstr "النموذج العام"
msgid "New"
msgstr "جديد"
msgid "Tracking code, description..."
msgstr "رمز التتبع، الوصف..."
msgid "All Statuses"
msgstr "جميع الحالات"
msgid "All Severities"
msgstr "جميع درجات الخطورة"
msgid "All Users"
msgstr "جميع المستخدمين"
msgid "Reporter Type"
msgstr "نوع المُبلّغ"
msgid "Anonymous Only"
msgstr "مجهول فقط"
msgid "Identified Only"
msgstr "معرّف فقط"
msgid "Showing"
msgstr "عرض"
msgid "to"
msgstr "إلى"
msgid "observations"
msgstr "ملاحظات"
msgid "Reporter"
msgstr "المُبلّغ"
msgid "Unassigned"
msgstr "غير معيّن"
msgid "No observations found"
msgstr "لم يتم العثور على ملاحظات"
msgid "Report an Observation"
msgstr "الإبلاغ عن ملاحظة"
msgid "Help us improve by reporting issues you notice"
msgstr "ساعدنا في التحسين من خلال الإبلاغ عن المشكلات التي تلاحظها"
msgid "Anonymous Reporting"
msgstr "إبلاغ مجهول"
msgid ""
"You can submit this report anonymously. Providing your information is "
"optional but may help us follow up if needed."
msgstr "يمكنك إرسال هذا البلاغ بشكل مجهول. تقديم معلوماتك اختياري ولكنه قد يساعدنا في المتابعة إذا لزم الأمر."
msgid "optional"
msgstr "اختياري"
msgid "Please describe what you observed in detail."
msgstr "يرجى وصف ما لاحظته بالتفصيل."
msgid "When did this occur?"
msgstr "متى حدث ذلك؟"
msgid "Click to upload files"
msgstr "انقر لتحميل الملفات"
msgid "Images, PDF, Word, Excel (max 10MB each)"
msgstr "صور، PDF، Word، Excel (بحد أقصى 10MB لكل ملف)"
msgid "Your Information"
msgstr "معلوماتك الشخصية"
msgid ""
"Providing your information helps us follow up if needed. Leave blank to "
"submit anonymously."
msgstr "تقديم معلوماتك يساعدنا في المتابعة عند الحاجة. اتركها فارغة لتقديم البلاغ بشكل مجهول."
msgid "Submit Observation"
msgstr "إرسال الملاحظة"
msgid "Track an existing observation"
msgstr "تتبع ملاحظة موجودة"
msgid "Observation Submitted"
msgstr "تم إرسال الملاحظة"
msgid "Thank You!"
msgstr "شكرًا لك!"
msgid "Your observation has been submitted successfully."
msgstr "تم إرسال ملاحظتك بنجاح."
msgid "Your Tracking Code"
msgstr "رمز التتبع الخاص بك"
msgid "Copy Code"
msgstr "نسخ الرمز"
msgid "Important"
msgstr "مهم"
msgid "Save this tracking code to check the status of your observation."
msgstr "احفظ رمز التتبع هذا للتحقق من حالة ملاحظتك."
msgid "Our team will review your observation and take appropriate action."
msgstr "سيقوم فريقنا بمراجعة ملاحظتك واتخاذ الإجراء المناسب."
msgid "You can track your observation status anytime using the tracking code."
msgstr "يمكنك تتبع حالة ملاحظتك في أي وقت باستخدام رمز التتبع."
#: templates/observations/public_success.html:246
msgid "Track Status"
msgstr "تتبع الحالة"
msgid "Submit Another"
msgstr "إرسال ملاحظة أخرى"
msgid "Copied!"
msgstr "تم النسخ!"
msgid "Track Observation"
msgstr "تتبع الملاحظة"
msgid "Track Your Observation"
msgstr "تتبع ملاحظتك"
msgid "Enter your tracking code to check the status"
msgstr "أدخل رمز التتبع للتحقق من الحالة"
msgid "e.g., OBS-ABC123"
msgstr "مثال: OBS-ABC123"
msgid "Track"
msgstr "تتبع"
msgid "Status Progress"
msgstr "تقدم الحالة"
msgid "Assigned"
msgstr "تم التعيين"
msgid "Being reviewed by our team"
msgstr "قيد المراجعة من قبل فريقنا"
msgid "Action is being taken"
msgstr "يتم اتخاذ إجراء"
msgid "Rejected"
msgstr "مرفوض"
msgid "This observation was not accepted"
msgstr "لم يتم قبول هذه الملاحظة"
msgid "Duplicate"
msgstr "مكررة"
msgid "This observation was marked as duplicate"
msgstr "تم تحديد هذه الملاحظة كمكررة"
msgid ""
"For privacy reasons, detailed notes and internal communications are not "
"shown here."
msgstr "لأسباب تتعلق بالخصوصية، لا يتم عرض الملاحظات التفصيلية والمراسلات الداخلية هنا."
msgid "Submit a new observation"
msgstr "إرسال ملاحظة جديدة"
#: templates/organizations/department_list.html:8
msgid "Departments"
msgstr "الأقسام"
@ -2982,12 +3394,6 @@ msgstr "إجمالي الأطباء"
msgid "Excellent (4.5+)"
msgstr "ممتاز (4.5+)"
#: templates/physicians/leaderboard.html:94
#: templates/physicians/physician_list.html:76
#: templates/physicians/ratings_list.html:71
msgid "All Departments"
msgstr "جميع الأقسام"
#: templates/physicians/leaderboard.html:103
msgid "Limit"
msgstr "الحد"

View File

@ -1,17 +1,30 @@
{% load i18n %}
{% load static %}
{% get_current_language as LANGUAGE_CODE %}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<html lang="{{ LANGUAGE_CODE }}" dir="{% if LANGUAGE_CODE == 'ar' %}rtl{% else %}ltr{% endif %}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% trans "Report an Observation" %} - Al Hammadi</title>
<!-- Bootstrap CSS -->
{% if LANGUAGE_CODE == 'ar' %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.rtl.min.css" rel="stylesheet">
{% else %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
{% endif %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
<!-- Arabic Font -->
<link href="https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap" rel="stylesheet">
<style>
{% if LANGUAGE_CODE == 'ar' %}
body {
font-family: 'Tajawal', sans-serif;
}
{% endif %}
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
@ -106,9 +119,79 @@
font-size: 2rem;
color: #667eea;
}
.language-switcher {
position: absolute;
top: 20px;
{% if LANGUAGE_CODE == 'ar' %}
left: 20px;
{% else %}
right: 20px;
{% endif %}
}
.language-switcher .btn {
background: rgba(255,255,255,0.9);
border: none;
padding: 8px 16px;
border-radius: 20px;
font-weight: 500;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
transition: all 0.2s;
}
.language-switcher .btn:hover {
background: white;
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(0,0,0,0.15);
}
.language-switcher .dropdown-menu {
min-width: 120px;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0,0,0,0.15);
}
.language-switcher .dropdown-item {
padding: 10px 20px;
}
.language-switcher .dropdown-item:hover {
background: #f0f3ff;
}
.language-switcher .dropdown-item.active {
background: #667eea;
color: white;
}
</style>
</head>
<body>
<!-- Language Switcher -->
<div class="language-switcher">
<div class="dropdown">
<button class="btn dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-globe me-1"></i>
{% if LANGUAGE_CODE == 'ar' %}العربية{% else %}English{% endif %}
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input type="hidden" name="language" value="en">
<input type="hidden" name="next" value="{{ request.path }}">
<button type="submit" class="dropdown-item {% if LANGUAGE_CODE == 'en' %}active{% endif %}">
<span class="me-2">🇬🇧</span> English
</button>
</form>
</li>
<li>
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input type="hidden" name="language" value="ar">
<input type="hidden" name="next" value="{{ request.path }}">
<button type="submit" class="dropdown-item {% if LANGUAGE_CODE == 'ar' %}active{% endif %}">
<span class="me-2">🇸🇦</span> العربية
</button>
</form>
</li>
</ul>
</div>
</div>
<div class="container">
<div class="form-container">
<!-- Header -->

View File

@ -1,17 +1,30 @@
{% load i18n %}
{% load static %}
{% get_current_language as LANGUAGE_CODE %}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<html lang="{{ LANGUAGE_CODE }}" dir="{% if LANGUAGE_CODE == 'ar' %}rtl{% else %}ltr{% endif %}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% trans "Observation Submitted" %} - Al Hammadi</title>
<!-- Bootstrap CSS -->
{% if LANGUAGE_CODE == 'ar' %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.rtl.min.css" rel="stylesheet">
{% else %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
{% endif %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
<!-- Arabic Font -->
<link href="https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap" rel="stylesheet">
<style>
{% if LANGUAGE_CODE == 'ar' %}
body {
font-family: 'Tajawal', sans-serif;
}
{% endif %}
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
@ -82,14 +95,84 @@
border-radius: 8px;
padding: 15px;
margin-top: 20px;
text-align: left;
text-align: {% if LANGUAGE_CODE == 'ar' %}right{% else %}left{% endif %};
}
.info-card i {
color: #0056b3;
}
.language-switcher {
position: absolute;
top: 20px;
{% if LANGUAGE_CODE == 'ar' %}
left: 20px;
{% else %}
right: 20px;
{% endif %}
}
.language-switcher .btn {
background: rgba(255,255,255,0.9);
border: none;
padding: 8px 16px;
border-radius: 20px;
font-weight: 500;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
transition: all 0.2s;
}
.language-switcher .btn:hover {
background: white;
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(0,0,0,0.15);
}
.language-switcher .dropdown-menu {
min-width: 120px;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0,0,0,0.15);
}
.language-switcher .dropdown-item {
padding: 10px 20px;
}
.language-switcher .dropdown-item:hover {
background: #f0f3ff;
}
.language-switcher .dropdown-item.active {
background: #667eea;
color: white;
}
</style>
</head>
<body>
<!-- Language Switcher -->
<div class="language-switcher">
<div class="dropdown">
<button class="btn dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-globe me-1"></i>
{% if LANGUAGE_CODE == 'ar' %}العربية{% else %}English{% endif %}
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input type="hidden" name="language" value="en">
<input type="hidden" name="next" value="{{ request.path }}">
<button type="submit" class="dropdown-item {% if LANGUAGE_CODE == 'en' %}active{% endif %}">
<span class="me-2">🇬🇧</span> English
</button>
</form>
</li>
<li>
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input type="hidden" name="language" value="ar">
<input type="hidden" name="next" value="{{ request.path }}">
<button type="submit" class="dropdown-item {% if LANGUAGE_CODE == 'ar' %}active{% endif %}">
<span class="me-2">🇸🇦</span> العربية
</button>
</form>
</li>
</ul>
</div>
</div>
<div class="success-container">
<!-- Success Icon -->
<div class="success-icon">
@ -131,7 +214,7 @@
<table class="table table-sm">
<tr>
<td class="text-muted">{% trans "Category" %}</td>
<td>{{ observation.category.name_en|default:"Not specified" }}</td>
<td>{{ observation.category.name|default:"Not specified" }}</td>
</tr>
<tr>
<td class="text-muted">{% trans "Severity" %}</td>

View File

@ -1,17 +1,30 @@
{% load i18n %}
{% load static %}
{% get_current_language as LANGUAGE_CODE %}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<html lang="{{ LANGUAGE_CODE }}" dir="{% if LANGUAGE_CODE == 'ar' %}rtl{% else %}ltr{% endif %}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% trans "Track Observation" %} - Al Hammadi</title>
<!-- Bootstrap CSS -->
{% if LANGUAGE_CODE == 'ar' %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.rtl.min.css" rel="stylesheet">
{% else %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
{% endif %}
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
<!-- Arabic Font -->
<link href="https://fonts.googleapis.com/css2?family=Tajawal:wght@400;500;700&display=swap" rel="stylesheet">
<style>
{% if LANGUAGE_CODE == 'ar' %}
body {
font-family: 'Tajawal', sans-serif;
}
{% endif %}
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
@ -72,13 +85,21 @@
}
.status-timeline {
position: relative;
{% if LANGUAGE_CODE == 'ar' %}
padding-right: 30px;
{% else %}
padding-left: 30px;
{% endif %}
margin-top: 20px;
}
.status-timeline::before {
content: '';
position: absolute;
{% if LANGUAGE_CODE == 'ar' %}
right: 10px;
{% else %}
left: 10px;
{% endif %}
top: 0;
bottom: 0;
width: 2px;
@ -94,7 +115,11 @@
.timeline-item::before {
content: '';
position: absolute;
{% if LANGUAGE_CODE == 'ar' %}
right: -24px;
{% else %}
left: -24px;
{% endif %}
top: 5px;
width: 12px;
height: 12px;
@ -123,9 +148,79 @@
.status-closed { background: #f5f5f5; color: #616161; }
.status-rejected { background: #ffebee; color: #d32f2f; }
.status-duplicate { background: #f5f5f5; color: #616161; }
.language-switcher {
position: absolute;
top: 20px;
{% if LANGUAGE_CODE == 'ar' %}
left: 20px;
{% else %}
right: 20px;
{% endif %}
}
.language-switcher .btn {
background: rgba(255,255,255,0.9);
border: none;
padding: 8px 16px;
border-radius: 20px;
font-weight: 500;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
transition: all 0.2s;
}
.language-switcher .btn:hover {
background: white;
transform: translateY(-2px);
box-shadow: 0 4px 15px rgba(0,0,0,0.15);
}
.language-switcher .dropdown-menu {
min-width: 120px;
border-radius: 10px;
box-shadow: 0 5px 20px rgba(0,0,0,0.15);
}
.language-switcher .dropdown-item {
padding: 10px 20px;
}
.language-switcher .dropdown-item:hover {
background: #f0f3ff;
}
.language-switcher .dropdown-item.active {
background: #667eea;
color: white;
}
</style>
</head>
<body>
<!-- Language Switcher -->
<div class="language-switcher">
<div class="dropdown">
<button class="btn dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-globe me-1"></i>
{% if LANGUAGE_CODE == 'ar' %}العربية{% else %}English{% endif %}
</button>
<ul class="dropdown-menu dropdown-menu-end">
<li>
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input type="hidden" name="language" value="en">
<input type="hidden" name="next" value="{{ request.path }}">
<button type="submit" class="dropdown-item {% if LANGUAGE_CODE == 'en' %}active{% endif %}">
<span class="me-2">🇬🇧</span> English
</button>
</form>
</li>
<li>
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input type="hidden" name="language" value="ar">
<input type="hidden" name="next" value="{{ request.path }}">
<button type="submit" class="dropdown-item {% if LANGUAGE_CODE == 'ar' %}active{% endif %}">
<span class="me-2">🇸🇦</span> العربية
</button>
</form>
</li>
</ul>
</div>
</div>
<div class="track-container">
<!-- Header -->
<div class="logo-header">
@ -176,7 +271,7 @@
<div class="row g-3">
<div class="col-6">
<small class="text-muted d-block">{% trans "Category" %}</small>
<strong>{{ observation.category.name_en|default:"Not specified" }}</strong>
<strong>{{ observation.category.name|default:"Not specified" }}</strong>
</div>
<div class="col-6">
<small class="text-muted d-block">{% trans "Severity" %}</small>