Skip to content

Commit

Permalink
chore: [IOBP-368] Revamp wallet transaction detail page (#5282)
Browse files Browse the repository at this point in the history
## Short description
This PR integrates the revamp of the new wallet transaction detail page

## List of changes proposed in this pull request
- Added into `walletV3` feature folder structure the `transaction`
folder
- Added the redux flow and saga mock (that doesn't make a real API
request until we switch from actual PM to BIZ Event);
- Added two new screens: `WalletTransactionDetailsScreen` and
`WalletTransactionOperationDetailsScreen`
- Added Skeletons showing up while loading some API requests;
- Connected redux flow & sagas to the `walletV3` feature store;
- Added translation locales;
- Edited the current `navigateToTransactionDetailsScreen` redirecting to
the new screen;

## How to test
- Go into the transactions list from the wallet home;
- Select any transaction from the list;
- You should be able to see the new transaction screen;

## Revamp design

https://www.figma.com/file/SDaOSTsQnJUxmoPQEfz3bJ/Ricevuta-di-pagamento-pagoPA?type=design&node-id=520-10951&mode=design&t=KSENC2iM2XXGMJaT-4

## Preview
|Before|After|
|-|-|
| <video
src="https://github.com/pagopa/io-app/assets/34343582/a9b8d7c6-4e1b-408a-a4bd-3d64c0d36cf2"
/> |<video
src="https://github.com/pagopa/io-app/assets/34343582/cf17a14f-ed57-4796-93b5-dcf4c8d71b07"
/>

**NB:** In the new transaction preview video there is a 2-second forced
loading to show up skeletons to showcase how the loading page looks when
it is loading
  • Loading branch information
Hantex9 authored Dec 4, 2023
1 parent e3608af commit cfb18dd
Show file tree
Hide file tree
Showing 22 changed files with 869 additions and 16 deletions.
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.
17 changes: 17 additions & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3788,3 +3788,20 @@ 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
subject: Oggetto del pagamento
17 changes: 17 additions & 0 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3788,3 +3788,20 @@ 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
subject: Oggetto del pagamento
12 changes: 4 additions & 8 deletions ts/components/ui/RNavScreenWithLargeHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import {
H3,
HeaderSecondLevel,
IOVisualCostants
} from "@pagopa/io-app-design-system";
import { H2, HeaderSecondLevel, IOStyles } from "@pagopa/io-app-design-system";
import { useNavigation } from "@react-navigation/native";
import React, { ComponentProps, useLayoutEffect, useState } from "react";
import { LayoutChangeEvent, View } from "react-native";
Expand Down Expand Up @@ -79,16 +75,16 @@ export const RNavScreenWithLargeHeader = ({
<Animated.ScrollView
contentContainerStyle={{
paddingBottom: insets.bottom,
paddingHorizontal: IOVisualCostants.appMarginDefault
flexGrow: 1
}}
onScroll={scrollHandler}
scrollEventThrottle={8}
snapToOffsets={[0, titleHeight]}
snapToEnd={false}
decelerationRate="normal"
>
<View onLayout={getTitleHeight}>
<H3>{title}</H3>
<View style={IOStyles.horizontalContentPadding} onLayout={getTitleHeight}>
<H2>{title}</H2>
</View>
{children}
</Animated.ScrollView>
Expand Down
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,79 @@
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 {
Divider,
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;
};

/**
* 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)
};

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

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,93 @@
import { useNavigation } from "@react-navigation/native";
import Placeholder from "rn-placeholder";
import React from "react";
import { View } from "react-native";
import { Body, 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;
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,
operationSubject: transaction.description,
operationName: transaction.description
}
);
}
};

const FeeAmountSection = () => {
if (psp && transaction?.fee && !loading) {
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 || ""
})}
.
</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.bgWhite]}>
<VSpacer size={16} />
<WalletTransactionDetailsList
transaction={transaction}
loading={loading}
onPress={handlePressTransactionDetails}
/>
<VSpacer size={8} />
<WalletTransactionTotalAmount
loading={loading}
totalAmount={transaction?.grandTotal.amount}
/>
<VSpacer size={8} />
<FeeAmountSection />
<VSpacer size={8} />
</View>
);
};
Loading

0 comments on commit cfb18dd

Please sign in to comment.