@burdenoff/microfe-assethandler 2026.703.7 → 2026.703.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"DigitalTwinPage.js","names":[],"sources":["../../../src/assethandler/pages/DigitalTwinPage.tsx"],"sourcesContent":["import { Box, Plus } from 'lucide-react';\nimport { useState } from 'react';\nimport {\n Button,\n GradientText,\n IllustratedEmptyState,\n GlassCard,\n PagePurpose,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { Pagination, usePagination } from '../components';\nimport { notify } from '../utils/toast';\n\nconst DIGITAL_TWINS_QUERY = gql`\n query AssetHandlerDigitalTwins {\n digitalTwins {\n id\n assetId\n modelRef\n fidelityLevel\n geometryRef\n updatedAt\n }\n }\n`;\n\nconst CREATE_DIGITAL_TWIN_MUTATION = gql`\n mutation AssetHandlerCreateDigitalTwin($input: CreateDigitalTwinInput!) {\n createDigitalTwin(input: $input) {\n id\n modelRef\n }\n }\n`;\n\ninterface DigitalTwin {\n id: string;\n assetId: string;\n modelRef: string;\n fidelityLevel: string;\n geometryRef: string | null;\n updatedAt: string;\n}\n\ninterface CreateDigitalTwinResult {\n createDigitalTwin: { id: string; modelRef: string };\n}\n\nconst FIDELITY_LEVELS = ['LOW', 'MEDIUM', 'HIGH', 'ULTRA'] as const;\n\nfunction NewDigitalTwinDialog({\n open,\n onOpenChange,\n onCreated,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onCreated: () => void;\n}) {\n const assets = useAssetHandlerStore((s) => s.assets);\n const [assetId, setAssetId] = useState('');\n const [modelRef, setModelRef] = useState('');\n const [fidelityLevel, setFidelityLevel] = useState<(typeof FIDELITY_LEVELS)[number]>('MEDIUM');\n const [geometryRef, setGeometryRef] = useState('');\n\n const reset = () => {\n setAssetId('');\n setModelRef('');\n setFidelityLevel('MEDIUM');\n setGeometryRef('');\n };\n\n const [createTwin, { loading }] = useMutation<CreateDigitalTwinResult>(\n CREATE_DIGITAL_TWIN_MUTATION,\n {\n onCompleted: (data) => {\n notify.success('Digital twin created', `${data.createDigitalTwin.modelRef} is now linked.`);\n reset();\n onOpenChange(false);\n onCreated();\n },\n onError: (error) => notify.error('Could not create digital twin', error.message),\n }\n );\n\n const handleSubmit = () => {\n if (!assetId) {\n notify.warning('Asset required', 'Select the asset this twin represents.');\n return;\n }\n if (!modelRef.trim()) {\n notify.warning('Model reference required', 'Enter the model reference for this twin.');\n return;\n }\n void createTwin({\n variables: {\n input: {\n assetId,\n modelRef: modelRef.trim(),\n fidelityLevel,\n geometryRef: geometryRef.trim() || null,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New Digital Twin</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Create a virtual replica linked to a physical asset.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Asset *</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {assets.map((asset) => (\n <SelectItem key={asset.id} value={asset.id}>\n {asset.assetTag} — {asset.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Model Reference *</Label>\n <Input\n placeholder=\"e.g., twin-pump-03\"\n value={modelRef}\n onChange={(e) => setModelRef(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Fidelity Level</Label>\n <Select\n value={fidelityLevel}\n onValueChange={(v) => setFidelityLevel(v as typeof fidelityLevel)}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {FIDELITY_LEVELS.map((f) => (\n <SelectItem key={f} value={f}>\n {f}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>Geometry Reference</Label>\n <Input\n placeholder=\"e.g., s3://twins/pump-03.glb\"\n value={geometryRef}\n onChange={(e) => setGeometryRef(e.target.value)}\n />\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? 'Creating…' : 'Create twin'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function DigitalTwinPage() {\n const [dialogOpen, setDialogOpen] = useState(false);\n const { data, loading, refetch } = useQuery<{ digitalTwins: DigitalTwin[] }>(DIGITAL_TWINS_QUERY, {\n fetchPolicy: 'cache-and-network',\n });\n\n const twins = data?.digitalTwins ?? [];\n const pagination = usePagination(twins, { pageSize: 8 });\n\n return (\n <div className=\"space-y-4 p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <h1 className=\"flex items-center gap-2 text-2xl font-semibold\">\n <Box className=\"h-6 w-6\" /> <GradientText>Digital Twin</GradientText>\n </h1>\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n New Twin\n </Button>\n </div>\n <PagePurpose>\n A live virtual replica of your most critical assets. Use digital twins to simulate what-if\n scenarios, validate maintenance changes, and visualise condition without touching the\n physical equipment — so you can de-risk decisions on high-value or hard-to-access assets.\n </PagePurpose>\n\n <NewDigitalTwinDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n onCreated={() => void refetch()}\n />\n\n <div className=\"grid gap-3 md:grid-cols-2\">\n {loading && twins.length === 0 ? (\n <div className=\"space-y-2 px-4 py-4\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"h-8 rounded-md bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n {!loading && twins.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No digital twins found\"\n description=\"Create a digital twin to model one of your assets.\"\n />\n ) : null}\n {pagination.pageItems.map((twin, i) => (\n <GlassCard\n key={twin.id}\n treatment={i === 0 && pagination.page === 1 ? 'glass' : 'plain'}\n glow={i === 0 && pagination.page === 1}\n className=\"p-4 border-border-seam\"\n >\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">\n Asset {twin.assetId}\n </p>\n <h2 className=\"mt-1 text-base font-semibold\">{twin.modelRef}</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">Fidelity: {twin.fidelityLevel}</p>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Geometry: {twin.geometryRef ?? 'Not linked'}\n </p>\n </GlassCard>\n ))}\n </div>\n <Pagination\n page={pagination.page}\n pageCount={pagination.pageCount}\n rangeStart={pagination.rangeStart}\n rangeEnd={pagination.rangeEnd}\n totalItems={pagination.totalItems}\n canPrev={pagination.canPrev}\n canNext={pagination.canNext}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"twins\"\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DigitalTwinPage.js","names":[],"sources":["../../../src/assethandler/pages/DigitalTwinPage.tsx"],"sourcesContent":["import { Box, Plus } from 'lucide-react';\nimport { useState } from 'react';\nimport {\n Button,\n GradientText,\n IllustratedEmptyState,\n GlassCard,\n PagePurpose,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { Pagination, usePagination } from '../components';\nimport { notify } from '../utils/toast';\n\nconst DIGITAL_TWINS_QUERY = gql`\n query AssetHandlerDigitalTwins {\n digitalTwins {\n id\n assetId\n modelRef\n fidelityLevel\n geometryRef\n updatedAt\n }\n }\n`;\n\nconst CREATE_DIGITAL_TWIN_MUTATION = gql`\n mutation AssetHandlerCreateDigitalTwin($input: CreateDigitalTwinInput!) {\n createDigitalTwin(input: $input) {\n id\n modelRef\n }\n }\n`;\n\ninterface DigitalTwin {\n id: string;\n assetId: string;\n modelRef: string;\n fidelityLevel: string;\n geometryRef: string | null;\n updatedAt: string;\n}\n\ninterface CreateDigitalTwinResult {\n createDigitalTwin: { id: string; modelRef: string };\n}\n\nconst FIDELITY_LEVELS = ['LOW', 'MEDIUM', 'HIGH', 'ULTRA'] as const;\n\nfunction NewDigitalTwinDialog({\n open,\n onOpenChange,\n onCreated,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n onCreated: () => void;\n}) {\n const assets = useAssetHandlerStore((s) => s.assets);\n const [assetId, setAssetId] = useState('');\n const [modelRef, setModelRef] = useState('');\n const [fidelityLevel, setFidelityLevel] = useState<(typeof FIDELITY_LEVELS)[number]>('MEDIUM');\n const [geometryRef, setGeometryRef] = useState('');\n\n const reset = () => {\n setAssetId('');\n setModelRef('');\n setFidelityLevel('MEDIUM');\n setGeometryRef('');\n };\n\n const [createTwin, { loading }] = useMutation<CreateDigitalTwinResult>(\n CREATE_DIGITAL_TWIN_MUTATION,\n {\n onCompleted: (data) => {\n notify.success('Digital twin created', `${data.createDigitalTwin.modelRef} is now linked.`);\n reset();\n onOpenChange(false);\n onCreated();\n },\n onError: (error) => notify.error('Could not create digital twin', error.message),\n }\n );\n\n const handleSubmit = () => {\n if (!assetId) {\n notify.warning('Asset required', 'Select the asset this twin represents.');\n return;\n }\n if (!modelRef.trim()) {\n notify.warning('Model reference required', 'Enter the model reference for this twin.');\n return;\n }\n void createTwin({\n variables: {\n input: {\n assetId,\n modelRef: modelRef.trim(),\n fidelityLevel,\n geometryRef: geometryRef.trim() || null,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New Digital Twin</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Create a virtual replica linked to a physical asset.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Asset *</Label>\n <Select value={assetId} onValueChange={setAssetId}>\n <SelectTrigger>\n <SelectValue placeholder=\"Select an asset\" />\n </SelectTrigger>\n <SelectContent>\n {assets.map((asset) => (\n <SelectItem key={asset.id} value={asset.id}>\n {asset.assetTag} — {asset.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Model Reference *</Label>\n <Input\n placeholder=\"e.g., twin-pump-03\"\n value={modelRef}\n onChange={(e) => setModelRef(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Fidelity Level</Label>\n <Select\n value={fidelityLevel}\n onValueChange={(v) => setFidelityLevel(v as typeof fidelityLevel)}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {FIDELITY_LEVELS.map((f) => (\n <SelectItem key={f} value={f}>\n {f}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>Geometry Reference</Label>\n <Input\n placeholder=\"e.g., s3://twins/pump-03.glb\"\n value={geometryRef}\n onChange={(e) => setGeometryRef(e.target.value)}\n />\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? 'Creating…' : 'Create twin'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function DigitalTwinPage() {\n const [dialogOpen, setDialogOpen] = useState(false);\n const { data, loading, refetch } = useQuery<{ digitalTwins: DigitalTwin[] }>(\n DIGITAL_TWINS_QUERY,\n {\n fetchPolicy: 'cache-and-network',\n }\n );\n\n const twins = data?.digitalTwins ?? [];\n const pagination = usePagination(twins, { pageSize: 8 });\n\n return (\n <div className=\"space-y-4 p-4\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <h1 className=\"flex items-center gap-2 text-2xl font-semibold\">\n <Box className=\"h-6 w-6\" /> <GradientText>Digital Twin</GradientText>\n </h1>\n <Button onClick={() => setDialogOpen(true)}>\n <Plus className=\"mr-2 h-4 w-4\" />\n New Twin\n </Button>\n </div>\n <PagePurpose>\n A live virtual replica of your most critical assets. Use digital twins to simulate what-if\n scenarios, validate maintenance changes, and visualise condition without touching the\n physical equipment — so you can de-risk decisions on high-value or hard-to-access assets.\n </PagePurpose>\n\n <NewDigitalTwinDialog\n open={dialogOpen}\n onOpenChange={setDialogOpen}\n onCreated={() => void refetch()}\n />\n\n <div className=\"grid gap-3 md:grid-cols-2\">\n {loading && twins.length === 0 ? (\n <div className=\"space-y-2 px-4 py-4\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"h-8 rounded-md bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n {!loading && twins.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No digital twins found\"\n description=\"Create a digital twin to model one of your assets.\"\n />\n ) : null}\n {pagination.pageItems.map((twin, i) => (\n <GlassCard\n key={twin.id}\n treatment={i === 0 && pagination.page === 1 ? 'glass' : 'plain'}\n glow={i === 0 && pagination.page === 1}\n className=\"p-4 border-border-seam\"\n >\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">\n Asset {twin.assetId}\n </p>\n <h2 className=\"mt-1 text-base font-semibold\">{twin.modelRef}</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">Fidelity: {twin.fidelityLevel}</p>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Geometry: {twin.geometryRef ?? 'Not linked'}\n </p>\n </GlassCard>\n ))}\n </div>\n <Pagination\n page={pagination.page}\n pageCount={pagination.pageCount}\n rangeStart={pagination.rangeStart}\n rangeEnd={pagination.rangeEnd}\n totalItems={pagination.totalItems}\n canPrev={pagination.canPrev}\n canNext={pagination.canNext}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"twins\"\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DiscoveryJobsPage.js","names":[],"sources":["../../../src/assethandler/pages/DiscoveryJobsPage.tsx"],"sourcesContent":["import { Radar } from 'lucide-react';\nimport type React from 'react';\nimport {\n Button,\n GradientText,\n IllustratedEmptyState,\n EmphasisPanel,\n PagePurpose,\n Input,\n Label,\n} from '@burdenoff/fe-libs/ui';\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { Pagination, usePagination } from '../components';\nimport { notify } from '../utils/toast';\n\nconst DISCOVERY_JOBS_QUERY = gql`\n query AssetHandlerDiscoveryJobs {\n discoveryJobs {\n id\n name\n source\n status\n assetsDiscovered\n startedAt\n completedAt\n }\n }\n`;\n\nconst START_DISCOVERY_JOB_MUTATION = gql`\n mutation AssetHandlerStartDiscoveryJob($input: StartDiscoveryJobInput!) {\n startDiscoveryJob(input: $input) {\n id\n name\n }\n }\n`;\n\ninterface DiscoveryJob {\n id: string;\n name: string;\n source: string;\n status: string;\n assetsDiscovered: number;\n startedAt: string | null;\n completedAt: string | null;\n}\n\ninterface StartDiscoveryJobResult {\n startDiscoveryJob: { id: string; name: string };\n}\n\nexport function DiscoveryJobsPage() {\n const [name, setName] = useState('');\n const [source, setSource] = useState('');\n\n const { data, loading, refetch } = useQuery<{ discoveryJobs: DiscoveryJob[] }>(\n DISCOVERY_JOBS_QUERY,\n { fetchPolicy: 'cache-and-network' }\n );\n\n const [startDiscoveryJob, { loading: starting }] = useMutation<StartDiscoveryJobResult>(\n START_DISCOVERY_JOB_MUTATION,\n {\n onCompleted: (result) => {\n notify.success('Discovery job started', `${result.startDiscoveryJob.name} is now scanning.`);\n setName('');\n setSource('');\n void refetch();\n },\n onError: (error) => notify.error('Could not start discovery job', error.message),\n }\n );\n\n const jobs = data?.discoveryJobs ?? [];\n const pagination = usePagination(jobs, { pageSize: 12 });\n\n const handleSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n if (!name.trim() || !source.trim()) {\n notify.warning('Missing details', 'Job name and discovery source are required.');\n return;\n }\n void startDiscoveryJob({ variables: { input: { name: name.trim(), source: source.trim() } } });\n };\n\n return (\n <div className=\"space-y-4 p-4\">\n <h1 className=\"flex items-center gap-2 text-2xl font-semibold\">\n <Radar className=\"h-6 w-6\" /> <GradientText>Discovery Jobs</GradientText>\n </h1>\n <PagePurpose>\n Automatically find assets across your cloud and on-prem environments instead of entering\n them by hand. Point a discovery job at a source (e.g. an AWS region) and it scans for new or\n changed assets and feeds them into your inventory — keeping the estate complete and up to\n date.\n </PagePurpose>\n <EmphasisPanel>\n <h2 className=\"text-sm font-semibold mb-3\">Start a discovery scan</h2>\n <form className=\"grid gap-3 md:grid-cols-3\" onSubmit={handleSubmit}>\n <div className=\"space-y-2\">\n <Label>Job Name</Label>\n <Input\n value={name}\n onChange={(event) => setName(event.target.value)}\n placeholder=\"e.g., Nightly datacenter scan\"\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Discovery Source</Label>\n <Input\n value={source}\n onChange={(event) => setSource(event.target.value)}\n placeholder=\"e.g., aws-ap-south-1\"\n />\n </div>\n <div className=\"flex items-end\">\n <Button className=\"w-full\" disabled={starting} type=\"submit\">\n {starting ? 'Starting…' : 'Start Job'}\n </Button>\n </div>\n </form>\n </EmphasisPanel>\n <div className=\"rounded-lg border\">\n <div className=\"grid grid-cols-5 gap-3 border-b px-4 py-3 text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n <span>Name</span>\n <span>Source</span>\n <span>Status</span>\n <span>Discovered</span>\n <span>Started</span>\n </div>\n {loading && jobs.length === 0 ? (\n <div className=\"space-y-2 px-4 py-4\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"h-8 rounded-md bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n {!loading && jobs.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No discovery jobs found\"\n description=\"Run a discovery job to populate this list.\"\n />\n ) : null}\n {pagination.pageItems.map((job) => (\n <div\n key={job.id}\n className=\"grid grid-cols-5 gap-3 border-b px-4 py-3 text-sm last:border-b-0\"\n >\n <span className=\"font-medium\">{job.name}</span>\n <span>{job.source}</span>\n <span>{job.status}</span>\n <span>{job.assetsDiscovered}</span>\n <span className=\"text-text-secondary\">\n {job.startedAt ? new Date(job.startedAt).toLocaleString() : 'n/a'}\n </span>\n </div>\n ))}\n </div>\n <Pagination\n page={pagination.page}\n pageCount={pagination.pageCount}\n rangeStart={pagination.rangeStart}\n rangeEnd={pagination.rangeEnd}\n totalItems={pagination.totalItems}\n canPrev={pagination.canPrev}\n canNext={pagination.canNext}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"jobs\"\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DiscoveryJobsPage.js","names":[],"sources":["../../../src/assethandler/pages/DiscoveryJobsPage.tsx"],"sourcesContent":["import { Radar } from 'lucide-react';\nimport type React from 'react';\nimport {\n Button,\n GradientText,\n IllustratedEmptyState,\n EmphasisPanel,\n PagePurpose,\n Input,\n Label,\n} from '@burdenoff/fe-libs/ui';\nimport { useState } from 'react';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { Pagination, usePagination } from '../components';\nimport { notify } from '../utils/toast';\n\nconst DISCOVERY_JOBS_QUERY = gql`\n query AssetHandlerDiscoveryJobs {\n discoveryJobs {\n id\n name\n source\n status\n assetsDiscovered\n startedAt\n completedAt\n }\n }\n`;\n\nconst START_DISCOVERY_JOB_MUTATION = gql`\n mutation AssetHandlerStartDiscoveryJob($input: StartDiscoveryJobInput!) {\n startDiscoveryJob(input: $input) {\n id\n name\n }\n }\n`;\n\ninterface DiscoveryJob {\n id: string;\n name: string;\n source: string;\n status: string;\n assetsDiscovered: number;\n startedAt: string | null;\n completedAt: string | null;\n}\n\ninterface StartDiscoveryJobResult {\n startDiscoveryJob: { id: string; name: string };\n}\n\nexport function DiscoveryJobsPage() {\n const [name, setName] = useState('');\n const [source, setSource] = useState('');\n\n const { data, loading, refetch } = useQuery<{ discoveryJobs: DiscoveryJob[] }>(\n DISCOVERY_JOBS_QUERY,\n { fetchPolicy: 'cache-and-network' }\n );\n\n const [startDiscoveryJob, { loading: starting }] = useMutation<StartDiscoveryJobResult>(\n START_DISCOVERY_JOB_MUTATION,\n {\n onCompleted: (result) => {\n notify.success(\n 'Discovery job started',\n `${result.startDiscoveryJob.name} is now scanning.`\n );\n setName('');\n setSource('');\n void refetch();\n },\n onError: (error) => notify.error('Could not start discovery job', error.message),\n }\n );\n\n const jobs = data?.discoveryJobs ?? [];\n const pagination = usePagination(jobs, { pageSize: 12 });\n\n const handleSubmit = (event: React.FormEvent) => {\n event.preventDefault();\n if (!name.trim() || !source.trim()) {\n notify.warning('Missing details', 'Job name and discovery source are required.');\n return;\n }\n void startDiscoveryJob({ variables: { input: { name: name.trim(), source: source.trim() } } });\n };\n\n return (\n <div className=\"space-y-4 p-4\">\n <h1 className=\"flex items-center gap-2 text-2xl font-semibold\">\n <Radar className=\"h-6 w-6\" /> <GradientText>Discovery Jobs</GradientText>\n </h1>\n <PagePurpose>\n Automatically find assets across your cloud and on-prem environments instead of entering\n them by hand. Point a discovery job at a source (e.g. an AWS region) and it scans for new or\n changed assets and feeds them into your inventory — keeping the estate complete and up to\n date.\n </PagePurpose>\n <EmphasisPanel>\n <h2 className=\"text-sm font-semibold mb-3\">Start a discovery scan</h2>\n <form className=\"grid gap-3 md:grid-cols-3\" onSubmit={handleSubmit}>\n <div className=\"space-y-2\">\n <Label>Job Name</Label>\n <Input\n value={name}\n onChange={(event) => setName(event.target.value)}\n placeholder=\"e.g., Nightly datacenter scan\"\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Discovery Source</Label>\n <Input\n value={source}\n onChange={(event) => setSource(event.target.value)}\n placeholder=\"e.g., aws-ap-south-1\"\n />\n </div>\n <div className=\"flex items-end\">\n <Button className=\"w-full\" disabled={starting} type=\"submit\">\n {starting ? 'Starting…' : 'Start Job'}\n </Button>\n </div>\n </form>\n </EmphasisPanel>\n <div className=\"rounded-lg border\">\n <div className=\"grid grid-cols-5 gap-3 border-b px-4 py-3 text-xs font-semibold uppercase tracking-wide text-text-secondary\">\n <span>Name</span>\n <span>Source</span>\n <span>Status</span>\n <span>Discovered</span>\n <span>Started</span>\n </div>\n {loading && jobs.length === 0 ? (\n <div className=\"space-y-2 px-4 py-4\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"h-8 rounded-md bg-bg-sunken motion-safe:animate-vc-shimmer\" />\n ))}\n </div>\n ) : null}\n {!loading && jobs.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No discovery jobs found\"\n description=\"Run a discovery job to populate this list.\"\n />\n ) : null}\n {pagination.pageItems.map((job) => (\n <div\n key={job.id}\n className=\"grid grid-cols-5 gap-3 border-b px-4 py-3 text-sm last:border-b-0\"\n >\n <span className=\"font-medium\">{job.name}</span>\n <span>{job.source}</span>\n <span>{job.status}</span>\n <span>{job.assetsDiscovered}</span>\n <span className=\"text-text-secondary\">\n {job.startedAt ? new Date(job.startedAt).toLocaleString() : 'n/a'}\n </span>\n </div>\n ))}\n </div>\n <Pagination\n page={pagination.page}\n pageCount={pagination.pageCount}\n rangeStart={pagination.rangeStart}\n rangeEnd={pagination.rangeEnd}\n totalItems={pagination.totalItems}\n canPrev={pagination.canPrev}\n canNext={pagination.canNext}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"jobs\"\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -28,7 +28,7 @@ var F = s`
28
28
  }
29
29
  }
30
30
  `, I = s`
31
- mutation AssetHandlerUpdateBudget($id: ID!, $input: UpdateBudgetInput!) {
31
+ mutation AssetHandlerUpdateBudget($id: ID!, $input: AssetHandlerUpdateBudgetInput!) {
32
32
  updateBudget(id: $id, input: $input) {
33
33
  id
34
34
  name
@@ -1 +1 @@
1
- {"version":3,"file":"FinanceBudgetDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/FinanceBudgetDetailPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n IllustratedEmptyState,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, Edit, Loader2 } from 'lucide-react';\nimport { useParams } from 'react-router-dom';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { NotFoundState } from '../components';\nimport { notify } from '../utils/toast';\n\n// ─── Backend types ────────────────────────────────────────────────────────────\ntype AssetBudgetStatus = 'ON_TRACK' | 'OVER_BUDGET' | 'UNDER_BUDGET';\n\ninterface AssetBudget {\n id: string;\n name: string;\n category: string;\n allocated: number;\n spent: number;\n remaining: number;\n period: string;\n department: string;\n status: AssetBudgetStatus;\n createdAt: string;\n updatedAt: string;\n}\n\nconst BUDGET_QUERY = gql`\n query AssetHandlerBudget($id: ID!) {\n budget(id: $id) {\n id\n name\n category\n allocated\n spent\n remaining\n period\n department\n status\n createdAt\n updatedAt\n }\n }\n`;\n\nconst UPDATE_BUDGET_MUTATION = gql`\n mutation AssetHandlerUpdateBudget($id: ID!, $input: UpdateBudgetInput!) {\n updateBudget(id: $id, input: $input) {\n id\n name\n }\n }\n`;\n\ninterface BudgetQueryResult {\n budget: AssetBudget | null;\n}\ninterface UpdateBudgetResult {\n updateBudget: { id: string; name: string };\n}\n\nconst BUDGET_STATUSES: AssetBudgetStatus[] = ['ON_TRACK', 'OVER_BUDGET', 'UNDER_BUDGET'];\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nconst statusVariant = (status: string): 'default' | 'secondary' | 'destructive' | 'outline' =>\n status === 'OVER_BUDGET' ? 'destructive' : status === 'UNDER_BUDGET' ? 'secondary' : 'default';\n\nexport function FinanceBudgetDetailPage() {\n const navigate = useAssetHandlerNavigate();\n const { budgetId } = useParams<{ budgetId: string }>();\n const { transactions } = useAssetHandlerStore();\n\n const { data, loading, refetch } = useQuery<BudgetQueryResult>(BUDGET_QUERY, {\n variables: { id: budgetId ?? '' },\n skip: !budgetId,\n fetchPolicy: 'cache-and-network',\n });\n\n const budget = data?.budget ?? null;\n\n const [editOpen, setEditOpen] = useState(false);\n const [form, setForm] = useState({\n name: '',\n category: '',\n department: '',\n period: '',\n allocated: '',\n spent: '',\n status: 'ON_TRACK' as AssetBudgetStatus,\n });\n\n const openEdit = () => {\n if (!budget) return;\n setForm({\n name: budget.name,\n category: budget.category,\n department: budget.department,\n period: budget.period,\n allocated: String(budget.allocated),\n spent: String(budget.spent),\n status: budget.status,\n });\n setEditOpen(true);\n };\n\n const [updateBudget, { loading: saving }] = useMutation<UpdateBudgetResult>(\n UPDATE_BUDGET_MUTATION,\n {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => {\n notify.success('Budget updated', 'Your changes have been saved.');\n setEditOpen(false);\n void refetch();\n },\n onError: (error) => notify.error('Could not update budget', error.message),\n }\n );\n\n const handleSave = () => {\n if (!budgetId) return;\n const parsedAllocated = Number(form.allocated);\n const parsedSpent = Number(form.spent);\n if (\n !form.name.trim() ||\n !form.category.trim() ||\n !form.department.trim() ||\n !form.period.trim()\n ) {\n notify.warning('Missing details', 'Name, category, department and period are required.');\n return;\n }\n if (!Number.isFinite(parsedAllocated) || !Number.isFinite(parsedSpent)) {\n notify.warning('Invalid numbers', 'Allocated and spent must be numeric.');\n return;\n }\n void updateBudget({\n variables: {\n id: budgetId,\n input: {\n name: form.name.trim(),\n category: form.category.trim(),\n department: form.department.trim(),\n period: form.period.trim(),\n allocated: parsedAllocated,\n spent: parsedSpent,\n status: form.status,\n },\n },\n });\n };\n\n if (loading && !budget) {\n return (\n <div className=\"flex min-h-[320px] items-center justify-center p-6\">\n <Loader2 className=\"h-8 w-8 animate-spin text-primary\" />\n </div>\n );\n }\n\n if (!budget) {\n return (\n <NotFoundState\n entityLabel=\"Budget\"\n onBack={() => navigate('/finance/finance-hub')}\n backLabel=\"Back to finance\"\n />\n );\n }\n\n const relatedTxns = transactions.filter((t) => t.category === budget.category);\n const utilizationPct = budget.allocated ? Math.round((budget.spent / budget.allocated) * 100) : 0;\n\n return (\n <div className=\"space-y-6 p-6\">\n <ResponsiveDialog open={editOpen} onOpenChange={setEditOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Edit Budget</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Update the allocation and status for this budget.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Name *</Label>\n <Input\n value={form.name}\n onChange={(e) => setForm((p) => ({ ...p, name: e.target.value }))}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Category *</Label>\n <Input\n value={form.category}\n onChange={(e) => setForm((p) => ({ ...p, category: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Department *</Label>\n <Input\n value={form.department}\n onChange={(e) => setForm((p) => ({ ...p, department: e.target.value }))}\n />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Period *</Label>\n <Input\n value={form.period}\n onChange={(e) => setForm((p) => ({ ...p, period: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select\n value={form.status}\n onValueChange={(v) => setForm((p) => ({ ...p, status: v as AssetBudgetStatus }))}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {BUDGET_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Allocated *</Label>\n <Input\n type=\"number\"\n value={form.allocated}\n onChange={(e) => setForm((p) => ({ ...p, allocated: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Spent *</Label>\n <Input\n type=\"number\"\n value={form.spent}\n onChange={(e) => setForm((p) => ({ ...p, spent: e.target.value }))}\n />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setEditOpen(false)} disabled={saving}>\n Cancel\n </Button>\n <Button onClick={handleSave} disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {saving ? 'Saving…' : 'Save Changes'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <Button variant=\"ghost\" size=\"icon\" onClick={() => navigate('/finance/finance-hub')}>\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold\">\n <GradientText>{budget.name}</GradientText>\n </h1>\n <Badge variant={statusVariant(budget.status)}>{humanize(budget.status)}</Badge>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">\n {budget.department} &middot; {budget.period}\n </p>\n </div>\n </div>\n <Button size=\"sm\" onClick={openEdit}>\n <Edit className=\"mr-2 h-4 w-4\" />\n Edit Budget\n </Button>\n </div>\n\n <PagePurpose>\n Drill into a single budget to see exactly how it is being consumed: what was allocated, what\n has been spent, what remains, and every transaction charged against it. Use it to catch\n overruns early and decide whether to reallocate, cut spend or top up.\n </PagePurpose>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Allocated</p>\n <p className=\"text-2xl font-bold tabular-nums\">${budget.allocated.toLocaleString()}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Spent</p>\n <p className=\"text-2xl font-bold tabular-nums\">${budget.spent.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">{utilizationPct}% utilized</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Remaining</p>\n <p\n className={`text-2xl font-bold ${budget.remaining < 0 ? 'text-status-error-text' : 'text-status-success-text'}`}\n >\n ${budget.remaining.toLocaleString()}\n </p>\n </CardContent>\n </Card>\n </div>\n\n <EmphasisPanel>\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Budget Utilization</CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <div className=\"h-4 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className={`h-full rounded-full transition-all ${budget.status === 'OVER_BUDGET' ? 'bg-status-error-bg' : 'bg-action-primary-bg'}`}\n style={{ width: `${Math.min(utilizationPct, 100)}%` }}\n />\n </div>\n <p className=\"text-sm text-text-secondary mt-2\">\n {utilizationPct}% of ${budget.allocated.toLocaleString()} allocated budget consumed\n </p>\n </CardContent>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle>Related Transactions</CardTitle>\n <CardDescription>Transactions in {budget.category} category</CardDescription>\n </CardHeader>\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\">ID</th>\n <th className=\"text-left p-3 font-medium\">Description</th>\n <th className=\"text-right p-3 font-medium\">Amount</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Date</th>\n </tr>\n </thead>\n <tbody>\n {relatedTxns.map((txn) => (\n <tr\n key={txn.id}\n className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\"\n onClick={() => navigate('/transactions/' + txn.id)}\n >\n <td className=\"p-3 font-mono text-xs\">{txn.id}</td>\n <td className=\"p-3 truncate max-w-xs\">{txn.description}</td>\n <td className=\"p-3 text-right font-medium\">\n ${Math.abs(txn.amount).toLocaleString()}\n </td>\n <td className=\"p-3\">\n <Badge variant=\"outline\">{txn.status}</Badge>\n </td>\n <td className=\"p-3 text-xs\">{new Date(txn.date).toLocaleDateString()}</td>\n </tr>\n ))}\n </tbody>\n </table>\n {relatedTxns.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No related transactions\"\n description={`No spend has been charged to the ${budget.category} category yet.`}\n />\n )}\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"FinanceBudgetDetailPage.js","names":[],"sources":["../../../src/assethandler/pages/FinanceBudgetDetailPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Input,\n Label,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n GradientText,\n EmphasisPanel,\n PagePurpose,\n IllustratedEmptyState,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { ArrowLeft, Edit, Loader2 } from 'lucide-react';\nimport { useParams } from 'react-router-dom';\nimport { gql } from '@apollo/client';\nimport { useMutation, useQuery } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { NotFoundState } from '../components';\nimport { notify } from '../utils/toast';\n\n// ─── Backend types ────────────────────────────────────────────────────────────\ntype AssetBudgetStatus = 'ON_TRACK' | 'OVER_BUDGET' | 'UNDER_BUDGET';\n\ninterface AssetBudget {\n id: string;\n name: string;\n category: string;\n allocated: number;\n spent: number;\n remaining: number;\n period: string;\n department: string;\n status: AssetBudgetStatus;\n createdAt: string;\n updatedAt: string;\n}\n\nconst BUDGET_QUERY = gql`\n query AssetHandlerBudget($id: ID!) {\n budget(id: $id) {\n id\n name\n category\n allocated\n spent\n remaining\n period\n department\n status\n createdAt\n updatedAt\n }\n }\n`;\n\nconst UPDATE_BUDGET_MUTATION = gql`\n mutation AssetHandlerUpdateBudget($id: ID!, $input: AssetHandlerUpdateBudgetInput!) {\n updateBudget(id: $id, input: $input) {\n id\n name\n }\n }\n`;\n\ninterface BudgetQueryResult {\n budget: AssetBudget | null;\n}\ninterface UpdateBudgetResult {\n updateBudget: { id: string; name: string };\n}\n\nconst BUDGET_STATUSES: AssetBudgetStatus[] = ['ON_TRACK', 'OVER_BUDGET', 'UNDER_BUDGET'];\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\nconst statusVariant = (status: string): 'default' | 'secondary' | 'destructive' | 'outline' =>\n status === 'OVER_BUDGET' ? 'destructive' : status === 'UNDER_BUDGET' ? 'secondary' : 'default';\n\nexport function FinanceBudgetDetailPage() {\n const navigate = useAssetHandlerNavigate();\n const { budgetId } = useParams<{ budgetId: string }>();\n const { transactions } = useAssetHandlerStore();\n\n const { data, loading, refetch } = useQuery<BudgetQueryResult>(BUDGET_QUERY, {\n variables: { id: budgetId ?? '' },\n skip: !budgetId,\n fetchPolicy: 'cache-and-network',\n });\n\n const budget = data?.budget ?? null;\n\n const [editOpen, setEditOpen] = useState(false);\n const [form, setForm] = useState({\n name: '',\n category: '',\n department: '',\n period: '',\n allocated: '',\n spent: '',\n status: 'ON_TRACK' as AssetBudgetStatus,\n });\n\n const openEdit = () => {\n if (!budget) return;\n setForm({\n name: budget.name,\n category: budget.category,\n department: budget.department,\n period: budget.period,\n allocated: String(budget.allocated),\n spent: String(budget.spent),\n status: budget.status,\n });\n setEditOpen(true);\n };\n\n const [updateBudget, { loading: saving }] = useMutation<UpdateBudgetResult>(\n UPDATE_BUDGET_MUTATION,\n {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: () => {\n notify.success('Budget updated', 'Your changes have been saved.');\n setEditOpen(false);\n void refetch();\n },\n onError: (error) => notify.error('Could not update budget', error.message),\n }\n );\n\n const handleSave = () => {\n if (!budgetId) return;\n const parsedAllocated = Number(form.allocated);\n const parsedSpent = Number(form.spent);\n if (\n !form.name.trim() ||\n !form.category.trim() ||\n !form.department.trim() ||\n !form.period.trim()\n ) {\n notify.warning('Missing details', 'Name, category, department and period are required.');\n return;\n }\n if (!Number.isFinite(parsedAllocated) || !Number.isFinite(parsedSpent)) {\n notify.warning('Invalid numbers', 'Allocated and spent must be numeric.');\n return;\n }\n void updateBudget({\n variables: {\n id: budgetId,\n input: {\n name: form.name.trim(),\n category: form.category.trim(),\n department: form.department.trim(),\n period: form.period.trim(),\n allocated: parsedAllocated,\n spent: parsedSpent,\n status: form.status,\n },\n },\n });\n };\n\n if (loading && !budget) {\n return (\n <div className=\"flex min-h-[320px] items-center justify-center p-6\">\n <Loader2 className=\"h-8 w-8 animate-spin text-primary\" />\n </div>\n );\n }\n\n if (!budget) {\n return (\n <NotFoundState\n entityLabel=\"Budget\"\n onBack={() => navigate('/finance/finance-hub')}\n backLabel=\"Back to finance\"\n />\n );\n }\n\n const relatedTxns = transactions.filter((t) => t.category === budget.category);\n const utilizationPct = budget.allocated ? Math.round((budget.spent / budget.allocated) * 100) : 0;\n\n return (\n <div className=\"space-y-6 p-6\">\n <ResponsiveDialog open={editOpen} onOpenChange={setEditOpen}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>Edit Budget</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Update the allocation and status for this budget.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Name *</Label>\n <Input\n value={form.name}\n onChange={(e) => setForm((p) => ({ ...p, name: e.target.value }))}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Category *</Label>\n <Input\n value={form.category}\n onChange={(e) => setForm((p) => ({ ...p, category: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Department *</Label>\n <Input\n value={form.department}\n onChange={(e) => setForm((p) => ({ ...p, department: e.target.value }))}\n />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Period *</Label>\n <Input\n value={form.period}\n onChange={(e) => setForm((p) => ({ ...p, period: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select\n value={form.status}\n onValueChange={(v) => setForm((p) => ({ ...p, status: v as AssetBudgetStatus }))}\n >\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {BUDGET_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Allocated *</Label>\n <Input\n type=\"number\"\n value={form.allocated}\n onChange={(e) => setForm((p) => ({ ...p, allocated: e.target.value }))}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Spent *</Label>\n <Input\n type=\"number\"\n value={form.spent}\n onChange={(e) => setForm((p) => ({ ...p, spent: e.target.value }))}\n />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => setEditOpen(false)} disabled={saving}>\n Cancel\n </Button>\n <Button onClick={handleSave} disabled={saving}>\n {saving ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {saving ? 'Saving…' : 'Save Changes'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-4\">\n <Button variant=\"ghost\" size=\"icon\" onClick={() => navigate('/finance/finance-hub')}>\n <ArrowLeft className=\"h-4 w-4\" />\n </Button>\n <div>\n <div className=\"flex items-center gap-3\">\n <h1 className=\"text-2xl font-bold\">\n <GradientText>{budget.name}</GradientText>\n </h1>\n <Badge variant={statusVariant(budget.status)}>{humanize(budget.status)}</Badge>\n </div>\n <p className=\"text-sm text-text-secondary mt-1\">\n {budget.department} &middot; {budget.period}\n </p>\n </div>\n </div>\n <Button size=\"sm\" onClick={openEdit}>\n <Edit className=\"mr-2 h-4 w-4\" />\n Edit Budget\n </Button>\n </div>\n\n <PagePurpose>\n Drill into a single budget to see exactly how it is being consumed: what was allocated, what\n has been spent, what remains, and every transaction charged against it. Use it to catch\n overruns early and decide whether to reallocate, cut spend or top up.\n </PagePurpose>\n\n <div className=\"grid gap-4 md:grid-cols-3\">\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Allocated</p>\n <p className=\"text-2xl font-bold tabular-nums\">${budget.allocated.toLocaleString()}</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Spent</p>\n <p className=\"text-2xl font-bold tabular-nums\">${budget.spent.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">{utilizationPct}% utilized</p>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <p className=\"text-sm text-text-secondary\">Remaining</p>\n <p\n className={`text-2xl font-bold ${budget.remaining < 0 ? 'text-status-error-text' : 'text-status-success-text'}`}\n >\n ${budget.remaining.toLocaleString()}\n </p>\n </CardContent>\n </Card>\n </div>\n\n <EmphasisPanel>\n <CardHeader className=\"px-0 pt-0\">\n <CardTitle>Budget Utilization</CardTitle>\n </CardHeader>\n <CardContent className=\"px-0 pb-0\">\n <div className=\"h-4 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className={`h-full rounded-full transition-all ${budget.status === 'OVER_BUDGET' ? 'bg-status-error-bg' : 'bg-action-primary-bg'}`}\n style={{ width: `${Math.min(utilizationPct, 100)}%` }}\n />\n </div>\n <p className=\"text-sm text-text-secondary mt-2\">\n {utilizationPct}% of ${budget.allocated.toLocaleString()} allocated budget consumed\n </p>\n </CardContent>\n </EmphasisPanel>\n\n <Card>\n <CardHeader>\n <CardTitle>Related Transactions</CardTitle>\n <CardDescription>Transactions in {budget.category} category</CardDescription>\n </CardHeader>\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\">ID</th>\n <th className=\"text-left p-3 font-medium\">Description</th>\n <th className=\"text-right p-3 font-medium\">Amount</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Date</th>\n </tr>\n </thead>\n <tbody>\n {relatedTxns.map((txn) => (\n <tr\n key={txn.id}\n className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\"\n onClick={() => navigate('/transactions/' + txn.id)}\n >\n <td className=\"p-3 font-mono text-xs\">{txn.id}</td>\n <td className=\"p-3 truncate max-w-xs\">{txn.description}</td>\n <td className=\"p-3 text-right font-medium\">\n ${Math.abs(txn.amount).toLocaleString()}\n </td>\n <td className=\"p-3\">\n <Badge variant=\"outline\">{txn.status}</Badge>\n </td>\n <td className=\"p-3 text-xs\">{new Date(txn.date).toLocaleDateString()}</td>\n </tr>\n ))}\n </tbody>\n </table>\n {relatedTxns.length === 0 && (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No related transactions\"\n description={`No spend has been charged to the ${budget.category} category yet.`}\n />\n )}\n </div>\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -16,14 +16,14 @@ var G = u`
16
16
  }
17
17
  }
18
18
  `, K = u`
19
- mutation AssetHandlerCreateBudget($input: CreateBudgetInput!) {
19
+ mutation AssetHandlerCreateBudget($input: AssetHandlerCreateBudgetInput!) {
20
20
  createBudget(input: $input) {
21
21
  id
22
22
  name
23
23
  }
24
24
  }
25
25
  `, q = u`
26
- mutation AssetHandlerCreateInvoice($input: CreateInvoiceInput!) {
26
+ mutation AssetHandlerCreateInvoice($input: AssetHandlerCreateInvoiceInput!) {
27
27
  createInvoice(input: $input) {
28
28
  id
29
29
  number
@@ -1 +1 @@
1
- {"version":3,"file":"FinanceFinanceHubPage.js","names":[],"sources":["../../../src/assethandler/pages/FinanceFinanceHubPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n GradientText,\n CTAOverflowMenu,\n EmphasisPanel,\n PagePurpose,\n NextSteps,\n IllustratedEmptyState,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { DollarSign, TrendingDown, Receipt, CreditCard, Download, Loader2 } from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\n\n// ─── Mutations ────────────────────────────────────────────────────────────────\nconst CREATE_TRANSACTION_MUTATION = gql`\n mutation AssetHandlerCreateTransaction($input: CreateTransactionInput!) {\n createTransaction(input: $input) {\n id\n description\n }\n }\n`;\n\nconst CREATE_BUDGET_MUTATION = gql`\n mutation AssetHandlerCreateBudget($input: CreateBudgetInput!) {\n createBudget(input: $input) {\n id\n name\n }\n }\n`;\n\nconst CREATE_INVOICE_MUTATION = gql`\n mutation AssetHandlerCreateInvoice($input: CreateInvoiceInput!) {\n createInvoice(input: $input) {\n id\n number\n }\n }\n`;\n\ninterface CreateTransactionResult {\n createTransaction: { id: string; description: string };\n}\ninterface CreateBudgetResult {\n createBudget: { id: string; name: string };\n}\ninterface CreateInvoiceResult {\n createInvoice: { id: string; number: string };\n}\n\nconst TRANSACTION_TYPES = ['PURCHASE', 'LEASE', 'DISPOSAL', 'TRANSFER', 'MAINTENANCE'] as const;\nconst TRANSACTION_STATUSES = ['PENDING', 'APPROVED', 'COMPLETED', 'REJECTED'] as const;\nconst BUDGET_STATUSES = ['ON_TRACK', 'OVER_BUDGET', 'UNDER_BUDGET'] as const;\nconst INVOICE_STATUSES = ['DRAFT', 'SENT', 'PAID', 'OVERDUE', 'CANCELLED'] as const;\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\n// ─── New Transaction dialog ───────────────────────────────────────────────────\nfunction NewTransactionDialog({\n open,\n onOpenChange,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const [type, setType] = useState<(typeof TRANSACTION_TYPES)[number]>('PURCHASE');\n const [status, setStatus] = useState<(typeof TRANSACTION_STATUSES)[number]>('PENDING');\n const [amount, setAmount] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [category, setCategory] = useState('');\n const [description, setDescription] = useState('');\n const [vendor, setVendor] = useState('');\n const [department, setDepartment] = useState('');\n\n const reset = () => {\n setType('PURCHASE');\n setStatus('PENDING');\n setAmount('');\n setCurrency('USD');\n setCategory('');\n setDescription('');\n setVendor('');\n setDepartment('');\n };\n\n const [createTransaction, { loading }] = useMutation<CreateTransactionResult>(\n CREATE_TRANSACTION_MUTATION,\n {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: (data) => {\n notify.success(\n 'Transaction created',\n `${data.createTransaction.description} was recorded.`\n );\n reset();\n onOpenChange(false);\n },\n onError: (error) => notify.error('Could not create transaction', error.message),\n }\n );\n\n const handleSubmit = () => {\n const parsedAmount = Number(amount);\n if (!Number.isFinite(parsedAmount) || amount.trim() === '') {\n notify.warning('Invalid amount', 'Enter a numeric amount for the transaction.');\n return;\n }\n if (!category.trim() || !description.trim()) {\n notify.warning('Missing details', 'Category and description are required.');\n return;\n }\n void createTransaction({\n variables: {\n input: {\n amount: parsedAmount,\n category: category.trim(),\n currency: currency.trim() || 'USD',\n description: description.trim(),\n type,\n status,\n vendor: vendor.trim() || null,\n department: department.trim() || null,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New Transaction</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Record a financial movement against your assets.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Type</Label>\n <Select value={type} onValueChange={(v) => setType(v as typeof type)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TRANSACTION_TYPES.map((t) => (\n <SelectItem key={t} value={t}>\n {humanize(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select value={status} onValueChange={(v) => setStatus(v as typeof status)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TRANSACTION_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Amount *</Label>\n <Input\n type=\"number\"\n placeholder=\"e.g., 1500\"\n value={amount}\n onChange={(e) => setAmount(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Currency</Label>\n <Input value={currency} onChange={(e) => setCurrency(e.target.value)} />\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>Category *</Label>\n <Input\n placeholder=\"e.g., it_hardware\"\n value={category}\n onChange={(e) => setCategory(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Description *</Label>\n <Textarea\n placeholder=\"What is this transaction for?\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Vendor</Label>\n <Input value={vendor} onChange={(e) => setVendor(e.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label>Department</Label>\n <Input value={department} onChange={(e) => setDepartment(e.target.value)} />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {loading ? 'Creating…' : 'Create Transaction'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n// ─── New Budget dialog ────────────────────────────────────────────────────────\nfunction NewBudgetDialog({\n open,\n onOpenChange,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const [name, setName] = useState('');\n const [category, setCategory] = useState('');\n const [department, setDepartment] = useState('');\n const [period, setPeriod] = useState('');\n const [allocated, setAllocated] = useState('');\n const [spent, setSpent] = useState('0');\n const [status, setStatus] = useState<(typeof BUDGET_STATUSES)[number]>('ON_TRACK');\n\n const reset = () => {\n setName('');\n setCategory('');\n setDepartment('');\n setPeriod('');\n setAllocated('');\n setSpent('0');\n setStatus('ON_TRACK');\n };\n\n const [createBudget, { loading }] = useMutation<CreateBudgetResult>(CREATE_BUDGET_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: (data) => {\n notify.success('Budget created', `${data.createBudget.name} is now being tracked.`);\n reset();\n onOpenChange(false);\n },\n onError: (error) => notify.error('Could not create budget', error.message),\n });\n\n const handleSubmit = () => {\n const parsedAllocated = Number(allocated);\n const parsedSpent = Number(spent);\n if (!name.trim() || !category.trim() || !department.trim() || !period.trim()) {\n notify.warning('Missing details', 'Name, category, department and period are required.');\n return;\n }\n if (!Number.isFinite(parsedAllocated) || allocated.trim() === '') {\n notify.warning('Invalid allocation', 'Enter a numeric allocated amount.');\n return;\n }\n void createBudget({\n variables: {\n input: {\n allocated: parsedAllocated,\n category: category.trim(),\n department: department.trim(),\n name: name.trim(),\n period: period.trim(),\n spent: Number.isFinite(parsedSpent) ? parsedSpent : 0,\n status,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New Budget</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Set an allocation to track departmental asset spend.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Name *</Label>\n <Input\n placeholder=\"e.g., IT Hardware Q1\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Category *</Label>\n <Input value={category} onChange={(e) => setCategory(e.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label>Department *</Label>\n <Input value={department} onChange={(e) => setDepartment(e.target.value)} />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Period *</Label>\n <Input\n placeholder=\"e.g., Q1 2026\"\n value={period}\n onChange={(e) => setPeriod(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select value={status} onValueChange={(v) => setStatus(v as typeof status)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {BUDGET_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Allocated *</Label>\n <Input\n type=\"number\"\n placeholder=\"e.g., 50000\"\n value={allocated}\n onChange={(e) => setAllocated(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Spent</Label>\n <Input type=\"number\" value={spent} onChange={(e) => setSpent(e.target.value)} />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {loading ? 'Creating…' : 'Create Budget'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n// ─── New Invoice dialog ───────────────────────────────────────────────────────\nfunction NewInvoiceDialog({\n open,\n onOpenChange,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const [number, setNumber] = useState('');\n const [vendor, setVendor] = useState('');\n const [amount, setAmount] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [issueDate, setIssueDate] = useState('');\n const [dueDate, setDueDate] = useState('');\n const [relatedPO, setRelatedPO] = useState('');\n const [status, setStatus] = useState<(typeof INVOICE_STATUSES)[number]>('DRAFT');\n\n const reset = () => {\n setNumber('');\n setVendor('');\n setAmount('');\n setCurrency('USD');\n setIssueDate('');\n setDueDate('');\n setRelatedPO('');\n setStatus('DRAFT');\n };\n\n const [createInvoice, { loading }] = useMutation<CreateInvoiceResult>(CREATE_INVOICE_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: (data) => {\n notify.success('Invoice created', `Invoice ${data.createInvoice.number} was added.`);\n reset();\n onOpenChange(false);\n },\n onError: (error) => notify.error('Could not create invoice', error.message),\n });\n\n const handleSubmit = () => {\n const parsedAmount = Number(amount);\n if (!number.trim() || !vendor.trim()) {\n notify.warning('Missing details', 'Invoice number and vendor are required.');\n return;\n }\n if (!Number.isFinite(parsedAmount) || amount.trim() === '') {\n notify.warning('Invalid amount', 'Enter a numeric invoice amount.');\n return;\n }\n if (!issueDate || !dueDate) {\n notify.warning('Missing dates', 'Issue date and due date are required.');\n return;\n }\n void createInvoice({\n variables: {\n input: {\n amount: parsedAmount,\n currency: currency.trim() || 'USD',\n dueDate: new Date(dueDate).toISOString(),\n issueDate: new Date(issueDate).toISOString(),\n number: number.trim(),\n relatedPO: relatedPO.trim() || null,\n status,\n vendor: vendor.trim(),\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New Invoice</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Log a vendor invoice for an asset purchase or service.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Invoice Number *</Label>\n <Input\n placeholder=\"e.g., INV-2026-001\"\n value={number}\n onChange={(e) => setNumber(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Vendor *</Label>\n <Input value={vendor} onChange={(e) => setVendor(e.target.value)} />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Amount *</Label>\n <Input\n type=\"number\"\n placeholder=\"e.g., 12000\"\n value={amount}\n onChange={(e) => setAmount(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Currency</Label>\n <Input value={currency} onChange={(e) => setCurrency(e.target.value)} />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Issue Date *</Label>\n <Input type=\"date\" value={issueDate} onChange={(e) => setIssueDate(e.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label>Due Date *</Label>\n <Input type=\"date\" value={dueDate} onChange={(e) => setDueDate(e.target.value)} />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Related PO</Label>\n <Input value={relatedPO} onChange={(e) => setRelatedPO(e.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select value={status} onValueChange={(v) => setStatus(v as typeof status)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {INVOICE_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {loading ? 'Creating…' : 'Create Invoice'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function FinanceFinanceHubPage() {\n const navigate = useAssetHandlerNavigate();\n const { transactions, budgets, invoices } = useAssetHandlerStore();\n\n const [txnDialogOpen, setTxnDialogOpen] = useState(false);\n const [budgetDialogOpen, setBudgetDialogOpen] = useState(false);\n const [invoiceDialogOpen, setInvoiceDialogOpen] = useState(false);\n\n const totalSpend = transactions.filter((t) => t.amount > 0).reduce((s, t) => s + t.amount, 0);\n const pendingTxns = transactions.filter((t) => t.status === 'pending');\n const overBudget = budgets.filter((b) => b.status === 'over_budget');\n const overdueInvoices = invoices.filter((i) => i.status === 'overdue');\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>Finance Hub</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Financial management for IT assets</p>\n </div>\n <CTAOverflowMenu\n primary={{ label: 'New Transaction', onSelect: () => setTxnDialogOpen(true) }}\n actions={[\n { label: 'New Budget', onSelect: () => setBudgetDialogOpen(true) },\n { label: 'New Invoice', onSelect: () => setInvoiceDialogOpen(true) },\n { label: 'Export', onSelect: () => {}, icon: <Download className=\"h-4 w-4\" /> },\n ]}\n />\n </div>\n\n <NewTransactionDialog open={txnDialogOpen} onOpenChange={setTxnDialogOpen} />\n <NewBudgetDialog open={budgetDialogOpen} onOpenChange={setBudgetDialogOpen} />\n <NewInvoiceDialog open={invoiceDialogOpen} onOpenChange={setInvoiceDialogOpen} />\n\n <PagePurpose>\n The money side of your asset estate: track spend, keep departmental budgets on course, and\n stay on top of vendor invoices. Use this hub to spot over-budget areas and overdue invoices\n early — so asset costs stay predictable and nothing slips past its due date.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-finance-hub\"\n steps={[\n {\n id: 'transactions',\n label: 'Review recent transactions',\n description: 'Check spend and approve anything still pending.',\n onClick: () => navigate('/transactions/transaction-list'),\n },\n {\n id: 'budgets',\n label: 'Review reporting dashboard',\n description: 'See budget health and spend trends across departments.',\n onClick: () => navigate('/reports/reports-dashboard'),\n },\n {\n id: 'reports',\n label: 'Build a finance report',\n description: 'Turn spend and budget data into a shareable report.',\n onClick: () => navigate('/reports/reports-dashboard'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <EmphasisPanel>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <DollarSign className=\"h-4 w-4\" />\n Total Spend\n </div>\n <p className=\"text-2xl font-bold mt-1 tabular-nums\">${totalSpend.toLocaleString()}</p>\n </EmphasisPanel>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <CreditCard className=\"h-4 w-4\" />\n Pending\n </div>\n <p className=\"text-2xl font-bold mt-1 text-status-info-text\">{pendingTxns.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 <TrendingDown className=\"h-4 w-4\" />\n Over Budget\n </div>\n <p className=\"text-2xl font-bold mt-1 text-status-error-text\">{overBudget.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 <Receipt className=\"h-4 w-4\" />\n Overdue Invoices\n </div>\n <p className=\"text-2xl font-bold mt-1 text-status-warning-text\">\n {overdueInvoices.length}\n </p>\n </CardContent>\n </Card>\n </div>\n\n <Tabs defaultValue=\"transactions\">\n <TabsList>\n <TabsTrigger value=\"transactions\">Transactions</TabsTrigger>\n <TabsTrigger value=\"budgets\">Budgets</TabsTrigger>\n <TabsTrigger value=\"invoices\">Invoices</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"transactions\" className=\"mt-4\">\n {transactions.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No transactions yet\"\n description=\"Asset-related spend and reimbursements will appear here as they are recorded.\"\n />\n ) : (\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\">ID</th>\n <th className=\"text-left p-3 font-medium\">Type</th>\n <th className=\"text-left p-3 font-medium\">Description</th>\n <th className=\"text-left p-3 font-medium\">Department</th>\n <th className=\"text-right p-3 font-medium\">Amount</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Date</th>\n </tr>\n </thead>\n <tbody>\n {transactions.map((txn) => (\n <tr\n key={txn.id}\n className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\"\n onClick={() => navigate('/transactions/' + txn.id)}\n >\n <td className=\"p-3 font-mono text-xs\">{txn.id}</td>\n <td className=\"p-3 capitalize\">{txn.type}</td>\n <td className=\"p-3 truncate max-w-xs\">{txn.description}</td>\n <td className=\"p-3 text-xs\">{txn.department}</td>\n <td\n className={`p-3 text-right font-medium ${txn.amount < 0 ? 'text-status-error-text' : ''}`}\n >\n ${Math.abs(txn.amount).toLocaleString()}\n </td>\n <td className=\"p-3\">\n <Badge variant=\"outline\">{txn.status}</Badge>\n </td>\n <td className=\"p-3 text-xs\">{new Date(txn.date).toLocaleDateString()}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n\n <TabsContent value=\"budgets\" className=\"mt-4\">\n {budgets.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No budgets defined\"\n description=\"Create departmental budgets to track allocated vs. actual asset spend.\"\n />\n ) : (\n <div className=\"grid gap-4 md:grid-cols-2\">\n {budgets.map((budget) => (\n <Card\n key={budget.id}\n className=\"cursor-pointer\"\n onClick={() => navigate('/finance/budgets/' + budget.id)}\n >\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{budget.name}</CardTitle>\n <Badge\n variant={\n budget.status === 'over_budget'\n ? 'destructive'\n : budget.status === 'under_budget'\n ? 'secondary'\n : 'default'\n }\n >\n {budget.status.replace('_', ' ')}\n </Badge>\n </div>\n <CardDescription>\n {budget.department} &middot; {budget.period}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Allocated</span>\n <span className=\"font-medium\">${budget.allocated.toLocaleString()}</span>\n </div>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Spent</span>\n <span className=\"font-medium\">${budget.spent.toLocaleString()}</span>\n </div>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Remaining</span>\n <span\n className={`font-medium ${budget.remaining < 0 ? 'text-status-error-text' : 'text-status-success-text'}`}\n >\n ${budget.remaining.toLocaleString()}\n </span>\n </div>\n <div className=\"h-2 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className={`h-full rounded-full ${budget.status === 'over_budget' ? 'bg-status-error-bg' : 'bg-action-primary-bg'}`}\n style={{\n width: `${Math.min((budget.spent / budget.allocated) * 100, 100)}%`,\n }}\n />\n </div>\n <p className=\"text-xs text-text-secondary text-right\">\n {Math.round((budget.spent / budget.allocated) * 100)}% utilized\n </p>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </TabsContent>\n\n <TabsContent value=\"invoices\" className=\"mt-4\">\n {invoices.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title=\"No invoices\"\n description=\"Vendor invoices for asset purchases and services will be listed here.\"\n />\n ) : (\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\">Invoice #</th>\n <th className=\"text-left p-3 font-medium\">Vendor</th>\n <th className=\"text-right p-3 font-medium\">Amount</th>\n <th className=\"text-left p-3 font-medium\">Issue Date</th>\n <th className=\"text-left p-3 font-medium\">Due Date</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n </tr>\n </thead>\n <tbody>\n {invoices.map((inv) => (\n <tr\n key={inv.id}\n className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\"\n onClick={() => navigate('/finance/invoices/' + inv.id)}\n >\n <td className=\"p-3 font-mono text-xs\">{inv.number}</td>\n <td className=\"p-3\">{inv.vendor}</td>\n <td className=\"p-3 text-right font-medium\">\n ${inv.amount.toLocaleString()}\n </td>\n <td className=\"p-3 text-xs\">{inv.issueDate}</td>\n <td className=\"p-3 text-xs\">{inv.dueDate}</td>\n <td className=\"p-3\">\n <Badge\n variant={\n inv.status === 'overdue'\n ? 'destructive'\n : inv.status === 'paid'\n ? 'default'\n : 'outline'\n }\n >\n {inv.status}\n </Badge>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AA0CA,IAAM,IAA8B,CAAG;;;;;;;GASjC,IAAyB,CAAG;;;;;;;GAS5B,IAA0B,CAAG;;;;;;;GAmB7B,IAAoB;CAAC;CAAY;CAAS;CAAY;CAAY;CAAc,EAChF,IAAuB;CAAC;CAAW;CAAY;CAAa;CAAW,EACvE,IAAkB;CAAC;CAAY;CAAe;CAAe,EAC7D,IAAmB;CAAC;CAAS;CAAQ;CAAQ;CAAW;CAAY,EAEpE,KAAY,MAChB,EACG,aAAa,CACb,QAAQ,MAAM,IAAI,CAClB,QAAQ,QAAQ,MAAM,EAAE,aAAa,CAAC;AAG3C,SAAS,EAAqB,EAC5B,SACA,mBAIC;CACD,IAAM,CAAC,GAAM,KAAW,EAA6C,WAAW,EAC1E,CAAC,GAAQ,KAAa,EAAgD,UAAU,EAChF,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,CAAC,GAAU,KAAe,EAAS,MAAM,EACzC,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAa,KAAkB,EAAS,GAAG,EAC5C,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,CAAC,GAAY,KAAiB,EAAS,GAAG,EAE1C,UAAc;AAQlB,EAPA,EAAQ,WAAW,EACnB,EAAU,UAAU,EACpB,EAAU,GAAG,EACb,EAAY,MAAM,EAClB,EAAY,GAAG,EACf,EAAe,GAAG,EAClB,EAAU,GAAG,EACb,EAAc,GAAG;IAGb,CAAC,GAAmB,EAAE,gBAAa,EACvC,GACA;EACE,gBAAgB,CAAC,wBAAwB;EACzC,cAAc,MAAS;AAMrB,GALA,EAAO,QACL,uBACA,GAAG,EAAK,kBAAkB,YAAY,gBACvC,EACD,GAAO,EACP,EAAa,GAAM;;EAErB,UAAU,MAAU,EAAO,MAAM,gCAAgC,EAAM,QAAQ;EAChF,CACF;AA4BD,QACE,kBAAC,GAAD;EAAwB;EAAoB;YAC1C,kBAAC,GAAD,EAAA,UAAA;GACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAuB,mBAAuC,CAAA,EAC9D,kBAAC,GAAD,EAAA,UAA6B,oDAEC,CAAA,CACP,EAAA,CAAA;GACzB,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,QAAY,CAAA,EACnB,kBAAC,GAAD;QAAQ,OAAO;QAAM,gBAAgB,MAAM,EAAQ,EAAiB;kBAApE,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAe,CAAA,EACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAkB,KAAK,MACtB,kBAAC,GAAD;SAAoB,OAAO;mBACxB,EAAS,EAAE;SACD,EAFI,EAEJ,CACb,EACY,CAAA,CACT;UACL;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,UAAc,CAAA,EACrB,kBAAC,GAAD;QAAQ,OAAO;QAAQ,gBAAgB,MAAM,EAAU,EAAmB;kBAA1E,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAe,CAAA,EACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAqB,KAAK,MACzB,kBAAC,GAAD;SAAoB,OAAO;mBACxB,EAAS,EAAE;SACD,EAFI,EAEJ,CACb,EACY,CAAA,CACT;UACL;SACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,YAAgB,CAAA,EACvB,kBAAC,GAAD;QACE,MAAK;QACL,aAAY;QACZ,OAAO;QACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;QAC1C,CAAA,CACE;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,YAAgB,CAAA,EACvB,kBAAC,GAAD;QAAO,OAAO;QAAU,WAAW,MAAM,EAAY,EAAE,OAAO,MAAM;QAAI,CAAA,CACpE;SACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,cAAkB,CAAA,EACzB,kBAAC,GAAD;OACE,aAAY;OACZ,OAAO;OACP,WAAW,MAAM,EAAY,EAAE,OAAO,MAAM;OAC5C,CAAA,CACE;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,iBAAqB,CAAA,EAC5B,kBAAC,GAAD;OACE,aAAY;OACZ,OAAO;OACP,WAAW,MAAM,EAAe,EAAE,OAAO,MAAM;OAC/C,MAAM;OACN,CAAA,CACE;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,UAAc,CAAA,EACrB,kBAAC,GAAD;QAAO,OAAO;QAAQ,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;QAAI,CAAA,CAChE;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,cAAkB,CAAA,EACzB,kBAAC,GAAD;QAAO,OAAO;QAAY,WAAW,MAAM,EAAc,EAAE,OAAO,MAAM;QAAI,CAAA,CACxE;SACF;;KACF;;GACN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;IAAQ,SAAQ;IAAU,eAAe,EAAa,GAAM;IAAE,UAAU;cAAS;IAExE,CAAA,EACT,kBAAC,GAAD;IAAQ,eAnHW;KACzB,IAAM,IAAe,OAAO,EAAO;AACnC,SAAI,CAAC,OAAO,SAAS,EAAa,IAAI,EAAO,MAAM,KAAK,IAAI;AAC1D,QAAO,QAAQ,kBAAkB,8CAA8C;AAC/E;;AAEF,SAAI,CAAC,EAAS,MAAM,IAAI,CAAC,EAAY,MAAM,EAAE;AAC3C,QAAO,QAAQ,mBAAmB,yCAAyC;AAC3E;;AAEG,OAAkB,EACrB,WAAW,EACT,OAAO;MACL,QAAQ;MACR,UAAU,EAAS,MAAM;MACzB,UAAU,EAAS,MAAM,IAAI;MAC7B,aAAa,EAAY,MAAM;MAC/B;MACA;MACA,QAAQ,EAAO,MAAM,IAAI;MACzB,YAAY,EAAW,MAAM,IAAI;MAClC,EACF,EACF,CAAC;;IA4FmC,UAAU;cAAzC,CACG,IAAU,kBAAC,GAAD,EAAS,WAAU,6BAA8B,CAAA,GAAG,MAC9D,IAAU,cAAc,qBAClB;MACc,EAAA,CAAA;GACD,EAAA,CAAA;EACT,CAAA;;AAKvB,SAAS,GAAgB,EACvB,SACA,mBAIC;CACD,IAAM,CAAC,GAAM,KAAW,EAAS,GAAG,EAC9B,CAAC,GAAU,KAAe,EAAS,GAAG,EACtC,CAAC,GAAY,KAAiB,EAAS,GAAG,EAC1C,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,CAAC,GAAW,KAAgB,EAAS,GAAG,EACxC,CAAC,GAAO,KAAY,EAAS,IAAI,EACjC,CAAC,GAAQ,KAAa,EAA2C,WAAW,EAE5E,UAAc;AAOlB,EANA,EAAQ,GAAG,EACX,EAAY,GAAG,EACf,EAAc,GAAG,EACjB,EAAU,GAAG,EACb,EAAa,GAAG,EAChB,EAAS,IAAI,EACb,EAAU,WAAW;IAGjB,CAAC,GAAc,EAAE,gBAAa,EAAgC,GAAwB;EAC1F,gBAAgB,CAAC,wBAAwB;EACzC,cAAc,MAAS;AAGrB,GAFA,EAAO,QAAQ,kBAAkB,GAAG,EAAK,aAAa,KAAK,wBAAwB,EACnF,GAAO,EACP,EAAa,GAAM;;EAErB,UAAU,MAAU,EAAO,MAAM,2BAA2B,EAAM,QAAQ;EAC3E,CAAC;AA4BF,QACE,kBAAC,GAAD;EAAwB;EAAoB;YAC1C,kBAAC,GAAD,EAAA,UAAA;GACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAuB,cAAkC,CAAA,EACzD,kBAAC,GAAD,EAAA,UAA6B,wDAEC,CAAA,CACP,EAAA,CAAA;GACzB,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,UAAc,CAAA,EACrB,kBAAC,GAAD;OACE,aAAY;OACZ,OAAO;OACP,WAAW,MAAM,EAAQ,EAAE,OAAO,MAAM;OACxC,CAAA,CACE;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,cAAkB,CAAA,EACzB,kBAAC,GAAD;QAAO,OAAO;QAAU,WAAW,MAAM,EAAY,EAAE,OAAO,MAAM;QAAI,CAAA,CACpE;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,gBAAoB,CAAA,EAC3B,kBAAC,GAAD;QAAO,OAAO;QAAY,WAAW,MAAM,EAAc,EAAE,OAAO,MAAM;QAAI,CAAA,CACxE;SACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,YAAgB,CAAA,EACvB,kBAAC,GAAD;QACE,aAAY;QACZ,OAAO;QACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;QAC1C,CAAA,CACE;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,UAAc,CAAA,EACrB,kBAAC,GAAD;QAAQ,OAAO;QAAQ,gBAAgB,MAAM,EAAU,EAAmB;kBAA1E,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAe,CAAA,EACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAgB,KAAK,MACpB,kBAAC,GAAD;SAAoB,OAAO;mBACxB,EAAS,EAAE;SACD,EAFI,EAEJ,CACb,EACY,CAAA,CACT;UACL;SACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,eAAmB,CAAA,EAC1B,kBAAC,GAAD;QACE,MAAK;QACL,aAAY;QACZ,OAAO;QACP,WAAW,MAAM,EAAa,EAAE,OAAO,MAAM;QAC7C,CAAA,CACE;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,SAAa,CAAA,EACpB,kBAAC,GAAD;QAAO,MAAK;QAAS,OAAO;QAAO,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;QAAI,CAAA,CAC5E;SACF;;KACF;;GACN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;IAAQ,SAAQ;IAAU,eAAe,EAAa,GAAM;IAAE,UAAU;cAAS;IAExE,CAAA,EACT,kBAAC,GAAD;IAAQ,eAnGW;KACzB,IAAM,IAAkB,OAAO,EAAU,EACnC,IAAc,OAAO,EAAM;AACjC,SAAI,CAAC,EAAK,MAAM,IAAI,CAAC,EAAS,MAAM,IAAI,CAAC,EAAW,MAAM,IAAI,CAAC,EAAO,MAAM,EAAE;AAC5E,QAAO,QAAQ,mBAAmB,sDAAsD;AACxF;;AAEF,SAAI,CAAC,OAAO,SAAS,EAAgB,IAAI,EAAU,MAAM,KAAK,IAAI;AAChE,QAAO,QAAQ,sBAAsB,oCAAoC;AACzE;;AAEG,OAAa,EAChB,WAAW,EACT,OAAO;MACL,WAAW;MACX,UAAU,EAAS,MAAM;MACzB,YAAY,EAAW,MAAM;MAC7B,MAAM,EAAK,MAAM;MACjB,QAAQ,EAAO,MAAM;MACrB,OAAO,OAAO,SAAS,EAAY,GAAG,IAAc;MACpD;MACD,EACF,EACF,CAAC;;IA4EmC,UAAU;cAAzC,CACG,IAAU,kBAAC,GAAD,EAAS,WAAU,6BAA8B,CAAA,GAAG,MAC9D,IAAU,cAAc,gBAClB;MACc,EAAA,CAAA;GACD,EAAA,CAAA;EACT,CAAA;;AAKvB,SAAS,GAAiB,EACxB,SACA,mBAIC;CACD,IAAM,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,CAAC,GAAQ,KAAa,EAAS,GAAG,EAClC,CAAC,GAAU,KAAe,EAAS,MAAM,EACzC,CAAC,GAAW,KAAgB,EAAS,GAAG,EACxC,CAAC,GAAS,KAAc,EAAS,GAAG,EACpC,CAAC,GAAW,KAAgB,EAAS,GAAG,EACxC,CAAC,GAAQ,KAAa,EAA4C,QAAQ,EAE1E,UAAc;AAQlB,EAPA,EAAU,GAAG,EACb,EAAU,GAAG,EACb,EAAU,GAAG,EACb,EAAY,MAAM,EAClB,EAAa,GAAG,EAChB,EAAW,GAAG,EACd,EAAa,GAAG,EAChB,EAAU,QAAQ;IAGd,CAAC,GAAe,EAAE,gBAAa,EAAiC,GAAyB;EAC7F,gBAAgB,CAAC,wBAAwB;EACzC,cAAc,MAAS;AAGrB,GAFA,EAAO,QAAQ,mBAAmB,WAAW,EAAK,cAAc,OAAO,aAAa,EACpF,GAAO,EACP,EAAa,GAAM;;EAErB,UAAU,MAAU,EAAO,MAAM,4BAA4B,EAAM,QAAQ;EAC5E,CAAC;AAgCF,QACE,kBAAC,GAAD;EAAwB;EAAoB;YAC1C,kBAAC,GAAD,EAAA,UAAA;GACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UAAuB,eAAmC,CAAA,EAC1D,kBAAC,GAAD,EAAA,UAA6B,0DAEC,CAAA,CACP,EAAA,CAAA;GACzB,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,oBAAwB,CAAA,EAC/B,kBAAC,GAAD;QACE,aAAY;QACZ,OAAO;QACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;QAC1C,CAAA,CACE;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,YAAgB,CAAA,EACvB,kBAAC,GAAD;QAAO,OAAO;QAAQ,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;QAAI,CAAA,CAChE;SACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,YAAgB,CAAA,EACvB,kBAAC,GAAD;QACE,MAAK;QACL,aAAY;QACZ,OAAO;QACP,WAAW,MAAM,EAAU,EAAE,OAAO,MAAM;QAC1C,CAAA,CACE;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,YAAgB,CAAA,EACvB,kBAAC,GAAD;QAAO,OAAO;QAAU,WAAW,MAAM,EAAY,EAAE,OAAO,MAAM;QAAI,CAAA,CACpE;SACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,gBAAoB,CAAA,EAC3B,kBAAC,GAAD;QAAO,MAAK;QAAO,OAAO;QAAW,WAAW,MAAM,EAAa,EAAE,OAAO,MAAM;QAAI,CAAA,CAClF;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,cAAkB,CAAA,EACzB,kBAAC,GAAD;QAAO,MAAK;QAAO,OAAO;QAAS,WAAW,MAAM,EAAW,EAAE,OAAO,MAAM;QAAI,CAAA,CAC9E;SACF;;KACN,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,cAAkB,CAAA,EACzB,kBAAC,GAAD;QAAO,OAAO;QAAW,WAAW,MAAM,EAAa,EAAE,OAAO,MAAM;QAAI,CAAA,CACtE;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAA,UAAO,UAAc,CAAA,EACrB,kBAAC,GAAD;QAAQ,OAAO;QAAQ,gBAAgB,MAAM,EAAU,EAAmB;kBAA1E,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAe,CAAA,EACD,CAAA,EAChB,kBAAC,GAAD,EAAA,UACG,EAAiB,KAAK,MACrB,kBAAC,GAAD;SAAoB,OAAO;mBACxB,EAAS,EAAE;SACD,EAFI,EAEJ,CACb,EACY,CAAA,CACT;UACL;SACF;;KACF;;GACN,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;IAAQ,SAAQ;IAAU,eAAe,EAAa,GAAM;IAAE,UAAU;cAAS;IAExE,CAAA,EACT,kBAAC,GAAD;IAAQ,eAzGW;KACzB,IAAM,IAAe,OAAO,EAAO;AACnC,SAAI,CAAC,EAAO,MAAM,IAAI,CAAC,EAAO,MAAM,EAAE;AACpC,QAAO,QAAQ,mBAAmB,0CAA0C;AAC5E;;AAEF,SAAI,CAAC,OAAO,SAAS,EAAa,IAAI,EAAO,MAAM,KAAK,IAAI;AAC1D,QAAO,QAAQ,kBAAkB,kCAAkC;AACnE;;AAEF,SAAI,CAAC,KAAa,CAAC,GAAS;AAC1B,QAAO,QAAQ,iBAAiB,wCAAwC;AACxE;;AAEG,OAAc,EACjB,WAAW,EACT,OAAO;MACL,QAAQ;MACR,UAAU,EAAS,MAAM,IAAI;MAC7B,SAAS,IAAI,KAAK,EAAQ,CAAC,aAAa;MACxC,WAAW,IAAI,KAAK,EAAU,CAAC,aAAa;MAC5C,QAAQ,EAAO,MAAM;MACrB,WAAW,EAAU,MAAM,IAAI;MAC/B;MACA,QAAQ,EAAO,MAAM;MACtB,EACF,EACF,CAAC;;IA8EmC,UAAU;cAAzC,CACG,IAAU,kBAAC,GAAD,EAAS,WAAU,6BAA8B,CAAA,GAAG,MAC9D,IAAU,cAAc,iBAClB;MACc,EAAA,CAAA;GACD,EAAA,CAAA;EACT,CAAA;;AAIvB,SAAgB,KAAwB;CACtC,IAAM,IAAW,GAAyB,EACpC,EAAE,iBAAc,YAAS,gBAAa,GAAsB,EAE5D,CAAC,GAAe,KAAoB,EAAS,GAAM,EACnD,CAAC,GAAkB,KAAuB,EAAS,GAAM,EACzD,CAAC,GAAmB,KAAwB,EAAS,GAAM,EAE3D,IAAa,EAAa,QAAQ,MAAM,EAAE,SAAS,EAAE,CAAC,QAAQ,GAAG,MAAM,IAAI,EAAE,QAAQ,EAAE,EACvF,IAAc,EAAa,QAAQ,MAAM,EAAE,WAAW,UAAU,EAChE,IAAa,EAAQ,QAAQ,MAAM,EAAE,WAAW,cAAc,EAC9D,IAAkB,EAAS,QAAQ,MAAM,EAAE,WAAW,UAAU;AAEtE,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACZ,kBAAC,GAAD,EAAA,UAAc,eAA0B,CAAA;KACrC,CAAA,EACL,kBAAC,KAAD;KAAG,WAAU;eAA8B;KAAsC,CAAA,CAC7E,EAAA,CAAA,EACN,kBAAC,GAAD;KACE,SAAS;MAAE,OAAO;MAAmB,gBAAgB,EAAiB,GAAK;MAAE;KAC7E,SAAS;MACP;OAAE,OAAO;OAAc,gBAAgB,EAAoB,GAAK;OAAE;MAClE;OAAE,OAAO;OAAe,gBAAgB,EAAqB,GAAK;OAAE;MACpE;OAAE,OAAO;OAAU,gBAAgB;OAAI,MAAM,kBAAC,GAAD,EAAU,WAAU,WAAY,CAAA;OAAE;MAChF;KACD,CAAA,CACE;;GAEN,kBAAC,GAAD;IAAsB,MAAM;IAAe,cAAc;IAAoB,CAAA;GAC7E,kBAAC,IAAD;IAAiB,MAAM;IAAkB,cAAc;IAAuB,CAAA;GAC9E,kBAAC,IAAD;IAAkB,MAAM;IAAmB,cAAc;IAAwB,CAAA;GAEjF,kBAAC,GAAD,EAAA,UAAa,uQAIC,CAAA;GAEd,kBAAC,GAAD;IACE,YAAW;IACX,OAAO;KACL;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,eAAe,EAAS,iCAAiC;MAC1D;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,eAAe,EAAS,6BAA6B;MACtD;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,eAAe,EAAS,6BAA6B;MACtD;KACF;IACD,CAAA;GAEF,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA,EAAA,cAE9B;SACN,kBAAC,KAAD;MAAG,WAAU;gBAAb,CAAoD,KAAE,EAAW,gBAAgB,CAAK;QACxE,EAAA,CAAA;KAChB,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAa,WAAU;gBAAvB,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAY,WAAU,WAAY,CAAA,EAAA,UAE9B;UACN,kBAAC,KAAD;OAAG,WAAU;iBAAiD,EAAY;OAAW,CAAA,CACzE;SACT,CAAA;KACP,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAa,WAAU;gBAAvB,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAc,WAAU,WAAY,CAAA,EAAA,cAEhC;UACN,kBAAC,KAAD;OAAG,WAAU;iBAAkD,EAAW;OAAW,CAAA,CACzE;SACT,CAAA;KACP,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;MAAa,WAAU;gBAAvB,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAS,WAAU,WAAY,CAAA,EAAA,mBAE3B;UACN,kBAAC,KAAD;OAAG,WAAU;iBACV,EAAgB;OACf,CAAA,CACQ;SACT,CAAA;KACH;;GAEN,kBAAC,GAAD;IAAM,cAAa;cAAnB;KACE,kBAAC,GAAD,EAAA,UAAA;MACE,kBAAC,GAAD;OAAa,OAAM;iBAAe;OAA0B,CAAA;MAC5D,kBAAC,GAAD;OAAa,OAAM;iBAAU;OAAqB,CAAA;MAClD,kBAAC,GAAD;OAAa,OAAM;iBAAW;OAAsB,CAAA;MAC3C,EAAA,CAAA;KAEX,kBAAC,GAAD;MAAa,OAAM;MAAe,WAAU;gBACzC,EAAa,WAAW,IACvB,kBAAC,GAAD;OACE,cAAa;OACb,OAAM;OACN,aAAY;OACZ,CAAA,GAEF,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;OAAa,WAAU;iBACrB,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,SAAD;SAAO,WAAU;mBAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;UAAI,WAAU;oBAAd;WACE,kBAAC,MAAD;YAAI,WAAU;sBAA4B;YAAO,CAAA;WACjD,kBAAC,MAAD;YAAI,WAAU;sBAA4B;YAAS,CAAA;WACnD,kBAAC,MAAD;YAAI,WAAU;sBAA4B;YAAgB,CAAA;WAC1D,kBAAC,MAAD;YAAI,WAAU;sBAA4B;YAAe,CAAA;WACzD,kBAAC,MAAD;YAAI,WAAU;sBAA6B;YAAW,CAAA;WACtD,kBAAC,MAAD;YAAI,WAAU;sBAA4B;YAAW,CAAA;WACrD,kBAAC,MAAD;YAAI,WAAU;sBAA4B;YAAS,CAAA;WAChD;aACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAa,KAAK,MACjB,kBAAC,MAAD;UAEE,WAAU;UACV,eAAe,EAAS,mBAAmB,EAAI,GAAG;oBAHpD;WAKE,kBAAC,MAAD;YAAI,WAAU;sBAAyB,EAAI;YAAQ,CAAA;WACnD,kBAAC,MAAD;YAAI,WAAU;sBAAkB,EAAI;YAAU,CAAA;WAC9C,kBAAC,MAAD;YAAI,WAAU;sBAAyB,EAAI;YAAiB,CAAA;WAC5D,kBAAC,MAAD;YAAI,WAAU;sBAAe,EAAI;YAAgB,CAAA;WACjD,kBAAC,MAAD;YACE,WAAW,8BAA8B,EAAI,SAAS,IAAI,2BAA2B;sBADvF,CAEC,KACG,KAAK,IAAI,EAAI,OAAO,CAAC,gBAAgB,CACpC;;WACL,kBAAC,MAAD;YAAI,WAAU;sBACZ,kBAAC,GAAD;aAAO,SAAQ;uBAAW,EAAI;aAAe,CAAA;YAC1C,CAAA;WACL,kBAAC,MAAD;YAAI,WAAU;sBAAe,IAAI,KAAK,EAAI,KAAK,CAAC,oBAAoB;YAAM,CAAA;WACvE;YAjBE,EAAI,GAiBN,CACL,EACI,CAAA,CACF;;QACJ,CAAA;OACM,CAAA,EACT,CAAA;MAEG,CAAA;KAEd,kBAAC,GAAD;MAAa,OAAM;MAAU,WAAU;gBACpC,EAAQ,WAAW,IAClB,kBAAC,GAAD;OACE,cAAa;OACb,OAAM;OACN,aAAY;OACZ,CAAA,GAEF,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAQ,KAAK,MACZ,kBAAC,GAAD;QAEE,WAAU;QACV,eAAe,EAAS,sBAAsB,EAAO,GAAG;kBAH1D,CAKE,kBAAC,GAAD;SAAY,WAAU;mBAAtB,CACE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,GAAD;WAAW,WAAU;qBAAa,EAAO;WAAiB,CAAA,EAC1D,kBAAC,GAAD;WACE,SACE,EAAO,WAAW,gBACd,gBACA,EAAO,WAAW,iBAChB,cACA;qBAGP,EAAO,OAAO,QAAQ,KAAK,IAAI;WAC1B,CAAA,CACJ;aACN,kBAAC,GAAD,EAAA,UAAA;UACG,EAAO;UAAW;UAAW,EAAO;UACrB,EAAA,CAAA,CACP;YACb,kBAAC,GAAD,EAAA,UACE,kBAAC,OAAD;SAAK,WAAU;mBAAf;UACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAsB;YAAgB,CAAA,EACtD,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CAA8B,KAAE,EAAO,UAAU,gBAAgB,CAAQ;cACrE;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAsB;YAAY,CAAA,EAClD,kBAAC,QAAD;YAAM,WAAU;sBAAhB,CAA8B,KAAE,EAAO,MAAM,gBAAgB,CAAQ;cACjE;;UACN,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,QAAD;YAAM,WAAU;sBAAsB;YAAgB,CAAA,EACtD,kBAAC,QAAD;YACE,WAAW,eAAe,EAAO,YAAY,IAAI,2BAA2B;sBAD9E,CAEC,KACG,EAAO,UAAU,gBAAgB,CAC9B;cACH;;UACN,kBAAC,OAAD;WAAK,WAAU;qBACb,kBAAC,OAAD;YACE,WAAW,uBAAuB,EAAO,WAAW,gBAAgB,uBAAuB;YAC3F,OAAO,EACL,OAAO,GAAG,KAAK,IAAK,EAAO,QAAQ,EAAO,YAAa,KAAK,IAAI,CAAC,IAClE;YACD,CAAA;WACE,CAAA;UACN,kBAAC,KAAD;WAAG,WAAU;qBAAb,CACG,KAAK,MAAO,EAAO,QAAQ,EAAO,YAAa,IAAI,EAAC,aACnD;;UACA;YACM,CAAA,CACT;UAtDA,EAAO,GAsDP,CACP;OACE,CAAA;MAEI,CAAA;KAEd,kBAAC,GAAD;MAAa,OAAM;MAAW,WAAU;gBACrC,EAAS,WAAW,IACnB,kBAAC,GAAD;OACE,cAAa;OACb,OAAM;OACN,aAAY;OACZ,CAAA,GAEF,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;OAAa,WAAU;iBACrB,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,SAAD;SAAO,WAAU;mBAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;UAAI,WAAU;oBAAd;WACE,kBAAC,MAAD;YAAI,WAAU;sBAA4B;YAAc,CAAA;WACxD,kBAAC,MAAD;YAAI,WAAU;sBAA4B;YAAW,CAAA;WACrD,kBAAC,MAAD;YAAI,WAAU;sBAA6B;YAAW,CAAA;WACtD,kBAAC,MAAD;YAAI,WAAU;sBAA4B;YAAe,CAAA;WACzD,kBAAC,MAAD;YAAI,WAAU;sBAA4B;YAAa,CAAA;WACvD,kBAAC,MAAD;YAAI,WAAU;sBAA4B;YAAW,CAAA;WAClD;aACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAS,KAAK,MACb,kBAAC,MAAD;UAEE,WAAU;UACV,eAAe,EAAS,uBAAuB,EAAI,GAAG;oBAHxD;WAKE,kBAAC,MAAD;YAAI,WAAU;sBAAyB,EAAI;YAAY,CAAA;WACvD,kBAAC,MAAD;YAAI,WAAU;sBAAO,EAAI;YAAY,CAAA;WACrC,kBAAC,MAAD;YAAI,WAAU;sBAAd,CAA2C,KACvC,EAAI,OAAO,gBAAgB,CAC1B;;WACL,kBAAC,MAAD;YAAI,WAAU;sBAAe,EAAI;YAAe,CAAA;WAChD,kBAAC,MAAD;YAAI,WAAU;sBAAe,EAAI;YAAa,CAAA;WAC9C,kBAAC,MAAD;YAAI,WAAU;sBACZ,kBAAC,GAAD;aACE,SACE,EAAI,WAAW,YACX,gBACA,EAAI,WAAW,SACb,YACA;uBAGP,EAAI;aACC,CAAA;YACL,CAAA;WACF;YAxBE,EAAI,GAwBN,CACL,EACI,CAAA,CACF;;QACJ,CAAA;OACM,CAAA,EACT,CAAA;MAEG,CAAA;KACT;;GACH"}
1
+ {"version":3,"file":"FinanceFinanceHubPage.js","names":[],"sources":["../../../src/assethandler/pages/FinanceFinanceHubPage.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useAssetHandlerNavigate } from '../hooks/useAssetHandlerNavigate';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Input,\n Label,\n Textarea,\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n GradientText,\n CTAOverflowMenu,\n EmphasisPanel,\n PagePurpose,\n NextSteps,\n IllustratedEmptyState,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { DollarSign, TrendingDown, Receipt, CreditCard, Download, Loader2 } from 'lucide-react';\nimport { gql } from '@apollo/client';\nimport { useMutation } from '@apollo/client/react';\nimport { useAssetHandlerStore } from '../store/assethandlerStore';\nimport { notify } from '../utils/toast';\n\n// ─── Mutations ────────────────────────────────────────────────────────────────\nconst CREATE_TRANSACTION_MUTATION = gql`\n mutation AssetHandlerCreateTransaction($input: CreateTransactionInput!) {\n createTransaction(input: $input) {\n id\n description\n }\n }\n`;\n\nconst CREATE_BUDGET_MUTATION = gql`\n mutation AssetHandlerCreateBudget($input: AssetHandlerCreateBudgetInput!) {\n createBudget(input: $input) {\n id\n name\n }\n }\n`;\n\nconst CREATE_INVOICE_MUTATION = gql`\n mutation AssetHandlerCreateInvoice($input: AssetHandlerCreateInvoiceInput!) {\n createInvoice(input: $input) {\n id\n number\n }\n }\n`;\n\ninterface CreateTransactionResult {\n createTransaction: { id: string; description: string };\n}\ninterface CreateBudgetResult {\n createBudget: { id: string; name: string };\n}\ninterface CreateInvoiceResult {\n createInvoice: { id: string; number: string };\n}\n\nconst TRANSACTION_TYPES = ['PURCHASE', 'LEASE', 'DISPOSAL', 'TRANSFER', 'MAINTENANCE'] as const;\nconst TRANSACTION_STATUSES = ['PENDING', 'APPROVED', 'COMPLETED', 'REJECTED'] as const;\nconst BUDGET_STATUSES = ['ON_TRACK', 'OVER_BUDGET', 'UNDER_BUDGET'] as const;\nconst INVOICE_STATUSES = ['DRAFT', 'SENT', 'PAID', 'OVERDUE', 'CANCELLED'] as const;\n\nconst humanize = (value: string) =>\n value\n .toLowerCase()\n .replace(/_/g, ' ')\n .replace(/^\\w/, (c) => c.toUpperCase());\n\n// ─── New Transaction dialog ───────────────────────────────────────────────────\nfunction NewTransactionDialog({\n open,\n onOpenChange,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const [type, setType] = useState<(typeof TRANSACTION_TYPES)[number]>('PURCHASE');\n const [status, setStatus] = useState<(typeof TRANSACTION_STATUSES)[number]>('PENDING');\n const [amount, setAmount] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [category, setCategory] = useState('');\n const [description, setDescription] = useState('');\n const [vendor, setVendor] = useState('');\n const [department, setDepartment] = useState('');\n\n const reset = () => {\n setType('PURCHASE');\n setStatus('PENDING');\n setAmount('');\n setCurrency('USD');\n setCategory('');\n setDescription('');\n setVendor('');\n setDepartment('');\n };\n\n const [createTransaction, { loading }] = useMutation<CreateTransactionResult>(\n CREATE_TRANSACTION_MUTATION,\n {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: (data) => {\n notify.success(\n 'Transaction created',\n `${data.createTransaction.description} was recorded.`\n );\n reset();\n onOpenChange(false);\n },\n onError: (error) => notify.error('Could not create transaction', error.message),\n }\n );\n\n const handleSubmit = () => {\n const parsedAmount = Number(amount);\n if (!Number.isFinite(parsedAmount) || amount.trim() === '') {\n notify.warning('Invalid amount', 'Enter a numeric amount for the transaction.');\n return;\n }\n if (!category.trim() || !description.trim()) {\n notify.warning('Missing details', 'Category and description are required.');\n return;\n }\n void createTransaction({\n variables: {\n input: {\n amount: parsedAmount,\n category: category.trim(),\n currency: currency.trim() || 'USD',\n description: description.trim(),\n type,\n status,\n vendor: vendor.trim() || null,\n department: department.trim() || null,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New Transaction</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Record a financial movement against your assets.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Type</Label>\n <Select value={type} onValueChange={(v) => setType(v as typeof type)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TRANSACTION_TYPES.map((t) => (\n <SelectItem key={t} value={t}>\n {humanize(t)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select value={status} onValueChange={(v) => setStatus(v as typeof status)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {TRANSACTION_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Amount *</Label>\n <Input\n type=\"number\"\n placeholder=\"e.g., 1500\"\n value={amount}\n onChange={(e) => setAmount(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Currency</Label>\n <Input value={currency} onChange={(e) => setCurrency(e.target.value)} />\n </div>\n </div>\n <div className=\"space-y-2\">\n <Label>Category *</Label>\n <Input\n placeholder=\"e.g., it_hardware\"\n value={category}\n onChange={(e) => setCategory(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Description *</Label>\n <Textarea\n placeholder=\"What is this transaction for?\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Vendor</Label>\n <Input value={vendor} onChange={(e) => setVendor(e.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label>Department</Label>\n <Input value={department} onChange={(e) => setDepartment(e.target.value)} />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {loading ? 'Creating…' : 'Create Transaction'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n// ─── New Budget dialog ────────────────────────────────────────────────────────\nfunction NewBudgetDialog({\n open,\n onOpenChange,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const [name, setName] = useState('');\n const [category, setCategory] = useState('');\n const [department, setDepartment] = useState('');\n const [period, setPeriod] = useState('');\n const [allocated, setAllocated] = useState('');\n const [spent, setSpent] = useState('0');\n const [status, setStatus] = useState<(typeof BUDGET_STATUSES)[number]>('ON_TRACK');\n\n const reset = () => {\n setName('');\n setCategory('');\n setDepartment('');\n setPeriod('');\n setAllocated('');\n setSpent('0');\n setStatus('ON_TRACK');\n };\n\n const [createBudget, { loading }] = useMutation<CreateBudgetResult>(CREATE_BUDGET_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: (data) => {\n notify.success('Budget created', `${data.createBudget.name} is now being tracked.`);\n reset();\n onOpenChange(false);\n },\n onError: (error) => notify.error('Could not create budget', error.message),\n });\n\n const handleSubmit = () => {\n const parsedAllocated = Number(allocated);\n const parsedSpent = Number(spent);\n if (!name.trim() || !category.trim() || !department.trim() || !period.trim()) {\n notify.warning('Missing details', 'Name, category, department and period are required.');\n return;\n }\n if (!Number.isFinite(parsedAllocated) || allocated.trim() === '') {\n notify.warning('Invalid allocation', 'Enter a numeric allocated amount.');\n return;\n }\n void createBudget({\n variables: {\n input: {\n allocated: parsedAllocated,\n category: category.trim(),\n department: department.trim(),\n name: name.trim(),\n period: period.trim(),\n spent: Number.isFinite(parsedSpent) ? parsedSpent : 0,\n status,\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New Budget</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Set an allocation to track departmental asset spend.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"space-y-2\">\n <Label>Name *</Label>\n <Input\n placeholder=\"e.g., IT Hardware Q1\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Category *</Label>\n <Input value={category} onChange={(e) => setCategory(e.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label>Department *</Label>\n <Input value={department} onChange={(e) => setDepartment(e.target.value)} />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Period *</Label>\n <Input\n placeholder=\"e.g., Q1 2026\"\n value={period}\n onChange={(e) => setPeriod(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select value={status} onValueChange={(v) => setStatus(v as typeof status)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {BUDGET_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Allocated *</Label>\n <Input\n type=\"number\"\n placeholder=\"e.g., 50000\"\n value={allocated}\n onChange={(e) => setAllocated(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Spent</Label>\n <Input type=\"number\" value={spent} onChange={(e) => setSpent(e.target.value)} />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {loading ? 'Creating…' : 'Create Budget'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\n// ─── New Invoice dialog ───────────────────────────────────────────────────────\nfunction NewInvoiceDialog({\n open,\n onOpenChange,\n}: {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n}) {\n const [number, setNumber] = useState('');\n const [vendor, setVendor] = useState('');\n const [amount, setAmount] = useState('');\n const [currency, setCurrency] = useState('USD');\n const [issueDate, setIssueDate] = useState('');\n const [dueDate, setDueDate] = useState('');\n const [relatedPO, setRelatedPO] = useState('');\n const [status, setStatus] = useState<(typeof INVOICE_STATUSES)[number]>('DRAFT');\n\n const reset = () => {\n setNumber('');\n setVendor('');\n setAmount('');\n setCurrency('USD');\n setIssueDate('');\n setDueDate('');\n setRelatedPO('');\n setStatus('DRAFT');\n };\n\n const [createInvoice, { loading }] = useMutation<CreateInvoiceResult>(CREATE_INVOICE_MUTATION, {\n refetchQueries: ['AssetHandlerBootstrap'],\n onCompleted: (data) => {\n notify.success('Invoice created', `Invoice ${data.createInvoice.number} was added.`);\n reset();\n onOpenChange(false);\n },\n onError: (error) => notify.error('Could not create invoice', error.message),\n });\n\n const handleSubmit = () => {\n const parsedAmount = Number(amount);\n if (!number.trim() || !vendor.trim()) {\n notify.warning('Missing details', 'Invoice number and vendor are required.');\n return;\n }\n if (!Number.isFinite(parsedAmount) || amount.trim() === '') {\n notify.warning('Invalid amount', 'Enter a numeric invoice amount.');\n return;\n }\n if (!issueDate || !dueDate) {\n notify.warning('Missing dates', 'Issue date and due date are required.');\n return;\n }\n void createInvoice({\n variables: {\n input: {\n amount: parsedAmount,\n currency: currency.trim() || 'USD',\n dueDate: new Date(dueDate).toISOString(),\n issueDate: new Date(issueDate).toISOString(),\n number: number.trim(),\n relatedPO: relatedPO.trim() || null,\n status,\n vendor: vendor.trim(),\n },\n },\n });\n };\n\n return (\n <ResponsiveDialog open={open} onOpenChange={onOpenChange}>\n <ResponsiveDialogContent>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New Invoice</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Log a vendor invoice for an asset purchase or service.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-4\">\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Invoice Number *</Label>\n <Input\n placeholder=\"e.g., INV-2026-001\"\n value={number}\n onChange={(e) => setNumber(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Vendor *</Label>\n <Input value={vendor} onChange={(e) => setVendor(e.target.value)} />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Amount *</Label>\n <Input\n type=\"number\"\n placeholder=\"e.g., 12000\"\n value={amount}\n onChange={(e) => setAmount(e.target.value)}\n />\n </div>\n <div className=\"space-y-2\">\n <Label>Currency</Label>\n <Input value={currency} onChange={(e) => setCurrency(e.target.value)} />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Issue Date *</Label>\n <Input type=\"date\" value={issueDate} onChange={(e) => setIssueDate(e.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label>Due Date *</Label>\n <Input type=\"date\" value={dueDate} onChange={(e) => setDueDate(e.target.value)} />\n </div>\n </div>\n <div className=\"grid gap-4 md:grid-cols-2\">\n <div className=\"space-y-2\">\n <Label>Related PO</Label>\n <Input value={relatedPO} onChange={(e) => setRelatedPO(e.target.value)} />\n </div>\n <div className=\"space-y-2\">\n <Label>Status</Label>\n <Select value={status} onValueChange={(v) => setStatus(v as typeof status)}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {INVOICE_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {humanize(s)}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button variant=\"outline\" onClick={() => onOpenChange(false)} disabled={loading}>\n Cancel\n </Button>\n <Button onClick={handleSubmit} disabled={loading}>\n {loading ? <Loader2 className=\"mr-2 h-4 w-4 animate-spin\" /> : null}\n {loading ? 'Creating…' : 'Create Invoice'}\n </Button>\n </ResponsiveDialogFooter>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n );\n}\n\nexport function FinanceFinanceHubPage() {\n const navigate = useAssetHandlerNavigate();\n const { transactions, budgets, invoices } = useAssetHandlerStore();\n\n const [txnDialogOpen, setTxnDialogOpen] = useState(false);\n const [budgetDialogOpen, setBudgetDialogOpen] = useState(false);\n const [invoiceDialogOpen, setInvoiceDialogOpen] = useState(false);\n\n const totalSpend = transactions.filter((t) => t.amount > 0).reduce((s, t) => s + t.amount, 0);\n const pendingTxns = transactions.filter((t) => t.status === 'pending');\n const overBudget = budgets.filter((b) => b.status === 'over_budget');\n const overdueInvoices = invoices.filter((i) => i.status === 'overdue');\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>Finance Hub</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">Financial management for IT assets</p>\n </div>\n <CTAOverflowMenu\n primary={{ label: 'New Transaction', onSelect: () => setTxnDialogOpen(true) }}\n actions={[\n { label: 'New Budget', onSelect: () => setBudgetDialogOpen(true) },\n { label: 'New Invoice', onSelect: () => setInvoiceDialogOpen(true) },\n { label: 'Export', onSelect: () => {}, icon: <Download className=\"h-4 w-4\" /> },\n ]}\n />\n </div>\n\n <NewTransactionDialog open={txnDialogOpen} onOpenChange={setTxnDialogOpen} />\n <NewBudgetDialog open={budgetDialogOpen} onOpenChange={setBudgetDialogOpen} />\n <NewInvoiceDialog open={invoiceDialogOpen} onOpenChange={setInvoiceDialogOpen} />\n\n <PagePurpose>\n The money side of your asset estate: track spend, keep departmental budgets on course, and\n stay on top of vendor invoices. Use this hub to spot over-budget areas and overdue invoices\n early — so asset costs stay predictable and nothing slips past its due date.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"assethandler-finance-hub\"\n steps={[\n {\n id: 'transactions',\n label: 'Review recent transactions',\n description: 'Check spend and approve anything still pending.',\n onClick: () => navigate('/transactions/transaction-list'),\n },\n {\n id: 'budgets',\n label: 'Review reporting dashboard',\n description: 'See budget health and spend trends across departments.',\n onClick: () => navigate('/reports/reports-dashboard'),\n },\n {\n id: 'reports',\n label: 'Build a finance report',\n description: 'Turn spend and budget data into a shareable report.',\n onClick: () => navigate('/reports/reports-dashboard'),\n },\n ]}\n />\n\n <div className=\"grid gap-4 md:grid-cols-4\">\n <EmphasisPanel>\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <DollarSign className=\"h-4 w-4\" />\n Total Spend\n </div>\n <p className=\"text-2xl font-bold mt-1 tabular-nums\">${totalSpend.toLocaleString()}</p>\n </EmphasisPanel>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-2 text-sm text-text-secondary\">\n <CreditCard className=\"h-4 w-4\" />\n Pending\n </div>\n <p className=\"text-2xl font-bold mt-1 text-status-info-text\">{pendingTxns.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 <TrendingDown className=\"h-4 w-4\" />\n Over Budget\n </div>\n <p className=\"text-2xl font-bold mt-1 text-status-error-text\">{overBudget.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 <Receipt className=\"h-4 w-4\" />\n Overdue Invoices\n </div>\n <p className=\"text-2xl font-bold mt-1 text-status-warning-text\">\n {overdueInvoices.length}\n </p>\n </CardContent>\n </Card>\n </div>\n\n <Tabs defaultValue=\"transactions\">\n <TabsList>\n <TabsTrigger value=\"transactions\">Transactions</TabsTrigger>\n <TabsTrigger value=\"budgets\">Budgets</TabsTrigger>\n <TabsTrigger value=\"invoices\">Invoices</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"transactions\" className=\"mt-4\">\n {transactions.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No transactions yet\"\n description=\"Asset-related spend and reimbursements will appear here as they are recorded.\"\n />\n ) : (\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\">ID</th>\n <th className=\"text-left p-3 font-medium\">Type</th>\n <th className=\"text-left p-3 font-medium\">Description</th>\n <th className=\"text-left p-3 font-medium\">Department</th>\n <th className=\"text-right p-3 font-medium\">Amount</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n <th className=\"text-left p-3 font-medium\">Date</th>\n </tr>\n </thead>\n <tbody>\n {transactions.map((txn) => (\n <tr\n key={txn.id}\n className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\"\n onClick={() => navigate('/transactions/' + txn.id)}\n >\n <td className=\"p-3 font-mono text-xs\">{txn.id}</td>\n <td className=\"p-3 capitalize\">{txn.type}</td>\n <td className=\"p-3 truncate max-w-xs\">{txn.description}</td>\n <td className=\"p-3 text-xs\">{txn.department}</td>\n <td\n className={`p-3 text-right font-medium ${txn.amount < 0 ? 'text-status-error-text' : ''}`}\n >\n ${Math.abs(txn.amount).toLocaleString()}\n </td>\n <td className=\"p-3\">\n <Badge variant=\"outline\">{txn.status}</Badge>\n </td>\n <td className=\"p-3 text-xs\">{new Date(txn.date).toLocaleDateString()}</td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n\n <TabsContent value=\"budgets\" className=\"mt-4\">\n {budgets.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title=\"No budgets defined\"\n description=\"Create departmental budgets to track allocated vs. actual asset spend.\"\n />\n ) : (\n <div className=\"grid gap-4 md:grid-cols-2\">\n {budgets.map((budget) => (\n <Card\n key={budget.id}\n className=\"cursor-pointer\"\n onClick={() => navigate('/finance/budgets/' + budget.id)}\n >\n <CardHeader className=\"pb-2\">\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">{budget.name}</CardTitle>\n <Badge\n variant={\n budget.status === 'over_budget'\n ? 'destructive'\n : budget.status === 'under_budget'\n ? 'secondary'\n : 'default'\n }\n >\n {budget.status.replace('_', ' ')}\n </Badge>\n </div>\n <CardDescription>\n {budget.department} &middot; {budget.period}\n </CardDescription>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-3\">\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Allocated</span>\n <span className=\"font-medium\">${budget.allocated.toLocaleString()}</span>\n </div>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Spent</span>\n <span className=\"font-medium\">${budget.spent.toLocaleString()}</span>\n </div>\n <div className=\"flex justify-between text-sm\">\n <span className=\"text-text-secondary\">Remaining</span>\n <span\n className={`font-medium ${budget.remaining < 0 ? 'text-status-error-text' : 'text-status-success-text'}`}\n >\n ${budget.remaining.toLocaleString()}\n </span>\n </div>\n <div className=\"h-2 rounded-full bg-bg-sunken overflow-hidden\">\n <div\n className={`h-full rounded-full ${budget.status === 'over_budget' ? 'bg-status-error-bg' : 'bg-action-primary-bg'}`}\n style={{\n width: `${Math.min((budget.spent / budget.allocated) * 100, 100)}%`,\n }}\n />\n </div>\n <p className=\"text-xs text-text-secondary text-right\">\n {Math.round((budget.spent / budget.allocated) * 100)}% utilized\n </p>\n </div>\n </CardContent>\n </Card>\n ))}\n </div>\n )}\n </TabsContent>\n\n <TabsContent value=\"invoices\" className=\"mt-4\">\n {invoices.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-files\"\n title=\"No invoices\"\n description=\"Vendor invoices for asset purchases and services will be listed here.\"\n />\n ) : (\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\">Invoice #</th>\n <th className=\"text-left p-3 font-medium\">Vendor</th>\n <th className=\"text-right p-3 font-medium\">Amount</th>\n <th className=\"text-left p-3 font-medium\">Issue Date</th>\n <th className=\"text-left p-3 font-medium\">Due Date</th>\n <th className=\"text-left p-3 font-medium\">Status</th>\n </tr>\n </thead>\n <tbody>\n {invoices.map((inv) => (\n <tr\n key={inv.id}\n className=\"border-b hover:bg-bg-sunken/50 cursor-pointer\"\n onClick={() => navigate('/finance/invoices/' + inv.id)}\n >\n <td className=\"p-3 font-mono text-xs\">{inv.number}</td>\n <td className=\"p-3\">{inv.vendor}</td>\n <td className=\"p-3 text-right font-medium\">\n ${inv.amount.toLocaleString()}\n </td>\n <td className=\"p-3 text-xs\">{inv.issueDate}</td>\n <td className=\"p-3 text-xs\">{inv.dueDate}</td>\n <td className=\"p-3\">\n <Badge\n variant={\n inv.status === 'overdue'\n ? 'destructive'\n : inv.status === 'paid'\n ? 'default'\n : 'outline'\n }\n >\n {inv.status}\n </Badge>\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </CardContent>\n </Card>\n )}\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":"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"}