Skip to content

Commit

Permalink
Merge branch 'master' into SIW-1455-credential-expiry-and-reissuing
Browse files Browse the repository at this point in the history
  • Loading branch information
mastro993 authored Jan 20, 2025
2 parents 9523d30 + 877ec8e commit c84c6df
Show file tree
Hide file tree
Showing 10 changed files with 1,281 additions and 905 deletions.
9 changes: 0 additions & 9 deletions locales/de/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -609,15 +609,6 @@ authentication:
privacyLink: "Datenschutzerklärung"
nospid: "Du hast keinen SPID? Erfahre mehr"
nospid-nocie: "Du hast keinen SPID und keine CIE? Erfahre mehr"
card1-title: "Alle Mitteilungen an einem Ort"
card1-content: "Zeige alle erhaltenen Mitteilungen von öffentlichen Körperschaften an"
card2-title: "Verwende deine bevorzugten Zahlungsmethoden"
card2-content: "Du kannst eine Steuer oder eine Strafe über dein Bankkonto oder mit deiner Bankkarte bezahlen"
card3-title: "Bezahle schnell eine Aufforderung in Papierform"
card3-content: "Durch das Scannen des QR-Codes kannst du schnell und einfach eine Zahlungsmitteilung in Papierform bezahlen"
card5-title: "Willkommen in IO!"
card5-content: "Lass uns gemeinsam herausfinden, was du machen kannst"
card5-content-accessibility: "Wähle das vorherige Element, um einen Chat mit dem IO-Team zu beginnen, wenn etwas nicht so funktioniert, wie es sollte."
expiredCardTitle: "CIE-Verifizierung fehlgeschlagen"
expiredCardHeaderTitle: "Anmeldung mit CIE"
expiredCardContent: "Die verwendete Karte ist möglicherweise abgelaufen oder nicht mehr gültig. Versuche dich mit SPID bei der App anzumelden."
Expand Down
20 changes: 11 additions & 9 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -653,15 +653,17 @@ authentication:
privacyLink: Privacy
nospid: Don't have SPID? Find out more
nospid-nocie: Don't have SPID or CIE? Find out more
card1-title: All messages in one place
card1-content: Display all the incoming communications from Public Administrations
card2-title: Use your favourite payment methods
card2-content: You can pay a tax or a penalty by your bank account and your cards
card3-title: Quickly pay a physical notice
card3-content: You can pay a notice also by scanning the QR code on the physical notice
card5-title: Welcome to IO!
card5-content: What can you do?
card5-content-accessibility: Select previous item to open a chat with the IO team if something is not working.
card0-title: Welcome to IO!
card0-content: Swipe left to see what you can do in the app
card0-content-accessibility: Select the previous item to open a chat with the IO team if something is not working as it should.
card1-title: Keep your personal documents safe
card1-content: With Documenti su IO you always have the digital version of your documents, such as driving licence and health card, at your fingertips
card2-title: Receive communications, also with legal value
card2-content: "Read incoming communications from organisations: by activating the SEND service, you will also receive communications with legal value and save on notification costs."
card3-title: Pay pagoPA notice by the method you prefer
card3-content: On IO, you can view and download receipts for your pagoPA payments, even if you have not paid in the app
card4-title: Access to the services you are most interested in
card4-content: Direct access to government services related to health, education, mobility, work and more
expiredCardTitle: The CIE verification failed
expiredCardHeaderTitle: Login with CIE
expiredCardContent: The card used is no longer valid or has expired. Use SPID to enter the app.
Expand Down
20 changes: 11 additions & 9 deletions locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -653,15 +653,17 @@ authentication:
privacyLink: Informativa privacy
nospid: Non hai SPID? Scopri di più
nospid-nocie: Non hai SPID o CIE? Scopri di più
card1-title: Tutti i messaggi in un solo posto
card1-content: Visualizza tutte le comunicazioni in arrivo dalle Amministrazioni Pubbliche
card2-title: Usa i tuoi metodi di pagamento preferiti
card2-content: Puoi pagare un tributo o una multa con il tuo conto corrente e le tue carte
card3-title: Paga velocemente un avviso cartaceo
card3-content: Tramite la scansione del QR code puoi velocemente pagare anche un avviso cartaceo
card5-title: Ti diamo il benvenuto su IO!
card5-content: Vediamo insieme cosa puoi fare
card5-content-accessibility: Seleziona elemento precedente per aprire una chat con il team di IO se qualcosa non funziona come dovrebbe.
card0-title: Ti diamo il benvenuto su IO!
card0-content: Scorri per sapere cosa puoi fare in app.
card0-content-accessibility: Seleziona elemento precedente per aprire una chat con il team di IO se qualcosa non funziona come dovrebbe.
card1-title: Conserva al sicuro i tuoi documenti personali
card1-content: Con Documenti su IO hai sempre a portata di mano la versione digitale dei tuoi documenti, come Patente e Tessera Sanitaria
card2-title: Ricevi comunicazioni, anche a valore legale
card2-content: "Leggi le comunicazioni in arrivo dagli enti: se attivi il servizio SEND, ricevi anche quelle a valore legale e risparmi sui costi di notifica"
card3-title: Paga gli avvisi pagoPA con il metodo che preferisci
card3-content: Su IO consulti e scarichi le ricevute dei tuoi pagamenti pagoPA, anche se non hai pagato in app
card4-title: Accedi ai servizi che più ti interessano
card4-content: Accedi direttamente a servizi della Pubblica Amministrazone dedicati a salute, educazione, mobilità, lavoro e molto altro
expiredCardTitle: La verifica della CIE non è andata a buon fine
expiredCardHeaderTitle: Entra con CIE
expiredCardContent: La carta utilizzata potrebbe essere scaduta o non più valida. Prova ad usare SPID per entrare in app.
Expand Down
2 changes: 1 addition & 1 deletion locales/it/markdown_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Lista numerata:

