Yaltopia-Hotels/src/pages/DiscountCodesPage.tsx
2026-03-22 03:55:51 +03:00

202 lines
6.3 KiB
TypeScript

import { Copy } from "lucide-react";
import { useCallback, useEffect, useState } from "react";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { useAuth } from "@/context/AuthContext";
import { apiGet, apiPatch, apiPost } from "@/lib/api";
import type { DiscountCode } from "@/lib/types";
function copy(s: string) {
void navigator.clipboard.writeText(s);
}
export function DiscountCodesPage() {
const { canManageCodes } = useAuth();
const [rows, setRows] = useState<DiscountCode[]>([]);
const [open, setOpen] = useState(false);
const [custom, setCustom] = useState("");
const [generate, setGenerate] = useState(true);
const [value, setValue] = useState("10");
const [dtype, setDtype] = useState<"percent" | "fixed_amount">("percent");
const load = useCallback(() => {
apiGet<{ data: DiscountCode[] }>("/discount-codes").then((r) =>
setRows(r.data)
);
}, []);
useEffect(() => {
load();
}, [load]);
async function create(e: React.FormEvent) {
e.preventDefault();
await apiPost("/discount-codes", {
generate,
code: generate ? undefined : custom,
discountType: dtype,
value: Number(value),
});
setOpen(false);
load();
}
async function toggle(dc: DiscountCode) {
if (!canManageCodes) return;
await apiPatch(`/discount-codes/${dc.id}`, { isActive: !dc.isActive });
load();
}
return (
<div className="space-y-6">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold">Discount codes</h1>
{canManageCodes && (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button>+ Generate code</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>New discount code</DialogTitle>
</DialogHeader>
<form onSubmit={create} className="grid gap-3">
<div className="flex items-center gap-2">
<input
type="checkbox"
checked={generate}
onChange={(e) => setGenerate(e.target.checked)}
id="gen"
/>
<Label htmlFor="gen">Auto-generate code</Label>
</div>
{!generate && (
<div className="space-y-2">
<Label>Custom code</Label>
<Input
value={custom}
onChange={(e) => setCustom(e.target.value)}
/>
</div>
)}
<div className="space-y-2">
<Label>Type</Label>
<Select
value={dtype}
onValueChange={(v) => setDtype(v as typeof dtype)}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="percent">Percent</SelectItem>
<SelectItem value="fixed_amount">Fixed amount</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label>Value</Label>
<Input
type="number"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
</div>
<Button type="submit">Create</Button>
</form>
</DialogContent>
</Dialog>
)}
</div>
<Card className="rounded-2xl">
<CardContent className="pt-6">
<Table>
<TableHeader>
<TableRow>
<TableHead>Code</TableHead>
<TableHead>Type</TableHead>
<TableHead>Value</TableHead>
<TableHead>Redemptions</TableHead>
<TableHead>Active</TableHead>
<TableHead />
</TableRow>
</TableHeader>
<TableBody>
{rows.map((d) => (
<TableRow key={d.id}>
<TableCell className="font-mono font-medium">{d.code}</TableCell>
<TableCell>{d.discountType}</TableCell>
<TableCell>
{d.discountType === "percent"
? `${d.value}%`
: d.value}
</TableCell>
<TableCell>
{d.redemptionCount}
{d.maxRedemptions != null && ` / ${d.maxRedemptions}`}
</TableCell>
<TableCell>
<Badge variant={d.isActive ? "success" : "secondary"}>
{d.isActive ? "Active" : "Off"}
</Badge>
</TableCell>
<TableCell className="flex gap-1">
<Button
variant="ghost"
size="icon"
type="button"
onClick={() => {
copy(d.code);
}}
title="Copy"
>
<Copy className="size-4" />
</Button>
{canManageCodes && (
<Button
variant="outline"
size="sm"
type="button"
onClick={() => toggle(d)}
>
Toggle
</Button>
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</div>
);
}