# قسم التصافي في التطبيق — ملف تسليم لمطوّر الموبايل (2026-11-05)

> العقد الكامل بالإنكليزية: `docs/api/custom-home-sections.md` (القسم 2a). هذا الملف يشرح ما يلزم التطبيق فقط.

## 1. ما الذي تغيّر

- **قبل:** كانت هناك عدة "صفقات" (flash deals)، لكل صفقة تاريخ بداية ونهاية واحد لكل منتجاتها، وكانت تُعرض في مكان ثابت من الصفحة الرئيسية.
- **الآن:** صارت **قسماً واحداً** من أقسام الصفحة الرئيسية اسمه "التصافي"، ونوعه `flash_deal`.
  - لكل منتج في القسم **خصمه الخاص، وبدايته ونهايته الخاصة**.
  - الفريق يتحكم بمكان القسم ولونه واسمه، ويستطيع إخفاءه، كأي قسم آخر.
- **لا توجد endpoints جديدة.** القسم يأتي مع `GET /api/v2/home-sections` الذي يستعمله التطبيق أصلاً. الجديد فقط مفتاحان مضافان على كل منتج من هذا القسم.

## 2. أين يأتي القسم

`GET /api/v2/home-sections`، أو المجموعة `custom_home_sections` في `POST /api/v2/app/data`:

```json
{
  "data": [
    {
      "id": 8,
      "title": "التصافي",
      "title_ar": "التصافي",
      "title_en": "Flash Sale",
      "type": "flash_deal",
      "products": [
        {
          "id": 120,
          "slug": "...",
          "name": "...",
          "thumbnail_image": "https://...",
          "has_discount": true,
          "discount": "-15%",
          "stroked_price": "1,200 ل.س",
          "main_price": "1,020 ل.س",
          "current_stock": 7,
          "...": "...",
          "offer_starts_at": 1762300800,
          "offer_ends_at": 1762387200
        }
      ],
      "links": {
        "all": "https://kapitano.shop/api/v2/home-sections/8/products",
        "web": "https://kapitano.shop/section/flash-sale"
      }
    }
  ],
  "layout": ["featured_categories", "custom_8", "custom_16", "..."],
  "backgrounds": { "custom_8": { "color": null, "title_color": "#1b1b28" } }
}
```

- **مكانه في الصفحة:** يحدده المفتاح `custom_<id>` في `layout`، كباقي الأقسام. **لا تعتمد على رقم `id` ثابت**، واعرف القسم من `type == "flash_deal"`.
- **عرض الكل:** `links.all`، وهو `GET /api/v2/home-sections/{id}/products?page=N`، بنفس شكل الكرت ومع المفتاحين نفسيهما. ويقبل الـ slug أيضاً: `home-sections/flash-sale/products`.
- **إن لم يكن هناك عرض ساري الآن**، أو أخفى الفريق القسم، فلن يأتي في `data`. إن وجدت مفتاحه في `layout` دون قسم مقابل في `data`، فتجاهله ولا ترسم مكاناً فارغاً.

## 3. المفتاحان الجديدان على كرت المنتج

| المفتاح | النوع | المعنى |
|---|---|---|
| `offer_starts_at` | int، ثوانٍ Unix | متى بدأ عرض هذا المنتج |
| `offer_ends_at` | int، ثوانٍ Unix | متى ينتهي عرض هذا المنتج |

- **يظهران على منتجات هذا القسم فقط.** باقي الأقسام والقوائم لا تحملهما، فلا يتغير شيء فيها.
- **القسم يرسل فقط العروض السارية الآن.** العرض الذي لم يبدأ بعد لا يُرسل، والعرض الذي انتهى لا يُرسل.
- **حقول السعر هي سعر العرض نفسه:** `main_price` و`stroked_price` و`discount` و`has_discount`. لا تحسب أي سعر في التطبيق.
- **السلة والطلب** يأخذان سعر العرض تلقائياً من الخادم ما دام العرض سارياً.

## 4. شكل الكرت (كما صار على الموقع)

- **القسم والكرت مثل باقي الأقسام تماماً:**
  - نفس حجم الكرت، ونفس العنوان وزر "عرض الكل".
  - الخلفية من `backgrounds["custom_<id>"]` كأي قسم، ونفس ألوان التطبيق.
