diff --git a/frontends/web/src/components/aopp/aopp.module.css b/frontends/web/src/components/aopp/aopp.module.css
index e9e8a89472..8d2dadbf60 100644
--- a/frontends/web/src/components/aopp/aopp.module.css
+++ b/frontends/web/src/components/aopp/aopp.module.css
@@ -7,6 +7,11 @@
text-align: center;
}
+.smallIcon {
+ margin: auto 0;
+ width: 30px;
+}
+
.successText {
color: var(--color-secondary);
font-weight: 400;
diff --git a/frontends/web/src/components/aopp/aopp.tsx b/frontends/web/src/components/aopp/aopp.tsx
index 562fac387a..e75a57c50f 100644
--- a/frontends/web/src/components/aopp/aopp.tsx
+++ b/frontends/web/src/components/aopp/aopp.tsx
@@ -1,5 +1,5 @@
/**
- * Copyright 2021-2024 Shift Crypto AG
+ * Copyright 2021 Shift Crypto AG
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,20 +14,21 @@
* limitations under the License.
*/
-import React, { ReactNode, useEffect, useState } from 'react';
-import { useTranslation } from 'react-i18next';
+import React, { Component, ReactNode } from 'react';
import * as accountAPI from '@/api/account';
import * as aoppAPI from '@/api/aopp';
+import { translate, TranslateProps } from '@/decorators/translate';
import { equal } from '@/utils/equal';
import { SimpleMarkup } from '@/utils/markup';
import { View, ViewHeader, ViewContent, ViewButtons } from '@/components/view/view';
import { Message } from '@/components/message/message';
import { Button, Field, Label, Select } from '@/components/forms';
import { CopyableInput } from '@/components/copy/Copy';
-import { PointToBitBox02 } from '@/components/icon';
+import { Cancel, PointToBitBox02 } from '@/components/icon';
import { VerifyAddress } from './verifyaddress';
import { Vasp } from './vasp';
import styles from './aopp.module.css';
+import { TUnsubscribe } from '@/utils/transport-common';
type TProps = {
children: ReactNode;
@@ -37,111 +38,164 @@ const Banner = ({ children }: TProps) => (
{children}
);
+type State = {
+ accountCode: accountAPI.AccountCode;
+ aopp?: aoppAPI.Aopp;
+}
+
+type Props = TranslateProps;
+
const domain = (callback: string): string => new URL(callback).host;
-export const Aopp = () => {
- const { t } = useTranslation();
+class Aopp extends Component {
+ public readonly state: State = {
+ accountCode: '',
+ aopp: undefined,
+ };
+ private unsubscribe?: TUnsubscribe;
- const [accountCode, setAccountCode] = useState('');
- const [aopp, setAopp] = useState();
+ public componentDidMount() {
+ this.setAccountCodeDefault();
+ this.unsubscribe = aoppAPI.subscribeAOPP(aopp => this.updateAOPP(aopp));
+ aoppAPI.getAOPP().then(aopp => this.setState({ aopp }));
+ }
+ public componentWillUnmount() {
+ if (this.unsubscribe) {
+ this.unsubscribe();
+ }
+ }
- const setAccountCodeDefault = (aopp: aoppAPI.Aopp | undefined) => {
+ private updateAOPP(aopp: aoppAPI.Aopp) {
+ let shouldUpdateAccountCodeDefault = false;
+ this.setState(currentState => {
+ if (aopp?.state === 'choosing-account'
+ && (
+ currentState.aopp?.state !== 'choosing-account'
+ || !equal(aopp.accounts, currentState.aopp?.accounts)
+ )
+ ) {
+ shouldUpdateAccountCodeDefault = true;
+ }
+ return { aopp };
+ }, () => { // callback when state did update
+ if (shouldUpdateAccountCodeDefault) {
+ this.setAccountCodeDefault();
+ }
+ });
+ }
+
+ private setAccountCodeDefault() {
+ const { aopp } = this.state;
if (aopp === undefined || aopp.state !== 'choosing-account') {
return;
}
if (aopp.accounts.length) {
- setAccountCode(aopp.accounts[0].code);
+ this.setState({ accountCode: aopp.accounts[0].code });
}
- };
-
- useEffect(() => {
- setAccountCodeDefault(aopp);
- const unsubscribe = aoppAPI.subscribeAOPP((new_aopp: aoppAPI.Aopp) => {
- if (new_aopp?.state === 'choosing-account'
- && (
- aopp?.state !== 'choosing-account'
- || !equal(new_aopp.accounts, aopp?.accounts)
- )) {
- setAccountCodeDefault(new_aopp);
- }
- setAopp(new_aopp);
- });
- aoppAPI.getAOPP().then(aopp => setAopp(aopp));
- return unsubscribe;
- }, [aopp]);
+ }
- const chooseAccount = (e: React.SyntheticEvent) => {
- if (accountCode) {
- aoppAPI.chooseAccount(accountCode);
+ private chooseAccount = (e: React.SyntheticEvent) => {
+ if (this.state.accountCode) {
+ aoppAPI.chooseAccount(this.state.accountCode);
}
e.preventDefault();
};
- if (!aopp) {
- return null;
- }
- switch (aopp.state) {
- case 'error':
- return (
-
-
- {domain(aopp.callback)}
-
-
-
- {t(`error.${aopp.errorCode}`, { host: domain(aopp.callback) })}
-
-
-
-
-
-
- );
- case 'inactive':
- // Inactive, waiting for action.
- return null;
- case 'user-approval':
- return (
-
-
-
- ${domain(aopp.callback)}`
- })} />
- )}
- withLogoText={t('aopp.addressRequestWithLogo')} />
-
-
-
-
-
-
- );
- case 'awaiting-keystore':
- return (
- {t('aopp.banner')}
- );
- case 'choosing-account': {
- const options = aopp.accounts.map(account => {
- return {
- text: account.name,
- value: account.code,
- };
- });
- return (
-
+ );
+ }
+ case 'syncing':
+ return (
{
-
-
-
- );
- }
- case 'syncing':
- return (
-
-
-
-
-
- {t('aopp.syncing')}
-
-
-
-
-
- );
- case 'signing':
- return (
-
-
-
-
-
- {t('aopp.signing')}
-
-
-
-
-
-
-
- {aopp.message}
-
-
-
-
-
- );
- case 'success':
- return (
-
-
- {t('aopp.success.title')}
-
- {t('aopp.success.message', { host: domain(aopp.callback) })}
-
-
-
-
-
-
-
-
- {aopp.message}
-
-
-
-
-
-
-
-
- );
+ );
+ case 'signing':
+ return (
+
+
+
+
+
+ {t('aopp.signing')}
+
+
+
+
+
+
+
+ {aopp.message}
+
+
+
+
+
+ );
+ case 'success':
+ return (
+
+
+ {t('aopp.success.title')}
+
+ {t('aopp.success.message', { host: domain(aopp.callback) })}
+
+
+
+
+
+
+
+
+ {aopp.message}
+
+
+
+
+
+
+
+
+ );
+ }
}
-};
+}
+const translateHOC = translate()(Aopp);
+export { translateHOC as Aopp };
\ No newline at end of file