Move billing fields from settings.json to store.json (TinybaseValues)#3458
Move billing fields from settings.json to store.json (TinybaseValues)#3458devin-ai-integration[bot] wants to merge 1 commit intomainfrom
Conversation
- Remove billing fields from settings.ts SETTINGS_MAPPING (no longer stored in settings.json) - Add billing fields to valueSchemaForTinybase in packages/store (stored in store.json via TinybaseValues) - Remove redundant trial_start_checked_at (already encoded in JWT) - Update hooks to use main store instead of settings store for billing values Co-Authored-By: yujonglee <yujonglee.dev@gmail.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
✅ Deploy Preview for hyprnote-storybook canceled.
|
✅ Deploy Preview for hyprnote canceled.
|
| hasCheckedRef.current = true; | ||
|
|
||
| if (canStartTrial) { |
There was a problem hiding this comment.
🔴 Removing trial_start_checked_at causes trial start API to be called on every app launch
The removal of the trial_start_checked_at persistence check causes startTrial() to be called on every app launch before the actual canStartTrial value is fetched from the server.
Click to expand
Root Cause
In billing.tsx:71, canStartTrial defaults to true while the query is loading:
const canStartTrial = isPro ? false : (canTrialQuery.data ?? true);The effect in useTrialStartOnFirstLaunch.ts runs immediately when isAuthenticated becomes true. Since canStartTrial is true (the default value before the API response), startTrial() is called:
useEffect(() => {
if (hasCheckedRef.current || !store || !isAuthenticated) {
return;
}
hasCheckedRef.current = true;
if (canStartTrial) {
startTrial(); // Called with canStartTrial = true (default)
}
}, [isAuthenticated, canStartTrial, store, startTrial]);Previous Behavior
The old code persisted trial_start_checked_at in the store to prevent this across app restarts:
const checkedAt = store.getValue("trial_start_checked_at");
if (checkedAt) {
hasCheckedRef.current = true;
return;
}
store.setValue("trial_start_checked_at", Date.now());Impact
- Unnecessary
postBillingStartTrialAPI calls on every app launch - The server will reject duplicate trial starts, but this wastes bandwidth and server resources
- Could cause race conditions or unexpected behavior in the billing system
(Refers to lines 73-77)
Recommendation: Either keep the trial_start_checked_at persistence check, or change canStartTrial to default to false while loading (e.g., canTrialQuery.data ?? false), or wait for the query to complete before running the effect by checking canTrialQuery.isSuccess.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Moves billing-related UI state fields from
settings.jsontostore.jsonusing the store2 plugin (TinybaseValues). The billing fields (trial_expired_modal_dismissed_at,trial_begin_modal_pending,pro_subscription_modal_shown_at) are not settings concerns and belong in the local store.Additionally removes
trial_start_checked_atentirely as it's redundant - this information is already encoded in the JWT andcanStartTrialfromuseBillingAccess()handles this check.Changes:
SETTINGS_MAPPINGin settings.tsvalueSchemaForTinybasein packages/storetrial_start_checked_atlogic inuseTrialStartOnFirstLaunchReview & Testing Checklist for Human
canStartTrialis sufficient: Confirm that removingtrial_start_checked_atcheck doesn't cause duplicate trial start attempts - thecanStartTrialfromuseBillingAccess()should handle this via JWTNotes
Link to Devin run: https://app.devin.ai/sessions/670ae6c5cdf64ce2bdb6a7c4fa86973e
Requested by: @yujonglee