Skip to content

Commit b1af1fb

Browse files
committed
feat: display recent activities in sentence style
1 parent 32c6432 commit b1af1fb

10 files changed

Lines changed: 229 additions & 90 deletions

File tree

packages/neuron-ui/src/components/Overview/index.tsx

Lines changed: 130 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
DefaultButton,
99
DetailsList,
1010
DetailsRow,
11+
Icon,
1112
IColumn,
1213
CheckboxVisibility,
1314
DetailsListLayoutMode,
@@ -24,66 +25,96 @@ import PropertyList, { Property } from 'widgets/PropertyList'
2425
import { StateWithDispatch } from 'states/stateProvider/reducer'
2526
import { updateTransactionList, addPopup } from 'states/stateProvider/actionCreators'
2627

27-
import { showErrorMessage } from 'services/remote'
28+
import { showTransactionDetails, showErrorMessage } from 'services/remote'
2829

2930
import { localNumberFormatter, shannonToCKBFormatter, uniformTimeFormatter as timeFormatter } from 'utils/formatters'
30-
import { PAGE_SIZE } from 'utils/const'
31+
import { PAGE_SIZE, Routes, CONFIRMATION_THRESHOLD } from 'utils/const'
3132

3233
const TITLE_FONT_SIZE = 'xxLarge'
34+
export type ActivityItem = State.Transaction & { confirmations: string; typeLabel: string }
35+
36+
const genTypeLabel = (type: 'send' | 'receive', confirmationCount: number) => {
37+
switch (type) {
38+
case 'send': {
39+
if (confirmationCount < CONFIRMATION_THRESHOLD) {
40+
return 'sending'
41+
}
42+
return 'sent'
43+
}
44+
case 'receive': {
45+
if (confirmationCount < CONFIRMATION_THRESHOLD) {
46+
return 'receiving'
47+
}
48+
return 'received'
49+
}
50+
default: {
51+
return type
52+
}
53+
}
54+
}
3355

