feat : limit each session to 1 hours when checkout
This commit is contained in:
@@ -1,34 +1,66 @@
|
||||
"use client";
|
||||
|
||||
import { useState, type FormEvent } from "react";
|
||||
import { useEffect, useState, type FormEvent } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
import { MobileSlipHandoff } from "@/components/commission/mobile-slip-handoff";
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { verificationError } from "@/lib/commission/verification-error";
|
||||
|
||||
export function CommissionPaymentForm({ checkoutId }: { checkoutId: string }) {
|
||||
export function CommissionPaymentForm({ checkoutId, amountBaht, qr, expiresAt, serverNow }: {
|
||||
checkoutId: string; amountBaht: number; qr: string | null; expiresAt: number; serverNow: number;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [now, setNow] = useState(serverNow);
|
||||
const expired = now >= expiresAt;
|
||||
const secondsLeft = Math.max(0, Math.ceil((expiresAt - now) / 1000));
|
||||
|
||||
useEffect(() => {
|
||||
const timer = window.setInterval(() => setNow(Date.now()), 1000);
|
||||
return () => window.clearInterval(timer);
|
||||
}, []);
|
||||
|
||||
async function submit(event: FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault(); setBusy(true); setError("");
|
||||
event.preventDefault();
|
||||
if (Date.now() >= expiresAt) { setNow(Date.now()); return; }
|
||||
setBusy(true); setError("");
|
||||
try {
|
||||
const response = await fetch(`/api/commission/checkouts/${checkoutId}/verify`, {
|
||||
method: "POST", body: new FormData(event.currentTarget),
|
||||
});
|
||||
const result = await response.json();
|
||||
if (!response.ok) throw new Error(verificationError(result.error));
|
||||
if (!response.ok) {
|
||||
if (result.error === "checkout-expired") setNow(Date.now());
|
||||
throw new Error(verificationError(result.error));
|
||||
}
|
||||
router.push(`/commission/tickets/${result.ticketId}`);
|
||||
} catch (cause) { setError(cause instanceof Error ? cause.message : "เกิดข้อผิดพลาด"); }
|
||||
finally { setBusy(false); }
|
||||
}
|
||||
return <form onSubmit={submit} className="flex flex-col gap-4"><FieldGroup>
|
||||
if (expired || !qr) return <Card><CardHeader><CardTitle>หมดเวลาชำระเงิน</CardTitle></CardHeader>
|
||||
<CardContent className="flex flex-col gap-3"><p>คำขอนี้หมดอายุแล้ว กรุณาสร้างคำขอใหม่</p>
|
||||
<Link href="/commission" className="text-sm underline">สร้างคำขอใหม่</Link>
|
||||
</CardContent></Card>;
|
||||
|
||||
return <><Card><CardHeader><CardTitle>สแกน PromptPay</CardTitle></CardHeader>
|
||||
<CardContent className="flex flex-col items-center gap-4">
|
||||
{/* Generated locally from the fixed checkout amount and configured recipient. */}
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img src={qr} alt={`PromptPay QR สำหรับชำระเงิน ${amountBaht} บาท`} width={300} height={300} />
|
||||
<strong>฿{amountBaht}</strong>
|
||||
<p className="text-sm text-muted-foreground">โอนเงินแล้วอัปโหลดรูปสลิปเพื่อยืนยัน</p>
|
||||
<p className="text-sm text-muted-foreground">เวลาชำระเงินที่เหลือ {String(Math.floor(secondsLeft / 60)).padStart(2, "0")}:{String(secondsLeft % 60).padStart(2, "0")}</p>
|
||||
</CardContent></Card>
|
||||
<form onSubmit={submit} className="flex flex-col gap-4"><FieldGroup>
|
||||
<Field><FieldLabel htmlFor="slip">อัปโหลดสลิปที่ชำระเงินแล้ว</FieldLabel>
|
||||
<Input id="slip" name="file" type="file" accept="image/png,image/jpeg,image/webp" required />
|
||||
<MobileSlipHandoff checkoutId={checkoutId} /></Field>
|
||||
<Button type="submit" disabled={busy}>{busy ? "กำลังตรวจสอบ..." : "ตรวจสอบสลิปและเปิด Ticket"}</Button>
|
||||
</FieldGroup>{error && <Alert variant="destructive"><AlertDescription>{error}</AlertDescription></Alert>}</form>;
|
||||
</FieldGroup>{error && <Alert variant="destructive"><AlertDescription>{error}</AlertDescription></Alert>}</form></>;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user