Skip to content

Commit

Permalink
feat: check if the feature is supported
Browse files Browse the repository at this point in the history
  • Loading branch information
runjuu committed Feb 7, 2024
1 parent 5209fb6 commit c059790
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 30 deletions.
1 change: 1 addition & 0 deletions packages/site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"autoprefixer": "^10.4.16",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"compare-versions": "^6.1.0",
"dotenv": "^16.3.1",
"gatsby-plugin-csp": "^1.1.4",
"gatsby-plugin-env-variables": "^2.3.0",
Expand Down
62 changes: 62 additions & 0 deletions packages/site/src/components/feature-guard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import { InfoCircledIcon } from '@radix-ui/react-icons';

import type { FeatureToCheck } from '@/utils';
import { useIsFeatureSupported } from '@/hooks/use-is-feature-supported';
import { cn } from '@/lib/utils';
import { useInstallSnap } from '@/hooks/use-install-snap';

export type FeatureGuardProps = {
feature: FeatureToCheck;
} & React.HTMLAttributes<HTMLDivElement>;

export function FeatureGuard({
feature,
children,
className,
...props
}: FeatureGuardProps) {
const isFeatureSupported = useIsFeatureSupported(feature);
const installSnap = useInstallSnap();

return (
<div
{...props}
className={cn(
'relative',
!isFeatureSupported && 'min-h-[3rem]',
className,
)}
>
{isFeatureSupported ? (
children
) : (
<div className="rounded-md bg-yellow-50 p-4">
<div className="flex">
<div className="flex-shrink-0">
<InfoCircledIcon
className="h-5 w-5 text-yellow-400"
aria-hidden="true"
/>
</div>
<div className="ml-3 flex-1 md:flex md:justify-between">
<p className="text-sm text-yellow-700">
Current installed version does not support this feature. Click
the Reinstall button to install the latest version.
</p>
<p className="mt-3 text-sm md:ml-6 md:mt-0">
<button
onClick={installSnap}
className="whitespace-nowrap font-medium text-yellow-700 hover:text-yellow-600"
>
Reinstall
<span aria-hidden="true"> &rarr;</span>
</button>
</p>
</div>
</div>
</div>
)}
</div>
);
}
23 changes: 23 additions & 0 deletions packages/site/src/hooks/use-install-snap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React, { useContext } from 'react';

import { connectSnap, getSnap } from '@/utils';
import { MetamaskActions, MetaMaskContext } from '@/hooks/MetamaskContext';

export function useInstallSnap() {
const [, dispatch] = useContext(MetaMaskContext);

return React.useCallback(async () => {
try {
await connectSnap();
const installedSnap = await getSnap();

dispatch({
type: MetamaskActions.SetInstalled,
payload: installedSnap,
});
} catch (e) {
console.error(e);
dispatch({ type: MetamaskActions.SetError, payload: e });
}
}, []);
}
8 changes: 8 additions & 0 deletions packages/site/src/hooks/use-installed-snap-version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react';

import { MetaMaskContext } from '@/hooks/MetamaskContext';

export function useInstalledSnapVersion() {
const [state] = React.useContext(MetaMaskContext);
return state.installedSnap?.version ?? null;
}
24 changes: 24 additions & 0 deletions packages/site/src/hooks/use-is-feature-supported.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import { compareVersions } from 'compare-versions';

import { useIsMetaMaskReady } from '@/hooks/use-is-meta-mask-ready';
import { type FeatureToCheck, isFeatureSupported } from '@/utils';
import { useInstalledSnapVersion } from '@/hooks/use-installed-snap-version';

export function useIsFeatureSupported(feature: FeatureToCheck) {
const isMetaMaskReady = useIsMetaMaskReady();
const [isSupported, setIsSupported] = React.useState<boolean>(false);
const installedSnapVersion = useInstalledSnapVersion();

React.useEffect(() => {
if (
isMetaMaskReady &&
installedSnapVersion &&
compareVersions(installedSnapVersion, '0.1.13') > 0
) {
isFeatureSupported(feature).then(setIsSupported);
}
}, [isMetaMaskReady, feature, installedSnapVersion]);

return isSupported;
}
30 changes: 18 additions & 12 deletions packages/site/src/modules/preferences/notifications.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { useToggleNotifications } from '@/hooks/use-toggle-notifications';
import React from 'react';

import { Checkbox } from '@/components/ui/checkbox';
import { useToggleNotifications } from '@/hooks/use-toggle-notifications';
import { FeatureGuard } from '@/components/feature-guard';

