gov-layout 1.2.25 → 1.2.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -241,11 +241,21 @@ import { UserHeader } from 'gov-layout';
241
241
  notifications={[
242
242
  {
243
243
  id: 1,
244
- title: 'คำร้องได้รับการอนุมัติ',
245
- description: 'คำร้องหมายเลข #1234',
244
+ title: 'คำร้องใหม่รอตรวจสอบ',
245
+ description: 'มีคำร้องใหม่เข้ามา กรุณาตรวจสอบ',
246
246
  date: '2 ชม. ที่แล้ว',
247
- type: 'success',
247
+ type: 'warning',
248
248
  isRead: false,
249
+ category: 'action', // ← แสดงในแท็บ "ต้องดำเนินการ"
250
+ },
251
+ {
252
+ id: 2,
253
+ title: 'คำร้องได้รับการอนุมัติ',
254
+ description: 'คำร้องหมายเลข #1234 อนุมัติสำเร็จ',
255
+ date: '5 ชม. ที่แล้ว',
256
+ type: 'success',
257
+ isRead: true,
258
+ category: 'general', // ← แสดงในแท็บ "แจ้งเตือนทั่วไป"
249
259
  },
250
260
  ]}
251
261
  onToggleSidebar={() => setOpen(true)}
@@ -273,15 +283,32 @@ import { UserHeader } from 'gov-layout';
273
283
  | `notificationBell` | `ReactNode?` | - | custom bell icon |
274
284
  | `className` | `string?` | - | className เพิ่มเติม |
275
285
 
286
+ ### 🔔 Notification Filter Tabs (v1.2.25+)
287
+
288
+ Dropdown แจ้งเตือนมีแท็บกรอง 3 หมวด พร้อม badge ตัวเลข:
289
+
290
+ | แท็บ | กรองจาก `category` | ตัวอย่างใช้งาน |
291
+ |------|-------------------|----------------|
292
+ | **ทั้งหมด** | แสดงทุกรายการ | ดูภาพรวม |
293
+ | **ต้องดำเนินการ** | `'action'` | คำร้องใหม่รอตรวจสอบ, ต้องอัปโหลดเอกสาร, มีคิวใหม่ |
294
+ | **แจ้งเตือนทั่วไป** | `'general'` หรือไม่ระบุ | อนุมัติสำเร็จ, จองสำเร็จ, ยกเลิกแล้ว |
295
+
296
+ > 💡 ถ้าไม่ส่ง `category` จะถูกจัดเป็น **แจ้งเตือนทั่วไป** อัตโนมัติ (backward compatible)
297
+
276
298
  ### Features
277
299
 
278
300
  - ✅ Notification bell พร้อม badge (99+ เมื่อเกิน)
279
301
  - ✅ ไม่มีแจ้งเตือน → ไม่แสดง badge
280
302
  - ✅ Notification dropdown แบบ scroll
303
+ - ✅ **Filter tabs**: ทั้งหมด / ต้องดำเนินการ / แจ้งเตือนทั่วไป 🆕
304
+ - ✅ **Badge ตัวเลข** แต่ละแท็บ 🆕
305
+ - ✅ **Category badge** "ต้องดำเนินการ" ติดแต่ละรายการ 🆕
306
+ - ✅ **Empty state แยกตาม filter** 🆕
281
307
  - ✅ กดแจ้งเตือนแต่ละรายการ → `onNotificationClick`
282
308
  - ✅ Subtitle ใต้ข้อความทักทาย (เช่น "ผู้สูงอายุ")
283
309
  - ✅ ปุ่มเปิด sidebar (☰)
284
310
  - ✅ กดโปรไฟล์ผู้ใช้ (avatar + ชื่อ) → `onProfile`
311
+ - ✅ รองรับ Dark Mode
285
312
 
286
313
  ---
287
314
 
@@ -433,6 +460,8 @@ interface User {
433
460
  }
434
461
 
435
462
  // การแจ้งเตือน
463
+ type NotificationCategory = 'action' | 'general';
464
+
436
465
  interface NotificationItem {
437
466
  id: string | number;
438
467
  title: string;
@@ -440,6 +469,7 @@ interface NotificationItem {
440
469
  date: string;
441
470
  type: 'info' | 'success' | 'warning' | 'error' | 'reminder';
442
471
  isRead: boolean;
472
+ category?: NotificationCategory; // 🆕 หมวดหมู่: 'action' | 'general'
443
473
  }
444
474
 
445
475
  // ตั้งค่า
package/dist/index.js CHANGED
@@ -625,6 +625,18 @@ function ProfileIcon() {
625
625
  }
626
626
  );
627
627
  }