3456
const ActivityList = ({
3557
columns,
3658
items,
59+
onGoToHistory,
60+
t,
3761
...props
3862
}: React.PropsWithoutRef<{
3963
columns: IColumn[]
4064
items: any
65+
onGoToHistory: any
66+
t: any
4167
isHeaderVisible?: boolean
4268
onRenderRow?: IRenderFunction<IDetailsRowProps>
4369
[index: string]: any
4470
}>) => (
45-
<DetailsList
46-
layoutMode={DetailsListLayoutMode.fixedColumns}
47-
checkboxVisibility={CheckboxVisibility.hidden}
48-
compact
49-
items={items}
50-
columns={columns}
51-
styles={{
52-
root: {
53-
backgroundColor: 'transparent',
54-
},
55-
headerWrapper: {
56-
selectors: {
57-
'.ms-DetailsHeader': {
58-
backgroundColor: 'transparent',
59-
},
60-
'.ms-DetailsHeader-cellName': {
61-
fontSize: FontSizes.xLarge,
62-
},
71+
<Stack>
72+
<DetailsList
73+
isHeaderVisible={false}
74+
layoutMode={DetailsListLayoutMode.justified}
75+
checkboxVisibility={CheckboxVisibility.hidden}
76+
compact
77+
items={items.slice(0, 10)}
78+
columns={columns}
79+
onItemInvoked={item => {
80+
showTransactionDetails(item.hash)
81+
}}
82+
styles={{
83+
root: {
84+
backgroundColor: 'transparent',
6385
},
64-
},
65-
contentWrapper: {
66-
selectors: {
67-
'.ms-DetailsRow': {
68-
backgroundColor: 'transparent',
69-
},
70-
'.ms-DetailsRow-cell': {
71-
fontSize: FontSizes.mediumPlus,
86+
contentWrapper: {
87+
selectors: {
88+
'.ms-DetailsRow': {
89+
backgroundColor: 'transparent',
90+
},
91+
'.ms-DetailsRow-cell': {
92+
fontSize: FontSizes.mediumPlus,
93+
},
7294
},
7395
},
74-
},
75-
}}
76-
{...props}
77-
/>
96+
}}
97+
{...props}
98+
/>
99+
{items.length > 10 ? (
100+
<Stack horizontalAlign="stretch">
101+
<DefaultButton onClick={onGoToHistory} styles={{ root: { border: 'none' } }}>
102+
{t('overview.more')}
103+
</DefaultButton>
104+
</Stack>
105+
) : null}
106+
</Stack>
78107
)
79108
const Overview = ({
80109
dispatch,
81110
app: { tipBlockNumber, chain, epoch, difficulty },
82111
wallet: { id, name, balance = '', addresses = [] },
83112
chain: {
113+
tipBlockNumber: syncedBlockNumber,
84114
codeHash = '',
85115
transactions: { items = [] },
86116
},
117+
history,
87118
}: React.PropsWithoutRef<StateWithDispatch & RouteComponentProps>) => {
88119
const [t] = useTranslation()
89120
const [displayBlockchainInfo, setDisplayBlockchainInfo] = useState(false)
@@ -100,6 +131,9 @@ const Overview = ({
100131
walletID: id,
101132
})(dispatch)
102133
}, [id, dispatch])
134+
const onGoToHistory = useCallback(() => {
135+
history.push(Routes.History)
136+
}, [history])
103137

104138
const onTransactionRowRender = useCallback((props?: IDetailsRowProps) => {
105139
if (props) {
@@ -108,29 +142,29 @@ const Overview = ({
108142
animationDuration: '0!important',
109143
},
110144
}
111-
if (props.item.status === 'failed') {
112-
customStyles.root = {
113-
animationDuration: '0!important',
114-
color: 'red',
115-
}
116-
}
117145
return <DetailsRow {...props} styles={customStyles} />
118146
}
119147
return null
120148
}, [])
121149

122-
const onTransactionTypeRender = useCallback((item?: any) => {
150+
const onTransactionActivityRender = useCallback((item?: ActivityItem) => {
123151
if (item) {
124152
return (
125-
<Text
126-
variant="mediumPlus"
127-
as="span"
128-
style={{
129-
color: item.type === 'receive' ? '#28b463' : '#e66465',
130-
}}
131-
>
132-
{item.type}
133-
</Text>
153+
<>
154+
<Text
155+
variant="mediumPlus"
156+
as="span"
157+
style={{
158+
color: item.type === 'receive' ? '#28b463' : '#e66465',
159+
}}
160+
title={`${item.value} shannon`}
161+
>
162+
{`${item.typeLabel} ${shannonToCKBFormatter(item.value)} CKB`}
163+
</Text>
164+
<Text variant="mediumPlus" as="span" title={item.confirmations} styles={{ root: [{ paddingLeft: '5px' }] }}>
165+
{item.confirmations}
166+
</Text>
167+
</>
134168
)
135169
}
136170
return null
@@ -149,6 +183,24 @@ const Overview = ({
149183

150184
const activityColumns: IColumn[] = useMemo(() => {
151185
return [
186+
{
187+
key: 'status',
188+
name: t('overview.status'),
189+
minWidth: 20,
190+
maxWidth: 20,
191+
onRender: (item?: State.Transaction) => {
192+
if (!item) {
193+
return null
194+
}
195+
let iconName = 'TransactionPending'
196+
if (item.status === 'success') {
197+
iconName = 'TransactionSuccess'
198+
} else if (item.status === 'failed') {
199+
iconName = 'TransactionFailure'
200+
}
201+
return <Icon iconName={iconName} title={item.status} />
202+
},
203+
},
152204
{
153205
key: 'timestamp',
154206
name: t('overview.datetime'),
@@ -157,30 +209,11 @@ const Overview = ({
157209
onRender: onTimestampRender,
158210
},
159211
{
160-
key: 'type',
161-
name: t('overview.type'),
212+
key: 'activity',
213+
name: t('overview.activity'),
162214
minWidth: 100,
163-
maxWidth: 100,
164-
onRender: onTransactionTypeRender,
165-
},
166-
{
167-
key: 'status',
168-
name: t('overview.status'),
169-
minWidth: 100,
170-
maxWidth: 100,
171-
},
172-
{
173-
key: 'value',
174-
name: t('overview.amount'),
175-
title: 'value',
176-
minWidth: 100,
177-
maxWidth: 500,
178-
onRender: (item?: State.Transaction) => {
179-
if (item) {
180-
return <span title={`${item.value} shannon`}>{`${shannonToCKBFormatter(item.value)} CKB`}</span>
181-
}
182-
return '-'
183-
},
215+
maxWidth: 600,
216+
onRender: onTransactionActivityRender,
184217
},
185218
].map(
186219
(col): IColumn => ({
@@ -189,7 +222,7 @@ const Overview = ({
189222
...col,
190223
})
191224
)
192-
}, [t, onTimestampRender, onTransactionTypeRender])
225+
}, [t, onTimestampRender, onTransactionActivityRender])
193226

194227
const balanceProperties: Property[] = useMemo(
195228
() => [
@@ -249,6 +282,24 @@ const Overview = ({
249282
}
250283
}, [defaultAddress, t, hideMinerInfo, dispatch])
251284

285+
const activityItems = useMemo(
286+
() =>
287+
items.map(item => {
288+
let confirmations = '(-)'
289+
let typeLabel: string = item.type
290+
if (item.blockNumber !== undefined) {
291+
const confirmationCount = 1 + Math.max(+syncedBlockNumber, +tipBlockNumber) - +item.blockNumber
292+
typeLabel = genTypeLabel(item.type, confirmationCount)
293+
confirmations =
294+
confirmationCount > 1
295+
? `(${t('overview.confirmations', { confirmationCount: localNumberFormatter(confirmationCount) })})`
296+
: `(${t('overview.confirmation', { confirmationCount: localNumberFormatter(confirmationCount) })})`
297+
}
298+
return { ...item, confirmations, typeLabel: t(`overview.${typeLabel}`) }
299+
}),
300+
[items, t, syncedBlockNumber, tipBlockNumber]
301+
)
302+
252303
return (
253304
<Stack tokens={{ childrenGap: 15 }} verticalFill horizontalAlign="stretch">
254305
<Text as="h1" variant={TITLE_FONT_SIZE}>
@@ -273,7 +324,13 @@ const Overview = ({
273324
{t('overview.recent-activities')}
274325
</Text>
275326
{items.length ? (
276-
<ActivityList columns={activityColumns} items={items} onRenderRow={onTransactionRowRender} />
327+
<ActivityList
328+
columns={activityColumns}
329+
items={activityItems}
330+
onRenderRow={onTransactionRowRender}
331+
onGoToHistory={onGoToHistory}
332+
t={t}
333+
/>
277334
) : (
278335
<div>{t('overview.no-recent-activities')}</div>
279336
)}

packages/neuron-ui/src/locales/en.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"balance": "Balance",
1717
"recent-activities": "Recent Activities",
1818
"no-recent-activities": "No Recent Activities",
19-
"type": "Type",
19+
"activity": "Activity",
2020
"datetime": "Date & Time",
2121
"status": "Status",
2222
"amount": "Amount",
@@ -29,7 +29,14 @@
2929
"lock-arg": "Lock Arg",
3030
"address": "Address",
3131
"code-hash": "Code Hash",
32-
"copy-pubkey-hash": "Copy Lock Arg (Pubkey Hash)"
32+
"copy-pubkey-hash": "Copy Lock Arg (Pubkey Hash)",
33+
"confirmation": "{{confirmationCount}} Confirmation",
34+
"confirmations": "{{confirmationCount}} Confirmations",
35+
"sent": "Sent",
36+
"sending": "Sending",
37+
"received": "Received",
38+
"receiving": "Receiving",
39+
"more": "More Transactions"
3340
},
3441
"wizard": {
3542
"welcome-to-nervos-neuron": "Welcome to Neuron",

packages/neuron-ui/src/locales/zh.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"balance": "余额",
1717
"recent-activities": "近期活动",
1818
"no-recent-activities": "近期没有活动",
19-
"type": "类型",
19+
"activity": "行为",
2020
"datetime": "时间",
2121
"status": "状态",
2222
"amount": "金额",
@@ -29,7 +29,14 @@
2929
"lock-arg": "Lock Arg",
3030
"address": "地址",
3131
"code-hash": "Code Hash",
32-
"copy-pubkey-hash": "复制 Lock Arg (Pubkey Hash)"
32+
"copy-pubkey-hash": "复制 Lock Arg (Pubkey Hash)",
33+
"confirmation": "已确认 {{confirmationCount}} 次数",
34+
"confirmations": "已确认 {{confirmationCount}} 次数",
35+
"sent": "已发送",
36+
"sending": "发送",
37+
"received": "已收款",
38+
"receiving": "收款",
39+
"more": "查看更多交易"
3340
},
3441
"wizard": {
3542
"welcome-to-nervos-neuron": "欢迎使用 Neuron",

packages/neuron-ui/src/states/initStates/chain.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { ConnectionStatus } from 'utils/const'
44
export const transactionState: State.DetailedTransaction = {
55
value: '',
66
hash: '',
7-
type: 'other',
7+
type: 'receive',
88
createdAt: '0',
99
updatedAt: '0',
1010
timestamp: '0',

packages/neuron-ui/src/stories/History.stories.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,14 @@ stories.addDecorator(withKnobs).add('With knobs', () => {
122122
pageSize: number('Page Size', 15),
123123
totalCount: number('Total Count', 200),
124124
items: transactions['Content List'].map((tx, idx) => ({
125-
type: text(`${idx}-Type`, tx.type) as 'send' | 'receive' | 'other',
125+
type: text(`${idx}-Type`, tx.type) as 'send' | 'receive',
126126
createdAt: text(`${idx}-Created at`, tx.createdAt),
127127
updatedAt: text(`${idx}-Updated at`, tx.updatedAt),
128128
timestamp: text(`${idx}-Timestamp`, tx.timestamp),
129129
value: text(`${idx}-Value`, tx.value),
130130
hash: text(`${idx}-Hash`, tx.hash),
131131
description: text(`${idx}-Description`, tx.description),
132+
blockNumber: text(`${idx}-BlockNumber`, tx.blockNumber),
132133
status: text(`${idx}-Status`, tx.status) as 'pending' | 'success' | 'failed',
133134
})),
134135
keywords: '',

0 commit comments

Comments
 (0)