Skip to content

Commit 0d4daf6

Browse files
authored
feat: [lw-12421] integrate nftprintlab
1 parent 62cb40f commit 0d4daf6

File tree

15 files changed

+223
-70
lines changed

15 files changed

+223
-70
lines changed

apps/browser-extension-wallet/.env.defaults

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ TERMS_OF_USE_URL=https://www.lace.io/iohktermsandconditions.pdf
5353
YOUTUBE_RECOVERY_PHRASE_VIDEO_URL=https://www.youtube-nocookie.com/embed/hOFVXo969rk?si=0a-hNDVME6eTboIX
5454
BANXA_LACE_URL=https://lacewallet.banxa-sandbox.com/
5555
BANXA_HOMEPAGE_URL=https://banxa.com/
56+
NFTPRINTLAB_URL=https://nftprintlab.io/
5657
GOV_TOOLS_URL_MAINNET=https://gov.tools
5758
GOV_TOOLS_URL_PREPROD=https://preprod.gov.tools
5859
GOV_TOOLS_URL_PREVIEW=https://preview.gov.tools

apps/browser-extension-wallet/.env.developerpreview

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ TERMS_OF_USE_URL=https://www.lace.io/iohktermsandconditions.pdf
5151
YOUTUBE_RECOVERY_PHRASE_VIDEO_URL=https://www.youtube-nocookie.com/embed/hOFVXo969rk?si=0a-hNDVME6eTboIX
5252
BANXA_LACE_URL=https://lacewallet.banxa-sandbox.com/
5353
BANXA_HOMEPAGE_URL=https://banxa.com/
54+
NFTPRINTLAB_URL=https://nftprintlab.io/
5455
GOV_TOOLS_URL_MAINNET=https://gov.tools
5556
GOV_TOOLS_URL_PREPROD=https://preprod.gov.tools
5657
GOV_TOOLS_URL_PREVIEW=https://preview.gov.tools

apps/browser-extension-wallet/.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ TERMS_OF_USE_URL=https://www.lace.io/iohktermsandconditions.pdf
5050
YOUTUBE_RECOVERY_PHRASE_VIDEO_URL=https://www.youtube-nocookie.com/embed/hOFVXo969rk?si=0a-hNDVME6eTboIX
5151
BANXA_LACE_URL=https://lacewallet.banxa-sandbox.com/
5252
BANXA_HOMEPAGE_URL=https://banxa.com/
53+
NFTPRINTLAB_URL=https://nftprintlab.io/
5354
GOV_TOOLS_URL_MAINNET=https://gov.tools
5455
GOV_TOOLS_URL_PREPROD=https://preprod.gov.tools
5556
GOV_TOOLS_URL_PREVIEW=https://preview.gov.tools
Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useAssetInfo, useRedirection, useWalletAvatar } from '@hooks';
22
import { walletRoutePaths } from '@routes';
3-
import React, { useMemo } from 'react';
3+
import React, { useCallback, useMemo, useState } from 'react';
44
import { useParams } from 'react-router-dom';
55
import styles from './Nfts.module.scss';
66
import { Button, Drawer, DrawerNavigation, toast, useObservable } from '@lace/common';
@@ -12,24 +12,32 @@ import { useTranslation } from 'react-i18next';
1212
import { SendFlowTriggerPoints, useOutputInitialState } from '@src/views/browser-view/features/send-transaction';
1313
import { APP_MODE_POPUP, DEFAULT_WALLET_BALANCE, SEND_NFT_DEFAULT_AMOUNT } from '@src/utils/constants';
1414
import { PostHogAction } from '@providers/AnalyticsProvider/analyticsTracker';
15-
import { useAnalyticsContext } from '@providers';
15+
import { useAnalyticsContext, useExternalLinkOpener } from '@providers';
1616
import { buttonIds } from '@hooks/useEnterKeyPress';
1717
import { withNftsFoldersContext } from '../context';
18+
import { usePostHogClientContext } from '@providers/PostHogClientProvider';
19+
import { NFTPrintLabDialog } from '@src/views/browser-view/features/nfts/components/NFTPrintLabDialog';
20+
21+
export const NFTPRINTLAB_URL = process.env.NFTPRINTLAB_URL;
1822

