Implement comprehensive topup billing system with user history viewing and admin management capabilities.
## Features Added
### Frontend
- Add topup history modal with paginated billing records
- Display order details: trade number, payment method, amount, money, status, create time
- Implement empty state with proper illustrations
- Add payment method column with localized display (Stripe, Alipay, WeChat)
- Add admin manual completion feature for pending orders
- Add Coins icon for recharge amount display
- Integrate "Bills" button in RechargeCard header
- Optimize code quality by using shared utility functions (isAdmin)
- Extract constants for status and payment method mappings
- Use React.useMemo for performance optimization
### Backend
- Create GET `/api/user/topup/self` endpoint for user topup history with pagination
- Create POST `/api/user/topup/complete` endpoint for admin manual order completion
- Add `payment_method` field to TopUp model for tracking payment types
- Implement `GetUserTopUps` method with proper pagination and ordering
- Implement `ManualCompleteTopUp` with transaction safety and row-level locking
- Add application-level mutex locks to prevent concurrent order processing
- Record payment method in Epay and Stripe payment flows
- Ensure idempotency and data consistency with proper error handling
### Internationalization
- Add i18n keys for Chinese (zh), English (en), and French (fr)
- Support for billing-related UI text and status messages
## Technical Improvements
- Use database transactions with FOR UPDATE row-level locking
- Implement sync.Map-based mutex for order-level concurrency control
- Proper error handling and user-friendly toast notifications
- Follow existing codebase patterns for empty states and modals
- Maintain code quality with extracted render functions and constants
## Files Changed
- Backend: controller/topup.go, controller/topup_stripe.go, model/topup.go, router/api-router.go
- Frontend: web/src/components/topup/modals/TopupHistoryModal.jsx (new), web/src/components/topup/RechargeCard.jsx, web/src/components/topup/index.jsx
- i18n: web/src/i18n/locales/{zh,en,fr}.json
- Replace blanket console route footer hiding with specific page targeting
- Only hide footer on pages that use CardPro component:
* /console/channel (channels management)
* /console/log (usage logs)
* /console/redemption (redemption codes)
* /console/user (user management)
* /console/token (token management)
* /console/midjourney (midjourney logs)
* /console/task (task logs)
* /console/models (model management)
* /pricing (pricing page)
- Footer now displays on other console pages (dashboard, settings, topup, etc.)
- Improves UI consistency by showing footer where CardPro's internal pagination isn't used
This change ensures footer is only hidden when CardPro component provides its own
pagination/footer functionality, while preserving footer visibility on other pages
that benefit from the global footer navigation.
- Ran: bun run eslint:fix && bun run lint:fix
- Inserted AGPL license header via eslint-plugin-header
- Enforced no-multiple-empty-lines and other lint rules
- Formatted code using Prettier v3 (@so1ve/prettier-config)
- No functional changes; formatting-only baseline across JS/JSX files
Reduce KPI font size on small screens to prevent overlapping of large
numbers while preserving the desktop layout.
Changes:
- InvitationCard.jsx: use `text-base sm:text-2xl` for
pending earnings, total earnings, and invite count.
- RechargeCard.jsx: use `text-base sm:text-2xl` for
current balance, historical usage, and request count.
Impact:
- Visual-only; no behavioral changes.
- Desktop/tablet unchanged.
- Lint passes.
Files:
- web/src/components/topup/InvitationCard.jsx
- web/src/components/topup/RechargeCard.jsx
Replace the fallback assignment of serverAddress in `web/src/pages/Home/index.jsx`
to use a template literal for `window.location.origin`.
- Aligns with the preferred style for constructing base URLs
- Keeps formatting consistent across the app
- No functional changes; behavior remains the same
- Lint passes with no new warnings or errors
Files affected:
- web/src/pages/Home/index.jsx
- Unify TopUp into a single-page layout and remove tabs
- Replace custom inputs with Semi UI Form components (Form.Input, Form.InputNumber, Form.Slot)
- Move online recharge form into the stats Card content for tighter, consistent layout
- Add account stats Card with blue theme (consistent with InvitationCard style)
- Remove RightStatsCard and inline the stats UI directly in RechargeCard
- Change preset amount UI to horizontal quick-action Buttons; swap order with payment methods
- Replace payment method Cards with Semi UI Buttons
- Use Button icon prop for Alipay/WeChat/Stripe with brand colors
- Use built-in Button loading; remove custom “processing...” text
- Replace custom spinners with Semi UI Spin and keep Skeleton for amount loading
- Wrap Redeem Code in a Card; use Typography for “Looking for a code? Buy Redeem Code” link
- Show info Banner when online recharge is disabled (instead of warning)
TopUp data flow and logic
- Generate preset amounts from min_topup using multipliers [1,5,10,30,50,100,300,500]
- Deduplicate /api/user/aff using a ref guard; fetch only once on mount
- Simplify user self fetch: update context only; remove unused local states and helpers
- Normalize payment method keys to alipay/wxpay/stripe and assign default colors
Cleanup
- Delete web/src/components/topup/RightStatsCard.jsx
- Remove unused helpers and local states in index.jsx (userQuota, userDataLoading, getUsername)
Dev notes
- No API changes; UI/UX refactor only
- Lint clean (no new linter errors)
Files
- web/src/components/topup/RechargeCard.jsx
- web/src/components/topup/index.jsx
- web/src/components/topup/InvitationCard.jsx (visual parity reference)
- web/src/components/topup/RightStatsCard.jsx (removed)
Summary
• Extracted `LogoSection`, `NavLinks`, `UserArea`, and `ActionButtons` from `HeaderBar.js`, reducing complexity and improving readability.
• Removed unused state, handlers, and redundant imports from `HeaderBar.js`.
• Simplified mobile/desktop logic:
– Menu icon now shows only on mobile `/console` routes.
– Logo, system name, and mode tags appear on all desktop screens and on mobile non-console pages.
• Reworked skeleton loaders:
– Narrower width on mobile (`40 px`) and clearer spacing (`p-1`).
• Added global `.scrollbar-hide` utility in `index.css` to enable scrollable areas without visible scrollbars.
• Ensured nav bar is horizontally scrollable across all breakpoints.
• Cleaned up language-switch, New Year, and notice handlers; consolidated side effects.
• Updated imports and internal calls after component extraction.
• Passed required props to new sub-components and removed obsolete ones.
• Confirmed zero linter warnings after refactor.
Why
Breaking the monolithic header into focused components makes future updates simpler, facilitates isolation testing, and aligns with the existing component architecture under `components/`. The UI tweaks provide a better mobile experience and consistent styling across devices.
Notes
No backend changes required. All routes and contexts remain untouched.
- AccountManagement.js
- Prevent action button from shifting when account IDs are long by adding gap, min-w-0, and flex-shrink-0; keep buttons in a fixed position.
- Add copyable Popover for account identifiers (email/GitHub/OIDC/Telegram/LinuxDO) using Typography.Paragraph with copyable; reveal full text on hover.
- Ensure ellipsis works by rendering the popover trigger as `block max-w-full truncate`.
- Import Popover and wire up `renderAccountInfo` across all binding rows.
- UserInfoHeader.js
- Apply unified `with-pastel-balls` background to match PricingVendorIntro.
- Remove legacy absolute-positioned circles and top gradient bar to avoid visual overlap.
- RechargeCard.jsx
- Colorize non-Alipay/WeChat/Stripe payment icons using backend `pay_methods[].color`; fallback to `var(--semi-color-text-2)`.
- Add `showClear` to the redemption code input for quicker clearing.
Notes:
- No linter errors introduced.
- i18n strings and behavior remain unchanged except for improved UX and visual consistency.
- Add RightStatsCard and place it in RechargeCard header
- Shows current balance, historical spend, and request count
- Mobile: stacks under title; three metrics split equally (flex-1); vertical dividers hidden on small screens
- Remove extra margins; small card styling
- RechargeCard
- Replace redeem code Input icon with Semi UI IconGift
- Style “Payable amount” number in red and bold; keep same style in confirm modal
- Always render payment methods as Cards (remove Button variant) with adaptive grid
- Use brand color icons: SiAlipay (#1677FF), SiWechat (#07C160), SiStripe (#635BFF)
- Replace Stripe icon with SiStripe
- Integrate RightStatsCard props; adjust header to flex-col on mobile and flex-row on desktop
- Hide Banner close button when online top-up is disabled (closeIcon={null})
- InvitationCard
- Simplify to match RechargeCard’s minimalist slate style
- Use Card title for “Rewards” and place content directly in body
- Improve link input and copy button; use Badge dots for bullet points
- TopUp index
- Remove separate right-column stats card; pass userState and renderQuota to RechargeCard
- Cleanup
- Lint passes; no functional changes to APIs or business logic