141 lines
3.7 KiB
TypeScript
141 lines
3.7 KiB
TypeScript
"use client";
|
||
|
||
import { payAgency } from "@/pages/finance/lib/api";
|
||
import { Button } from "@/shared/ui/button";
|
||
import {
|
||
Dialog,
|
||
DialogContent,
|
||
DialogFooter,
|
||
DialogHeader,
|
||
DialogTitle,
|
||
} from "@/shared/ui/dialog";
|
||
import { Input } from "@/shared/ui/input";
|
||
import { Label } from "@/shared/ui/label";
|
||
import { useMutation } from "@tanstack/react-query";
|
||
import { Loader2 } from "lucide-react";
|
||
import { useForm } from "react-hook-form";
|
||
import { useTranslation } from "react-i18next";
|
||
import { toast } from "sonner";
|
||
|
||
interface PayDialogProps {
|
||
open: boolean;
|
||
onClose: () => void;
|
||
agencyId: number;
|
||
}
|
||
|
||
interface PayFormValues {
|
||
amount: string; // formatted value (e.g. "1 200 000")
|
||
note: string;
|
||
}
|
||
|
||
// Narxni formatlovchi funksiya
|
||
function formatPrice(value: number | string): string {
|
||
const num = Number(value.toString().replace(/\D/g, ""));
|
||
if (isNaN(num)) return "";
|
||
return num.toLocaleString("ru-RU");
|
||
}
|
||
|
||
export function PayDialog({ open, onClose, agencyId }: PayDialogProps) {
|
||
const { t } = useTranslation();
|
||
|
||
const form = useForm<PayFormValues>({
|
||
defaultValues: {
|
||
amount: "",
|
||
note: "",
|
||
},
|
||
});
|
||
|
||
const { mutate, isPending } = useMutation({
|
||
mutationFn: ({
|
||
body,
|
||
}: {
|
||
body: {
|
||
travel_agency: number;
|
||
amount: number;
|
||
note: string;
|
||
};
|
||
}) => payAgency({ body }),
|
||
onSuccess: () => {
|
||
onClose();
|
||
},
|
||
onError: () => {
|
||
toast.error(t("Xatolik yuz berdi"), {
|
||
richColors: true,
|
||
position: "top-center",
|
||
});
|
||
},
|
||
});
|
||
|
||
const handleAmountChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||
const raw = e.target.value.replace(/\D/g, "");
|
||
const formatted = formatPrice(raw);
|
||
form.setValue("amount", formatted);
|
||
};
|
||
|
||
const handleSubmit = async (values: PayFormValues) => {
|
||
const cleanAmount = Number(
|
||
values.amount.replace(/\s/g, "").replace(/,/g, ""),
|
||
);
|
||
mutate({
|
||
body: {
|
||
amount: cleanAmount,
|
||
note: values.note,
|
||
travel_agency: agencyId,
|
||
},
|
||
});
|
||
};
|
||
|
||
return (
|
||
<Dialog open={open} onOpenChange={onClose}>
|
||
<DialogContent className="sm:max-w-md text-white bg-gray-900">
|
||
<DialogHeader>
|
||
<DialogTitle>{t("Qolgan summani to‘lash")}</DialogTitle>
|
||
</DialogHeader>
|
||
|
||
<form
|
||
onSubmit={form.handleSubmit(handleSubmit)}
|
||
className="space-y-4 py-2"
|
||
>
|
||
{/* Summani kiritish */}
|
||
<div className="space-y-2">
|
||
<Label htmlFor="amount">{t("Summani kiriting")}</Label>
|
||
<Input
|
||
id="amount"
|
||
inputMode="numeric"
|
||
placeholder="1 200 000"
|
||
value={form.watch("amount")}
|
||
onChange={handleAmountChange}
|
||
/>
|
||
{form.formState.errors.amount && (
|
||
<p className="text-red-400 text-sm">
|
||
{t("Summani to‘g‘ri kiriting")}
|
||
</p>
|
||
)}
|
||
</div>
|
||
|
||
{/* Izoh */}
|
||
<div className="space-y-2">
|
||
<Label htmlFor="note">{t("Izoh")}</Label>
|
||
<Input
|
||
id="note"
|
||
type="text"
|
||
placeholder={t("Izoh kiriting") || ""}
|
||
{...form.register("note")}
|
||
/>
|
||
</div>
|
||
|
||
{/* Tugmalar */}
|
||
<DialogFooter className="flex justify-end gap-3 pt-4">
|
||
<Button type="button" variant="outline" onClick={onClose}>
|
||
{t("Bekor qilish")}
|
||
</Button>
|
||
<Button type="submit" disabled={isPending}>
|
||
{isPending ? <Loader2 className="animate-spin" /> : t("To‘lash")}
|
||
</Button>
|
||
</DialogFooter>
|
||
</form>
|
||
</DialogContent>
|
||
</Dialog>
|
||
);
|
||
}
|