191 lines
4.7 KiB
TypeScript
191 lines
4.7 KiB
TypeScript
import { zodResolver } from "@hookform/resolvers/zod";
|
|
import { useCallback } from "react";
|
|
import { useForm } from "react-hook-form";
|
|
import { toast } from "sonner";
|
|
import { z } from "zod";
|
|
import { useImportFromProvider } from "@/api/generated/manga-import/manga-import.ts";
|
|
import { useGetProviders } from "@/api/generated/provider/provider.ts";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog.tsx";
|
|
import {
|
|
Form,
|
|
FormControl,
|
|
FormDescription,
|
|
FormField,
|
|
FormItem,
|
|
FormLabel,
|
|
FormMessage,
|
|
} from "@/components/ui/form.tsx";
|
|
import { Input } from "@/components/ui/input";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select.tsx";
|
|
|
|
interface ProviderImportDialogProps {
|
|
dialogOpen: boolean;
|
|
onDialogOpenChange: (open: boolean) => void;
|
|
}
|
|
|
|
export const ProviderImportDialog = ({
|
|
dialogOpen,
|
|
onDialogOpenChange,
|
|
}: ProviderImportDialogProps) => {
|
|
const formSchema = z.object({
|
|
value: z.string().min(1, "Please enter an ID or URL."),
|
|
providerId: z.string(),
|
|
myAnimeListId: z.string().optional(),
|
|
});
|
|
|
|
const form = useForm<z.infer<typeof formSchema>>({
|
|
resolver: zodResolver(formSchema),
|
|
defaultValues: {
|
|
value: "",
|
|
providerId: "",
|
|
myAnimeListId: undefined,
|
|
},
|
|
});
|
|
|
|
const { data: providerData, isFetching: isFetchingProviders } =
|
|
useGetProviders({ manualImport: true });
|
|
|
|
const { mutate: importFromProvider, isPending: isPendingImportFromProvider } =
|
|
useImportFromProvider({
|
|
mutation: {
|
|
onSuccess: () => {
|
|
form.reset();
|
|
onDialogOpenChange(false);
|
|
toast.success("Manga imported successfully!");
|
|
},
|
|
},
|
|
});
|
|
|
|
const handleSubmit = useCallback(
|
|
(data: z.output<typeof formSchema>) => {
|
|
importFromProvider({
|
|
providerId: Number(data.providerId),
|
|
data: { id: data.value, metadataId: data.myAnimeListId },
|
|
});
|
|
},
|
|
[importFromProvider],
|
|
);
|
|
|
|
return (
|
|
<Dialog open={dialogOpen} onOpenChange={onDialogOpenChange}>
|
|
<DialogContent>
|
|
<DialogHeader>
|
|
<DialogTitle>Import from Provider</DialogTitle>
|
|
<DialogDescription>
|
|
Enter a Provider manga URL or ID to import it to your library.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<Form {...form}>
|
|
<form
|
|
id="importForm"
|
|
onSubmit={form.handleSubmit(handleSubmit)}
|
|
className="space-y-4"
|
|
>
|
|
<FormField
|
|
control={form.control}
|
|
name="providerId"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>Provider</FormLabel>
|
|
<FormControl>
|
|
<Select
|
|
onValueChange={field.onChange}
|
|
defaultValue={field.value}
|
|
{...field}
|
|
disabled={isFetchingProviders}
|
|
required
|
|
>
|
|
<SelectTrigger className="w-[180px]">
|
|
<SelectValue placeholder="Select a provider" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{providerData?.data?.providers?.map((provider) => (
|
|
<SelectItem
|
|
key={provider.id}
|
|
value={provider.id.toString()}
|
|
>
|
|
{provider.name}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="value"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>URL or ID</FormLabel>
|
|
<FormControl>
|
|
<Input
|
|
placeholder="e.g., https://mangadex.org/title/..."
|
|
disabled={isPendingImportFromProvider}
|
|
{...field}
|
|
/>
|
|
</FormControl>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
<FormField
|
|
control={form.control}
|
|
name="myAnimeListId"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormLabel>MyAnimeList ID (Optional)</FormLabel>
|
|
<FormControl>
|
|
<Input
|
|
placeholder="e.g., 13 (for One Piece)"
|
|
disabled={isPendingImportFromProvider}
|
|
{...field}
|
|
/>
|
|
</FormControl>
|
|
<FormDescription>
|
|
Optionally link this manga to a MyAnimeList entry for better
|
|
precision on metadata fetching.
|
|
</FormDescription>
|
|
<FormMessage />
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</form>
|
|
</Form>
|
|
<DialogFooter>
|
|
<Button
|
|
type="button"
|
|
variant="outline"
|
|
onClick={() => onDialogOpenChange(false)}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
type="submit"
|
|
disabled={isPendingImportFromProvider || isFetchingProviders}
|
|
form="importForm"
|
|
>
|
|
Import
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|