Skip to content

Commit 26fa14c

Browse files
committed
Merge branch 'tx-note-component'
2 parents 3bb7b37 + 094b9af commit 26fa14c

File tree

2 files changed

+101
-75
lines changed

2 files changed

+101
-75
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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, useRef, useState } from 'react';
18+
import { useTranslation } from 'react-i18next';
19+
import * as accountApi from '../../api/account';
20+
import { Input } from '../../components/forms';
21+
import { useDarkmode } from '../../hooks/darkmode';
22+
import { Edit, EditLight, Save, SaveLight } from '../icon/icon';
23+
24+
import style from './transaction.module.css';
25+
26+
type Props = {
27+
accountCode: accountApi.AccountCode;
28+
internalID: string;
29+
// Contains the existing note.
30+
note: string;
31+
}
32+
33+
export function Note({ accountCode, note, internalID }: Props) {
34+
const { isDarkMode } = useDarkmode();
35+
const { t } = useTranslation();
36+
const [newNote, setNewNote] = useState<string>(note);
37+
const [editMode, setEditMode] = useState<boolean>(!note);
38+
const inputRef = useRef<HTMLInputElement>(null);
39+
const editButtonRef = useRef<HTMLButtonElement>(null);
40+
41+
useEffect(() => {
42+
if (editMode && inputRef.current) {
43+
inputRef.current.focus();
44+
}
45+
}, [editMode]);
46+
47+
const handleNoteInput = (e: Event) => {
48+
const target = e.target as HTMLInputElement;
49+
setNewNote(target.value);
50+
};
51+
52+
const handleEdit = (e: React.SyntheticEvent) => {
53+
e.preventDefault();
54+
if (editMode && note !== newNote) {
55+
accountApi.postNotesTx(accountCode, {
56+
internalTxID: internalID,
57+
note: newNote,
58+
}).catch(console.error);
59+
}
60+
setEditMode(!editMode);
61+
};
62+
63+
return (
64+
<form onSubmit={handleEdit} className={style.detailInput}>
65+
<label htmlFor="note">{t('note.title')}</label>
66+
<Input
67+
align="right"
68+
autoFocus={editMode}
69+
className={style.textOnlyInput}
70+
readOnly={!editMode}
71+
type="text"
72+
id="note"
73+
transparent
74+
placeholder={t('note.input.placeholder')}
75+
value={newNote}
76+
maxLength={256}
77+
onInput={handleNoteInput}
78+
ref={inputRef}/>
79+
<button
80+
className={style.editButton}
81+
onClick={handleEdit}
82+
title={t(`transaction.note.${editMode ? 'save' : 'edit'}`)}
83+
type="button"
84+
ref={editButtonRef}>
85+
{
86+
editMode
87+
? isDarkMode ? <SaveLight /> : <Save />
88+
: isDarkMode ? <EditLight /> : <Edit />
89+
}
90+
</button>
91+
</form>
92+
);
93+
}

frontends/web/src/components/transactions/transaction.tsx

Lines changed: 8 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,23 @@
1515
* limitations under the License.
1616
*/
1717

18-
import React, { Component, createRef } from 'react';
18+
import { Component } from 'react';
1919
import * as accountApi from '../../api/account';
20-
import { Input } from '../../components/forms';
2120
import { translate, TranslateProps } from '../../decorators/translate';
2221
import { A } from '../anchor/anchor';
2322
import { Dialog } from '../dialog/dialog';
2423
import { CopyableInput } from '../copy/Copy';
25-
import { Edit, EditLight, ExpandIcon, Save, SaveLight } from '../icon/icon';
24+
import { ExpandIcon } from '../icon/icon';
2625
import { ProgressRing } from '../progressRing/progressRing';
2726
import { FiatConversion } from '../rates/rates';
2827
import { Amount } from '../../components/amount/amount';
2928
import { ArrowIn, ArrowOut, ArrowSelf } from './components/icons';
30-
import { getDarkmode } from '../darkmode/darkmode';
29+
import { Note } from './note';
3130
import parentStyle from './transactions.module.css';
3231
import style from './transaction.module.css';
3332

3433
interface State {
3534
transactionDialog: boolean;
36-
newNote: string;
37-
editMode: boolean;
3835
transactionInfo?: accountApi.ITransaction;
3936
}
4037

