355 lines
12 KiB
TypeScript
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>
|
|
);
|
|
} |