From 330226ecd6e6ed8227ca05fb4f4fb571518e8b92 Mon Sep 17 00:00:00 2001 From: andrzej Date: Sun, 30 Jun 2024 17:36:44 +0200 Subject: [PATCH] implement inline text input --- prisma/dev.db | Bin 69632 -> 69632 bytes src/app/lib/update.ts | 7 +++-- src/app/publication/columns.tsx | 3 ++ src/app/publication/page.tsx | 2 +- src/app/story/page.tsx | 2 +- src/app/submission/create.tsx | 9 +++--- src/app/submission/page.tsx | 2 +- src/app/tailwind.css | 8 +++++ src/app/ui/inputs/textInput.tsx | 48 +++++++++++++++++++++++------- src/app/ui/tables/contextMenu.tsx | 28 ++++++++++++----- src/app/ui/tables/data-table.tsx | 13 ++++---- 11 files changed, 88 insertions(+), 34 deletions(-) diff --git a/prisma/dev.db b/prisma/dev.db index 4524a6696e345bf11f8c83185d382e15227b8208..62efc39f904de857bd7ab602404c78dad280ae7f 100644 GIT binary patch delta 442 zcmXBQ&r1|>7zXh7J3pMAad)0ATtaJcbSn}=R62C%vZU;3DcJDPWgXpNnI(6&9hXoq z?zPKga|}xV0l@}uf{-^6l-+}ZMnp@X5k@M4BK95PJw4C+ffwHSMQMIfdUu<(7VbP{ zt(Eb&&xSQs7H_ePRjyhx5k=HoZK668!v|{9uLx`C#cO16q+j9j{|Rmke%Jd`noRwD zELU-y%8ZdUi{`9dw%kI=wF@QNEe%XMQx8&Ni2S8|mmKDoekT7y!anr`pYjt%H)^B; z5?c6(Zp>l~X#g8o)z8D>hrZ}f>QO-@#_F+pjJ1nd2RV?s^#)l z5wfCgNF*fXgAv<&fBPP|zS;-~_+%6W_3h1~!A9KLKJyIulir6j5bbu($p& z#9JZ$g)RKW5A36fCdbQ&#yO2po1`+P`Hkb@n+kRbmpH>Q4mtgb-5@^x84J&&k*FGx LMec%w>$~xPf5L!+ delta 428 zcmXAl%S!@L6o>DfhdMR-vxkLbIYzZAFlkXsD-ePxDB9Y{NC@SiqeMI1wy~IHi~0+K z8rlUx?b`HkGoaF-l2{F)avA|gR>h%Mxhzyo3!{g2fW?LdGDfnXOkG*vVHu4-sQW+FK+ zgn5xz+sTv?X8j~YIo#k3CW=@<98sL$!1w8dH9Gbs%Q7bsO3U7|mp1d$dRCb#X39`Zz;fXXJB8)pBeOC<1Zh$&9+JFBQ{@8Ly1E zLf!0j%q&%crc#OYGz~Be(Dy>xD6HyD{SLX$4NWuJIDuHz%COSzf=%#+H$34MSFmx4 zQ!Daf!Appb@)Fz4O*zT3j|LsN>d23H#WiZEI$`oIWIt0q&c8C(ynK$ey3io_#s{8p Z&*TO!EdSy@HfLpz{Aao(tNzpH{{_$Pd6obG diff --git a/src/app/lib/update.ts b/src/app/lib/update.ts index 16d983b..333f030 100644 --- a/src/app/lib/update.ts +++ b/src/app/lib/update.ts @@ -21,12 +21,15 @@ export async function updateStory(data: Story & { genres: number[] }) { redirect("/story") } -export async function updateTextField({ text, table, column, id }: { text: string, table: string, column: string, id: number }) { - const res = prisma[table].update({ +export async function updateTextField({ text, table, column, id, pathname }: { text: string, table: string, column: string, id: number, pathname: string }) { + const res = await prisma[table].update({ where: { id }, data: { [column]: text } }) + console.log(`updated record in ${table}: ${res}`) + revalidatePath(pathname) + redirect(pathname) } diff --git a/src/app/publication/columns.tsx b/src/app/publication/columns.tsx index 5a37f33..44637d4 100644 --- a/src/app/publication/columns.tsx +++ b/src/app/publication/columns.tsx @@ -17,6 +17,7 @@ import Link from "next/link" import { PubsWithGenres } from "./page" import { DialogClose } from "@radix-ui/react-dialog" import { actions } from "app/ui/tables/actions" +import { TextInputCell } from "app/ui/inputs/textInput" const columnHelper = createColumnHelper() @@ -35,12 +36,14 @@ export const columns: ColumnDef[] = [ ) }, + cell: TextInputCell }, { accessorKey: "link", header: "Link", + cell: TextInputCell }, columnHelper.accessor("genres", { diff --git a/src/app/publication/page.tsx b/src/app/publication/page.tsx index d945b33..4162619 100644 --- a/src/app/publication/page.tsx +++ b/src/app/publication/page.tsx @@ -13,7 +13,7 @@ export default async function Page() { const pubs = await getPubsWithGenres() return (
- + diff --git a/src/app/story/page.tsx b/src/app/story/page.tsx index a75734b..66eeddf 100644 --- a/src/app/story/page.tsx +++ b/src/app/story/page.tsx @@ -21,7 +21,7 @@ export default async function Page() { return (
- + {/* TODO - EDIT STORY DIALOG */} diff --git a/src/app/submission/create.tsx b/src/app/submission/create.tsx index ffe1731..5ded6cc 100644 --- a/src/app/submission/create.tsx +++ b/src/app/submission/create.tsx @@ -1,13 +1,11 @@ "use client" -import { createStory, createSub } from "app/lib/create" +import { createSub } from "app/lib/create" import { Dialog, DialogHeader, DialogTrigger, DialogContent, DialogClose, DialogTitle, DialogFooter, DialogDescription } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { ComponentProps } from "react"; -import { Genre, Pub, Story } from "@prisma/client"; -import StoryForm from "app/ui/forms/story"; +import { Pub, Response, Story } from "@prisma/client"; import SubmissionForm from "app/ui/forms/sub"; -import { getPubs, getResponses, getStories } from "app/lib/get"; export default function CreateSubmissionDialog({ stories, pubs, responses }: ComponentProps<"div"> & { stories: Story[], pubs: Pub[], responses: Response[] }) { @@ -24,9 +22,10 @@ export default function CreateSubmissionDialog({ stories, pubs, responses }: Com + + - ) diff --git a/src/app/submission/page.tsx b/src/app/submission/page.tsx index 473f642..1eeb8d0 100644 --- a/src/app/submission/page.tsx +++ b/src/app/submission/page.tsx @@ -17,7 +17,7 @@ export default async function Page() { const responses = await getResponses() return (
- + { - const initialValue = getValue() - useEffect(() => { - setValue(initialValue) - }, [initialValue]) - const [value, setValue] = useState("") +export const TextInputCell = (props: CellContext) => { + let initialValue = props.getValue() + const [value, setValue] = useState(initialValue) const [isActive, setIsActive] = useState(false) + const table = props.table.options.meta.tableName + const id = props.row.original.id + const column = props.column.id + const pathname = props.table.options.meta.pathname + + function handleConfirm() { + updateTextField({ + id, + table, + text: value, + column, + pathname + }) + initialValue = value + handleClose() + } + function handleClose() { + setValue(initialValue) + setIsActive(false) + } + function handleKeyDown(event: React.KeyboardEvent) { + if (event.code === "Enter") { + handleConfirm() + } + } + + return (
setIsActive(prev => !prev)} + className="w-full h-fit flex items-center justify-center" > {isActive ?
setValue(e.target.value)} - onBlur={() => setIsActive(false)} + onChange={e => setValue(e.target.value)} // onBlur={handleClose} autoFocus={true} + onKeyDown={handleKeyDown} />
- - + +
:

{value}

diff --git a/src/app/ui/tables/contextMenu.tsx b/src/app/ui/tables/contextMenu.tsx index c237519..dbae76d 100644 --- a/src/app/ui/tables/contextMenu.tsx +++ b/src/app/ui/tables/contextMenu.tsx @@ -1,14 +1,16 @@ import { Dialog, DialogTrigger, DialogClose, DialogDescription, DialogContent, DialogTitle, DialogHeader, DialogFooter } from "@/components/ui/dialog" import { Button } from "@/components/ui/button" -import { ContextMenuContent, ContextMenuItem } from "@/components/ui/context-menu" +import { ContextMenuContent, ContextMenuItem, ContextMenuSubTrigger, ContextMenuSeparator, ContextMenuSub, ContextMenuSubContent } from "@/components/ui/context-menu" import { deleteRecord } from "app/lib/del" import { Trash2 } from "lucide-react" import Link from "next/link" -import { ContextMenuSeparator } from "@radix-ui/react-context-menu" - -export default function FormContextMenu({ pathname, row, selectedRows, deselect }) { - +import { ComponentProps } from "react" +import { Row, Table, TableState } from "@tanstack/react-table" +import { letterCase } from "app/lib/functions" +export default function FormContextMenu({ table, row }: ComponentProps<"div"> & { table: Table, row: Row }) { + const pathname = table.options.meta.pathname + const selectedRows = table.getSelectedRowModel().flatRows return ( @@ -17,13 +19,25 @@ export default function FormContextMenu({ pathname, row, selectedRows, deselect Inspect - Edit : "" } + { + selectedRows.length <= 1 ? + + Edit + + {Object.keys(row.original).map(e => { + if (e !== "id") { + return {letterCase(e)} + } + })} + + : "" + } { selectedRows ? - Deselect + { table.resetRowSelection() }}>Deselect : "" } diff --git a/src/app/ui/tables/data-table.tsx b/src/app/ui/tables/data-table.tsx index 91dab39..26097d0 100644 --- a/src/app/ui/tables/data-table.tsx +++ b/src/app/ui/tables/data-table.tsx @@ -55,8 +55,9 @@ export interface DataTableProps { export function DataTable({ columns, data, - children -}: DataTableProps & ComponentProps<"div">) { + children, + tableName +}: DataTableProps & ComponentProps<"div"> & { tableName: string }) { //STATE const [sorting, setSorting] = useState([]) const [columnFilters, setColumnFilters] = useState( @@ -65,6 +66,7 @@ export function DataTable({ const [columnVisibility, setColumnVisibility] = useState({}) // + const pathname: Pathname = usePathname() const table = useReactTable({ data, columns, @@ -85,13 +87,14 @@ export function DataTable({ //this is where you put arbitrary functions etc to make them accessible via the table api meta: { updateTextField, + tableName, + pathname } }) - const pathname: Pathname = usePathname() const [filterBy, setFilterBy] = useState(table.getAllColumns()[0]) const [isContextMenuOpen, setIsContextMenuOpen] = useState(false) return (<> @@ -227,10 +230,8 @@ export function DataTable({ ))}