Skip to content

Commit

Permalink
chore: [IOPLT-516] Add CTA to enroll to a trial on Profile section (#…
Browse files Browse the repository at this point in the history
…5794)

> [!warning]
> This PR depends on #5777 

## Short description
This PR aims to add a new screen with CTA to handle the loading status
of a specific trial under profile section

## List of changes proposed in this pull request
- Adds the TrialSystemPlayground under Playground section of
Profile/DeveloperSection

## How to test
Try to start the subscription by using this PR code on dev-server
pagopa/io-dev-api-server#378

---------

Co-authored-by: Mario Perrotta <[email protected]>
  • Loading branch information
CrisTofani and hevelius authored Jun 27, 2024
1 parent 5538ed0 commit 469e872
Show file tree
Hide file tree
Showing 12 changed files with 191 additions and 4 deletions.
5 changes: 5 additions & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,8 @@ profile:
title: Warning
message: To add a new test card, you must enable the pagoPA test environment from the settings.
closeButton: Close
trial:
titleSection: Join a trial
itWallet:
itWalletTest: IT Wallet
itWalletTestDescription: Enable the IT Wallet test environment
Expand Down Expand Up @@ -3275,6 +3277,9 @@ features:
requestAssistance: "Something wrong? Contact {{authSource}}"
showClaimValues: "Show claim values"
hideClaimValues: "Hide claim values"
trialSystem:
toast:
subscribed: Done! You will receive a message when the trial period will begin.
webView:
error:
missingParams: Not all information necessary to access this page are available
Expand Down
5 changes: 5 additions & 0 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,8 @@ profile:
title: Attenzione
message: Per aggiungere una nuova carta di test, devi abilitare l'ambiente pagoPA di test dalle impostazioni.
closeButton: Chiudi
trial:
titleSection: Partecipa alla sperimentazione
itWallet:
itWalletTest: IT Wallet
itWalletTestDescription: Abilita ambiente di test per IT Wallet
Expand Down Expand Up @@ -3275,6 +3277,9 @@ features:
requestAssistance: "Qualcosa non torna? Contatta {{authSource}}"
showClaimValues: "Mostra gli attributi del documento"
hideClaimValues: "Nascondi gli attributi del documento"
trialSystem:
toast:
subscribed: Fatto! Riceverai un messaggio all’avvio della sperimentazione
webView:
error:
missingParams: Non sono presenti le informazioni necessarie per accedere a questa pagina
Expand Down
1 change: 1 addition & 0 deletions ts/features/trialSystem/api/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { defaultRetryingFetch } from "../../../utils/fetch";
export const createTrialSystemClient = (baseUrl: string, token: SessionToken) =>
createClient<"Bearer">({
baseUrl,
basePath: "/api/v1",
fetchApi: defaultRetryingFetch(),
withDefaults: op => params =>
op({
Expand Down
11 changes: 10 additions & 1 deletion ts/features/trialSystem/store/actions/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { ActionType, createAsyncAction } from "typesafe-actions";
import {
ActionType,
createAsyncAction,
createStandardAction
} from "typesafe-actions";
import { TrialId } from "../../../../../definitions/trial_systwem/TrialId";
import { Subscription } from "../../../../../definitions/trial_systwem/Subscription";

Expand All @@ -19,6 +23,11 @@ export const trialSystemActivationStatus = createAsyncAction(
"TRIAL_SYSTEM_ACTIVATION_STATUS_FAILURE"
)<TrialId, Subscription, ErrorPayload>();

export const trialSystemActivationStatusReset = createStandardAction(
"TRIAL_SYSTEM_ACTIVATION_STATUS_RESET"
)<TrialId>();

export type TrialSystemActions =
| ActionType<typeof trialSystemActivationStatusUpsert>
| ActionType<typeof trialSystemActivationStatusReset>
| ActionType<typeof trialSystemActivationStatus>;
41 changes: 40 additions & 1 deletion ts/features/trialSystem/store/reducers/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as pot from "@pagopa/ts-commons/lib/pot";
import { getType } from "typesafe-actions";
import { pipe } from "fp-ts/lib/function";
import { TrialId } from "../../../../../definitions/trial_systwem/TrialId";
import {
SubscriptionState,
Expand All @@ -8,8 +9,10 @@ import {
import { Action } from "../../../../store/actions/types";
import {
trialSystemActivationStatus,
trialSystemActivationStatusReset,
trialSystemActivationStatusUpsert
} from "../actions";
import { GlobalState } from "../../../../store/reducers/types";

export type TrialSystemState = Record<
TrialId,
Expand Down Expand Up @@ -39,6 +42,11 @@ export const trialSystemActivationStatusReducer = (
...state,
[action.payload.trialId]: pot.some(action.payload.state)
};
case getType(trialSystemActivationStatusReset):
return {
...state,
[action.payload]: pot.none
};
case getType(trialSystemActivationStatusUpsert.failure):
case getType(trialSystemActivationStatus.failure):
return {
Expand All @@ -63,7 +71,38 @@ export const trialSystemActivationStatusReducer = (
}
};

const isStateActive = (status: pot.Pot<SubscriptionState, Error>) =>
const isStateActive = (status: pot.Pot<SubscriptionState, Error> | undefined) =>
status &&
pot.isSome(status) &&
(status.value === SubscriptionStateEnum.ACTIVE ||
status.value === SubscriptionStateEnum.SUBSCRIBED);

export const trialSystemActivationStatusSelector = (
state: GlobalState
): TrialSystemState => state.trialSystem;

export const trialStatusSelector = (id: TrialId) => (state: GlobalState) =>
pipe(
state,
trialSystemActivationStatusSelector,
status => status[id] ?? pot.none,
pot.toUndefined
);

export const isLoadingTrialStatusSelector =
(id: TrialId) => (state: GlobalState) =>
pipe(
state,
trialSystemActivationStatusSelector,
status => status[id] ?? pot.none,
pot.isLoading
);

export const isUpdatingTrialStatusSelector =
(id: TrialId) => (state: GlobalState) =>
pipe(
state,
trialSystemActivationStatusSelector,
status => status[id] ?? pot.none,
pot.isUpdating
);
Empty file.
17 changes: 16 additions & 1 deletion ts/features/trialSystem/store/sagas/watchTrialSystemSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@ import { SagaIterator } from "redux-saga";
import { call, put, takeLatest } from "typed-redux-saga/macro";
import { ActionType } from "typesafe-actions";
import { readableReport } from "@pagopa/ts-commons/lib/reporters";
import { IOToast } from "@pagopa/io-app-design-system";
import { SessionToken } from "../../../../types/SessionToken";
import { TrialSystemClient, createTrialSystemClient } from "../../api/client";
import { apiUrlPrefix } from "../../../../config";
import {
trialSystemActivationStatus,
trialSystemActivationStatusReset,
trialSystemActivationStatusUpsert
} from "../actions";
import { getError } from "../../../../utils/errors";
import I18n from "../../../../i18n";

function* handleTrialSystemActivationStatusUpsert(
upsertTrialSystemActivationStatus: TrialSystemClient["createSubscription"],
Expand All @@ -30,13 +33,15 @@ function* handleTrialSystemActivationStatusUpsert(
);
} else if (result.right.status === 201) {
yield* put(trialSystemActivationStatusUpsert.success(result.right.value));
IOToast.success(I18n.t("features.trialSystem.toast.subscribed"));
} else {
yield* put(
trialSystemActivationStatusUpsert.failure({
trialId: action.payload,
error: new Error(`response status ${result.right.status}`)
})
);
IOToast.error(I18n.t("global.genericError"));
}
} catch (e) {
yield* put(
Expand All @@ -45,6 +50,7 @@ function* handleTrialSystemActivationStatusUpsert(
error: getError(e)
})
);
IOToast.error(I18n.t("global.genericError"));
}
}

Expand All @@ -64,8 +70,17 @@ function* handleTrialSystemActivationStatus(
error: new Error(readableReport(result.left))
})
);
} else if (result.right.status === 200) {
return;
}

