Skip to content

feat: added web redirect#2087

Draft
RohitKushvaha01 wants to merge 1 commit intoAcode-Foundation:ajit/fix-fetch-auth-configfrom
RohitKushvaha01:ajit/fix-fetch-auth-config
Draft

feat: added web redirect#2087
RohitKushvaha01 wants to merge 1 commit intoAcode-Foundation:ajit/fix-fetch-auth-configfrom
RohitKushvaha01:ajit/fix-fetch-auth-config

Conversation

@RohitKushvaha01
Copy link
Copy Markdown
Member

No description provided.

@RohitKushvaha01 RohitKushvaha01 marked this pull request as draft May 6, 2026 13:50
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 6, 2026

Greptile Summary

This 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 proot and iap Cordova plugin dependencies.

  • Web redirect flow added across plugin.js, plugin.view.js, and sidebarApps/extensions/index.js: when !config.IAP_AVAILABLE and the plugin is paid, auth.getLoggedInUser() is called and CustomTabs.open navigates to the appropriate URL.
  • New Buttons branch in plugin.view.js renders a distinct "open in browser" buy button (with open_in_browser icon) when IAP is unavailable, wired to a local openPluginWebsite handler rather than the IAP buy prop.
  • data-paid DOM attribute added to plugin list items in item.js; currently not read by any code.

Confidence Score: 3/5

The 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 remotePlugin.owned so previously-purchased plugins always bounce back to the web, and openPluginWebsite has no error handling, meaning any auth failure produces a silent crash in the UI. These affect the core paid-plugin journey added by this PR.

src/sidebarApps/extensions/index.js (missing ownership check before redirect) and src/pages/plugin/plugin.view.js (missing try/catch and button guard in openPluginWebsite).

Important Files Changed

Filename Overview
src/pages/plugin/plugin.view.js Adds openPluginWebsite async handler and a new IAP-unavailable buy button path; missing try/catch in the handler and no button debounce.
src/sidebarApps/extensions/index.js Adds IAP-unavailable redirect for paid plugins, but does not check remotePlugin.owned, blocking install for users who already purchased via web.
src/pages/plugin/plugin.js Adds !config.IAP_AVAILABLE guard in buy(), but the block is unreachable from the detail page since plugin.view.js uses openPluginWebsite instead.
src/pages/plugins/item.js Adds data-paid DOM attribute that is not consumed anywhere in the codebase.
package.json Removes proot and iap Cordova plugin dependencies.
package-lock.json Lockfile updated to reflect removal of proot and iap plugins; marks them as extraneous.

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]
Loading

Reviews (1): Last reviewed commit: "feat: added web redirect" | Re-trigger Greptile

Comment on lines +288 to +306
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 },
() => {},
() => {},
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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).

Comment on lines 775 to +795
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;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Comment on lines +256 to +275
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;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

Comment on lines +370 to +381
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>
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

Comment thread src/pages/plugins/item.js
className="list-item"
data-action="open"
data-installed={(!!installed).toString()}
data-paid={(price > 0).toString()}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 data-paid attribute is written but never read

The attribute is set on the list item element but no code in the repository reads or selects by data-paid. If this is intended for future use or CSS styling, a brief comment would help clarify intent; otherwise it adds unnecessary noise to the DOM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant