diff --git a/src/api/api-paths.ts b/src/api/api-paths.ts index 33db519b..dcc144bc 100644 --- a/src/api/api-paths.ts +++ b/src/api/api-paths.ts @@ -155,6 +155,11 @@ export const API_PATHS = { update: "DropdownOptions/Update", delete: "DropdownOptions", }, + services: { + list: "services", + byId: (id: string | number) => `services/${id}`, + deactivate: (id: string | number) => `services/${id}/deactivate`, + }, user: { list: "User", }, diff --git a/src/app/(protected)/settings/services.tsx b/src/app/(protected)/settings/services.tsx new file mode 100644 index 00000000..5fcb4ebd --- /dev/null +++ b/src/app/(protected)/settings/services.tsx @@ -0,0 +1,611 @@ +import { useEffect, useMemo, useState } from "react"; +import { + Alert, + Autocomplete, + Box, + Button, + Checkbox, + Chip, + CircularProgress, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, + Divider, + Drawer, + FormControl, + FormControlLabel, + FormHelperText, + InputLabel, + MenuItem, + Select, + Stack, + Switch, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + TextField, + Typography, +} from "@mui/material"; +import { ChevronRight, Circle, Droplets, Hammer, Plus, Settings2, Wrench, Zap } from "lucide-react"; +import { SettingsNav } from "@/components/common/settings-nav"; +import { useAuthContext } from "@/providers/auth-context"; +import { getPrimaryUserRole, isAdminUser } from "@/lib/auth/user-utils"; +import { useDropdownOptionsByCategory } from "@/domain/settings/dropdown-options/use-cases/use-dropdown-options-by-category"; +import { useTaskTemplates } from "@/domain/settings/task-templates/use-cases/use-task-templates"; +import { + SERVICE_WORK_ORDER_TYPES, + type Service, + type ServiceInput, + type ServiceWorkOrderType, +} from "@/domain/services/types/service"; +import { + useCreateService, + useDeactivateService, + useServices, + useUpdateService, +} from "@/domain/services/use-cases/use-services"; + +type ServiceStatus = "all" | "active" | "inactive"; +type ServiceForm = Omit & { + completionDocTemplateId: string | number | null; +}; + +const EMPTY_FORM: ServiceForm = { + name: "", + trade: "", + iconKey: "", + requiresCompletionDocument: false, + completionDocTemplateId: null, + supportedWorkOrderTypes: ["PM", "Reactive", "Emergency"], +}; + +const DEFAULT_ICON_BY_TRADE: Record = { + HVAC: "droplets", + Plumbing: "droplets", + Electrical: "zap", + "General Building": "hammer", +}; + +const ICONS = [ + { key: "wrench", label: "Wrench", Icon: Wrench }, + { key: "droplets", label: "Droplets", Icon: Droplets }, + { key: "zap", label: "Zap", Icon: Zap }, + { key: "hammer", label: "Hammer", Icon: Hammer }, + { key: "settings", label: "Settings", Icon: Settings2 }, +] as const; + +function ServiceIcon({ iconKey, size = 18 }: { iconKey: string; size?: number }) { + const icon = ICONS.find((item) => item.key === iconKey) ?? ICONS[0]; + const Icon = icon.Icon; + return