implement controlled edit / delete dialogs

This commit is contained in:
andrzej 2024-08-07 15:46:14 +02:00
parent e5d2aba207
commit a204eec776
5 changed files with 84 additions and 121 deletions

Binary file not shown.

View File

@ -706,22 +706,6 @@ body {
z-index: 100; z-index: 100;
} }
.col-span-full {
grid-column: 1 / -1;
}
.col-start-1 {
grid-column-start: 1;
}
.col-start-3 {
grid-column-start: 3;
}
.col-end-3 {
grid-column-end: 3;
}
.m-auto { .m-auto {
margin: auto; margin: auto;
} }
@ -975,18 +959,6 @@ body {
width: 100vw; width: 100vw;
} }
.w-1 {
width: 0.25rem;
}
.w-6 {
width: 1.5rem;
}
.w-32 {
width: 8rem;
}
.min-w-\[8rem\] { .min-w-\[8rem\] {
min-width: 8rem; min-width: 8rem;
} }
@ -1012,10 +984,6 @@ body {
max-width: 24rem; max-width: 24rem;
} }
.max-w-28 {
max-width: 7rem;
}
.max-w-xs { .max-w-xs {
max-width: 20rem; max-width: 20rem;
} }
@ -1088,10 +1056,6 @@ body {
user-select: none; user-select: none;
} }
.grid-cols-12 {
grid-template-columns: repeat(12, minmax(0, 1fr));
}
.flex-row { .flex-row {
flex-direction: row; flex-direction: row;
} }
@ -1132,10 +1096,6 @@ body {
justify-content: space-between; justify-content: space-between;
} }
.justify-around {
justify-content: space-around;
}
.gap-1 { .gap-1 {
gap: 0.25rem; gap: 0.25rem;
} }
@ -1148,14 +1108,6 @@ body {
gap: 1rem; gap: 1rem;
} }
.gap-3 {
gap: 0.75rem;
}
.gap-44 {
gap: 11rem;
}
.gap-x-16 { .gap-x-16 {
-moz-column-gap: 4rem; -moz-column-gap: 4rem;
column-gap: 4rem; column-gap: 4rem;
@ -1169,10 +1121,6 @@ body {
row-gap: 2rem; row-gap: 2rem;
} }
.gap-y-4 {
row-gap: 1rem;
}
.space-x-1 > :not([hidden]) ~ :not([hidden]) { .space-x-1 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0; --tw-space-x-reverse: 0;
margin-right: calc(0.25rem * var(--tw-space-x-reverse)); margin-right: calc(0.25rem * var(--tw-space-x-reverse));

View File

@ -8,14 +8,12 @@ import { Row, Table, TableState } from "@tanstack/react-table"
import { tableNameToItemName } from "app/lib/nameMaps" import { tableNameToItemName } from "app/lib/nameMaps"
import EditSubmissionDialog from "app/submission/edit" import EditSubmissionDialog from "app/submission/edit"
export default function FormContextMenu({ table, row }: ComponentProps<"div"> & { table: Table<any>, row: Row<any> }) { export default function FormContextMenu({ table, row, openEditDialog, openDeleteDialog }: ComponentProps<"div"> & { table: Table<any>, row: Row<any>, openEditDialog: (row: Row<any>) => void, openDeleteDialog: (row: Row<any>) => void }) {
const pathname = table.options.meta.pathname const pathname = table.options.meta.pathname
const selectedRows = table.getSelectedRowModel().flatRows const selectedRows = table.getSelectedRowModel().flatRows
const [dialog, setDialog] = useState<"edit" | "delete" | null>("delete")
return ( return (
<Dialog modal={true}>
<ContextMenuContent > <ContextMenuContent >
{pathname !== "/submission" && selectedRows.length <= 1 ? {pathname !== "/submission" && selectedRows.length <= 1 ?
<> <>
@ -29,11 +27,9 @@ export default function FormContextMenu({ table, row }: ComponentProps<"div"> &
{ {
pathname === "/submission" ? pathname === "/submission" ?
<> <>
<DialogTrigger asChild> <ContextMenuItem onClick={() => openEditDialog(row)}>
<ContextMenuItem onClick={() => setDialog("edit")}>
Edit Edit
</ContextMenuItem> </ContextMenuItem>
</DialogTrigger>
</> </>
: "" : ""
} }
@ -44,44 +40,8 @@ export default function FormContextMenu({ table, row }: ComponentProps<"div"> &
: "" : ""
} }
<ContextMenuSeparator /> <ContextMenuSeparator />
<DialogTrigger asChild> <ContextMenuItem className="text-destructive" onClick={() => openDeleteDialog(row)}>Delete</ContextMenuItem>
<ContextMenuItem className="text-destructive" onClick={() => setDialog("delete")}>Delete</ContextMenuItem>
</DialogTrigger>
</ContextMenuContent> </ContextMenuContent>
<DialogContent>
{
dialog === "delete" ?
<>
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
<DialogDescription>
Deleting a {tableNameToItemName(table.options.meta.tableName)} cannot be undone!
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="destructive"
onClick={() => {
deleteRecord(row.original.id, pathname)
}}>Yes, delete it!
</Button>
</DialogClose>
</DialogFooter>
</>
: dialog === "edit" ?
<EditSubmissionDialog
stories={table.options.meta.stories}
pubs={table.options.meta.pubs}
responses={table.options.meta.responses}
defaults={row.original}
/>
:
<>
<DialogTitle>Edit/delete dialog</DialogTitle>
</>
}
</DialogContent>
</Dialog>
) )
} }

View File

@ -26,7 +26,8 @@ import {
getFilteredRowModel, getFilteredRowModel,
getCoreRowModel, getCoreRowModel,
getPaginationRowModel, getPaginationRowModel,
useReactTable useReactTable,
Row
} from "@tanstack/react-table" } from "@tanstack/react-table"
import { import {
@ -40,13 +41,15 @@ import {
import { EyeIcon, Trash2 } from "lucide-react" import { EyeIcon, Trash2 } from "lucide-react"
import { usePathname } from "next/navigation" import { usePathname } from "next/navigation"
import FormContextMenu from "./contextMenu" import FormContextMenu from "./contextMenu"
import { deleteRecords } from "app/lib/del" import { deleteRecord, deleteRecords } from "app/lib/del"
import { Pathname } from "app/types" import { Pathname } from "app/types"
import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTrigger } from "@/components/ui/dialog" import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTrigger } from "@/components/ui/dialog"
import pluralize from "app/lib/pluralize" import pluralize from "app/lib/pluralize"
import { updateField } from "app/lib/update" import { updateField } from "app/lib/update"
import { tableNameToItemName } from "app/lib/nameMaps" import { tableNameToItemName } from "app/lib/nameMaps"
import { Genre, Pub, Response, Story } from "@prisma/client" import { Genre, Pub, Response, Story } from "@prisma/client"
import EditSubmissionDialog from "app/submission/edit"
import { DialogTitle } from "@radix-ui/react-dialog"
export interface DataTableProps<TData, TValue> { export interface DataTableProps<TData, TValue> {
columns: ColumnDef<TData, TValue>[] columns: ColumnDef<TData, TValue>[]
@ -65,6 +68,9 @@ export function DataTable<TData, TValue>({
genres genres
}: DataTableProps<TData, TValue> & ComponentProps<"div"> & { tableName: string, stories?: Story[], pubs?: Pub[], responses?: Response[], genres?: Genre[] }) { }: DataTableProps<TData, TValue> & ComponentProps<"div"> & { tableName: string, stories?: Story[], pubs?: Pub[], responses?: Response[], genres?: Genre[] }) {
//STATE //STATE
const [isEditDialogVisible, setIsEditDialogVisible] = useState<boolean>(false)
const [isDeleteDialogVisible, setIsDeleteDialogVisible] = useState<boolean>(false)
const [dialogRow, SetDialogRow] = useState<Row<any> | null>(null)
const [sorting, setSorting] = useState<SortingState>([]) const [sorting, setSorting] = useState<SortingState>([])
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>( const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>(
[] []
@ -103,6 +109,14 @@ export function DataTable<TData, TValue>({
}) })
function openEditDialog(row) {
setIsEditDialogVisible(true)
SetDialogRow(row)
}
function openDeleteDialog(row) {
setIsDeleteDialogVisible(true)
SetDialogRow(row)
}
const [filterBy, setFilterBy] = useState(table.getAllColumns()[0]) const [filterBy, setFilterBy] = useState(table.getAllColumns()[0])
@ -143,6 +157,39 @@ export function DataTable<TData, TValue>({
{children} {children}
<Dialog open={isEditDialogVisible} onOpenChange={setIsEditDialogVisible}>
<DialogContent>
<EditSubmissionDialog
stories={stories}
pubs={pubs}
responses={responses}
defaults={dialogRow?.original}
/>
</DialogContent>
</Dialog>
<Dialog open={isDeleteDialogVisible} onOpenChange={setIsDeleteDialogVisible}>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you sure?</DialogTitle>
<DialogDescription>
Deleting a {tableNameToItemName(tableName)} cannot be undone!
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="destructive"
onClick={() => {
deleteRecord(dialogRow.original.id, pathname)
}}>Yes, delete it!
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
<Dialog> <Dialog>
<DialogTrigger asChild> <DialogTrigger asChild>
<Button variant="destructive" disabled={!(table.getIsSomeRowsSelected() || table.getIsAllRowsSelected())}> <Button variant="destructive" disabled={!(table.getIsSomeRowsSelected() || table.getIsAllRowsSelected())}>
@ -227,12 +274,18 @@ export function DataTable<TData, TValue>({
<TableBody> <TableBody>
{table.getRowModel().rows?.length ? ( {table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => ( table.getRowModel().rows.map((row) => (
<ContextMenu onOpenChange={open => setIsContextMenuOpen(open)} key={row.id + "contextMenu"}> <ContextMenu key={row.id + "contextMenu"}>
<ContextMenuTrigger asChild> <ContextMenuTrigger asChild>
<TableRow <TableRow
key={row.id} key={row.id}
data-state={row.getIsSelected() && "selected"} data-state={row.getIsSelected() && "selected"}
tabIndex={0} tabIndex={0}
onDoubleClick={() => {
if (tableName === "sub") {
openEditDialog(row)
}
}
}
> >
{row.getVisibleCells().map((cell) => ( {row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}> <TableCell key={cell.id}>
@ -243,6 +296,8 @@ export function DataTable<TData, TValue>({
key={"formContextMenu" + row.id} key={"formContextMenu" + row.id}
row={row} row={row}
table={table} table={table}
openEditDialog={openEditDialog}
openDeleteDialog={openDeleteDialog}
/> />
</TableRow> </TableRow>
</ContextMenuTrigger> </ContextMenuTrigger>

View File

@ -83,7 +83,7 @@ export function TextInputCell(props: CellContext<any, any>) {
<FormControl <FormControl
> >
<Input <Input
className="w-fit" className="w-full"
type="text" type="text"
autoFocus={true} autoFocus={true}
{...field} {...field}