Link

[esempio di link](https://io.italia.it)
[esempio di link](https://ioapp.it/)


Esempio link interni
Expand Down
33 changes: 24 additions & 9 deletions ts/features/services/home/hooks/useInstitutionsFetcher.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import * as pot from "@pagopa/ts-commons/lib/pot";
import { useCallback, useEffect, useState } from "react";
import { ScopeTypeEnum } from "../../../../../definitions/services/ScopeType";
import { useIODispatch, useIOSelector } from "../../../../store/hooks";
import { paginatedInstitutionsGet } from "../store/actions";
import {
isErrorPaginatedInstitutionsSelector,
isLoadingPaginatedInstitutionsSelector,
isUpdatingPaginatedInstitutionsSelector,
paginatedInstitutionsCurrentPageSelector,
paginatedInstitutionsLastPageSelector,
paginatedInstitutionsSelector
paginatedInstitutionsPotSelector
} from "../store/reducers";

const LIMIT: number = 10;
const NEXT_PAGE_LOADING_WAIT_MILLISECONDS: number = 1000;

export const useInstitutionsFetcher = () => {
const dispatch = useIODispatch();

const paginatedInstitutions = useIOSelector(paginatedInstitutionsSelector);
const paginatedInstitutionsPot = useIOSelector(
paginatedInstitutionsPotSelector
);
const currentPage = useIOSelector(paginatedInstitutionsCurrentPageSelector);
const isLastPage = useIOSelector(paginatedInstitutionsLastPageSelector);
const isLoading = useIOSelector(isLoadingPaginatedInstitutionsSelector);
const isUpdating = useIOSelector(isUpdatingPaginatedInstitutionsSelector);
const isError = useIOSelector(isErrorPaginatedInstitutionsSelector);

const paginatedInstitutions = pot.toUndefined(paginatedInstitutionsPot);
const isError = pot.isError(paginatedInstitutionsPot);
const isLoading = pot.isLoading(paginatedInstitutionsPot);
const isUpdating = pot.isUpdating(paginatedInstitutionsPot);

const [isRefreshing, setIsRefreshing] = useState<boolean>(false);

Expand Down Expand Up @@ -51,10 +54,22 @@ export const useInstitutionsFetcher = () => {
if (isLastPage) {
return;
}
// If there was an error in the last page-loading, we prevent
// the page from reloading continuosly when the server endpoint keeps
// replying with an error. In such case we block the call and wait for
// a little bit before the request can be sent again
if (isError) {
const millisecondsAfterLastError =
new Date().getTime() - paginatedInstitutionsPot.error.time.getTime();

if (millisecondsAfterLastError < NEXT_PAGE_LOADING_WAIT_MILLISECONDS) {
return;
}
}

fetchPage(page);
},
[isLastPage, fetchPage]
[isError, isLastPage, paginatedInstitutionsPot, fetchPage]
);

const refresh = useCallback(() => {
Expand Down
61 changes: 22 additions & 39 deletions ts/features/services/home/screens/ServicesHomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,29 +87,25 @@ export const ServicesHomeScreen = () => {
[navigation]
);

const renderListHeaderComponent = () => (
<>
<SearchInputComponent />
<FeaturedServiceList />
<FeaturedInstitutionList />
<ListItemHeader label={I18n.t("services.home.institutions.title")} />
</>
);

const SearchInputComponent = useCallback(
const renderListHeaderComponent = useCallback(
() => (
<SearchInput
accessibilityLabel={I18n.t("services.search.input.placeholder")}
cancelButtonLabel={I18n.t("services.search.input.cancel")}
clearAccessibilityLabel={I18n.t("services.search.input.clear")}
placeholder={I18n.t("services.search.input.placeholder")}
pressable={{
onPress: () => {
analytics.trackSearchStart({ source: "search_bar" });
navigateToSearch();
}
}}
/>
<>
<SearchInput
accessibilityLabel={I18n.t("services.search.input.placeholder")}
cancelButtonLabel={I18n.t("services.search.input.cancel")}
clearAccessibilityLabel={I18n.t("services.search.input.clear")}
placeholder={I18n.t("services.search.input.placeholder")}
pressable={{
onPress: () => {
analytics.trackSearchStart({ source: "search_bar" });
navigateToSearch();
}
}}
/>
<FeaturedServiceList />
<FeaturedInstitutionList />
<ListItemHeader label={I18n.t("services.home.institutions.title")} />
</>
),
[navigateToSearch]
);
Expand Down Expand Up @@ -146,23 +142,10 @@ export const ServicesHomeScreen = () => {
refresh();
}, [dispatch, refresh]);

const handleEndReached = useCallback(
({ distanceFromEnd }: { distanceFromEnd: number }) => {
// Managed behavior:
// at the end of data load, in case of response error,
// the footer is removed from total list length and
// `onEndReached` is triggered continuously causing an endless loop.
// Implemented solution:
// this guard is needed to avoid endless loop
if (distanceFromEnd === 0) {
return;
}

analytics.trackInstitutionsScroll();
fetchNextPage(currentPage + 1);
},
[currentPage, fetchNextPage]
);
const handleEndReached = useCallback(() => {
analytics.trackInstitutionsScroll();
fetchNextPage(currentPage + 1);
}, [currentPage, fetchNextPage]);

const navigateToInstitution = useCallback(
({ fiscal_code, id, name }: Institution) => {
Expand Down
139 changes: 12 additions & 127 deletions ts/features/services/home/store/reducers/__tests__/store.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import * as pot from "@pagopa/ts-commons/lib/pot";
import MockDate from "mockdate";
import { Action, createStore } from "redux";
import {
featuredInstitutionsSelector,
featuredServicesSelector,
isErrorFeaturedInstitutionsSelector,
isErrorFeaturedServicesSelector,
isErrorPaginatedInstitutionsSelector,
isLoadingFeaturedInstitutionsSelector,
isLoadingFeaturedServicesSelector,
isLoadingPaginatedInstitutionsSelector,
isUpdatingPaginatedInstitutionsSelector,
paginatedInstitutionsCurrentPageSelector,
paginatedInstitutionsLastPageSelector,
paginatedInstitutionsSelector
Expand Down Expand Up @@ -81,6 +79,9 @@ const MOCK_NETWORK_ERROR: NetworkError = {
value: new Error("response status code 500")
};

const MOCKED_DATE = new Date();
MockDate.set(MOCKED_DATE);

describe("Services home paginatedInstitutions reducer", () => {
it("should have initial state", () => {
const state = appReducer(undefined, applicationChangeState("active"));
Expand Down Expand Up @@ -129,7 +130,10 @@ describe("Services home paginatedInstitutions reducer", () => {
offset: 0,
limit: 3
},
MOCK_NETWORK_ERROR
{
reason: MOCK_NETWORK_ERROR,
time: MOCKED_DATE
}
)
);
});
Expand Down Expand Up @@ -198,7 +202,10 @@ describe("Services home paginatedInstitutions reducer", () => {
offset: 3,
limit: 3
},
MOCK_NETWORK_ERROR
{
reason: MOCK_NETWORK_ERROR,
time: MOCKED_DATE
}
)
);
});
Expand Down Expand Up @@ -254,128 +261,6 @@ describe("Services home paginatedInstitutions selectors", () => {
});
});

describe("isLoadingPaginatedInstitutionsSelector", () => {
it("should return true when pot.loading", () => {
const isLoading = isLoadingPaginatedInstitutionsSelector(
appReducer(
{} as GlobalState,
paginatedInstitutionsGet.request({ offset: 0, limit: 3 })
)
);
expect(isLoading).toStrictEqual(true);
});

it("should return false when not pot.loading", () => {
expect(
isLoadingPaginatedInstitutionsSelector(
appReducer(undefined, {} as Action)
)
).toStrictEqual(false);

expect(
isLoadingPaginatedInstitutionsSelector(
appReducer(
{} as GlobalState,
paginatedInstitutionsGet.success({
institutions: MOCK_INSTITUTIONS,
count: 23,
offset: 0,
limit: 3
})
)
)
).toStrictEqual(false);
});
});

describe("isUpdatingPaginatedInstitutionsSelector", () => {
it("should return true when pot.updating", () => {
const state = appReducer(undefined, applicationChangeState("active"));
const store = createStore(appReducer, state as any);

store.dispatch(
paginatedInstitutionsGet.success({
institutions: MOCK_INSTITUTIONS,
count: 23,
offset: 0,
limit: 3
})
);
store.dispatch(paginatedInstitutionsGet.request({ offset: 3, limit: 3 }));

const isUpdating = isUpdatingPaginatedInstitutionsSelector(
store.getState()
);

expect(isUpdating).toStrictEqual(true);
});

it("should return false when not pot.updating", () => {
expect(
isUpdatingPaginatedInstitutionsSelector(
appReducer(undefined, {} as Action)
)
).toStrictEqual(false);

expect(
isUpdatingPaginatedInstitutionsSelector(
appReducer(
{} as GlobalState,
paginatedInstitutionsGet.request({ offset: 0, limit: 3 })
)
)
).toStrictEqual(false);

expect(
isUpdatingPaginatedInstitutionsSelector(
appReducer(
{} as GlobalState,
paginatedInstitutionsGet.success({
institutions: MOCK_INSTITUTIONS,
count: 23,
offset: 0,
limit: 3
})
)
)
).toStrictEqual(false);
});
});

describe("isErrorPaginatedInstitutionsSelector", () => {
it("should return true when pot.error", () => {
const isError = isErrorPaginatedInstitutionsSelector(
appReducer(
{} as GlobalState,
paginatedInstitutionsGet.failure(MOCK_NETWORK_ERROR)
)
);
expect(isError).toStrictEqual(true);
});

it("should return false when not pot.error", () => {
expect(
isErrorPaginatedInstitutionsSelector(
appReducer(undefined, {} as Action)
)
).toStrictEqual(false);

expect(
isErrorPaginatedInstitutionsSelector(
appReducer(
{} as GlobalState,
paginatedInstitutionsGet.success({
institutions: MOCK_INSTITUTIONS,
count: 23,
offset: 0,
limit: 3
})
)
)
).toStrictEqual(false);
});
});

describe("paginatedInstitutionsCurrentPageSelector", () => {
[
{ expectedPage: 0, offset: 0, limit: 20, count: 55 },
Expand Down
Loading

0 comments on commit c84c6df

Please sign in to comment.