Skip to content

Commit

Permalink
refactor: fix default installed handling
Browse files Browse the repository at this point in the history
  • Loading branch information
janniks committed Nov 17, 2023
1 parent 8135687 commit 47c2eb7
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 78 deletions.
10 changes: 5 additions & 5 deletions packages/connect-ui/src/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
* It contains typing information for all components that exist in this project.
*/
import { HTMLStencilElement, JSXBase } from "@stencil/core/internal";
import { StxProvider } from "./providers";
import { WebBTCProvider } from "./providers";
export namespace Components {
interface ConnectModal {
"callback": Function;
"defaultProviders": StxProvider[];
"registeredProviders": StxProvider[];
"defaultProviders": WebBTCProvider[];
"installedProviders": WebBTCProvider[];
}
}
declare global {
Expand All @@ -27,8 +27,8 @@ declare global {
declare namespace LocalJSX {
interface ConnectModal {
"callback"?: Function;
"defaultProviders"?: StxProvider[];
"registeredProviders"?: StxProvider[];
"defaultProviders"?: WebBTCProvider[];
"installedProviders"?: WebBTCProvider[];
}
interface IntrinsicElements {
"connect-modal": ConnectModal;
Expand Down
54 changes: 29 additions & 25 deletions packages/connect-ui/src/components/modal/modal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Component, Element, Prop, h } from '@stencil/core';
import { StxProvider } from '../../providers';
import { WebBTCProvider } from '../../providers';
import { setSelectedProvider } from '../../session';
import CloseIcon from './assets/close-icon.svg';
import { getBrowser, getPlatform } from './utils';
Expand All @@ -11,8 +11,8 @@ import { getBrowser, getPlatform } from './utils';
shadow: true,
})
export class Modal {
@Prop() defaultProviders: StxProvider[];
@Prop() registeredProviders: StxProvider[];
@Prop() defaultProviders: WebBTCProvider[];
@Prop() installedProviders: WebBTCProvider[];

@Prop() callback: Function;

Expand All @@ -30,8 +30,8 @@ export class Modal {
}

// todo: nice to have:
// getComment(provider: StxProvider, browser: string, isMobile?: string) {
// if (!provider.urls) return null;
// getComment(provider: WebBTCProvider, browser: string, isMobile?: string) {
// if (!provider) return null;

// const hasExtension = this.getBrowserUrl(provider);
// const hasMobile = this.getMobileUrl(provider);
Expand All @@ -44,32 +44,36 @@ export class Modal {
// return null;
// }

getBrowserUrl(provider: StxProvider) {
return provider.urls?.chromeWebStore ?? provider.urls?.mozillaWebStore;
getBrowserUrl(provider: WebBTCProvider) {
return provider.chromeWebStoreUrl ?? provider.mozillaAddOnsUrl;
}

getMobileUrl(provider: StxProvider) {
return provider.urls?.iOSAppStore ?? provider.urls?.androidAppStore;
getMobileUrl(provider: WebBTCProvider) {
return provider.iOSAppStoreUrl ?? provider.googlePlayStoreUrl;
}

getInstallUrl(provider: StxProvider, browser: string) {
getInstallUrl(provider: WebBTCProvider, browser: string) {
if (browser === 'Chrome') {
return provider.urls?.chromeWebStore ?? this.getMobileUrl(provider) ?? provider.urls?.about;
return provider.chromeWebStoreUrl ?? this.getMobileUrl(provider) ?? provider.webUrl;
} else if (browser === 'Firefox') {
return provider.urls?.mozillaWebStore ?? this.getMobileUrl(provider) ?? provider.urls?.about;
return provider.mozillaAddOnsUrl ?? this.getMobileUrl(provider) ?? provider.webUrl;
} else if (browser === 'IOS') {
return provider.urls?.iOSAppStore ?? this.getBrowserUrl(provider) ?? provider.urls?.about;
return provider.iOSAppStoreUrl ?? this.getBrowserUrl(provider) ?? provider.webUrl;
} else if (browser === 'Android') {
return provider.urls?.androidAppStore ?? this.getBrowserUrl(provider) ?? provider.urls?.about;
return provider.googlePlayStoreUrl ?? this.getBrowserUrl(provider) ?? provider.webUrl;
} else {
return this.getBrowserUrl(provider) ?? provider.urls?.about ?? this.getMobileUrl(provider);
return this.getBrowserUrl(provider) ?? provider.webUrl ?? this.getMobileUrl(provider);
}
}

render() {
const browser = getBrowser();
const mobile = getPlatform();

const notInstalledProviders = this.defaultProviders.filter(
p => this.installedProviders.findIndex(i => i.id === p.id) === -1 // keep providers NOT already in installed list
);

return (
<div class="modal-container">
<div class="modal-body leading-snug space-y-5 cursor-default">
Expand All @@ -85,7 +89,7 @@ export class Modal {
<img src={CloseIcon} />
</button>
</div>
{this.registeredProviders.length === 0 ? (
{this.installedProviders.length === 0 ? (
<div class="space-y-3">
<p>No installed wallets detected. You can install one from the list below.</p>
<div class="text-center">
Expand All @@ -108,19 +112,19 @@ export class Modal {
</div>

{/* INSTALLED SECTION */}
{this.registeredProviders.length > 0 && (
{this.installedProviders.length > 0 && (
<div class="space-y-2">
<p class="text-xs font-semibold text-gray-400">INSTALLED</p>
{this.registeredProviders.map((provider: StxProvider) => (
{this.installedProviders.map((provider: WebBTCProvider) => (
<div class="flex gap-3 items-center">
<div class="basis-12 aspect-square">
<img src={provider.icon} alt={`${provider.name} Icon`} class="w-full h-full" />
</div>
<div class="flex-1">
<div class="text-xl font-bold">{provider.name}</div>
{provider.urls?.about && (
{provider.webUrl && (
<a
href={provider.urls.about}
href={provider.webUrl}
class="text-gray-400 text-sm"
rel="noopener noreferrer"
>
Expand All @@ -139,20 +143,20 @@ export class Modal {
</div>
)}

{/* DEFAULT SECTION */}
{this.defaultProviders.length > 0 && (
{/* NOT INSTALLED DEFAULT SECTION */}
{notInstalledProviders.length > 0 && (
<div class="space-y-2">
<p class="text-xs font-semibold text-gray-400">POPULAR</p>
{this.defaultProviders.map((provider: StxProvider) => (
{notInstalledProviders.map((provider: WebBTCProvider) => (
<div class="flex gap-3 items-center">
<div class="basis-12 aspect-square">
<img src={provider.icon} alt={`${provider.name} Icon`} class="w-full h-full" />
</div>
<div class="flex-1">
<div class="text-xl font-bold">{provider.name}</div>
{provider.urls?.about && (
{provider.webUrl && (
<a
href={provider.urls.about}
href={provider.webUrl}
class="text-gray-400 text-sm"
rel="noopener noreferrer"
target="_blank"
Expand Down
10 changes: 5 additions & 5 deletions packages/connect-ui/src/components/modal/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

## Properties

| Property | Attribute | Description | Type | Default |
| --------------------- | --------- | ----------- | --------------- | ----------- |
| `callback` | -- | | `Function` | `undefined` |
| `defaultProviders` | -- | | `StxProvider[]` | `undefined` |
| `registeredProviders` | -- | | `StxProvider[]` | `undefined` |
| Property | Attribute | Description | Type | Default |
| -------------------- | --------- | ----------- | ------------------ | ----------- |
| `callback` | -- | | `Function` | `undefined` |
| `defaultProviders` | -- | | `WebBTCProvider[]` | `undefined` |
| `installedProviders` | -- | | `WebBTCProvider[]` | `undefined` |


----------------------------------------------
Expand Down
47 changes: 36 additions & 11 deletions packages/connect-ui/src/providers.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,56 @@
// AUTO REGISTERED PROVIDERS

export interface StxProvider {
export interface WebBTCProvider {
/** The global "path" of the provider (e.g. `"MyProvider"` if registered at `window.MyProvider`) */
id: string;
/** The name of the provider, as displayed to the user */
name: string;
/** The data URL of an image to show (e.g. `data:image/png;base64,iVBORw0...`) @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs */
icon?: string;
/** Different web URLs of the provider */
urls?: {
about?: string;
chromeWebStore?: string;
mozillaWebStore?: string;
androidAppStore?: string;
iOSAppStore?: string;
};
/** Web URL of the provider */
webUrl?: string;

chromeWebStoreUrl?: string;
mozillaAddOnsUrl?: string;
googlePlayStoreUrl?: string;
iOSAppStoreUrl?: string;
}

declare global {
interface Window {
webbtc_stx_providers?: any; // replace 'any' with the actual type if known
/**
* @experimental @beta
* An experimental global registry of providers that can be used by the UI to display a list of providers to the user.
* Wallets can add their provider to this list without needing to update `@stacks/connect` itself.
* This is an experimental API and may change in the future.
* This will be used as a test-run before switching to `webbtc` and WBIP004.
* The provider objects are WBIP004 compliant.
* It may happen that no wallet implements this feature before `@stacks/connect` switches to `webbtc`.
*/
webbtc_stx_providers?: WebBTCProvider[];
}
}

export const getRegisteredProviders = () => {
if (typeof window === 'undefined') return [];
if (!window.webbtc_stx_providers) return [];

return window.webbtc_stx_providers as StxProvider[];
return window.webbtc_stx_providers;
};

export const getInstalledProviders = (defaultProviders: WebBTCProvider[] = []) => {
if (typeof window === 'undefined') return [];

const registeredProviders = getRegisteredProviders();

const additionalInstalledProviders = defaultProviders.filter(dp => {
// already registered, don't add again
if (registeredProviders.find(rp => rp.id === dp.id)) return false;

// check if default provider is installed (even if not registered)
const provider = dp.id.split('.').reduce((acc, part) => acc?.[part], window);
return !!provider;
});

return registeredProviders.concat(additionalInstalledProviders);
};
7 changes: 7 additions & 0 deletions packages/connect/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,11 @@ export * from './profile';
export * from './types';
export * from './utils';
export * from './ui';

// re-exports
export * from '@stacks/auth';
export {
clearSelectedProvider,
getSelectedProvider,
setSelectedProvider,
} from '@stacks/connect-ui';
6 changes: 1 addition & 5 deletions packages/connect/src/stories/Connect.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,7 @@ const ConnectWithMockedWallet = () => {
alert('MockedProvider.authenticationRequest()');
},
};
return (
<ConnectPage>
<button onClick={() => clearSelectedProvider()}>Disconnect</button>
</ConnectPage>
);
return <ConnectPage />;
};
export const WithMockedWallet = {
render: () => <ConnectWithMockedWallet />,
Expand Down
2 changes: 2 additions & 0 deletions packages/connect/src/stories/ConnectPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { showConnect } from '@stacks/connect';
import { clearSelectedProvider } from '@stacks/connect-ui';

export const ConnectPage = ({ children }: { children?: any }) => {
function connect() {
Expand All @@ -13,6 +14,7 @@ export const ConnectPage = ({ children }: { children?: any }) => {
return (
<div>
<button onClick={connect}>Connect Wallet</button>
<button onClick={() => clearSelectedProvider()}>Disconnect</button>
{children}
</div>
);
Expand Down
Loading

0 comments on commit 47c2eb7

Please sign in to comment.