Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: [IOBP-368] Revamp wallet transaction detail page #5282

Merged
merged 32 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e9f2367
Merge remote-tracking branch 'origin/master' into IOBP-368-new-wallet…
Hantex9 Nov 29, 2023
7086053
feat: New transaction details revamp
Hantex9 Nov 29, 2023
36acc00
feat: Added skeletons when loading
Hantex9 Nov 29, 2023
76fb94d
feat: Created details operation screen
Hantex9 Nov 29, 2023
53713e3
revert: Podfile
Hantex9 Nov 29, 2023
2d1b9c8
Merge remote-tracking branch 'origin/master' into IOBP-368-new-wallet…
Hantex9 Nov 29, 2023
8632835
chore: completed operation transaction details screen
Hantex9 Nov 30, 2023
c1d2887
Merge branch 'master' into IOBP-368-new-wallet-transaction-detail
Hantex9 Nov 30, 2023
6fa967e
chore: added i18n labels
Hantex9 Nov 30, 2023
378a646
chore: added grandTotal and unused double props
Hantex9 Nov 30, 2023
0ed1a64
chore: removed null-safe operator
Hantex9 Nov 30, 2023
b3f4a0e
chore: Changed to undefined every possible null reference
Hantex9 Nov 30, 2023
f94e62f
chore: removed comment typo
Hantex9 Nov 30, 2023
934d85f
chore: removed unuseful optional-chaining operator
Hantex9 Nov 30, 2023
52ce78b
chore: added styling property for more readability
Hantex9 Nov 30, 2023
31b14c9
chore: renamed function
Hantex9 Nov 30, 2023
1096aa6
chore: added optional chaining operator
Hantex9 Nov 30, 2023
1113290
chore: renamed some italians temporary variables
Hantex9 Nov 30, 2023
5fac444
chore: added loading status into variable
Hantex9 Nov 30, 2023
276f5f8
chore: added operation subject into operation details screen
Hantex9 Nov 30, 2023
5ee6025
feat: Integrated the new RNavScreenWithLargeHeader into transaction d…
Hantex9 Nov 30, 2023
b1f115e
chore: added dimensions window into a variable
Hantex9 Nov 30, 2023
e6a03f3
chore: indent
Hantex9 Nov 30, 2023
d0a7a8b
chore: removed unused imports
Hantex9 Nov 30, 2023
03b925d
chore: removed unused imports
Hantex9 Nov 30, 2023
43186fd
Merge branch 'master' into IOBP-368-new-wallet-transaction-detail
Hantex9 Dec 1, 2023
32da611
Merge branch 'master' into IOBP-368-new-wallet-transaction-detail
Hantex9 Dec 1, 2023
75e9eeb
chore: Added transaction screen navigation based on DS feature flag
Hantex9 Dec 1, 2023
4269580
Merge branch 'master' into IOBP-368-new-wallet-transaction-detail
Hantex9 Dec 1, 2023
0100c64
Merge branch 'master' into IOBP-368-new-wallet-transaction-detail
Hantex9 Dec 4, 2023
e4c2f59
fix: Added FF into wallet home screen
Hantex9 Dec 4, 2023
027d4a6
Merge branch 'master' into IOBP-368-new-wallet-transaction-detail
Hantex9 Dec 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions img/features/wallet/transaction-receipt-divider.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3788,3 +3788,19 @@ fastLogin:
description: every time a login with SPID or CIE is performed, we'll send you an e-mail to let you know.
whatsNew:
title: What's changed?
transaction:
details:
title: Dettaglio operazione
totalAmount: Totale
totalFee: Il totale comprende
totalFeePsp: di commissione, applicata da {{pspName}}
info:
title: Informazioni sulla transazione
pspName: Gestore della transazione (PSP)
dateAndHour: Data e ora
transactionId: ID transazione
operation:
amount: Importo
creditor: Ente creditore
debtor: Debitore
iuv: IUV
16 changes: 16 additions & 0 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3788,3 +3788,19 @@ fastLogin:
description: a ogni nuovo accesso con SPID o CIE, ti invieremo un’email.
whatsNew:
title: Cosa cambia?
transaction:
details:
title: Dettaglio operazione
totalAmount: Totale
totalFee: Il totale comprende
totalFeePsp: di commissione, applicata da {{pspName}}
info:
title: Informazioni sulla transazione
pspName: Gestore della transazione (PSP)
dateAndHour: Data e ora
transactionId: ID transazione
operation:
amount: Importo
creditor: Ente creditore
debtor: Debitore
iuv: IUV
3 changes: 3 additions & 0 deletions ts/features/walletV3/common/saga/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { isPagoPATestEnabledSelector } from "../../../../store/reducers/persiste
import { createWalletClient } from "../api/client";
import { watchWalletOnboardingSaga } from "../../onboarding/saga";
import { watchWalletDetailsSaga } from "../../details/saga";
import { watchWalletTransactionSaga } from "../../transaction/saga";