- **بجانب عنوان القسم:** شارة صفراء `#ffc519` بنص كحلي `#1A1255`: "أقرب عرض ينتهي بعد" ثم الوقت المتبقي.
  - الوقت المتبقي هو إلى أقرب `offer_ends_at` بين منتجات القسم.
  - حين ينتهي ذلك العرض، تنتقل الشارة إلى العرض التالي.
  - على الهاتف تكفي الأيقونة والوقت.
- **تحت السعر في كل كرت:**
  - "وفّر X ل.س"، أي الفرق بين `stroked_price` و`main_price`؛
  - "بقي N فقط" إذا كان `current_stock` بين 1 و5؛
  - "نفد من المخزون" بدل زر السلة إذا كان `current_stock == 0`.
- **العدّاد إلى `offer_ends_at`:** ثلاث حلقات بلون التطبيق الأساسي.
  - **يوم أو أكثر:** يوم / ساعة / دقيقة.
    - حلقة الأيام تمتلئ نسبةً إلى طول العرض كله، أي `offer_ends_at - offer_starts_at`.
    - الساعات تمتلئ من 24، والدقائق من 60.
  - **أقل من يوم:** ساعة / دقيقة / ثانية.
  - **أقل من 60 ثانية:** حلقة واحدة للثواني، بجانبها نص "الدقيقة الأخيرة!".
  - **عند الوصول إلى 0:**
    - يظهر "انتهى العرض"، ويختفي زر السلة؛
    - أو احذف الكرت من القائمة، فالطلب التالي لن يرسله أصلاً.

## 5. ملاحظات مهمة للتنفيذ

- **ساعة الجهاز قد تكون خاطئة.**
  - احسب الفرق بين وقت الخادم ووقت الجهاز من ترويسة `Date` في الرد، واستعمله في العدّاد.
  - أو على الأقل لا تحذف كرتاً قبل أن يؤكد الخادم ذلك في الطلب التالي.
- **التحديث:**
  - الخادم يخزّن الرد حتى أقرب لحظة يبدأ فيها عرض أو ينتهي، فالطلب التالي بعد هذه اللحظة يأتي بالقائمة الجديدة.
  - يكفي إعادة جلب `home-sections` عند فتح الشاشة، أو عند انتهاء عدّاد أحد الكروت.
- **العدّادات:** استعمل مؤقّتاً واحداً لكل الكروت، لا مؤقّتاً لكل كرت.
- **ترتيب المنتجات:** هو ترتيب الفريق كما يأتي. لا تعِد ترتيبه.

## 6. النسخ القديمة من التطبيق

لا يلزمها أي تعديل. الـ endpoints القديمة ما زالت تجيب بالشكل القديم، لكن من القسم الجديد:

- **`GET flash-deals`** و**`flash-deals/info/{slug}`:** صفقة **واحدة**:
  - `id` هو رقم القسم، و`slug` هو `flash-sale`؛
  - `date` هو أبعد `offer_ends_at` بين العروض السارية؛
  - ومعها أول 6 منتجات.
  - إن لم يكن هناك عرض ساري، تجيب `data: []`.
- **`GET flash-deal-products/{slug}`:** منتجات القسم، مع المفتاحين الجديدين.
- **`GET flash-deals-banners`:** تجيب `data: []`.

**في النسخة الجديدة:**
- ارسم القسم من `home-sections`؛
- **توقّف عن استدعاء `flash-deals*`**؛
- واحذف كتلة الصفقات الثابتة القديمة من الصفحة الرئيسية، وإلا ظهر القسم مرتين.

## 7. قائمة تحقق للمطوّر

- [ ] رسم القسم في مكانه من `layout` عندما يكون `type == "flash_deal"`.
- [ ] قراءة `offer_starts_at` و`offer_ends_at`، والعدّاد بالحلقات (يوم-ساعة-دقيقة، وأقل من يوم: ساعة-دقيقة-ثانية)، والدقيقة الأخيرة، و"انتهى العرض".
- [ ] شاشة "عرض الكل" من `links.all`، مع ترقيم الصفحات.
- [ ] الكرت مثل باقي الأقسام، و"وفّر" و"بقي N فقط" تحت السعر، وشارة "أقرب عرض ينتهي بعد" بجانب العنوان.
- [ ] إزالة كتلة الصفقات القديمة، وإيقاف استدعاء `flash-deals*`.
- [ ] الرابط العميق `kapitano://section/flash-sale` يفتح شاشة "عرض الكل" (`home-sections/flash-sale/products`).
