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

feat: [IOCOM-840] Preconditions bottom sheet, new DS #5912

Merged
merged 27 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9f55e40
WiP
Vangaorth Jun 25, 2024
eb20144
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jun 25, 2024
c3046a6
WiP
Vangaorth Jun 26, 2024
17f174c
WiP
Vangaorth Jun 26, 2024
13e2d7c
Pre-renaming
Vangaorth Jun 26, 2024
0418d5d
Post rename
Vangaorth Jun 26, 2024
393781a
Implementation done, missing tests
Vangaorth Jun 27, 2024
02e2a42
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jun 27, 2024
0ab204c
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jun 27, 2024
8234717
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jun 27, 2024
bb45c90
Tests
Vangaorth Jun 28, 2024
485cd74
Tests
Vangaorth Jun 28, 2024
ca37a23
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jun 28, 2024
714dea5
Merge branch 'IOCOM-840_preconditions' of https://github.com/pagopa/i…
Vangaorth Jun 28, 2024
18e0386
Tests
Vangaorth Jun 28, 2024
566d856
Fixed bad snapshot title
Vangaorth Jun 28, 2024
7472074
Tests
Vangaorth Jun 30, 2024
526b32e
Tests
Vangaorth Jun 30, 2024
b54fd72
Tests
Vangaorth Jun 30, 2024
ddc7ebf
Tests
Vangaorth Jul 1, 2024
617a722
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jul 1, 2024
353827c
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jul 1, 2024
d19be25
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jul 4, 2024
0e78d2d
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jul 4, 2024
d8c846a
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jul 4, 2024
9def4f4
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jul 4, 2024
af814ae
Merge branch 'master' into IOCOM-840_preconditions
Vangaorth Jul 5, 2024
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
42 changes: 0 additions & 42 deletions ts/boot/__tests__/__snapshots__/persistedStore.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -43,48 +43,6 @@ Object {
"calendarEvents": Object {
"byMessageId": Object {},
},
"messages": Object {
"allPaginated": Object {
"archive": Object {
"data": Object {
"kind": "PotNone",
},
"lastRequest": Object {
"_tag": "None",
},
},
"inbox": Object {
"data": Object {
"kind": "PotNone",
},
"lastRequest": Object {
"_tag": "None",
},
},
"migration": Object {
"_tag": "None",
},
"shownCategory": "INBOX",
},
"detailsById": Object {},
"downloads": Object {},
"messageGetStatus": Object {
"status": "idle",
},
"messagePrecondition": Object {
"content": Object {
"kind": "undefined",
},
"messageId": Object {
"_tag": "None",
},
},
"paginatedById": Object {},
"payments": Object {
"userSelectedPayments": Set {},
},
"thirdPartyById": Object {},
},
"messagesStatus": Object {},
"organizations": Object {
"all": Array [],
Expand Down
4 changes: 3 additions & 1 deletion ts/boot/__tests__/persistedStore.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import _ from "lodash";
import { applicationChangeState } from "../../store/actions/application";
import { appReducer } from "../../store/reducers";
import { GlobalState } from "../../store/reducers/types";
Expand Down Expand Up @@ -43,7 +44,8 @@ describe("Check the addition for new fields to the persisted store. If one of th
expect(globalState.crossSessions).toMatchSnapshot();
});
it("Freeze 'entities' state", () => {
expect(globalState.entities).toMatchSnapshot();
const entitiesWithoutMessages = _.omit(globalState.entities, "messages");
expect(entitiesWithoutMessages).toMatchSnapshot();
});
it("Freeze 'authentication' state", () => {
expect(globalState.authentication).toMatchSnapshot();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
isCdcEnabledSelector,
isCGNEnabledSelector,
isPnEnabledSelector,
isPnSupportedSelector
isPnAppVersionSupportedSelector
} from "../../../store/reducers/backendStatus";
import { openAppStoreUrl } from "../../../utils/url";

Expand Down Expand Up @@ -69,7 +69,7 @@ const LegacySpecialServicesCTA = (props: Props) => {
const isCdcEnabled = cdcEnabledSelector && cdcEnabled;

const isPnEnabled = useIOSelector(isPnEnabledSelector);
const isPnSupported = useIOSelector(isPnSupportedSelector);
const isPnSupported = useIOSelector(isPnAppVersionSupportedSelector);

const mapSpecialServiceConfig = new Map<string, SpecialServiceConfig>([
["cgn", { isEnabled: isCGNEnabled, isSupported: true }],
Expand Down
88 changes: 88 additions & 0 deletions ts/features/messages/components/Home/Preconditions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React, { useCallback, useEffect } from "react";
import { useIOBottomSheetModal } from "../../../../utils/hooks/bottomSheet";
import {
useIODispatch,
useIOSelector,
useIOStore
} from "../../../../store/hooks";
import {
preconditionsCategoryTagSelector,
preconditionsRequireAppUpdateSelector,
shouldPresentPreconditionsBottomSheetSelector
} from "../../store/reducers/messagePrecondition";
import {
clearLegacyMessagePrecondition,
idlePreconditionStatusAction,
retrievingDataPreconditionStatusAction,
toIdlePayload,
toRetrievingDataPayload,
toUpdateRequiredPayload,
updateRequiredPreconditionStatusAction
} from "../../store/actions/preconditions";
import { MESSAGES_ROUTES } from "../../navigation/routes";
import { trackDisclaimerOpened } from "../../analytics";
import { UIMessageId } from "../../types";
import { useIONavigation } from "../../../../navigation/params/AppParamsList";
import { PreconditionsTitle } from "./PreconditionsTitle";
import { PreconditionsContent } from "./PreconditionsContent";
import { PreconditionsFooter } from "./PreconditionsFooter";

export const Preconditions = () => {
const navigation = useIONavigation();
const dispatch = useIODispatch();
const store = useIOStore();
const onDismissCallback = useCallback(() => {
dispatch(clearLegacyMessagePrecondition());
dispatch(idlePreconditionStatusAction(toIdlePayload()));
}, [dispatch]);
const onNavigationCallback = useCallback(
(messageId: UIMessageId) => {
navigation.navigate(MESSAGES_ROUTES.MESSAGES_NAVIGATOR, {
screen: MESSAGES_ROUTES.MESSAGE_ROUTER,
params: {
messageId,
fromNotification: false
}
});
},
[navigation]
);
const modal = useIOBottomSheetModal({
snapPoint: [500],
title: <PreconditionsTitle />,
component: <PreconditionsContent />,
footer: (
<PreconditionsFooter
onDismiss={() => modal.dismiss()}
onNavigation={onNavigationCallback}
/>
),
onDismiss: onDismissCallback
});
const shouldPresentBottomSheet = useIOSelector(
shouldPresentPreconditionsBottomSheetSelector
);

useEffect(() => {
if (shouldPresentBottomSheet) {
const state = store.getState();
const categoryTag = preconditionsCategoryTagSelector(state);
if (categoryTag) {
trackDisclaimerOpened(categoryTag);
}
modal.present();

const requiresAppUpdate = preconditionsRequireAppUpdateSelector(state);
if (requiresAppUpdate) {
dispatch(
updateRequiredPreconditionStatusAction(toUpdateRequiredPayload())
);
} else {
dispatch(
retrievingDataPreconditionStatusAction(toRetrievingDataPayload())
);
}
}
}, [dispatch, modal, shouldPresentBottomSheet, store]);
return modal.bottomSheet;
};
131 changes: 131 additions & 0 deletions ts/features/messages/components/Home/PreconditionsContent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React, { useCallback } from "react";
import { View } from "react-native";
import Placeholder from "rn-placeholder";
import { VSpacer } from "@pagopa/io-app-design-system";
import {
useIODispatch,
useIOSelector,
useIOStore
} from "../../../../store/hooks";
import {
preconditionsCategoryTagSelector,
preconditionsContentMarkdownSelector,
preconditionsContentSelector
} from "../../store/reducers/messagePrecondition";
import I18n from "../../../../i18n";
import { pnMinAppVersionSelector } from "../../../../store/reducers/backendStatus";
import { MessageMarkdown } from "../MessageDetail/MessageMarkdown";
import {
errorPreconditionStatusAction,
shownPreconditionStatusAction,
toErrorPayload,
toShownPayload
} from "../../store/actions/preconditions";
import { trackDisclaimerLoadError } from "../../analytics";
import { PreconditionsFeedback } from "./PreconditionsFeedback";

export const PreconditionsContent = () => {
const content = useIOSelector(preconditionsContentSelector);
switch (content) {
case "content":
return <PreconditionsContentMarkdown />;
case "error":
return <PreconditionsContentError />;
case "loading":
return <PreconditionsContentSkeleton />;
case "update":
return <PreconditionsContentUpdate />;
}
return null;
};

const PreconditionsContentMarkdown = () => {
const dispatch = useIODispatch();
const store = useIOStore();

const markdown = useIOSelector(preconditionsContentMarkdownSelector);

const onLoadEndCallback = useCallback(() => {
dispatch(shownPreconditionStatusAction(toShownPayload()));
}, [dispatch]);
const onErrorCallback = useCallback(
(anyError: any) => {
const state = store.getState();
const category = preconditionsCategoryTagSelector(state);
if (category) {
trackDisclaimerLoadError(category);
}
dispatch(
errorPreconditionStatusAction(
toErrorPayload(`Markdown loading failure (${anyError})`)
)
);
},
[dispatch, store]
);

if (!markdown) {
return null;
}

return (
<MessageMarkdown
loadingLines={7}
onLoadEnd={onLoadEndCallback}
onError={onErrorCallback}
testID="preconditions_content_message_markdown"
>
{markdown}
</MessageMarkdown>
);
};

const PreconditionsContentError = () => (
<PreconditionsFeedback
pictogram="umbrellaNew"
title={I18n.t("global.genericError")}
/>
);

const PreconditionsContentSkeleton = () => (
<View accessible={false}>
{Array.from({ length: 3 }).map((_, i) => (
<View key={`pre_content_ske_${i}`}>
<Placeholder.Box
width={"100%"}
animate={"fade"}
height={21}
radius={4}
/>
<VSpacer size={8} />
<Placeholder.Box
width={"100%"}
animate={"fade"}
height={21}
radius={4}
/>
<VSpacer size={8} />
<Placeholder.Box
width={"90%"}
animate={"fade"}
height={21}
radius={4}
/>
<VSpacer size={8} />
</View>
))}
</View>
);

const PreconditionsContentUpdate = () => {
const pnMinAppVersion = useIOSelector(pnMinAppVersionSelector);
return (
<PreconditionsFeedback
pictogram="umbrellaNew"
title={I18n.t("features.messages.updateBottomSheet.title")}
subtitle={I18n.t("features.messages.updateBottomSheet.subtitle", {
value: pnMinAppVersion
})}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ type Props = {
subtitle?: string;
};

export const MessageFeedback = ({ pictogram, title, subtitle }: Props) => (
export const PreconditionsFeedback = ({
pictogram,
title,
subtitle
}: Props) => (
<View style={styles.container}>
<Pictogram name={pictogram} size={120} />
<VSpacer size={24} />
Expand Down
Loading
Loading