120 lines
3.5 KiB
TypeScript
120 lines
3.5 KiB
TypeScript
import { useForm } from "@tanstack/react-form";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Progress } from "@/components/ui/progress";
|
|
import type { AxiosProgressEvent } from "axios";
|
|
import { useState } from "react";
|
|
import { toast } from "sonner";
|
|
|
|
interface UploadVersionFormProps {
|
|
onSubmit: (fd: FormData, config?: { onUploadProgress: (e: AxiosProgressEvent) => void }) => Promise<void>;
|
|
closeDialog: () => void;
|
|
}
|
|
|
|
export function UploadVersionForm({ onSubmit, closeDialog }: UploadVersionFormProps) {
|
|
const [uploadPercent, setUploadPercent] = useState(0);
|
|
const [isUploading, setIsUploading] = useState(false);
|
|
const [isDone, setIsDone] = useState(false);
|
|
|
|
const form = useForm({
|
|
defaultValues: { files: new DataTransfer().files, newVersion: "" },
|
|
onSubmit: async ({ value }) => {
|
|
if (!value.newVersion || value.files.length === 0) {
|
|
toast.error("Vui lòng điền đầy đủ thông tin");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
setIsUploading(true);
|
|
setUploadPercent(0);
|
|
setIsDone(false);
|
|
|
|
const fd = new FormData();
|
|
Array.from(value.files).forEach((f) => fd.append("FileInput", f));
|
|
fd.append("Version", value.newVersion);
|
|
|
|
await onSubmit(fd, {
|
|
onUploadProgress: (e: AxiosProgressEvent) => {
|
|
if (e.total) {
|
|
const progress = Math.round((e.loaded * 100) / e.total);
|
|
setUploadPercent(progress);
|
|
}
|
|
},
|
|
});
|
|
|
|
setIsDone(true);
|
|
} catch (error) {
|
|
console.error("Upload error:", error);
|
|
toast.error("Upload thất bại!");
|
|
} finally {
|
|
setIsUploading(false);
|
|
}
|
|
},
|
|
});
|
|
|
|
return (
|
|
<form
|
|
className="space-y-4"
|
|
onSubmit={(e) => {
|
|
e.preventDefault();
|
|
form.handleSubmit();
|
|
}}
|
|
>
|
|
<form.Field name="newVersion">
|
|
{(field) => (
|
|
<div>
|
|
<Label>Phiên bản</Label>
|
|
<Input
|
|
value={field.state.value}
|
|
onChange={(e) => field.handleChange(e.target.value)}
|
|
placeholder="1.0.0"
|
|
disabled={isUploading || isDone}
|
|
/>
|
|
</div>
|
|
)}
|
|
</form.Field>
|
|
|
|
<form.Field name="files">
|
|
{(field) => (
|
|
<div>
|
|
<Label>File</Label>
|
|
<Input
|
|
type="file"
|
|
onChange={(e) => e.target.files && field.handleChange(e.target.files)}
|
|
disabled={isUploading || isDone}
|
|
/>
|
|
</div>
|
|
)}
|
|
</form.Field>
|
|
|
|
{(uploadPercent > 0 || isUploading || isDone) && (
|
|
<div className="space-y-2">
|
|
<div className="flex justify-between text-sm">
|
|
<span>{isDone ? "Hoàn tất!" : "Đang tải lên..."}</span>
|
|
<span>{uploadPercent}%</span>
|
|
</div>
|
|
<Progress value={uploadPercent} className="w-full" />
|
|
</div>
|
|
)}
|
|
|
|
<div className="flex justify-end gap-2">
|
|
{!isDone ? (
|
|
<>
|
|
<Button type="button" variant="outline" onClick={closeDialog} disabled={isUploading}>
|
|
Hủy
|
|
</Button>
|
|
<Button type="submit" disabled={isUploading}>
|
|
{isUploading ? "Đang tải..." : "Upload"}
|
|
</Button>
|
|
</>
|
|
) : (
|
|
<Button type="button" onClick={closeDialog}>
|
|
Hoàn tất
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</form>
|
|
);
|
|
}
|