admin entry actions
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import { insertSchema, updateRouteSchema, updateSchema } from "~/lib/schema/cv/category"
|
||||
import { updateRouteSchema, updateRouteSchemaCliennt } from "~/lib/schema/cv/entry"
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { z } from "zod";
|
||||
@@ -9,112 +9,211 @@ import { Select, SelectContent, SelectTrigger, SelectItem, SelectValue } from "~
|
||||
import { trpc } from "~/app/_trpc/Client";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import * as Card from '~/components/ui/card'
|
||||
import { useRouter } from "next/navigation";
|
||||
import { use } from "react";
|
||||
|
||||
export default function UpdateCvCategoryForm({params}:{params:{id:string}}) {
|
||||
import { format } from 'date-fns'
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "~/components/ui/popover";
|
||||
import { cn } from "~/lib/utils";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import { Calendar } from "~/components/ui/calendar";
|
||||
export default function UpdateCvEntryForm({ params }: { params: { id: string } }) {
|
||||
const id = params.id
|
||||
const categories = trpc.cv.category.list.useQuery()
|
||||
console.log(id)
|
||||
const category = trpc.cv.category.get.useQuery({id:id})
|
||||
const form = useForm<z.infer<typeof updateRouteSchema>>({
|
||||
resolver: zodResolver(updateRouteSchema),
|
||||
const entry = trpc.cv.entry.get.useQuery({ id: id })
|
||||
const form = useForm<z.infer<typeof updateRouteSchemaCliennt>>({
|
||||
resolver: zodResolver(updateRouteSchemaCliennt),
|
||||
defaultValues: {
|
||||
by: {id: id},
|
||||
by: { id: id },
|
||||
update: {
|
||||
layoutPosition: category.data?.layoutPosition,
|
||||
name: category.data?.layoutPosition
|
||||
categoryId: entry.data?.categoryId,
|
||||
title: entry.data?.title,
|
||||
description: entry.data?.description,
|
||||
}
|
||||
}
|
||||
})
|
||||
category.promise.then((data) => {
|
||||
form.setValue("update.layoutPosition",data?.layoutPosition)
|
||||
form.setValue("update.name",data?.name)
|
||||
entry.promise.then((v) => {
|
||||
form.setValue('update.title',v?.title)
|
||||
form.setValue('update.description',v?.description);
|
||||
form.setValue('update.fromTime',new Date(Date.parse(v ? v.fromTime: "")))
|
||||
form.setValue('update.toTime',new Date(Date.parse(v ? v.toTime: "")))
|
||||
form.setValue('update.categoryId',v?.categoryId)
|
||||
})
|
||||
const mutation = trpc.cv.category.update.useMutation({onSuccess: () => {
|
||||
category.refetch()
|
||||
}})
|
||||
function onSubmit(values: z.infer<typeof updateRouteSchema>) {
|
||||
const mutation = trpc.cv.entry.update.useMutation({
|
||||
onSuccess: () => {
|
||||
entry.refetch()
|
||||
}
|
||||
})
|
||||
function onSubmit(values: z.infer<typeof updateRouteSchemaCliennt>) {
|
||||
let { title, categoryId, description } = values.update;
|
||||
mutation.mutate({
|
||||
by: {id: id},
|
||||
by: { id: id },
|
||||
update: {
|
||||
layoutPosition: values.update.layoutPosition,
|
||||
name: values.update.name
|
||||
fromTime: format(values.update.fromTime, 'yyyy-MM-dd'),
|
||||
toTime: format(values.update.toTime, 'yyyy-MM-dd'),
|
||||
title: title,
|
||||
categoryId: categoryId,
|
||||
description: description
|
||||
}
|
||||
})
|
||||
}
|
||||
if (category.data !== undefined) {
|
||||
if (entry.data !== undefined) {
|
||||
return (
|
||||
<Card.Card className="w-5/6 lg:w-1/2">
|
||||
<Card.CardHeader>
|
||||
<Card.CardTitle>
|
||||
Update Category
|
||||
</Card.CardTitle>
|
||||
</Card.CardHeader>
|
||||
<Card.CardContent>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="update.name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
Name
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="name" onChange={field.onChange} value={field.value == null ? undefined : field.value} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
>
|
||||
</FormField>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="by.id"
|
||||
render={({field}) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input hidden onChange={field.onChange} value={field.value}/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
>
|
||||
</FormField>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="update.layoutPosition"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
Layout Position
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Select onValueChange={field.onChange} defaultValue={field.value == null ? undefined : field.value}>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={form.getValues().update.layoutPosition} />
|
||||
</SelectTrigger>
|
||||
<Card.CardHeader>
|
||||
<Card.CardTitle>
|
||||
Create Entry
|
||||
</Card.CardTitle>
|
||||
</Card.CardHeader>
|
||||
<Card.CardContent>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="update.categoryId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
Category
|
||||
</FormLabel>
|
||||
{
|
||||
categories.data ? (
|
||||
<Select onValueChange={field.onChange} defaultValue={categories.data[0]?.id}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={categories.data[0]?.name ? categories.data[0]?.name : "Select category"} />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{updateRouteSchema.shape.update.shape.layoutPosition.unwrap().unwrap().options.map((o) => (
|
||||
<SelectItem key={o} value={o}> {o} </SelectItem>
|
||||
))}
|
||||
{categories.data?.map((c) => {
|
||||
return (<SelectItem value={c.id}> {c.name} </SelectItem>)
|
||||
})}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
>
|
||||
</FormField>
|
||||
<Button type="submit"> Update </Button>
|
||||
<FormMessage className={mutation.status == "success" ? "text-green-500" : "text-red-500"}>
|
||||
{mutation.error ? mutation.error.message : mutation.status}
|
||||
</FormMessage>
|
||||
</form>
|
||||
</Form>
|
||||
</Card.CardContent>
|
||||
</Card.Card>
|
||||
) : <Select></Select>
|
||||
}
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="update.title"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
Title
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="title" onChange={field.onChange} value={field.value == null ? undefined : field.value} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="update.description"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
Description
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="description" onChange={field.onChange} value={field.value == null ? undefined : field.value} />
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="update.fromTime"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>From Date</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[240px] pl-3 text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP")
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
disabled={(date) =>
|
||||
date > new Date() || date < new Date("1900-01-01")
|
||||
}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="update.toTime"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>To Date</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[240px] pl-3 text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP")
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
disabled={(date) =>
|
||||
date > new Date() || date < new Date("1900-01-01")
|
||||
}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit"> Update </Button>
|
||||
<FormMessage className={mutation.status == "success" ? "text-green-500" : "text-red-500"}>
|
||||
{mutation.error ? mutation.error.message : mutation.status}
|
||||
</FormMessage>
|
||||
</form>
|
||||
</Form>
|
||||
</Card.CardContent>
|
||||
</Card.Card>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
'use server'
|
||||
|
||||
import UpdateCvCategoryForm from "./UpdateForm";
|
||||
import UpdateCvEntryForm from "./UpdateForm";
|
||||
|
||||
export default async function Page({params}:{params: Promise<{id:string}>}) {
|
||||
console.log(params)
|
||||
const {id} = await params;
|
||||
return (
|
||||
<UpdateCvCategoryForm params={{id:id}}/>
|
||||
<UpdateCvEntryForm params={{id:id}}/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import { insertSchema } from "~/lib/schema/cv/entry"
|
||||
import { insertSchema, insertSchemaForm } from "~/lib/schema/cv/entry"
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { format } from 'date-fns'
|
||||
@@ -18,9 +18,8 @@ import { useState } from "react"
|
||||
|
||||
export default function CreateCvEntryForm() {
|
||||
const categories = trpc.cv.category.list.useQuery()
|
||||
const [categoyIds, setCategoryIds] = useState<string[]>([])
|
||||
const form = useForm<z.infer<typeof insertSchema>>({
|
||||
resolver: zodResolver(insertSchema),
|
||||
const form = useForm<z.infer<typeof insertSchemaForm>>({
|
||||
resolver: zodResolver(insertSchemaForm),
|
||||
defaultValues: {
|
||||
id: crypto.randomUUID(),
|
||||
title: "",
|
||||
@@ -29,22 +28,27 @@ export default function CreateCvEntryForm() {
|
||||
|
||||
}
|
||||
})
|
||||
categories.promise.then((data) => {
|
||||
form.setValue("categoryId", data[0]?.id)
|
||||
setCategoryIds(data.map((cat) => cat.id))
|
||||
})
|
||||
const mutation = trpc.cv.entry.create.useMutation({
|
||||
onSuccess: (data) => { form.setValue("id", data[0] ? data[0].id : "") }
|
||||
})
|
||||
function onSubmit(values: z.infer<typeof insertSchema>) {
|
||||
mutation.mutate(values)
|
||||
function onSubmit(values: z.infer<typeof insertSchemaForm>) {
|
||||
let { id, title, categoryId, description } = values
|
||||
let v: z.infer<typeof insertSchema> = {
|
||||
id: id,
|
||||
categoryId: categoryId,
|
||||
description: description,
|
||||
title: title,
|
||||
fromTime: format(values.fromTime,'yyyy-MM-dd'),
|
||||
toTime: format(values.toTime,'yyyy-MM-dd'),
|
||||
}
|
||||
mutation.mutate(v)
|
||||
form.setValue("id", crypto.randomUUID())
|
||||
}
|
||||
return (
|
||||
<Card.Card className="w-5/6 lg:w-1/2">
|
||||
<Card.CardHeader>
|
||||
<Card.CardTitle>
|
||||
Create Category
|
||||
Create Entry
|
||||
</Card.CardTitle>
|
||||
</Card.CardHeader>
|
||||
<Card.CardContent>
|
||||
@@ -53,6 +57,33 @@ export default function CreateCvEntryForm() {
|
||||
onSubmit={form.handleSubmit(onSubmit)}
|
||||
className="space-y-8"
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="categoryId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
Category
|
||||
</FormLabel>
|
||||
{
|
||||
categories.data ? (
|
||||
<Select onValueChange={field.onChange} defaultValue={categories.data[0]?.id}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder={categories.data[0]?.name ? categories.data[0]?.name : "Select category" } />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{ categories.data?.map((c) => {
|
||||
return (<SelectItem value={c.id}> {c.name} </SelectItem>)
|
||||
})}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
) : <Select></Select>
|
||||
}
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="title"
|
||||
@@ -73,7 +104,7 @@ export default function CreateCvEntryForm() {
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
Title
|
||||
Description
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="description" onChange={field.onChange} value={field.value == null ? undefined : field.value} />
|
||||
@@ -83,9 +114,86 @@ export default function CreateCvEntryForm() {
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="categoryId"
|
||||
>
|
||||
</FormField>
|
||||
name="fromTime"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>From Date</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[240px] pl-3 text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP")
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
disabled={(date) =>
|
||||
date > new Date() || date < new Date("1900-01-01")
|
||||
}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="toTime"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>To Date</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[240px] pl-3 text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}
|
||||
>
|
||||
{field.value ? (
|
||||
format(field.value, "PPP")
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
disabled={(date) =>
|
||||
date > new Date() || date < new Date("1900-01-01")
|
||||
}
|
||||
initialFocus
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit"> Create </Button>
|
||||
<FormMessage className={mutation.status == "success" ? "text-green-500" : "text-red-500"}>
|
||||
{mutation.error ? mutation.error.message : mutation.status}
|
||||
|
||||
@@ -8,50 +8,44 @@ import { useGsapContext } from "~/app/_providers/GsapProvicer";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Delete } from 'lucide-react'
|
||||
export default function CvPage() {
|
||||
const cvCategories = trpc.cv.category.list.useQuery();
|
||||
const cvEntries = trpc.cv.entry.list.useQuery();
|
||||
const gsap = useGsapContext()
|
||||
const container = useRef<HTMLDivElement>(null);
|
||||
const mut = trpc.cv.category.delete.useMutation({onSuccess: () => {
|
||||
const mut = trpc.cv.entry.delete.useMutation({onSuccess: () => {
|
||||
console.log('success')
|
||||
cvCategories.refetch()
|
||||
cvEntries.refetch()
|
||||
}})
|
||||
const deleteCategory = (id: string) => {
|
||||
const deleteEntry = (id: string) => {
|
||||
console.log(`deleting ${id}`)
|
||||
mut.mutate(id)
|
||||
}
|
||||
useGSAP(() => {
|
||||
gsap?.from('.gsapan', { x: -100, opacity: 0, duration: 0.5, stagger: { each: 0.3 } })
|
||||
}, { scope: container, dependencies: [cvCategories.status], revertOnUpdate: true });
|
||||
}, { scope: container, dependencies: [cvEntries.status], revertOnUpdate: true });
|
||||
return (
|
||||
<div ref={container} className="w-5/6 lg:w-1/2 flex flex-col gap-3">
|
||||
{cvCategories.data == undefined ?
|
||||
{cvEntries.data == undefined ?
|
||||
<div className="gsapan"></div>
|
||||
:
|
||||
<>
|
||||
{cvCategories.data.map((cat) => {
|
||||
{cvEntries.data.map((ent) => {
|
||||
return (
|
||||
<Card.Card className="gsapan" key={cat.id}>
|
||||
<Link href={`/admin/cv/category/${cat.id}`}>
|
||||
<Card.Card className="gsapan" key={ent.id}>
|
||||
<Link href={`/admin/cv/entry/${ent.id}`}>
|
||||
<Card.CardHeader>
|
||||
<Card.CardTitle>
|
||||
Category Name : {cat.name}
|
||||
Entry Name: { ent.title }
|
||||
</Card.CardTitle>
|
||||
</Card.CardHeader>
|
||||
</Link>
|
||||
<Card.CardContent className="flex flex-row">
|
||||
Category id : {cat.id} <br />
|
||||
Category Position : {cat.layoutPosition} <br />
|
||||
{
|
||||
cat.cvEntry.length > 0 ? (
|
||||
<>
|
||||
{cat.cvEntry.map((entry) => {
|
||||
<Link href={`/admin/cv/entry/${entry.id}`}> {entry.title} </Link>
|
||||
})}
|
||||
</>
|
||||
) : (<></>)
|
||||
}
|
||||
<div>
|
||||
Category id : {ent.id} <br />
|
||||
Category Name :
|
||||
<Link href={`/admin/cv/entry/${ent.categoryId}`}> {ent.category?.name} </Link>
|
||||
</div>
|
||||
<Button
|
||||
className="ml-auto cursor-pointer" variant="destructive" onClick={() => { deleteCategory(cat.id) }}>
|
||||
className="ml-auto cursor-pointer" variant="destructive" onClick={() => { deleteEntry(ent.id) }}>
|
||||
<Delete />
|
||||
</Button>
|
||||
</Card.CardContent>
|
||||
|
||||
Reference in New Issue
Block a user