Skip to content

Commit

Permalink
Merge branch 'master' into IOBP-238-idpay-cie-onboarding-xstate-flow
Browse files Browse the repository at this point in the history
  • Loading branch information
forrest57 authored Sep 18, 2023
2 parents 0abaaa1 + 3703fa5 commit eff7814
Show file tree
Hide file tree
Showing 16 changed files with 466 additions and 119 deletions.
7 changes: 7 additions & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3151,11 +3151,14 @@ features:
error: "Si è verificato un errore con la tua richiesta"
details:
title: Dettaglio del messaggio
noticeCode: "Codice avviso"
loadError:
title: Qualcosa è andato storto
body: Non è stato possibile recuperare i dettagli del tuo messaggio. Riprova per favore
cancelledMessage:
body: "Questa notifica è stata annullata dall'ente mittente. Puoi ignorarne il contenuto."
unpaidPayments: "Per l'eventuale rimborso di pagamenti legati a questa notifica, contatta l'ente mittente."
payments: "Pagamenti"
paymentSection:
title: Avviso di pagamento
attachmentsSection:
Expand Down Expand Up @@ -3747,6 +3750,10 @@ unsupportedDevice:
fastLogin:
userInteraction:
sessionExpired:
noPin:
title: Too much time has passed!
subtitle: For security reasons, you must authenticate again with SPID or CIE. You can then resume IO configuration from where you left off.
submitButtonTitle: Continue
continueNavigation:
title: "La tua sessione è scaduta"
subtitle: "Per continuare a utilizzare l’app premi su Continua la navigazione."
Expand Down
9 changes: 8 additions & 1 deletion locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3175,11 +3175,14 @@ features:
error: "Si è verificato un errore con la tua richiesta"
details:
title: Dettaglio del messaggio
noticeCode: "Codice avviso"
loadError:
title: Qualcosa è andato storto
body: Non è stato possibile recuperare i dettagli del tuo messaggio. Riprova per favore
cancelledMessage:
body: "Questa notifica è stata annullata dall'ente mittente. Puoi ignorarne il contenuto."
unpaidPayments: "Per l'eventuale rimborso di pagamenti legati a questa notifica, contatta l'ente mittente."
payments: "Pagamenti"
paymentSection:
title: Avviso di pagamento
attachmentsSection:
Expand Down Expand Up @@ -3770,7 +3773,11 @@ unsupportedDevice:
faq: "Come mai?"
fastLogin:
userInteraction:
sessionExpired:
sessionExpired:
noPin:
title: È passato troppo tempo!
subtitle: Per ragioni di sicurezza devi autenticarti di nuovo con SPID o CIE. Potrai poi continuare la configurazione di IO da dove l’avevi interrotta.
submitButtonTitle: Continua
continueNavigation:
title: "La tua sessione è scaduta"
subtitle: "Per continuare a utilizzare l’app premi su Continua la navigazione."
Expand Down
3 changes: 2 additions & 1 deletion ts/components/box/InfoBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type Props = {
iconColor?: IOColors;
iconSize?: IOIconSizeScale;
alignedCentral?: boolean;
testID?: string;
};

