From 2dbcfbe924457840b42e8a89ffb9d42c1f0e1614 Mon Sep 17 00:00:00 2001 From: MohamedHasan07 Date: Tue, 21 Jul 2026 16:56:53 +0530 Subject: [PATCH] v2.3 updates in {tosat floder structure and svg for data not found --- public/images/original_Svg.svg | 195 ++++++++ src/components/customs/DataTable.tsx | 10 +- src/components/customs/EmptyState.tsx | 16 +- .../customs/EmptyStateIllustration.tsx | 229 +++++++++ src/components/layouts/Headers.tsx | 171 +++++-- src/components/layouts/Sidebar.tsx | 11 +- src/features/assets/pages/AssetList.tsx | 105 ++-- src/features/assets/pages/NewAsset.tsx | 55 ++- .../attributes/pages/AttributeList.tsx | 24 +- .../attributes/pages/NewAttribute.tsx | 12 +- .../attributes/types/attribute.types.ts | 4 + src/features/contacts/api/contact.api.ts | 0 .../contacts/components/ContactTable.tsx | 0 src/features/contacts/hook/useContact.ts | 0 src/features/contacts/index.ts | 0 src/features/contacts/pages/NewContact.tsx | 0 .../contacts/routes/contact.routes.tsx | 0 .../contacts/services/contact.service.ts | 0 src/features/contacts/types/contact.types.ts | 0 .../contacts/validation/contact.schema.ts | 0 .../product/components/ProductAssetsTab.tsx | 43 +- src/features/product/pages/NewProduct.tsx | 6 +- src/features/roles/pages/RoleList.tsx | 26 +- src/features/settings/pages/ThemeSettings.tsx | 7 - .../settings/routes/settings.routes.tsx | 1 + src/features/units/pages/NewUnit.tsx | 272 +++++------ src/features/users/pages/NewUser.tsx | 208 ++++++-- src/features/users/pages/UserList.tsx | 451 +++++++++++++++--- src/features/users/routes/users.routes.tsx | 2 + src/routes/routeConfig.ts | 28 +- src/services/toast/components/CloseButton.tsx | 23 - src/services/toast/components/ProgressBar.tsx | 38 -- src/services/toast/components/Toast.css | 300 ------------ src/services/toast/components/Toast.tsx | 180 ++++--- .../toast/components/ToastContainer.tsx | 4 +- src/services/toast/components/ToastIcons.tsx | 12 - .../toast/components/ToastProvider.tsx | 41 ++ src/services/toast/hooks/useToast.ts | 5 +- .../toast/hooks/useToastRouteCleanup.ts | 33 -- src/services/toast/index.ts | 35 +- src/services/toast/messages/index.ts | 7 - .../toast/messages/system.messages.ts | 45 -- .../toast/{ => services}/toast.service.ts | 191 ++++++-- src/services/toast/styles/toast.css | 121 +++++ src/services/toast/toast.config.ts | 73 --- src/services/toast/toast.errors.ts | 103 ---- src/services/toast/toast.factory.ts | 55 --- src/services/toast/toast.icons.tsx | 83 ---- src/services/toast/toast.internal.ts | 59 --- src/services/toast/toast.promise.ts | 78 --- src/services/toast/toast.provider.tsx | 36 -- src/services/toast/toast.registry.ts | 76 --- src/services/toast/toast.types.ts | 93 ---- src/services/toast/toast.utils.ts | 149 ------ src/services/toast/types/toast.types.ts | 56 +++ src/services/toast/utils/toast.utils.ts | 184 +++++++ 56 files changed, 2111 insertions(+), 1845 deletions(-) create mode 100644 public/images/original_Svg.svg create mode 100644 src/components/customs/EmptyStateIllustration.tsx delete mode 100644 src/features/contacts/api/contact.api.ts delete mode 100644 src/features/contacts/components/ContactTable.tsx delete mode 100644 src/features/contacts/hook/useContact.ts delete mode 100644 src/features/contacts/index.ts delete mode 100644 src/features/contacts/pages/NewContact.tsx delete mode 100644 src/features/contacts/routes/contact.routes.tsx delete mode 100644 src/features/contacts/services/contact.service.ts delete mode 100644 src/features/contacts/types/contact.types.ts delete mode 100644 src/features/contacts/validation/contact.schema.ts delete mode 100644 src/services/toast/components/CloseButton.tsx delete mode 100644 src/services/toast/components/ProgressBar.tsx delete mode 100644 src/services/toast/components/Toast.css delete mode 100644 src/services/toast/components/ToastIcons.tsx create mode 100644 src/services/toast/components/ToastProvider.tsx delete mode 100644 src/services/toast/hooks/useToastRouteCleanup.ts delete mode 100644 src/services/toast/messages/index.ts delete mode 100644 src/services/toast/messages/system.messages.ts rename src/services/toast/{ => services}/toast.service.ts (50%) create mode 100644 src/services/toast/styles/toast.css delete mode 100644 src/services/toast/toast.config.ts delete mode 100644 src/services/toast/toast.errors.ts delete mode 100644 src/services/toast/toast.factory.ts delete mode 100644 src/services/toast/toast.icons.tsx delete mode 100644 src/services/toast/toast.internal.ts delete mode 100644 src/services/toast/toast.promise.ts delete mode 100644 src/services/toast/toast.provider.tsx delete mode 100644 src/services/toast/toast.registry.ts delete mode 100644 src/services/toast/toast.types.ts delete mode 100644 src/services/toast/toast.utils.ts create mode 100644 src/services/toast/types/toast.types.ts create mode 100644 src/services/toast/utils/toast.utils.ts diff --git a/public/images/original_Svg.svg b/public/images/original_Svg.svg new file mode 100644 index 0000000..e015c6e --- /dev/null +++ b/public/images/original_Svg.svg @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No Data Found + There are no records to display. + + diff --git a/src/components/customs/DataTable.tsx b/src/components/customs/DataTable.tsx index 42cfdef..254e965 100644 --- a/src/components/customs/DataTable.tsx +++ b/src/components/customs/DataTable.tsx @@ -1,4 +1,5 @@ import { useState, useMemo, useRef, useEffect, type ReactNode } from "react"; +import { EmptyStateIllustration } from "./EmptyStateIllustration"; import { Search, X, ChevronsUpDown, ChevronUp, ChevronDown, ChevronLeft, ChevronRight, Settings2, Check, Filter @@ -37,6 +38,7 @@ export interface DataTableProps { onView?: (row: T) => void; onEdit?: (row: T) => void; onDelete?: (row: T) => void; + canDelete?: (row: T) => boolean; customActions?: (row: T) => CustomAction[]; }; } @@ -344,8 +346,10 @@ export function DataTable = any>({ ) : paged.length === 0 ? ( - - No records found + +
+ +
) : ( @@ -388,7 +392,7 @@ export function DataTable = any>({ actionConfig.onView!(row) : undefined} onEdit={actionConfig.onEdit ? () => actionConfig.onEdit!(row) : undefined} - onDelete={actionConfig.onDelete ? () => actionConfig.onDelete!(row) : undefined} + onDelete={(actionConfig.onDelete && (actionConfig.canDelete ? actionConfig.canDelete(row) : true)) ? () => actionConfig.onDelete!(row) : undefined} customActions={actionConfig.customActions ? actionConfig.customActions(row) : undefined} /> diff --git a/src/components/customs/EmptyState.tsx b/src/components/customs/EmptyState.tsx index 6f14655..5aa4668 100644 --- a/src/components/customs/EmptyState.tsx +++ b/src/components/customs/EmptyState.tsx @@ -1,11 +1,12 @@ import React from "react"; -import { Inbox } from "lucide-react"; +import { EmptyStateIllustration } from "./EmptyStateIllustration"; interface EmptyStateProps { title?: string; description?: string; action?: React.ReactNode; icon?: React.ReactNode; + illustration?: boolean; } export function EmptyState({ @@ -13,12 +14,17 @@ export function EmptyState({ description = "There are no items to display.", action, icon, + illustration = true, }: EmptyStateProps) { return ( -
-
- {icon ?? } -
+
+ {icon ? ( +
+ {icon} +
+ ) : illustration ? ( + + ) : null}

{title}

{description}

{action &&
{action}
} diff --git a/src/components/customs/EmptyStateIllustration.tsx b/src/components/customs/EmptyStateIllustration.tsx new file mode 100644 index 0000000..6d2b07b --- /dev/null +++ b/src/components/customs/EmptyStateIllustration.tsx @@ -0,0 +1,229 @@ +export function EmptyStateIllustration({ className }: { className?: string }) { + return ( + + + {/* Inner Cavity Gradient using Theme Variables */} + + + + + + {/* Handle Gradient using Theme Variables */} + + + + + + + + + {/* 1. Background Soft Cloud/Blob */} + + + + {/* Dotted Arc behind graphic */} + + + + {/* 2. Floating Sparkles / 4-Point Stars */} + + {/* Top Left */} + + {/* Top Right */} + + {/* Mid Left */} + + {/* Bottom Right */} + + {/* Near Database */} + + + + {/* 3. Ground Shadow under Box */} + + + + + + {/* 4. Database Cylinder Stack (Top Left) */} + + + + {/* Lower Disk */} + + + + {/* Upper Disk */} + + + + {/* Inner Lines */} + + + + + {/* 5. Folder Icon (Bottom Left) */} + + {/* Back Cover */} + + + {/* Paper Sheet inside Folder */} + + + + + {/* Front Cover */} + + + + {/* 6. Document Card 1 (Top Right - Image Card) */} + + + + {/* Image Box */} + + {/* Mountain landscape */} + + + + {/* Text Lines */} + + + + + + {/* 7. Document Card 2 (Lower Right - Text Card with Folded Corner) */} + + {/* Card Body */} + + + {/* Folded Corner */} + + + {/* Text Lines */} + + + + + + + + {/* 8. Open Cardboard Box (3D Isometric Construction) */} + + {/* Back-Left Flap */} + + + {/* Back-Right Flap */} + + + {/* Inner Cavity */} + + + {/* Left Front Face */} + + + {/* Right Front Face */} + + + {/* Front-Left Flap */} + + + {/* Front-Right Flap */} + + + {/* Shipping Label / Sticker on Left Front Face */} + + + + + + + {/* Details on Right Front Face */} + + + + + + {/* Soft tint patch on right face */} + + + + + {/* 9. Floating Magnifying Glass (Center Top) */} + + {/* Handle */} + + + + {/* Lens Outer Rings */} + + + + {/* Lens Glass */} + + + {/* Reflection Arc */} + + + {/* Exclamation Mark ! */} + + + + + {/* 10. Text Labels */} + + + No Data Found + + + There are no records to display. + + + + ); +} diff --git a/src/components/layouts/Headers.tsx b/src/components/layouts/Headers.tsx index 59ecdc6..6f2ecef 100644 --- a/src/components/layouts/Headers.tsx +++ b/src/components/layouts/Headers.tsx @@ -1,13 +1,12 @@ import { useNavigate } from "react-router-dom"; -import { Bell, ChevronDown, Building2, Globe, LogOut } from "lucide-react"; +import { Bell, ChevronDown, Building2, Globe, LogOut, Shield, User, Settings, CheckCircle2, ChevronRight } from "lucide-react"; import { useLanguage, type Language } from "../../contexts/LanguageContext"; import { useHeader } from "../../contexts/HeaderContext"; import { useAppDispatch, useAppSelector } from "../../store"; import { logout } from "../../store/slices/authSlice"; import { useState, useRef, useEffect } from "react"; import { notificationService } from "../../features/notifications"; - - +import { notify } from "../../services/toast"; export function Header() { const { title, subtitle } = useHeader(); @@ -20,6 +19,17 @@ export function Header() { const [headerUnread, setHeaderUnread] = useState(0); const menuRef = useRef(null); + // Derive real-time display values from Redux user state + const userName = user?.name || user?.user_name || (user?.email ? user.email.split('@')[0] : "User"); + const userEmail = user?.email || "user@pim.com"; + const userInitials = userName.slice(0, 2).toUpperCase(); + + const roleName = user?.roles?.[0]?.name || user?.roles?.[0]?.role_name || user?.role_name || + (user?.type === 'platform' || user?.email === 'admin@admin.com' ? "Super Admin" : "Member"); + + const tenantName = user?.tenant?.name || user?.tenant_name || + (user?.type === 'platform' || !user?.tenant_id ? "Platform Core" : `Tenant #${user.tenant_id}`); + useEffect(() => { let mounted = true; const sync = async () => { @@ -28,18 +38,15 @@ export function Header() { }; sync(); - // Listen to socket for real-time updates const handleUnreadCount = (data: { unreadCount: number }) => { if (mounted) setHeaderUnread(data.unreadCount); }; - // The socket might not be immediately connected here depending on when Headers renders vs useNotifications - // But socketService caches listeners and binds them when connected. import("../../services/socket.service").then(({ socketService }) => { socketService.on("notification:unread-count", handleUnreadCount); }); - const id = setInterval(sync, 60_000); // Polling fallback + const id = setInterval(sync, 60_000); return () => { mounted = false; clearInterval(id); @@ -61,6 +68,7 @@ export function Header() { const handleLogout = () => { dispatch(logout()); + notify.info("Logged out successfully"); navigate("/login"); }; @@ -79,75 +87,154 @@ export function Header() { {/* Right Side Controls */}
+ {/* Language Selector */}
- + {/* Real-time Tenant Indicator Button */} +
+ + {tenantName} +
+ {/* Notifications Bell */}
+ {/* Profile Card Trigger & Popover */}
+ {/* Profile Card Popover (Senior Dev Card UI with Real-time Data) */} {showProfileMenu && ( -
- +
+ {/* User Header */} +
+
+
+ {userInitials} +
+ +
+ +
+

+ {userName} +

+

+ {userEmail} +

+
+ + + Active Session + +
+
+
+ + {/* Role & Tenant Real-time Badges */} +
+ {/* Real-time Role Badge */} +
+ + + Role + + + {roleName} + +
+ + {/* Real-time Tenant Badge */} +
+ + + Tenant + + + {tenantName} + +
+
+ + {/* Action Navigation */} +
+ + + +
+ + {/* Sign Out Action */} +
+ +
)}
diff --git a/src/components/layouts/Sidebar.tsx b/src/components/layouts/Sidebar.tsx index b15440a..1eb1f53 100644 --- a/src/components/layouts/Sidebar.tsx +++ b/src/components/layouts/Sidebar.tsx @@ -46,7 +46,7 @@ export function Sidebar() { const isChildActive = (item: NavItem): boolean => { if (!item.children) return false; - return item.children.some(child => isItemActive(child.href) || location.pathname.startsWith(child.href)); + return item.children.some(child => isItemActive(child.href)); }; const filterNavItems = (items: NavItem[]): NavItem[] => { @@ -89,11 +89,10 @@ export function Sidebar() {