Skip to content

Commit

Permalink
feat(IT Wallet): [SIW-214] Add PID to wallet (#4790)
Browse files Browse the repository at this point in the history
## Short description
This PR adds the PID credential to the wallet section, along with a
detail screen.
Most of the changes are tied to the PID and will be generalised in the
future.

## List of changes proposed in this pull request
- `locales/en/index.yml` & `locales/it/index.yml`: Adds locales;
- `ts/features/it-wallet/components/ClaimsList.tsx`: Adds the issuer
name to the claim list unrecognized data section;
- `ts/features/it-wallet/navigation/ItwStackNavigator.tsx`: Adds the new
details screen to the navigator;
- `ts/features/it-wallet/navigation/params.ts`: Adds the new details
screen params;
- `ts/features/it-wallet/navigation/routes.ts`: Adds the new
presentation routes;
- `ts/features/it-wallet/screens/ItwCredentialDetails.tsx`: Adds the VC
details screen (currently only for PID);
- `ts/features/it-wallet/screens/ItwHomeScreen.tsx`: Adds the PID card
to the wallet section;
- `ts/features/it-wallet/store/reducers/itwCredentials.ts`: Adds a
selector for VCs;

## How to test
Complete a PID issuing flow and check if the card gets renders in the
`Wallet` section. Then try to press it to navigate to the details
screen.

---------

Co-authored-by: Mario Perrotta <mario.perrotta@pagopa.it>
  • Loading branch information
LazyAfternoons and hevelius committed Jul 18, 2023
1 parent ccb3f33 commit a418542
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 20 deletions.
10 changes: 7 additions & 3 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3253,10 +3253,10 @@ features:
confirm: "Activate IT Wallet"
homeScreen:
categories:
any: "Tutto"
personal: "Personali"
any: "Any"
personal: "Personal"
cgn: "Carta giovani"
payments: "Metodi di pagamento"
payments: "Payments methods"
infoAuthScreen:
title: "Log in with CIE + PIN and save your digital identity"
subTitle: "To activate IT Wallet you need to authenticate yourself using your Electronic Identity Card (CIE) + PIN."
Expand Down Expand Up @@ -3297,6 +3297,10 @@ features:
title: "Done! your IT Wallet is active on IO!"
content: "Now you can use IO to access the digital services of the Public Administration and obtain new digital credentials."
button: "Continue"
presentation:
credentialDetails:
buttons:
qrCode: "Show QR code"
verifiableCredentials:
type:
digitalCredential: "Digital Credential"
Expand Down
4 changes: 4 additions & 0 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3321,6 +3321,10 @@ features:
title: "Fatto! il tuo IT Wallet è attivo su IO!"
content: "Ora puoi usare IO per accedere ai servizi digitali della Pubblica Amministrazione e ottenere nuove credenziali digitali."
button: "Continua"
presentation:
credentialDetails:
buttons:
qrCode: "Mostra QR code"
verifiableCredentials:
type:
digitalCredential: "Identità Digitale"
Expand Down
7 changes: 6 additions & 1 deletion ts/features/it-wallet/components/ClaimsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,12 @@ const ClaimsList = ({ claims }: ClaimsListProps) => {
<VSpacer />
<H4 weight={"Regular"} color={"bluegrey"}>
{I18n.t(
"features.itWallet.verifiableCredentials.unrecognizedData.body"
"features.itWallet.verifiableCredentials.unrecognizedData.body",
{
issuer:
claims.verified_claims.verification.evidence[0].record.source
.organization_name
}
)}
</H4>
<VSpacer />
Expand Down
5 changes: 5 additions & 0 deletions ts/features/it-wallet/navigation/ItwStackNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import ItwActivationDetailsScreen from "../screens/discovery/ItwActivationDetail
import ItwActivationInfoAuthScreen from "../screens/issuing/ItwActivationInfoAuthScreen";
import PidPreviewScreen from "../screens/issuing/PidPreviewScreen";
import PidActivationScreen from "../screens/issuing/PidActivationScreen";
import ItwCredentialDetails from "../screens/ItwCredentialDetails";
import { ItwParamsList } from "./params";
import { ITW_ROUTES } from "./routes";

Expand Down Expand Up @@ -56,5 +57,9 @@ export const ItwStackNavigator = () => (
name={ITW_ROUTES.ACTIVATION.CIE_WRONG_PIN_SCREEN}
component={CieWrongCiePinScreen}
/>
<Stack.Screen
name={ITW_ROUTES.PRESENTATION.VC_DETAILS}
component={ItwCredentialDetails}
/>
</Stack.Navigator>
);
1 change: 1 addition & 0 deletions ts/features/it-wallet/navigation/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ export type ItwParamsList = {
[ITW_ROUTES.ACTIVATION
.CIE_WRONG_PIN_SCREEN]: CieWrongCiePinScreenNavigationParams;
[ITW_ROUTES.ACTIVATION.CIE_PIN_TEMP_LOCKED_SCREEN]: undefined;
[ITW_ROUTES.PRESENTATION.VC_DETAILS]: undefined;
};
3 changes: 3 additions & 0 deletions ts/features/it-wallet/navigation/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,8 @@ export const ITW_ROUTES = {
CIE_CONSENT_DATA_USAGE: "ITW_CIE_CONSENT_DATA_USAGE",
CIE_WRONG_PIN_SCREEN: "ITW_CIE_WRONG_PIN_SCREEN",
CIE_PIN_TEMP_LOCKED_SCREEN: "ITW_CIE_PIN_TEMP_LOCKED_SCREEN"
} as const,
PRESENTATION: {
VC_DETAILS: "ITW_PRESENTATION_VC_DETAILS"
} as const
} as const;
63 changes: 63 additions & 0 deletions ts/features/it-wallet/screens/ItwCredentialDetails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from "react";
import { View } from "native-base";
import { SafeAreaView, ScrollView } from "react-native";
import FooterWithButtons from "../../../components/ui/FooterWithButtons";
import I18n from "../../../i18n";
import BaseScreenComponent from "../../../components/screens/BaseScreenComponent";
import { emptyContextualHelp } from "../../../utils/emptyContextualHelp";
import { IOStyles } from "../../../components/core/variables/IOStyles";
import { VSpacer } from "../../../components/core/spacer/Spacer";
import PidCredential from "../components/PidCredential";
import ClaimsList from "../components/ClaimsList";
import { useIOSelector } from "../../../store/hooks";
import { ItwWalletVcsSelector } from "../store/reducers/itwCredentials";

/**
* Renders a preview screen which displays a visual representation and the claims contained in the PID.
* This screen should be generalized for any verifiable crediential but for now it's only used for the PID.
*/
const ItwCredentialDetails = () => {
const pid = useIOSelector(ItwWalletVcsSelector)[0];
const clamis = pid.verified_claims.claims;
const spacerSize = 32;

const presentationButton = {
title: I18n.t(
"features.itWallet.presentation.credentialDetails.buttons.qrCode"
),
iconName: "io-qr",
iconColor: "white",
onPress: () => null
};

return (
<BaseScreenComponent
goBack={true}
headerTitle={I18n.t(
"features.itWallet.verifiableCredentials.type.digitalCredential"
)}
contextualHelp={emptyContextualHelp}
>
<SafeAreaView style={{ ...IOStyles.flex }}>
<ScrollView>
<VSpacer />
<View style={IOStyles.horizontalContentPadding}>
<PidCredential
name={`${clamis.given_name} ${clamis.family_name}`}
fiscalCode={clamis.tax_id_number}
/>
<VSpacer />
<ClaimsList claims={pid} />
<VSpacer size={spacerSize} />
</View>
</ScrollView>
<FooterWithButtons
type={"SingleButton"}
leftButton={presentationButton}
/>
</SafeAreaView>
</BaseScreenComponent>
);
};

export default ItwCredentialDetails;
59 changes: 45 additions & 14 deletions ts/features/it-wallet/screens/ItwHomeScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import { useNavigation } from "@react-navigation/native";
import { ScrollView, View } from "react-native";
import { Pressable, ScrollView, View } from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import TopScreenComponent from "../../../components/screens/TopScreenComponent";
import ROUTES from "../../../navigation/routes";
Expand All @@ -10,7 +10,13 @@ import { ItwActionBanner } from "../components/ItwActionBanner";
import { IOStyles } from "../../../components/core/variables/IOStyles";
import BadgeButton from "../components/design/BadgeButton";
import { useIOSelector } from "../../../store/hooks";
import { ItwWalletActivatedSelector } from "../store/reducers/itwCredentials";
import {
ItwWalletActivatedSelector,
ItwWalletVcsSelector
} from "../store/reducers/itwCredentials";
import PidCredential from "../components/PidCredential";
import { VSpacer } from "../../../components/core/spacer/Spacer";
import { ITW_ROUTES } from "../navigation/routes";

const contextualHelpMarkdown: ContextualHelpPropsMarkdown = {
title: "wallet.contextualHelpTitle",
Expand All @@ -23,6 +29,7 @@ const ItwHomeScreen = () => {
const navigation = useNavigation();
const isWalletActive = useIOSelector(ItwWalletActivatedSelector);
const [selectedBadgeIdx, setSelectedBadgeIdx] = useState(0);
const pid = useIOSelector(ItwWalletVcsSelector);
const badgesLabels = [
I18n.t("features.itWallet.homeScreen.categories.any"),
I18n.t("features.itWallet.homeScreen.categories.personal"),
Expand Down Expand Up @@ -60,18 +67,42 @@ const ItwHomeScreen = () => {
/>
))}
</ScrollView>
{!isWalletActive && (
<ItwActionBanner
title={I18n.t("features.itWallet.innerActionBanner.title")}
content={I18n.t(
"features.itWallet.innerActionBanner.description"
)}
action={I18n.t("features.itWallet.innerActionBanner.action")}
labelClose={I18n.t(
"features.itWallet.innerActionBanner.hideLabel"
)}
/>
)}
</View>
<View
style={{ ...IOStyles.flex, ...IOStyles.horizontalContentPadding }}
>
<ScrollView style={{ flex: 1 }}>
{!isWalletActive ? (
<ItwActionBanner
title={I18n.t("features.itWallet.innerActionBanner.title")}
content={I18n.t(
"features.itWallet.innerActionBanner.description"
)}
action={I18n.t("features.itWallet.innerActionBanner.action")}
labelClose={I18n.t(
"features.itWallet.innerActionBanner.hideLabel"
)}
/>
) : (selectedBadgeIdx === 0 || selectedBadgeIdx === 1) && pid ? (
<>
<VSpacer />
<Pressable
onPress={() =>
navigation.navigate(ITW_ROUTES.MAIN, {
screen: ITW_ROUTES.PRESENTATION.VC_DETAILS
})
}
>
<PidCredential
name={`${pid[0].verified_claims.claims.given_name} ${pid[0].verified_claims.claims.family_name}`}
fiscalCode={pid[0].verified_claims.claims.tax_id_number}
/>
</Pressable>
</>
) : (
<></>
)}
</ScrollView>
</View>
</TopScreenComponent>
</SafeAreaView>
Expand Down
6 changes: 4 additions & 2 deletions ts/features/it-wallet/screens/issuing/PidPreviewScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { useItwAbortFlow } from "../../hooks/useItwAbortFlow";
import { ITW_ROUTES } from "../../navigation/routes";
import { useOnFirstRender } from "../../../../utils/hooks/useOnFirstRender";
import ItwLoadingSpinnerOverlay from "../../components/ItwLoadingSpinnerOverlay";
import { ItwParamsList } from "../../navigation/params";
import { IOStackNavigationProp } from "../../../../navigation/params/AppParamsList";

/**
* Renders a preview screen which displays a visual representation and the claims contained in the PID.
Expand All @@ -25,7 +27,7 @@ const PidPreviewScreen = () => {
const spacerSize = 32;
const pidMock = getPidMock();
const { present, bottomSheet } = useItwAbortFlow();
const navigation = useNavigation();
const navigation = useNavigation<IOStackNavigationProp<ItwParamsList>>();
const [isLoading, setIsLoading] = useState(true);

/**
Expand All @@ -48,7 +50,7 @@ const PidPreviewScreen = () => {
primary: true,
onPress: () =>
navigation.navigate(ITW_ROUTES.ACTIVATION.PID_ISSUING, {
vc: pidMock
pid: pidMock
}),
title: I18n.t("features.itWallet.issuing.pidPreviewScreen.buttons.add")
};
Expand Down
21 changes: 21 additions & 0 deletions ts/features/it-wallet/store/reducers/itwCredentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,34 @@ const reducer = (
return state;
};

/**
* Selects the itwallet state from the global state.
* @param state - the global state
* @returns the itwallet state.
*/
export const ItwWalletSelector = (state: GlobalState) =>
state.features.itWallet.wallet;

/**
* Selects the itwallet activated flag from the global state.
* @param state - the global state
* @returns the itwallet activated flag.
*/
export const ItwWalletActivatedSelector = (state: GlobalState) =>
pot.getOrElse(
pot.map(state.features.itWallet.wallet, w => w.activated),
false
);

/**
* Selects the itwallet vcs from the global state.
* @param state - the global state
* @returns the itwallet vcs flag.
*/
export const ItwWalletVcsSelector = (state: GlobalState) =>
pot.getOrElse(
pot.map(state.features.itWallet.wallet, w => w.vcs),
[]
);

export default reducer;

0 comments on commit a418542

Please sign in to comment.