export function Notifications() {
const { toggle, platforms } = useToggleNotifications();
Expand All @@ -15,17 +18,20 @@ export function Notifications() {
<div className="max-w-xl text-sm text-gray-500">
Choose which platforms you want to receive notifications on.
</div>
<div className="flex items-center gap-4">
{platforms.map((platform) => (
<label key={platform.id} className="flex items-center gap-2">
<Checkbox
checked={platform.enabled}
onCheckedChange={() => toggle(platform.id)}
/>
{platform.name}
</label>
))}
</div>

<FeatureGuard feature="togglePlatform">
<div className="flex items-center gap-4">
{platforms.map((platform) => (
<label key={platform.id} className="flex items-center gap-2">
<Checkbox
checked={platform.enabled}
onCheckedChange={() => toggle(platform.id)}
/>
{platform.name}
</label>
))}
</div>
</FeatureGuard>
</div>
</div>
</div>
Expand Down
19 changes: 2 additions & 17 deletions packages/site/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { useContext } from 'react';
import { ExclamationTriangleIcon } from '@radix-ui/react-icons';
import { navigate } from 'gatsby';
import {
connectSnap,
getSnap,
sendClearState,
shouldDisplayReconnectButton,
testImage,
Expand All @@ -28,25 +26,12 @@ import { Button } from '@/components/ui/button';
import { SEO } from '@/components/SEO';
import { Preferences } from '@/modules/preferences';
import { useIsMetaMaskReady } from '@/hooks/use-is-meta-mask-ready';
import { useInstallSnap } from '@/hooks/use-install-snap';

const Index = () => {
const [state, dispatch] = useContext(MetaMaskContext);
const isMetaMaskReady = useIsMetaMaskReady();

const handleConnectClick = async () => {
try {
await connectSnap();
const installedSnap = await getSnap();

dispatch({
type: MetamaskActions.SetInstalled,
payload: installedSnap,
});
} catch (e) {
console.error(e);
dispatch({ type: MetamaskActions.SetError, payload: e });
}
};
const handleConnectClick = useInstallSnap();

const handleSendClearStateClick = async () => {
try {
Expand Down
20 changes: 20 additions & 0 deletions packages/site/src/utils/snap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,4 +302,24 @@ export const getPlatformInfos = async () => {
})) as PlatformInfo[];
};

export type FeatureToCheck = 'togglePlatform';

export const isFeatureSupported = (
feature: FeatureToCheck,
): Promise<boolean> => {
return window.ethereum
.request({
method: 'wallet_invokeSnap',
params: {
snapId: defaultSnapOrigin,
request: {
method: 'isFeatureSupported',
params: { feature },
},
},
})
.then((result) => result as boolean)
.catch(() => false);
};

export const isLocalSnap = (snapId: string) => snapId.startsWith('local:');
2 changes: 1 addition & 1 deletion packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/NaturalSelectionLabs/RSS3-Social-Notifier-Snap.git"
},
"source": {
"shasum": "y2WbB4B+HA/2FQD4XRN8oWquK0FOYbNbvikIPmbUtQA=",
"shasum": "cIhW9of8p3HYc0MAjoDAFQjBI+whgM4wSMkhIJfnMTM=",
"location": {
"npm": {
"filePath": "dist/bundle.js",
Expand Down
11 changes: 11 additions & 0 deletions packages/snap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,17 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => {
})) satisfies PlatformInfo[];
}

case 'isFeatureSupported': {
const { feature } = request.params as { feature: string };

switch (feature) {
case 'togglePlatform':
return true;
default:
return false;
}
}

default:
throw new Error('Method not found.');
}
Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10230,6 +10230,13 @@ __metadata:
languageName: node
linkType: hard

"compare-versions@npm:^6.1.0":
version: 6.1.0
resolution: "compare-versions@npm:6.1.0"
checksum: d4e2a45706a023d8d0b6680338b66b79e20bd02d1947f0ac6531dab634cbed89fa373b3f03d503c5e489761194258d6e1bae67a07f88b1efc61648454f2d47e7
languageName: node
linkType: hard

"compress-commons@npm:^5.0.1":
version: 5.0.1
resolution: "compress-commons@npm:5.0.1"
Expand Down Expand Up @@ -21691,6 +21698,7 @@ __metadata:
autoprefixer: ^10.4.16
class-variance-authority: ^0.7.0
clsx: ^2.0.0
compare-versions: ^6.1.0
dotenv: ^16.3.1
eslint: ^8.21.0
eslint-config-prettier: ^8.1.0
Expand Down

0 comments on commit c059790

Please sign in to comment.