garage-erp/shared/components/form-dialog.tsx
2026-03-26 03:49:05 +03:00

88 lines
2.8 KiB
TypeScript

import React from 'react'
import { useQueryStates, parseAsBoolean, parseAsString } from 'nuqs'
import { Button } from '@/shared/components/ui/button'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/shared/components/ui/dialog'
import { ScrollArea } from '@/shared/components/ui/scroll-area'
import { Plus } from 'lucide-react'
export const formDialogParams = {
dialog: parseAsBoolean.withDefault(false),
resourceId: parseAsString,
}
export function useFormDialog(paramKey?: string) {
// Default (no paramKey) uses the standard `dialog` and `resourceId` params
const defaultState = useQueryStates(formDialogParams)
// When a paramKey is provided, use prefixed params to avoid URL collisions
const prefixedState = useQueryStates({
[`${paramKey ?? "_"}_dialog`]: parseAsBoolean.withDefault(false),
[`${paramKey ?? "_"}_resourceId`]: parseAsString,
})
if (paramKey) {
const [params, setParams] = prefixedState
const dialogKey = `${paramKey}_dialog`
const resourceIdKey = `${paramKey}_resourceId`
const open = (resourceId?: string) => {
setParams({ [dialogKey]: true, [resourceIdKey]: resourceId ?? null })
}
const close = () => {
setParams({ [dialogKey]: false, [resourceIdKey]: null })
}
return {
isOpen: (params as Record<string, unknown>)[dialogKey] as boolean,
resourceId: (params as Record<string, unknown>)[resourceIdKey] as string | null,
open,
close,
}
}
const [params, setParams] = defaultState
const open = (resourceId?: string) => {
setParams({ dialog: true, resourceId: resourceId ?? null })
}
const close = () => {
setParams({ dialog: false, resourceId: null })
}
return {
isOpen: params.dialog,
resourceId: params.resourceId,
open,
close,
}
}
export default function FormDialog(props: {
children: (resourceId: string | null) => React.ReactNode
title: string
paramKey?: string
}) {
const { isOpen, resourceId, open, close } = useFormDialog(props.paramKey)
return (
<>
<Button size='lg' onClick={() => open()}>
<Plus />
{props.title}
</Button>
<Dialog open={isOpen} onOpenChange={(v) => { if (!v) close() }}>
<DialogContent className='min-w-xl'>
<DialogHeader>
<DialogTitle className='text-2xl font-bold'>
{props.title}
</DialogTitle>
</DialogHeader>
<ScrollArea className='max-h-[80vh] px-4'>
{props.children(resourceId)}
</ScrollArea>
</DialogContent>
</Dialog>
</>
)
}