const styles = StyleSheet.create({
Expand Down Expand Up @@ -40,7 +41,7 @@ export const InfoBox: React.FunctionComponent<Props> = props => {
const iconSize = props.iconSize ?? ICON_SIZE;
const centralAlignment = props.alignedCentral ? styles.alignedCentral : {};
return (
<View style={[styles.row, centralAlignment]}>
<View style={[styles.row, centralAlignment]} testID={props.testID}>
<View style={styles.icon}>
<Icon name={iconName} size={iconSize} color={iconColor} />
</View>
Expand Down
20 changes: 18 additions & 2 deletions ts/features/fastLogin/saga/tokenRefreshSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { readableReport } from "@pagopa/ts-commons/lib/reporters";
import { ValidationError } from "io-ts";
import { getType } from "typesafe-actions";
import { RequestResponseTypes } from "@pagopa/ts-commons/lib/requests";
import { sessionExpired } from "../../../store/actions/authentication";
import {
logoutRequest,
sessionExpired
} from "../../../store/actions/authentication";
import { SessionToken } from "../../../types/SessionToken";
import { startApplicationInitialization } from "../../../store/actions/application";
import {
Expand Down Expand Up @@ -40,8 +43,10 @@ import {
askUserToRefreshSessionToken,
showRefreshTokenLoader,
refreshSessionToken,
refreshTokenTransientError
refreshTokenTransientError,
refreshTokenNoPinError
} from "../store/actions";
import { getPin } from "../../../utils/keychain";

export function* watchTokenRefreshSaga(): SagaIterator {
yield* takeLatest(refreshSessionToken.request, handleRefreshSessionToken);
Expand All @@ -52,8 +57,19 @@ function* handleRefreshSessionToken(
typeof refreshSessionToken.request
>
) {
const isPinAvailable = O.isSome(yield* call(getPin));

const { withUserInteraction } = refreshSessionTokenRequestAction.payload;

if (!isPinAvailable) {
if (withUserInteraction) {
yield* put(refreshTokenNoPinError());
} else {
yield* put(logoutRequest());
}
return;
}

if (!withUserInteraction) {
yield* call(doRefreshTokenSaga, refreshSessionTokenRequestAction);
return;
Expand Down
99 changes: 99 additions & 0 deletions ts/features/fastLogin/screens/FastLoginModals.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import I18n from "i18n-js";
import React from "react";
import { useDispatch } from "react-redux";
import { TokenRefreshState } from "../store/reducers";
import { logoutRequest } from "../../../store/actions/authentication";
import { openWebUrl } from "../../../utils/url";
import { askUserToRefreshSessionToken } from "../store/actions";
import AskUserInteractionScreen from "./AskUserInterarctionScreen";
import RefreshTokenLoadingScreen from "./RefreshTokenLoadingScreen";

const FastLoginModals = (
tokenRefreshing: TokenRefreshState,
isFastLoginUserInteractionNeeded: boolean
) => {
const dispatch = useDispatch();

if (tokenRefreshing.kind === "no-pin-error") {
return (
<AskUserInteractionScreen
pictogramName="timeout"
title={I18n.t("fastLogin.userInteraction.sessionExpired.noPin.title")}
subtitle={I18n.t(
"fastLogin.userInteraction.sessionExpired.noPin.subtitle"
)}
onSubmit={() => {
dispatch(logoutRequest());
}}
buttonStylesProps={{
submitButtonStyle: {
type: "solid",
title: I18n.t(
"fastLogin.userInteraction.sessionExpired.noPin.submitButtonTitle"
)
}
}}
/>
);
}

if (tokenRefreshing.kind === "transient-error") {
return (
<AskUserInteractionScreen
pictogramName="umbrella"
title={I18n.t(
"fastLogin.userInteraction.sessionExpired.transientError.title"
)}
subtitle={I18n.t(
"fastLogin.userInteraction.sessionExpired.transientError.subtitle"
)}
onSubmit={() => {
// FIXME: update this URL once available
// https://pagopa.atlassian.net/browse/IOPID-393
openWebUrl("https://io.italia.it/faq");
}}
buttonStylesProps={{
submitButtonStyle: {
type: "solid",
title: I18n.t(
"fastLogin.userInteraction.sessionExpired.transientError.submitButtonTitle"
)
}
}}
/>
);
}

if (tokenRefreshing.kind === "in-progress") {
return <RefreshTokenLoadingScreen />;
}

if (isFastLoginUserInteractionNeeded) {
return (
<AskUserInteractionScreen
pictogramName="timeout"
title={I18n.t(
"fastLogin.userInteraction.sessionExpired.continueNavigation.title"
)}
subtitle={I18n.t(
"fastLogin.userInteraction.sessionExpired.continueNavigation.subtitle"
)}
onSubmit={() => {
dispatch(askUserToRefreshSessionToken.success("yes"));
}}
buttonStylesProps={{
submitButtonStyle: {
type: "solid",
title: I18n.t(
"fastLogin.userInteraction.sessionExpired.continueNavigation.submitButtonTitle"
)
}
}}
/>
);
}

return undefined;
};

export default FastLoginModals;
4 changes: 4 additions & 0 deletions ts/features/fastLogin/store/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export const refreshTokenTransientError = createStandardAction(
"REFRESHING_TOKEN_TRANSIENT_ERROR"
)<void>();

export const refreshTokenNoPinError = createStandardAction(
"REFRESHING_TOKEN_NO_PIN_ERROR"
)<void>();

export const clearTokenTransientError = createStandardAction(
"CLEAR_TOKEN_TRANSIENT_ERROR"
)<void>();
Expand Down
14 changes: 13 additions & 1 deletion ts/features/fastLogin/store/reducers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
clearPendingAction,
clearTokenTransientError,
refreshSessionToken,
refreshTokenNoPinError,
refreshTokenTransientError,
savePendingAction,
showRefreshTokenLoader
Expand Down Expand Up @@ -37,14 +38,20 @@ type TokenRefreshErrorState = {
type TokenRefreshTransientErrorState = {
kind: "transient-error";
};

type TokenRefreshNoPinErrorState = {
kind: "no-pin-error";
};

type TokenRefreshSuccessState = {
kind: "success";
timestamp: number;
};
type TokenRefreshState =
export type TokenRefreshState =
| TokenRefreshProgressState
| TokenRefreshErrorState
| TokenRefreshTransientErrorState
| TokenRefreshNoPinErrorState
| TokenRefreshSuccessState
| TokenRefreshIdleState;

Expand Down Expand Up @@ -109,6 +116,11 @@ export const fastLoginReducer = (
...state,
tokenRefresh: { kind: "transient-error" }
};
case getType(refreshTokenNoPinError):
return {
...state,
tokenRefresh: { kind: "no-pin-error" }
};
case getType(clearTokenTransientError):
return {
...state,
Expand Down
2 changes: 1 addition & 1 deletion ts/features/messages/components/MessageAttachments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ export const MessageAttachments = (props: Props): React.ReactElement | null =>
props.attachments.length > 0 ? (
<>
{props.attachments.map((attachment, index) => (
<View key={index}>
<View key={index} testID="MessageAttachmentContainer">
<AttachmentItem
attachment={attachment}
disabled={props.disabled}
Expand Down
51 changes: 19 additions & 32 deletions ts/features/pn/components/PnMessageDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ import { H5 } from "../../../components/core/typography/H5";
import FooterWithButtons from "../../../components/ui/FooterWithButtons";
import I18n from "../../../i18n";
import ROUTES from "../../../navigation/routes";
import {
TransactionSummary,
TransactionSummaryRow
} from "../../../screens/wallet/payment/components/TransactionSummary";
import { TransactionSummaryErrorDetails } from "../../../screens/wallet/payment/components/TransactionSummaryErrorDetails";
import { TransactionSummaryRow } from "../../../screens/wallet/payment/components/TransactionSummary";
import { TransactionSummaryStatus } from "../../../screens/wallet/payment/components/TransactionSummaryStatus";
import { TransactionSummaryError } from "../../../screens/wallet/payment/NewTransactionSummaryScreen";
import { paymentVerifica } from "../../../store/actions/wallet/payment";
Expand Down Expand Up @@ -51,6 +47,7 @@ import { PnMessageDetailsHeader } from "./PnMessageDetailsHeader";
import { PnMessageDetailsSection } from "./PnMessageDetailsSection";
import { PnMessageTimeline } from "./PnMessageTimeline";
import { PnMessageTimelineCTA } from "./PnMessageTimelineCTA";
import { PnMessagePayment } from "./PnMessagePayment";

const styles = StyleSheet.create({
content: {
Expand Down Expand Up @@ -79,11 +76,14 @@ export const PnMessageDetails = ({

const dispatch = useIODispatch();
const navigation = useNavigation();
const frontendUrl = useIOSelector(pnFrontendUrlSelector);

const viewRef = createRef<View>();
const frontendUrl = useIOSelector(pnFrontendUrlSelector);

const isCancelled = message.isCancelled ?? false;
const completedPaymentNoticeCode =
isCancelled && message.completedPayments
? message.completedPayments[0]
: undefined;

const paymentVerification = useIOSelector(
state => state.wallet.payment.verifica
Expand Down Expand Up @@ -143,12 +143,13 @@ export const PnMessageDetails = ({
trackPNPaymentInfoPaid();
} else if (O.isSome(paymentVerificationError)) {
trackPNPaymentInfoError(paymentVerificationError);
} else {
} else if (!isCancelled) {
trackPNPaymentInfoPayable();
}
setShouldTrackMixpanel(false);
}, [
firstLoadingRequest,
isCancelled,
isPaid,
isVerifyingPayment,
paymentVerificationError,
Expand Down Expand Up @@ -196,30 +197,16 @@ export const PnMessageDetails = ({
/>
</PnMessageDetailsSection>
)}
{payment && (
<PnMessageDetailsSection
title={I18n.t("features.pn.details.paymentSection.title")}
>
{firstLoadingRequest && (
<>
<TransactionSummary
paymentVerification={paymentVerification}
paymentNoticeNumber={payment.noticeCode}
organizationFiscalCode={payment.creditorTaxId}
isPaid={isPaid}
/>
{O.isSome(paymentVerificationError) && (
<TransactionSummaryErrorDetails
error={paymentVerificationError}
paymentNoticeNumber={payment.noticeCode}
organizationFiscalCode={payment.creditorTaxId}
messageId={messageId}
/>
)}
</>
)}
</PnMessageDetailsSection>
)}
<PnMessagePayment
messageId={messageId}
firstLoadingRequest={firstLoadingRequest}
isCancelled={isCancelled}
isPaid={isPaid}
payment={payment}
paymentVerification={paymentVerification}
paymentVerificationError={paymentVerificationError}
completedPaymentNoticeCode={completedPaymentNoticeCode}
/>
<PnMessageDetailsSection
title={I18n.t("features.pn.details.infoSection.title")}
>
Expand Down
3 changes: 2 additions & 1 deletion ts/features/pn/components/PnMessageDetailsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ const styles = StyleSheet.create({
type Props = Readonly<{
title?: string;
icon?: React.ReactNode;
testID?: string;
}>;

export const PnMessageDetailsSection = (
props: React.PropsWithChildren<Props>
): React.ReactElement | null => (
<View style={styles.container}>
<View style={styles.container} testID={props.testID}>
<View style={styles.header}>
{props.title && <H2 color="bluegrey">{props.title}</H2>}
{props.icon && <View style={styles.icon}>{props.icon}</View>}
Expand Down
Loading

0 comments on commit eff7814

Please sign in to comment.