@@ -47,13 +44,8 @@ interface TransactionProps extends accountApi.ITransaction {
4744
type Props = TransactionProps & TranslateProps;
4845

4946
class Transaction extends Component<Props, State> {
50-
private input = createRef<HTMLInputElement>();
51-
private editButton = createRef<HTMLButtonElement>();
52-
5347
public readonly state: State = {
5448
transactionDialog: false,
55-
newNote: this.props.note,
56-
editMode: !this.props.note,
5749
};
5850

5951
private parseTimeShort = (time: string) => {
@@ -74,8 +66,6 @@ class Transaction extends Component<Props, State> {
7466
this.setState({
7567
transactionInfo: transaction,
7668
transactionDialog: true,
77-
newNote: this.props.note,
78-
editMode: !this.props.note,
7969
});
8070
})
8171
.catch(console.error);
@@ -85,37 +75,6 @@ class Transaction extends Component<Props, State> {
8575
this.setState({ transactionDialog: false });
8676
};
8777

88-
private handleNoteInput = (e: Event) => {
89-
const target = e.target as HTMLInputElement;
90-
this.setState({ newNote: target.value });
91-
};
92-
93-
private handleEdit = (e: React.SyntheticEvent) => {
94-
e.preventDefault();
95-
if (this.state.editMode && this.props.note !== this.state.newNote) {
96-
accountApi.postNotesTx(this.props.accountCode, {
97-
internalTxID: this.props.internalID,
98-
note: this.state.newNote,
99-
})
100-
.catch(console.error);
101-
}
102-
this.focusEdit();
103-
this.setState(
104-
({ editMode }) => ({ editMode: !editMode }),
105-
this.focusEdit,
106-
);
107-
};
108-
109-
private focusEdit = () => {
110-
if (this.editButton.current) {
111-
this.editButton.current.blur();
112-
}
113-
if (this.state.editMode && this.input.current) {
114-
this.input.current.scrollLeft = this.input.current.scrollWidth;
115-
this.input.current.focus();
116-
}
117-
};
118-
11978
public render() {
12079
const {
12180
t,
@@ -133,8 +92,6 @@ class Transaction extends Component<Props, State> {
13392
} = this.props;
13493
const {
13594
transactionDialog,
136-
newNote,
137-
editMode,
13895
transactionInfo,
13996
} = this.state;
14097
const arrow = type === 'receive' ? (
@@ -153,7 +110,6 @@ class Transaction extends Component<Props, State> {
153110
failed: t('transaction.status.failed'),
154111
}[status];
155112
const progress = numConfirmations < numConfirmationsComplete ? (numConfirmations / numConfirmationsComplete) * 100 : 100;
156-
const darkmode = getDarkmode();
157113

158114
return (
159115
<div className={[style.container, index === 0 ? style.first : ''].join(' ')}>
@@ -238,34 +194,11 @@ class Transaction extends Component<Props, State> {
238194
slim
239195
medium>
240196
{transactionInfo && <>
241-
<form onSubmit={this.handleEdit} className={style.detailInput}>
242-
<label htmlFor="note">{t('note.title')}</label>
243-
<Input
244-
align="right"
245-
autoFocus={editMode}
246-
className={style.textOnlyInput}
247-
readOnly={!editMode}
248-
type="text"
249-
id="note"
250-
transparent
251-
placeholder={t('note.input.placeholder')}
252-
value={newNote}
253-
maxLength={256}
254-
onInput={this.handleNoteInput}
255-
ref={this.input}/>
256-
<button
257-
className={style.editButton}
258-
onClick={this.handleEdit}
259-
title={t(`transaction.note.${editMode ? 'save' : 'edit'}`)}
260-
type="button"
261-
ref={this.editButton}>
262-
{
263-
editMode
264-
? darkmode ? <SaveLight /> : <Save />
265-
: darkmode ? <EditLight /> : <Edit />
266-
}
267-
</button>
268-
</form>
197+
<Note
198+
accountCode={this.props.accountCode}
199+
internalID={this.props.internalID}
200+
note={this.props.note}
201+
/>
269202
<div className={style.detail}>
270203
<label>{t('transaction.details.type')}</label>
271204
<p>{arrow}</p>

0 commit comments

Comments
 (0)