Skip to content

Commit f736614

Browse files
committed
Merge remote-tracking branch 'nicolas/transaction-refactor-continue'
2 parents 5ef0906 + cbbc794 commit f736614

File tree

9 files changed

+560
-264
lines changed

9 files changed

+560
-264
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* Copyright 2024 Shift Crypto AG
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { CopyableInput } from '@/components/copy/Copy';
18+
import transactionStyle from '@/components/transactions/transactions.module.css';
19+
import parentStyle from '@/components/transactions/transaction.module.css';
20+
21+
type TPropsTxAddress = {
22+
label: string;
23+
addresses: string[];
24+
}
25+
26+
export const TxAddress = ({
27+
label,
28+
addresses,
29+
}: TPropsTxAddress) => {
30+
return (
31+
<div className={transactionStyle.activity}>
32+
<span className={parentStyle.label}>
33+
{label}
34+
</span>
35+
<span className={parentStyle.address}>
36+
{addresses[0]}
37+
{addresses.length > 1 && (
38+
<span className={parentStyle.badge}>
39+
(+{addresses.length - 1})
40+
</span>
41+
)}
42+
</span>
43+
</div>
44+
);
45+
};
46+
47+
type TPropsTxDetailCopyableValues = {
48+
label: string;
49+
values: string[];
50+
}
51+
52+
export const TxDetailCopyableValues = ({
53+
label,
54+
values,
55+
}: TPropsTxDetailCopyableValues) => {
56+
return (
57+
<div className={`${parentStyle.detail} ${parentStyle.addresses}`}>
58+
<label>{label}</label>
59+
<div className={parentStyle.detailAddresses}>
60+
{values.map((addrOrTxID) => (
61+
<CopyableInput
62+
key={addrOrTxID}
63+
alignRight
64+
borderLess
65+
flexibleHeight
66+
className={parentStyle.detailAddress}
67+
value={addrOrTxID}
68+
/>
69+
))}
70+
</div>
71+
</div>
72+
);
73+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Copyright 2024 Shift Crypto AG
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import type { ITransaction } from '@/api/account';
18+
import { Warning } from '@/components/icon/icon';
19+
import { ArrowIn, ArrowOut, ArrowSelf } from './icons';
20+
21+
type TProps = Pick<ITransaction, 'status' | 'type'>;
22+
23+
export const Arrow = ({ status, type }: TProps) => {
24+
if (status === 'failed') {
25+
return <Warning style={{ maxWidth: '18px' }} />;
26+
}
27+
if (type === 'receive') {
28+
return <ArrowIn />;
29+
}
30+
if (type === 'send') {
31+
return <ArrowOut />;
32+
}
33+
return <ArrowSelf />;
34+
};
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* Copyright 2024 Shift Crypto AG
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { useTranslation } from 'react-i18next';
18+
import { parseTimeShort } from '@/utils/date';
19+
import { TxDetail } from './detail';
20+
import transactionsStyle from '@/components/transactions/transactions.module.css';
21+
import parentStyle from '@/components/transactions/transaction.module.css';
22+
23+
type TProps = {
24+
time: string | null;
25+
}
26+
27+
export const TxDate = ({ time }: TProps) => {
28+
const { i18n, t } = useTranslation();
29+
const shortDate = time ? parseTimeShort(time, i18n.language) : '---';
30+
return (
31+
<div className={transactionsStyle.date}>
32+
<span className={parentStyle.columnLabel}>
33+
{t('transaction.details.date')}:
34+
</span>
35+
<span className={parentStyle.date}>{shortDate}</span>
36+
</div>
37+
);
38+
};
39+
40+
export const TxDateDetail = ({ time }: TProps) => {
41+
const { i18n, t } = useTranslation();
42+
const shortDate = time ? parseTimeShort(time, i18n.language) : '---';
43+
return (
44+
<TxDetail
45+
label={t('transaction.details.date')}>
46+
{shortDate}
47+
</TxDetail>
48+
);
49+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* Copyright 2024 Shift Crypto AG
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import parentStyle from '@/components/transactions/transaction.module.css';
18+
19+
type TProps = React.PropsWithChildren<{
20+
label: string;
21+
}>;
22+
23+
export const TxDetail = ({
24+
label,
25+
children,
26+
}: TProps) => {
27+
return (
28+
<div className={parentStyle.detail}>
29+
<label>{label}</label>
30+
<p>{children}</p>
31+
</div>
32+
);
33+
};
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/**
2+
* Copyright 2024 Shift Crypto AG
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import { useEffect, useState } from 'react';
18+
import { useTranslation } from 'react-i18next';
19+
import { ITransaction, IAmount, getTransaction } from '@/api/account';
20+
import { A } from '@/components/anchor/anchor';
21+
import { Dialog } from '@/components/dialog/dialog';
22+
import { FiatConversion } from '@/components/rates/rates';
23+
import { Amount } from '@/components/amount/amount';
24+
import { Note } from '@/components/transactions/note';
25+
import { TxDetail } from './detail';
26+
import { Arrow } from './arrow';
27+
import { TxDateDetail } from './date';
28+
import { TxStatusDetail } from './status';
29+
import { TxDetailCopyableValues } from './address-or-txid';
30+
import parentStyle from '@/components/transactions/transaction.module.css';
31+
32+
type TProps = {
33+
open: boolean;
34+
onClose: () => void;
35+
accountCode: string;
36+
internalID: string;
37+
note: string;
38+
status: ITransaction['status'];
39+
type: ITransaction['type'];
40+
numConfirmations: number;
41+
numConfirmationsComplete: number;
42+
time: string | null;
43+
amount: IAmount;
44+
sign: string;
45+
typeClassName: string;
46+
explorerURL: string;
47+
}
48+
49+
export const TxDetailsDialog = ({
50+
open,
51+
onClose,
52+
accountCode,
53+
internalID,
54+
note,
55+
status,
56+
type,
57+
numConfirmations,
58+
numConfirmationsComplete,
59+
time,
60+
amount,
61+
sign,
62+
typeClassName,
63+
explorerURL,
64+
}: TProps) => {
65+
const { t } = useTranslation();
66+
67+
const [transactionInfo, setTransactionInfo] = useState<ITransaction | null>(null);
68+
69+
useEffect(() => {
70+
if (!transactionInfo && open) {
71+
getTransaction(accountCode, internalID).then(transaction => {
72+
if (!transaction) {
73+
console.error(`Unable to retrieve transaction ${internalID}`);
74+
}
75+
setTransactionInfo(transaction);
76+
}).catch(console.error);
77+
}
78+
}, [accountCode, internalID, open, transactionInfo]);
79+
80+
// Amount and Confirmations info are displayed using props data
81+
// instead of transactionInfo because they are live updated.
82+
return (
83+
<Dialog
84+
open={open && !!transactionInfo}
85+
title={t('transaction.details.title')}
86+
onClose={onClose}
87+
slim
88+
medium>
89+
{transactionInfo && (
90+
<>
91+
<Note
92+
accountCode={accountCode}
93+
internalID={internalID}
94+
note={note}
95+
/>
96+
<TxDetail label={t('transaction.details.type')}>
97+
<Arrow
98+
status={status}
99+
type={type}
100+
/>
101+
</TxDetail>
102+
<TxDetail label={t('transaction.confirmation')}>{numConfirmations}</TxDetail>
103+
<TxStatusDetail
104+
status={status}
105+
numConfirmations={numConfirmations}
106+
numConfirmationsComplete={numConfirmationsComplete}
107+
/>
108+
<TxDateDetail time={time} />
109+
<TxDetail label={t('transaction.details.fiat')}>
110+
<span className={`${parentStyle.fiat} ${typeClassName}`}>
111+
<FiatConversion amount={amount} sign={sign} noAction />
112+
</span>
113+
</TxDetail>
114+
<TxDetail label={t('transaction.details.fiatAtTime')}>
115+
<span className={`${parentStyle.fiat} ${typeClassName}`}>
116+
{transactionInfo.amountAtTime ?
117+
<FiatConversion amount={transactionInfo.amountAtTime} sign={sign} noAction />
118+
:
119+
<FiatConversion noAction />
120+
}
121+
</span>
122+
</TxDetail>
123+
<TxDetail label={t('transaction.details.amount')}>
124+
<span className={`${parentStyle.amount} ${typeClassName}`}>
125+
{sign}
126+
<Amount amount={amount.amount} unit={amount.unit} />
127+
</span>
128+
{' '}
129+
<span className={`${parentStyle.currencyUnit} ${typeClassName}`}>{transactionInfo.amount.unit}</span>
130+
</TxDetail>
131+
{
132+
transactionInfo.fee && transactionInfo.fee.amount ? (
133+
<TxDetail label={t('transaction.fee')}>
134+
<Amount amount={transactionInfo.fee.amount} unit={transactionInfo.fee.unit} />
135+
{' '}
136+
<span className={parentStyle.currencyUnit}>{transactionInfo.fee.unit}</span>
137+
</TxDetail>
138+
) : (
139+
<TxDetail label={t('transaction.fee')}>---</TxDetail>
140+
)
141+
}
142+
<TxDetailCopyableValues
143+
label={t('transaction.details.address')}
144+
values={transactionInfo.addresses}
145+
/>
146+
{
147+
transactionInfo.gas ? (
148+
<TxDetail label={t('transaction.gas')}>{transactionInfo.gas}</TxDetail>
149+
) : null
150+
}
151+
{
152+
transactionInfo.nonce ? (
153+
<TxDetail label="Nonce">{transactionInfo.nonce}</TxDetail>
154+
) : null
155+
}
156+
{
157+
transactionInfo.weight ? (
158+
<TxDetail label={t('transaction.weight')}>
159+
{transactionInfo.weight}
160+
{' '}
161+
<span className={parentStyle.currencyUnit}>WU</span>
162+
</TxDetail>
163+
) : null
164+
}
165+
{
166+
transactionInfo.vsize ? (
167+
<TxDetail label={t('transaction.vsize')}>
168+
{transactionInfo.vsize}
169+
{' '}
170+
<span className={parentStyle.currencyUnit}>b</span>
171+
</TxDetail>
172+
) : null
173+
}
174+
{
175+
transactionInfo.size ? (
176+
<TxDetail label={t('transaction.size')}>
177+
{transactionInfo.size}
178+
{' '}
179+
<span className={parentStyle.currencyUnit}>b</span>
180+
</TxDetail>
181+
) : null
182+
}
183+
<TxDetailCopyableValues
184+
label={t('transaction.explorer')}
185+
values={[transactionInfo.txID]}
186+
/>
187+
<div className={`${parentStyle.detail} flex-center`}>
188+
<A
189+
href={explorerURL + transactionInfo.txID}
190+
title={`${t('transaction.explorerTitle')}\n${explorerURL}${transactionInfo.txID}`}>
191+
{t('transaction.explorerTitle')}
192+
</A>
193+
</div>
194+
</>
195+
)}
196+
</Dialog>
197+
);
198+
};

0 commit comments

Comments
 (0)