yslootahrobotics/CHANGELOG.md

5.9 KiB

Changelog — Lootah Robotics G1 Configurator

تاريخ التغييرات — 20 أبريل 2026


2ff21c5 — perf: compress GLBs 75%, add Draco decoder, loading spinner for attire

المشكلة

  • الموبايلات القديمة كانت تعلّق لأوقات طويلة عند تحميل الأزياء الجديدة
  • التبديل بين الأزياء (Robot Doctor / Security Guard) كان يعلّق بدون أي مؤشر تحميل

التغييرات

الملف التغيير
public/models/robot-doctor.glb ضغط Draco: 32 MB → 8.5 MB (توفير 74%)
public/models/security-guard.glb ضغط Draco: 29 MB → 6.85 MB (توفير 77%)
public/draco/ إضافة ملفات Draco decoder للمتصفح
src/components/RobotModel.tsx تفعيل useGLTF.setDecoderPath('/draco/')
src/components/RobotCanvas.tsx تفعيل Draco decoder + تخفيض DPR من 2x إلى 1.5x
src/components/ScrollScene.tsx تفعيل Draco decoder
src/components/ConfigPanel.tsx إضافة spinner عند تحميل زي جديد

لماذا كانت المشكلة موجودة؟

الملفات كانت مضغوطة بـ Draco لكن المتصفح لم يكن عنده الـ decoder لفك الضغط، فكان يفشل بصمت ويرجع للروبوت الأساسي.


b2a484f — fix: dynamic attire buttons in ScrollOverlays + mobile touch support

المشكلة

  • أزرار الأزياء في صفحة الـ Landing (Kandura, Vest, Suit) كانت مكتوبة بشكل ثابت (hardcoded)
  • أي زي جديد يضاف من الأدمن لا يظهر في الصفحة الرئيسية
  • الأزرار كانت تعمل بـ hover فقط (لا تعمل على الموبايل بالضغط)

التغييرات

الملف التغيير
src/components/ScrollOverlays.tsx جلب الأزياء ديناميكياً من /api/admin/pricing/
src/components/ScrollOverlays.tsx إضافة onClick بجانب onMouseEnter لدعم اللمس
src/components/ScrollOverlays.tsx إضافة pointerEvents: 'auto' لأن الـ overlay كان pointerEvents: 'none'

320b77b — fix: contacts API - use ADMIN_JWT_SECRET env var

المشكلة

  • صفحة Contacts في الأدمن كانت ترجع خطأ 500

السبب

  • Route الـ contacts كان يستخدم JWT_SECRET بينما باقي الـ routes تستخدم ADMIN_JWT_SECRET
  • أي JWT مولّد بـ ADMIN_JWT_SECRET سيفشل التحقق عند استخدام متغير مختلف

التغييرات

الملف التغيير
src/app/api/admin/contacts/route.ts استخدام ADMIN_JWT_SECRET بدلاً من JWT_SECRET
src/app/api/admin/contacts/route.ts إضافة رسالة خطأ واضحة إذا كان ADMIN_JWT_SECRET غير موجود

25ffbf4 — feat: add favicon and app icons for PWA support

التغييرات

الملف التغيير
public/favicon.ico أيقونة المتصفح
public/apple-touch-icon.png أيقونة iOS Home Screen
public/icon-192.png أيقونة PWA 192px
public/icon-192-maskable.png أيقونة PWA maskable 192px
public/icon-512.png أيقونة PWA 512px
public/icon-512-maskable.png أيقونة PWA maskable 512px
src/app/layout.tsx إضافة <link rel="icon"> و <link rel="apple-touch-icon">

e686d41 — fix: use configStore.getState().setPersonaAttire in ScrollOverlays

المشكلة

  • بناء Docker كان يفشل مع خطأ TypeScript:
    Property 'getState' does not exist on type '<T>(selector: (state: ConfigStore) => T) => T'
    

السبب

كان الكود يستخدم useConfigStore.getState() لكن useConfigStore هو React hook (دالة عادية) وليس Zustand store. فقط configStore المُصدَّر من vanilla Zustand يملك .getState().

بالإضافة لذلك، اسم الدالة كان خاطئاً: setActivePersonaAttire بدلاً من setPersonaAttire.

التغييرات

الملف التغيير
src/components/ScrollOverlays.tsx useConfigStore.getState().setActivePersonaAttire()configStore.getState().setPersonaAttire()

e159965 — feat: add GET endpoint to retrieve contact requests with admin authentication

التغييرات

الملف التغيير
src/app/api/admin/contacts/route.ts إضافة GET endpoint لجلب طلبات التواصل مع التحقق من الأدمن

ملاحظات عامة على البنية

متغيرات البيئة المطلوبة

ADMIN_JWT_SECRET=   # مطلوب لجميع routes الأدمن
DATABASE_URL=       # Prisma / SQLite
STRIPE_SECRET_KEY=  # للمدفوعات

هيكل Stores

Store الوصف
configStore (vanilla Zustand) الألوان والزي النشط — يدعم .getState()
useConfigStore (React hook) wrapper لـ configStore للاستخدام داخل components
personaStore (vanilla Zustand) قائمة الأزياء — تُحمَّل من API عند التهيئة
pricingStore أسعار العناصر — تُزامَن مع قاعدة البيانات

تدفق الأزياء المرفوعة

  1. الأدمن يرفع .glb من لوحة التحكم
  2. يُضغط تلقائياً بـ Draco عبر upload-model route
  3. يُحفظ المسار في قاعدة البيانات (PricingItem.modelPath)
  4. عند تحميل الصفحة، personaStore.hydrate() يجلب الأزياء من /api/admin/pricing/
  5. تظهر تلقائياً في ConfigPanel وفي ScrollOverlays (الصفحة الرئيسية)