@burdenoff/microfe-kadaikodi 2026.802.1 → 2026.830.1
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/dist/kadaikodi/KadaikodiRoot.d.ts.map +1 -1
- package/dist/kadaikodi/KadaikodiRoot.js +69 -72
- package/dist/kadaikodi/KadaikodiRoot.js.map +1 -1
- package/dist/kadaikodi/components/InvestmentCard.d.ts.map +1 -1
- package/dist/kadaikodi/components/InvestmentCard.js +58 -54
- package/dist/kadaikodi/components/InvestmentCard.js.map +1 -1
- package/dist/kadaikodi/components/OrderCard.d.ts.map +1 -1
- package/dist/kadaikodi/components/StatusBadge.d.ts.map +1 -1
- package/dist/kadaikodi/components/StatusBadge.js +25 -14
- package/dist/kadaikodi/components/StatusBadge.js.map +1 -1
- package/dist/kadaikodi/hooks/useKadaikodiApi.d.ts +24 -0
- package/dist/kadaikodi/hooks/useKadaikodiApi.d.ts.map +1 -1
- package/dist/kadaikodi/hooks/useKadaikodiApi.js +177 -132
- package/dist/kadaikodi/hooks/useKadaikodiApi.js.map +1 -1
- package/dist/kadaikodi/pages/HomePage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/HomePage.js +284 -282
- package/dist/kadaikodi/pages/HomePage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.d.ts +7 -2
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.js +319 -228
- package/dist/kadaikodi/pages/admin/AdminAnalyticsPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.js +1 -1
- package/dist/kadaikodi/pages/admin/AdminOrdersPage.js.map +1 -1
- package/dist/kadaikodi/pages/admin/CartManagementPage.d.ts +10 -4
- package/dist/kadaikodi/pages/admin/CartManagementPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/admin/CartManagementPage.js +320 -279
- package/dist/kadaikodi/pages/admin/CartManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.js +365 -292
- package/dist/kadaikodi/pages/cart-owner/MerchantOnboardingPage.js.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.d.ts +7 -2
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.js +300 -158
- package/dist/kadaikodi/pages/cart-owner/StaffManagementPage.js.map +1 -1
- package/dist/kadaikodi/pages/common/SettingsPage.js +286 -286
- package/dist/kadaikodi/pages/common/SettingsPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDetailPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDetailPage.js +3 -3
- package/dist/kadaikodi/pages/customer/CartDetailPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.d.ts +13 -3
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.js +270 -220
- package/dist/kadaikodi/pages/customer/CartDiscoveryPage.js.map +1 -1
- package/dist/kadaikodi/pages/customer/CustomerDashboard.js +97 -97
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.js +1 -1
- package/dist/kadaikodi/pages/customer/OrderTrackingPage.js.map +1 -1
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.d.ts +5 -3
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.d.ts.map +1 -1
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.js +286 -199
- package/dist/kadaikodi/pages/worker/TaskDetailsPage.js.map +1 -1
- package/dist/kadaikodi/types/index.d.ts +46 -2
- package/dist/kadaikodi/types/index.d.ts.map +1 -1
- package/dist/shared/hooks/useTr.d.ts +2 -0
- package/dist/shared/hooks/useTr.d.ts.map +1 -0
- package/dist/shared/hooks/useTr.js +14 -0
- package/dist/shared/hooks/useTr.js.map +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StaffManagementPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/cart-owner/StaffManagementPage.tsx"],"sourcesContent":["/**\n * Staff Management Page\n *\n * Team overview and roster for the signed-in owner's own service provider (cart).\n * Lists the provider's real workers (useProviderWorkers) with role/status filters\n * and search, and invites new workers (useCreateProviderWorker). No fabricated\n * staff, performance metrics, or earnings.\n *\n * @module kadaikodi/pages/cart-owner\n */\n\nimport { useState, useMemo } from 'react';\nimport {\n UserPlus,\n Phone,\n Search,\n X,\n Mail,\n CheckCircle2,\n AlertCircle,\n Users,\n Clock,\n Briefcase,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { StatCard, AvatarStack } from '../../components/viz';\nimport type { Person } from '../../components/viz';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport {\n useProviders,\n useProviderWorkers,\n useCreateProviderWorker,\n type KadaikodiProviderWorkerRow,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface InviteForm {\n name: string;\n email: string;\n phone: string;\n role: string;\n}\n\ninterface StatusMessage {\n text: string;\n type: 'success' | 'error';\n}\n\ninterface WorkerMetadata {\n email?: string;\n phone?: string;\n}\n\n// ============================================================================\n// Constants & helpers\n// ============================================================================\n\nconst ROLE_OPTIONS = ['MANAGER', 'CHEF', 'SERVER', 'DELIVERY', 'CASHIER'] as const;\n\nconst prettify = (s: string): string =>\n s\n .replace(/_/g, ' ')\n .toLowerCase()\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n\nconst statusColor = (status: string): { label: string; color: string; dot: string } => {\n const s = status.toUpperCase();\n if (s === 'ACTIVE')\n return {\n label: prettify(status),\n color: 'text-status-success-text',\n dot: 'bg-status-success-text',\n };\n if (s === 'ON_LEAVE' || s === 'ON-LEAVE')\n return {\n label: prettify(status),\n color: 'text-status-warning-text',\n dot: 'bg-status-warning-text',\n };\n return { label: prettify(status), color: 'text-text-secondary', dot: 'bg-muted-foreground' };\n};\n\nconst readMetadata = (metadata: Record<string, unknown> | null | undefined): WorkerMetadata => {\n if (!metadata || typeof metadata !== 'object') return {};\n const m = metadata as Record<string, unknown>;\n return {\n email: typeof m.email === 'string' ? m.email : undefined,\n phone: typeof m.phone === 'string' ? m.phone : undefined,\n };\n};\n\nconst emptyInviteForm: InviteForm = {\n name: '',\n email: '',\n phone: '',\n role: 'SERVER',\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const StaffManagementPage = () => {\n const { currentUser } = useKadaikodi();\n\n // Resolve the signed-in owner's provider (\"my cart\"), then load its workers.\n const { data: providers = [], isLoading: providersLoading } = useProviders();\n const myProvider = useMemo(\n () => providers.find((p) => p.ownerId === currentUser?.id) ?? providers[0],\n [providers, currentUser?.id]\n );\n const providerId = myProvider?.id;\n const { data: workers = [], isLoading: workersLoading } = useProviderWorkers(providerId);\n const createWorker = useCreateProviderWorker();\n\n // Filters\n const [searchQuery, setSearchQuery] = useState('');\n const [roleFilter, setRoleFilter] = useState('');\n const [statusFilter, setStatusFilter] = useState('');\n\n // Invite modal\n const [showInviteModal, setShowInviteModal] = useState(false);\n const [inviteForm, setInviteForm] = useState<InviteForm>(emptyInviteForm);\n\n // Status\n const [statusMessage, setStatusMessage] = useState<StatusMessage | null>(null);\n\n const showStatus = (text: string, type: 'success' | 'error') => {\n setStatusMessage({ text, type });\n setTimeout(() => setStatusMessage(null), 3000);\n };\n\n // ---- Derived ----\n const roles = useMemo(() => [...new Set(workers.map((w) => w.role))].sort(), [workers]);\n const statuses = useMemo(() => [...new Set(workers.map((w) => w.status))].sort(), [workers]);\n\n const activeCount = workers.filter((w) => w.status.toUpperCase() === 'ACTIVE').length;\n const onLeaveCount = workers.filter((w) => {\n const s = w.status.toUpperCase();\n return s === 'ON_LEAVE' || s === 'ON-LEAVE';\n }).length;\n\n const filteredStaff = useMemo(() => {\n let result = [...workers];\n if (searchQuery) {\n const q = searchQuery.toLowerCase();\n result = result.filter((w) => {\n const meta = readMetadata(w.metadata);\n return (\n w.name.toLowerCase().includes(q) ||\n w.role.toLowerCase().includes(q) ||\n (meta.email ?? '').toLowerCase().includes(q) ||\n (meta.phone ?? '').includes(q)\n );\n });\n }\n if (roleFilter) result = result.filter((w) => w.role === roleFilter);\n if (statusFilter) result = result.filter((w) => w.status === statusFilter);\n result.sort((a, b) => a.name.localeCompare(b.name));\n return result;\n }, [workers, searchQuery, roleFilter, statusFilter]);\n\n const hasActiveFilters = Boolean(searchQuery || roleFilter || statusFilter);\n\n // ---- Handlers ----\n const handleInvite = () => {\n if (!inviteForm.name.trim() || !inviteForm.role) {\n showStatus('Please provide a name and role', 'error');\n return;\n }\n if (!providerId) {\n showStatus('No cart found to add staff to', 'error');\n return;\n }\n createWorker.mutate(\n {\n providerId,\n name: inviteForm.name.trim(),\n role: inviteForm.role,\n workerId: inviteForm.email.trim() || inviteForm.name.trim(),\n metadata: {\n email: inviteForm.email.trim() || undefined,\n phone: inviteForm.phone.trim() || undefined,\n },\n },\n {\n onSuccess: () => {\n setShowInviteModal(false);\n setInviteForm(emptyInviteForm);\n showStatus('Staff member added successfully', 'success');\n },\n onError: () => showStatus('Could not add staff member. Please try again.', 'error'),\n }\n );\n };\n\n const renderWorkerRow = (member: KadaikodiProviderWorkerRow) => {\n const status = statusColor(member.status);\n const meta = readMetadata(member.metadata);\n const initials = member.name\n .split(' ')\n .map((p) => p[0])\n .filter(Boolean)\n .slice(0, 2)\n .join('')\n .toUpperCase();\n\n return (\n <div key={member.id} className=\"p-4 sm:p-5 hover:bg-bg-sunken/30 transition-colors\">\n <div className=\"flex flex-col sm:flex-row sm:items-center gap-4\">\n <div className=\"flex items-center gap-4 flex-1 min-w-0\">\n <div className=\"relative shrink-0\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-bg-sunken text-sm font-semibold text-text-primary\">\n {initials || '?'}\n </div>\n <span\n className={cn(\n 'absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 rounded-full border-2 border-card',\n status.dot\n )}\n />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <p className=\"text-sm font-medium text-text-primary\">{member.name}</p>\n <span className=\"inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium bg-[var(--color-accent-soft)] text-text-primary\">\n {prettify(member.role)}\n </span>\n <span className={cn('text-xs', status.color)}>{status.label}</span>\n </div>\n {(meta.email || meta.phone) && (\n <div className=\"flex items-center gap-3 mt-1 text-xs text-text-secondary flex-wrap\">\n {meta.email && (\n <span className=\"flex items-center gap-1\">\n <Mail className=\"h-3 w-3\" />\n {meta.email}\n </span>\n )}\n {meta.phone && (\n <span className=\"flex items-center gap-1\">\n <Phone className=\"h-3 w-3\" />\n {meta.phone}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n </div>\n </div>\n );\n };\n\n return (\n <PageLayout\n title=\"Staff Management\"\n description=\"Manage your workers and delivery partners\"\n actions={\n <button\n type=\"button\"\n onClick={() => {\n setInviteForm(emptyInviteForm);\n setShowInviteModal(true);\n }}\n disabled={!providerId}\n className={cn(\n 'inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors',\n providerId\n ? 'bg-accent text-text-primary hover:bg-accent/80'\n : 'bg-bg-sunken text-text-secondary cursor-not-allowed'\n )}\n >\n <UserPlus className=\"h-4 w-4\" />\n Add Staff\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n Your team in one place. Use this page to add workers and delivery partners to your cart, see\n who's active, and keep your roster organised so orders go out on time. Build a reliable\n crew around your cart.\n </PagePurpose>\n\n <div className=\"space-y-4\">\n {/* Status Message */}\n {statusMessage && (\n <div\n className={cn(\n 'flex items-center gap-2 rounded-lg border p-3',\n statusMessage.type === 'success'\n ? 'border-status-success-text/30 bg-status-success-bg-subtle'\n : 'border-status-error-text/30 bg-status-error-bg-subtle'\n )}\n >\n {statusMessage.type === 'success' ? (\n <CheckCircle2 className=\"h-4 w-4 text-status-success-text\" />\n ) : (\n <AlertCircle className=\"h-4 w-4 text-status-error-text\" />\n )}\n <span\n className={cn(\n 'text-sm font-medium',\n statusMessage.type === 'success'\n ? 'text-status-success-text'\n : 'text-status-error-text'\n )}\n >\n {statusMessage.text}\n </span>\n </div>\n )}\n\n {providersLoading ? (\n <div className=\"flex items-center justify-center py-24\">\n <div className=\"h-10 w-10 animate-spin rounded-full border-b-2 border-foreground\" />\n </div>\n ) : !myProvider ? (\n <EmptyState\n illustration=\"empty-people\"\n title=\"Create your cart first\"\n description=\"You need a service provider before you can add staff. Set up your cart to get started.\"\n />\n ) : (\n <>\n {/* Summary Stats — the one emphasis zone for this page */}\n <EmphasisPanel>\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <h2 className=\"text-base font-semibold text-text-primary\">Team Overview</h2>\n {workers.length > 0 && (\n <AvatarStack\n people={workers.map((w): Person => ({ name: w.name, role: w.role }))}\n max={6}\n size={30}\n />\n )}\n </div>\n <div className=\"grid grid-cols-2 sm:grid-cols-4 gap-3\">\n <StatCard\n label=\"Total Staff\"\n value={workers.length}\n icon={<Users className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Active\"\n value={<span className=\"text-status-success-text\">{activeCount}</span>}\n icon={<CheckCircle2 className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"On Leave\"\n value={<span className=\"text-status-warning-text\">{onLeaveCount}</span>}\n icon={<Clock className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Roles\"\n value={roles.length}\n icon={<Briefcase className=\"h-4 w-4\" />}\n />\n </div>\n </EmphasisPanel>\n\n {/* Filters */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 shadow-sm\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"text\"\n placeholder=\"Search staff...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface pl-10 pr-4 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <select\n value={roleFilter}\n onChange={(e) => setRoleFilter(e.target.value)}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"\">All Roles</option>\n {roles.map((r) => (\n <option key={r} value={r}>\n {prettify(r)}\n </option>\n ))}\n </select>\n <select\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value)}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"\">All Status</option>\n {statuses.map((s) => (\n <option key={s} value={s}>\n {prettify(s)}\n </option>\n ))}\n </select>\n </div>\n </div>\n\n {/* Staff List */}\n {workersLoading ? (\n <div className=\"flex items-center justify-center py-16\">\n <div className=\"h-10 w-10 animate-spin rounded-full border-b-2 border-foreground\" />\n </div>\n ) : filteredStaff.length === 0 ? (\n <EmptyState\n illustration={hasActiveFilters ? 'empty-search' : 'empty-people'}\n title=\"No staff members found\"\n description={\n hasActiveFilters\n ? 'No team members match your current filters. Try clearing them or searching for a different name.'\n : 'You have no staff yet. Add your first worker or delivery partner to start building your team.'\n }\n action={\n hasActiveFilters ? (\n <button\n type=\"button\"\n onClick={() => {\n setSearchQuery('');\n setRoleFilter('');\n setStatusFilter('');\n }}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n Clear filters\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={() => {\n setInviteForm(emptyInviteForm);\n setShowInviteModal(true);\n }}\n className=\"inline-flex items-center gap-2 rounded-md bg-accent px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent/80\"\n >\n <UserPlus className=\"h-4 w-4\" />\n Add Staff\n </button>\n )\n }\n />\n ) : (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface shadow-sm divide-y divide-border\">\n {filteredStaff.map(renderWorkerRow)}\n </div>\n )}\n </>\n )}\n </div>\n\n {/* Invite Staff Modal */}\n {showInviteModal && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div className=\"w-full max-w-lg rounded-lg border border-border-subtle bg-bg-surface shadow-xl\">\n <div className=\"p-6\">\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-lg font-semibold text-text-primary\">Add Staff Member</h3>\n <button\n type=\"button\"\n onClick={() => setShowInviteModal(false)}\n className=\"rounded p-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-sunken\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n Full Name *\n </label>\n <input\n type=\"text\"\n value={inviteForm.name}\n onChange={(e) => setInviteForm((p) => ({ ...p, name: e.target.value }))}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Email</label>\n <input\n type=\"email\"\n value={inviteForm.email}\n onChange={(e) => setInviteForm((p) => ({ ...p, email: e.target.value }))}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n Phone\n </label>\n <input\n type=\"tel\"\n value={inviteForm.phone}\n onChange={(e) => setInviteForm((p) => ({ ...p, phone: e.target.value }))}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n Role *\n </label>\n <select\n value={inviteForm.role}\n onChange={(e) => setInviteForm((p) => ({ ...p, role: e.target.value }))}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n {ROLE_OPTIONS.map((r) => (\n <option key={r} value={r}>\n {prettify(r)}\n </option>\n ))}\n </select>\n </div>\n </div>\n </div>\n <div className=\"flex gap-3 mt-6\">\n <button\n type=\"button\"\n onClick={() => setShowInviteModal(false)}\n className=\"flex-1 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleInvite}\n disabled={createWorker.isPending}\n className={cn(\n 'flex-1 rounded-md px-4 py-2 text-sm font-medium transition-colors',\n createWorker.isPending\n ? 'bg-bg-sunken text-text-secondary cursor-not-allowed'\n : 'bg-accent text-text-primary hover:bg-accent/80'\n )}\n >\n {createWorker.isPending ? 'Adding...' : 'Add Staff'}\n </button>\n </div>\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AA+DA,IAAM,KAAe;CAAC;CAAW;CAAQ;CAAU;CAAY;CAAU,EAEnE,KAAY,MAChB,EACG,QAAQ,MAAM,IAAI,CAClB,aAAa,CACb,QAAQ,UAAU,MAAM,EAAE,aAAa,CAAC,EAEvC,KAAe,MAAkE;CACrF,IAAM,IAAI,EAAO,aAAa;AAa9B,QAZI,MAAM,WACD;EACL,OAAO,EAAS,EAAO;EACvB,OAAO;EACP,KAAK;EACN,GACC,MAAM,cAAc,MAAM,aACrB;EACL,OAAO,EAAS,EAAO;EACvB,OAAO;EACP,KAAK;EACN,GACI;EAAE,OAAO,EAAS,EAAO;EAAE,OAAO;EAAuB,KAAK;EAAuB;GAGxF,KAAgB,MAAyE;AAC7F,KAAI,CAAC,KAAY,OAAO,KAAa,SAAU,QAAO,EAAE;CACxD,IAAM,IAAI;AACV,QAAO;EACL,OAAO,OAAO,EAAE,SAAU,WAAW,EAAE,QAAQ,KAAA;EAC/C,OAAO,OAAO,EAAE,SAAU,WAAW,EAAE,QAAQ,KAAA;EAChD;GAGG,IAA8B;CAClC,MAAM;CACN,OAAO;CACP,OAAO;CACP,MAAM;CACP,EAMY,UAA4B;CACvC,IAAM,EAAE,mBAAgB,GAAc,EAGhC,EAAE,MAAM,IAAY,EAAE,EAAE,WAAW,MAAqB,GAAc,EACtE,IAAa,QACX,EAAU,MAAM,MAAM,EAAE,YAAY,GAAa,GAAG,IAAI,EAAU,IACxE,CAAC,GAAW,GAAa,GAAG,CAC7B,EACK,IAAa,GAAY,IACzB,EAAE,MAAM,IAAU,EAAE,EAAE,WAAW,MAAmB,EAAmB,EAAW,EAClF,IAAe,GAAyB,EAGxC,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAY,KAAiB,EAAS,GAAG,EAC1C,CAAC,GAAc,KAAmB,EAAS,GAAG,EAG9C,CAAC,GAAiB,KAAsB,EAAS,GAAM,EACvD,CAAC,GAAY,KAAiB,EAAqB,EAAgB,EAGnE,CAAC,GAAe,KAAoB,EAA+B,KAAK,EAExE,KAAc,GAAc,MAA8B;AAE9D,EADA,EAAiB;GAAE;GAAM;GAAM,CAAC,EAChC,iBAAiB,EAAiB,KAAK,EAAE,IAAK;IAI1C,IAAQ,QAAc,CAAC,GAAG,IAAI,IAAI,EAAQ,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAQ,CAAC,EACjF,KAAW,QAAc,CAAC,GAAG,IAAI,IAAI,EAAQ,KAAK,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAQ,CAAC,EAEtF,KAAc,EAAQ,QAAQ,MAAM,EAAE,OAAO,aAAa,KAAK,SAAS,CAAC,QACzE,KAAe,EAAQ,QAAQ,MAAM;EACzC,IAAM,IAAI,EAAE,OAAO,aAAa;AAChC,SAAO,MAAM,cAAc,MAAM;GACjC,CAAC,QAEG,IAAgB,QAAc;EAClC,IAAI,IAAS,CAAC,GAAG,EAAQ;AACzB,MAAI,GAAa;GACf,IAAM,IAAI,EAAY,aAAa;AACnC,OAAS,EAAO,QAAQ,MAAM;IAC5B,IAAM,IAAO,EAAa,EAAE,SAAS;AACrC,WACE,EAAE,KAAK,aAAa,CAAC,SAAS,EAAE,IAChC,EAAE,KAAK,aAAa,CAAC,SAAS,EAAE,KAC/B,EAAK,SAAS,IAAI,aAAa,CAAC,SAAS,EAAE,KAC3C,EAAK,SAAS,IAAI,SAAS,EAAE;KAEhC;;AAKJ,SAHI,MAAY,IAAS,EAAO,QAAQ,MAAM,EAAE,SAAS,EAAW,GAChE,MAAc,IAAS,EAAO,QAAQ,MAAM,EAAE,WAAW,EAAa,GAC1E,EAAO,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,CAAC,EAC5C;IACN;EAAC;EAAS;EAAa;EAAY;EAAa,CAAC,EAE9C,IAAmB,GAAQ,KAAe,KAAc;AA2F9D,QACE,kBAAC,GAAD;EACE,OAAM;EACN,aAAY;EACZ,SACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe;AAEb,IADA,EAAc,EAAgB,EAC9B,EAAmB,GAAK;;GAE1B,UAAU,CAAC;GACX,WAAW,EACT,6FACA,IACI,mDACA,sDACL;aAZH,CAcE,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA,EAAA,YAEzB;;YApBb;GAuBE,kBAAC,GAAD;IAAa,WAAU;cAAO;IAIhB,CAAA;GAEd,kBAAC,OAAD;IAAK,WAAU;cAAf,CAEG,KACC,kBAAC,OAAD;KACE,WAAW,EACT,iDACA,EAAc,SAAS,YACnB,8DACA,wDACL;eANH,CAQG,EAAc,SAAS,YACtB,kBAAC,GAAD,EAAc,WAAU,oCAAqC,CAAA,GAE7D,kBAAC,GAAD,EAAa,WAAU,kCAAmC,CAAA,EAE5D,kBAAC,QAAD;MACE,WAAW,EACT,uBACA,EAAc,SAAS,YACnB,6BACA,yBACL;gBAEA,EAAc;MACV,CAAA,CACH;QAGP,IACC,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD,EAAK,WAAU,oEAAqE,CAAA;KAChF,CAAA,GACH,IAOH,kBAAA,GAAA,EAAA,UAAA;KAEE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBAA4C;OAAkB,CAAA,EAC3E,EAAQ,SAAS,KAChB,kBAAC,GAAD;OACE,QAAQ,EAAQ,KAAK,OAAe;QAAE,MAAM,EAAE;QAAM,MAAM,EAAE;QAAM,EAAE;OACpE,KAAK;OACL,MAAM;OACN,CAAA,CAEA;SACN,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,GAAD;QACE,OAAM;QACN,OAAO,EAAQ;QACf,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;QACnC,CAAA;OACF,kBAAC,GAAD;QACE,OAAM;QACN,OAAO,kBAAC,QAAD;SAAM,WAAU;mBAA4B;SAAmB,CAAA;QACtE,MAAM,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA;QAC1C,CAAA;OACF,kBAAC,GAAD;QACE,OAAM;QACN,OAAO,kBAAC,QAAD;SAAM,WAAU;mBAA4B;SAAoB,CAAA;QACvE,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;QACnC,CAAA;OACF,kBAAC,GAAD;QACE,OAAM;QACN,OAAO,EAAM;QACb,MAAM,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;QACvC,CAAA;OACE;QACQ,EAAA,CAAA;KAGhB,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,wEAAyE,CAAA,EAC3F,kBAAC,SAAD;UACE,MAAK;UACL,aAAY;UACZ,OAAO;UACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;UAC/C,WAAU;UACV,CAAA,CACE;;QACN,kBAAC,UAAD;SACE,OAAO;SACP,WAAW,MAAM,EAAc,EAAE,OAAO,MAAM;SAC9C,WAAU;mBAHZ,CAKE,kBAAC,UAAD;UAAQ,OAAM;oBAAG;UAAkB,CAAA,EAClC,EAAM,KAAK,MACV,kBAAC,UAAD;UAAgB,OAAO;oBACpB,EAAS,EAAE;UACL,EAFI,EAEJ,CACT,CACK;;QACT,kBAAC,UAAD;SACE,OAAO;SACP,WAAW,MAAM,EAAgB,EAAE,OAAO,MAAM;SAChD,WAAU;mBAHZ,CAKE,kBAAC,UAAD;UAAQ,OAAM;oBAAG;UAAmB,CAAA,EACnC,GAAS,KAAK,MACb,kBAAC,UAAD;UAAgB,OAAO;oBACpB,EAAS,EAAE;UACL,EAFI,EAEJ,CACT,CACK;;QACL;;MACF,CAAA;KAGL,IACC,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD,EAAK,WAAU,oEAAqE,CAAA;MAChF,CAAA,GACJ,EAAc,WAAW,IAC3B,kBAAC,GAAD;MACE,cAAc,IAAmB,iBAAiB;MAClD,OAAM;MACN,aACE,IACI,qGACA;MAEN,QACE,IACE,kBAAC,UAAD;OACE,MAAK;OACL,eAAe;AAGb,QAFA,EAAe,GAAG,EAClB,EAAc,GAAG,EACjB,EAAgB,GAAG;;OAErB,WAAU;iBACX;OAEQ,CAAA,GAET,kBAAC,UAAD;OACE,MAAK;OACL,eAAe;AAEb,QADA,EAAc,EAAgB,EAC9B,EAAmB,GAAK;;OAE1B,WAAU;iBANZ,CAQE,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA,EAAA,YAEzB;;MAGb,CAAA,GAEF,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAc,KAxPJ,MAAuC;OAC9D,IAAM,IAAS,EAAY,EAAO,OAAO,EACnC,IAAO,EAAa,EAAO,SAAS;AAS1C,cACE,kBAAC,OAAD;QAAqB,WAAU;kBAC7B,kBAAC,OAAD;SAAK,WAAU;mBACb,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,OAAD;YAAK,WAAU;sBAbR,EAAO,KACrB,MAAM,IAAI,CACV,KAAK,MAAM,EAAE,GAAG,CAChB,OAAO,QAAQ,CACf,MAAM,GAAG,EAAE,CACX,KAAK,GAAG,CACR,aAAa,IAQS;YACT,CAAA,EACN,kBAAC,QAAD,EACE,WAAW,EACT,iFACA,EAAO,IACR,EACD,CAAA,CACE;cACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,OAAD;YAAK,WAAU;sBAAf;aACE,kBAAC,KAAD;cAAG,WAAU;wBAAyC,EAAO;cAAS,CAAA;aACtE,kBAAC,QAAD;cAAM,WAAU;wBACb,EAAS,EAAO,KAAK;cACjB,CAAA;aACP,kBAAC,QAAD;cAAM,WAAW,EAAG,WAAW,EAAO,MAAM;wBAAG,EAAO;cAAa,CAAA;aAC/D;gBACJ,EAAK,SAAS,EAAK,UACnB,kBAAC,OAAD;YAAK,WAAU;sBAAf,CACG,EAAK,SACJ,kBAAC,QAAD;aAAM,WAAU;uBAAhB,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC3B,EAAK,MACD;gBAER,EAAK,SACJ,kBAAC,QAAD;aAAM,WAAU;uBAAhB,CACE,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA,EAC5B,EAAK,MACD;eAEL;cAEJ;aACF;;SACF,CAAA;QACF,EAzCI,EAAO,GAyCX;QAmMuC;MAC/B,CAAA;KAEP,EAAA,CAAA,GAlIH,kBAAC,GAAD;KACE,cAAa;KACb,OAAM;KACN,aAAY;KACZ,CAAA,CAgIA;;GAGL,KACC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,OAAD;MAAK,WAAU;gBAAf;OACE,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,MAAD;SAAI,WAAU;mBAA0C;SAAqB,CAAA,EAC7E,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAmB,GAAM;SACxC,WAAU;mBAEV,kBAAC,GAAD,EAAG,WAAU,WAAY,CAAA;SAClB,CAAA,CACL;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;UAAO,WAAU;oBAAmD;UAE5D,CAAA,EACR,kBAAC,SAAD;UACE,MAAK;UACL,OAAO,EAAW;UAClB,WAAW,MAAM,GAAe,OAAO;WAAE,GAAG;WAAG,MAAM,EAAE,OAAO;WAAO,EAAE;UACvE,WAAU;UACV,CAAA,CACE,EAAA,CAAA;SACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;UAAO,WAAU;oBAAmD;UAAa,CAAA,EACjF,kBAAC,SAAD;UACE,MAAK;UACL,OAAO,EAAW;UAClB,WAAW,MAAM,GAAe,OAAO;WAAE,GAAG;WAAG,OAAO,EAAE,OAAO;WAAO,EAAE;UACxE,WAAU;UACV,CAAA,CACE,EAAA,CAAA;SACN,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;WAAO,WAAU;qBAAmD;WAE5D,CAAA,EACR,kBAAC,SAAD;WACE,MAAK;WACL,OAAO,EAAW;WAClB,WAAW,MAAM,GAAe,OAAO;YAAE,GAAG;YAAG,OAAO,EAAE,OAAO;YAAO,EAAE;WACxE,WAAU;WACV,CAAA,CACE,EAAA,CAAA,EACN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;WAAO,WAAU;qBAAmD;WAE5D,CAAA,EACR,kBAAC,UAAD;WACE,OAAO,EAAW;WAClB,WAAW,MAAM,GAAe,OAAO;YAAE,GAAG;YAAG,MAAM,EAAE,OAAO;YAAO,EAAE;WACvE,WAAU;qBAET,GAAa,KAAK,MACjB,kBAAC,UAAD;YAAgB,OAAO;sBACpB,EAAS,EAAE;YACL,EAFI,EAEJ,CACT;WACK,CAAA,CACL,EAAA,CAAA,CACF;;SACF;;OACN,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,UAAD;SACE,MAAK;SACL,eAAe,EAAmB,GAAM;SACxC,WAAU;mBACX;SAEQ,CAAA,EACT,kBAAC,UAAD;SACE,MAAK;SACL,eA1WW;AACzB,cAAI,CAAC,EAAW,KAAK,MAAM,IAAI,CAAC,EAAW,MAAM;AAC/C,aAAW,kCAAkC,QAAQ;AACrD;;AAEF,cAAI,CAAC,GAAY;AACf,aAAW,iCAAiC,QAAQ;AACpD;;AAEF,YAAa,OACX;WACE;WACA,MAAM,EAAW,KAAK,MAAM;WAC5B,MAAM,EAAW;WACjB,UAAU,EAAW,MAAM,MAAM,IAAI,EAAW,KAAK,MAAM;WAC3D,UAAU;YACR,OAAO,EAAW,MAAM,MAAM,IAAI,KAAA;YAClC,OAAO,EAAW,MAAM,MAAM,IAAI,KAAA;YACnC;WACF,EACD;WACE,iBAAiB;AAGf,YAFA,EAAmB,GAAM,EACzB,EAAc,EAAgB,EAC9B,EAAW,mCAAmC,UAAU;;WAE1D,eAAe,EAAW,iDAAiD,QAAQ;WACpF,CACF;;SA+Ua,UAAU,EAAa;SACvB,WAAW,EACT,qEACA,EAAa,YACT,wDACA,iDACL;mBAEA,EAAa,YAAY,cAAc;SACjC,CAAA,CACL;;OACF;;KACF,CAAA;IACF,CAAA;GAEG"}
|
|
1
|
+
{"version":3,"file":"StaffManagementPage.js","names":[],"sources":["../../../../src/kadaikodi/pages/cart-owner/StaffManagementPage.tsx"],"sourcesContent":["/**\n * Staff Management Page\n *\n * Team overview and roster for the signed-in owner's own service provider (cart).\n * Lists the provider's real workers (useProviderWorkers) with role/status filters\n * and search, invites new workers (useCreateProviderWorker) and edits a worker's\n * stored contact details (useUpdateProviderWorker).\n *\n * Per-worker task load comes from the real `ProviderWorker.tasks` resolver — no\n * fabricated performance metrics or earnings. Role, employment status and worker\n * removal are deliberately absent: `kadaikodiUpdateProviderWorker` accepts only\n * `metadata`, and the service exposes no delete mutation for a worker.\n *\n * @module kadaikodi/pages/cart-owner\n */\n\nimport { useState, useMemo } from 'react';\nimport {\n UserPlus,\n Phone,\n Search,\n X,\n Mail,\n Pencil,\n CheckCircle2,\n AlertCircle,\n Users,\n Clock,\n ClipboardList,\n Briefcase,\n} from 'lucide-react';\nimport { EmphasisPanel, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { StatCard, AvatarStack } from '../../components/viz';\nimport type { Person } from '../../components/viz';\nimport { useKadaikodi } from '../../context/KadaikodiContext';\nimport {\n useProviders,\n useProviderWorkers,\n useCreateProviderWorker,\n useUpdateProviderWorker,\n PROVIDER_WORKER_TASK_LIMIT,\n type KadaikodiProviderWorkerRow,\n} from '../../hooks/useKadaikodiApi';\nimport { cn } from '../../utils/cn';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface InviteForm {\n name: string;\n email: string;\n phone: string;\n role: string;\n}\n\ninterface StatusMessage {\n text: string;\n type: 'success' | 'error';\n}\n\ninterface WorkerMetadata {\n email?: string;\n phone?: string;\n}\n\n/** Contact-detail edit — the only worker fields the service lets us update. */\ninterface EditForm {\n id: string;\n name: string;\n email: string;\n phone: string;\n}\n\n/** Per-worker task counts derived from the worker's real `tasks` connection. */\ninterface WorkerTaskLoad {\n /** Tasks whose assignedAt falls on today's date. */\n assignedToday: number;\n /** True when the server page was full, so the count is a floor, not a total. */\n truncated: boolean;\n /** Tasks not yet completed or cancelled. */\n open: number;\n}\n\n// ============================================================================\n// Constants & helpers\n// ============================================================================\n\nconst ROLE_OPTIONS = ['MANAGER', 'CHEF', 'SERVER', 'DELIVERY', 'CASHIER'] as const;\n\nconst prettify = (s: string): string =>\n s\n .replace(/_/g, ' ')\n .toLowerCase()\n .replace(/\\b\\w/g, (c) => c.toUpperCase());\n\nconst statusColor = (status: string): { label: string; color: string; dot: string } => {\n const s = status.toUpperCase();\n if (s === 'ACTIVE')\n return {\n label: prettify(status),\n color: 'text-status-success-text',\n dot: 'bg-status-success-text',\n };\n if (s === 'ON_LEAVE' || s === 'ON-LEAVE')\n return {\n label: prettify(status),\n color: 'text-status-warning-text',\n dot: 'bg-status-warning-text',\n };\n return { label: prettify(status), color: 'text-text-secondary', dot: 'bg-muted-foreground' };\n};\n\nconst readMetadata = (metadata: Record<string, unknown> | null | undefined): WorkerMetadata => {\n if (!metadata || typeof metadata !== 'object') return {};\n const m = metadata as Record<string, unknown>;\n return {\n email: typeof m.email === 'string' ? m.email : undefined,\n phone: typeof m.phone === 'string' ? m.phone : undefined,\n };\n};\n\nconst emptyInviteForm: InviteForm = {\n name: '',\n email: '',\n phone: '',\n role: 'SERVER',\n};\n\nconst isSameDay = (iso: string | null | undefined, reference: Date): boolean => {\n if (!iso) return false;\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return false;\n return (\n d.getFullYear() === reference.getFullYear() &&\n d.getMonth() === reference.getMonth() &&\n d.getDate() === reference.getDate()\n );\n};\n\n/**\n * Count a worker's task load from the rows the server actually returned.\n *\n * `tasks` comes back newest-first and capped at PROVIDER_WORKER_TASK_LIMIT, so a\n * full page means the count is a lower bound — surfaced as \"N+\" rather than\n * reported as a total.\n */\nconst readTaskLoad = (worker: KadaikodiProviderWorkerRow, today: Date): WorkerTaskLoad => {\n const tasks = worker.tasks ?? [];\n return {\n assignedToday: tasks.filter((t) => isSameDay(t.assignedAt, today)).length,\n truncated: tasks.length >= PROVIDER_WORKER_TASK_LIMIT,\n open: tasks.filter((t) => {\n const s = t.status.toUpperCase();\n return s !== 'COMPLETED' && s !== 'CANCELLED';\n }).length,\n };\n};\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const StaffManagementPage = () => {\n const { currentUser } = useKadaikodi();\n\n // Resolve the signed-in owner's provider (\"my cart\"), then load its workers.\n const { data: providers = [], isLoading: providersLoading } = useProviders();\n const myProvider = useMemo(\n () => providers.find((p) => p.ownerId === currentUser?.id) ?? providers[0],\n [providers, currentUser?.id]\n );\n const providerId = myProvider?.id;\n const { data: workers = [], isLoading: workersLoading } = useProviderWorkers(providerId);\n const createWorker = useCreateProviderWorker();\n const updateWorker = useUpdateProviderWorker();\n\n // Filters\n const [searchQuery, setSearchQuery] = useState('');\n const [roleFilter, setRoleFilter] = useState('');\n const [statusFilter, setStatusFilter] = useState('');\n\n // Invite modal\n const [showInviteModal, setShowInviteModal] = useState(false);\n const [inviteForm, setInviteForm] = useState<InviteForm>(emptyInviteForm);\n\n // Edit-contact modal\n const [editForm, setEditForm] = useState<EditForm | null>(null);\n\n // Status\n const [statusMessage, setStatusMessage] = useState<StatusMessage | null>(null);\n\n const showStatus = (text: string, type: 'success' | 'error') => {\n setStatusMessage({ text, type });\n setTimeout(() => setStatusMessage(null), 3000);\n };\n\n // ---- Derived ----\n const roles = useMemo(() => [...new Set(workers.map((w) => w.role))].sort(), [workers]);\n const statuses = useMemo(() => [...new Set(workers.map((w) => w.status))].sort(), [workers]);\n\n const activeCount = workers.filter((w) => w.status.toUpperCase() === 'ACTIVE').length;\n const onLeaveCount = workers.filter((w) => {\n const s = w.status.toUpperCase();\n return s === 'ON_LEAVE' || s === 'ON-LEAVE';\n }).length;\n\n // Task load per worker, keyed by worker id, from the real `tasks` connection.\n const taskLoads = useMemo(() => {\n const today = new Date();\n return new Map(workers.map((w) => [w.id, readTaskLoad(w, today)]));\n }, [workers]);\n\n const assignedTodayTotal = useMemo(\n () => [...taskLoads.values()].reduce((sum, load) => sum + load.assignedToday, 0),\n [taskLoads]\n );\n const assignedTodayTruncated = useMemo(\n () => [...taskLoads.values()].some((load) => load.truncated),\n [taskLoads]\n );\n\n const filteredStaff = useMemo(() => {\n let result = [...workers];\n if (searchQuery) {\n const q = searchQuery.toLowerCase();\n result = result.filter((w) => {\n const meta = readMetadata(w.metadata);\n return (\n w.name.toLowerCase().includes(q) ||\n w.role.toLowerCase().includes(q) ||\n (meta.email ?? '').toLowerCase().includes(q) ||\n (meta.phone ?? '').includes(q)\n );\n });\n }\n if (roleFilter) result = result.filter((w) => w.role === roleFilter);\n if (statusFilter) result = result.filter((w) => w.status === statusFilter);\n result.sort((a, b) => a.name.localeCompare(b.name));\n return result;\n }, [workers, searchQuery, roleFilter, statusFilter]);\n\n const hasActiveFilters = Boolean(searchQuery || roleFilter || statusFilter);\n\n // ---- Handlers ----\n const handleInvite = () => {\n if (!inviteForm.name.trim() || !inviteForm.role) {\n showStatus('Please provide a name and role', 'error');\n return;\n }\n if (!providerId) {\n showStatus('No cart found to add staff to', 'error');\n return;\n }\n createWorker.mutate(\n {\n providerId,\n name: inviteForm.name.trim(),\n role: inviteForm.role,\n workerId: inviteForm.email.trim() || inviteForm.name.trim(),\n metadata: {\n email: inviteForm.email.trim() || undefined,\n phone: inviteForm.phone.trim() || undefined,\n },\n },\n {\n onSuccess: () => {\n setShowInviteModal(false);\n setInviteForm(emptyInviteForm);\n showStatus('Staff member added successfully', 'success');\n },\n onError: () => showStatus('Could not add staff member. Please try again.', 'error'),\n }\n );\n };\n\n const handleSaveContact = () => {\n if (!editForm) return;\n const email = editForm.email.trim();\n const phone = editForm.phone.trim();\n updateWorker.mutate(\n {\n id: editForm.id,\n // The service merges this onto the worker's existing metadata; an empty\n // string clears the stored value rather than leaving a stale one behind.\n metadata: { email, phone },\n },\n {\n onSuccess: () => {\n setEditForm(null);\n showStatus('Contact details updated', 'success');\n },\n onError: () => showStatus('Could not update contact details. Please try again.', 'error'),\n }\n );\n };\n\n const renderWorkerRow = (member: KadaikodiProviderWorkerRow) => {\n const status = statusColor(member.status);\n const meta = readMetadata(member.metadata);\n const load = taskLoads.get(member.id);\n const initials = member.name\n .split(' ')\n .map((p) => p[0])\n .filter(Boolean)\n .slice(0, 2)\n .join('')\n .toUpperCase();\n\n return (\n <div key={member.id} className=\"p-4 sm:p-5 hover:bg-bg-sunken/30 transition-colors\">\n <div className=\"flex flex-col sm:flex-row sm:items-center gap-4\">\n <div className=\"flex items-center gap-4 flex-1 min-w-0\">\n <div className=\"relative shrink-0\">\n <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-bg-sunken text-sm font-semibold text-text-primary\">\n {initials || '?'}\n </div>\n <span\n className={cn(\n 'absolute -bottom-0.5 -right-0.5 h-3.5 w-3.5 rounded-full border-2 border-card',\n status.dot\n )}\n />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-center gap-2 flex-wrap\">\n <p className=\"text-sm font-medium text-text-primary\">{member.name}</p>\n <span className=\"inline-flex items-center rounded-full px-2 py-0.5 text-[10px] font-medium bg-[var(--color-accent-soft)] text-text-primary\">\n {prettify(member.role)}\n </span>\n <span className={cn('text-xs', status.color)}>{status.label}</span>\n </div>\n {(meta.email || meta.phone) && (\n <div className=\"flex items-center gap-3 mt-1 text-xs text-text-secondary flex-wrap\">\n {meta.email && (\n <span className=\"flex items-center gap-1\">\n <Mail className=\"h-3 w-3\" />\n {meta.email}\n </span>\n )}\n {meta.phone && (\n <span className=\"flex items-center gap-1\">\n <Phone className=\"h-3 w-3\" />\n {meta.phone}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n\n <div className=\"flex items-center gap-4 sm:justify-end\">\n {load && (\n <div className=\"text-xs text-text-secondary\">\n <p className=\"flex items-center gap-1\">\n <ClipboardList className=\"h-3 w-3\" />\n <span className=\"tabular-nums text-text-primary\">\n {load.assignedToday}\n {load.truncated ? '+' : ''}\n </span>\n assigned today\n </p>\n <p className=\"mt-0.5\">\n <span className=\"tabular-nums\">{load.open}</span> open\n </p>\n </div>\n )}\n <button\n type=\"button\"\n onClick={() =>\n setEditForm({\n id: member.id,\n name: member.name,\n email: meta.email ?? '',\n phone: meta.phone ?? '',\n })\n }\n aria-label={`Edit contact details for ${member.name}`}\n className=\"rounded-md border border-border-subtle p-2 text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary\"\n >\n <Pencil className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n </div>\n );\n };\n\n return (\n <PageLayout\n title=\"Staff Management\"\n description=\"Manage your workers and delivery partners\"\n actions={\n <button\n type=\"button\"\n onClick={() => {\n setInviteForm(emptyInviteForm);\n setShowInviteModal(true);\n }}\n disabled={!providerId}\n className={cn(\n 'inline-flex items-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors',\n providerId\n ? 'bg-accent text-text-primary hover:bg-accent/80'\n : 'bg-bg-sunken text-text-secondary cursor-not-allowed'\n )}\n >\n <UserPlus className=\"h-4 w-4\" />\n Add Staff\n </button>\n }\n >\n <PagePurpose className=\"mb-6\">\n Your team in one place. Use this page to add workers and delivery partners to your cart, see\n who's active, and keep your roster organised so orders go out on time. Build a reliable\n crew around your cart.\n </PagePurpose>\n\n <div className=\"space-y-4\">\n {/* Status Message */}\n {statusMessage && (\n <div\n className={cn(\n 'flex items-center gap-2 rounded-lg border p-3',\n statusMessage.type === 'success'\n ? 'border-status-success-text/30 bg-status-success-bg-subtle'\n : 'border-status-error-text/30 bg-status-error-bg-subtle'\n )}\n >\n {statusMessage.type === 'success' ? (\n <CheckCircle2 className=\"h-4 w-4 text-status-success-text\" />\n ) : (\n <AlertCircle className=\"h-4 w-4 text-status-error-text\" />\n )}\n <span\n className={cn(\n 'text-sm font-medium',\n statusMessage.type === 'success'\n ? 'text-status-success-text'\n : 'text-status-error-text'\n )}\n >\n {statusMessage.text}\n </span>\n </div>\n )}\n\n {providersLoading ? (\n <div className=\"flex items-center justify-center py-24\">\n <div className=\"h-10 w-10 animate-spin rounded-full border-b-2 border-foreground\" />\n </div>\n ) : !myProvider ? (\n <EmptyState\n illustration=\"empty-people\"\n title=\"Create your cart first\"\n description=\"You need a service provider before you can add staff. Set up your cart to get started.\"\n />\n ) : (\n <>\n {/* Summary Stats — the one emphasis zone for this page */}\n <EmphasisPanel>\n <div className=\"mb-4 flex items-center justify-between gap-3\">\n <h2 className=\"text-base font-semibold text-text-primary\">Team Overview</h2>\n {workers.length > 0 && (\n <AvatarStack\n people={workers.map((w): Person => ({ name: w.name, role: w.role }))}\n max={6}\n size={30}\n />\n )}\n </div>\n <div className=\"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-3\">\n <StatCard\n label=\"Total Staff\"\n value={workers.length}\n icon={<Users className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Active\"\n value={<span className=\"text-status-success-text\">{activeCount}</span>}\n icon={<CheckCircle2 className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"On Leave\"\n value={<span className=\"text-status-warning-text\">{onLeaveCount}</span>}\n icon={<Clock className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Assigned Today\"\n value={`${assignedTodayTotal}${assignedTodayTruncated ? '+' : ''}`}\n icon={<ClipboardList className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Roles\"\n value={roles.length}\n icon={<Briefcase className=\"h-4 w-4\" />}\n />\n </div>\n </EmphasisPanel>\n\n {/* Filters */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4 shadow-sm\">\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3\">\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"text\"\n placeholder=\"Search staff...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface pl-10 pr-4 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <select\n value={roleFilter}\n onChange={(e) => setRoleFilter(e.target.value)}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"\">All Roles</option>\n {roles.map((r) => (\n <option key={r} value={r}>\n {prettify(r)}\n </option>\n ))}\n </select>\n <select\n value={statusFilter}\n onChange={(e) => setStatusFilter(e.target.value)}\n className=\"rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n <option value=\"\">All Status</option>\n {statuses.map((s) => (\n <option key={s} value={s}>\n {prettify(s)}\n </option>\n ))}\n </select>\n </div>\n </div>\n\n {/* Staff List */}\n {workersLoading ? (\n <div className=\"flex items-center justify-center py-16\">\n <div className=\"h-10 w-10 animate-spin rounded-full border-b-2 border-foreground\" />\n </div>\n ) : filteredStaff.length === 0 ? (\n <EmptyState\n illustration={hasActiveFilters ? 'empty-search' : 'empty-people'}\n title=\"No staff members found\"\n description={\n hasActiveFilters\n ? 'No team members match your current filters. Try clearing them or searching for a different name.'\n : 'You have no staff yet. Add your first worker or delivery partner to start building your team.'\n }\n action={\n hasActiveFilters ? (\n <button\n type=\"button\"\n onClick={() => {\n setSearchQuery('');\n setRoleFilter('');\n setStatusFilter('');\n }}\n className=\"rounded-md border border-border-subtle px-4 py-2 text-sm text-text-primary hover:bg-bg-sunken\"\n >\n Clear filters\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={() => {\n setInviteForm(emptyInviteForm);\n setShowInviteModal(true);\n }}\n className=\"inline-flex items-center gap-2 rounded-md bg-accent px-4 py-2 text-sm font-medium text-text-primary hover:bg-accent/80\"\n >\n <UserPlus className=\"h-4 w-4\" />\n Add Staff\n </button>\n )\n }\n />\n ) : (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface shadow-sm divide-y divide-border\">\n {filteredStaff.map(renderWorkerRow)}\n </div>\n )}\n </>\n )}\n </div>\n\n {/* Edit contact details modal — metadata is the only updatable field set */}\n {editForm && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div className=\"w-full max-w-md rounded-lg border border-border-subtle bg-bg-surface shadow-xl\">\n <div className=\"p-6\">\n <div className=\"flex items-center justify-between mb-1\">\n <h3 className=\"text-lg font-semibold text-text-primary\">Edit contact details</h3>\n <button\n type=\"button\"\n onClick={() => setEditForm(null)}\n className=\"rounded p-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-sunken\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n <p className=\"mb-4 text-sm text-text-secondary\">{editForm.name}</p>\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Email</label>\n <input\n type=\"email\"\n value={editForm.email}\n onChange={(e) => setEditForm((p) => (p ? { ...p, email: e.target.value } : p))}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Phone</label>\n <input\n type=\"tel\"\n value={editForm.phone}\n onChange={(e) => setEditForm((p) => (p ? { ...p, phone: e.target.value } : p))}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n </div>\n <p className=\"mt-3 text-xs text-text-muted\">\n Name, role and employment status are set when a worker is added and cannot be\n changed here.\n </p>\n <div className=\"flex gap-3 mt-6\">\n <button\n type=\"button\"\n onClick={() => setEditForm(null)}\n className=\"flex-1 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleSaveContact}\n disabled={updateWorker.isPending}\n className={cn(\n 'flex-1 rounded-md px-4 py-2 text-sm font-medium transition-colors',\n updateWorker.isPending\n ? 'bg-bg-sunken text-text-secondary cursor-not-allowed'\n : 'bg-accent text-text-primary hover:bg-accent/80'\n )}\n >\n {updateWorker.isPending ? 'Saving...' : 'Save'}\n </button>\n </div>\n </div>\n </div>\n </div>\n )}\n\n {/* Invite Staff Modal */}\n {showInviteModal && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div className=\"w-full max-w-lg rounded-lg border border-border-subtle bg-bg-surface shadow-xl\">\n <div className=\"p-6\">\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-lg font-semibold text-text-primary\">Add Staff Member</h3>\n <button\n type=\"button\"\n onClick={() => setShowInviteModal(false)}\n className=\"rounded p-1.5 text-text-secondary hover:text-text-primary hover:bg-bg-sunken\"\n >\n <X className=\"h-5 w-5\" />\n </button>\n </div>\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n Full Name *\n </label>\n <input\n type=\"text\"\n value={inviteForm.name}\n onChange={(e) => setInviteForm((p) => ({ ...p, name: e.target.value }))}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">Email</label>\n <input\n type=\"email\"\n value={inviteForm.email}\n onChange={(e) => setInviteForm((p) => ({ ...p, email: e.target.value }))}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n <div className=\"grid grid-cols-2 gap-4\">\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n Phone\n </label>\n <input\n type=\"tel\"\n value={inviteForm.phone}\n onChange={(e) => setInviteForm((p) => ({ ...p, phone: e.target.value }))}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n />\n </div>\n <div>\n <label className=\"block text-sm font-medium text-text-primary mb-1\">\n Role *\n </label>\n <select\n value={inviteForm.role}\n onChange={(e) => setInviteForm((p) => ({ ...p, role: e.target.value }))}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary\"\n >\n {ROLE_OPTIONS.map((r) => (\n <option key={r} value={r}>\n {prettify(r)}\n </option>\n ))}\n </select>\n </div>\n </div>\n </div>\n <div className=\"flex gap-3 mt-6\">\n <button\n type=\"button\"\n onClick={() => setShowInviteModal(false)}\n className=\"flex-1 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={handleInvite}\n disabled={createWorker.isPending}\n className={cn(\n 'flex-1 rounded-md px-4 py-2 text-sm font-medium transition-colors',\n createWorker.isPending\n ? 'bg-bg-sunken text-text-secondary cursor-not-allowed'\n : 'bg-accent text-text-primary hover:bg-accent/80'\n )}\n >\n {createWorker.isPending ? 'Adding...' : 'Add Staff'}\n </button>\n </div>\n </div>\n </div>\n </div>\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|