feat: added web redirect#2087
feat: added web redirect#2087RohitKushvaha01 wants to merge 1 commit intoAcode-Foundation:ajit/fix-fetch-auth-configfrom
Conversation
Greptile SummaryThis PR adds a web-redirect fallback for purchasing paid plugins when Google Play IAP is unavailable: unauthenticated users are sent to the login page and authenticated users are sent directly to the plugin's web purchase page. It also removes the
Confidence Score: 3/5The redirect flow works for first-time purchases, but users who already bought a plugin via web have no path to install it from the sidebar, and the async handler in the detail page view can produce unhandled rejections on auth errors. Two distinct broken user flows exist: the sidebar never checks
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User taps Buy button] --> B{IAP available?}
B -- Yes --> C[Standard IAP purchase flow]
B -- No --> D[auth.getLoggedInUser]
D --> E{User authenticated?}
E -- No --> F[CustomTabs: open web auth page]
E -- Yes --> G[CustomTabs: open plugin web page]
F --> H[Return - no install]
G --> I[Return - no install]
Reviews (1): Last reviewed commit: "feat: added web redirect" | Re-trigger Greptile |
| async function openPluginWebsite() { | ||
| const user = await auth.getLoggedInUser(); | ||
| if (!user) { | ||
| CustomTabs.open( | ||
| `${config.BASE_URL}/login?redirect=app`, | ||
| { showTitle: true }, | ||
| () => {}, | ||
| () => {}, | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| CustomTabs.open( | ||
| `${config.BASE_URL}/plugin/${id}`, | ||
| { showTitle: true }, | ||
| () => {}, | ||
| () => {}, | ||
| ); | ||
| } |
There was a problem hiding this comment.
Unhandled promise rejection in
openPluginWebsite
openPluginWebsite is an async function called directly from an onclick handler, but it has no try/catch. If auth.getLoggedInUser() rejects (e.g. network error, token parse failure), the rejection is silently swallowed by the browser and the user sees nothing. Add a try/catch and surface the error the same way the rest of the file does (helpers.error or alert).
| const isPaid = remotePlugin.price > 0; | ||
| if (isPaid && !config.IAP_AVAILABLE) { | ||
| const user = await auth.getLoggedInUser(); | ||
| if (!user) { | ||
| CustomTabs.open( | ||
| `${config.BASE_URL}/login?redirect=app`, | ||
| { showTitle: true }, | ||
| () => {}, | ||
| () => {}, | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| CustomTabs.open( | ||
| `${config.BASE_URL}/plugin/${remotePlugin.id}`, | ||
| { showTitle: true }, | ||
| () => {}, | ||
| () => {}, | ||
| ); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Purchased plugins always redirected to web when IAP is unavailable
When isPaid && !config.IAP_AVAILABLE, the code unconditionally redirects to the web without first checking remotePlugin.owned. In contrast, plugin.js sets purchased = remotePlugin.owned and only shows the buy flow for unpurchased plugins. A user who already paid for a plugin via the web redirect will hit this branch on every install attempt and be sent back to the web again rather than being allowed to install — they have no way to complete the install from the sidebar.
Consider checking remotePlugin.owned (or an equivalent field) before redirecting, as plugin.js does.
| if (!config.IAP_AVAILABLE) { | ||
| const user = await auth.getLoggedInUser(); | ||
| if (!user) { | ||
| CustomTabs.open( | ||
| `${config.BASE_URL}/login?redirect=app`, | ||
| { showTitle: true }, | ||
| () => {}, | ||
| () => {}, | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| CustomTabs.open( | ||
| `${config.BASE_URL}/plugin/${plugin.id}`, | ||
| { showTitle: true }, | ||
| () => {}, | ||
| () => {}, | ||
| ); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Dead code:
!config.IAP_AVAILABLE block in buy() is never reached
When !config.IAP_AVAILABLE, plugin.view.js's Buttons component renders the buy button with onclick={openPluginWebsite} (a local function), not with the buy prop. So this guard block inside buy() will never execute from the plugin detail page. The redirect logic for this scenario lives entirely in openPluginWebsite; this copy adds confusion without adding safety.
| if (!config.IAP_AVAILABLE && isPaid && !purchased && price) { | ||
| return ( | ||
| <button | ||
| data-type="buy" | ||
| className="btn btn-install" | ||
| onclick={openPluginWebsite} | ||
| > | ||
| <i className="icon open_in_browser"></i> | ||
| {price} | ||
| </button> | ||
| ); | ||
| } |
There was a problem hiding this comment.
No loading/disabled state on the web-redirect buy button
openPluginWebsite performs an async auth.getLoggedInUser() call before opening the browser tab, but the button is never disabled during that window. Multiple rapid taps will queue multiple CustomTabs.open calls, potentially opening several browser tabs. Setting button.disabled = true at the start of openPluginWebsite (or mirroring how the IAP buy path sets loading text) would prevent this.
| className="list-item" | ||
| data-action="open" | ||
| data-installed={(!!installed).toString()} | ||
| data-paid={(price > 0).toString()} |
There was a problem hiding this comment.
No description provided.