implement 'edit' functionality for pubs
This commit is contained in:
parent
9bc1750848
commit
5b4e961859
BIN
prisma/dev.db
BIN
prisma/dev.db
Binary file not shown.
|
@ -6,6 +6,8 @@ import { revalidatePath } from "next/cache"
|
||||||
import { redirect } from "next/navigation"
|
import { redirect } from "next/navigation"
|
||||||
import { storySchema, subSchema } from "app/ui/forms/schemas"
|
import { storySchema, subSchema } from "app/ui/forms/schemas"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
import { StoryWithGenres } from "app/story/page"
|
||||||
|
import { PubWithGenres } from "app/publication/page"
|
||||||
|
|
||||||
|
|
||||||
export async function updateField({ datum, table, column, id, pathname }: { datum?: string | number | Genre[], table: string, column: string, id: number, pathname: string }) {
|
export async function updateField({ datum, table, column, id, pathname }: { datum?: string | number | Genre[], table: string, column: string, id: number, pathname: string }) {
|
||||||
|
@ -22,7 +24,7 @@ export async function updateField({ datum, table, column, id, pathname }: { datu
|
||||||
return res
|
return res
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
return false
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,11 +42,11 @@ export async function updateGenres({ genres, table, id, pathname }: { genres: {
|
||||||
return res
|
return res
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
return false
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateSub(data: Sub): Promise<Sub | boolean> {
|
export async function updateSub(data: Sub): Promise<Sub> {
|
||||||
"use server"
|
"use server"
|
||||||
try {
|
try {
|
||||||
subSchema.parse(data)
|
subSchema.parse(data)
|
||||||
|
@ -53,12 +55,12 @@ export async function updateSub(data: Sub): Promise<Sub | boolean> {
|
||||||
return res
|
return res
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
return false
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function updateStory(data: Story & { genres: number[] }): Promise<Story | boolean> {
|
export async function updateStory(data: StoryWithGenres): Promise<{ success: string }> {
|
||||||
"use server"
|
"use server"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -66,25 +68,25 @@ export async function updateStory(data: Story & { genres: number[] }): Promise<S
|
||||||
const storyData = await prepStoryData(data)
|
const storyData = await prepStoryData(data)
|
||||||
const genresArray = await prepGenreData(data.genres)
|
const genresArray = await prepGenreData(data.genres)
|
||||||
//submit
|
//submit
|
||||||
const res = prisma.story.update({
|
const res = await prisma.story.update({
|
||||||
where: { id: data.id },
|
where: { id: data.id },
|
||||||
data: storyData
|
data: storyData
|
||||||
})
|
})
|
||||||
await prisma.story.update({
|
const genreRes = await prisma.story.update({
|
||||||
where: { id: data.id },
|
where: { id: data.id },
|
||||||
data: {
|
data: {
|
||||||
genres: { set: genresArray }
|
genres: { set: genresArray }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return res
|
return { success: "Updated the story '" + res.title + "'." }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
return false
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function updatePub(data: Pub & { genres: number[] }): Promise<Pub | boolean> {
|
export async function updatePub(data: PubWithGenres): Promise<{ success: string }> {
|
||||||
"use server"
|
"use server"
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -93,7 +95,7 @@ export async function updatePub(data: Pub & { genres: number[] }): Promise<Pub |
|
||||||
(data)
|
(data)
|
||||||
const genresArray = await prepGenreData(data.genres)
|
const genresArray = await prepGenreData(data.genres)
|
||||||
//submit
|
//submit
|
||||||
const res = prisma.pub.update({
|
const res = await prisma.pub.update({
|
||||||
where: { id: data.id },
|
where: { id: data.id },
|
||||||
data: pubData
|
data: pubData
|
||||||
})
|
})
|
||||||
|
@ -103,10 +105,10 @@ export async function updatePub(data: Pub & { genres: number[] }): Promise<Pub |
|
||||||
genres: { set: genresArray }
|
genres: { set: genresArray }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return res
|
return { success: "Updated the publication '" + res.title + "'" }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
return false
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { z } from "zod";
|
||||||
import { storySchema } from "app/ui/forms/schemas";
|
import { storySchema } from "app/ui/forms/schemas";
|
||||||
import { Pub, Story } from "@prisma/client";
|
import { Pub, Story } from "@prisma/client";
|
||||||
import { pubSchema } from "app/ui/forms/schemas";
|
import { pubSchema } from "app/ui/forms/schemas";
|
||||||
|
import { StoryWithGenres } from "app/story/page";
|
||||||
|
|
||||||
//schemas
|
//schemas
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ const pubSchemaTrimmed = pubSchema.omit({ genres: true })
|
||||||
const genreSchema = z.object({ id: z.number() })
|
const genreSchema = z.object({ id: z.number() })
|
||||||
const genresSchema = z.array(genreSchema)
|
const genresSchema = z.array(genreSchema)
|
||||||
|
|
||||||
export async function prepStoryData(data: Story & { genres: number[] }): Promise<{ title: string, word_count: number }> {
|
export async function prepStoryData(data: StoryWithGenres): Promise<{ title: string, word_count: number }> {
|
||||||
const storyData = structuredClone(data)
|
const storyData = structuredClone(data)
|
||||||
delete storyData.genres
|
delete storyData.genres
|
||||||
//throw an error if validation fails
|
//throw an error if validation fails
|
||||||
|
@ -18,7 +19,7 @@ export async function prepStoryData(data: Story & { genres: number[] }): Promise
|
||||||
return storyData
|
return storyData
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function prepPubData(data: Pub & { genres: number[] }): Promise<Pub | Boolean> {
|
export async function prepPubData(data: Pub & { genres: number[] }): Promise<Pub> {
|
||||||
const pubData = structuredClone(data)
|
const pubData = structuredClone(data)
|
||||||
delete pubData.genres
|
delete pubData.genres
|
||||||
pubSchemaTrimmed.safeParse(pubData)
|
pubSchemaTrimmed.safeParse(pubData)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
|
import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
|
||||||
import { ArrowUpDown, BookType, Clock, Drama, SquareArrowOutUpRight } from "lucide-react"
|
import { ArrowUpDown, BookType, Clock, Drama, SquareArrowOutUpRight } from "lucide-react"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { PubsWithGenres } from "./page"
|
import { PubWithGenres } from "./page"
|
||||||
import { TextInputCell } from "app/ui/tables/inputs/textInput"
|
import { TextInputCell } from "app/ui/tables/inputs/textInput"
|
||||||
import { selectCol } from "app/ui/tables/selectColumn"
|
import { selectCol } from "app/ui/tables/selectColumn"
|
||||||
import NumberInputCell from "app/ui/tables/inputs/numberInput"
|
import NumberInputCell from "app/ui/tables/inputs/numberInput"
|
||||||
|
@ -10,9 +10,9 @@ import { pubSchema } from "app/ui/forms/schemas"
|
||||||
import GenrePickerInputCell from "app/ui/tables/inputs/genrePickerInput"
|
import GenrePickerInputCell from "app/ui/tables/inputs/genrePickerInput"
|
||||||
|
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<PubsWithGenres>()
|
const columnHelper = createColumnHelper<PubWithGenres>()
|
||||||
|
|
||||||
export const columns: ColumnDef<PubsWithGenres>[] = [
|
export const columns: ColumnDef<PubWithGenres>[] = [
|
||||||
selectCol,
|
selectCol,
|
||||||
{
|
{
|
||||||
accessorKey: "title",
|
accessorKey: "title",
|
||||||
|
@ -26,7 +26,7 @@ export const columns: ColumnDef<PubsWithGenres>[] = [
|
||||||
Title
|
Title
|
||||||
</span>
|
</span>
|
||||||
<span className="block sm:hidden"><BookType /></span>
|
<span className="block sm:hidden"><BookType /></span>
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
<ArrowUpDown className="ml-2 h-4 w-4 hidden md:block" />
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,34 +7,23 @@ import { createPub } from "app/lib/create";
|
||||||
import PubForm from "app/ui/forms/pub";
|
import PubForm from "app/ui/forms/pub";
|
||||||
import { Plus } from "lucide-react";
|
import { Plus } from "lucide-react";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { PubWithGenres } from "./page";
|
||||||
|
|
||||||
export default function CreatePubDialog({ genres }: ComponentProps<"div"> & { genres: Genre[] }) {
|
export default function EditPubDialog({ genres, closeDialog, defaults, dbAction }: ComponentProps<"div"> & { genres: Genre[], closeDialog: () => void, defaults: PubWithGenres, dbAction: (data: PubWithGenres) => Promise<{ success: string }> }) {
|
||||||
|
|
||||||
const [isOpen, setIsOpen] = useState(false)
|
|
||||||
function closeDialog() {
|
|
||||||
setIsOpen(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
<>
|
||||||
<DialogTrigger asChild>
|
<DialogHeader>
|
||||||
<Button>
|
<DialogTitle>Edit publication</DialogTitle>
|
||||||
<span className="hidden md:block">Create new publication</span>
|
<DialogDescription>Modify an entry for an existing publication.</DialogDescription>
|
||||||
<Plus className="block md:hidden" />
|
</DialogHeader>
|
||||||
</Button>
|
<PubForm dbAction={dbAction} genres={genres} closeDialog={closeDialog} defaults={defaults} />
|
||||||
</DialogTrigger>
|
<DialogFooter>
|
||||||
<DialogContent>
|
<Button form="pubform">Submit</Button>
|
||||||
<DialogHeader>
|
</DialogFooter>
|
||||||
<DialogTitle>Edit publication</DialogTitle>
|
</>
|
||||||
<DialogDescription>Modify an entry for an existing publication.</DialogDescription>
|
|
||||||
</DialogHeader>
|
|
||||||
<PubForm dbAction={createPub} genres={genres} closeDialog={closeDialog} />
|
|
||||||
<DialogFooter>
|
|
||||||
<Button form="pubform">Submit</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
|
|
||||||
</DialogContent>
|
|
||||||
</Dialog>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { columns } from "./columns";
|
||||||
import { DataTable } from "app/ui/tables/data-table";
|
import { DataTable } from "app/ui/tables/data-table";
|
||||||
import CreatePubDialog from "./create";
|
import CreatePubDialog from "./create";
|
||||||
|
|
||||||
export type PubsWithGenres = Pub & { genres: Array<Genre> }
|
export type PubWithGenres = Pub & { genres: Array<Genre> }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ export const columns: ColumnDef<StoryWithGenres>[] = [
|
||||||
Title
|
Title
|
||||||
</span>
|
</span>
|
||||||
<span className="block sm:hidden"><BookType /></span>
|
<span className="block sm:hidden"><BookType /></span>
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
<ArrowUpDown className="ml-2 h-4 w-4 hidden md:block" />
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -52,7 +52,7 @@ export const columns: ColumnDef<StoryWithGenres>[] = [
|
||||||
<span className="sm:hidden">
|
<span className="sm:hidden">
|
||||||
<Tally5 />
|
<Tally5 />
|
||||||
</span>
|
</span>
|
||||||
<ArrowUpDown className="ml-2 h-4 w-4" />
|
<ArrowUpDown className="ml-2 h-4 w-4 hidden md:block" />
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
"use client"
|
"use client"
|
||||||
import { createStory } from "app/lib/create"
|
|
||||||
import { Dialog, DialogHeader, DialogTrigger, DialogContent, DialogClose, DialogTitle, DialogFooter, DialogDescription } from "@/components/ui/dialog";
|
import { Dialog, DialogHeader, DialogTrigger, DialogContent, DialogClose, DialogTitle, DialogFooter, DialogDescription } from "@/components/ui/dialog";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { ComponentProps, useState } from "react";
|
import { ComponentProps, useState } from "react";
|
||||||
import { Genre, Story } from "@prisma/client";
|
import { Genre, Story } from "@prisma/client";
|
||||||
import StoryForm from "app/ui/forms/story";
|
import StoryForm from "app/ui/forms/story";
|
||||||
|
import { StoryWithGenres } from "./page";
|
||||||
|
|
||||||
|
|
||||||
export default function EditStoryDialog({ genres, closeDialog, defaults }: ComponentProps<"div"> & { genres: Genre[], closeDialog: () => void, defaults: Story }) {
|
export default function EditStoryDialog({ genres, closeDialog, defaults, dbAction }: ComponentProps<"div"> & { genres: Genre[], closeDialog: () => void, defaults: StoryWithGenres, dbAction: (data: StoryWithGenres) => Promise<{ success: string }> }) {
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -16,7 +16,7 @@ export default function EditStoryDialog({ genres, closeDialog, defaults }: Compo
|
||||||
<DialogTitle>Edit story</DialogTitle>
|
<DialogTitle>Edit story</DialogTitle>
|
||||||
<DialogDescription>Create an entry for a new story i.e. a thing you intend to submit for publication.</DialogDescription>
|
<DialogDescription>Create an entry for a new story i.e. a thing you intend to submit for publication.</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<StoryForm dbAction={createStory} genres={genres} className="" closeDialog={closeDialog} defaults={defaults} />
|
<StoryForm dbAction={dbAction} genres={genres} className="" closeDialog={closeDialog} defaults={defaults} />
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
<Button form="storyform">Submit</Button>
|
<Button form="storyform">Submit</Button>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
|
|
|
@ -50,7 +50,7 @@ export const columns: ColumnDef<SubComplete>[] = [
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="p-0"
|
className="p-0 flex justify-center w-full"
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
>
|
>
|
||||||
<span className="hidden md:block"> Date Submitted </span>
|
<span className="hidden md:block"> Date Submitted </span>
|
||||||
|
@ -76,7 +76,7 @@ export const columns: ColumnDef<SubComplete>[] = [
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="p-0"
|
className="p-0 flex justify-center w-full"
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
>
|
>
|
||||||
<span className="hidden md:block"> Date Responded </span>
|
<span className="hidden md:block"> Date Responded </span>
|
||||||
|
@ -105,7 +105,7 @@ export const columns: ColumnDef<SubComplete>[] = [
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="p-0"
|
className="p-0 flex justify-center w-full"
|
||||||
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
|
||||||
>
|
>
|
||||||
<span className="hidden md:block"> Response </span>
|
<span className="hidden md:block"> Response </span>
|
||||||
|
|
|
@ -706,6 +706,10 @@ body {
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.float-right {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
.m-auto {
|
.m-auto {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
@ -777,14 +781,6 @@ body {
|
||||||
margin-top: 1.5rem;
|
margin-top: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mt-auto {
|
|
||||||
margin-top: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-4 {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
@ -887,10 +883,6 @@ body {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.h-5\/6 {
|
|
||||||
height: 83.333333%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.max-h-96 {
|
.max-h-96 {
|
||||||
max-height: 24rem;
|
max-height: 24rem;
|
||||||
}
|
}
|
||||||
|
@ -976,8 +968,8 @@ body {
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
}
|
}
|
||||||
|
|
||||||
.w-5\/6 {
|
.w-1\/2 {
|
||||||
width: 83.333333%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.min-w-\[8rem\] {
|
.min-w-\[8rem\] {
|
||||||
|
@ -1021,6 +1013,18 @@ body {
|
||||||
max-width: 20rem;
|
max-width: 20rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.max-w-40 {
|
||||||
|
max-width: 10rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-w-\[50\%\] {
|
||||||
|
max-width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-w-60 {
|
||||||
|
max-width: 15rem;
|
||||||
|
}
|
||||||
|
|
||||||
.shrink-0 {
|
.shrink-0 {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
@ -1105,6 +1109,18 @@ body {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content-center {
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-start {
|
||||||
|
align-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-between {
|
||||||
|
align-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
.items-start {
|
.items-start {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
@ -1129,6 +1145,10 @@ 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;
|
||||||
}
|
}
|
||||||
|
@ -1220,6 +1240,10 @@ body {
|
||||||
margin-bottom: calc(2rem * var(--tw-space-y-reverse));
|
margin-bottom: calc(2rem * var(--tw-space-y-reverse));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.self-end {
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
.justify-self-end {
|
.justify-self-end {
|
||||||
justify-self: end;
|
justify-self: end;
|
||||||
}
|
}
|
||||||
|
@ -1267,11 +1291,6 @@ body {
|
||||||
border-top-right-radius: 1.5rem;
|
border-top-right-radius: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rounded-l-3xl {
|
|
||||||
border-top-left-radius: 1.5rem;
|
|
||||||
border-bottom-left-radius: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rounded-tl-3xl {
|
.rounded-tl-3xl {
|
||||||
border-top-left-radius: 1.5rem;
|
border-top-left-radius: 1.5rem;
|
||||||
}
|
}
|
||||||
|
@ -1493,6 +1512,10 @@ body {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.align-top {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
.align-middle {
|
.align-middle {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
@ -1536,6 +1559,11 @@ body {
|
||||||
line-height: 1rem;
|
line-height: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.text-6xl {
|
||||||
|
font-size: 3.75rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.font-black {
|
.font-black {
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,15 +22,17 @@ import GenrePicker from "./genrePicker"
|
||||||
import { pubSchema } from "./schemas"
|
import { pubSchema } from "./schemas"
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import { Ban } from "lucide-react"
|
import { Ban } from "lucide-react"
|
||||||
|
import { PubWithGenres } from "app/publication/page"
|
||||||
|
|
||||||
export default function PubForm({ genres, dbAction, className, closeDialog, defaults }: ComponentProps<"div"> & { genres: Array<Genre>, dbAction: (data: any) => Promise<{ success: string }>, closeDialog: () => void, defaults?: Pub }) {
|
export default function PubForm({ genres, dbAction, className, closeDialog, defaults }: ComponentProps<"div"> & { genres: Array<Genre>, dbAction: (data: any) => Promise<{ success: string }>, closeDialog: () => void, defaults?: PubWithGenres }) {
|
||||||
const form = useForm<z.infer<typeof pubSchema>>({
|
const form = useForm<z.infer<typeof pubSchema>>({
|
||||||
resolver: zodResolver(pubSchema),
|
resolver: zodResolver(pubSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
title: "",
|
id: defaults?.id,
|
||||||
link: "",
|
title: defaults?.title ?? "",
|
||||||
query_after_days: 30,
|
link: defaults?.link ?? "",
|
||||||
genres: []
|
query_after_days: defaults?.query_after_days ?? 30,
|
||||||
|
genres: defaults?.genres.map(e => e.id) ?? []
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -39,7 +41,7 @@ export default function PubForm({ genres, dbAction, className, closeDialog, defa
|
||||||
async function onSubmit(values: z.infer<typeof pubSchema>) {
|
async function onSubmit(values: z.infer<typeof pubSchema>) {
|
||||||
try {
|
try {
|
||||||
const res = await dbAction(values)
|
const res = await dbAction(values)
|
||||||
if (!res) throw new Error("something went wrong")
|
if (!res?.success) throw new Error("something went wrong")
|
||||||
toast({ title: "Success!", description: res.success })
|
toast({ title: "Success!", description: res.success })
|
||||||
router.refresh()
|
router.refresh()
|
||||||
closeDialog()
|
closeDialog()
|
||||||
|
|
|
@ -7,6 +7,7 @@ export const storySchema = z.object({
|
||||||
})
|
})
|
||||||
|
|
||||||
export const pubSchema = z.object({
|
export const pubSchema = z.object({
|
||||||
|
id: z.coerce.number().optional(),
|
||||||
title: z.string().min(2).max(50),
|
title: z.string().min(2).max(50),
|
||||||
link: z.string(),
|
link: z.string(),
|
||||||
query_after_days: z.coerce.number().min(30),
|
query_after_days: z.coerce.number().min(30),
|
||||||
|
|
|
@ -34,6 +34,7 @@ export default function StoryForm({ genres, dbAction, className, closeDialog, de
|
||||||
const form = useForm<z.infer<typeof formSchema>>({
|
const form = useForm<z.infer<typeof formSchema>>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
|
id: defaults?.id,
|
||||||
title: defaults?.title ?? "",
|
title: defaults?.title ?? "",
|
||||||
word_count: defaults?.word_count ?? 500,
|
word_count: defaults?.word_count ?? 500,
|
||||||
genres: defaults?.genres.map(e => e.id) ?? []
|
genres: defaults?.genres.map(e => e.id) ?? []
|
||||||
|
@ -47,7 +48,7 @@ export default function StoryForm({ genres, dbAction, className, closeDialog, de
|
||||||
try {
|
try {
|
||||||
const res = await dbAction(values)
|
const res = await dbAction(values)
|
||||||
//server actions return undefined if middleware authentication fails
|
//server actions return undefined if middleware authentication fails
|
||||||
if (!res.success) throw new Error("something went wrong")
|
if (!res?.success) throw new Error("something went wrong")
|
||||||
toast({ title: "Success!", description: res.success })
|
toast({ title: "Success!", description: res.success })
|
||||||
router.refresh()
|
router.refresh()
|
||||||
closeDialog()
|
closeDialog()
|
||||||
|
@ -86,7 +87,7 @@ export default function StoryForm({ genres, dbAction, className, closeDialog, de
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="inline-flex flex-wrap w-full gap-x-16 gap-y-8 items-baseline max-w-full">
|
<div className="inline-flex flex-wrap justify-around items-start w-full gap-x-16 gap-y-8 items-baseline max-w-full">
|
||||||
|
|
||||||
<GenrePicker
|
<GenrePicker
|
||||||
genres={genres}
|
genres={genres}
|
||||||
|
@ -97,7 +98,7 @@ export default function StoryForm({ genres, dbAction, className, closeDialog, de
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="word_count"
|
name="word_count"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem className="flex flex-col">
|
<FormItem className="flex flex-col ">
|
||||||
<FormLabel className="h-5">Word count</FormLabel>
|
<FormLabel className="h-5">Word count</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input className=" w-24" type="number" step={500} {...field}></Input>
|
<Input className=" w-24" type="number" step={500} {...field}></Input>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { Badge } from "@/components/ui/badge";
|
||||||
export default function GenreBadges(props: ComponentProps<"div"> & { genres: Array<Genre> }) {
|
export default function GenreBadges(props: ComponentProps<"div"> & { genres: Array<Genre> }) {
|
||||||
return (
|
return (
|
||||||
<div className={"flex flex-wrap gap-1 justify-center " + props.className}>
|
<div className={"flex flex-wrap gap-1 justify-center " + props.className}>
|
||||||
{props.genres.map((e: Genre) => (<Badge className="" key={e.name}>{e.name}</Badge>))}
|
{props.genres.map((e: Genre) => (<Badge className="text-xs md:text-sm" key={e.name}>{e.name}</Badge>))}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ 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, updatePub, updateStory } 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 EditSubmissionDialog from "app/submission/edit"
|
||||||
|
@ -53,6 +53,7 @@ import { DialogTitle } from "@radix-ui/react-dialog"
|
||||||
import { toast } from "@/components/ui/use-toast"
|
import { toast } from "@/components/ui/use-toast"
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
import EditStoryDialog from "app/story/edit"
|
import EditStoryDialog from "app/story/edit"
|
||||||
|
import EditPubDialog from "app/publication/edit"
|
||||||
|
|
||||||
export interface DataTableProps<TData, TValue> {
|
export interface DataTableProps<TData, TValue> {
|
||||||
columns: ColumnDef<TData, TValue>[]
|
columns: ColumnDef<TData, TValue>[]
|
||||||
|
@ -178,12 +179,19 @@ export function DataTable<TData, TValue>({
|
||||||
/>
|
/>
|
||||||
: tableName === "story" ?
|
: tableName === "story" ?
|
||||||
< EditStoryDialog
|
< EditStoryDialog
|
||||||
|
dbAction={updateStory}
|
||||||
genres={genres}
|
genres={genres}
|
||||||
// TODO: prepare genre data so that it can be read by StoryForm
|
|
||||||
defaults={dialogRow?.original}
|
defaults={dialogRow?.original}
|
||||||
closeDialog={closeEditDialog}
|
closeDialog={closeEditDialog}
|
||||||
/>
|
/>
|
||||||
: ""
|
: tableName === "pub" ?
|
||||||
|
<EditPubDialog
|
||||||
|
dbAction={updatePub}
|
||||||
|
genres={genres}
|
||||||
|
defaults={dialogRow?.original}
|
||||||
|
closeDialog={closeEditDialog}
|
||||||
|
/>
|
||||||
|
: ""
|
||||||
}
|
}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
@ -205,6 +213,7 @@ export function DataTable<TData, TValue>({
|
||||||
const res = await deleteRecord(dialogRow.original.id, pathname)
|
const res = await deleteRecord(dialogRow.original.id, pathname)
|
||||||
if (!res) toast({ title: "Oh dear...", description: "Failed to delete." })
|
if (!res) toast({ title: "Oh dear...", description: "Failed to delete." })
|
||||||
if (res) toast({ title: "Successfully deleted record of id:", description: dialogRow.original.id })
|
if (res) toast({ title: "Successfully deleted record of id:", description: dialogRow.original.id })
|
||||||
|
table.resetRowSelection()
|
||||||
router.refresh()
|
router.refresh()
|
||||||
}}>Yes, delete it!
|
}}>Yes, delete it!
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -235,6 +244,7 @@ export function DataTable<TData, TValue>({
|
||||||
const res = await deleteRecords(recordIds, pathname)
|
const res = await deleteRecords(recordIds, pathname)
|
||||||
if (!res) toast({ title: "Oh dear...", description: "Failed to delete." })
|
if (!res) toast({ title: "Oh dear...", description: "Failed to delete." })
|
||||||
if (res) toast({ title: "Successfully deleted records of id:", description: JSON.stringify(recordIds) })
|
if (res) toast({ title: "Successfully deleted records of id:", description: JSON.stringify(recordIds) })
|
||||||
|
table.resetRowSelection()
|
||||||
router.refresh()
|
router.refresh()
|
||||||
setIsDeleteDialogVisible(false)
|
setIsDeleteDialogVisible(false)
|
||||||
}}>
|
}}>
|
||||||
|
|
Loading…
Reference in New Issue