import { eventQueries } from "@/entities/event";
import { formatUsdt } from "@/shared/lib/money/usdt";
import { getCurrencySymbol } from "@/shared/lib/web3";
import { Loader } from "@/shared/ui/Loader";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/shared/ui/select";
import { useQuery } from "@tanstack/react-query";
export interface CategoryOption {
categoryId: number;
name: string;
discount: number;
quota: number;
hasQuota: boolean;
ticketsBought: number;
}
interface CategorySelectProps {
eventId: number;
ticketPrice: bigint;
selectedCategoryId: number | null;
onCategorySelect: (category: CategoryOption | null) => void;
}
export const CategorySelect: React.FC<CategorySelectProps> = ({
eventId,
ticketPrice,
selectedCategoryId,
onCategorySelect,
}) => {
const { data: event, isLoading: isEventLoading } = useQuery(
eventQueries.detail(eventId),
);
const { data: categories, isLoading } = useQuery(
eventQueries.categories(eventId),
);
if (isLoading || isEventLoading) {
return (
<div className="flex items-center gap-2 py-3">
<Loader />
<span className="text-muted-foreground">Loading categories...</span>
</div>
);
}
if (!event || !categories || categories.length === 0) {
return null;
}
const maxTickets = event.place.maxTickets;
const globalRemaining = Math.max(
0,
maxTickets - Number(event.ticketsBought ?? 0),
);
const getCategoryPrice = (category: CategoryOption): bigint => {
if (category.discount === 0) return ticketPrice;
// Contract amounts are integer token units. Keep this integer to avoid validation issues.
const discount = (ticketPrice * BigInt(category.discount)) / 10000n;
return ticketPrice - discount;
};
const getRemainingQuota = (category: CategoryOption): number => {
if (!category.hasQuota) return globalRemaining;
const byQuota = category.quota - category.ticketsBought;
return Math.max(0, Math.min(byQuota, globalRemaining));
};
const isSoldOut = (category: CategoryOption): boolean => {
if (globalRemaining <= 0) return true;
if (!category.hasQuota) return false;
return category.ticketsBought >= category.quota;
};
const handleSelect = (value: string) => {
const category = categories.find((c) => c.categoryId === Number(value));
if (category) {
onCategorySelect(category);
}
};
const selectedCategory = selectedCategoryId
? categories.find((c) => c.categoryId === selectedCategoryId)
: null;
const finalPrice = selectedCategory
? getCategoryPrice(selectedCategory)
: ticketPrice;
return (
<div className="space-y-3">
<div>
<label
htmlFor="category-select"
className="text-sm text-muted-foreground mb-1 block"
>
Select Ticket Category
</label>
<Select
name="category-select"
value={selectedCategoryId?.toString() ?? ""}
onValueChange={handleSelect}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Choose a category" />
</SelectTrigger>
<SelectContent>
{categories.map((category) => {
const remaining = getRemainingQuota(category);
const soldOut = isSoldOut(category);
const price = getCategoryPrice(category);
const discountPercent = category.discount / 100;
const discountLabel =
discountPercent > 0 ? `-${discountPercent.toFixed(2)}%` : "";
return (
<SelectItem
key={category.categoryId}
value={category.categoryId.toString()}
disabled={soldOut}
>
<div className="flex items-center justify-between w-full gap-4 text-sm">
<span className="font-medium">{category.name}</span>
<span className="text-green-500">{discountLabel}</span>
<span
className={category.discount > 0 ? "text-green-500" : ""}
>
{formatUsdt(price)}{" "}
<img
src={getCurrencySymbol()}
className="h-4 aspect-square inline"
alt="currency"
/>
</span>
<span
className={
remaining < 5 ? "text-red-500" : "text-muted-foreground"
}
>
{`${remaining} left`}
</span>
</div>
</SelectItem>
);
})}
</SelectContent>
</Select>
</div>
{selectedCategory && selectedCategory.discount > 0 && (
<div className="flex justify-between items-center text-sm bg-green-500/10 p-2">
<span className="text-green-600">You save:</span>
<span className="text-green-600 font-medium">
{formatUsdt(ticketPrice - finalPrice)}{" "}
<img
src={getCurrencySymbol()}
className="h-4 aspect-square inline"
alt="currency"
/>
</span>
</div>
)}
</div>
);
};