export function* watchWalletV3Saga(bpdToken: string): SagaIterator {
const isPagoPATestEnabled = yield* select(isPagoPATestEnabledSelector);
Expand All @@ -23,4 +24,6 @@ export function* watchWalletV3Saga(bpdToken: string): SagaIterator {
yield* fork(watchWalletOnboardingSaga, client, token);

yield* fork(watchWalletDetailsSaga, client, token);

yield* fork(watchWalletTransactionSaga, client, token);
}
6 changes: 5 additions & 1 deletion ts/features/walletV3/common/store/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { WalletDetailsActions } from "../../../details/store/actions";
import { WalletOnboardingActions } from "../../../onboarding/store/actions";
import { WalletTransactionActions } from "../../../transaction/store/actions";

export type WalletV3Actions = WalletOnboardingActions | WalletDetailsActions;
export type WalletV3Actions =
| WalletOnboardingActions
| WalletDetailsActions
| WalletTransactionActions;
7 changes: 6 additions & 1 deletion ts/features/walletV3/common/store/reducers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@ import walletOnboardingReducer, {
import walletDetailsReducer, {
WalletDetailsState
} from "../../../details/store";
import walletTransactionReducer, {
WalletTransactionState
} from "../../../transaction/store";

export type WalletV3State = {
onboarding: WalletOnboardingState;
details: WalletDetailsState;
transaction: WalletTransactionState;
};

const walletV3Reducer = combineReducers({
onboarding: walletOnboardingReducer,
details: walletDetailsReducer
details: walletDetailsReducer,
transaction: walletTransactionReducer
});

export default walletV3Reducer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from "react";
import { pipe } from "fp-ts/lib/function";
import * as O from "fp-ts/lib/Option";
import { View } from "react-native";
import Placeholder from "rn-placeholder";
import {
HSpacer,
IOStyles,
ListItemTransaction,
VSpacer
} from "@pagopa/io-app-design-system";
import { Transaction } from "../../../../types/pagopa";
import { formatNumberCentsToAmount } from "../../../../utils/stringBuilder";
import { Dettaglio } from "../../../../../definitions/pagopa/Dettaglio";
import {
cleanTransactionDescription,
getTransactionIUV
} from "../../../../utils/payment";

type Props =
| {
transaction?: Transaction | null;
loading: boolean;
onPress: (operationDetails: Dettaglio) => void;
}
| {
transaction?: Transaction | null;
loading: true;
onPress: (operationDetails: Dettaglio) => void;
};
Hantex9 marked this conversation as resolved.
Show resolved Hide resolved

/**
* This component renders a list of transaction details which currently is just a single item
* TODO: Using the actual information, this component is already arranged to handle a list that will be implemented from the BIZ Event implementation (https://pagopa.atlassian.net/browse/IOBP-440)
*/
export const WalletTransactionDetailsList = ({
transaction,
loading,
onPress
}: Props) => {
if (loading) {
return <SkeletonTransactionDetailsList />;
}
if (!transaction) {
return <></>;
}

const operationDetails: Dettaglio = {
importo: transaction.amount.amount,
enteBeneficiario: transaction.merchant,
IUV: pipe(getTransactionIUV(transaction.description), O.toUndefined)
};
forrest57 marked this conversation as resolved.
Show resolved Hide resolved

return (
<ListItemTransaction
title={cleanTransactionDescription(transaction.description)}
subtitle={transaction.merchant}
transactionStatus="success"
transactionAmount={formatNumberCentsToAmount(
transaction.amount.amount,
true,
"right"
)}
hasChevronRight
onPress={() => onPress?.(operationDetails)}
/>
);
};

const SkeletonTransactionDetailsList = () => (
<View style={[IOStyles.flex, IOStyles.rowSpaceBetween, IOStyles.alignCenter]}>
<View style={[IOStyles.flex, { paddingVertical: 12 }]}>
<Placeholder.Box height={16} width="90%" radius={4} />
<VSpacer size={8} />
<Placeholder.Box height={16} width="30%" radius={4} />
</View>
<Placeholder.Box height={16} width={48} radius={4} />
<HSpacer size={16} />
<Placeholder.Box height={16} width={16} radius={4} />
</View>
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { useNavigation } from "@react-navigation/native";
import Placeholder from "rn-placeholder";
import React from "react";
import { View } from "react-native";
import { Body, H1, IOStyles, VSpacer } from "@pagopa/io-app-design-system";
import { Psp, Transaction } from "../../../../types/pagopa";
import { Dettaglio } from "../../../../../definitions/pagopa/Dettaglio";
import { formatNumberCentsToAmount } from "../../../../utils/stringBuilder";
import I18n from "../../../../i18n";
import {
WalletTransactionRoutes,
WalletTransactionStackNavigation
} from "../navigation/navigator";

import { WalletTransactionTotalAmount } from "./WalletTransactionTotalAmount";
import { WalletTransactionDetailsList } from "./WalletTransactionDetailsList";

type Props = {
transaction?: Transaction | null;
psp?: Psp;
loading: boolean;
};

export const WalletTransactionHeadingSection = ({
transaction,
psp,
loading
}: Props) => {
const navigation = useNavigation<WalletTransactionStackNavigation>();

const handlePressTransactionDetails = (operationDetails: Dettaglio) => {
if (transaction) {
navigation.navigate(
WalletTransactionRoutes.WALLET_TRANSACTION_OPERATION_DETAILS,
{
operationDetails,
operationName: transaction?.description
Hantex9 marked this conversation as resolved.
Show resolved Hide resolved
}
);
}
};

const FeeAmountSection = () => {
if (psp && transaction && transaction.fee && !loading) {
Hantex9 marked this conversation as resolved.
Show resolved Hide resolved
const formattedFee = formatNumberCentsToAmount(
transaction.fee.amount,
true,
"right"
);
return (
<Body>
{I18n.t("transaction.details.totalFee")}{" "}
<Body weight="Medium">{formattedFee}</Body>{" "}
{I18n.t("transaction.details.totalFeePsp", {
pspName: psp.businessName || ""
Hantex9 marked this conversation as resolved.
Show resolved Hide resolved
})}
.
</Body>
);
}
if (loading) {
return (
<View style={IOStyles.flex}>
<VSpacer size={4} />
<Placeholder.Line width="100%" animate="fade" />
<VSpacer size={8} />
<Placeholder.Line width="50%" animate="fade" />
</View>
);
}
return <></>;
};

return (
<View
style={[
IOStyles.horizontalContentPadding,
IOStyles.flex,
IOStyles.bgWhite
]}
>
<H1>{I18n.t("transaction.details.title")}</H1>
<VSpacer size={16} />
<WalletTransactionDetailsList
transaction={transaction}
loading={loading}
onPress={handlePressTransactionDetails}
/>
<WalletTransactionTotalAmount
loading={loading}
totalAmount={transaction?.amount.amount}
/>
<VSpacer size={8} />
<FeeAmountSection />
<VSpacer size={8} />
</View>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/* eslint-disable functional/immutable-data */
import * as React from "react";
import { StyleSheet, View } from "react-native";
import Placeholder from "rn-placeholder";
import {
Divider,
IOColors,
IORadiusScale,
IOVisualCostants,
ListItemHeader,
ListItemInfo,
ListItemInfoCopy,
VSpacer
} from "@pagopa/io-app-design-system";
import { IOStyles } from "../../../../components/core/variables/IOStyles";
import I18n from "../../../../i18n";
import { Psp, Transaction } from "../../../../types/pagopa";
import { format } from "../../../../utils/dates";
import { clipboardSetStringWithFeedback } from "../../../../utils/clipboard";
import TransactionReceiptDivider from "../../../../../img/features/wallet/transaction-receipt-divider.svg";

type WalletTransactionInfoSectionProps = {
transaction?: Transaction | null;
Hantex9 marked this conversation as resolved.
Show resolved Hide resolved
psp?: Psp;
loading?: boolean;
};

const styles = StyleSheet.create({
container: {
backgroundColor: IOColors["grey-50"]
},
contentCard: {
borderRadius: IORadiusScale["1"],
marginVertical: IOVisualCostants.appMarginDefault
}
});

/**
* Component that shows a success message after the wallet onboarding process is completed
* TODO: Define the desired design of this component
*/
const WalletTransactionInfoSection = ({
transaction,
psp,
loading
}: WalletTransactionInfoSectionProps) => (
<>
<TransactionReceiptDivider
height={24}
width={"100%"}
preserveAspectRatio="xMin slice" // Add this property to fit the width to the parent
/>
<View
style={[
IOStyles.horizontalContentPadding,
styles.container,
IOStyles.flex
Hantex9 marked this conversation as resolved.
Show resolved Hide resolved
]}
>
<View
style={[
styles.contentCard,
IOStyles.horizontalContentPadding,
IOStyles.bgWhite
]}
Hantex9 marked this conversation as resolved.
Show resolved Hide resolved
>
<ListItemHeader
label={I18n.t("transaction.details.info.title")}
accessibilityLabel={I18n.t("transaction.details.info.title")}
/>
{loading && (
<>
<SkeletonItem />
<Divider />
<SkeletonItem />
<Divider />
<SkeletonItem />
</>
)}
{!loading && transaction && (
<>
{psp?.businessName && (
<>
<ListItemInfo
accessibilityLabel={I18n.t(
"transaction.details.info.pspName"
)}
label={I18n.t("transaction.details.info.pspName")}
value={psp?.businessName}
Hantex9 marked this conversation as resolved.
Show resolved Hide resolved
/>
<Divider />
</>
)}
<ListItemInfo
accessibilityLabel={I18n.t(
"transaction.details.info.dateAndHour"
)}
label={I18n.t("transaction.details.info.dateAndHour")}
value={format(transaction.created, "DD MMMM YYYY, HH:mm:ss")}
/>
<Divider />
<ListItemInfoCopy
onPress={() =>
clipboardSetStringWithFeedback(transaction.id.toString())
}
accessibilityLabel={I18n.t(
"transaction.details.info.transactionId"
)}
label={I18n.t("transaction.details.info.transactionId")}
value={transaction.id.toString()}
/>
</>
)}
</View>
</View>
</>
);

const SkeletonItem = () => (
<View style={[IOStyles.flex, { paddingVertical: 12 }]}>
<Placeholder.Box height={16} width="80%" radius={4} />
<VSpacer size={8} />
<Placeholder.Box height={16} width="25%" radius={4} />
Hantex9 marked this conversation as resolved.
Show resolved Hide resolved
</View>
);

export default WalletTransactionInfoSection;
Loading
Loading