diff --git a/src/app/api/auth/actions.ts b/src/app/api/auth/actions.ts index 8d9944e..96dd094 100644 --- a/src/app/api/auth/actions.ts +++ b/src/app/api/auth/actions.ts @@ -9,7 +9,7 @@ export async function getJWTSecretKey() { const secret = process.env.JWT_SECRET if (!secret) throw new Error("There is no JWT secret key") try { - const enc: Uint8Array = new TextEncoder().encode(secret) + const enc = new TextEncoder().encode(secret) return enc } catch (error) { throw new Error("failed to getJWTSecretKey", error.message) diff --git a/src/app/lib/create.ts b/src/app/lib/create.ts index fa99386..022b882 100644 --- a/src/app/lib/create.ts +++ b/src/app/lib/create.ts @@ -8,15 +8,16 @@ import { storySchema } from "app/ui/forms/schemas" import { pubSchema } from "app/ui/forms/schemas" import { subSchema } from "app/ui/forms/schemas" import { prepGenreData, prepStoryData } from "./validate" +import { SubForm } from "app/ui/forms/sub" //TODO - data validation, error handling, unauthorized access handling -export async function createStory(data: Story & { genres: number[] }): Promise<{ success: string }> { +export async function createStory({ story, genres }: { story: Story, genres: number[] }): Promise<{ success: string }> { // will return undefined if middleware authorization fails "use server" try { - const storyData = await prepStoryData(data) - const genresArray = await prepGenreData(data.genres) + const storyData = await prepStoryData(story) + const genresArray = await prepGenreData(genres) //submit const res = await prisma.story.create({ data: storyData }) @@ -27,24 +28,17 @@ export async function createStory(data: Story & { genres: number[] }): Promise<{ } }) revalidatePath("/story") - return { success: `Created the story '${data.title}'.` } + return { success: `Created the story '${story.title}'.` } } catch (error) { console.error(error) - return false } } -export async function createPub(data: Pub & { genres: number[] }): Promise<{ success: string }> { +export async function createPub({ pub, genres }: { pub: Pub, genres: number[] }): Promise<{ success: string }> { "use server" - //prepare data - const pubData = { - title: data.title, - link: data.link, - query_after_days: data.query_after_days - } - const genresArray = data.genres.map(e => { return { id: e } }) + const genresArray = genres.map(e => { return { id: e } }) //prepare schemas const schema = pubSchema.omit({ genres: true }) @@ -54,12 +48,12 @@ export async function createPub(data: Pub & { genres: number[] }): Promise<{ suc try { //validate - schema.parse(pubData) + schema.parse(pub) genresSchema.safeParse(genresArray) //submit const res = await prisma.pub.create({ - data: pubData + data: pub }) const genresRes = await prisma.pub.update({ where: { id: res.id }, @@ -67,10 +61,9 @@ export async function createPub(data: Pub & { genres: number[] }): Promise<{ suc { genres: { set: genresArray } } }) revalidatePath("/publication") - return { success: `Created the publication '${data.title}'.` } + return { success: `Created the publication '${pub.title}'.` } } catch (error) { console.error(error) - return false } } diff --git a/src/app/lib/del.ts b/src/app/lib/del.ts index 499551a..c4877bd 100644 --- a/src/app/lib/del.ts +++ b/src/app/lib/del.ts @@ -10,9 +10,10 @@ const tableMap = { "/submission": "sub" } -export async function deleteRecord(id: number, pathname: Pathname): Promise { +export async function deleteRecord(id: number, pathname: string): Promise { const table = tableMap[pathname] try { + //@ts-ignore const res = await prisma[table].delete({ where: { id } }) console.log(`deleted from ${table}: ${res.id}`) revalidatePath(pathname) diff --git a/src/app/lib/pluralize.ts b/src/app/lib/pluralize.ts index 1e5fda4..d5369cb 100644 --- a/src/app/lib/pluralize.ts +++ b/src/app/lib/pluralize.ts @@ -1,4 +1,4 @@ -export default function pluralize(word: "story" | "publication" | "submission"): string { +export default function pluralize(word: string): string { const map = { story: "stories", publication: "publications", diff --git a/src/app/lib/update.ts b/src/app/lib/update.ts index 576e222..7a41579 100644 --- a/src/app/lib/update.ts +++ b/src/app/lib/update.ts @@ -3,11 +3,8 @@ import { prepGenreData, prepPubData, prepStoryData } from "./validate" import { Genre, Pub, Story, Sub } from "@prisma/client" import prisma from "./db" import { revalidatePath } from "next/cache" -import { redirect } from "next/navigation" -import { storySchema, subSchema } from "app/ui/forms/schemas" -import { z } from "zod" -import { StoryWithGenres } from "app/story/page" -import { PubWithGenres } from "app/publication/page" +import { subSchema } from "app/ui/forms/schemas" +import { SubForm } from "app/ui/forms/sub" export async function updateField({ datum, table, column, id, pathname }: { datum?: string | number | Genre[], table: string, column: string, id: number, pathname: string }) { @@ -46,7 +43,7 @@ export async function updateGenres({ genres, table, id, pathname }: { genres: { } } -export async function updateSub(data: Sub): Promise { +export async function updateSub(data: SubForm): Promise { "use server" try { subSchema.parse(data) @@ -60,7 +57,7 @@ export async function updateSub(data: Sub): Promise { } -export async function updateStory(data: StoryWithGenres): Promise<{ success: string }> { +export async function updateStory(data: Story & { genres: number[] }): Promise<{ success: string }> { "use server" try { @@ -86,7 +83,7 @@ export async function updateStory(data: StoryWithGenres): Promise<{ success: str } -export async function updatePub(data: PubWithGenres): Promise<{ success: string }> { +export async function updatePub(data: Pub & { genres: number[] }): Promise<{ success: string }> { "use server" try { diff --git a/src/app/lib/validate.ts b/src/app/lib/validate.ts index 6c30724..318eacd 100644 --- a/src/app/lib/validate.ts +++ b/src/app/lib/validate.ts @@ -11,17 +11,15 @@ const pubSchemaTrimmed = pubSchema.omit({ genres: true }) const genreSchema = z.object({ id: z.number() }) const genresSchema = z.array(genreSchema) -export async function prepStoryData(data: StoryWithGenres): Promise<{ title: string, word_count: number }> { +export async function prepStoryData(data: Story): Promise<{ title: string, word_count: number }> { const storyData = structuredClone(data) - delete storyData.genres //throw an error if validation fails storySchemaTrimmed.safeParse(storyData) return storyData } -export async function prepPubData(data: Pub & { genres: number[] }): Promise { +export async function prepPubData(data: Pub): Promise { const pubData = structuredClone(data) - delete pubData.genres pubSchemaTrimmed.safeParse(pubData) return pubData } diff --git a/src/app/publication/[id]/page.tsx b/src/app/publication/[id]/page.tsx index 2287750..28a9c41 100644 --- a/src/app/publication/[id]/page.tsx +++ b/src/app/publication/[id]/page.tsx @@ -31,7 +31,7 @@ export default async function Page({ params }: { params: { id: string } }) { {pub.title} Submissions: - + ) } diff --git a/src/app/publication/columns.tsx b/src/app/publication/columns.tsx index bac57ab..e8f1730 100644 --- a/src/app/publication/columns.tsx +++ b/src/app/publication/columns.tsx @@ -32,6 +32,7 @@ export const columns: ColumnDef[] = [ }, cell: cell => ( <> + {/* @ts-ignore */}

{cell.getValue()}

@@ -49,6 +50,7 @@ export const columns: ColumnDef[] = [ ), cell: cell => ( <> + {/* @ts-ignore */}

{cell.getValue()}

@@ -78,6 +80,7 @@ export const columns: ColumnDef[] = [ ), cell: cell => ( <> + {/* @ts-ignore */}

{cell.getValue()}

diff --git a/src/app/publication/edit.tsx b/src/app/publication/edit.tsx index e7162c8..2ca4a6a 100644 --- a/src/app/publication/edit.tsx +++ b/src/app/publication/edit.tsx @@ -2,14 +2,14 @@ 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 } from "@prisma/client"; +import { Genre, Pub } from "@prisma/client"; import { createPub } from "app/lib/create"; import PubForm from "app/ui/forms/pub"; import { Plus } from "lucide-react"; import { useState } from "react"; import { PubWithGenres } from "./page"; -export default function EditPubDialog({ genres, closeDialog, defaults, dbAction }: ComponentProps<"div"> & { genres: Genre[], closeDialog: () => void, defaults: PubWithGenres, dbAction: (data: PubWithGenres) => Promise<{ success: string }> }) { +export default function EditPubDialog({ genres, closeDialog, defaults, dbAction }: ComponentProps<"div"> & { genres: Genre[], closeDialog: () => void, defaults: PubWithGenres, dbAction: (data: Pub & { genres: number[] }) => Promise<{ success: string }> }) { return ( diff --git a/src/app/story/columns.tsx b/src/app/story/columns.tsx index 6ff72ee..a9e2bda 100644 --- a/src/app/story/columns.tsx +++ b/src/app/story/columns.tsx @@ -31,6 +31,7 @@ export const columns: ColumnDef[] = [ }, cell: cell => ( <> + {/* @ts-ignore */}

{cell.getValue()}

@@ -59,6 +60,7 @@ export const columns: ColumnDef[] = [ enableColumnFilter: false, cell: cell => ( <> + {/* @ts-ignore */}

{cell.getValue()}

diff --git a/src/app/story/create/page.tsx b/src/app/story/create/page.tsx index 00f9027..5d7546a 100644 --- a/src/app/story/create/page.tsx +++ b/src/app/story/create/page.tsx @@ -4,9 +4,10 @@ import prisma from "app/lib/db"; import { revalidatePath } from "next/cache"; import { redirect } from "next/navigation"; import { CreateContainerContent, CreateContainerHeader, CreateContainer, CreateContainerDescription } from "app/ui/createContainer"; +import { Story } from "@prisma/client"; export default async function Page() { const genres = await getGenres() - async function createStory(data) { + async function createStory(data: Story & { genres: number[] }): Promise<{ success: string }> { "use server" const genresArray = data.genres.map(e => { return { id: e } }) const res = await prisma.story.create({ @@ -26,12 +27,14 @@ export default async function Page() { revalidatePath("/story") redirect("/story") } + + return ( New story Make an entry for a new work of fiction i.e. a thing you intend to submit for publication. - + ) diff --git a/src/app/story/edit.tsx b/src/app/story/edit.tsx index 72474ff..78551eb 100644 --- a/src/app/story/edit.tsx +++ b/src/app/story/edit.tsx @@ -2,12 +2,12 @@ import { DialogHeader, DialogTitle, DialogFooter, DialogDescription } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { ComponentProps, useState } from "react"; -import { Genre } from "@prisma/client"; +import { Genre, Story } from "@prisma/client"; import StoryForm from "app/ui/forms/story"; import { StoryWithGenres } from "./page"; -export default function EditStoryDialog({ genres, closeDialog, defaults, dbAction }: ComponentProps<"div"> & { genres: Genre[], closeDialog: () => void, defaults: StoryWithGenres, dbAction: (data: StoryWithGenres) => Promise<{ success: string }> }) { +export default function EditStoryDialog({ genres, closeDialog, defaults, dbAction }: ComponentProps<"div"> & { genres: Genre[], closeDialog: () => void, defaults: StoryWithGenres, dbAction: (data: Story & { genres: number[] }) => Promise<{ success: string }> }) { return ( diff --git a/src/app/submission/create/page.tsx b/src/app/submission/create/page.tsx index ad883cc..fb5bfa8 100644 --- a/src/app/submission/create/page.tsx +++ b/src/app/submission/create/page.tsx @@ -10,19 +10,12 @@ export default async function Page() { const stories = await getStories() const pubs = await getPubs() const responses = await getResponses() - async function createSub(data) { - "use server" - const res = await prisma.sub.create({ data }) - console.log(res) - revalidatePath("/submission") - redirect("/submission") - } return ( New submission - + ) diff --git a/src/app/test/page.tsx b/src/app/test/page.tsx deleted file mode 100644 index 7ebf44c..0000000 --- a/src/app/test/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import { CheckboxReactHookFormMultiple } from "app/ui/forms/Checkboxdemo"; - -export default function Page() { - return ( - - ) -} diff --git a/src/app/ui/forms/editSub.tsx b/src/app/ui/forms/editSub.tsx index 2e10ad2..945cc4d 100644 --- a/src/app/ui/forms/editSub.tsx +++ b/src/app/ui/forms/editSub.tsx @@ -56,13 +56,13 @@ export default function EditSubmissionForm({ stories, pubs, responses, defaults, )) const pubsSelectItems = pubs.map(e => ( - + {e.title} )) const reponsesSelectItems = responses.map(e => ( - + {e.response} )) @@ -106,7 +106,7 @@ export default function EditSubmissionForm({ stories, pubs, responses, defaults, render={({ field }) => ( Story - @@ -129,7 +129,7 @@ export default function EditSubmissionForm({ stories, pubs, responses, defaults, render={({ field }) => ( Publication - @@ -173,9 +173,8 @@ export default function EditSubmissionForm({ stories, pubs, responses, defaults, - { field.onChange(e); setIsSubCalendarOpen(false); }} disabled={(date) => date > new Date() || date < new Date("1900-01-01") @@ -218,10 +217,8 @@ export default function EditSubmissionForm({ stories, pubs, responses, defaults, - { field.onChange(e); setIsRespCalendarOpen(false); }} + {/* @ts-ignore */} + { field.onChange(e); setIsRespCalendarOpen(false); }} disabled={(date) => date > new Date() || date < new Date("1900-01-01") } @@ -244,7 +241,7 @@ export default function EditSubmissionForm({ stories, pubs, responses, defaults, render={({ field }) => ( Response - diff --git a/src/app/ui/forms/pub.tsx b/src/app/ui/forms/pub.tsx index 3580880..422913a 100644 --- a/src/app/ui/forms/pub.tsx +++ b/src/app/ui/forms/pub.tsx @@ -40,7 +40,14 @@ export default function PubForm({ genres, dbAction, className, closeDialog, defa async function onSubmit(values: z.infer) { try { - const res = await dbAction(values) + const res = await dbAction({ + pub: { + id: values?.id, + title: values.title, + link: values.link, + query_after_days: values.query_after_days + }, genres: values.genres + }) if (!res?.success) throw new Error("something went wrong") toast({ title: "Success!", description: res.success }) router.refresh() diff --git a/src/app/ui/forms/story.tsx b/src/app/ui/forms/story.tsx index 1945104..7e02965 100644 --- a/src/app/ui/forms/story.tsx +++ b/src/app/ui/forms/story.tsx @@ -30,7 +30,7 @@ export const formSchema = z.object({ genres: z.array(z.number()) }) -export default function StoryForm({ genres, dbAction, className, closeDialog, defaults }: ComponentProps<"div"> & { genres: Array, dbAction: (data: any) => Promise<{ success: string }>, className: string, closeDialog: () => void, defaults?: StoryWithGenres }) { +export default function StoryForm({ genres, dbAction, className, closeDialog, defaults }: ComponentProps<"div"> & { genres: Array, dbAction: (data: any) => Promise<{ success: string }>, className: string, closeDialog?: () => void, defaults?: StoryWithGenres }) { const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { @@ -40,13 +40,19 @@ export default function StoryForm({ genres, dbAction, className, closeDialog, de genres: defaults?.genres.map(e => e.id) ?? [] }, }) - console.log("DEFAULTS: " + defaults) const router = useRouter() async function onSubmit(values: z.infer) { try { - const res = await dbAction(values) + const res = await dbAction({ + story: { + id: values?.id, + title: values.title, + word_count: values.word_count, + }, + genres: values.genres + }) //server actions return undefined if middleware authentication fails if (!res?.success) throw new Error("something went wrong") toast({ title: "Success!", description: res.success }) diff --git a/src/app/ui/forms/sub.tsx b/src/app/ui/forms/sub.tsx index 0dd2005..6035f04 100644 --- a/src/app/ui/forms/sub.tsx +++ b/src/app/ui/forms/sub.tsx @@ -36,11 +36,12 @@ import { createSub } from "app/lib/create" import { subSchema } from "./schemas" import { useRouter } from "next/navigation" import { Ban } from "lucide-react" +import { Story } from "@prisma/client" export type SubForm = z.infer -export default function SubmissionForm({ stories, pubs, responses, defaults, closeDialog }: { stories: any, pubs: any, responses: any, defaults?: any, closeDialog: () => void }) { +export default function SubmissionForm({ stories, pubs, responses, defaults, closeDialog }: { stories: any, pubs: any, responses: any, defaults?: any, closeDialog?: () => void }) { const form = useForm>({ resolver: zodResolver(subSchema), defaultValues: { @@ -50,19 +51,19 @@ export default function SubmissionForm({ stories, pubs, responses, defaults, clo }) const [isSubCalendarOpen, setIsSubCalendarOpen] = useState(false); const [isRespCalendarOpen, setIsRespCalendarOpen] = useState(false); - const storiesSelectItems = stories.map(e => ( - + const storiesSelectItems = stories.map((e: Story) => ( + {e.title} )) const pubsSelectItems = pubs.map(e => ( - + {e.title} )) const reponsesSelectItems = responses.map(e => ( - + {e.response} )) @@ -71,6 +72,7 @@ export default function SubmissionForm({ stories, pubs, responses, defaults, clo async function onSubmit(values: z.infer) { try { + //@ts-ignore const res = await createSub(values) if (!res) throw new Error("something went wrong") toast({ title: "Successfully created new submission!" }) @@ -102,7 +104,7 @@ export default function SubmissionForm({ stories, pubs, responses, defaults, clo render={({ field }) => ( Story - @@ -125,7 +127,7 @@ export default function SubmissionForm({ stories, pubs, responses, defaults, clo render={({ field }) => ( Publication - @@ -169,9 +171,8 @@ export default function SubmissionForm({ stories, pubs, responses, defaults, clo - { field.onChange(e); setIsSubCalendarOpen(false); }} disabled={(date) => date > new Date() || date < new Date("1900-01-01") @@ -214,9 +215,8 @@ export default function SubmissionForm({ stories, pubs, responses, defaults, clo - { field.onChange(e); setIsRespCalendarOpen(false); }} disabled={(date) => date > new Date() || date < new Date("1900-01-01") @@ -240,7 +240,7 @@ export default function SubmissionForm({ stories, pubs, responses, defaults, clo render={({ field }) => ( Response - diff --git a/src/app/ui/tables/contextMenu.tsx b/src/app/ui/tables/contextMenu.tsx index 2a41b25..5aa5d60 100644 --- a/src/app/ui/tables/contextMenu.tsx +++ b/src/app/ui/tables/contextMenu.tsx @@ -4,6 +4,7 @@ import { ComponentProps, useState } from "react" import { Row, Table, TableState } from "@tanstack/react-table" export default function FormContextMenu({ table, row, openEditDialog, openDeleteDialog }: ComponentProps<"div"> & { table: Table, row: Row, openEditDialog: (row: Row) => void, openDeleteDialog: (row: Row) => void }) { + //@ts-ignore const pathname = table.options.meta.pathname const selectedRows = table.getSelectedRowModel().flatRows diff --git a/src/app/ui/tables/data-table.tsx b/src/app/ui/tables/data-table.tsx index f53f217..d31944a 100644 --- a/src/app/ui/tables/data-table.tsx +++ b/src/app/ui/tables/data-table.tsx @@ -82,7 +82,7 @@ export function DataTable({ const [columnVisibility, setColumnVisibility] = useState({}) // - const pathname: Pathname = usePathname() + const pathname: string = usePathname() const table = useReactTable({ data, columns, @@ -141,17 +141,13 @@ export function DataTable({ + {/*@ts-ignore*/} {table .getAllColumns() .filter((column) => column.getCanFilter()) - .map((column) => { - return ( - - {column.id} - - ) - })} + //@ts-ignore + .map((column) => { return ( {column.id} ) })} @@ -234,6 +230,7 @@ export function DataTable({ {`Delete ${Object.keys(table.getState().rowSelection).length} ${pluralize(pathname.slice(1))}?`} + {/* @ts-ignore */} {`Deleting ${pluralize(tableNameToItemName(table.options.meta.tableName))} cannot be undone!`} @@ -241,7 +238,9 @@ export function DataTable({ onClick={async () => { const selectedRows = table.getState().rowSelection const rowIds = Object.keys(selectedRows) + //@ts-ignore const recordIds = rowIds.map(id => Number(table.getRow(id).original.id)) + //@ts-ignore const res = await deleteRecords(recordIds, pathname) if (!res) toast({ title: "Oh dear...", description: "Failed to delete." }) if (res) toast({ title: "Successfully deleted records of id:", description: JSON.stringify(recordIds) }) diff --git a/src/app/ui/tables/inputs/genrePickerInput.tsx b/src/app/ui/tables/inputs/genrePickerInput.tsx index c384b73..654eee1 100644 --- a/src/app/ui/tables/inputs/genrePickerInput.tsx +++ b/src/app/ui/tables/inputs/genrePickerInput.tsx @@ -3,7 +3,7 @@ import { FormField, FormItem, FormLabel, FormMessage, FormControl, Form } from " import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover" import { Button } from "@/components/ui/button" import { Checkbox } from "@/components/ui/checkbox" -import { ComponentProps, useState } from "react" +import { BaseSyntheticEvent, ComponentProps, EventHandler, useState } from "react" import { EventType, useForm, UseFormReturn } from "react-hook-form" import { CellContext } from "@tanstack/react-table" import { z } from "zod" @@ -16,16 +16,18 @@ import { useRouter } from "next/navigation" export default function GenrePickerInputCell(props: CellContext) { - + //@ts-ignore const table = props.table.options.meta.tableName + //@ts-ignore const pathname = props.table.options.meta.pathname const id = props.row.original.id const column = props.column.id const value = props.cell.getValue() + //@ts-ignore const genres = props.table.options.meta.genres const [isActive, setIsActive] = useState(false) const router = useRouter() - async function onSubmit({ genres }: { genres: number[] }, event: Event) { + async function onSubmit({ genres }: { genres: number[] }, event: BaseSyntheticEvent) { event.preventDefault() try { const genresArray = genres.map((e) => { return { id: e } }) diff --git a/src/app/ui/tables/inputs/numberInput.tsx b/src/app/ui/tables/inputs/numberInput.tsx index d4571ef..938ec69 100644 --- a/src/app/ui/tables/inputs/numberInput.tsx +++ b/src/app/ui/tables/inputs/numberInput.tsx @@ -12,11 +12,14 @@ import { Form, FormControl, FormField, FormItem, FormMessage } from "@/component export default function NumberInputCell({ cellContext, className }: { cellContext: CellContext, className: string }) { const [isActive, setIsActive] = useState(false) + //@ts-ignore const table = cellContext.table.options.meta.tableName const id = cellContext.row.original.id const column = cellContext.column.id + //@ts-ignore const pathname = cellContext.table.options.meta.pathname const value = cellContext.cell.getValue() + //@ts-ignore const formSchema = cellContext.column.columnDef.meta.formSchema.pick({ [column]: true }) const form = useForm>({ @@ -77,13 +80,8 @@ export default function NumberInputCell({ cellContext, className }: { cellContex > - + {/* @ts-ignore */} + diff --git a/src/app/ui/tables/inputs/textInput.tsx b/src/app/ui/tables/inputs/textInput.tsx index 1be4ea5..304ad1e 100644 --- a/src/app/ui/tables/inputs/textInput.tsx +++ b/src/app/ui/tables/inputs/textInput.tsx @@ -13,15 +13,14 @@ import { useRouter } from "next/navigation"; export function TextInputCell({ cellContext, className }: { className: string, cellContext: CellContext }) { const [isActive, setIsActive] = useState(false) - if (cellContext === undefined) { - console.error("CELL CONTEXT UNDEFINED!") - return false - } + //@ts-ignore const table = cellContext.table.options.meta.tableName const id = cellContext.row.original.id const column = cellContext.column.id + //@ts-ignore const pathname = cellContext.table.options.meta.pathname const value = cellContext.cell.getValue() + //@ts-ignore const formSchema = cellContext.column.columnDef.meta.formSchema.pick({ [column]: true }) const form = useForm>({