@burdenoff/microfe-assethandler 2026.626.1 → 2026.703.2
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/assethandler/AssetHandlerRoot.js +0 -24
- package/dist/assethandler/AssetHandlerRoot.js.map +1 -1
- package/dist/assethandler/AssetHandlerRoutes.js +92 -160
- package/dist/assethandler/AssetHandlerRoutes.js.map +1 -1
- package/dist/assethandler/pages/AiPredictionsPage.js.map +1 -1
- package/dist/assethandler/pages/AnalyticsPage.js +367 -402
- package/dist/assethandler/pages/AnalyticsPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetCategoriesPage.js +29 -26
- package/dist/assethandler/pages/AssetsAssetCategoriesPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetCheckInOutPage.js +278 -164
- package/dist/assethandler/pages/AssetsAssetCheckInOutPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetCreatePage.js +200 -242
- package/dist/assethandler/pages/AssetsAssetCreatePage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetDetailPage.js +192 -286
- package/dist/assethandler/pages/AssetsAssetDetailPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetListPage.js +204 -296
- package/dist/assethandler/pages/AssetsAssetListPage.js.map +1 -1
- package/dist/assethandler/pages/AssetsAssetTrackingPage.js +38 -42
- package/dist/assethandler/pages/AssetsAssetTrackingPage.js.map +1 -1
- package/dist/assethandler/pages/DashboardPage.js +212 -236
- package/dist/assethandler/pages/DashboardPage.js.map +1 -1
- package/dist/assethandler/pages/DigitalTwinPage.js.map +1 -1
- package/dist/assethandler/pages/DiscoveryJobsPage.js.map +1 -1
- package/dist/assethandler/pages/EsgDashboardPage.js.map +1 -1
- package/dist/assethandler/pages/FinanceBudgetDetailPage.js.map +1 -1
- package/dist/assethandler/pages/FinanceFinanceHubPage.js.map +1 -1
- package/dist/assethandler/pages/ItilChangeManagementPage.js.map +1 -1
- package/dist/assethandler/pages/ItilIncidentDetailPage.js +41 -85
- package/dist/assethandler/pages/ItilIncidentDetailPage.js.map +1 -1
- package/dist/assethandler/pages/ItilIncidentManagementPage.js.map +1 -1
- package/dist/assethandler/pages/ItilItilhubPage.js +1 -2
- package/dist/assethandler/pages/ItilItilhubPage.js.map +1 -1
- package/dist/assethandler/pages/ItilProblemManagementPage.js.map +1 -1
- package/dist/assethandler/pages/KnowledgeBasePage.js.map +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenanceCalendarPage.js +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenanceCalendarPage.js.map +1 -1
- package/dist/assethandler/pages/MaintenanceMaintenanceSchedulerPage.js +37 -86
- package/dist/assethandler/pages/MaintenanceMaintenanceSchedulerPage.js.map +1 -1
- package/dist/assethandler/pages/OperationsMaintenanceDetailPage.js +82 -98
- package/dist/assethandler/pages/OperationsMaintenanceDetailPage.js.map +1 -1
- package/dist/assethandler/pages/OperationsOperationsHubPage.js +6 -22
- package/dist/assethandler/pages/OperationsOperationsHubPage.js.map +1 -1
- package/dist/assethandler/pages/OperationsWorkOrderDetailPage.js +4 -34
- package/dist/assethandler/pages/OperationsWorkOrderDetailPage.js.map +1 -1
- package/dist/assethandler/pages/PortfolioPortfolioOverviewPage.js +105 -150
- package/dist/assethandler/pages/PortfolioPortfolioOverviewPage.js.map +1 -1
- package/dist/assethandler/pages/ProvenancePage.js.map +1 -1
- package/dist/assethandler/pages/SecuritySecurityHubPage.js.map +1 -1
- package/dist/assethandler/pages/TransactionsTransactionDetailPage.js +116 -152
- package/dist/assethandler/pages/TransactionsTransactionDetailPage.js.map +1 -1
- package/dist/assethandler/providers/AssetHandlerProvider.js.map +1 -1
- package/dist/assethandler/store/assethandlerStore.js +68 -2206
- package/dist/assethandler/store/assethandlerStore.js.map +1 -1
- package/dist/assethandler/utils/toast.js +33 -0
- package/dist/assethandler/utils/toast.js.map +1 -0
- package/package.json +5 -4
- package/dist/assethandler/pages/AssetsAssetEditPage.js +0 -353
- package/dist/assethandler/pages/AssetsAssetEditPage.js.map +0 -1
- package/dist/assethandler/pages/AuditTrailPage.js +0 -215
- package/dist/assethandler/pages/AuditTrailPage.js.map +0 -1
- package/dist/assethandler/pages/MarketplaceMarketplaceDetailPage.js +0 -177
- package/dist/assethandler/pages/MarketplaceMarketplaceDetailPage.js.map +0 -1
- package/dist/assethandler/pages/MarketplaceMarketplaceListPage.js +0 -162
- package/dist/assethandler/pages/MarketplaceMarketplaceListPage.js.map +0 -1
- package/dist/assethandler/pages/MarketplaceMarketplaceOrdersPage.js +0 -143
- package/dist/assethandler/pages/MarketplaceMarketplaceOrdersPage.js.map +0 -1
- package/dist/assethandler/pages/MarketplaceMarketplaceSellPage.js +0 -163
- package/dist/assethandler/pages/MarketplaceMarketplaceSellPage.js.map +0 -1
- package/dist/assethandler/pages/ReportsReportBuilderPage.js +0 -208
- package/dist/assethandler/pages/ReportsReportBuilderPage.js.map +0 -1
- package/dist/assethandler/pages/ReportsReportsDashboardPage.js +0 -236
- package/dist/assethandler/pages/ReportsReportsDashboardPage.js.map +0 -1
- package/dist/assethandler/pages/ReportsReportsListPage.js +0 -144
- package/dist/assethandler/pages/ReportsReportsListPage.js.map +0 -1
- package/dist/assethandler/pages/SecurityScheduleBackupPage.js +0 -149
- package/dist/assethandler/pages/SecurityScheduleBackupPage.js.map +0 -1
- package/dist/assethandler/pages/UsersPage.js +0 -208
- package/dist/assethandler/pages/UsersPage.js.map +0 -1
- package/dist/assethandler/pages/UsersUserCreatePage.js +0 -220
- package/dist/assethandler/pages/UsersUserCreatePage.js.map +0 -1
- package/dist/assethandler/pages/UsersUserManagementHubPage.js +0 -373
- package/dist/assethandler/pages/UsersUserManagementHubPage.js.map +0 -1
- package/dist/assethandler/pages/WorkflowsWorkflowBuilderPage.js +0 -264
- package/dist/assethandler/pages/WorkflowsWorkflowBuilderPage.js.map +0 -1
- package/dist/assethandler/pages/WorkflowsWorkflowExecutionsPage.js +0 -206
- package/dist/assethandler/pages/WorkflowsWorkflowExecutionsPage.js.map +0 -1
- package/dist/assethandler/pages/WorkflowsWorkflowListPage.js +0 -171
- package/dist/assethandler/pages/WorkflowsWorkflowListPage.js.map +0 -1
- package/dist/assethandler/pages/WorkflowsWorkflowTemplatesPage.js +0 -173
- package/dist/assethandler/pages/WorkflowsWorkflowTemplatesPage.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssetsAssetListPage.js","names":[],"sources":["../../../src/assethandler/pages/AssetsAssetListPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Checkbox,\n Separator,\n GradientText,\n CTAOverflowMenu,\n IllustratedEmptyState,\n EmphasisPanel,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Search,\n Filter,\n Plus,\n Download,\n Grid3x3,\n List,\n Table as TableIcon,\n Trash2,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { tWithFallback } from '../utils/i18n';\n\nconst statusColors: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n active: 'default',\n inactive: 'outline',\n under_maintenance: 'secondary',\n disposed: 'destructive',\n reserved: 'secondary',\n in_transit: 'outline',\n};\n\nconst conditionColors: Record<string, string> = {\n excellent: 'text-status-success-text bg-status-success-bg-subtle',\n good: 'text-status-info-text bg-status-info-bg-subtle',\n fair: 'text-status-warning-text bg-status-warning-bg-subtle',\n poor: 'text-status-warning-text bg-status-warning-bg-subtle',\n non_functional: 'text-status-error-text bg-status-error-bg-subtle',\n};\n\nexport function AssetsAssetListPage() {\n const { t } = useI18n();\n const { assets } = useAssetHandlerStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [categoryFilter, setCategoryFilter] = useState('all');\n const [statusFilter, setStatusFilter] = useState('all');\n const [viewMode, setViewMode] = useState<'table' | 'grid' | 'list'>('table');\n const [selectedAssets, setSelectedAssets] = useState<string[]>([]);\n\n const filteredAssets = useMemo(() => {\n return assets.filter((a) => {\n const matchesSearch =\n searchQuery === '' ||\n a.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n a.assetTag.toLowerCase().includes(searchQuery.toLowerCase()) ||\n a.serialNumber.toLowerCase().includes(searchQuery.toLowerCase());\n const matchesCategory = categoryFilter === 'all' || a.category === categoryFilter;\n const matchesStatus = statusFilter === 'all' || a.status === statusFilter;\n return matchesSearch && matchesCategory && matchesStatus;\n });\n }, [assets, searchQuery, categoryFilter, statusFilter]);\n\n const toggleSelect = (id: string) => {\n setSelectedAssets((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]));\n };\n\n const toggleAll = () => {\n if (selectedAssets.length === filteredAssets.length) {\n setSelectedAssets([]);\n } else {\n setSelectedAssets(filteredAssets.map((a) => a.id));\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>\n {tWithFallback(t, 'assethandler.assets.list.title', 'Asset Inventory')}\n </GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {assets.length} total assets · $\n {assets.reduce((s, a) => s + a.currentValue, 0).toLocaleString()} portfolio value\n </p>\n </div>\n <CTAOverflowMenu\n primary={{\n label: tWithFallback(t, 'assethandler.assets.list.actions.addAsset', 'Add Asset'),\n onSelect: () => {},\n icon: <Plus className=\"h-4 w-4\" />,\n }}\n actions={[\n {\n label: tWithFallback(t, 'assethandler.assets.list.actions.export', 'Export'),\n onSelect: () => {},\n icon: <Download className=\"h-4 w-4\" />,\n },\n ]}\n />\n </div>\n\n <PagePurpose>\n {tWithFallback(\n t,\n 'assethandler.assets.list.purpose',\n 'The single source of truth for every asset you own or manage. Search, filter and group by category, status or condition to find any item fast, review its value and assignment, then drill in to update, check it in/out or schedule maintenance.'\n )}\n </PagePurpose>\n\n {/* Portfolio summary emphasis */}\n <EmphasisPanel className=\"flex flex-wrap items-center justify-between gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.summary.label', 'Total portfolio value')}\n </p>\n <p className=\"text-3xl font-bold tabular-nums\">\n ${assets.reduce((s, a) => s + a.currentValue, 0).toLocaleString()}\n </p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-sm text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.summary.tracked', 'Assets tracked')}\n </p>\n <p className=\"text-3xl font-bold tabular-nums\">{assets.length}</p>\n </div>\n </EmphasisPanel>\n\n {/* Filters Bar */}\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex flex-col md:flex-row gap-3\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder={tWithFallback(\n t,\n 'assethandler.assets.list.search.placeholder',\n 'Search by name, asset tag, serial number...'\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <Select value={categoryFilter} onValueChange={setCategoryFilter}>\n <SelectTrigger className=\"w-[180px]\">\n <SelectValue\n placeholder={tWithFallback(\n t,\n 'assethandler.assets.list.filters.category.placeholder',\n 'Category'\n )}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tWithFallback(\n t,\n 'assethandler.assets.list.filters.category.all',\n 'All Categories'\n )}\n </SelectItem>\n <SelectItem value=\"electronics\">Electronics</SelectItem>\n <SelectItem value=\"it_hardware\">IT Hardware</SelectItem>\n <SelectItem value=\"furniture\">Furniture</SelectItem>\n <SelectItem value=\"vehicles\">Vehicles</SelectItem>\n <SelectItem value=\"equipment\">Equipment</SelectItem>\n <SelectItem value=\"software\">Software</SelectItem>\n <SelectItem value=\"networking\">Networking</SelectItem>\n <SelectItem value=\"servers\">Servers</SelectItem>\n </SelectContent>\n </Select>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger className=\"w-[160px]\">\n <SelectValue\n placeholder={tWithFallback(\n t,\n 'assethandler.assets.list.filters.status.placeholder',\n 'Status'\n )}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tWithFallback(t, 'assethandler.assets.list.filters.status.all', 'All Statuses')}\n </SelectItem>\n <SelectItem value=\"active\">\n {tWithFallback(t, 'assethandler.assets.list.filters.status.active', 'Active')}\n </SelectItem>\n <SelectItem value=\"inactive\">\n {tWithFallback(t, 'assethandler.assets.list.filters.status.inactive', 'Inactive')}\n </SelectItem>\n <SelectItem value=\"under_maintenance\">\n {tWithFallback(\n t,\n 'assethandler.assets.list.filters.status.underMaintenance',\n 'Under Maintenance'\n )}\n </SelectItem>\n <SelectItem value=\"disposed\">\n {tWithFallback(t, 'assethandler.assets.list.filters.status.disposed', 'Disposed')}\n </SelectItem>\n <SelectItem value=\"reserved\">\n {tWithFallback(t, 'assethandler.assets.list.filters.status.reserved', 'Reserved')}\n </SelectItem>\n <SelectItem value=\"in_transit\">\n {tWithFallback(\n t,\n 'assethandler.assets.list.filters.status.inTransit',\n 'In Transit'\n )}\n </SelectItem>\n </SelectContent>\n </Select>\n <div className=\"flex gap-1 border rounded-md p-0.5\">\n <Button\n variant={viewMode === 'table' ? 'default' : 'ghost'}\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={() => setViewMode('table')}\n >\n <TableIcon className=\"h-4 w-4\" />\n </Button>\n <Button\n variant={viewMode === 'grid' ? 'default' : 'ghost'}\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={() => setViewMode('grid')}\n >\n <Grid3x3 className=\"h-4 w-4\" />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'default' : 'ghost'}\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={() => setViewMode('list')}\n >\n <List className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n\n {selectedAssets.length > 0 && (\n <div className=\"flex items-center gap-3 mt-3 pt-3 border-t\">\n <span className=\"text-sm text-text-secondary\">\n {selectedAssets.length}{' '}\n {tWithFallback(t, 'assethandler.assets.list.bulk.selected', 'selected')}\n </span>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setSelectedAssets([])}>\n {tWithFallback(t, 'assethandler.assets.list.bulk.clear', 'Clear')}\n </Button>\n <Button variant=\"destructive\" size=\"sm\">\n <Trash2 className=\"mr-2 h-3 w-3\" />\n {tWithFallback(\n t,\n 'assethandler.assets.list.bulk.deleteSelected',\n 'Delete Selected'\n )}\n </Button>\n </div>\n )}\n </CardContent>\n </Card>\n\n {/* Results */}\n <div className=\"text-sm text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.results.showing', 'Showing')}{' '}\n {filteredAssets.length} {tWithFallback(t, 'assethandler.assets.list.results.of', 'of')}{' '}\n {assets.length} {tWithFallback(t, 'assethandler.assets.list.results.assets', 'assets')}\n </div>\n\n {viewMode === 'table' && (\n <Card>\n <CardContent className=\"p-0\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-bg-sunken/50\">\n <th className=\"p-3 w-10\">\n <Checkbox\n checked={\n selectedAssets.length === filteredAssets.length &&\n filteredAssets.length > 0\n }\n onCheckedChange={toggleAll}\n />\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.assetTag', 'Asset Tag')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.name', 'Name')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.category', 'Category')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.status', 'Status')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.condition', 'Condition')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.location', 'Location')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.assignedTo', 'Assigned To')}\n </th>\n <th className=\"text-right p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.value', 'Value')}\n </th>\n </tr>\n </thead>\n <tbody>\n {filteredAssets.map((asset) => (\n <tr key={asset.id} className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\">\n <td className=\"p-3\">\n <Checkbox\n checked={selectedAssets.includes(asset.id)}\n onCheckedChange={() => toggleSelect(asset.id)}\n />\n </td>\n <td className=\"p-3 font-mono text-xs\">{asset.assetTag}</td>\n <td className=\"p-3\">\n <div>\n <p className=\"font-medium\">{asset.name}</p>\n <p className=\"text-xs text-text-secondary\">{asset.serialNumber}</p>\n </div>\n </td>\n <td className=\"p-3 capitalize\">{asset.category.replace('_', ' ')}</td>\n <td className=\"p-3\">\n <Badge variant={statusColors[asset.status] || 'outline'}>\n {asset.status.replace('_', ' ')}\n </Badge>\n </td>\n <td className=\"p-3\">\n <span\n className={`inline-flex rounded-md px-2 py-0.5 text-xs font-medium ${conditionColors[asset.condition] || ''}`}\n >\n {asset.condition}\n </span>\n </td>\n <td className=\"p-3 text-xs max-w-[200px] truncate\">{asset.location}</td>\n <td className=\"p-3 text-xs\">{asset.assignedTo}</td>\n <td className=\"p-3 text-right font-medium\">\n ${asset.currentValue.toLocaleString()}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n\n {viewMode === 'grid' && (\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {filteredAssets.map((asset) => (\n <Card key={asset.id} className=\"cursor-pointer hover:shadow-md transition-shadow\">\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <Badge variant={statusColors[asset.status] || 'outline'}>\n {asset.status.replace('_', ' ')}\n </Badge>\n <span className=\"text-xs font-mono text-text-secondary\">{asset.assetTag}</span>\n </div>\n <CardTitle className=\"text-base mt-2\">{asset.name}</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.grid.category', 'Category')}\n </span>\n <span className=\"capitalize\">{asset.category.replace('_', ' ')}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.grid.condition', 'Condition')}\n </span>\n <span\n className={`rounded-md px-2 py-0.5 text-xs font-medium ${conditionColors[asset.condition] || ''}`}\n >\n {asset.condition}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.grid.department', 'Department')}\n </span>\n <span className=\"text-xs\">{asset.department}</span>\n </div>\n <Separator />\n <div className=\"flex justify-between items-center\">\n <span className=\"text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.grid.value', 'Value')}\n </span>\n <span className=\"font-bold text-lg\">\n ${asset.currentValue.toLocaleString()}\n </span>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {viewMode === 'list' && (\n <div className=\"space-y-2\">\n {filteredAssets.map((asset) => (\n <Card key={asset.id} className=\"cursor-pointer hover:shadow-sm transition-shadow\">\n <CardContent className=\"py-3 px-4\">\n <div className=\"flex items-center gap-4\">\n <Checkbox\n checked={selectedAssets.includes(asset.id)}\n onCheckedChange={() => toggleSelect(asset.id)}\n />\n <div className=\"flex-1 min-w-0 grid grid-cols-6 gap-4 items-center\">\n <div className=\"col-span-2\">\n <p className=\"font-medium text-sm truncate\">{asset.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {asset.assetTag} · {asset.serialNumber}\n </p>\n </div>\n <div className=\"capitalize text-sm\">{asset.category.replace('_', ' ')}</div>\n <div>\n <Badge variant={statusColors[asset.status] || 'outline'} className=\"text-xs\">\n {asset.status.replace('_', ' ')}\n </Badge>\n </div>\n <div className=\"text-sm text-text-secondary truncate\">{asset.location}</div>\n <div className=\"text-right font-medium\">\n ${asset.currentValue.toLocaleString()}\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {filteredAssets.length === 0 && (\n <IllustratedEmptyState\n illustration={\n searchQuery || categoryFilter !== 'all' || statusFilter !== 'all'\n ? 'empty-search'\n : 'empty-data'\n }\n title={tWithFallback(t, 'assethandler.assets.list.empty.title', 'No assets found')}\n description={tWithFallback(\n t,\n 'assethandler.assets.list.empty.description',\n 'Try adjusting your filters or add a new asset to get started.'\n )}\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AssetsAssetListPage.js","names":[],"sources":["../../../src/assethandler/pages/AssetsAssetListPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n GradientText,\n IllustratedEmptyState,\n EmphasisPanel,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { Search, Plus, Grid3x3, List, Table as TableIcon } from 'lucide-react';\nimport { useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { tWithFallback } from '../utils/i18n';\n\nconst statusColors: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n active: 'default',\n inactive: 'outline',\n maintenance: 'secondary',\n retired: 'outline',\n disposed: 'destructive',\n};\n\nconst conditionColors: Record<string, string> = {\n excellent: 'text-status-success-text bg-status-success-bg-subtle',\n good: 'text-status-info-text bg-status-info-bg-subtle',\n fair: 'text-status-warning-text bg-status-warning-bg-subtle',\n poor: 'text-status-warning-text bg-status-warning-bg-subtle',\n damaged: 'text-status-error-text bg-status-error-bg-subtle',\n};\n\nexport function AssetsAssetListPage() {\n const { t } = useI18n();\n const navigate = useNavigate();\n const { assets, hydrated } = useAssetHandlerStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [categoryFilter, setCategoryFilter] = useState('all');\n const [statusFilter, setStatusFilter] = useState('all');\n const [viewMode, setViewMode] = useState<'table' | 'grid' | 'list'>('table');\n\n const categories = useMemo(\n () => [...new Set(assets.map((a) => a.category).filter(Boolean))].sort(),\n [assets]\n );\n\n const filteredAssets = useMemo(() => {\n return assets.filter((a) => {\n const matchesSearch =\n searchQuery === '' ||\n a.name.toLowerCase().includes(searchQuery.toLowerCase()) ||\n a.assetTag.toLowerCase().includes(searchQuery.toLowerCase()) ||\n a.serialNumber.toLowerCase().includes(searchQuery.toLowerCase());\n const matchesCategory = categoryFilter === 'all' || a.category === categoryFilter;\n const matchesStatus = statusFilter === 'all' || a.status === statusFilter;\n return matchesSearch && matchesCategory && matchesStatus;\n });\n }, [assets, searchQuery, categoryFilter, statusFilter]);\n\n const activeCount = assets.filter((a) => a.status === 'active').length;\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Header */}\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>\n {tWithFallback(t, 'assethandler.assets.list.title', 'Asset Inventory')}\n </GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {assets.length}{' '}\n {tWithFallback(t, 'assethandler.assets.list.subtitle.totalAssets', 'total assets')}{' '}\n · {activeCount}{' '}\n {tWithFallback(t, 'assethandler.assets.list.subtitle.active', 'active')}\n </p>\n </div>\n <Button size=\"sm\" onClick={() => navigate('/assets/asset-create')}>\n <Plus className=\"mr-2 h-4 w-4\" />\n {tWithFallback(t, 'assethandler.assets.list.actions.addAsset', 'Add Asset')}\n </Button>\n </div>\n\n <PagePurpose>\n {tWithFallback(\n t,\n 'assethandler.assets.list.purpose',\n 'The single source of truth for every asset you own or manage. Search, filter and group by category, status or condition to find any item fast, review its assignment, then drill in to update, check it in/out or schedule maintenance.'\n )}\n </PagePurpose>\n\n {/* Inventory summary emphasis */}\n <EmphasisPanel className=\"flex flex-wrap items-center justify-between gap-4\">\n <div>\n <p className=\"text-sm text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.summary.tracked', 'Assets tracked')}\n </p>\n <p className=\"text-3xl font-bold tabular-nums\">{assets.length}</p>\n </div>\n <div className=\"text-right\">\n <p className=\"text-sm text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.summary.categories', 'Categories')}\n </p>\n <p className=\"text-3xl font-bold tabular-nums\">{categories.length}</p>\n </div>\n </EmphasisPanel>\n\n {/* Filters Bar */}\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex flex-col md:flex-row gap-3\">\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input\n placeholder={tWithFallback(\n t,\n 'assethandler.assets.list.search.placeholder',\n 'Search by name, asset tag, serial number...'\n )}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-9\"\n />\n </div>\n <Select value={categoryFilter} onValueChange={setCategoryFilter}>\n <SelectTrigger className=\"w-[180px]\">\n <SelectValue\n placeholder={tWithFallback(\n t,\n 'assethandler.assets.list.filters.category.placeholder',\n 'Category'\n )}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tWithFallback(\n t,\n 'assethandler.assets.list.filters.category.all',\n 'All Categories'\n )}\n </SelectItem>\n {categories.map((category) => (\n <SelectItem key={category} value={category} className=\"capitalize\">\n {category.replace(/_/g, ' ')}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n <Select value={statusFilter} onValueChange={setStatusFilter}>\n <SelectTrigger className=\"w-[160px]\">\n <SelectValue\n placeholder={tWithFallback(\n t,\n 'assethandler.assets.list.filters.status.placeholder',\n 'Status'\n )}\n />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">\n {tWithFallback(t, 'assethandler.assets.list.filters.status.all', 'All Statuses')}\n </SelectItem>\n <SelectItem value=\"active\">\n {tWithFallback(t, 'assethandler.assets.list.filters.status.active', 'Active')}\n </SelectItem>\n <SelectItem value=\"inactive\">\n {tWithFallback(t, 'assethandler.assets.list.filters.status.inactive', 'Inactive')}\n </SelectItem>\n <SelectItem value=\"maintenance\">\n {tWithFallback(\n t,\n 'assethandler.assets.list.filters.status.maintenance',\n 'Maintenance'\n )}\n </SelectItem>\n <SelectItem value=\"retired\">\n {tWithFallback(t, 'assethandler.assets.list.filters.status.retired', 'Retired')}\n </SelectItem>\n <SelectItem value=\"disposed\">\n {tWithFallback(t, 'assethandler.assets.list.filters.status.disposed', 'Disposed')}\n </SelectItem>\n </SelectContent>\n </Select>\n <div className=\"flex gap-1 border rounded-md p-0.5\">\n <Button\n variant={viewMode === 'table' ? 'default' : 'ghost'}\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={() => setViewMode('table')}\n >\n <TableIcon className=\"h-4 w-4\" />\n </Button>\n <Button\n variant={viewMode === 'grid' ? 'default' : 'ghost'}\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={() => setViewMode('grid')}\n >\n <Grid3x3 className=\"h-4 w-4\" />\n </Button>\n <Button\n variant={viewMode === 'list' ? 'default' : 'ghost'}\n size=\"icon\"\n className=\"h-8 w-8\"\n onClick={() => setViewMode('list')}\n >\n <List className=\"h-4 w-4\" />\n </Button>\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Results */}\n <div className=\"text-sm text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.results.showing', 'Showing')}{' '}\n {filteredAssets.length} {tWithFallback(t, 'assethandler.assets.list.results.of', 'of')}{' '}\n {assets.length} {tWithFallback(t, 'assethandler.assets.list.results.assets', 'assets')}\n </div>\n\n {!hydrated && assets.length === 0 ? (\n <div className=\"space-y-2\">\n {Array.from({ length: 6 }).map((_, i) => (\n <div key={i} className=\"h-10 rounded-md bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n\n {viewMode === 'table' && filteredAssets.length > 0 && (\n <Card>\n <CardContent className=\"p-0\">\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-sm\">\n <thead>\n <tr className=\"border-b bg-bg-sunken/50\">\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.assetTag', 'Asset Tag')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.name', 'Name')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.category', 'Category')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.status', 'Status')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.condition', 'Condition')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.location', 'Location')}\n </th>\n <th className=\"text-left p-3 font-medium\">\n {tWithFallback(t, 'assethandler.assets.list.table.assignedTo', 'Assigned To')}\n </th>\n </tr>\n </thead>\n <tbody>\n {filteredAssets.map((asset) => (\n <tr\n key={asset.id}\n className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\"\n onClick={() => navigate(`/assets/${asset.id}`)}\n >\n <td className=\"p-3 font-mono text-xs\">{asset.assetTag}</td>\n <td className=\"p-3\">\n <div>\n <p className=\"font-medium\">{asset.name}</p>\n <p className=\"text-xs text-text-secondary\">{asset.serialNumber}</p>\n </div>\n </td>\n <td className=\"p-3 capitalize\">{asset.category.replace(/_/g, ' ')}</td>\n <td className=\"p-3\">\n <Badge variant={statusColors[asset.status] || 'outline'}>\n {asset.status.replace(/_/g, ' ')}\n </Badge>\n </td>\n <td className=\"p-3\">\n <span\n className={`inline-flex rounded-md px-2 py-0.5 text-xs font-medium ${conditionColors[asset.condition] || ''}`}\n >\n {asset.condition}\n </span>\n </td>\n <td className=\"p-3 text-xs max-w-[200px] truncate\">\n {asset.location || '—'}\n </td>\n <td className=\"p-3 text-xs\">{asset.assignedTo || '—'}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n\n {viewMode === 'grid' && filteredAssets.length > 0 && (\n <div className=\"grid gap-4 md:grid-cols-2 lg:grid-cols-3\">\n {filteredAssets.map((asset) => (\n <Card\n key={asset.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`/assets/${asset.id}`)}\n >\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <Badge variant={statusColors[asset.status] || 'outline'}>\n {asset.status.replace(/_/g, ' ')}\n </Badge>\n <span className=\"text-xs font-mono text-text-secondary\">{asset.assetTag}</span>\n </div>\n <CardTitle className=\"text-base mt-2\">{asset.name}</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.grid.category', 'Category')}\n </span>\n <span className=\"capitalize\">{asset.category.replace(/_/g, ' ')}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.grid.condition', 'Condition')}\n </span>\n <span\n className={`rounded-md px-2 py-0.5 text-xs font-medium ${conditionColors[asset.condition] || ''}`}\n >\n {asset.condition}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">\n {tWithFallback(t, 'assethandler.assets.list.grid.assignedTo', 'Assigned To')}\n </span>\n <span className=\"text-xs\">{asset.assignedTo || '—'}</span>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {viewMode === 'list' && filteredAssets.length > 0 && (\n <div className=\"space-y-2\">\n {filteredAssets.map((asset) => (\n <Card\n key={asset.id}\n className=\"cursor-pointer\"\n onClick={() => navigate(`/assets/${asset.id}`)}\n >\n <CardContent className=\"py-3 px-4\">\n <div className=\"flex items-center gap-4\">\n <div className=\"flex-1 min-w-0 grid grid-cols-5 gap-4 items-center\">\n <div className=\"col-span-2\">\n <p className=\"font-medium text-sm truncate\">{asset.name}</p>\n <p className=\"text-xs text-text-secondary\">\n {asset.assetTag} · {asset.serialNumber}\n </p>\n </div>\n <div className=\"capitalize text-sm\">{asset.category.replace(/_/g, ' ')}</div>\n <div>\n <Badge variant={statusColors[asset.status] || 'outline'} className=\"text-xs\">\n {asset.status.replace(/_/g, ' ')}\n </Badge>\n </div>\n <div className=\"text-sm text-text-secondary truncate\">\n {asset.location || '—'}\n </div>\n </div>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n\n {hydrated && filteredAssets.length === 0 && (\n <IllustratedEmptyState\n illustration={\n searchQuery || categoryFilter !== 'all' || statusFilter !== 'all'\n ? 'empty-search'\n : 'empty-data'\n }\n title={tWithFallback(t, 'assethandler.assets.list.empty.title', 'No assets found')}\n description={tWithFallback(\n t,\n 'assethandler.assets.list.empty.description',\n 'Try adjusting your filters or add a new asset to get started.'\n )}\n action={\n <Button size=\"sm\" onClick={() => navigate('/assets/asset-create')}>\n <Plus className=\"mr-2 h-4 w-4\" />\n {tWithFallback(t, 'assethandler.assets.list.actions.addAsset', 'Add Asset')}\n </Button>\n }\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { useAssetHandlerStore as e } from "../store/assethandlerStore.js";
|
|
2
|
-
import {
|
|
2
|
+
import { useMemo as t } from "react";
|
|
3
|
+
import { Building as n, HelpCircle as r, MapPin as i, Radio as a, RefreshCw as o, Search as s } from "lucide-react";
|
|
3
4
|
import { Badge as c, Button as l, Card as u, CardContent as d, CardDescription as f, CardHeader as p, CardTitle as m, EmphasisPanel as h, GradientText as g, IllustratedEmptyState as _, Input as v, PagePurpose as y } from "@burdenoff/fe-libs/ui";
|
|
4
5
|
import { jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
5
6
|
//#region src/assethandler/pages/AssetsAssetTrackingPage.tsx
|
|
6
7
|
var S = {
|
|
7
8
|
active: "default",
|
|
8
9
|
inactive: "outline",
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
maintenance: "secondary",
|
|
11
|
+
retired: "outline",
|
|
12
|
+
disposed: "destructive"
|
|
13
|
+
}, C = "Unlocated";
|
|
14
|
+
function w() {
|
|
15
|
+
let { assets: w } = e(), T = t(() => w.reduce((e, t) => {
|
|
16
|
+
let n = t.location.trim() || C;
|
|
17
|
+
return e[n] || (e[n] = []), e[n].push(t), e;
|
|
18
|
+
}, {}), [w]), E = w.filter((e) => e.location.trim()).length, D = w.length - E, O = Object.keys(T).filter((e) => e !== C).length;
|
|
13
19
|
return /* @__PURE__ */ x("div", {
|
|
14
20
|
className: "space-y-6 p-6",
|
|
15
21
|
children: [
|
|
@@ -21,8 +27,8 @@ function C() {
|
|
|
21
27
|
}), /* @__PURE__ */ x("p", {
|
|
22
28
|
className: "text-sm text-text-secondary",
|
|
23
29
|
children: [
|
|
24
|
-
"
|
|
25
|
-
|
|
30
|
+
"Location overview for ",
|
|
31
|
+
w.length,
|
|
26
32
|
" assets"
|
|
27
33
|
]
|
|
28
34
|
})] }), /* @__PURE__ */ x("div", {
|
|
@@ -38,51 +44,41 @@ function C() {
|
|
|
38
44
|
})]
|
|
39
45
|
}),
|
|
40
46
|
/* @__PURE__ */ x("div", {
|
|
41
|
-
className: "grid gap-4 md:grid-cols-
|
|
47
|
+
className: "grid gap-4 md:grid-cols-3",
|
|
42
48
|
children: [
|
|
43
49
|
/* @__PURE__ */ b(u, { children: /* @__PURE__ */ x(d, {
|
|
44
50
|
className: "pt-4",
|
|
45
51
|
children: [/* @__PURE__ */ x("div", {
|
|
46
52
|
className: "flex items-center gap-2 text-sm text-text-secondary",
|
|
47
|
-
children: [/* @__PURE__ */ b(a, { className: "h-4 w-4" }), "
|
|
53
|
+
children: [/* @__PURE__ */ b(a, { className: "h-4 w-4" }), "Located Assets"]
|
|
48
54
|
}), /* @__PURE__ */ b("p", {
|
|
49
55
|
className: "text-2xl font-bold mt-1",
|
|
50
|
-
children:
|
|
56
|
+
children: E
|
|
51
57
|
})]
|
|
52
58
|
}) }),
|
|
53
59
|
/* @__PURE__ */ b(u, { children: /* @__PURE__ */ x(d, {
|
|
54
60
|
className: "pt-4",
|
|
55
61
|
children: [/* @__PURE__ */ x("div", {
|
|
56
62
|
className: "flex items-center gap-2 text-sm text-text-secondary",
|
|
57
|
-
children: [/* @__PURE__ */ b(
|
|
63
|
+
children: [/* @__PURE__ */ b(n, { className: "h-4 w-4" }), "Locations"]
|
|
58
64
|
}), /* @__PURE__ */ b("p", {
|
|
59
65
|
className: "text-2xl font-bold mt-1",
|
|
60
|
-
children:
|
|
66
|
+
children: O
|
|
61
67
|
})]
|
|
62
68
|
}) }),
|
|
63
69
|
/* @__PURE__ */ b(u, { children: /* @__PURE__ */ x(d, {
|
|
64
70
|
className: "pt-4",
|
|
65
71
|
children: [/* @__PURE__ */ x("div", {
|
|
66
72
|
className: "flex items-center gap-2 text-sm text-text-secondary",
|
|
67
|
-
children: [/* @__PURE__ */ b(
|
|
73
|
+
children: [/* @__PURE__ */ b(r, { className: "h-4 w-4" }), "Unlocated"]
|
|
68
74
|
}), /* @__PURE__ */ b("p", {
|
|
69
75
|
className: "text-2xl font-bold mt-1",
|
|
70
|
-
children:
|
|
71
|
-
})]
|
|
72
|
-
}) }),
|
|
73
|
-
/* @__PURE__ */ b(u, { children: /* @__PURE__ */ x(d, {
|
|
74
|
-
className: "pt-4",
|
|
75
|
-
children: [/* @__PURE__ */ x("div", {
|
|
76
|
-
className: "flex items-center gap-2 text-sm text-text-secondary",
|
|
77
|
-
children: [/* @__PURE__ */ b(n, { className: "h-4 w-4" }), "Last Update"]
|
|
78
|
-
}), /* @__PURE__ */ b("p", {
|
|
79
|
-
className: "text-lg font-bold mt-1",
|
|
80
|
-
children: "Just now"
|
|
76
|
+
children: D
|
|
81
77
|
})]
|
|
82
78
|
}) })
|
|
83
79
|
]
|
|
84
80
|
}),
|
|
85
|
-
/* @__PURE__ */ b(y, { children: "Know where your assets physically are
|
|
81
|
+
/* @__PURE__ */ b(y, { children: "Know where your assets physically are. See them grouped by location, so you can locate equipment fast, spot assets that still have no recorded location, and confirm items are where they should be." }),
|
|
86
82
|
/* @__PURE__ */ x("div", {
|
|
87
83
|
className: "grid gap-6 lg:grid-cols-5",
|
|
88
84
|
children: [/* @__PURE__ */ x(h, {
|
|
@@ -97,7 +93,7 @@ function C() {
|
|
|
97
93
|
children: /* @__PURE__ */ x("div", {
|
|
98
94
|
className: "text-center",
|
|
99
95
|
children: [
|
|
100
|
-
/* @__PURE__ */ b(
|
|
96
|
+
/* @__PURE__ */ b(i, { className: "h-12 w-12 text-text-secondary mx-auto mb-2" }),
|
|
101
97
|
/* @__PURE__ */ b("p", {
|
|
102
98
|
className: "text-text-secondary",
|
|
103
99
|
children: "Interactive map view"
|
|
@@ -118,37 +114,37 @@ function C() {
|
|
|
118
114
|
placeholder: "Search assets...",
|
|
119
115
|
className: "pl-9"
|
|
120
116
|
})]
|
|
121
|
-
})] }), /* @__PURE__ */ b(d, { children:
|
|
117
|
+
})] }), /* @__PURE__ */ b(d, { children: w.length === 0 ? /* @__PURE__ */ b(_, {
|
|
122
118
|
illustration: "empty-generic",
|
|
123
|
-
title: "No
|
|
124
|
-
description: "
|
|
119
|
+
title: "No assets to track",
|
|
120
|
+
description: "Add an asset and give it a location to see it grouped here."
|
|
125
121
|
}) : /* @__PURE__ */ b("div", {
|
|
126
122
|
className: "space-y-4",
|
|
127
|
-
children: Object.entries(
|
|
123
|
+
children: Object.entries(T).map(([e, t]) => /* @__PURE__ */ x("div", { children: [/* @__PURE__ */ x("h4", {
|
|
128
124
|
className: "text-sm font-medium flex items-center gap-2 mb-2",
|
|
129
125
|
children: [
|
|
130
|
-
/* @__PURE__ */ b(
|
|
126
|
+
/* @__PURE__ */ b(n, { className: "h-3.5 w-3.5" }),
|
|
131
127
|
e,
|
|
132
128
|
/* @__PURE__ */ b(c, {
|
|
133
129
|
variant: "secondary",
|
|
134
130
|
className: "text-[10px]",
|
|
135
|
-
children:
|
|
131
|
+
children: t.length
|
|
136
132
|
})
|
|
137
133
|
]
|
|
138
134
|
}), /* @__PURE__ */ b("div", {
|
|
139
135
|
className: "space-y-2 ml-5",
|
|
140
|
-
children:
|
|
136
|
+
children: t.map((e) => /* @__PURE__ */ x("div", {
|
|
141
137
|
className: "flex items-start gap-3 rounded border p-2.5",
|
|
142
|
-
children: [/* @__PURE__ */ b(
|
|
138
|
+
children: [/* @__PURE__ */ b(i, { className: "h-3.5 w-3.5 mt-0.5 text-text-secondary shrink-0" }), /* @__PURE__ */ x("div", {
|
|
143
139
|
className: "flex-1 min-w-0",
|
|
144
140
|
children: [
|
|
145
141
|
/* @__PURE__ */ b("p", {
|
|
146
142
|
className: "text-sm font-medium truncate",
|
|
147
|
-
children: e.
|
|
143
|
+
children: e.name
|
|
148
144
|
}),
|
|
149
|
-
/* @__PURE__ */
|
|
145
|
+
/* @__PURE__ */ b("p", {
|
|
150
146
|
className: "text-xs text-text-secondary",
|
|
151
|
-
children:
|
|
147
|
+
children: e.assetTag
|
|
152
148
|
}),
|
|
153
149
|
/* @__PURE__ */ x("div", {
|
|
154
150
|
className: "flex items-center gap-2 mt-1",
|
|
@@ -156,14 +152,14 @@ function C() {
|
|
|
156
152
|
variant: S[e.status] || "outline",
|
|
157
153
|
className: "text-[10px]",
|
|
158
154
|
children: e.status.replace("_", " ")
|
|
159
|
-
}), /* @__PURE__ */ x("span", {
|
|
155
|
+
}), e.updatedAt ? /* @__PURE__ */ x("span", {
|
|
160
156
|
className: "text-[10px] text-text-secondary",
|
|
161
|
-
children: ["Updated: ", new Date(e.
|
|
162
|
-
})]
|
|
157
|
+
children: ["Updated: ", new Date(e.updatedAt).toLocaleDateString()]
|
|
158
|
+
}) : null]
|
|
163
159
|
})
|
|
164
160
|
]
|
|
165
161
|
})]
|
|
166
|
-
}, e.
|
|
162
|
+
}, e.id))
|
|
167
163
|
})] }, e))
|
|
168
164
|
}) })]
|
|
169
165
|
})]
|
|
@@ -172,6 +168,6 @@ function C() {
|
|
|
172
168
|
});
|
|
173
169
|
}
|
|
174
170
|
//#endregion
|
|
175
|
-
export {
|
|
171
|
+
export { w as AssetsAssetTrackingPage };
|
|
176
172
|
|
|
177
173
|
//# sourceMappingURL=AssetsAssetTrackingPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssetsAssetTrackingPage.js","names":[],"sources":["../../../src/assethandler/pages/AssetsAssetTrackingPage.tsx"],"sourcesContent":["import {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Input,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { MapPin, Search, RefreshCw, Radio, Navigation, Building, Clock } from 'lucide-react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\n\nconst statusColors: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n active: 'default',\n inactive: 'outline',\n under_maintenance: 'secondary',\n};\n\nexport function AssetsAssetTrackingPage() {\n const { assetLocations } = useAssetHandlerStore();\n\n const buildingGroups = assetLocations.reduce<Record<string, typeof assetLocations>>(\n (acc, loc) => {\n if (!acc[loc.building]) acc[loc.building] = [];\n acc[loc.building].push(loc);\n return acc;\n },\n {}\n );\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>Asset Tracking</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Real-time location tracking for {assetLocations.length} assets\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\">\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n Refresh\n </Button>\n <Button size=\"sm\">\n <Radio className=\"mr-2 h-4 w-4\" />\n Track New Asset\n </Button>\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Radio className=\"h-4 w-4\" />\n Tracked Assets\n </div>\n <p className=\"text-2xl font-bold mt-1\">{assetLocations.length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Building className=\"h-4 w-4\" />\n Buildings\n </div>\n <p className=\"text-2xl font-bold mt-1\">{Object.keys(buildingGroups).length}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Navigation className=\"h-4 w-4\" />\n In Field\n </div>\n <p className=\"text-2xl font-bold mt-1\">\n {assetLocations.filter((l) => l.building === 'Field').length}\n </p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Clock className=\"h-4 w-4\" />\n Last Update\n </div>\n <p className=\"text-lg font-bold mt-1\">Just now</p>\n </CardContent>\n </Card>\n </div>\n\n <PagePurpose>\n Know where your assets physically are at any moment. See them grouped by building, floor and\n room (and out in the field), so you can locate equipment fast, spot anything that has moved\n unexpectedly, and confirm assets are where they should be.\n </PagePurpose>\n\n <div className=\"grid gap-6 lg:grid-cols-5\">\n <EmphasisPanel className=\"lg:col-span-3\">\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Location Map</CardTitle>\n <CardDescription>Geographic distribution of tracked assets</CardDescription>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <div className=\"bg-bg-sunken rounded-lg h-80 flex items-center justify-center border-2 border-dashed\">\n <div className=\"text-center\">\n <MapPin className=\"h-12 w-12 text-text-secondary mx-auto mb-2\" />\n <p className=\"text-text-secondary\">Interactive map view</p>\n <p className=\"text-xs text-text-secondary mt-1\">\n Map integration would render here\n </p>\n </div>\n </div>\n </CardContent>\n </EmphasisPanel>\n\n <Card className=\"lg:col-span-2\">\n <CardHeader>\n <CardTitle>Asset Locations</CardTitle>\n <div className=\"relative mt-2\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input placeholder=\"Search assets...\" className=\"pl-9\" />\n </div>\n </CardHeader>\n <CardContent>\n {assetLocations.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No tracked assets\"\n description=\"Start tracking an asset's location and it will appear here grouped by building.\"\n />\n ) : (\n <div className=\"space-y-4\">\n {Object.entries(buildingGroups).map(([building, locations]) => (\n <div key={building}>\n <h4 className=\"text-sm font-medium flex items-center gap-2 mb-2\">\n <Building className=\"h-3.5 w-3.5\" />\n {building}\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n {locations.length}\n </Badge>\n </h4>\n <div className=\"space-y-2 ml-5\">\n {locations.map((loc) => (\n <div\n key={loc.assetId}\n className=\"flex items-start gap-3 rounded border p-2.5\"\n >\n <MapPin className=\"h-3.5 w-3.5 mt-0.5 text-text-secondary shrink-0\" />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium truncate\">{loc.assetName}</p>\n <p className=\"text-xs text-text-secondary\">\n {loc.floor !== '-' ? `Floor ${loc.floor}, ` : ''}\n {loc.room}\n </p>\n <div className=\"flex items-center gap-2 mt-1\">\n <Badge\n variant={statusColors[loc.status] || 'outline'}\n className=\"text-[10px]\"\n >\n {loc.status.replace('_', ' ')}\n </Badge>\n <span className=\"text-[10px] text-text-secondary\">\n Updated: {new Date(loc.lastUpdated).toLocaleTimeString()}\n </span>\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AssetsAssetTrackingPage.js","names":[],"sources":["../../../src/assethandler/pages/AssetsAssetTrackingPage.tsx"],"sourcesContent":["import { useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Input,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport { MapPin, Search, RefreshCw, Radio, Building, HelpCircle } from 'lucide-react';\nimport { useAssetHandlerStore, type Asset } from '../store/assethandlerStore';\n\nconst statusColors: Record<string, 'default' | 'secondary' | 'destructive' | 'outline'> = {\n active: 'default',\n inactive: 'outline',\n maintenance: 'secondary',\n retired: 'outline',\n disposed: 'destructive',\n};\n\nconst UNLOCATED = 'Unlocated';\n\nexport function AssetsAssetTrackingPage() {\n const { assets } = useAssetHandlerStore();\n\n const locationGroups = useMemo(\n () =>\n assets.reduce<Record<string, Asset[]>>((acc, asset) => {\n const key = asset.location.trim() || UNLOCATED;\n if (!acc[key]) acc[key] = [];\n acc[key].push(asset);\n return acc;\n }, {}),\n [assets]\n );\n\n const locatedCount = assets.filter((a) => a.location.trim()).length;\n const unlocatedCount = assets.length - locatedCount;\n const locationCount = Object.keys(locationGroups).filter((k) => k !== UNLOCATED).length;\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex items-center justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold\">\n <GradientText>Asset Tracking</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n Location overview for {assets.length} assets\n </p>\n </div>\n <div className=\"flex gap-2\">\n <Button variant=\"outline\" size=\"sm\">\n <RefreshCw className=\"mr-2 h-4 w-4\" />\n Refresh\n </Button>\n <Button size=\"sm\">\n <Radio className=\"mr-2 h-4 w-4\" />\n Track New Asset\n </Button>\n </div>\n </div>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Radio className=\"h-4 w-4\" />\n Located Assets\n </div>\n <p className=\"text-2xl font-bold mt-1\">{locatedCount}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <Building className=\"h-4 w-4\" />\n Locations\n </div>\n <p className=\"text-2xl font-bold mt-1\">{locationCount}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <HelpCircle className=\"h-4 w-4\" />\n Unlocated\n </div>\n <p className=\"text-2xl font-bold mt-1\">{unlocatedCount}</p>\n </CardContent>\n </Card>\n </div>\n\n <PagePurpose>\n Know where your assets physically are. See them grouped by location, so you can locate\n equipment fast, spot assets that still have no recorded location, and confirm items are\n where they should be.\n </PagePurpose>\n\n <div className=\"grid gap-6 lg:grid-cols-5\">\n <EmphasisPanel className=\"lg:col-span-3\">\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Location Map</CardTitle>\n <CardDescription>Geographic distribution of tracked assets</CardDescription>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <div className=\"bg-bg-sunken rounded-lg h-80 flex items-center justify-center border-2 border-dashed\">\n <div className=\"text-center\">\n <MapPin className=\"h-12 w-12 text-text-secondary mx-auto mb-2\" />\n <p className=\"text-text-secondary\">Interactive map view</p>\n <p className=\"text-xs text-text-secondary mt-1\">\n Map integration would render here\n </p>\n </div>\n </div>\n </CardContent>\n </EmphasisPanel>\n\n <Card className=\"lg:col-span-2\">\n <CardHeader>\n <CardTitle>Asset Locations</CardTitle>\n <div className=\"relative mt-2\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-text-secondary\" />\n <Input placeholder=\"Search assets...\" className=\"pl-9\" />\n </div>\n </CardHeader>\n <CardContent>\n {assets.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No assets to track\"\n description=\"Add an asset and give it a location to see it grouped here.\"\n />\n ) : (\n <div className=\"space-y-4\">\n {Object.entries(locationGroups).map(([location, groupAssets]) => (\n <div key={location}>\n <h4 className=\"text-sm font-medium flex items-center gap-2 mb-2\">\n <Building className=\"h-3.5 w-3.5\" />\n {location}\n <Badge variant=\"secondary\" className=\"text-[10px]\">\n {groupAssets.length}\n </Badge>\n </h4>\n <div className=\"space-y-2 ml-5\">\n {groupAssets.map((asset) => (\n <div key={asset.id} className=\"flex items-start gap-3 rounded border p-2.5\">\n <MapPin className=\"h-3.5 w-3.5 mt-0.5 text-text-secondary shrink-0\" />\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium truncate\">{asset.name}</p>\n <p className=\"text-xs text-text-secondary\">{asset.assetTag}</p>\n <div className=\"flex items-center gap-2 mt-1\">\n <Badge\n variant={statusColors[asset.status] || 'outline'}\n className=\"text-[10px]\"\n >\n {asset.status.replace('_', ' ')}\n </Badge>\n {asset.updatedAt ? (\n <span className=\"text-[10px] text-text-secondary\">\n Updated: {new Date(asset.updatedAt).toLocaleDateString()}\n </span>\n ) : null}\n </div>\n </div>\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|