بناء من الصفر على باك إند NestJS، بقرار المالك 2026-08-04 الذي يعكس قرارَي نقل GetX (2026-07-21) واعتماد باك إند PHP (2026-07-27). لا يُورَّث سطر دارت من apps/*-archive-cubit، وسيرو مرجع بصري وسلوكي لا مصدر نسخ. الوثائق: - docs/37: الخطة الكاملة بستّ مراحل وبواباتها - docs/38: عقد الـAPI من 37 controller، معظمه متحقَّق حيّاً من السيرفر المنشور - docs/39: جرد 202 شاشة في تطبيقَي سيرو، مصنّفة داخل/خارج النطاق الطبقة الأصلية منقولة من *-archive-cubit وحدها لأنها هوية النشر: - rider_new → com.mobileapp.store.ride · shorebird 496cb3ac - driver_new → com.sefer_driver (أندرويد) · com.sefer.driver (iOS) · 68cc9345 - أُصلح تعارض: هدف RunnerTests في driver_new كان يحمل bundle الراكب الأصول مصدرها *-archive-cubit لا سيرو: أصول الأرشيف مجموعة أشمل (كل صور سيرو + صور تريبز) وخطوطها هي خطوط docs/26. استُكمل السائق بعشرة ملفات ناقصة من سيرو (شعارات مزوّدي الدفع + صوتان). lib/ مكتوب من الصفر (11 ملف لكل تطبيق): - AppConfig بأعلام const — أساس نموذج lite/pro/max - TokenStore على التخزين الآمن، يقرأ exp محليّاً بلا حزمة خارجية - AuthInterceptor بتجديد استباقي وطلقة واحدة — عمر التوكن 15 دقيقة فقط - ApiClient و ApiException يفهم مصفوفة message في NestJS flutter analyze نظيف في التطبيقين. البناء الفعلي لم يُجرَّب بعد: بوابة المرحلة 1 تتطلّب البناء على السيرفر، والوصول إليه غير متاح حالياً. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
197 lines
12 KiB
Markdown
197 lines
12 KiB
Markdown
# 39 — جرد شاشات سيرو: المرجع البصري والسلوكي
|
|
|
|
الغرض: هذا **ما نبني عليه الشكل والترتيب** في `rider_new` و`driver_new`
|
|
(م0.3 من `docs/37`). المصدر: `~/development/App/Siro/siro_rider` و`siro_driver`.
|
|
|
|
> **قاعدة الاستخدام**: هذا الملف يجيب على «ما هي الشاشة، وما ترتيب خطواتها،
|
|
> وأي حالة حافة عولجت ميدانياً». **لا يُنسخ ملف دارت واحد من سيرو.**
|
|
> شكل الواجهة يُعاد بناؤه على `docs/26` بجودة أعلى، والعقد من `docs/38`.
|
|
|
|
---
|
|
|
|
## 1. المخزون — الحجم الحقيقي
|
|
|
|
| | شاشات/ويدجت | ملاحظة |
|
|
|---|---|---|
|
|
| `siro_rider/lib/views` | 89 ملف | يشمل الطعام والنقل العام |
|
|
| `siro_driver/lib/views` | 113 ملف | يشمل التوصيل والتلعيب والإحصاءات |
|
|
|
|
**ليس كله في النطاق.** خارج نطاق `docs/37` تماماً: `food/`, `food_delivery/`,
|
|
`transit/`, `gamification/`, `assurance_health_page`, `siro_prime_page`,
|
|
`android_bot`. هذي تُقرأ لاحقاً عند وحدات `docs/33` المدفوعة، لا الآن.
|
|
|
|
**داخل النطاق** (م1–م6): المصادقة · الخريطة وطلب الرحلة · مسار الرحلة ·
|
|
المحفظة · الدراور والملف · الإشعارات · التقييم.
|
|
|
|
---
|
|
|
|
## 2. المصادقة — مرجع م3
|
|
|
|
### التسلسل في سيرو (متطابق في التطبيقين)
|
|
|
|
```
|
|
موافقة الشروط → إذن الموقع → رقم الهاتف → OTP → [تسجيل] → الرئيسية
|
|
```
|
|
|
|
بوابتان **قبل** أي حقل إدخال، وكل واحدة شاشة كاملة لا حوار:
|
|
|
|
1. **صفحة الموافقة** (`_buildAgreementPage`): نصّ الاتفاقية بـHTML من الخادم،
|
|
مربّع اختيار، وزر متابعة **معطّل حتى يُؤشَّر**. تُحفظ
|
|
(`BoxName.agreeTerms == 'agreed'`) ولا تتكرر.
|
|
2. **صفحة إذن الموقع**: تطلب الإذن، ومعها زر `openAppSettings()` للحالة التي
|
|
يرفض فيها المستخدم نهائياً. تطبيق السائق يراقب دورة حياة التطبيق
|
|
(`WidgetsBindingObserver` + `didChangeAppLifecycleState`) ليعيد الفحص عند
|
|
**العودة من إعدادات النظام** — بلا هذا تبقى الشاشة عالقة. حالة حافة حقيقية
|
|
لازم تُنقل.
|
|
|
|
### شاشة الهاتف
|
|
- `IntlPhoneField` مع مفتاح دولة افتراضي من `BoxName.countryCode`.
|
|
- تحقّقات مطبّقة: فارغ · **يبدأ بصفر → رفض** («أدخل بلا الصفر») · أقصر من 10.
|
|
- الرقم يُرسل بلا `+`.
|
|
|
|
### شاشة الـOTP
|
|
- **3 خانات** في سيرو، حقل واحد بتباعد حروف كبير + ثلاث نقاط تقدّم متحرّكة.
|
|
- ⚠️ **تريبز يستخدم 4 خانات** (`docs/38`). الشكل يُقلَّد، الطول لا.
|
|
- ⚠️ **لا يوجد عدّاد إعادة إرسال ولا زر «إعادة الإرسال» في سيرو.** هذه
|
|
**فجوة، لا مرجع**: تريبز يحدّ `send-otp` بـ3 طلبات/5 دقائق، فبلا عدّاد
|
|
تنازلي يُحظر المستخدم بثلاث ضغطات. **لازم نضيفها.**
|
|
|
|
### شاشة التسجيل
|
|
الاسم الأول · الأخير · البريد. ⚠️ عقد تريبز يقبل `{ name, language }` فقط
|
|
(`PATCH /users/me`) — حقل اسم واحد. لا تُنقل الحقول كما هي.
|
|
|
|
### فروق تطبيق السائق
|
|
مسار إضافي بعد الدخول: `registration_view` (تسجيل السائق) →
|
|
`pending_driver_page` (شاشة «قيد المراجعة») → `camera_lisence_page` /
|
|
`text_scanner` / `passportimage` (تصوير الوثائق) → `cars_inserting_page`.
|
|
يقابلها في تريبز: `/drivers/apply` → `/drivers/profile` →
|
|
`/drivers/documents` → `/vehicles`، **ثم إعادة دخول إجبارية** لأن الدور
|
|
يتغيّر بعد الاعتماد (مصيدة `docs/38` §5).
|
|
|
|
### ما لا يُنقل من طبقة مصادقة سيرو
|
|
`login_controller.dart` فيه JWT مزدوج (توكن عام + `walletJwt` منفصل)، وقفل
|
|
تزامن ساكن، وعدّاد إخفاقات، وفكّ base64 يدوي للـpayload. **هذا تعقيد مفروض
|
|
من باك إند PHP**، وتريبز عنده `access_token`/`refresh_token` واحد. لا يُنقل.
|
|
المُنقَل هو الفكرة الصالحة: **تجديد واحد متزامن لا يتضاعف عند تعدد الطلبات**.
|
|
|
|
---
|
|
|
|
## 3. الخريطة وطلب الرحلة — مرجع م4
|
|
|
|
أنضج جزء في سيرو، وأدقّ ما نأخذه منه. الوحدة: `views/home/route_planner/`
|
|
(10 ملفات، 1,928 سطراً) + `views/home/map_widget.dart/`.
|
|
|
|
### البنية: خريطة ثابتة + ورقة سفلية بثلاث حالات
|
|
1. **مطوية** (`_Collapsed`) — بطاقة «إلى أين؟» فقط.
|
|
2. **موسّعة** (`_Expanded`) — المخطّط الكامل.
|
|
3. **اختيار من الخريطة** (`RpMapPickOverlay`) — الورقة تنزوي، ودبّوس ثابت في
|
|
المنتصف (`rp_center_pin`) والخريطة تتحرك تحته. النمط الصحيح: **المستخدم
|
|
يحرّك الخريطة لا الدبّوس.**
|
|
|
|
### ترتيب المخطّط الموسّع (من أعلى لأسفل)
|
|
ترويسة → **مبدّل نوع الطلب** (لنفسي ⇄ لشخص آخر) → **الخط الزمني للمسار**
|
|
(المصدر · محطات وسيطة · الوجهة) → **وصول سريع** (المنزل/العمل) → **متقدّم**.
|
|
|
|
- المصدر افتراضياً = الموقع الحالي، وقابل للتغيير من الخريطة.
|
|
- عند «لشخص آخر» يتبدّل حقل المصدر فوراً (`rp_sheet.dart:509`).
|
|
- **المحطات الوسيطة** صفوف قابلة للإضافة/الحذف — يقابلها `stops[]` في
|
|
`POST /trips` (`docs/38` §4). موجودة في الطرفين.
|
|
- المفضّلات (`rp_favorites`) والبحث (`rp_search_dialog` + `rp_search_results`).
|
|
|
|
### نافذة البحث عن سائق (`searching_captain_window`)
|
|
- أنيميشن رادار (دورة ثانيتين) + نصّ الحالة من الكنترولر + مؤشّر دوّار.
|
|
- **لا مقبض سحب** — لا تُغلق بالسحب، **فقط بزر «إلغاء البحث»**. قرار تصميمي
|
|
صحيح يُنقل: المستخدم لا يزيح شاشة البحث بالخطأ.
|
|
- الويدجت «غبي» بلا منطق؛ المؤقّت في الكنترولر هو من يقرر متى يعرض حوار
|
|
زيادة الأجرة. **يقابل مباشرةً** مصيدة `docs/38` §4: `expired`/`no_drivers`
|
|
قد لا يصلان من الخادم → **المهلة المحليّة إلزامية**. سيرو عالجها؛ نكرّرها.
|
|
|
|
### بطاقة الرحلة الجارية (`apply_order_widget`, 871 سطراً)
|
|
ترويسة مضغوطة · بطاقة معلومات · **شارة السائق** · **لوحة مركبة مرسومة** ·
|
|
أيقونة سيارة متحرّكة · صف أزرار · حقل رسالة مخصّصة · مؤشّرا
|
|
«وصل السائق وينتظر ن دقيقة» و«الوقت المتبقّي للوصول».
|
|
هذي المكوّنات هي ما يجعل الشاشة تبدو احترافية — تُعاد بناؤها في
|
|
`packages/tripz_ui`، لا تُنسخ.
|
|
|
|
### شاشات مساندة
|
|
`payment_method_page` · `cash_confirm_bottom_page` · `cancel_raide_page`
|
|
(أسباب الإلغاء) · `ride_begin_passenger` · `car_details_widget_to_go` ·
|
|
`trip_monitor` + `trip_link_monitor` (مشاركة رابط تتبّع) ·
|
|
`voice_call_bottom_sheet` (WebRTC — يقابل `call:*` في `docs/38` §9).
|
|
|
|
### شاشة السائق (`order_request_page`, 468 سطراً)
|
|
خريطة → **كبسولة «الوصول للراكب»** → بطاقة سفلية:
|
|
`الراكب + السعر` → `شريط معلومات (المسافة/المدة)` → `العناوين` → `الأزرار`.
|
|
- **حالة تحميل صريحة** إن وصل العرض بلا بيانات كاملة — لا شاشة فارغة.
|
|
- `order_over_lay.dart` (847 سطراً) = العرض المنبثق فوق أي شاشة. يقابل
|
|
`trip:offer` و`trip:offer_taken` في `docs/38` §9.
|
|
- ⚠️ شارة `driverEarningsExtra` تعتمد حقولاً من `add_ride.php` (باك إند PHP)
|
|
**غير موجودة في عقد NestJS** — تُسقط أو يُضاف لها حقل في الخادم. مثال حيّ
|
|
على أن سيرو ليس مطابقاً للعقد.
|
|
|
|
---
|
|
|
|
## 4. المحفظة — مرجع م5
|
|
|
|
| الراكب | السائق |
|
|
|---|---|
|
|
| `passenger_wallet` · `payment_history_passenger_page` · `cliq_payment_sheet` · `payment_screen_cliq/mtn/sham` | `walet_captain` · `pay_out_screen` · `weekly_payment_page` · `transfer_budget_page` · `points_captain` · `ecash` · `bank_account_egypt` |
|
|
|
|
محفظة السائق مقسّمة لويدجت جاهزة (`balance_card` ·
|
|
`financial_summary_card` · `quick_actions` · `transaction_preview_item`) —
|
|
تفكيك جيد يُحتذى.
|
|
|
|
⚠️ **مصيدتان**:
|
|
1. سيرو يخلط محفظة الراكب والسائق في تصميم واحد. تريبز يفصلهما (التزام مقابل
|
|
إيراد) — لا تُوحَّد الشاشة.
|
|
2. `pay_out_screen` في سيرو **خطوة واحدة**؛ تريبز **خطوتان** مع OTP
|
|
(`docs/38` §6). الشاشة تُعاد تصميمها لا تُقلَّد.
|
|
|
|
---
|
|
|
|
## 5. الدراور والملف والإشعارات — مرجع م6
|
|
|
|
**الراكب**: `drawer_menu_page` · `passenger_profile_page` · `order_history` ·
|
|
`setting_page` · `languages` · `about_page` · `contact_us` ·
|
|
`frequentlyQuestionsPage` · `share_app_page` · `complaint_page` ·
|
|
`promos_passenger_page` · `taarif_page` · `notification_page` ·
|
|
`rate_captain` + `rating_driver_bottom`.
|
|
|
|
**السائق**: `drawer_captain` · `bottom_bar` (تنقّل سفلي — الراكب بلا) ·
|
|
`profile_captain` · `captains_cars` · `history_captain` +
|
|
`history_details_page` · `settings_captain` · `behavior_page` ·
|
|
`feed_back_page` · `help_captain` + `help_details_replay_page` ·
|
|
`available_rides_page` · `statistics_dashboard` (+6 ويدجت رسوم) ·
|
|
`rate_passenger` · `ride_calculate_driver` · `sos_connect` (استغاثة).
|
|
|
|
**شاشة التقييم مهمة معمارياً**: تُفرض عند فتح التطبيق عبر
|
|
`GET /trips/rating/pending` (`docs/38` §7) — تُبنى في م5 لا م6.
|
|
|
|
---
|
|
|
|
## 6. الويدجت المشتركة — مدخل `packages/tripz_ui`
|
|
|
|
الملفات نفسها **مكرّرة حرفياً** في التطبيقين:
|
|
`circle_container` · `elevated_btn` · `error_snakbar` · `icon_widget_menu` ·
|
|
`my_circular_indicator_timer` · `my_scafold` · `my_textField` · `mycircular` ·
|
|
`mydialoug` · `voice_call_bottom_sheet`.
|
|
|
|
**هذا بالضبط ما تحلّه `packages/tripz_ui`** (م2.11): ازدواج مؤكَّد في سيرو،
|
|
لا يتكرر عندنا.
|
|
|
|
---
|
|
|
|
## 7. ملاحظات أداء — مادة قائمة الممنوعات (م2.12)
|
|
|
|
من قراءة سيرو، هذي أنماط تُتجنّب في `*_new`:
|
|
- `Get.put()` داخل `build()` (`login_page.dart:27`) — حقن عند كل إعادة بناء.
|
|
- ملفات ويدجت تتجاوز 800 سطر (`apply_order_widget` 871 ·
|
|
`order_over_lay` 847 · `home_captin` 840) — تفكّك.
|
|
- `GetBuilder` يلفّ الشاشة كاملة → إعادة بناء الشجرة كلها عند أي تحديث.
|
|
البديل: `BlocSelector`/`buildWhen` على أصغر جزء.
|
|
- منطق داخل الويدجت. النمط الصحيح موجود في سيرو نفسه
|
|
(`searching_captain_window` «غبي» والمؤقّت في الكنترولر) — يُعمَّم.
|
|
|
|
> قائمة الممنوعات النهائية تُستكمل في م2 بعد تشخيص `*-archive-cubit` نفسه —
|
|
> فسبب الأداء المرفوض هناك، لا هنا.
|