1923
export const NftDetail = withNftsFoldersContext((): React.ReactElement => {
24+
const [nftPrintLabDialogOpen, setNftPrintLabDialogOpen] = useState(false);
2025
const {
2126
inMemoryWallet,
22-
walletUI: { appMode }
27+
walletUI: { appMode },
28+
currentChain
2329
} = useWalletStore();
2430
const { t } = useTranslation();
2531
const analytics = useAnalyticsContext();
32+
const posthog = usePostHogClientContext();
2633
const { setAvatar } = useWalletAvatar();
2734

2835
const redirectToNfts = useRedirection(walletRoutePaths.nfts);
2936
const redirectToSend = useRedirection<{ params: { id?: string } }>(walletRoutePaths.send);
3037
const { id } = useParams<{ id: string }>();
3138
const assetsInfo = useAssetInfo();
3239
const setSendInitialState = useOutputInitialState();
40+
const openExternalLink = useExternalLinkOpener();
3341

3442
const assetId = Wallet.Cardano.AssetId(id);
3543
const assetInfo = assetsInfo?.get(assetId);
@@ -51,30 +59,53 @@ export const NftDetail = withNftsFoldersContext((): React.ReactElement => {
5159
analytics.sendEventToPostHog(PostHogAction.NFTDetailSetAsAvatarClick);
5260
};
5361

62+
const handleOpenTabNFTPrintLab = useCallback(() => {
63+
analytics.sendEventToPostHog(PostHogAction.NFTDetailPrintClick);
64+
setNftPrintLabDialogOpen(true);
65+
}, [analytics]);
66+
67+
const isMainnet = currentChain?.networkMagic === Wallet.Cardano.NetworkMagics.Mainnet;
68+
const canPrintNft = isMainnet && posthog?.isFeatureFlagEnabled('nftprintlab');
69+
5470
return (
55-
<Drawer
56-
popupView
57-
className={styles.drawer}
58-
visible
59-
navigation={<DrawerNavigation onArrowIconClick={() => redirectToNfts()} />}
60-
dataTestId="nft-details-drawer"
61-
footer={
62-
<div className={styles.footer}>
63-
<Button id={buttonIds.nftDetailsBtnId} className={styles.sendBtn} onClick={handleOpenSend}>
64-
{t('core.nftDetail.sendNFT')}
65-
</Button>
66-
</div>
67-
}
68-
>
69-
{assetInfo && (
70-
<NftDetailView
71-
{...nftDetailSelector(assetInfo)}
72-
isPopup={appMode === APP_MODE_POPUP}
73-
amount={amount}
74-
title={<h2 className={styles.secondaryTitle}>{nftNameSelector(assetInfo)}</h2>}
75-
onSetAsAvatar={handleSetAsAvatar}
76-
/>
77-
)}
78-
</Drawer>
71+
<>
72+
<Drawer
73+
popupView
74+
className={styles.drawer}
75+
visible
76+
navigation={<DrawerNavigation onArrowIconClick={() => redirectToNfts()} />}
77+
dataTestId="nft-details-drawer"
78+
footer={
79+
<div className={styles.footer}>
80+
<Button id={buttonIds.nftDetailsBtnId} className={styles.sendBtn} onClick={handleOpenSend}>
81+
{t('core.nftDetail.sendNFT')}
82+
</Button>
83+
</div>
84+
}
85+
>
86+
{assetInfo && (
87+
<NftDetailView
88+
{...nftDetailSelector(assetInfo)}
89+
isPopup={appMode === APP_MODE_POPUP}
90+
amount={amount}
91+
title={<h2 className={styles.secondaryTitle}>{nftNameSelector(assetInfo)}</h2>}
92+
onSetAsAvatar={handleSetAsAvatar}
93+
onPrintNft={canPrintNft ? handleOpenTabNFTPrintLab : undefined}
94+
/>
95+
)}
96+
</Drawer>
97+
<NFTPrintLabDialog
98+
onCancel={() => {
99+
analytics.sendEventToPostHog(PostHogAction.NFTPrintLabDisclaimerCancelClick);
100+
setNftPrintLabDialogOpen(false);
101+
}}
102+
open={nftPrintLabDialogOpen}
103+
onConfirm={() => {
104+
analytics.sendEventToPostHog(PostHogAction.NFTPrintLabDisclaimerConfirmClick);
105+
openExternalLink(NFTPRINTLAB_URL);
106+
setNftPrintLabDialogOpen(false);
107+
}}
108+
/>
109+
</>
79110
);
80111
});

apps/browser-extension-wallet/src/lib/scripts/types/feature-flags.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ export enum ExperimentName {
1212
WEBSOCKET_API = 'websocket-api',
1313
DAPP_EXPLORER = 'dapp-explorer',
1414
SEND_CONSOLE_ERRORS_TO_SENTRY = 'send-console-errors-to-sentry',
15-
BITCOIN_WALLETS = 'bitcoin-wallets'
15+
BITCOIN_WALLETS = 'bitcoin-wallets',
16+
NFTPRINTLAB = 'nftprintlab'
1617
}
1718

1819
export type FeatureFlag = `${ExperimentName}`;

apps/browser-extension-wallet/src/providers/PostHogClientProvider/client/config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ const defaultFeatureFlags: FeatureFlags = {
3636
[ExperimentName.WEBSOCKET_API]: false,
3737
[ExperimentName.DAPP_EXPLORER]: false,
3838
[ExperimentName.SEND_CONSOLE_ERRORS_TO_SENTRY]: false,
39-
[ExperimentName.BITCOIN_WALLETS]: false
39+
[ExperimentName.BITCOIN_WALLETS]: false,
40+
[ExperimentName.NFTPRINTLAB]: false
4041
};
4142

4243
export const featureFlagsByNetworkInitialValue: FeatureFlagsByNetwork = {
Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* eslint-disable unicorn/no-nested-ternary */
2-
import React, { ReactElement, useMemo } from 'react';
2+
import React, { ReactElement, useCallback, useMemo, useState } from 'react';
33
import { useTranslation } from 'react-i18next';
44
import { NftDetail } from '@lace/core';
55
import { Wallet } from '@lace/cardano';
@@ -11,8 +11,12 @@ import { nftDetailSelector, nftNameSelector } from '../selectors';
1111
import styles from './DetailsDrawer.module.scss';
1212
import { useWalletStore } from '@stores';
1313
import { useWalletAvatar } from '@hooks';
14-
import { useAnalyticsContext } from '@providers';
14+
import { useAnalyticsContext, useExternalLinkOpener } from '@providers';
1515
import { APP_MODE_POPUP } from '@src/utils/constants';
16+
import { usePostHogClientContext } from '@providers/PostHogClientProvider';
17+
import { NFTPrintLabDialog } from './NFTPrintLabDialog';
18+
19+
export const NFTPRINTLAB_URL = process.env.NFTPRINTLAB_URL;
1620

1721
interface GeneralSettingsDrawerProps {
1822
onClose: () => void;
@@ -27,22 +31,27 @@ export const DetailsDrawer = ({
2731
assetsInfo = new Map(),
2832
onSend
2933
}: GeneralSettingsDrawerProps): ReactElement => {
34+
const [nftPrintLabDialogOpen, setNftPrintLabDialogOpen] = useState(false);
3035
const { t } = useTranslation();
3136
const {
32-
walletUI: { appMode }
37+
walletUI: { appMode },
38+
currentChain
3339
} = useWalletStore();
40+
const posthog = usePostHogClientContext();
3441
const assetInfo = useMemo(
3542
() => (isNil(assetsInfo) ? undefined : assetsInfo.get(selectedNft?.assetId)),
3643
[selectedNft, assetsInfo]
3744
);
3845
const { setAvatar } = useWalletAvatar();
3946
const analytics = useAnalyticsContext();
47+
const openExternalLink = useExternalLinkOpener();
4048

4149
const nftDetailTranslation = {
4250
tokenInformation: t('core.nftDetail.tokenInformation'),
4351
attributes: t('core.nftDetail.attributes'),
4452
setAsAvatar: t('core.nftDetail.setAsAvatar'),
45-
directory: t('core.nftDetail.directory')
53+
directory: t('core.nftDetail.directory'),
54+
printNft: t('core.nftDetail.printNft')
4655
};
4756

4857
const handleSetAsAvatar = (image: string) => {
@@ -51,34 +60,57 @@ export const DetailsDrawer = ({
5160
void analytics.sendEventToPostHog(PostHogAction.NFTDetailSetAsAvatarClick);
5261
};
5362

63+
const handleOpenTabNFTPrintLab = useCallback(() => {
64+
analytics.sendEventToPostHog(PostHogAction.NFTDetailPrintClick);
65+
setNftPrintLabDialogOpen(true);
66+
}, [analytics]);
67+
68+
const isMainnet = currentChain?.networkMagic === Wallet.Cardano.NetworkMagics.Mainnet;
69+
const canPrintNft = isMainnet && posthog?.isFeatureFlagEnabled('nftprintlab');
70+
5471
return (
55-
<Drawer
56-
open={!!selectedNft}
57-
onClose={onClose}
58-
title={assetInfo ? <DrawerHeader title={nftNameSelector(assetInfo)} /> : undefined}
59-
navigation={
60-
selectedNft ? <DrawerNavigation title={t('core.nftDetail.title')} onCloseIconClick={onClose} /> : undefined
61-
}
62-
dataTestId="nft-details-drawer"
63-
footer={
64-
<div>
65-
<Button className={styles.sendButton} onClick={onSend} id={buttonIds.nftDetailsBtnId}>
66-
{t('browserView.crypto.nft.send')}
67-
</Button>
68-
</div>
69-
}
70-
>
71-
{selectedNft && assetInfo && (
72-
<div className={styles.wrapper}>
73-
<NftDetail
74-
{...nftDetailSelector(assetInfo)}
75-
isPopup={appMode === APP_MODE_POPUP}
76-
amount={selectedNft.amount}
77-
translations={nftDetailTranslation}
78-
onSetAsAvatar={handleSetAsAvatar}
79-
/>
80-
</div>
81-
)}
82-
</Drawer>
72+
<>
73+
<Drawer
74+
open={!!selectedNft}
75+
onClose={onClose}
76+
title={assetInfo ? <DrawerHeader title={nftNameSelector(assetInfo)} /> : undefined}
77+
navigation={
78+
selectedNft ? <DrawerNavigation title={t('core.nftDetail.title')} onCloseIconClick={onClose} /> : undefined
79+
}
80+
dataTestId="nft-details-drawer"
81+
footer={
82+
<div>
83+
<Button className={styles.sendButton} onClick={onSend} id={buttonIds.nftDetailsBtnId}>
84+
{t('browserView.crypto.nft.send')}
85+
</Button>
86+
</div>
87+
}
88+
>
89+
{selectedNft && assetInfo && (
90+
<div className={styles.wrapper}>
91+
<NftDetail
92+
{...nftDetailSelector(assetInfo)}
93+
isPopup={appMode === APP_MODE_POPUP}
94+
amount={selectedNft.amount}
95+
translations={nftDetailTranslation}
96+
onSetAsAvatar={handleSetAsAvatar}
97+
onPrintNft={canPrintNft ? handleOpenTabNFTPrintLab : undefined}
98+
/>
99+
</div>
100+
)}
101+
</Drawer>
102+
<NFTPrintLabDialog
103+
onCancel={() => {
104+
analytics.sendEventToPostHog(PostHogAction.NFTPrintLabDisclaimerCancelClick);
105+
setNftPrintLabDialogOpen(false);
106+
}}
107+
open={nftPrintLabDialogOpen}
108+
onConfirm={() => {
109+
analytics.sendEventToPostHog(PostHogAction.NFTPrintLabDisclaimerConfirmClick);
110+
openExternalLink(NFTPRINTLAB_URL);
111+
setNftPrintLabDialogOpen(false);
112+
}}
113+
/>
114+
</>
83115
);
84116
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.disclaimerFullWrapper {
2+
text-align: center;
3+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import React from 'react';
2+
import { Box, Dialog, Text, TextLink } from '@input-output-hk/lace-ui-toolkit';
3+
import styles from './NFTPrintLabDialog.module.scss';
4+
import { useTranslation } from 'react-i18next';
5+
import { useExternalLinkOpener } from '@providers';
6+
7+
export const NFTPRINTLAB_URL = process.env.NFTPRINTLAB_URL;
8+
9+
interface NFTPrintLabDialogProps {
10+
open: boolean;
11+
onCancel: () => void;
12+
onConfirm: () => void;
13+
}
14+
export const NFTPrintLabDialog = ({ open, onCancel, onConfirm }: NFTPrintLabDialogProps): React.ReactElement => {
15+
const { t } = useTranslation();
16+
const openExternalLink = useExternalLinkOpener();
17+
const handleOpenTabNFTPrintLabHomepage = () => {
18+
openExternalLink(NFTPRINTLAB_URL);
19+
};
20+
21+
return (
22+
<Dialog.Root open={open} setOpen={onCancel} zIndex={1000}>
23+
<Dialog.Title>{t('browserView.nfts.printlab.modal.title')}</Dialog.Title>
24+
<Dialog.Description>
25+
<Box className={styles.disclaimerFullWrapper}>
26+
<Text.Body.Normal weight="$medium" color="secondary" data-testid="nftprintlab-dialog-disclaimer-part1">
27+
{t('browserView.nfts.printlab.disclaimer.full.part1')}
28+
</Text.Body.Normal>
29+
<TextLink
30+
onClick={handleOpenTabNFTPrintLabHomepage}
31+
label={t('browserView.nfts.printlab.disclaimer.full.nftprintlabLinkCaption')}
32+
testId="nftprintlab-dialog-disclaimer-link-caption-1"
33+
/>
34+
</Box>
35+
</Dialog.Description>
36+
<Dialog.Actions>
37+
<Dialog.Action
38+
cancel
39+
label={t('browserView.nfts.printlab.modal.cancel')}
40+
onClick={onCancel}
41+
testId="nftprintlab-dialog-go-back-button"
42+
/>
43+
<Dialog.Action
44+
autoFocus
45+
label={t('browserView.nfts.printlab.modal.continue')}
46+
onClick={onConfirm}
47+
testId="nftprintlab-dialog-continue-button"
48+
/>
49+
</Dialog.Actions>
50+
</Dialog.Root>
51+
);
52+
};

apps/browser-extension-wallet/src/views/browser-view/features/nfts/selectors.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ export const nftDetailSelector = (asset: AssetOrHandleInfo): NftDetailProps => {
8080
tokenInformation: i18n.t('core.nftDetail.tokenInformation'),
8181
attributes: i18n.t('core.nftDetail.attributes'),
8282
directory: i18n.t('core.nftDetail.directory'),
83-
setAsAvatar: i18n.t('core.nftDetail.setAsAvatar')
83+
setAsAvatar: i18n.t('core.nftDetail.setAsAvatar'),
84+
printNft: i18n.t('core.nftDetail.printNft')
8485
}
8586
};
8687
};

packages/common/src/analytics/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ export enum PostHogAction {
158158
NFTCreateFolderNameYourFolderNextClick = 'nft | create folder | name your folder | next | click',
159159
NFTCreateFolderSelectNftsNextClick = 'nft | create folder | select nfts | next | click',
160160
NFTDetailSetAsAvatarClick = 'nft | nft detail | set as your wallet avatar | click',
161+
NFTDetailPrintClick = 'nft | nft detail | print nft | click',
162+
NFTPrintLabDisclaimerCancelClick = 'nft | print nft | disclaimer | cancel | click',
163+
NFTPrintLabDisclaimerConfirmClick = 'nft | print nft | disclaimer | confirm | click',
161164
// Address book
162165
AddressBookAddAddressClick = 'address book | add address | click',
163166
AddressBookAddNewAddressSaveAddressClick = 'address book | add new address | save address | click',
Lines changed: 4 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)