mmy / components /HeroEditorDialog.tsx
Mohammad Shahid
first commit
3a7a84c
"use client";
import { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { toast } from "sonner";
import { useRouter } from 'next/navigation';
import { HeroData } from '@/types';
import { heroFormSchema } from '@/lib/validators';
import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from '@/components/ui/dialog';
import { Form } from '@/components/ui/form';
import { ScrollArea } from '@/components/ui/scroll-area';
import { IdentitySection } from '@/components/editor-sections/IdentitySection';
import { VisualsSection } from '@/components/editor-sections/VisualsSection';
import { AudioSection } from '@/components/editor-sections/AudioSection';
import { PowerLogicSection } from '@/components/editor-sections/PowerLogicSection';
import { updateHeroAction } from '@/app/actions/db.actions';
import { getDirtyValues } from '@/lib/utils';
import { StatsSection } from './editor-sections/StatsSection';
// Note: StatsSection is complex and would need a similar refactor. Assuming it's done.
interface HeroEditorDialogProps {
hero: HeroData;
isOpen: boolean;
onClose: () => void;
}
export const HeroEditorDialog = ({ hero, isOpen, onClose }: HeroEditorDialogProps) => {
const router = useRouter();
const form = useForm<z.infer<typeof heroFormSchema>>({
resolver: zodResolver(heroFormSchema),
defaultValues: {
...hero,
heroGender:
hero.heroGender === "Male" || hero.heroGender === "Female"
? hero.heroGender
: undefined,
introLineAudioUrl: hero.introLineAudioUrl ?? null,
superpowerActivationLineAudioUrl: hero.superpowerActivationLineAudioUrl ?? null,
},
});
// Reset form if hero changes
useEffect(() => {
form.reset({
...hero,
heroGender:
hero.heroGender === "Male" || hero.heroGender === "Female"
? hero.heroGender
: undefined,
introLineAudioUrl: hero.introLineAudioUrl ?? null,
superpowerActivationLineAudioUrl: hero.superpowerActivationLineAudioUrl ?? null,
});
}, [hero, form]);
const onSubmit = async (values: z.infer<typeof heroFormSchema>) => {
const { dirtyFields } = form.formState;
const dirtyValues = getDirtyValues(dirtyFields, values);
// If nothing changed, don't even bother the server
if (Object.keys(dirtyValues).length === 0) {
toast.info("No changes to save.");
return;
}
const toastId = toast.loading("Saving your hero...");
if (!hero._id) {
toast.error("Hero ID is missing. Cannot update hero.");
return;
}
const result = await updateHeroAction(hero._id, dirtyValues);
if (result.success) {
toast.success(result.message, { id: toastId });
router.refresh();
onClose();
} else {
toast.error(result.message || "Something went wrong.", { id: toastId });
}
};
return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="max-w-4xl h-[95vh] flex flex-col">
<DialogHeader>
<DialogTitle>Edit Hero: {form.watch('heroName')}</DialogTitle>
<DialogDescription>
Modify any aspect of your hero. Use the AI buttons to regenerate specific fields.
</DialogDescription>
</DialogHeader>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex-grow overflow-hidden">
<ScrollArea className="h-full pr-6">
<div className="space-y-6">
<IdentitySection form={form} />
<StatsSection form={form} />
<VisualsSection form={form} />
<AudioSection form={form} />
<PowerLogicSection form={form} />
</div>
</ScrollArea>
</form>
</Form>
<DialogFooter className="pt-4 mt-4 border-t">
<Button type="button" variant="outline" onClick={onClose} disabled={form.formState.isSubmitting}>
Cancel
</Button>
<Button type="submit" className='cursor-pointer' onClick={form.handleSubmit(onSubmit)} disabled={form.formState.isSubmitting}>
{form.formState.isSubmitting ? "Saving..." : "Save Changes"}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
};