if (result.right.status === 200) {
yield* put(trialSystemActivationStatus.success(result.right.value));
return;
}

if (result.right.status === 404) {
yield* put(trialSystemActivationStatusReset(action.payload));
return;
} else {
yield* put(
trialSystemActivationStatus.failure({
Expand Down
5 changes: 5 additions & 0 deletions ts/navigation/ProfileNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import IdPayOnboardingPlayground from "../screens/profile/playgrounds/IdPayOnboa
import ItwPlayground from "../screens/profile/playgrounds/ItwPlayground";
import MarkdownPlayground from "../screens/profile/playgrounds/MarkdownPlayground";
import { isGestureEnabled } from "../utils/navigation";
import TrialSystemPlayground from "../screens/profile/TrialSystemPlayground";
import { ProfileParamsList } from "./params/ProfileParamsList";
import ROUTES from "./routes";

Expand Down Expand Up @@ -123,6 +124,10 @@ const ProfileStackNavigator = () => (
name={ROUTES.CGN_LANDING_PLAYGROUND}
component={CgnLandingPlayground}
/>
<Stack.Screen
name={ROUTES.TRIALS_SYSTEM_PLAYGROUND}
component={TrialSystemPlayground}
/>
<Stack.Screen
options={{
headerShown: false
Expand Down
1 change: 1 addition & 0 deletions ts/navigation/params/ProfileParamsList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export type ProfileParamsList = {
[ROUTES.PROFILE_REMOVE_ACCOUNT_DETAILS]: undefined;
[ROUTES.PROFILE_REMOVE_ACCOUNT_SUCCESS]: undefined;
[ROUTES.CGN_LANDING_PLAYGROUND]: undefined;
[ROUTES.TRIALS_SYSTEM_PLAYGROUND]: undefined;
[ROUTES.PROFILE_PREFERENCES_NOTIFICATIONS]: undefined;
[ROUTES.IDPAY_ONBOARDING_PLAYGROUND]: undefined;
[ROUTES.IDPAY_CODE_PLAYGROUND]: undefined;
Expand Down
1 change: 1 addition & 0 deletions ts/navigation/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ const ROUTES = {
// Developer Mode
DESIGN_SYSTEM: "DESIGN_SYSTEM",
CGN_LANDING_PLAYGROUND: "CGN_LANDING_PLAYGROUND",
TRIALS_SYSTEM_PLAYGROUND: "TRIAL_SYSTEM_PLAYGROUND",
IDPAY_ONBOARDING_PLAYGROUND: "IDPAY_ONBOARDING_PLAYGROUND",
LOLLIPOP_PLAYGROUND: "LOLLIPOP_PLAYGROUND",
IDPAY_CODE_PLAYGROUND: "IDPAY_CODE_PLAYGROUND",
Expand Down
10 changes: 9 additions & 1 deletion ts/screens/profile/DeveloperModeSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import {
useIOThemeContext
} from "@pagopa/io-app-design-system";
import AsyncStorage from "@react-native-async-storage/async-storage";
import I18n from "i18n-js";
import * as React from "react";
import { ComponentProps } from "react";
import { Alert, FlatList, ListRenderItemInfo } from "react-native";
import I18n from "../../i18n";
import { AlertModal } from "../../components/ui/AlertModal";
import { LightModalContext } from "../../components/ui/LightModal";
import { isPlaygroundsEnabled } from "../../config";
Expand Down Expand Up @@ -374,6 +374,13 @@ const PlaygroundsSection = () => {
screen: ROUTES.CGN_LANDING_PLAYGROUND
})
},
{
value: I18n.t("profile.main.trial.titleSection"),
onPress: () =>
navigation.navigate(ROUTES.PROFILE_NAVIGATOR, {
screen: ROUTES.TRIALS_SYSTEM_PLAYGROUND
})
},
{
condition: isIdPayTestEnabled,
value: "IDPay Onboarding",
Expand Down Expand Up @@ -557,6 +564,7 @@ const DeveloperTestEnvironmentSection = ({
value={isItWalletTestEnabled}
onSwitchValueChange={onItWalletTestToggle}
/>
<Divider />
</ContentWrapper>
);
};
Expand Down
98 changes: 98 additions & 0 deletions ts/screens/profile/TrialSystemPlayground.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import {
Body,
ButtonSolid,
ContentWrapper,
H3,
VSpacer
} from "@pagopa/io-app-design-system";
import * as React from "react";
import { SafeAreaView, StyleSheet, View } from "react-native";
import { useEffect } from "react";
import { constNull } from "fp-ts/lib/function";
import { IOStyles } from "../../components/core/variables/IOStyles";
import { useHeaderSecondLevel } from "../../hooks/useHeaderSecondLevel";
import { useIODispatch, useIOSelector } from "../../store/hooks";
import {
isLoadingTrialStatusSelector,
trialStatusSelector
} from "../../features/trialSystem/store/reducers";
import { TrialId } from "../../../definitions/trial_systwem/TrialId";
import {
trialSystemActivationStatus,
trialSystemActivationStatusUpsert
} from "../../features/trialSystem/store/actions";
import I18n from "../../i18n";
import { SubscriptionStateEnum } from "../../../definitions/trial_systwem/SubscriptionState";

const styles = StyleSheet.create({
row: {
flexDirection: "row",
alignItems: "center"
}
});

const TRIAL_ID = "test-trial-id" as TrialId;

const TrialSystemPlayground = () => {
const dispatch = useIODispatch();
const trialStatus = useIOSelector(trialStatusSelector(TRIAL_ID));
const isTrialStatusLoading = useIOSelector(
isLoadingTrialStatusSelector(TRIAL_ID)
);

const isTrialStatusUpdating = useIOSelector(
isLoadingTrialStatusSelector(TRIAL_ID)
);

useEffect(() => {
dispatch(trialSystemActivationStatus.request(TRIAL_ID));
}, [dispatch]);

useHeaderSecondLevel({
title: "Sistema di Sperimentazione Playground",
canGoBack: true
});

return (
<SafeAreaView style={IOStyles.flex}>
<ContentWrapper>
<H3>{"Sperimentazione di IT-Wallet"}</H3>
<VSpacer />
<View style={styles.row}>
<Body color="black" weight="Semibold">
{"Stato attuale: "}
</Body>
<Body color="black" weight="Bold">
{trialStatus ? trialStatus : "Non presente"}
</Body>
</View>
<VSpacer />

{!isTrialStatusLoading && (
<>
{trialStatus === undefined ||
trialStatus === SubscriptionStateEnum.UNSUBSCRIBED ? (
<ButtonSolid
loading={isTrialStatusUpdating}
fullWidth
label={I18n.t("profile.main.trial.titleSection")}
onPress={() =>
dispatch(trialSystemActivationStatusUpsert.request(TRIAL_ID))
}
/>
) : (
<ButtonSolid
fullWidth
color="danger"
label={"Disiscriviti"}
onPress={constNull}
/>
)}
</>
)}
</ContentWrapper>
</SafeAreaView>
);
};

export default TrialSystemPlayground;

0 comments on commit 469e872

Please sign in to comment.