feat: add AFC Store with MercadoPago purchases and prize redemption
Some checks failed
Deploy / deploy (push) Has been cancelled
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>
This commit is contained in:
52
apps/web/src/components/afc/RedemptionHistoryTable.tsx
Normal file
52
apps/web/src/components/afc/RedemptionHistoryTable.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
"use client";
|
||||
|
||||
import { useTranslations } from "next-intl";
|
||||
import { StatusBadge } from "./StatusBadge";
|
||||
import type { Redemption } from "@/lib/afc";
|
||||
|
||||
interface RedemptionHistoryTableProps {
|
||||
redemptions: Redemption[];
|
||||
}
|
||||
|
||||
export function RedemptionHistoryTable({ redemptions }: RedemptionHistoryTableProps) {
|
||||
const t = useTranslations("afc");
|
||||
|
||||
if (redemptions.length === 0) {
|
||||
return (
|
||||
<p className="text-center text-gray-500 py-8">{t("no_redemptions")}</p>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-white/10 text-gray-400">
|
||||
<th className="text-left py-3 px-2 font-medium">{t("date")}</th>
|
||||
<th className="text-left py-3 px-2 font-medium">{t("prize")}</th>
|
||||
<th className="text-right py-3 px-2 font-medium">AFC</th>
|
||||
<th className="text-center py-3 px-2 font-medium">{t("status")}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{redemptions.map((r) => (
|
||||
<tr key={r.id} className="border-b border-white/5 hover:bg-white/[0.02]">
|
||||
<td className="py-3 px-2 text-gray-300">
|
||||
{new Date(r.created_at).toLocaleDateString()}
|
||||
</td>
|
||||
<td className="py-3 px-2 text-white">
|
||||
{r.prize_detail}
|
||||
</td>
|
||||
<td className="py-3 px-2 text-right text-red-400 font-medium">
|
||||
-{r.amount_afc}
|
||||
</td>
|
||||
<td className="py-3 px-2 text-center">
|
||||
<StatusBadge status={r.status} />
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user