+ {t("orders.orderNoLabel")}{" "} + {displayNo} + · + {formatLotteryInstant(placedAt ?? null)} +
+ ); +} diff --git a/src/features/orders/ticket-item-status.tsx b/src/features/orders/ticket-item-status.tsx index 34c3b57..75ec375 100644 --- a/src/features/orders/ticket-item-status.tsx +++ b/src/features/orders/ticket-item-status.tsx @@ -19,13 +19,16 @@ export function ticketStatusDisplay( if (status === "settled_win" && total > 0) { return { label: t?.("ticketStatus.settled_win") ?? status, dotClass: "bg-emerald-500" }; } - if (status === "settled_lose" || status === "settled_win") { + if (status === "settled_lose" || (status === "settled_win" && total <= 0)) { return { label: t?.("ticketStatus.settled_lose") ?? status, dotClass: "bg-background", ring: true, }; } + if (status === "failed") { + return { label: t?.("ticketStatus.failed") ?? status, dotClass: "bg-red-500" }; + } return { label: t?.("ticketStatus.unknown", { status, defaultValue: status }) ?? status, dotClass: "bg-red-500", diff --git a/src/features/orders/ticket-order-detail-screen.tsx b/src/features/orders/ticket-order-detail-screen.tsx index bd70043..c10c737 100644 --- a/src/features/orders/ticket-order-detail-screen.tsx +++ b/src/features/orders/ticket-order-detail-screen.tsx @@ -1,7 +1,8 @@ "use client"; import Link from "next/link"; -import { useCallback, useEffect, useState } from "react"; +import { useSearchParams } from "next/navigation"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { getTicketItemDetail } from "@/api/ticket-items"; @@ -17,6 +18,7 @@ import { import { Skeleton } from "@/components/ui/skeleton"; import { TwentyThreeResultsGrid } from "@/features/results/twenty-three-results-grid"; import { useCurrencyCatalog } from "@/hooks/use-currency-catalog"; +import { orderGroupPath } from "@/features/orders/group-ticket-items"; import { StatusDot, ticketStatusDisplay } from "@/features/orders/ticket-item-status"; import { formatLotteryInstant } from "@/lib/player-datetime"; import { formatMinorAsCurrency } from "@/lib/money"; @@ -67,6 +69,7 @@ type TicketItemDetailWithExtras = TicketItemDetailPayload & { /** 界面文档 §4.8 注单详情 */ export function TicketOrderDetailScreen({ ticketNo }: { ticketNo: string }) { + const searchParams = useSearchParams(); const { t } = useTranslation("player"); const { activeCurrency } = useActivePlayerCurrency(); useCurrencyCatalog(); @@ -74,6 +77,27 @@ export function TicketOrderDetailScreen({ ticketNo }: { ticketNo: string }) { const [error, setError] = useState{error ?? t("orders.noData")}
@@ -174,8 +198,8 @@ export function TicketOrderDetailScreen({ ticketNo }: { ticketNo: string }) { return ({t("orders.groupNotFound")}
+ + {t("orders.backToOrders")} + ++ {group.draw_no ?? "—"} +
++ {t("orders.itemCount", { count: group.items.length })} +
+{t("orders.stake")}
++ {formatMinorAsCurrency(group.total_bet_amount, cur)} +
+{t("orders.deduction")}
++ {formatMinorAsCurrency(group.actual_deduct_amount, cur)} +
++ {t("orders.win", { amount: formatMinorAsCurrency(totalWin, cur) })} +
+ ) : null} +{t("orders.betItems")}
++ {playLabel(row.play_code, t)} · {row.original_number ?? row.play_code} +
++ {t("orders.ticketNo", { ticketNo: row.ticket_no })} +
++ {t("orders.win", { amount: formatMinorAsCurrency(lineWin, lineCur) })} +
+ ) : null} +- {row.draw_no ?? "—"} -
-+
+ {group.draw_no ?? "—"} +
+{playLabel(row.play_code, t)} · {row.original_number ?? row.play_code}
-{t("orders.stake")}
- {formatMinorAsCurrency(row.total_bet_amount, cur)} + {formatMinorAsCurrency(group.total_bet_amount, cur)}
{t("orders.deduction")}
- {formatMinorAsCurrency(row.actual_deduct_amount, cur)} + {formatMinorAsCurrency(group.actual_deduct_amount, cur)}
{t("orders.win", { amount: formatMinorAsCurrency(totalWin, cur) })}
) : null} -- {formatLotteryInstant(row.placed_at ?? null)} -
); })} diff --git a/src/i18n/locales/en/player.json b/src/i18n/locales/en/player.json index 31f21cd..3cedf18 100644 --- a/src/i18n/locales/en/player.json +++ b/src/i18n/locales/en/player.json @@ -396,6 +396,14 @@ "detailTitle": "Ticket detail", "ticketNo": "Ticket {{ticketNo}}", "orderNo": "Order {{orderNo}}", + "orderNoLabel": "Order No.", + "orderNoAt": "Order No. {{orderNo}} · {{time}}", + "noOrderNo": "—", + "groupDetail": "Order detail", + "groupNotFound": "Could not load this order. Please open it again from My Bets.", + "betItems": "Bet lines", + "itemCount": "{{count}} bet line(s)", + "viewBetLine": "View bet line detail", "drawNo": "Issue", "placedAt": "Placed at", "number": "Number", @@ -421,6 +429,7 @@ "settledAt": "Settled at {{time}}", "viewDraw": "View this draw", "backToOrders": "Back to My Bets", + "backToGroup": "Back to order detail", "notFound": "Ticket does not exist or cannot be viewed.", "noData": "No data", "loadFailed": "Failed to load" @@ -555,6 +564,7 @@ "pending_payout": "Won, pending payout", "settled_win": "Paid", "settled_lose": "Not won", + "failed": "Failed", "unknown": "{{status}}" }, "prizeTier": { diff --git a/src/i18n/locales/ne/player.json b/src/i18n/locales/ne/player.json index 261d677..f5e4588 100644 --- a/src/i18n/locales/ne/player.json +++ b/src/i18n/locales/ne/player.json @@ -396,6 +396,14 @@ "detailTitle": "टिकट विवरण", "ticketNo": "टिकट {{ticketNo}}", "orderNo": "अर्डर {{orderNo}}", + "orderNoLabel": "अर्डर नं.", + "orderNoAt": "अर्डर नं. {{orderNo}} · {{time}}", + "noOrderNo": "—", + "groupDetail": "अर्डर विवरण", + "groupNotFound": "यो अर्डर लोड हुन सकेन। कृपया मेरा बेटबाट फेरि खोल्नुहोस्।", + "betItems": "बेट लाइन विवरण", + "itemCount": "जम्मा {{count}} बेट लाइन", + "viewBetLine": "बेट लाइन विवरण हेर्नुहोस्", "drawNo": "इश्यू", "placedAt": "राखेको समय", "number": "नम्बर", @@ -413,9 +421,15 @@ "jackpotAmount": "Jackpot {{amount}}", "payoutTotal": "कुल भुक्तानी {{amount}}", "matchLose": "मिलान नतिजा: जितेन", + "matchResult": "मिलान नतिजा", + "drawPendingMatch": "यस इश्यूका ड्र नम्बर प्रकाशित भएका छैनन्। जित-नजित अझै निर्धारण गर्न मिल्दैन।", + "matchPendingDraw": "ड्र पर्खँदैछ। जित-नजित अझै निर्धारण गर्न मिल्दैन।", + "matchPendingSettlement": "ड्र नतिजा प्रकाशित भयो। सेटल पछि जित-नजित देखाइनेछ।", + "timeline": "समयरेखा", "settledAt": "सेटल समय {{time}}", "viewDraw": "यो ड्र हेर्नुहोस्", "backToOrders": "मेरा बेटमा फर्कनुहोस्", + "backToGroup": "अर्डर विवरणमा फर्कनुहोस्", "notFound": "टिकट छैन वा हेर्न अनुमति छैन।", "noData": "डेटा छैन", "loadFailed": "लोड असफल" @@ -550,6 +564,7 @@ "pending_payout": "जितेको, भुक्तानी बाँकी", "settled_win": "भुक्तानी भयो", "settled_lose": "जितेन", + "failed": "असफल", "unknown": "{{status}}" }, "prizeTier": { diff --git a/src/i18n/locales/zh/player.json b/src/i18n/locales/zh/player.json index 8e2ca2b..1dd229a 100644 --- a/src/i18n/locales/zh/player.json +++ b/src/i18n/locales/zh/player.json @@ -396,6 +396,14 @@ "detailTitle": "注单详情", "ticketNo": "注单号 {{ticketNo}}", "orderNo": "订单 {{orderNo}}", + "orderNoLabel": "订单号", + "orderNoAt": "订单号 {{orderNo}} · {{time}}", + "noOrderNo": "—", + "groupDetail": "订单详情", + "groupNotFound": "无法加载该订单,请从注单列表重新进入。", + "betItems": "注项明细", + "itemCount": "共 {{count}} 条注项", + "viewBetLine": "查看注项详情", "drawNo": "期号", "placedAt": "下单时间", "number": "号码", @@ -421,6 +429,7 @@ "settledAt": "结算时间 {{time}}", "viewDraw": "查看本期开奖", "backToOrders": "返回我的注单", + "backToGroup": "返回订单详情", "notFound": "注单不存在或无权查看", "noData": "无数据", "loadFailed": "加载失败" @@ -555,6 +564,7 @@ "pending_payout": "已中奖待派彩", "settled_win": "已派彩", "settled_lose": "未中奖", + "failed": "失败", "unknown": "{{status}}" }, "prizeTier": {