@propknot/shared-ui 1.0.7 → 1.0.8

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.
Files changed (3) hide show
  1. package/dist/index.js +437 -61
  2. package/dist/index.mjs +462 -55
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -211,6 +211,7 @@ __export(index_exports, {
211
211
  NOTIFICATION_CHANNELS: () => NOTIFICATION_CHANNELS,
212
212
  NOTIFICATION_TYPES: () => NOTIFICATION_TYPES,
213
213
  Navbar: () => Navbar_default,
214
+ NotificationBell: () => NotificationBell_default,
214
215
  NotificationManager: () => NotificationManager_default,
215
216
  NotificationPatterns: () => NotificationPatterns,
216
217
  NotificationProvider: () => NotificationProvider,
@@ -1553,7 +1554,6 @@ var CustomThemeProvider = ({ children }) => {
1553
1554
  if (!event.origin.startsWith("http://localhost:")) return;
1554
1555
  const { type, theme } = event.data;
1555
1556
  if (type === "THEME_CHANGE" && theme && ["light", "dark"].includes(theme)) {
1556
- console.log("Embedded app received theme change:", theme);
1557
1557
  setCurrentTheme(theme);
1558
1558
  }
1559
1559
  };
@@ -3348,11 +3348,386 @@ var NotificationManager = () => {
3348
3348
  };
3349
3349
  var NotificationManager_default = NotificationManager;
3350
3350
 
3351
- // src/components/ErrorBoundary/ErrorBoundary.js
3351
+ // src/components/Notifications/NotificationBell.js
3352
3352
  var import_react13 = __toESM(require("react"));
3353
3353
  var import_material9 = require("@mui/material");
3354
3354
  var import_icons_material3 = require("@mui/icons-material");
3355
- var ErrorBoundary = class extends import_react13.default.Component {
3355
+ var import_date_fns2 = require("date-fns");
3356
+ var NotificationBell = ({ api: api2, useSocket: useSocket2, useAuth: useAuth2 }) => {
3357
+ const [anchorEl, setAnchorEl] = (0, import_react13.useState)(null);
3358
+ const [notifications, setNotifications] = (0, import_react13.useState)([]);
3359
+ const [unreadCount, setUnreadCount] = (0, import_react13.useState)(0);
3360
+ const [loading, setLoading] = (0, import_react13.useState)(false);
3361
+ const [error, setError] = (0, import_react13.useState)(null);
3362
+ const [page, setPage] = (0, import_react13.useState)(1);
3363
+ const [hasMore, setHasMore] = (0, import_react13.useState)(true);
3364
+ const { socket, isConnected } = useSocket2 ? useSocket2() : { socket: null, isConnected: false };
3365
+ const { user } = useAuth2 ? useAuth2() : { user: null };
3366
+ const open = Boolean(anchorEl);
3367
+ const fetchNotifications = (0, import_react13.useCallback)(async (pageNum = 1, append = false) => {
3368
+ if (!api2) return;
3369
+ setLoading(true);
3370
+ setError(null);
3371
+ try {
3372
+ const response = await api2.get("/notifications", {
3373
+ params: {
3374
+ page: pageNum,
3375
+ limit: 20,
3376
+ sort: "-createdAt"
3377
+ }
3378
+ });
3379
+ const newNotifications = response.data.notifications || [];
3380
+ if (append) {
3381
+ setNotifications((prev) => [...prev, ...newNotifications]);
3382
+ } else {
3383
+ setNotifications(newNotifications);
3384
+ }
3385
+ setHasMore(newNotifications.length === 20);
3386
+ setUnreadCount(response.data.unreadCount || 0);
3387
+ } catch (err) {
3388
+ console.error("Failed to fetch notifications:", err);
3389
+ setError("Failed to load notifications");
3390
+ } finally {
3391
+ setLoading(false);
3392
+ }
3393
+ }, [api2]);
3394
+ const fetchUnreadCount = (0, import_react13.useCallback)(async () => {
3395
+ if (!api2) return;
3396
+ try {
3397
+ const response = await api2.get("/notifications/unread");
3398
+ setUnreadCount(response.data.count || 0);
3399
+ } catch (err) {
3400
+ console.error("Failed to fetch unread count:", err);
3401
+ }
3402
+ }, [api2]);
3403
+ (0, import_react13.useEffect)(() => {
3404
+ fetchNotifications();
3405
+ fetchUnreadCount();
3406
+ }, [fetchNotifications, fetchUnreadCount]);
3407
+ (0, import_react13.useEffect)(() => {
3408
+ if (!socket || !isConnected) return;
3409
+ const handleNewNotification = (notification) => {
3410
+ setNotifications((prev) => [notification, ...prev]);
3411
+ setUnreadCount((prev) => prev + 1);
3412
+ };
3413
+ const handleNotificationRead = (notificationId) => {
3414
+ setNotifications(
3415
+ (prev) => prev.map((n) => n._id === notificationId ? { ...n, read: true } : n)
3416
+ );
3417
+ setUnreadCount((prev) => Math.max(0, prev - 1));
3418
+ };
3419
+ socket.on("notification", handleNewNotification);
3420
+ socket.on("notification:read", handleNotificationRead);
3421
+ return () => {
3422
+ socket.off("notification", handleNewNotification);
3423
+ socket.off("notification:read", handleNotificationRead);
3424
+ };
3425
+ }, [socket, isConnected]);
3426
+ const handleClick = (event) => {
3427
+ setAnchorEl(event.currentTarget);
3428
+ if (notifications.length === 0) {
3429
+ fetchNotifications();
3430
+ }
3431
+ };
3432
+ const handleClose = () => {
3433
+ setAnchorEl(null);
3434
+ };
3435
+ const handleMarkAsRead = async (notificationId) => {
3436
+ if (!api2) return;
3437
+ try {
3438
+ await api2.put(`/notifications/${notificationId}/read`);
3439
+ setNotifications(
3440
+ (prev) => prev.map((n) => n._id === notificationId ? { ...n, read: true, readAt: /* @__PURE__ */ new Date() } : n)
3441
+ );
3442
+ setUnreadCount((prev) => Math.max(0, prev - 1));
3443
+ } catch (err) {
3444
+ console.error("Failed to mark notification as read:", err);
3445
+ }
3446
+ };
3447
+ const handleMarkAllAsRead = async () => {
3448
+ if (!api2) return;
3449
+ try {
3450
+ await api2.put("/notifications/mark-all-read");
3451
+ setNotifications(
3452
+ (prev) => prev.map((n) => ({ ...n, read: true, readAt: /* @__PURE__ */ new Date() }))
3453
+ );
3454
+ setUnreadCount(0);
3455
+ } catch (err) {
3456
+ console.error("Failed to mark all as read:", err);
3457
+ }
3458
+ };
3459
+ const handleNotificationClick = async (notification) => {
3460
+ if (!notification.read) {
3461
+ await handleMarkAsRead(notification._id);
3462
+ }
3463
+ if (notification.actionUrl) {
3464
+ window.location.href = notification.actionUrl;
3465
+ }
3466
+ handleClose();
3467
+ };
3468
+ const handleLoadMore = () => {
3469
+ const nextPage = page + 1;
3470
+ setPage(nextPage);
3471
+ fetchNotifications(nextPage, true);
3472
+ };
3473
+ const getNotificationIcon = (type) => {
3474
+ const iconProps = { fontSize: "small" };
3475
+ switch (type) {
3476
+ case "TICKET_CREATED":
3477
+ case "TICKET_UPDATED":
3478
+ case "TICKET_ASSIGNED":
3479
+ case "TICKET_RESOLVED":
3480
+ case "TICKET_COMMENTED":
3481
+ case "TICKET_STATUS_CHANGED":
3482
+ return /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Assignment, { ...iconProps });
3483
+ case "MESSAGE_RECEIVED":
3484
+ case "MENTION_RECEIVED":
3485
+ return /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Message, { ...iconProps });
3486
+ case "PAYMENT_DUE":
3487
+ case "PAYMENT_OVERDUE":
3488
+ return /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Payment, { ...iconProps });
3489
+ case "PROPERTY_UPDATED":
3490
+ case "LEASE_EXPIRING":
3491
+ return /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Home, { ...iconProps });
3492
+ case "APPLIANCE_MAINTENANCE_DUE":
3493
+ case "MAINTENANCE_SCHEDULED":
3494
+ return /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Build, { ...iconProps });
3495
+ case "SYSTEM_ALERT":
3496
+ return /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Warning, { ...iconProps });
3497
+ case "SUCCESS":
3498
+ return /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.CheckCircle, { ...iconProps });
3499
+ case "ERROR":
3500
+ return /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Error, { ...iconProps });
3501
+ case "WARNING":
3502
+ return /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Warning, { ...iconProps });
3503
+ case "INFO":
3504
+ default:
3505
+ return /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Info, { ...iconProps });
3506
+ }
3507
+ };
3508
+ const getNotificationColor = (type) => {
3509
+ if ((type == null ? void 0 : type.includes("ERROR")) || (type == null ? void 0 : type.includes("OVERDUE"))) return "error.main";
3510
+ if ((type == null ? void 0 : type.includes("WARNING")) || (type == null ? void 0 : type.includes("DUE"))) return "warning.main";
3511
+ if ((type == null ? void 0 : type.includes("SUCCESS")) || (type == null ? void 0 : type.includes("RESOLVED"))) return "success.main";
3512
+ return "primary.main";
3513
+ };
3514
+ const getPriorityChip = (priority) => {
3515
+ if (!priority || priority === "NORMAL" || priority === "LOW") return null;
3516
+ const colors = {
3517
+ HIGH: "warning",
3518
+ URGENT: "error"
3519
+ };
3520
+ return /* @__PURE__ */ import_react13.default.createElement(
3521
+ import_material9.Chip,
3522
+ {
3523
+ label: priority,
3524
+ size: "small",
3525
+ color: colors[priority] || "default",
3526
+ sx: { ml: 1, height: 20, fontSize: "0.7rem" }
3527
+ }
3528
+ );
3529
+ };
3530
+ return /* @__PURE__ */ import_react13.default.createElement(import_react13.default.Fragment, null, /* @__PURE__ */ import_react13.default.createElement(
3531
+ import_material9.IconButton,
3532
+ {
3533
+ color: "inherit",
3534
+ onClick: handleClick,
3535
+ sx: {
3536
+ ml: 1,
3537
+ "&:hover": {
3538
+ bgcolor: "action.hover"
3539
+ }
3540
+ }
3541
+ },
3542
+ /* @__PURE__ */ import_react13.default.createElement(
3543
+ import_material9.Badge,
3544
+ {
3545
+ badgeContent: unreadCount,
3546
+ color: "error",
3547
+ max: 99
3548
+ },
3549
+ unreadCount > 0 ? /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Notifications, null) : /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.NotificationsNone, null)
3550
+ )
3551
+ ), /* @__PURE__ */ import_react13.default.createElement(
3552
+ import_material9.Menu,
3553
+ {
3554
+ anchorEl,
3555
+ open,
3556
+ onClose: handleClose,
3557
+ PaperProps: {
3558
+ sx: {
3559
+ width: 420,
3560
+ maxHeight: 600,
3561
+ overflow: "hidden",
3562
+ display: "flex",
3563
+ flexDirection: "column"
3564
+ }
3565
+ },
3566
+ transformOrigin: { horizontal: "right", vertical: "top" },
3567
+ anchorOrigin: { horizontal: "right", vertical: "bottom" }
3568
+ },
3569
+ /* @__PURE__ */ import_react13.default.createElement(
3570
+ import_material9.Box,
3571
+ {
3572
+ sx: {
3573
+ p: 2,
3574
+ pb: 1.5,
3575
+ display: "flex",
3576
+ alignItems: "center",
3577
+ justifyContent: "space-between",
3578
+ borderBottom: "1px solid",
3579
+ borderColor: "divider"
3580
+ }
3581
+ },
3582
+ /* @__PURE__ */ import_react13.default.createElement(import_material9.Box, { sx: { display: "flex", alignItems: "center", gap: 1 } }, /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Notifications, { color: "primary" }), /* @__PURE__ */ import_react13.default.createElement(import_material9.Typography, { variant: "h6", sx: { fontWeight: 600 } }, "Notifications"), unreadCount > 0 && /* @__PURE__ */ import_react13.default.createElement(
3583
+ import_material9.Chip,
3584
+ {
3585
+ label: unreadCount,
3586
+ size: "small",
3587
+ color: "primary",
3588
+ sx: { height: 22, fontSize: "0.75rem" }
3589
+ }
3590
+ )),
3591
+ /* @__PURE__ */ import_react13.default.createElement(import_material9.Box, null, unreadCount > 0 && /* @__PURE__ */ import_react13.default.createElement(
3592
+ import_material9.Button,
3593
+ {
3594
+ size: "small",
3595
+ startIcon: /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.DoneAll, null),
3596
+ onClick: handleMarkAllAsRead,
3597
+ sx: { textTransform: "none", fontSize: "0.75rem" }
3598
+ },
3599
+ "Mark all read"
3600
+ ), /* @__PURE__ */ import_react13.default.createElement(import_material9.IconButton, { size: "small", onClick: handleClose }, /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Close, { fontSize: "small" })))
3601
+ ),
3602
+ error && /* @__PURE__ */ import_react13.default.createElement(import_material9.Alert, { severity: "error", sx: { m: 2 } }, error),
3603
+ /* @__PURE__ */ import_react13.default.createElement(
3604
+ import_material9.Box,
3605
+ {
3606
+ sx: {
3607
+ flex: 1,
3608
+ overflow: "auto",
3609
+ maxHeight: 450
3610
+ }
3611
+ },
3612
+ loading && notifications.length === 0 ? /* @__PURE__ */ import_react13.default.createElement(import_material9.Box, { sx: { display: "flex", justifyContent: "center", p: 4 } }, /* @__PURE__ */ import_react13.default.createElement(import_material9.CircularProgress, { size: 32 })) : notifications.length === 0 ? /* @__PURE__ */ import_react13.default.createElement(
3613
+ import_material9.Box,
3614
+ {
3615
+ sx: {
3616
+ display: "flex",
3617
+ flexDirection: "column",
3618
+ alignItems: "center",
3619
+ justifyContent: "center",
3620
+ p: 4,
3621
+ textAlign: "center"
3622
+ }
3623
+ },
3624
+ /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.NotificationsNone, { sx: { fontSize: 64, color: "text.secondary", mb: 2 } }),
3625
+ /* @__PURE__ */ import_react13.default.createElement(import_material9.Typography, { variant: "body1", color: "text.secondary", sx: { fontWeight: 500 } }, "No notifications yet"),
3626
+ /* @__PURE__ */ import_react13.default.createElement(import_material9.Typography, { variant: "body2", color: "text.secondary" }, "You're all caught up!")
3627
+ ) : /* @__PURE__ */ import_react13.default.createElement(import_material9.List, { sx: { p: 0 } }, notifications.map((notification, index) => /* @__PURE__ */ import_react13.default.createElement(import_react13.default.Fragment, { key: notification._id }, /* @__PURE__ */ import_react13.default.createElement(
3628
+ import_material9.ListItem,
3629
+ {
3630
+ button: true,
3631
+ onClick: () => handleNotificationClick(notification),
3632
+ sx: {
3633
+ py: 1.5,
3634
+ px: 2,
3635
+ bgcolor: notification.read ? "transparent" : "action.hover",
3636
+ "&:hover": {
3637
+ bgcolor: notification.read ? "action.hover" : "action.selected"
3638
+ },
3639
+ borderLeft: notification.read ? "none" : "3px solid",
3640
+ borderLeftColor: getNotificationColor(notification.type),
3641
+ transition: "all 0.2s"
3642
+ }
3643
+ },
3644
+ /* @__PURE__ */ import_react13.default.createElement(import_material9.ListItemAvatar, null, /* @__PURE__ */ import_react13.default.createElement(
3645
+ import_material9.Avatar,
3646
+ {
3647
+ sx: {
3648
+ bgcolor: notification.read ? "grey.300" : getNotificationColor(notification.type),
3649
+ width: 40,
3650
+ height: 40
3651
+ }
3652
+ },
3653
+ getNotificationIcon(notification.type)
3654
+ )),
3655
+ /* @__PURE__ */ import_react13.default.createElement(
3656
+ import_material9.ListItemText,
3657
+ {
3658
+ primary: /* @__PURE__ */ import_react13.default.createElement(import_material9.Box, { sx: { display: "flex", alignItems: "center", mb: 0.5 } }, /* @__PURE__ */ import_react13.default.createElement(
3659
+ import_material9.Typography,
3660
+ {
3661
+ variant: "body2",
3662
+ sx: {
3663
+ fontWeight: notification.read ? 400 : 600,
3664
+ flex: 1
3665
+ }
3666
+ },
3667
+ notification.title
3668
+ ), getPriorityChip(notification.priority)),
3669
+ secondary: /* @__PURE__ */ import_react13.default.createElement(import_react13.default.Fragment, null, /* @__PURE__ */ import_react13.default.createElement(
3670
+ import_material9.Typography,
3671
+ {
3672
+ variant: "body2",
3673
+ color: "text.secondary",
3674
+ sx: {
3675
+ display: "-webkit-box",
3676
+ WebkitLineClamp: 2,
3677
+ WebkitBoxOrient: "vertical",
3678
+ overflow: "hidden",
3679
+ mb: 0.5
3680
+ }
3681
+ },
3682
+ notification.message
3683
+ ), /* @__PURE__ */ import_react13.default.createElement(import_material9.Typography, { variant: "caption", color: "text.secondary" }, (0, import_date_fns2.formatDistanceToNow)(new Date(notification.createdAt), { addSuffix: true })))
3684
+ }
3685
+ )
3686
+ ), index < notifications.length - 1 && /* @__PURE__ */ import_react13.default.createElement(import_material9.Divider, null)))),
3687
+ hasMore && notifications.length > 0 && /* @__PURE__ */ import_react13.default.createElement(import_material9.Box, { sx: { p: 2, textAlign: "center", borderTop: "1px solid", borderColor: "divider" } }, /* @__PURE__ */ import_react13.default.createElement(
3688
+ import_material9.Button,
3689
+ {
3690
+ onClick: handleLoadMore,
3691
+ disabled: loading,
3692
+ size: "small",
3693
+ sx: { textTransform: "none" }
3694
+ },
3695
+ loading ? "Loading..." : "Load more"
3696
+ ))
3697
+ ),
3698
+ /* @__PURE__ */ import_react13.default.createElement(
3699
+ import_material9.Box,
3700
+ {
3701
+ sx: {
3702
+ p: 1.5,
3703
+ borderTop: "1px solid",
3704
+ borderColor: "divider",
3705
+ textAlign: "center"
3706
+ }
3707
+ },
3708
+ /* @__PURE__ */ import_react13.default.createElement(
3709
+ import_material9.Button,
3710
+ {
3711
+ size: "small",
3712
+ startIcon: /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Settings, null),
3713
+ onClick: () => {
3714
+ window.location.href = "/settings?tab=general";
3715
+ handleClose();
3716
+ },
3717
+ sx: { textTransform: "none" }
3718
+ },
3719
+ "Notification Settings"
3720
+ )
3721
+ )
3722
+ ));
3723
+ };
3724
+ var NotificationBell_default = NotificationBell;
3725
+
3726
+ // src/components/ErrorBoundary/ErrorBoundary.js
3727
+ var import_react14 = __toESM(require("react"));
3728
+ var import_material10 = require("@mui/material");
3729
+ var import_icons_material4 = require("@mui/icons-material");
3730
+ var ErrorBoundary = class extends import_react14.default.Component {
3356
3731
  constructor(props) {
3357
3732
  super(props);
3358
3733
  this.state = {
@@ -3393,8 +3768,8 @@ var ErrorBoundary = class extends import_react13.default.Component {
3393
3768
  if (this.state.hasError) {
3394
3769
  const isNavigationError = (_b = (_a = this.state.error) == null ? void 0 : _a.message) == null ? void 0 : _b.includes("getBoundingClientRect");
3395
3770
  const isDOMError = ((_d = (_c = this.state.error) == null ? void 0 : _c.message) == null ? void 0 : _d.includes("null")) || ((_f = (_e = this.state.error) == null ? void 0 : _e.message) == null ? void 0 : _f.includes("undefined"));
3396
- return /* @__PURE__ */ import_react13.default.createElement(
3397
- import_material9.Box,
3771
+ return /* @__PURE__ */ import_react14.default.createElement(
3772
+ import_material10.Box,
3398
3773
  {
3399
3774
  sx: {
3400
3775
  display: "flex",
@@ -3405,32 +3780,32 @@ var ErrorBoundary = class extends import_react13.default.Component {
3405
3780
  p: 3
3406
3781
  }
3407
3782
  },
3408
- /* @__PURE__ */ import_react13.default.createElement(import_material9.Card, { sx: { maxWidth: 600, width: "100%" } }, /* @__PURE__ */ import_react13.default.createElement(import_material9.CardContent, null, /* @__PURE__ */ import_react13.default.createElement(import_material9.Stack, { spacing: 3, alignItems: "center" }, /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.BugReport, { sx: { fontSize: 64, color: "error.main" } }), /* @__PURE__ */ import_react13.default.createElement(import_material9.Typography, { variant: "h5", component: "h2", textAlign: "center" }, "Oops! Something went wrong"), /* @__PURE__ */ import_react13.default.createElement(import_material9.Alert, { severity: "error", sx: { width: "100%" } }, /* @__PURE__ */ import_react13.default.createElement(import_material9.Typography, { variant: "body2" }, isNavigationError && /* @__PURE__ */ import_react13.default.createElement(import_react13.default.Fragment, null, /* @__PURE__ */ import_react13.default.createElement("strong", null, "UI Component Error:"), " A component tried to access an element before it was ready. This is usually temporary."), isDOMError && !isNavigationError && /* @__PURE__ */ import_react13.default.createElement(import_react13.default.Fragment, null, /* @__PURE__ */ import_react13.default.createElement("strong", null, "DOM Error:"), " A component couldn't find an expected element. This might be due to rapid state changes."), !isNavigationError && !isDOMError && /* @__PURE__ */ import_react13.default.createElement(import_react13.default.Fragment, null, /* @__PURE__ */ import_react13.default.createElement("strong", null, "Application Error:"), " An unexpected error occurred while rendering the component."))), process.env.NODE_ENV === "development" && this.state.error && /* @__PURE__ */ import_react13.default.createElement(import_material9.Alert, { severity: "warning", sx: { width: "100%" } }, /* @__PURE__ */ import_react13.default.createElement(import_material9.Typography, { variant: "body2", component: "div" }, /* @__PURE__ */ import_react13.default.createElement("strong", null, "Debug Info:"), /* @__PURE__ */ import_react13.default.createElement("br", null), /* @__PURE__ */ import_react13.default.createElement("code", { style: { fontSize: "0.75rem", wordBreak: "break-word" } }, this.state.error.toString()))), /* @__PURE__ */ import_react13.default.createElement(import_material9.Stack, { direction: "row", spacing: 2 }, /* @__PURE__ */ import_react13.default.createElement(
3409
- import_material9.Button,
3783
+ /* @__PURE__ */ import_react14.default.createElement(import_material10.Card, { sx: { maxWidth: 600, width: "100%" } }, /* @__PURE__ */ import_react14.default.createElement(import_material10.CardContent, null, /* @__PURE__ */ import_react14.default.createElement(import_material10.Stack, { spacing: 3, alignItems: "center" }, /* @__PURE__ */ import_react14.default.createElement(import_icons_material4.BugReport, { sx: { fontSize: 64, color: "error.main" } }), /* @__PURE__ */ import_react14.default.createElement(import_material10.Typography, { variant: "h5", component: "h2", textAlign: "center" }, "Oops! Something went wrong"), /* @__PURE__ */ import_react14.default.createElement(import_material10.Alert, { severity: "error", sx: { width: "100%" } }, /* @__PURE__ */ import_react14.default.createElement(import_material10.Typography, { variant: "body2" }, isNavigationError && /* @__PURE__ */ import_react14.default.createElement(import_react14.default.Fragment, null, /* @__PURE__ */ import_react14.default.createElement("strong", null, "UI Component Error:"), " A component tried to access an element before it was ready. This is usually temporary."), isDOMError && !isNavigationError && /* @__PURE__ */ import_react14.default.createElement(import_react14.default.Fragment, null, /* @__PURE__ */ import_react14.default.createElement("strong", null, "DOM Error:"), " A component couldn't find an expected element. This might be due to rapid state changes."), !isNavigationError && !isDOMError && /* @__PURE__ */ import_react14.default.createElement(import_react14.default.Fragment, null, /* @__PURE__ */ import_react14.default.createElement("strong", null, "Application Error:"), " An unexpected error occurred while rendering the component."))), process.env.NODE_ENV === "development" && this.state.error && /* @__PURE__ */ import_react14.default.createElement(import_material10.Alert, { severity: "warning", sx: { width: "100%" } }, /* @__PURE__ */ import_react14.default.createElement(import_material10.Typography, { variant: "body2", component: "div" }, /* @__PURE__ */ import_react14.default.createElement("strong", null, "Debug Info:"), /* @__PURE__ */ import_react14.default.createElement("br", null), /* @__PURE__ */ import_react14.default.createElement("code", { style: { fontSize: "0.75rem", wordBreak: "break-word" } }, this.state.error.toString()))), /* @__PURE__ */ import_react14.default.createElement(import_material10.Stack, { direction: "row", spacing: 2 }, /* @__PURE__ */ import_react14.default.createElement(
3784
+ import_material10.Button,
3410
3785
  {
3411
3786
  variant: "contained",
3412
- startIcon: /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Refresh, null),
3787
+ startIcon: /* @__PURE__ */ import_react14.default.createElement(import_icons_material4.Refresh, null),
3413
3788
  onClick: this.handleRetry,
3414
3789
  color: "primary"
3415
3790
  },
3416
3791
  "Try Again"
3417
- ), /* @__PURE__ */ import_react13.default.createElement(
3418
- import_material9.Button,
3792
+ ), /* @__PURE__ */ import_react14.default.createElement(
3793
+ import_material10.Button,
3419
3794
  {
3420
3795
  variant: "outlined",
3421
- startIcon: /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Refresh, null),
3796
+ startIcon: /* @__PURE__ */ import_react14.default.createElement(import_icons_material4.Refresh, null),
3422
3797
  onClick: this.handleReload
3423
3798
  },
3424
3799
  "Reload Page"
3425
- ), this.props.onNavigateHome && /* @__PURE__ */ import_react13.default.createElement(
3426
- import_material9.Button,
3800
+ ), this.props.onNavigateHome && /* @__PURE__ */ import_react14.default.createElement(
3801
+ import_material10.Button,
3427
3802
  {
3428
3803
  variant: "outlined",
3429
- startIcon: /* @__PURE__ */ import_react13.default.createElement(import_icons_material3.Home, null),
3804
+ startIcon: /* @__PURE__ */ import_react14.default.createElement(import_icons_material4.Home, null),
3430
3805
  onClick: this.props.onNavigateHome
3431
3806
  },
3432
3807
  "Go Home"
3433
- )), /* @__PURE__ */ import_react13.default.createElement(import_material9.Typography, { variant: "body2", color: "text.secondary", textAlign: "center" }, "If this problem persists, try refreshing the page or clearing your browser cache. The error has been logged for debugging."))))
3808
+ )), /* @__PURE__ */ import_react14.default.createElement(import_material10.Typography, { variant: "body2", color: "text.secondary", textAlign: "center" }, "If this problem persists, try refreshing the page or clearing your browser cache. The error has been logged for debugging."))))
3434
3809
  );
3435
3810
  }
3436
3811
  return this.props.children;
@@ -3439,26 +3814,26 @@ var ErrorBoundary = class extends import_react13.default.Component {
3439
3814
  var ErrorBoundary_default = ErrorBoundary;
3440
3815
 
3441
3816
  // src/contexts/SocketContext.js
3442
- var import_react14 = __toESM(require("react"));
3817
+ var import_react15 = __toESM(require("react"));
3443
3818
  var import_socket = require("socket.io-client");
3444
- var SocketContext = (0, import_react14.createContext)();
3819
+ var SocketContext = (0, import_react15.createContext)();
3445
3820
  var useSocket = () => {
3446
- const context = (0, import_react14.useContext)(SocketContext);
3821
+ const context = (0, import_react15.useContext)(SocketContext);
3447
3822
  if (!context) {
3448
3823
  throw new Error("useSocket must be used within SocketProvider");
3449
3824
  }
3450
3825
  return context;
3451
3826
  };
3452
3827
  var SocketProvider = ({ children }) => {
3453
- const [socket, setSocket] = (0, import_react14.useState)(null);
3454
- const [isConnected, setIsConnected] = (0, import_react14.useState)(false);
3455
- const [tenantToken, setTenantToken] = (0, import_react14.useState)(null);
3828
+ const [socket, setSocket] = (0, import_react15.useState)(null);
3829
+ const [isConnected, setIsConnected] = (0, import_react15.useState)(false);
3830
+ const [tenantToken, setTenantToken] = (0, import_react15.useState)(null);
3456
3831
  const { user } = useAuth();
3457
- (0, import_react14.useEffect)(() => {
3832
+ (0, import_react15.useEffect)(() => {
3458
3833
  const token = localStorage.getItem("tenantToken");
3459
3834
  setTenantToken(token);
3460
3835
  }, []);
3461
- (0, import_react14.useEffect)(() => {
3836
+ (0, import_react15.useEffect)(() => {
3462
3837
  if (user || tenantToken) {
3463
3838
  const userType = user ? "property_manager" : "tenant";
3464
3839
  const authToken = user ? localStorage.getItem("token") : tenantToken;
@@ -3485,15 +3860,15 @@ var SocketProvider = ({ children }) => {
3485
3860
  socket,
3486
3861
  isConnected
3487
3862
  };
3488
- return /* @__PURE__ */ import_react14.default.createElement(SocketContext.Provider, { value }, children);
3863
+ return /* @__PURE__ */ import_react15.default.createElement(SocketContext.Provider, { value }, children);
3489
3864
  };
3490
3865
 
3491
3866
  // src/hooks/useNotifications.js
3492
- var import_react15 = require("react");
3493
- var import_icons_material4 = require("@mui/icons-material");
3867
+ var import_react16 = require("react");
3868
+ var import_icons_material5 = require("@mui/icons-material");
3494
3869
  var useNotifications = () => {
3495
3870
  const notification = useNotification();
3496
- const notifyApiSuccess = (0, import_react15.useCallback)((operation, entityName) => {
3871
+ const notifyApiSuccess = (0, import_react16.useCallback)((operation, entityName) => {
3497
3872
  const messages = {
3498
3873
  create: `${entityName} created successfully`,
3499
3874
  update: `${entityName} updated successfully`,
@@ -3504,7 +3879,7 @@ var useNotifications = () => {
3504
3879
  };
3505
3880
  return notification.showSuccess(messages[operation] || `${operation} completed successfully`);
3506
3881
  }, [notification]);
3507
- const notifyApiError = (0, import_react15.useCallback)((operation, entityName, error) => {
3882
+ const notifyApiError = (0, import_react16.useCallback)((operation, entityName, error) => {
3508
3883
  var _a, _b;
3509
3884
  const baseMessages = {
3510
3885
  create: `Failed to create ${entityName}`,
@@ -3521,20 +3896,20 @@ var useNotifications = () => {
3521
3896
  { persistent: true }
3522
3897
  );
3523
3898
  }, [notification]);
3524
- const notifyFileUploadStart = (0, import_react15.useCallback)((fileName) => {
3899
+ const notifyFileUploadStart = (0, import_react16.useCallback)((fileName) => {
3525
3900
  return notification.showProgress(`Uploading ${fileName}...`, 0, {
3526
3901
  title: "File Upload",
3527
3902
  actions: [{
3528
3903
  label: "Cancel",
3529
- icon: /* @__PURE__ */ React.createElement(import_icons_material4.ContentCopy, null),
3904
+ icon: /* @__PURE__ */ React.createElement(import_icons_material5.ContentCopy, null),
3530
3905
  color: "error"
3531
3906
  }]
3532
3907
  });
3533
3908
  }, [notification]);
3534
- const notifyFileUploadProgress = (0, import_react15.useCallback)((notificationId, progress, fileName) => {
3909
+ const notifyFileUploadProgress = (0, import_react16.useCallback)((notificationId, progress, fileName) => {
3535
3910
  notification.updateProgress(notificationId, progress, `Uploading ${fileName}... ${Math.round(progress)}%`);
3536
3911
  }, [notification]);
3537
- const notifyFileUploadComplete = (0, import_react15.useCallback)((notificationId, fileName) => {
3912
+ const notifyFileUploadComplete = (0, import_react16.useCallback)((notificationId, fileName) => {
3538
3913
  notification.updateNotification(notificationId, {
3539
3914
  type: "success",
3540
3915
  message: `${fileName} uploaded successfully`,
@@ -3544,7 +3919,7 @@ var useNotifications = () => {
3544
3919
  actions: []
3545
3920
  });
3546
3921
  }, [notification]);
3547
- const notifyFileUploadError = (0, import_react15.useCallback)((notificationId, fileName, error) => {
3922
+ const notifyFileUploadError = (0, import_react16.useCallback)((notificationId, fileName, error) => {
3548
3923
  notification.updateNotification(notificationId, {
3549
3924
  type: "error",
3550
3925
  message: `Failed to upload ${fileName}: ${error}`,
@@ -3552,12 +3927,12 @@ var useNotifications = () => {
3552
3927
  persistent: true,
3553
3928
  actions: [{
3554
3929
  label: "Retry",
3555
- icon: /* @__PURE__ */ React.createElement(import_icons_material4.Refresh, null),
3930
+ icon: /* @__PURE__ */ React.createElement(import_icons_material5.Refresh, null),
3556
3931
  color: "error"
3557
3932
  }]
3558
3933
  });
3559
3934
  }, [notification]);
3560
- const notifyValidationError = (0, import_react15.useCallback)((errors) => {
3935
+ const notifyValidationError = (0, import_react16.useCallback)((errors) => {
3561
3936
  const errorCount = Array.isArray(errors) ? errors.length : Object.keys(errors).length;
3562
3937
  const message = errorCount === 1 ? "Please fix the validation error" : `Please fix ${errorCount} validation errors`;
3563
3938
  return notification.showWarning(message, {
@@ -3565,7 +3940,7 @@ var useNotifications = () => {
3565
3940
  duration: 6e3
3566
3941
  });
3567
3942
  }, [notification]);
3568
- const notifyConfirmAction = (0, import_react15.useCallback)((message, onConfirm, onCancel = null) => {
3943
+ const notifyConfirmAction = (0, import_react16.useCallback)((message, onConfirm, onCancel = null) => {
3569
3944
  return notification.showAction(message, [
3570
3945
  {
3571
3946
  label: "Confirm",
@@ -3584,28 +3959,28 @@ var useNotifications = () => {
3584
3959
  title: "Confirmation Required"
3585
3960
  });
3586
3961
  }, [notification]);
3587
- const notifyLoading = (0, import_react15.useCallback)((message) => {
3962
+ const notifyLoading = (0, import_react16.useCallback)((message) => {
3588
3963
  return notification.showLoading(message);
3589
3964
  }, [notification]);
3590
- const stopLoading = (0, import_react15.useCallback)((notificationId) => {
3965
+ const stopLoading = (0, import_react16.useCallback)((notificationId) => {
3591
3966
  notification.removeNotification(notificationId);
3592
3967
  }, [notification]);
3593
- const notifyNetworkError = (0, import_react15.useCallback)(() => {
3968
+ const notifyNetworkError = (0, import_react16.useCallback)(() => {
3594
3969
  return notification.showError("Network connection lost. Please check your internet connection.", {
3595
3970
  title: "Connection Error",
3596
3971
  persistent: true,
3597
3972
  actions: [{
3598
3973
  label: "Retry",
3599
- icon: /* @__PURE__ */ React.createElement(import_icons_material4.Refresh, null),
3974
+ icon: /* @__PURE__ */ React.createElement(import_icons_material5.Refresh, null),
3600
3975
  color: "error",
3601
3976
  onClick: () => window.location.reload()
3602
3977
  }]
3603
3978
  });
3604
3979
  }, [notification]);
3605
- const notifyNetworkReconnected = (0, import_react15.useCallback)(() => {
3980
+ const notifyNetworkReconnected = (0, import_react16.useCallback)(() => {
3606
3981
  return notification.showSuccess("Connection restored");
3607
3982
  }, [notification]);
3608
- const notifyMaintenance = (0, import_react15.useCallback)((message, scheduledTime) => {
3983
+ const notifyMaintenance = (0, import_react16.useCallback)((message, scheduledTime) => {
3609
3984
  return notification.showWarning(message, {
3610
3985
  title: "Scheduled Maintenance",
3611
3986
  persistent: true,
@@ -3616,18 +3991,18 @@ var useNotifications = () => {
3616
3991
  }]
3617
3992
  });
3618
3993
  }, [notification]);
3619
- const notifyPermissionDenied = (0, import_react15.useCallback)((action = "perform this action") => {
3994
+ const notifyPermissionDenied = (0, import_react16.useCallback)((action = "perform this action") => {
3620
3995
  return notification.showError(`You don't have permission to ${action}`, {
3621
3996
  title: "Access Denied",
3622
3997
  duration: 6e3
3623
3998
  });
3624
3999
  }, [notification]);
3625
- const notifyDataOutOfSync = (0, import_react15.useCallback)((onRefresh) => {
4000
+ const notifyDataOutOfSync = (0, import_react16.useCallback)((onRefresh) => {
3626
4001
  return notification.showWarning("Data may be outdated", {
3627
4002
  title: "Sync Warning",
3628
4003
  actions: [{
3629
4004
  label: "Refresh",
3630
- icon: /* @__PURE__ */ React.createElement(import_icons_material4.Refresh, null),
4005
+ icon: /* @__PURE__ */ React.createElement(import_icons_material5.Refresh, null),
3631
4006
  onClick: onRefresh
3632
4007
  }]
3633
4008
  });
@@ -3655,7 +4030,7 @@ var useNotifications = () => {
3655
4030
  };
3656
4031
 
3657
4032
  // src/hooks/useUnifiedNotifications.js
3658
- var import_react16 = require("react");
4033
+ var import_react17 = require("react");
3659
4034
 
3660
4035
  // src/utils/unifiedNotifications.js
3661
4036
  var NOTIFICATION_TYPES = {
@@ -4025,17 +4400,17 @@ var setSocketContext = (context) => unifiedNotificationManager.setSocketContext(
4025
4400
  var useUnifiedNotifications = () => {
4026
4401
  const toastContext = useNotification();
4027
4402
  const socketContext = useSocket();
4028
- (0, import_react16.useEffect)(() => {
4403
+ (0, import_react17.useEffect)(() => {
4029
4404
  if (toastContext) {
4030
4405
  setToastContext(toastContext);
4031
4406
  }
4032
4407
  }, [toastContext]);
4033
- (0, import_react16.useEffect)(() => {
4408
+ (0, import_react17.useEffect)(() => {
4034
4409
  if (socketContext) {
4035
4410
  setSocketContext(socketContext);
4036
4411
  }
4037
4412
  }, [socketContext]);
4038
- const initializePushNotifications = (0, import_react16.useCallback)(async () => {
4413
+ const initializePushNotifications = (0, import_react17.useCallback)(async () => {
4039
4414
  try {
4040
4415
  await requestNotificationPermission();
4041
4416
  await subscribeToPushNotifications();
@@ -4045,21 +4420,21 @@ var useUnifiedNotifications = () => {
4045
4420
  return false;
4046
4421
  }
4047
4422
  }, []);
4048
- const showSuccess = (0, import_react16.useCallback)((message, title, options = {}) => {
4423
+ const showSuccess = (0, import_react17.useCallback)((message, title, options = {}) => {
4049
4424
  return notifySuccess(message, title, {
4050
4425
  channels: [NOTIFICATION_CHANNELS.TOAST],
4051
4426
  sound: true,
4052
4427
  ...options
4053
4428
  });
4054
4429
  }, []);
4055
- const showError = (0, import_react16.useCallback)((message, title, options = {}) => {
4430
+ const showError = (0, import_react17.useCallback)((message, title, options = {}) => {
4056
4431
  return notifyError(message, title, {
4057
4432
  channels: [NOTIFICATION_CHANNELS.TOAST, NOTIFICATION_CHANNELS.BROWSER],
4058
4433
  persistent: true,
4059
4434
  ...options
4060
4435
  });
4061
4436
  }, []);
4062
- const showWarning = (0, import_react16.useCallback)((message, title, options = {}) => {
4437
+ const showWarning = (0, import_react17.useCallback)((message, title, options = {}) => {
4063
4438
  return notify({
4064
4439
  message,
4065
4440
  title,
@@ -4068,7 +4443,7 @@ var useUnifiedNotifications = () => {
4068
4443
  ...options
4069
4444
  });
4070
4445
  }, []);
4071
- const showInfo = (0, import_react16.useCallback)((message, title, options = {}) => {
4446
+ const showInfo = (0, import_react17.useCallback)((message, title, options = {}) => {
4072
4447
  return notify({
4073
4448
  message,
4074
4449
  title,
@@ -4077,7 +4452,7 @@ var useUnifiedNotifications = () => {
4077
4452
  ...options
4078
4453
  });
4079
4454
  }, []);
4080
- const notifyTicket = (0, import_react16.useCallback)((ticket, changeType, options = {}) => {
4455
+ const notifyTicket = (0, import_react17.useCallback)((ticket, changeType, options = {}) => {
4081
4456
  return notifyTicketUpdate(ticket, changeType, {
4082
4457
  channels: [
4083
4458
  NOTIFICATION_CHANNELS.TOAST,
@@ -4087,7 +4462,7 @@ var useUnifiedNotifications = () => {
4087
4462
  ...options
4088
4463
  });
4089
4464
  }, []);
4090
- const notifyNewMessage = (0, import_react16.useCallback)((senderName, messageContent, propertyAddress, options = {}) => {
4465
+ const notifyNewMessage = (0, import_react17.useCallback)((senderName, messageContent, propertyAddress, options = {}) => {
4091
4466
  return notifyMessage(senderName, messageContent, propertyAddress, {
4092
4467
  channels: [
4093
4468
  NOTIFICATION_CHANNELS.BROWSER,
@@ -4097,7 +4472,7 @@ var useUnifiedNotifications = () => {
4097
4472
  ...options
4098
4473
  });
4099
4474
  }, []);
4100
- const notifySystemAlert = (0, import_react16.useCallback)((message, title, options = {}) => {
4475
+ const notifySystemAlert = (0, import_react17.useCallback)((message, title, options = {}) => {
4101
4476
  return notify({
4102
4477
  message,
4103
4478
  title,
@@ -4112,7 +4487,7 @@ var useUnifiedNotifications = () => {
4112
4487
  ...options
4113
4488
  });
4114
4489
  }, []);
4115
- const showLoading = (0, import_react16.useCallback)((message, options = {}) => {
4490
+ const showLoading = (0, import_react17.useCallback)((message, options = {}) => {
4116
4491
  return notify({
4117
4492
  message,
4118
4493
  type: NOTIFICATION_TYPES.LOADING,
@@ -4121,7 +4496,7 @@ var useUnifiedNotifications = () => {
4121
4496
  ...options
4122
4497
  });
4123
4498
  }, []);
4124
- const notifyImportant = (0, import_react16.useCallback)((message, title, options = {}) => {
4499
+ const notifyImportant = (0, import_react17.useCallback)((message, title, options = {}) => {
4125
4500
  return notify({
4126
4501
  message,
4127
4502
  title,
@@ -4136,7 +4511,7 @@ var useUnifiedNotifications = () => {
4136
4511
  ...options
4137
4512
  });
4138
4513
  }, []);
4139
- const notifyBatch = (0, import_react16.useCallback)(async (notifications) => {
4514
+ const notifyBatch = (0, import_react17.useCallback)(async (notifications) => {
4140
4515
  const results = [];
4141
4516
  for (const notification of notifications) {
4142
4517
  try {
@@ -4277,11 +4652,11 @@ var useAccessibleColors = () => {
4277
4652
  };
4278
4653
 
4279
4654
  // src/hooks/useContrastText.js
4280
- var import_react17 = require("react");
4655
+ var import_react18 = require("react");
4281
4656
  var import_styles4 = require("@mui/material/styles");
4282
4657
  var useContrastText = () => {
4283
4658
  const theme = (0, import_styles4.useTheme)();
4284
- const utils = (0, import_react17.useMemo)(() => ({
4659
+ const utils = (0, import_react18.useMemo)(() => ({
4285
4660
  /**
4286
4661
  * Get accessible text color for any background color
4287
4662
  * @param {string} backgroundColor - Background color in hex format
@@ -4963,6 +5338,7 @@ var isTenantAuthenticated = () => {
4963
5338
  NOTIFICATION_CHANNELS,
4964
5339
  NOTIFICATION_TYPES,
4965
5340
  Navbar,
5341
+ NotificationBell,
4966
5342
  NotificationManager,
4967
5343
  NotificationPatterns,
4968
5344
  NotificationProvider,