Some checks failed
Deploy / deploy (push) Has been cancelled
Players can now buy AfterCoin with real money (MercadoPago Checkout Pro, $15 MXN/AFC) and redeem AFC for gift cards or cash withdrawals. Admin fulfills redemptions manually. - Bridge: payments + redemptions tables, CRUD routes, PATCH auth - Next.js API: verify-disk, balance, create-preference, webhook (idempotent minting with HMAC signature verification), redeem, payment/redemption history - Frontend: hub, buy flow (4 packages + custom), redeem flow (gift cards + cash out), success/failure/pending pages, history with tabs, 8 components - i18n: full English + Spanish translations - Infra: nginx /api/afc/ → Next.js, docker-compose env vars, .env.example Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { useTranslations } from "next-intl";
|
|
|
|
interface RedeemFormProps {
|
|
prizeType: string;
|
|
prizeDetail: string;
|
|
costAfc: number;
|
|
onSubmit: (deliveryInfo: string) => void;
|
|
onCancel: () => void;
|
|
loading: boolean;
|
|
}
|
|
|
|
export function RedeemForm({
|
|
prizeType,
|
|
prizeDetail,
|
|
costAfc,
|
|
onSubmit,
|
|
onCancel,
|
|
loading,
|
|
}: RedeemFormProps) {
|
|
const t = useTranslations("afc");
|
|
const [deliveryInfo, setDeliveryInfo] = useState("");
|
|
|
|
const isBankTransfer = prizeType === "bank_transfer";
|
|
const isMercadoPago = prizeType === "mercadopago";
|
|
|
|
const placeholder = isBankTransfer
|
|
? t("clabe_placeholder")
|
|
: isMercadoPago
|
|
? t("mp_account_placeholder")
|
|
: t("delivery_placeholder");
|
|
|
|
const label = isBankTransfer
|
|
? t("clabe_label")
|
|
: isMercadoPago
|
|
? t("mp_account_label")
|
|
: t("delivery_label");
|
|
|
|
return (
|
|
<div className="bg-gray-900 border border-white/10 rounded-2xl p-6 space-y-5">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-white">{prizeDetail}</h3>
|
|
<p className="text-sm text-amber-400">{costAfc} AFC</p>
|
|
</div>
|
|
<button
|
|
onClick={onCancel}
|
|
className="text-sm text-gray-500 hover:text-gray-300 transition-colors"
|
|
>
|
|
{t("cancel")}
|
|
</button>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<label className="block text-sm font-medium text-gray-400">
|
|
{label}
|
|
</label>
|
|
<input
|
|
type="text"
|
|
value={deliveryInfo}
|
|
onChange={(e) => setDeliveryInfo(e.target.value)}
|
|
placeholder={placeholder}
|
|
className="w-full bg-gray-800 border border-white/10 rounded-xl px-4 py-3 text-white placeholder:text-gray-600 focus:outline-none focus:border-amber-500/50 focus:ring-1 focus:ring-amber-500/25 transition-all"
|
|
/>
|
|
</div>
|
|
|
|
<div className="bg-amber-500/10 border border-amber-500/20 rounded-xl p-4 text-sm text-amber-300/80">
|
|
{t("redeem_warning")}
|
|
</div>
|
|
|
|
<button
|
|
onClick={() => onSubmit(deliveryInfo)}
|
|
disabled={loading || !deliveryInfo.trim()}
|
|
className="w-full py-3 bg-amber-500 hover:bg-amber-400 disabled:bg-gray-700 disabled:text-gray-500 text-black font-bold rounded-xl transition-colors"
|
|
>
|
|
{loading ? t("processing") : t("confirm_redeem")}
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|