Files
admin.fellies.app/src/components/images/edit/EditImageForm.tsx

355 lines
12 KiB
TypeScript

"use client"
import { updateImage } from "@/actions/images/updateImage";
import { Button } from "@/components/ui/button";
import { Calendar } from "@/components/ui/calendar";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
import { Album, Artist, ColorPalette, ColorPaletteItem, ExtractColor, Image, ImageColor, ImageMetadata, ImageStats, ImageVariant, PixelSummary, ThemeSeed } from "@/generated/prisma";
import { cn } from "@/lib/utils";
import { imageSchema } from "@/schemas/images/imageSchema";
import { zodResolver } from "@hookform/resolvers/zod";
import { format } from "date-fns";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import * as z from "zod/v4";
type ImageWithItems = Image & {
album: Album | null,
artist: Artist | null,
colors: ImageColor[],
extractColors: ExtractColor[],
metadata: ImageMetadata[],
pixels: PixelSummary[],
stats: ImageStats[],
theme: ThemeSeed[],
variants: ImageVariant[],
palettes: (
ColorPalette & {
items: ColorPaletteItem[]
}
)[]
};
export default function EditImageForm({ image, artists, albums }: { image: ImageWithItems, artists: Artist[], albums: Album[] }) {
const router = useRouter();
const form = useForm<z.infer<typeof imageSchema>>({
resolver: zodResolver(imageSchema),
defaultValues: {
fileKey: image.fileKey,
imageName: image.imageName,
originalFile: image.originalFile,
uploadDate: image.uploadDate,
altText: image.altText || "",
description: image.description || "",
fileType: image.fileType || "",
imageData: image.imageData || "",
creationMonth: image.creationMonth || undefined,
creationYear: image.creationYear || undefined,
fileSize: image.fileSize || undefined,
creationDate: image.creationDate ? new Date(image.creationDate) : undefined,
artistId: image.artist?.id || undefined,
albumId: image.album?.id || undefined,
},
})
// const watchCreationDate = form.watch("creationDate");
// console.log("Watched creationDate:", watchCreationDate);
async function onSubmit(values: z.infer<typeof imageSchema>) {
const updatedImage = await updateImage(values, image.id)
if (updatedImage) {
toast.success("Image updated")
router.push(`/images`)
}
}
return (
<div className="flex flex-col gap-8">
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="fileKey"
render={({ field }) => (
<FormItem>
<FormLabel>Image Key</FormLabel>
<FormControl><Input {...field} disabled /></FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="imageName"
render={({ field }) => (
<FormItem>
<FormLabel>Image Name</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="originalFile"
render={({ field }) => (
<FormItem>
<FormLabel>Original file</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="uploadDate"
render={({ field }) => (
<FormItem className="flex flex-col">
<FormLabel>Upload Date</FormLabel>
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
variant="outline"
className={cn(
"pl-3 text-left font-normal",
!field.value && "text-muted-foreground"
)}
>
{field.value ? format(field.value, "PPP") : "Pick a date"}
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
mode="single"
selected={field.value}
onSelect={field.onChange}
initialFocus
/>
</PopoverContent>
</Popover>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="altText"
render={({ field }) => (
<FormItem>
<FormLabel>Alt Text</FormLabel>
<FormControl><Input {...field} /></FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="description"
render={({ field }) => (
<FormItem>
<FormLabel>Description</FormLabel>
<FormControl><Textarea {...field} /></FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="fileType"
render={({ field }) => (
<FormItem>
<FormLabel>Filetype</FormLabel>
<FormControl><Input {...field} disabled /></FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="imageData"
render={({ field }) => (
<FormItem>
<FormLabel>imageData</FormLabel>
<FormControl><Input {...field} disabled /></FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="creationDate"
render={({ field }) => (
<FormItem className="flex flex-col gap-1">
<FormLabel>Creation Date</FormLabel>
<div className="flex items-center gap-2">
<Popover>
<PopoverTrigger asChild>
<FormControl>
<Button
variant="outline"
className={cn(
"pl-3 text-left font-normal",
!field.value && "text-muted-foreground"
)}
>
{field.value ? format(field.value, "PPP") : "Pick a date"}
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-auto p-0" align="start">
<Calendar
mode="single"
selected={field.value}
onSelect={(date) => {
field.onChange(date);
if (date) {
form.setValue("creationMonth", date.getUTCMonth() + 1);
form.setValue("creationYear", date.getUTCFullYear());
}
}}
initialFocus
/>
</PopoverContent>
</Popover>
{field.value && (
<Button
type="button"
variant="ghost"
size="sm"
onClick={() => {
form.setValue("creationDate", undefined, { shouldValidate: true });
form.setValue("creationMonth", undefined);
form.setValue("creationYear", undefined);
}}
>
Clear
</Button>
)}
</div>
<FormMessage />
</FormItem>
)}
/>
<div className="grid grid-cols-2 gap-4">
<FormField
control={form.control}
name="creationMonth"
render={({ field }) => (
<FormItem>
<FormLabel>Creation Month</FormLabel>
<FormControl>
<Input
type="number"
min={1}
max={12}
disabled={!!form.watch("creationDate")}
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="creationYear"
render={({ field }) => (
<FormItem>
<FormLabel>Creation Year</FormLabel>
<FormControl>
<Input
type="number"
min={1900}
max={2100}
disabled={!!form.watch("creationDate")}
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<FormField
control={form.control}
name="fileSize"
render={({ field }) => (
<FormItem>
<FormLabel>fileSize in byte</FormLabel>
<FormControl>
<Input
type="number"
{...field}
disabled
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="artistId"
render={({ field }) => (
<FormItem>
<FormLabel>Artist</FormLabel>
<Select onValueChange={field.onChange} value={field.value}>
<FormControl>
<SelectTrigger><SelectValue placeholder="Select artist" /></SelectTrigger>
</FormControl>
<SelectContent>
{artists.map((artist) => (
<SelectItem key={artist.id} value={artist.id}>{artist.displayName}</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="albumId"
render={({ field }) => (
<FormItem>
<FormLabel>Album</FormLabel>
<Select onValueChange={field.onChange} value={field.value}>
<FormControl>
<SelectTrigger><SelectValue placeholder="Select album" /></SelectTrigger>
</FormControl>
<SelectContent>
{albums.map((album) => (
<SelectItem key={album.id} value={album.id}>{album.name}</SelectItem>
))}
</SelectContent>
</Select>
<FormMessage />
</FormItem>
)}
/>
<div className="flex flex-col gap-4">
<Button type="submit">Submit</Button>
<Button type="reset" variant="secondary" onClick={() => router.back()}>Cancel</Button>
</div>
</form>
</Form>
</div>
);
}