humam kerdiah 4bfd8c84a9 feat: add template checkpoint edit dialog and vendor management components
- 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.
2026-05-18 12:08:42 +04:00

120 lines
3.8 KiB
TypeScript

"use client"
import { useState } from "react"
import { useQueryStates } from "nuqs"
import { useQuery, useQueryClient, type UseQueryOptions } from "@tanstack/react-query"
import type { DataViewChangeEvent, DataViewPaginationState, DataViewSorting } from "./types"
import { dataTableSearchParams } from "./search-params"
import { DEFAULT_PER_PAGE, type CrudListResponse } from "@garage/api"
type DataTableClient = {
list(query?: any): Promise<any>
}
type DataTableParams = {
page: number
per_page: number
sort_by: string | null
sort_order: "asc" | "desc" | null
}
type UseDataTableQueryOptions<C extends DataTableClient> = {
queryKey: string[]
client: C
queryOptions?: Omit<UseQueryOptions<CrudListResponse<C>>, "queryKey" | "queryFn">
extraParams?: Record<string, unknown>
/** When true, pagination/sorting state lives in component state instead of URL params. Used for tables inside dialogs so they don't share state with the parent page. */
localState?: boolean
}
export function useDataTableQuery<C extends DataTableClient>({
queryKey,
client,
queryOptions,
extraParams,
localState = false,
}: UseDataTableQueryOptions<C>) {
const [urlParams, setUrlParams] = useQueryStates(dataTableSearchParams)
const [localParams, setLocalParams] = useState<DataTableParams>({
page: 1,
per_page: DEFAULT_PER_PAGE,
sort_by: null,
sort_order: null,
})
const params: DataTableParams = localState ? localParams : urlParams
const setParams = (next: Partial<DataTableParams>) => {
if (localState) {
setLocalParams((prev) => ({ ...prev, ...next }))
} else {
setUrlParams(next)
}
}
const _queryKey = [...queryKey, params, ...(extraParams ? [extraParams] : [])]
const query = useQuery<CrudListResponse<C>>({
queryKey: _queryKey,
queryFn: () => {
const apiParams: Record<string, unknown> = {
page: params.page,
per_page: params.per_page,
...extraParams,
}
if (params.sort_by) apiParams.sort_by = params.sort_by
if (params.sort_order) apiParams.sort_order = params.sort_order
return client.list(apiParams) as Promise<CrudListResponse<C>>
},
...queryOptions,
})
const pagination: DataViewPaginationState = {
page: params.page,
pageSize: params.per_page,
pageCount: (query.data as any)?.meta?.last_page ?? 1,
total: (query.data as any)?.meta?.total ?? 0,
}
const sorting: DataViewSorting = params.sort_by
? [{ id: params.sort_by, desc: params.sort_order === "desc" }]
: []
const handleChange = (event: DataViewChangeEvent) => {
switch (event.type) {
case "pagination":
setParams({
page: event.pagination.page,
per_page: event.pagination.pageSize,
})
break
case "sorting": {
const sort = event.sorting[0]
setParams({
sort_by: sort?.id ?? null,
sort_order: sort ? (sort.desc ? "desc" : "asc") : null,
page: 1,
})
break
}
}
}
const queryClient = useQueryClient();
const invalidateQuery = () => {
// Prefix-match on the base route key so all paginated/sorted variants of
// the list refetch — exact-matching the params object is flaky because
// nuqs returns a fresh reference per render.
queryClient.invalidateQueries({ queryKey, refetchType: "active" })
}
return {
...query,
pagination,
sorting,
params,
setParams,
handleChange,
invalidateQuery,
}
}