- Implemented TemplateCheckpointEditDialog for creating and editing inspection checkpoints. - Added VendorActions component for managing vendor actions including edit, activate/deactivate, and delete. - Created VendorContext for managing vendor state across components. - Developed VendorGeneralInfo component to display detailed vendor information. - Introduced AedSymbol and Money components for consistent currency representation. - Added PromptDialog for user input prompts throughout the application. - Implemented RelationLink component for unified related-data display in CRUD tables. - Created InspectionTemplatesClient for API interactions related to inspection templates.
123 lines
4.1 KiB
TypeScript
123 lines
4.1 KiB
TypeScript
"use client"
|
|
|
|
import { useState, useRef } from "react"
|
|
import { Button } from "@/shared/components/ui/button"
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
DialogFooter,
|
|
} from "@/shared/components/ui/dialog"
|
|
import { CrudResource, type CrudResourceProps } from "@/shared/data-view/resource-page"
|
|
import type { ResourcePageClient, ResourceItem } from "@/shared/data-view/resource-page"
|
|
|
|
export type ResourceSelectorDialogProps<TClient extends ResourcePageClient> = {
|
|
/** Dialog title shown in the header */
|
|
title: string
|
|
/** Opens/closes the dialog */
|
|
open: boolean
|
|
onOpenChange: (open: boolean) => void
|
|
/** Called when user confirms selection */
|
|
onConfirm: (selectedRows: ResourceItem<TClient>[]) => void
|
|
/** CrudResource config for the table (columns, routeKey, getClient, etc.) */
|
|
crudProps: Omit<CrudResourceProps<TClient>, "render" | "tableProps">
|
|
/** Optional rowKey for selection identity. Defaults to "id" */
|
|
rowKey?: keyof ResourceItem<TClient>
|
|
/**
|
|
* Selection mode.
|
|
* - "multi" (default): checkbox multi-select + Confirm button
|
|
* - "single": row click immediately fires onConfirm with the clicked row
|
|
*/
|
|
selectionMode?: "single" | "multi"
|
|
/** Show a search input above the table. Defaults to true. */
|
|
searchable?: boolean
|
|
/** Placeholder for the search input. */
|
|
searchPlaceholder?: string
|
|
}
|
|
|
|
export function ResourceSelectorDialog<TClient extends ResourcePageClient>({
|
|
title,
|
|
open,
|
|
onOpenChange,
|
|
onConfirm,
|
|
crudProps,
|
|
rowKey,
|
|
selectionMode = "multi",
|
|
searchable = true,
|
|
searchPlaceholder = "Search...",
|
|
}: ResourceSelectorDialogProps<TClient>) {
|
|
type TItem = ResourceItem<TClient>
|
|
|
|
const selectedRef = useRef<TItem[]>([])
|
|
const [count, setCount] = useState(0)
|
|
|
|
const handleSelectionChange = (rows: TItem[]) => {
|
|
selectedRef.current = rows
|
|
setCount(rows.length)
|
|
}
|
|
|
|
const handleConfirm = () => {
|
|
onConfirm(selectedRef.current)
|
|
selectedRef.current = []
|
|
setCount(0)
|
|
onOpenChange(false)
|
|
}
|
|
|
|
const handleCancel = () => {
|
|
selectedRef.current = []
|
|
setCount(0)
|
|
onOpenChange(false)
|
|
}
|
|
|
|
const handleRowClick = (row: TItem) => {
|
|
onConfirm([row])
|
|
onOpenChange(false)
|
|
}
|
|
|
|
const sharedCrudProps = {
|
|
...crudProps,
|
|
localState: crudProps.localState ?? true,
|
|
searchable: crudProps.searchable ?? searchable,
|
|
searchPlaceholder: crudProps.searchPlaceholder ?? searchPlaceholder,
|
|
}
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={(v) => { if (!v) handleCancel() }}>
|
|
<DialogContent className="min-w-4xl max-h-[90vh] flex flex-col gap-3 p-4">
|
|
<DialogHeader>
|
|
<DialogTitle className="text-xl font-semibold">{title}</DialogTitle>
|
|
</DialogHeader>
|
|
<div className="flex-1 overflow-auto min-h-0">
|
|
{selectionMode === "single" ? (
|
|
<CrudResource<TClient>
|
|
{...sharedCrudProps}
|
|
onRowClick={handleRowClick}
|
|
/>
|
|
) : (
|
|
<CrudResource<TClient>
|
|
{...sharedCrudProps}
|
|
tableProps={{
|
|
selection: {
|
|
onSelectionChange: handleSelectionChange,
|
|
...(rowKey ? { rowKey } : {}),
|
|
},
|
|
}}
|
|
/>
|
|
)}
|
|
</div>
|
|
{selectionMode === "multi" && (
|
|
<DialogFooter>
|
|
<Button variant="outline" onClick={handleCancel}>
|
|
Cancel
|
|
</Button>
|
|
<Button onClick={handleConfirm} disabled={count === 0}>
|
|
Confirm{count > 0 ? ` (${count})` : ""}
|
|
</Button>
|
|
</DialogFooter>
|
|
)}
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|