628
+ function DefaultAvatarIcon() {
629
+ return /* @__PURE__ */ jsxRuntime.jsx(
630
+ "svg",
631
+ {
632
+ width: "20",
633
+ height: "20",
634
+ viewBox: "0 0 24 24",
635
+ fill: "currentColor",
636
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z" })
637
+ }
638
+ );
639
+ }
628
640
  function SidebarUserProfile({
629
641
  user,
630
642
  roleLabel,
@@ -640,9 +652,6 @@ function SidebarUserProfile({
640
652
  }
641
653
  return user.firstName || user.lastName || "\u0E1C\u0E39\u0E49\u0E43\u0E0A\u0E49";
642
654
  };
643
- const getInitial = () => {
644
- return user.firstName?.charAt(0) || user.lastName?.charAt(0) || "?";
645
- };
646
655
  if (collapsed) {
647
656
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: {
648
657
  padding: "12px 8px",
@@ -681,11 +690,9 @@ function SidebarUserProfile({
681
690
  display: "flex",
682
691
  alignItems: "center",
683
692
  justifyContent: "center",
684
- color: "#fff",
685
- fontWeight: 700,
686
- fontSize: "14px"
693
+ color: "#fff"
687
694
  },
688
- children: getInitial()
695
+ children: /* @__PURE__ */ jsxRuntime.jsx(DefaultAvatarIcon, {})
689
696
  }
690
697
  )
691
698
  }
@@ -802,11 +809,9 @@ function SidebarUserProfile({
802
809
  alignItems: "center",
803
810
  justifyContent: "center",
804
811
  color: "#fff",
805
- fontWeight: 700,
806
- fontSize: "16px",
807
812
  flexShrink: 0
808
813
  },
809
- children: getInitial()
814
+ children: /* @__PURE__ */ jsxRuntime.jsx(DefaultAvatarIcon, {})
810
815
  }
811
816
  ),
812
817
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [
@@ -1097,6 +1102,9 @@ function HamburgerIcon() {
1097
1102
  }
1098
1103
  ) });
1099
1104
  }
1105
+ function MessageOutlinedIcon(props) {
1106
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { focusable: "false", "aria-hidden": "true", viewBox: "0 0 24 24", fill: "currentColor", ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 4h16v12H5.17L4 17.17zm0-2c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm2 10h12v2H6zm0-3h12v2H6zm0-3h12v2H6z" }) });
1107
+ }
1100
1108
  function getNotifBg(type) {
1101
1109
  const map = {
1102
1110
  success: "#dcfce7",
@@ -1440,12 +1448,26 @@ function UserHeader({
1440
1448
  "div",
1441
1449
  {
1442
1450
  style: {
1443
- padding: "32px",
1451
+ padding: "48px 32px",
1444
1452
  textAlign: "center",
1445
- color: "#9ca3af",
1446
- fontSize: "14px"
1453
+ color: isDark ? "#9ca3af" : "#6b7280",
1454
+ fontSize: "14px",
1455
+ display: "flex",
1456
+ flexDirection: "column",
1457
+ alignItems: "center",
1458
+ justifyContent: "center",
1459
+ gap: "12px"
1447
1460
  },
1448
- children: activeFilter === "all" ? "\u{1F514} \u0E44\u0E21\u0E48\u0E21\u0E35\u0E01\u0E32\u0E23\u0E41\u0E08\u0E49\u0E07\u0E40\u0E15\u0E37\u0E2D\u0E19\u0E43\u0E2B\u0E21\u0E48" : activeFilter === "action" ? "\u2705 \u0E44\u0E21\u0E48\u0E21\u0E35\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E17\u0E35\u0E48\u0E15\u0E49\u0E2D\u0E07\u0E14\u0E33\u0E40\u0E19\u0E34\u0E19\u0E01\u0E32\u0E23" : "\u{1F4CB} \u0E44\u0E21\u0E48\u0E21\u0E35\u0E01\u0E32\u0E23\u0E41\u0E08\u0E49\u0E07\u0E40\u0E15\u0E37\u0E2D\u0E19\u0E17\u0E31\u0E48\u0E27\u0E44\u0E1B"
1461
+ children: activeFilter === "action" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1462
+ /* @__PURE__ */ jsxRuntime.jsx(MessageOutlinedIcon, { style: { width: "48px", height: "48px", opacity: 0.4 } }),
1463
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: "\u0E44\u0E21\u0E48\u0E21\u0E35\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23\u0E17\u0E35\u0E48\u0E15\u0E49\u0E2D\u0E07\u0E14\u0E33\u0E40\u0E19\u0E34\u0E19\u0E01\u0E32\u0E23" })
1464
+ ] }) : activeFilter === "all" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1465
+ /* @__PURE__ */ jsxRuntime.jsx(BellIcon2, {}),
1466
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500, marginTop: "8px" }, children: "\u0E44\u0E21\u0E48\u0E21\u0E35\u0E01\u0E32\u0E23\u0E41\u0E08\u0E49\u0E07\u0E40\u0E15\u0E37\u0E2D\u0E19\u0E43\u0E2B\u0E21\u0E48" })
1467
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1468
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "40px", opacity: 0.6, marginBottom: "-8px" }, children: "\u{1F4CB}" }),
1469
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 500 }, children: "\u0E44\u0E21\u0E48\u0E21\u0E35\u0E01\u0E32\u0E23\u0E41\u0E08\u0E49\u0E07\u0E40\u0E15\u0E37\u0E2D\u0E19\u0E17\u0E31\u0E48\u0E27\u0E44\u0E1B" })
1470
+ ] })
1449
1471
  }
1450
1472
  ) : filteredNotifications.map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
1451
1473
  "div",