feat: support subscription redemption codes - #5084
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThis PR extends redemption code functionality to support subscription plan grants alongside quota grants, implementing backend validation, data models, error handling, comprehensive testing, and full-stack frontend UI with multi-language support. It also adds Claude file relay handling and improves stream scanner resilience. ChangesSubscription Redemption Code Implementation
Infrastructure and Relay Improvements
🎯 4 (Complex) | ⏱️ ~60 minutes Suggested Reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (1)
web/classic/src/i18n/locales/zh-CN.json (1)
3811-3811: 💤 Low valueQuestionable translation key: standalone punctuation
The key-value pair
"、": "、"is unusual. The Chinese enumeration comma (、) is typically embedded directly within translated strings rather than defined as a separate translation key.Unless there's a specific use case requiring this standalone punctuation key, consider removing it or documenting its purpose. If it's meant to be used in dynamic string concatenation, that pattern should be avoided in favor of proper i18n interpolation.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/classic/src/i18n/locales/zh-CN.json` at line 3811, The translation file contains a questionable standalone key "、" mapping to itself; remove this standalone punctuation key from the locale (or add a clear comment/documentation in the repo explaining its specific intended use) and refactor any code that consumes it to use proper i18n interpolation/placeholders in functions like t(...) instead of concatenating a punctuation translation; look for usages of the symbol "、" in templates or code and replace dynamic concatenation with interpolation in the relevant translation keys.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@model/redemption.go`:
- Around line 286-288: The DB query that populates plans (the DB.Select("id",
"title").Where("id IN ?", planIDs).Find(&plans).Error check) is currently
returning silently on error; instead log the error with context (include the
error value and planIDs) and return the error up the stack (or at minimum return
after logging) so failures aren't swallowed; make the same change for the second
identical check later in the file (the other DB.Select(...).Find(&plans).Error
usage) and use the project’s logger (or log.Printf/log.Errorf) to emit a clear
message referencing "plans" and the planIDs variable.
In `@relay/channel/claude/relay-claude.go`:
- Around line 380-398: The code currently silently skips file parts in the
dto.ContentTypeFile branch (when file.FileData == "" or when mimeType is
unsupported), which can cause the request to proceed with missing attachments;
update the dto.ContentTypeFile handling (the block that reads
mediaMessage.GetFile(), uses mimeTypeFromMessageFile, and appends to
claudeMediaMessages with dto.ClaudeMediaMessage) to instead return a validation
error when file.FileData is empty but file.FileID exists (or when file is
entirely missing) and to return a clear validation error for unsupported MIME
types (i.e., not text/* or application/pdf) rather than continue; ensure the
error messages reference the offending file (file.FileID or a description) so
callers can correct the input.
In `@web/classic/src/components/topup/index.jsx`:
- Around line 179-210: The subscription-success branch (when
isSubscriptionRedemption is true) updates messaging but does not refresh the
subscriptions state (activeSubscriptions / allSubscriptions); add an await call
after the Modal.success in that branch to invoke the same routine that refreshes
subscriptions (the function used elsewhere to populate
activeSubscriptions/allSubscriptions — e.g.
fetchSubscriptions()/loadSubscriptions()/getSubscriptions()), similar to the
existing await getUserQuota() call at the end, so the UI updates immediately
after redemption.
In
`@web/default/src/features/redemption-codes/components/redemptions-mutate-drawer.tsx`:
- Around line 106-117: The effect that loads plans when the drawer opens
(useEffect dependent on open) currently calls getAdminPlans() but doesn't handle
promise rejections, which can leave stale plans; wrap the fetch in a try/catch
(or add .catch) and on any error or non-success result call setPlans([]) and
log/report the error so rejected promises are handled; update the block that
calls getAdminPlans() to ensure failures always clear plans (setPlans([])) and
avoid unhandled rejections.
In `@web/default/src/features/redemption-codes/lib/redemption-form.ts`:
- Line 42: The validation for quota_dollars in the redemption form uses
z.number().min(0) but the error text says "Quota must be a positive number";
update either the rule or the message to match: either change the schema to
z.number().min(1, t('Quota must be a positive number')) if zero should be
disallowed, or keep min(0) and change the message to t('Quota must be a
non-negative number') (update the quota_dollars line accordingly).
In `@web/default/src/features/wallet/hooks/use-redemption.ts`:
- Around line 45-59: The conditional currently treats response.data as an object
but doesn't guard against null (typeof null === 'object'); update the checks in
use-redemption.ts so you verify response.data is non-null before accessing
properties — e.g., change occurrences like "typeof response.data === 'object' &&
response.data.redemption_type === 'subscription'" to explicitly ensure
response.data != null (or response.data !== null) first, and similarly guard
access to response.data.subscription_plan_title,
response.data.subscription_plan_id and response.data.quota when computing
quotaAdded.
In `@web/default/src/i18n/locales/fr.json`:
- Line 539: Multiple billing/subscription strings in fr.json are still English
(e.g., the key/value pair "Bind a Pancake store + product": "Bind a Pancake
store + product"); replace these English values with their proper French
translations (or remove the entries so the app falls back to the base locale)
for that key and for the other affected entries referenced (lines/ranges you
listed). Locate and update the exact keys in
web/default/src/i18n/locales/fr.json (for example the "Bind a Pancake store +
product" key and the other keys in the ranges 566-567, 1033-1035, 1039-1040,
etc.) to French strings consistent with the UX, ensuring grammar and context
match billing/checkout flows.
In `@web/default/src/i18n/locales/ja.json`:
- Line 539: Several entries in the Japanese locale file are left in English
(e.g., the string key "Bind a Pancake store + product" and other entries listed
in the review) — locate those literal English values in ja.json (search for
"Bind a Pancake store + product" and the other English phrases around the
reported ranges) and replace them with accurate Japanese translations,
preserving the exact JSON keys, punctuation and any interpolation placeholders;
after editing, validate the JSON and run the i18n linter/tests to ensure no
missing keys or formatting issues.
In `@web/default/src/i18n/locales/ru.json`:
- Line 539: The Russian locale file contains untranslated English values (e.g.,
the key "Bind a Pancake store + product") which leads to mixed-language UI;
update the ru.json entries so the values are proper Russian translations for
that key and the other newly added keys referenced (those still showing English
strings), preserving the exact JSON keys and formatting, keeping any
placeholders intact, and run a quick lint/parse to ensure valid JSON after
replacing the English text with Russian equivalents.
In `@web/default/src/i18n/locales/vi.json`:
- Line 539: The added English entry "Bind a Pancake store + product" in vi.json
(and the other listed English lines) must be translated into Vietnamese before
merging; update the value for the "Bind a Pancake store + product" key (and the
entries at the provided locations: 566-567, 1033-1040, etc.) with accurate
Vietnamese translations, preserving any punctuation/placeholders and JSON string
formatting, then run the i18n JSON validator/linter to ensure no syntax errors
and that plural/placeholders remain intact (search for the English phrases in
vi.json to locate each key).
---
Nitpick comments:
In `@web/classic/src/i18n/locales/zh-CN.json`:
- Line 3811: The translation file contains a questionable standalone key "、"
mapping to itself; remove this standalone punctuation key from the locale (or
add a clear comment/documentation in the repo explaining its specific intended
use) and refactor any code that consumes it to use proper i18n
interpolation/placeholders in functions like t(...) instead of concatenating a
punctuation translation; look for usages of the symbol "、" in templates or code
and replace dynamic concatenation with interpolation in the relevant translation
keys.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2ba913ee-e480-4f20-9d05-f4839bbd99a7
📒 Files selected for processing (40)
controller/model.gocontroller/redemption.gocontroller/redemption_topup_test.gocontroller/user.gomodel/errors.gomodel/redemption.gomodel/redemption_subscription_test.gomodel/task_cas_test.gorelay/channel/claude/relay-claude.gorelay/helper/stream_scanner.goweb/classic/src/components/table/redemptions/RedemptionsColumnDefs.jsxweb/classic/src/components/table/redemptions/modals/EditRedemptionModal.jsxweb/classic/src/components/topup/index.jsxweb/classic/src/i18n/locales/en.jsonweb/classic/src/i18n/locales/fr.jsonweb/classic/src/i18n/locales/ja.jsonweb/classic/src/i18n/locales/ru.jsonweb/classic/src/i18n/locales/vi.jsonweb/classic/src/i18n/locales/zh-CN.jsonweb/classic/src/i18n/locales/zh-TW.jsonweb/classic/src/i18n/locales/zh.jsonweb/default/src/features/redemption-codes/components/redemptions-columns.tsxweb/default/src/features/redemption-codes/components/redemptions-mutate-drawer.tsxweb/default/src/features/redemption-codes/lib/redemption-form.tsweb/default/src/features/redemption-codes/types.tsweb/default/src/features/wallet/hooks/use-redemption.tsweb/default/src/features/wallet/types.tsweb/default/src/i18n/locales/_reports/_sync-report.jsonweb/default/src/i18n/locales/_reports/fr.untranslated.jsonweb/default/src/i18n/locales/_reports/ja.untranslated.jsonweb/default/src/i18n/locales/_reports/ru.untranslated.jsonweb/default/src/i18n/locales/_reports/vi.untranslated.jsonweb/default/src/i18n/locales/_reports/zh.untranslated.jsonweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.jsonweb/default/src/i18n/static-keys.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/src/features/redemption-codes/lib/redemption-form.ts`:
- Line 42: The quota_dollars schema currently enforces z.number().min(1)
unconditionally which breaks subscription-type redemptions that legitimately
have quota 0; update the validation in redemption-form.ts so quota_dollars
allows 0 for subscription redemptions (or is optional/nullable when
redemptionType === 'subscription'). Locate the quota_dollars definition(s) (the
z.number().min(1, ...) lines) and replace with a conditional rule or refine the
parent schema to use z.preprocess/z.union or .refine that checks redemptionType
(or makes quota_dollars optional) so existing subscription codes from the
backend with quota 0 pass validation; apply the same change to the other
occurrences referenced (the blocks around the other quota_dollars definitions).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 1c09469f-7a96-48c8-953a-b86f335ff8f2
📒 Files selected for processing (25)
model/redemption.gorelay/channel/claude/relay-claude.gorelay/channel/claude/relay_claude_test.goweb/classic/src/components/settings/PaymentSetting.jsxweb/classic/src/components/topup/index.jsxweb/classic/src/i18n/locales/en.jsonweb/classic/src/i18n/locales/fr.jsonweb/classic/src/i18n/locales/ja.jsonweb/classic/src/i18n/locales/ru.jsonweb/classic/src/i18n/locales/vi.jsonweb/classic/src/i18n/locales/zh-CN.jsonweb/classic/src/i18n/locales/zh-TW.jsonweb/classic/src/i18n/locales/zh.jsonweb/default/src/features/redemption-codes/components/redemptions-mutate-drawer.tsxweb/default/src/features/redemption-codes/lib/redemption-form.tsweb/default/src/features/wallet/hooks/use-redemption.tsweb/default/src/i18n/locales/_reports/_sync-report.jsonweb/default/src/i18n/locales/_reports/fr.untranslated.jsonweb/default/src/i18n/locales/_reports/ja.untranslated.jsonweb/default/src/i18n/locales/_reports/ru.untranslated.jsonweb/default/src/i18n/locales/_reports/vi.untranslated.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.json
💤 Files with no reviewable changes (12)
- web/classic/src/i18n/locales/fr.json
- web/classic/src/i18n/locales/ru.json
- web/classic/src/i18n/locales/ja.json
- web/classic/src/i18n/locales/zh-TW.json
- web/classic/src/i18n/locales/zh.json
- web/default/src/i18n/locales/_reports/ru.untranslated.json
- web/classic/src/i18n/locales/en.json
- web/default/src/i18n/locales/_reports/fr.untranslated.json
- web/default/src/i18n/locales/_reports/ja.untranslated.json
- web/classic/src/i18n/locales/zh-CN.json
- web/default/src/i18n/locales/_reports/vi.untranslated.json
- web/classic/src/i18n/locales/vi.json
✅ Files skipped from review due to trivial changes (1)
- web/default/src/i18n/locales/ru.json
…n-redemption-codes
…n-redemption-codes # Conflicts: # web/default/src/features/redemption-codes/components/redemptions-mutate-drawer.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
web/default/src/i18n/locales/ru.json (1)
527-527:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUntranslated English values are still present in
ru.json.These entries are still English and will cause mixed-language UI in the RU locale. Please localize them to Russian (keeping placeholders unchanged).
Tags:
Also applies to: 707-707, 3173-3173, 3185-3185, 3187-3187, 3538-3538, 3709-3709, 3744-3744
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@web/default/src/i18n/locales/ru.json` at line 527, Several keys in the Russian locale file still have English values (e.g., the "Benefit" key and the other entries referenced at positions 707, 3173, 3185, 3187, 3538, 3709, 3744); update each value to its proper Russian translation while preserving all JSON syntax, punctuation and any interpolation placeholders (e.g., {0}, {{name}}) exactly as-is. Locate the keys (such as "Benefit") in web/default/src/i18n/locales/ru.json, replace the English strings with Russian equivalents, keep surrounding quotes and trailing commas intact, and run a quick JSON lint to ensure no formatting errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/src/i18n/locales/vi.json`:
- Line 527: The vi.json localization contains untranslated English strings for
the redemption/subscription UX (e.g., the "Benefit" key) causing mixed-language
UI; open web/default/src/i18n/locales/vi.json, find the English-valued keys
related to redemption/subscription (including the "Benefit" key and the other
recently changed entries) and replace their values with proper Vietnamese
translations that match tone and context of adjacent keys so the UI is fully
localized.
---
Duplicate comments:
In `@web/default/src/i18n/locales/ru.json`:
- Line 527: Several keys in the Russian locale file still have English values
(e.g., the "Benefit" key and the other entries referenced at positions 707,
3173, 3185, 3187, 3538, 3709, 3744); update each value to its proper Russian
translation while preserving all JSON syntax, punctuation and any interpolation
placeholders (e.g., {0}, {{name}}) exactly as-is. Locate the keys (such as
"Benefit") in web/default/src/i18n/locales/ru.json, replace the English strings
with Russian equivalents, keep surrounding quotes and trailing commas intact,
and run a quick JSON lint to ensure no formatting errors.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 529748c8-c490-4504-b9ab-56060b825d6e
📒 Files selected for processing (14)
controller/user.goweb/classic/src/components/settings/PaymentSetting.jsxweb/default/src/features/redemption-codes/components/redemptions-columns.tsxweb/default/src/features/redemption-codes/components/redemptions-mutate-drawer.tsxweb/default/src/features/redemption-codes/lib/redemption-form.tsweb/default/src/i18n/locales/_reports/_sync-report.jsonweb/default/src/i18n/locales/en.jsonweb/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.jsonweb/default/src/i18n/static-keys.tsweb/default/src/routes/_authenticated/usage-logs/$section.tsx
💤 Files with no reviewable changes (4)
- web/classic/src/components/settings/PaymentSetting.jsx
- web/default/src/routes/_authenticated/usage-logs/$section.tsx
- web/default/src/i18n/static-keys.ts
- web/default/src/i18n/locales/zh.json
✅ Files skipped from review due to trivial changes (2)
- web/default/src/i18n/locales/_reports/_sync-report.json
- web/default/src/i18n/locales/fr.json
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/src/i18n/locales/vi.json`:
- Line 707: The Vietnamese translation for the key "Choose whether this code
grants quota or a plan" is grammatically awkward; update the value in vi.json
for that exact key to a more natural phrasing such as "Chọn xem mã này cấp hạn
mức hay cấp gói đăng ký" so the UX copy reads smoothly; locate the string
exactly ("Choose whether this code grants quota or a plan") and replace its
value with the suggested Vietnamese sentence (or an equivalent natural variant).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d20aa913-65b7-4e7e-b258-764eee4d57ab
📒 Files selected for processing (3)
web/default/src/i18n/locales/_reports/_sync-report.jsonweb/default/src/i18n/locales/ru.jsonweb/default/src/i18n/locales/vi.json
✅ Files skipped from review due to trivial changes (1)
- web/default/src/i18n/locales/_reports/_sync-report.json
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@web/default/src/i18n/locales/vi.json`:
- Line 707: Replace the sentence-style translation key "Choose whether this code
grants quota or a plan" in the vi.json locale with a hierarchical key such as
redemption.form.benefitType.description, move the translated string under that
new key, and update all consumers that reference the old sentence key (e.g., any
i18n.t(...) or <Trans> usages) to use "redemption.form.benefitType.description"
instead; ensure you remove the old flat key to avoid duplication and keep naming
consistent across other locales.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 68ea2b80-7223-425b-aa7c-30a8c577add4
📒 Files selected for processing (4)
web/default/src/i18n/locales/fr.jsonweb/default/src/i18n/locales/ja.jsonweb/default/src/i18n/locales/vi.jsonweb/default/src/i18n/locales/zh.json
提交说明 / PR Notice
Compare:
main...fishxcode:newapi:feature/subscription-redemption-codes
变更描述 / Description
本 PR 为兑换码增加“订阅套餐兑换码”能力,同时保持原有额度兑换码行为兼容。
主要变更:
Redemption增加兑换类型、订阅套餐 ID、套餐标题展示字段。/api/user/topup的data继续返回数字,避免影响旧前端或外部调用方。变更类型 / Type of change
关联任务 / Related Issue
提交前检查项 / Checklist
运行证明 / Proof of Work
本地验证通过:
功能核对:
number | object。number | object。Summary by CodeRabbit
New Features
Bug Fixes
Internationalization
Tests