feat: enhance wallet strip for mobile responsiveness
Some checks failed
lotteryfront CI / build (push) Has been cancelled

- Added mobile-specific styles to the HallWalletStrip component for better usability on smaller screens.
- Adjusted padding, font sizes, and spacing based on device type.
- Introduced a new hook `useIsMobile` to determine the device type.

feat: sort ticket items by provider code

- Updated the sorting logic in `sortTicketGroupItems` to include provider code for better organization of ticket items.

feat: display provider information in ticket order details

- Added a `providerLabel` function to format provider information.
- Updated `TicketOrderDetailScreen` and `TicketOrdersListScreen` to display provider name and code.

feat: enhance ticket item types with provider information

- Extended `TicketItemListRow` and `TicketItemDetailPayload` types to include optional provider code and name.

feat: add API for fetching bet providers

- Created a new API endpoint to retrieve bet providers.
- Defined types for bet provider data in `bet-provider.ts`.

chore: update player spacing constants

- Adjusted padding values in `player-spacing.ts` for improved layout consistency.
This commit is contained in:
2026-07-08 15:57:09 +08:00
parent 45376473f3
commit add3d1fc05
17 changed files with 619 additions and 104 deletions

View File

@@ -15,6 +15,7 @@ import {
} from "@/features/wallet/wallet-transfer-dialogs";
import { useActivePlayerCurrency } from "@/hooks/use-active-player-currency";
import { useApiQuery } from "@/hooks/use-api-query";
import { useIsMobile } from "@/hooks/use-mobile";
import { formatMinorAsCurrency } from "@/lib/money";
import { isCreditFundingPlayer } from "@/lib/player-funding-mode";
import { PLAYER_CURRENCY_CHANGE_EVENT } from "@/lib/player-currency-preference";
@@ -30,6 +31,7 @@ export function HallWalletStrip() {
const { activeCurrency } = useActivePlayerCurrency();
const { mutate } = useSWRConfig();
const degradedWalletPollRef = useRef<number | null>(null);
const isMobile = useIsMobile();
const currency = activeCurrency;
const isDegraded = mode === "polling" || mode === "offline";
@@ -75,7 +77,7 @@ export function HallWalletStrip() {
return (
<section
className="mb-3 space-y-2.5"
className={cn("mb-3", isMobile ? "space-y-2" : "space-y-2.5")}
aria-label={
isCreditPlayer
? t("wallet.creditAvailable", { defaultValue: "可用信用" })
@@ -84,7 +86,8 @@ export function HallWalletStrip() {
>
<div
className={cn(
"relative overflow-hidden rounded-xl bg-[#e5002c] px-3 py-3 text-white shadow-[0_10px_28px_rgba(229,0,44,0.25)]",
"relative overflow-hidden rounded-xl bg-[#e5002c] text-white shadow-[0_10px_28px_rgba(229,0,44,0.25)]",
isMobile ? "px-3 py-2.5" : "px-3 py-3",
)}
>
<Image
@@ -95,27 +98,34 @@ export function HallWalletStrip() {
className="pointer-events-none object-cover object-center"
aria-hidden
/>
<div className="relative flex items-center gap-3">
<div className="flex size-14 shrink-0 items-center justify-center rounded-full bg-white text-[#d81435] shadow-sm">
<Wallet className="size-7" aria-hidden />
<div className={cn("relative flex items-center", isMobile ? "gap-2.5" : "gap-3")}>
<div
className={cn(
"shrink-0 rounded-full bg-white text-[#d81435] shadow-sm",
isMobile
? "flex size-11 items-center justify-center"
: "flex size-14 items-center justify-center",
)}
>
<Wallet className={cn(isMobile ? "size-5.5" : "size-7")} aria-hidden />
</div>
<div className="min-w-0 flex-1">
<p className="text-sm font-semibold text-white/90">
<p className={cn("font-semibold text-white/90", isMobile ? "text-[13px]" : "text-sm")}>
{isCreditPlayer
? t("wallet.creditAvailable", { defaultValue: "可用信用" })
: t("wallet.balance")}
</p>
{loading ? (
<Skeleton className="mt-2 h-8 w-44 rounded-md bg-white/25" />
<Skeleton className={cn("rounded-md bg-white/25", isMobile ? "mt-1.5 h-7 w-36" : "mt-2 h-8 w-44")} />
) : (
<PlayerMoneyDisplay
amountMinor={headlineMinor}
currency={currency}
className="mt-1 text-white"
className={cn("text-white", isMobile ? "mt-0.5" : "mt-1")}
/>
)}
{isCreditPlayer && !loading && balance ? (
<p className="mt-2 text-xs text-white/75">
<p className={cn("text-white/75", isMobile ? "mt-1 text-[11px]" : "mt-2 text-xs")}>
{t("wallet.creditSummary", {
defaultValue: "授信 {{limit}} · 已用 {{used}}",
limit: formatMinorAsCurrency(balance.credit_limit ?? 0, currency),
@@ -128,12 +138,15 @@ export function HallWalletStrip() {
</div>
{isCreditPlayer ? null : (
<div className="grid grid-cols-2 gap-2.5">
<div className={cn("grid grid-cols-2", isMobile ? "gap-2" : "gap-2.5")}>
<TransferInDialog
idPrefix="hall-"
triggerVariant="hall"
triggerLabel={t("wallet.transferIn")}
triggerClassName="h-12 rounded-lg text-base font-bold"
triggerClassName={cn(
"rounded-lg font-bold",
isMobile ? "h-10 text-sm" : "h-12 text-base",
)}
currency={currency}
lotteryMinor={transferInLotteryMinor}
mainMinor={mainMinor}
@@ -143,7 +156,10 @@ export function HallWalletStrip() {
idPrefix="hall-"
triggerVariant="hall"
triggerLabel={t("wallet.transferOut")}
triggerClassName="h-12 rounded-lg text-base font-bold"
triggerClassName={cn(
"rounded-lg font-bold",
isMobile ? "h-10 text-sm" : "h-12 text-base",
)}
currency={currency}
availableMinor={availableMinor}
onSuccess={async () => { await mutate(BALANCE_KEY(currency)); }}