Skip to content

Commit f52ed6f

Browse files
[DDW-716] Implement static screens for signing dApp interaction transactions (#2626)
* [DDW-716] Initial file structure * [DDW-716] Single wallet * [DDW-716] Assets Transaction Confirmation basic component structure * [DDW-716] AssetsTransactionConfirmation progress * [DDW-716] DappTransactionRequest progress * [DDW-716] Tokens list progress * [DDW-716] Missing token - init * [DDW-716] Missing token * [DDW-716] Missing token - progress * [DDW-716] Missing token - progress * [DDW-716] Add Wallet option * [DDW-716] Toggle button * [DDW-716] Code content * [DDW-716] Translation manager * [DDW-716] Request Notification - init * [DDW-716] General Notification Story * [DDW-716] Notification with buttons - init * [DDW-716] Notification with buttons - progress * [DDW-716] Invert Buttons * [DDW-716] Sorting themes object * [DDW-716] Remove click to close when there are buttons * [DDW-716] Color buttons * [DDW-716] Add uniqueId to the wallet token * [DDW-716] Add uniqueId to the wallet token * [DDW-716] Assets amounts * [DDW-716] Insuficient Balance * [DDW-716] Validation and copy * [DDW-716] Translation * [DDW-716] Raw additional data and metadata * [DDW-716] Fix Netifly * [DDW-716] Translation and popover positioning * [DDW-716] Not enough ada error * [DDW-716] Disable button when no Ada funds * [DDW-716] Not enough ada copy and translation * [DDW-716] JP translation * [DDW-716] Translation and adjustments * [DDW-716] JP translation * [DDW-716] Code improvements * [DDW-716] Code improvements * [DDW-716] Improve error states * [DDW-716] Styling adjustments * [DDW-716] New copy * [DDW-716] Lint fix * [DDW-716] Notification styling adjustment * [DDW-716] Styling adjustments * [DDW-716] Styling adjustments and Ada name * [DDW-716] Adjustments and new copy * [DDW-716] Adjustments * [DDW-716] Styling adjustment * [DDW-716] Styling adjustment * [DDW-716] Styling adjustment * [DDW-716] Adjustments * [DDW-716] Scroll styles and correct ada capitalization * [DDW-716] Small style adjust * [DDW-716] Error message adjustment * [DDW-716] Last adjustments * [DDW-716] adaErrorPopOver placement * Revert "[DDW-716] adaErrorPopOver placement" This reverts commit b112193. * [DDW-716] Code improvements * [DDW-716] Fix lint issue * [DDW-716] Test build error * [DDW-716] Fixes CHANGELOG * [DDW-716] Remove Debug files * [DDW-716] Run linters Co-authored-by: Nikola Glumac <[email protected]>
1 parent 47ee582 commit f52ed6f

File tree

64 files changed

+2793
-1068
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+2793
-1068
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ Changelog
33

44
## vNext
55

6+
### Features
7+
8+
- Implemented static screens for signing dApp interaction transactions ([PR 2626](https://github.com/input-output-hk/daedalus/pull/2626))
9+
610
### Fixes
711

812
- Fixed some Japanese translations for the external currencies ([PR 2667](https://github.com/input-output-hk/daedalus/pull/2667))

netlify.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
[build]
2-
environment = { YARN_VERSION = "1.22.4", NODE_VERSION = "12.19.0" }
2+
environment = { YARN_VERSION = "1.22.4", NODE_VERSION = "12.19.0" }

source/renderer/app/api/api.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2733,17 +2733,23 @@ const _createWalletFromServerData = action(
27332733
// Mapping asset items from server data
27342734
const walletAssets = {
27352735
available: assets.available.map((item) => {
2736+
const { policy_id: policyId, asset_name: assetName, quantity } = item;
2737+
const uniqueId = `${policyId}${assetName}`;
27362738
return {
2737-
policyId: item.policy_id,
2738-
assetName: item.asset_name,
2739-
quantity: new BigNumber(item.quantity.toString()),
2739+
uniqueId,
2740+
policyId,
2741+
assetName,
2742+
quantity: new BigNumber(quantity.toString()),
27402743
};
27412744
}),
27422745
total: assets.total.map((item) => {
2746+
const { policy_id: policyId, asset_name: assetName, quantity } = item;
2747+
const uniqueId = `${policyId}${assetName}`;
27432748
return {
2744-
policyId: item.policy_id,
2745-
assetName: item.asset_name,
2746-
quantity: new BigNumber(item.quantity.toString()),
2749+
uniqueId,
2750+
policyId,
2751+
assetName,
2752+
quantity: new BigNumber(quantity.toString()),
27472753
};
27482754
}),
27492755
};

source/renderer/app/api/assets/types.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export type Token = {
5353
assetName: string,
5454
quantity: BigNumber,
5555
address?: ?string,
56-
uniqueId?: string,
56+
uniqueId: string,
5757
};
5858

5959
export type Tokens = Array<Token>;

source/renderer/app/components/assets/Asset.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ type Props = {
8484
// In case it's not possible to calculate the container width
8585
// this props defines after how many characters the `metadata.name` text will cut off
8686
metadataNameChars?: number,
87+
hasError?: boolean,
8788
};
8889

8990
type State = {
@@ -175,12 +176,14 @@ export default class Asset extends Component<Props, State> {
175176
small,
176177
fullFingerprint,
177178
hasWarning,
179+
hasError,
178180
} = this.props;
179181
const { fingerprint, metadata, decimals, recommendedDecimals } = asset;
180182
const { name } = metadata || {};
181183
const contentStyles = classnames([
182184
styles.pill,
183185
small ? styles.small : null,
186+
hasError ? styles.error : null,
184187
]);
185188
let warningPopOverMessage;
186189
if (hasWarning) {

source/renderer/app/components/assets/Asset.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@
4242
width: 11px;
4343
}
4444
}
45+
&.error {
46+
.fingerprint {
47+
background-color: var(--theme-background-color-error);
48+
color: var(--theme-color-error);
49+
}
50+
.metadataName {
51+
color: var(--theme-color-error);
52+
}
53+
}
4554
}
4655

4756
.fingerprint {

source/renderer/app/components/assets/AssetContent.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ type Props = {
7575
highlightFingerprint?: boolean,
7676
className?: string,
7777
intl: intlShape.isRequired,
78+
hasError?: boolean,
7879
};
7980

8081
type ItemCopied = ?string;
@@ -130,13 +131,14 @@ const AssetContent = observer((props: Props) => {
130131
);
131132
};
132133

133-
const { asset, highlightFingerprint, className, intl } = props;
134+
const { asset, highlightFingerprint, className, intl, hasError } = props;
134135
const { fingerprint, policyId, assetName, metadata } = asset;
135136
const { name, ticker, description } = metadata || {};
136137
const componentStyles = classnames([
137138
styles.component,
138139
className,
139140
highlightFingerprint ? styles.highlightFingerprint : null,
141+
hasError ? styles.error : null,
140142
]);
141143
return (
142144
<div className={componentStyles}>

source/renderer/app/components/assets/AssetContent.scss

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,24 +58,37 @@
5858
width: calc(100% - 87px);
5959
}
6060
}
61+
&.error {
62+
* {
63+
color: var(--theme-color-error);
64+
}
65+
.fingerprint {
66+
background-color: var(--theme-background-color-error);
67+
}
68+
.copyIcon {
69+
g {
70+
fill: var(--theme-color-error);
71+
}
72+
svg > path {
73+
stroke: var(--theme-color-error);
74+
}
75+
}
76+
}
6177
}
6278

6379
.fingerprint {
6480
background: var(--theme-widgets-asset-token-fingerprint-background-color);
6581
border-radius: 3px;
6682
color: var(--theme-widgets-asset-token-text-color);
83+
cursor: pointer;
6784
display: inline-flex;
6885
font-family: var(--font-medium);
6986
font-size: 11px;
7087
font-weight: 500;
7188
line-height: 1.27;
7289
padding: 4px;
73-
white-space: nowrap;
74-
}
75-
76-
.fingerprint {
77-
cursor: pointer;
7890
position: relative;
91+
white-space: nowrap;
7992

8093
.copyIcon {
8194
margin-left: 9px;
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
// @flow
2+
import React from 'react';
3+
import classnames from 'classnames';
4+
import BigNumber from 'bignumber.js';
5+
import {
6+
defineMessages,
7+
intlShape,
8+
injectIntl,
9+
FormattedHTMLMessage,
10+
} from 'react-intl';
11+
import { PopOver } from 'react-polymorph/lib/components/PopOver';
12+
import { observer } from 'mobx-react';
13+
import SVGInline from 'react-svg-inline';
14+
import questionMarkIcon from '../../assets/images/question-mark.inline.svg';
15+
import styles from './AssetTransactionConfirmation.scss';
16+
import type { AssetToken } from '../../api/assets/types';
17+
import Asset from './Asset';
18+
import { formattedTokenWalletAmount } from '../../utils/formatters';
19+
20+
const messages = defineMessages({
21+
assetLabel: {
22+
id: 'asset.transactionConfirmation.assetLabel',
23+
defaultMessage: '!!!Token #{assetNumber}',
24+
description: '"assetLabel" item on AssetTransactionConfirmation.',
25+
},
26+
unformattedAmountLabel: {
27+
id: 'asset.transactionConfirmation.unformattedAmountLabel',
28+
defaultMessage: '!!!unformatted amount',
29+
description:
30+
'"unformattedAmountLabel" item on AssetTransactionConfirmation.',
31+
},
32+
unformattedAmountMessageForHardwareWallets: {
33+
id:
34+
'asset.transactionConfirmation.unformattedAmountMessageForHardwareWallets',
35+
defaultMessage:
36+
'!!!Native assets may specify a number of decimal places, as defined in the Cardano token registry. Daedalus uses this information to format the amount that is being sent in the transaction.<br /><br />The native token unformatted amount is the amount without these decimal places. Please ensure that you verify both amounts, as some wallet software may not yet use the Cardano token registry.',
37+
description:
38+
'"unformattedAmountMessageForHardwareWallets" item on AssetTransactionConfirmation.',
39+
},
40+
unformattedAmountMessageForSoftwareWallets: {
41+
id:
42+
'asset.transactionConfirmation.unformattedAmountMessageForSoftwareWallets',
43+
defaultMessage:
44+
'!!!Native assets may specify a number of decimal places, as defined in the Cardano token registry. Daedalus uses this information to format the amount that is being sent in the transaction.<br /><br />The native token unformatted amount is the amount without these decimal places. Please ensure that you verify both amounts, as some wallet software may not yet use the Cardano token registry.<br /><br />The native token unformatted amount will be displayed on the hardware wallet device during transaction confirmation.',
45+
description:
46+
'"unformattedAmountMessageForSoftwareWallets" item on AssetTransactionConfirmation.',
47+
},
48+
missingToken: {
49+
id: 'asset.transactionConfirmation.missingToken',
50+
defaultMessage: '!!!There is no such token in this wallet',
51+
description: '"missingToken" item on AssetTransactionConfirmation.',
52+
},
53+
insufficientBalance: {
54+
id: 'asset.transactionConfirmation.insufficientBalance',
55+
defaultMessage:
56+
'!!!Insufficient funds. The balance of the token in this wallet is {formattedBalance} (Unformatted: {unformattedBalance})',
57+
description: '"insufficientBalance" item on AssetTransactionConfirmation.',
58+
},
59+
});
60+
61+
type Props = {
62+
asset: AssetToken,
63+
assetNumber: number,
64+
intl: intlShape.isRequired,
65+
isHardwareWallet: boolean,
66+
tokenIsMissing?: boolean,
67+
insufficientBalance?: boolean,
68+
amount: BigNumber,
69+
};
70+
71+
const onCopyAssetItem = () => {};
72+
73+
const AssetTransactionConfirmation = observer((props: Props) => {
74+
const {
75+
assetNumber,
76+
asset,
77+
intl,
78+
isHardwareWallet,
79+
tokenIsMissing,
80+
insufficientBalance,
81+
amount,
82+
} = props;
83+
const hasError = tokenIsMissing || insufficientBalance;
84+
const { metadata, decimals } = asset;
85+
const formattedAmount = formattedTokenWalletAmount(
86+
amount,
87+
metadata,
88+
decimals
89+
);
90+
const unformattedAmount = formattedTokenWalletAmount(amount, null, 0);
91+
92+
const formattedBalance = formattedTokenWalletAmount(
93+
asset.quantity,
94+
metadata,
95+
decimals
96+
);
97+
const unformattedBalance = formattedTokenWalletAmount(
98+
asset.quantity,
99+
null,
100+
0
101+
);
102+
103+
const componentStyles = classnames(styles.component, {
104+
[styles.error]: hasError,
105+
});
106+
107+
const content = (
108+
<>
109+
<div className={styles.assetsContainer}>
110+
<h3>
111+
<span className={styles.assetLabel}>
112+
{intl.formatMessage(messages.assetLabel, { assetNumber })}{' '}
113+
</span>
114+
<Asset
115+
asset={asset}
116+
onCopyAssetItem={onCopyAssetItem}
117+
hasError={hasError}
118+
/>
119+
</h3>
120+
<div className={styles.amountFeesWrapper}>
121+
<div className={styles.amount}>{formattedAmount}</div>
122+
</div>
123+
</div>
124+
<div className={styles.assetsContainer}>
125+
<div className={styles.unformattedAmountLine} />
126+
<div className={styles.unformattedAmountLabel}>
127+
{intl.formatMessage(messages.unformattedAmountLabel)}
128+
<PopOver
129+
content={
130+
<FormattedHTMLMessage
131+
{...messages[
132+
isHardwareWallet
133+
? 'unformattedAmountMessageForHardwareWallets'
134+
: 'unformattedAmountMessageForSoftwareWallets'
135+
]}
136+
tagName="div"
137+
/>
138+
}
139+
>
140+
<div className={styles.questionMark}>
141+
<SVGInline svg={questionMarkIcon} />
142+
</div>
143+
</PopOver>
144+
{':'}
145+
</div>
146+
<div className={styles.unformattedAmount}>{unformattedAmount}</div>
147+
</div>
148+
</>
149+
);
150+
151+
if (tokenIsMissing) {
152+
return (
153+
<div className={componentStyles}>
154+
<PopOver
155+
content={intl.formatMessage(messages.missingToken)}
156+
appendTo="parent"
157+
placement="bottom"
158+
>
159+
{content}
160+
</PopOver>
161+
</div>
162+
);
163+
}
164+
165+
if (insufficientBalance) {
166+
return (
167+
<div className={componentStyles}>
168+
<PopOver
169+
content={intl.formatMessage(messages.insufficientBalance, {
170+
formattedBalance,
171+
unformattedBalance,
172+
})}
173+
appendTo="parent"
174+
placement="bottom"
175+
>
176+
{content}
177+
</PopOver>
178+
</div>
179+
);
180+
}
181+
182+
return <div className={componentStyles}>{content}</div>;
183+
});
184+
185+
export default injectIntl(AssetTransactionConfirmation);

0 commit comments

Comments
 (0)