معمل
تصميم نظام إشعارات فوري
25 دقيقة
متوسط3 المحاولات المجانية
التعليمات
الهدف
ابنِ مكون React <NotificationSystem> يستقبل إشعارات فورية عبر WebSocket، ويعرضها في لوحة منسدلة مجمّعة، ويتعامل مع سيناريوهات عدم الاتصال بسلاسة. هذا تحدٍ شائع في مقابلات تصميم أنظمة الواجهة الأمامية يختبر التواصل الفوري وإدارة الحالة وإمكانية الوصول.
المتطلبات
1. جرس الإشعارات مع عداد غير المقروء
- عرض زر أيقونة جرس في الرأسية
- عرض شارة عدد غير المقروء (مثلاً "3") على الجرس
- الشارة يجب أن تختفي عندما يكون العدد 0
- تحريك الشارة عند وصول إشعار جديد (نبض أو تكبير CSS)
- أيقونة الجرس يجب أن تكون
<button>مع أنماط تركيز مناسبة
2. لوحة الإشعارات المنسدلة
- تفتح عند النقر على أيقونة الجرس
- تغلق عند النقر خارجها أو الضغط على Escape أو النقر على الجرس مجددًا
- تُجمّع الإشعارات حسب النوع: "رسائل"، "نظام"، "نشاط"
- كل إشعار يعرض: أيقونة، عنوان، وصف، وطابع زمني نسبي (مثلاً "قبل دقيقتين")
- زر "تعليم الكل كمقروء" في الأعلى
- رابط "عرض جميع الإشعارات" في الأسفل
- ارتفاع أقصى مع تجاوز قابل للتمرير
3. إدارة اتصال WebSocket
- الاتصال بنقطة نهاية WebSocket عند تركيب المكون
- تنفيذ إعادة اتصال بتراجع أسي (1 ثانية، 2 ثانية، 4 ثوانٍ، 8 ثوانٍ... حتى 30 ثانية كحد أقصى)
- عرض مؤشر حالة الاتصال (متصل/يُعيد الاتصال/غير متصل)
- تنظيف الاتصال عند فك التركيب
4. التحديثات المتفائلة
- عندما ينقر المستخدم "تعليم كمقروء"، حدّث واجهة المستخدم فورًا
- إذا فشل طلب الخادم، أرجع الإشعار لحالة غير مقروء
- اعرض إشعار خطأ خفيف إذا حدث الإرجاع
5. الطابور بدون اتصال
- اكتشف عندما يصبح المتصفح غير متصل باستخدام
navigator.onLineوأحداثonline/offline - ضع إجراءات "تعليم كمقروء" في طابور أثناء عدم الاتصال
- أفرغ الطابور عند استعادة الاتصال
- احفظ الطابور في
localStorageحتى يبقى بعد تحديث الصفحة
6. إمكانية الوصول (مناطق ARIA الحية)
- زر الجرس يجب أن يحتوي على
aria-labelمع عدد غير المقروء (مثلاً "إشعارات، 3 غير مقروءة") - اللوحة المنسدلة يجب أن تحتوي على
role="dialog"وaria-label="الإشعارات" - الإشعارات الجديدة يجب أن تُعلن عبر منطقة
aria-live="polite" - جميع العناصر يجب أن تكون قابلة للتنقل بمفاتيح الأسهم وقابلة للتحديد بـ Enter
- التركيز يجب أن ينتقل إلى اللوحة عند الفتح ويعود للجرس عند الإغلاق
مخطط البيانات
يجب أن يعمل مكونك مع شكل البيانات هذا:
type NotificationType = 'message' | 'system' | 'activity';
interface Notification {
id: string;
type: NotificationType;
title: string;
description: string;
timestamp: string; // سلسلة تاريخ ISO
isRead: boolean;
actionUrl?: string; // رابط اختياري للتنقل إليه
}
interface NotificationGroup {
type: NotificationType;
label: string;
notifications: Notification[];
}
interface WebSocketMessage {
event: 'new_notification' | 'notification_read' | 'bulk_read';
payload: Notification | { ids: string[] };
}
مثال على الاستخدام
<NotificationSystem
wsUrl="wss://api.example.com/notifications"
userId="user-123"
onNotificationClick={(notification) => router.push(notification.actionUrl)}
/>
تلميحات
- استخدم
useReducerلحالة الإشعارات — يتعامل مع انتقالات الحالة المعقدة (إضافة، تعليم كمقروء، قراءة جماعية، إرجاع) بنظافة - أنشئ خطاف
useWebSocketمخصص يُغلّف الاتصال وإعادة الاتصال ومعالجة الرسائل - استخدم
useRefلتتبع مهلة إعادة الاتصال الحالية للتنظيف - استخدم
Intl.RelativeTimeFormatللطوابع الزمنية المقروءة - جمّع الإشعارات مع
Array.prototype.reduceأوObject.groupBy - لطابور عدم الاتصال، أنشئ فئة صغيرة بطرق
enqueueوflushوrestore - استخدم
aria-live="polite"على عنصر مخفي مرئيًا لإعلان الإشعارات الجديدة
معايير التقييم
جرس الإشعارات: زر جرس مع شارة عدد غير مقروء ديناميكية، الشارة تختفي عند الصفر، عنصر زر مناسب مع أنماط تركيز15 نقاط
اللوحة المنسدلة: تفتح/تغلق بشكل صحيح، تُجمّع الإشعارات حسب النوع، تعرض العنوان/الوصف/الطابع الزمني، لديها وظيفة تعليم الكل كمقروء والإغلاق20 نقاط
إدارة WebSocket: يتصل عند التركيب، ينفّذ إعادة اتصال بتراجع أسي مع تأخير أقصى، يعرض حالة الاتصال، ينظّف عند فك التركيب20 نقاط
التحديثات المتفائلة: تعليم كمقروء يحدّث واجهة المستخدم فورًا، يتراجع عند فشل الخادم، يعرض ملاحظات خطأ عند التراجع15 نقاط
الطابور بدون اتصال: يكتشف حالة الاتصال/عدم الاتصال، يضع الإجراءات في طابور بدون اتصال، يُفرغ عند إعادة الاتصال، يحفظ الطابور في localStorage15 نقاط
إمكانية الوصول: الجرس لديه aria-label مع العدد، اللوحة لديها role=dialog، الإشعارات الجديدة تُعلن عبر منطقة aria-live، تنقل بلوحة المفاتيح مع السهم/Enter/Escape، إدارة التركيز15 نقاط
حلك
هذا المعمل يتطلب TypeScript
TSTypeScript(مطلوب)
3 محاولات مجانية متبقية