(
}
if (typeof value === "object" && value !== null) {
+ if (value instanceof Set) {
+ // Set could not be serialized to JSON because values are not stored as properties
+ // For display purposes, we convert it to an array
+ return Array.from(value).map(item =>
+ truncateObjectStrings(item, maxLength)
+ ) as T;
+ }
+
return Object.entries(value).reduce(
(acc, [key, val]) => ({
...acc,
diff --git a/ts/components/debug/withDebugEnabled.tsx b/ts/components/debug/withDebugEnabled.tsx
index 72eb5eccea5..303a6aa45dd 100644
--- a/ts/components/debug/withDebugEnabled.tsx
+++ b/ts/components/debug/withDebugEnabled.tsx
@@ -6,11 +6,13 @@ import { isDebugModeEnabledSelector } from "../../store/reducers/debug";
* This HOC allows to render the wrapped component only if the debug mode is enabled, otherwise returns null (nothing)
*/
export const withDebugEnabled =
- (WrappedComponent: React.ComponentType
) =>
+
>(
+ WrappedComponent: React.ComponentType
+ ) =>
(props: P) => {
const isDebug = useIOSelector(isDebugModeEnabledSelector);
if (!isDebug) {
return null;
}
- return ;
+ return ;
};
diff --git a/ts/features/itwallet/onboarding/screens/WalletCardOnboardingScreen.tsx b/ts/features/itwallet/onboarding/screens/WalletCardOnboardingScreen.tsx
index 0efb8a6768f..cdaf466893f 100644
--- a/ts/features/itwallet/onboarding/screens/WalletCardOnboardingScreen.tsx
+++ b/ts/features/itwallet/onboarding/screens/WalletCardOnboardingScreen.tsx
@@ -112,7 +112,7 @@ const ItwCredentialOnboardingSection = () => {
);
return (
- <>
+
@@ -134,7 +134,7 @@ const ItwCredentialOnboardingSection = () => {
/>
))}
- >
+
);
};
@@ -175,7 +175,7 @@ const OtherCardsOnboardingSection = (props: { showTitle?: boolean }) => {
);
return (
- <>
+
{props.showTitle && (
{
onPress={navigateToPaymentMethodOnboarding}
/>
- >
+
);
};
diff --git a/ts/features/wallet/components/WalletCardsContainer.tsx b/ts/features/wallet/components/WalletCardsContainer.tsx
index 9d08e1c2a8b..562c74fec75 100644
--- a/ts/features/wallet/components/WalletCardsContainer.tsx
+++ b/ts/features/wallet/components/WalletCardsContainer.tsx
@@ -3,12 +3,12 @@ import { useFocusEffect } from "@react-navigation/native";
import * as React from "react";
import { View } from "react-native";
import Animated, { LinearTransition } from "react-native-reanimated";
+import { useDebugInfo } from "../../../hooks/useDebugInfo";
import I18n from "../../../i18n";
import { useIONavigation } from "../../../navigation/params/AppParamsList";
import { useIOSelector } from "../../../store/hooks";
import { isItwEnabledSelector } from "../../../store/reducers/backendStatus/remoteConfig";
import { useIOBottomSheetAutoresizableModal } from "../../../utils/hooks/bottomSheet";
-import { ItwDiscoveryBannerStandalone } from "../../itwallet/common/components/discoveryBanner/ItwDiscoveryBannerStandalone";
import {
ItwEidInfoBottomSheetContent,
ItwEidInfoBottomSheetTitle
@@ -16,22 +16,22 @@ import {
import { ItwEidLifecycleAlert } from "../../itwallet/common/components/ItwEidLifecycleAlert";
import { ItwFeedbackBanner } from "../../itwallet/common/components/ItwFeedbackBanner";
import { ItwWalletReadyBanner } from "../../itwallet/common/components/ItwWalletReadyBanner";
+import { ItwDiscoveryBannerStandalone } from "../../itwallet/common/components/discoveryBanner/ItwDiscoveryBannerStandalone";
import { itwCredentialsEidStatusSelector } from "../../itwallet/credentials/store/selectors";
import { itwLifecycleIsValidSelector } from "../../itwallet/lifecycle/store/selectors";
+import { useItwWalletInstanceRevocationAlert } from "../../itwallet/walletInstance/hook/useItwWalletInstanceRevocationAlert";
import {
isWalletEmptySelector,
- selectIsWalletCardsLoading,
+ selectIsWalletLoading,
+ selectWalletCardsByCategory,
selectWalletCategories,
- selectWalletCategoryFilter,
- selectWalletItwCards,
selectWalletOtherCards,
shouldRenderWalletEmptyStateSelector
} from "../store/selectors";
-import { WalletCardCategoryFilter } from "../types";
-import { useItwWalletInstanceRevocationAlert } from "../../itwallet/walletInstance/hook/useItwWalletInstanceRevocationAlert";
+import { withWalletCategoryFilter } from "../utils";
+import { WalletCardSkeleton } from "./WalletCardSkeleton";
import { WalletCardsCategoryContainer } from "./WalletCardsCategoryContainer";
import { WalletCardsCategoryRetryErrorBanner } from "./WalletCardsCategoryRetryErrorBanner";
-import { WalletCardSkeleton } from "./WalletCardSkeleton";
import { WalletEmptyScreenContent } from "./WalletEmptyScreenContent";
const EID_INFO_BOTTOM_PADDING = 128;
@@ -42,9 +42,8 @@ const EID_INFO_BOTTOM_PADDING = 128;
* and the empty state
*/
const WalletCardsContainer = () => {
- const isLoading = useIOSelector(selectIsWalletCardsLoading);
+ const isLoading = useIOSelector(selectIsWalletLoading);
const isWalletEmpty = useIOSelector(isWalletEmptySelector);
- const selectedCategory = useIOSelector(selectWalletCategoryFilter);
const shouldRenderEmptyState = useIOSelector(
shouldRenderWalletEmptyStateSelector
);
@@ -55,13 +54,6 @@ const WalletCardsContainer = () => {
// placeholders in the wallet
const shouldRenderLoadingState = isLoading && isWalletEmpty;
- // Returns true if no category filter is selected or if the filter matches the given category
- const shouldRenderCategory = React.useCallback(
- (filter: WalletCardCategoryFilter): boolean =>
- selectedCategory === undefined || selectedCategory === filter,
- [selectedCategory]
- );
-
// Content to render in the wallet screen, based on the current state
const walletContent = React.useMemo(() => {
if (shouldRenderLoadingState) {
@@ -72,11 +64,11 @@ const WalletCardsContainer = () => {
}
return (
- {shouldRenderCategory("itw") && }
- {shouldRenderCategory("other") && }
+
+
);
- }, [shouldRenderEmptyState, shouldRenderCategory, shouldRenderLoadingState]);
+ }, [shouldRenderEmptyState, shouldRenderLoadingState]);
return (
{
);
};
+/**
+ * Skeleton for the wallet cards container
+ */
const WalletCardsContainerSkeleton = () => (
<>
@@ -97,15 +92,29 @@ const WalletCardsContainerSkeleton = () => (
>
);
-const ItwWalletCardsContainer = () => {
+/**
+ * Card container for the ITW credentials
+ */
+const ItwWalletCardsContainer = withWalletCategoryFilter("itw", () => {
const navigation = useIONavigation();
- const cards = useIOSelector(selectWalletItwCards);
+ const cards = useIOSelector(state =>
+ selectWalletCardsByCategory(state, "itw")
+ );
const isItwValid = useIOSelector(itwLifecycleIsValidSelector);
const isItwEnabled = useIOSelector(isItwEnabledSelector);
const eidStatus = useIOSelector(itwCredentialsEidStatusSelector);
const isEidExpired = eidStatus === "jwtExpired";
+ useDebugInfo({
+ itw: {
+ isItwValid,
+ isItwEnabled,
+ eidStatus,
+ cards
+ }
+ });
+
const eidInfoBottomSheet = useIOBottomSheetAutoresizableModal(
{
title: ,
@@ -172,12 +181,21 @@ const ItwWalletCardsContainer = () => {
{isItwValid && eidInfoBottomSheet.bottomSheet}
>
);
-};
+});
-const OtherWalletCardsContainer = () => {
+/**
+ * Card container for the other cards (payments, bonus, etc.)
+ */
+const OtherWalletCardsContainer = withWalletCategoryFilter("other", () => {
const cards = useIOSelector(selectWalletOtherCards);
const categories = useIOSelector(selectWalletCategories);
+ useDebugInfo({
+ other: {
+ cards
+ }
+ });
+
const sectionHeader = React.useMemo((): ListItemHeader | undefined => {
// The section header must be displayed only if there are more categories
if (categories.size <= 1) {
@@ -203,7 +221,7 @@ const OtherWalletCardsContainer = () => {
bottomElement={}
/>
);
-};
+});
export {
ItwWalletCardsContainer,
diff --git a/ts/features/wallet/components/WalletCategoryFilterTabs.tsx b/ts/features/wallet/components/WalletCategoryFilterTabs.tsx
index 9cec1e0534e..10b0921f266 100644
--- a/ts/features/wallet/components/WalletCategoryFilterTabs.tsx
+++ b/ts/features/wallet/components/WalletCategoryFilterTabs.tsx
@@ -10,10 +10,11 @@ import { useIODispatch, useIOSelector } from "../../../store/hooks";
import { trackWalletCategoryFilter } from "../../itwallet/analytics";
import { walletSetCategoryFilter } from "../store/actions/preferences";
import {
- selectWalletCategories,
+ isWalletCategoryFilteringEnabledSelector,
selectWalletCategoryFilter
} from "../store/selectors";
import { walletCardCategoryFilters } from "../types";
+import { useDebugInfo } from "../../../hooks/useDebugInfo";
/**
* Renders filter tabs to categorize cards on the wallet home screen.
@@ -23,18 +24,27 @@ import { walletCardCategoryFilters } from "../types";
const WalletCategoryFilterTabs = () => {
const dispatch = useIODispatch();
- const selectedCategory = useIOSelector(selectWalletCategoryFilter);
- const categories = useIOSelector(selectWalletCategories);
+ const categoryFilter = useIOSelector(selectWalletCategoryFilter);
+ const isFilteringEnabled = useIOSelector(
+ isWalletCategoryFilteringEnabledSelector
+ );
+
+ useDebugInfo({
+ wallet: {
+ isFilteringEnabled,
+ categoryFilter
+ }
+ });
const selectedIndex = React.useMemo(
() =>
- selectedCategory
- ? walletCardCategoryFilters.indexOf(selectedCategory) + 1
+ categoryFilter
+ ? walletCardCategoryFilters.indexOf(categoryFilter) + 1
: 0,
- [selectedCategory]
+ [categoryFilter]
);
- if (categories.size <= 1) {
+ if (!isFilteringEnabled) {
return null;
}
diff --git a/ts/features/wallet/components/__tests__/WalletCardsContainer.test.tsx b/ts/features/wallet/components/__tests__/WalletCardsContainer.test.tsx
index c364c9f9a4f..13b5dec74bd 100644
--- a/ts/features/wallet/components/__tests__/WalletCardsContainer.test.tsx
+++ b/ts/features/wallet/components/__tests__/WalletCardsContainer.test.tsx
@@ -95,7 +95,7 @@ describe("WalletCardsContainer", () => {
it("should render the loading screen", () => {
jest
- .spyOn(walletSelectors, "selectIsWalletCardsLoading")
+ .spyOn(walletSelectors, "selectIsWalletLoading")
.mockImplementation(() => true);
jest
.spyOn(walletSelectors, "selectWalletCategoryFilter")
@@ -117,7 +117,7 @@ describe("WalletCardsContainer", () => {
it("should render the empty screen", () => {
jest
- .spyOn(walletSelectors, "selectIsWalletCardsLoading")
+ .spyOn(walletSelectors, "selectIsWalletLoading")
.mockImplementation(() => false);
jest
.spyOn(walletSelectors, "selectWalletCategoryFilter")
@@ -150,14 +150,14 @@ describe("WalletCardsContainer", () => {
.mockImplementation(() => [T_CARDS["1"], T_CARDS["2"], T_CARDS["3"]]);
jest
- .spyOn(walletSelectors, "selectWalletItwCards")
+ .spyOn(walletSelectors, "selectWalletCardsByCategory")
.mockImplementation(() => [T_CARDS["4"], T_CARDS["5"]]);
jest
.spyOn(configSelectors, "isItwEnabledSelector")
.mockImplementation(() => true);
jest
- .spyOn(walletSelectors, "selectIsWalletCardsLoading")
+ .spyOn(walletSelectors, "selectIsWalletLoading")
.mockImplementation(() => false);
jest
.spyOn(walletSelectors, "selectWalletCategoryFilter")
@@ -193,7 +193,7 @@ describe("WalletCardsContainer", () => {
.mockImplementation(() => true);
jest
- .spyOn(walletSelectors, "selectIsWalletCardsLoading")
+ .spyOn(walletSelectors, "selectIsWalletLoading")
.mockImplementation(() => isLoading);
jest
.spyOn(walletSelectors, "shouldRenderWalletEmptyStateSelector")
@@ -244,7 +244,7 @@ describe("ItwWalletCardsContainer", () => {
.spyOn(configSelectors, "isItwEnabledSelector")
.mockImplementation(() => true);
jest
- .spyOn(walletSelectors, "selectWalletItwCards")
+ .spyOn(walletSelectors, "selectWalletCardsByCategory")
.mockImplementation(() => [T_CARDS["4"], T_CARDS["5"]]);
const { queryByTestId } = renderComponent(ItwWalletCardsContainer);
diff --git a/ts/features/wallet/components/__tests__/WalletCategoryFilterTabs.test.tsx b/ts/features/wallet/components/__tests__/WalletCategoryFilterTabs.test.tsx
index 06452f7ab0c..9740c683227 100644
--- a/ts/features/wallet/components/__tests__/WalletCategoryFilterTabs.test.tsx
+++ b/ts/features/wallet/components/__tests__/WalletCategoryFilterTabs.test.tsx
@@ -12,25 +12,25 @@ import * as selectors from "../../store/selectors";
import { WalletCategoryFilterTabs } from "../WalletCategoryFilterTabs";
describe("WalletCategoryFilterTabs", () => {
- it("should not render the component if there is only one cards category in the wallet", () => {
+ it("should not render the component if category filtering is not enabled", () => {
jest
.spyOn(selectors, "selectWalletCategoryFilter")
.mockImplementation(() => undefined);
jest
- .spyOn(selectors, "selectWalletCategories")
- .mockImplementation(() => new Set(["itw"]));
+ .spyOn(selectors, "isWalletCategoryFilteringEnabledSelector")
+ .mockImplementation(() => false);
const { queryByTestId } = renderComponent();
expect(queryByTestId("CategoryTabsContainerTestID")).toBeNull();
});
- it("should render the component if there is more than one cards category in the wallet", () => {
+ it("should render the component if category filtering is enabled", () => {
jest
.spyOn(selectors, "selectWalletCategoryFilter")
.mockImplementation(() => undefined);
jest
- .spyOn(selectors, "selectWalletCategories")
- .mockImplementation(() => new Set(["itw", "other"]));
+ .spyOn(selectors, "isWalletCategoryFilteringEnabledSelector")
+ .mockImplementation(() => true);
const { queryByTestId } = renderComponent();
expect(queryByTestId("CategoryTabsContainerTestID")).not.toBeNull();
@@ -45,8 +45,8 @@ describe("WalletCategoryFilterTabs", () => {
.spyOn(selectors, "selectWalletCategoryFilter")
.mockImplementation(() => undefined);
jest
- .spyOn(selectors, "selectWalletCategories")
- .mockImplementation(() => new Set(["itw", "other"]));
+ .spyOn(selectors, "isWalletCategoryFilteringEnabledSelector")
+ .mockImplementation(() => true);
const { getByTestId } = renderComponent();
const itwTab = getByTestId("CategoryTabTestID-itw");
diff --git a/ts/features/wallet/saga/index.ts b/ts/features/wallet/saga/index.ts
index 5511df75f9b..36eb1639359 100644
--- a/ts/features/wallet/saga/index.ts
+++ b/ts/features/wallet/saga/index.ts
@@ -10,7 +10,7 @@ import {
import { walletUpdate } from "../store/actions";
import { walletAddCards } from "../store/actions/cards";
import { walletToggleLoadingState } from "../store/actions/placeholders";
-import { selectWalletPlaceholders } from "../store/selectors";
+import { selectWalletPlaceholderCards } from "../store/selectors";
import { handleWalletAnalyticsSaga } from "./handleWalletAnalyticsSaga";
import { handleWalletPlaceholdersTimeout } from "./handleWalletLoadingPlaceholdersTimeout";
import { handleWalletLoadingStateSaga } from "./handleWalletLoadingStateSaga";
@@ -21,7 +21,7 @@ const LOADING_STATE_TIMEOUT = 2000 as Millisecond;
export function* watchWalletSaga(): SagaIterator {
// Adds persisted placeholders as cards in the wallet
// to be displayed while waiting for the actual cards
- const placeholders = yield* select(selectWalletPlaceholders);
+ const placeholders = yield* select(selectWalletPlaceholderCards);
yield* put(walletAddCards(placeholders));
yield* takeLatest(
diff --git a/ts/features/wallet/screens/__tests__/WalletHomeScreen.test.tsx b/ts/features/wallet/screens/__tests__/WalletHomeScreen.test.tsx
index 6bae047df8c..048de392d91 100644
--- a/ts/features/wallet/screens/__tests__/WalletHomeScreen.test.tsx
+++ b/ts/features/wallet/screens/__tests__/WalletHomeScreen.test.tsx
@@ -1,12 +1,10 @@
-import * as pot from "@pagopa/ts-commons/lib/pot";
-import _ from "lodash";
import configureMockStore from "redux-mock-store";
import ROUTES from "../../../../navigation/routes";
import { applicationChangeState } from "../../../../store/actions/application";
import { appReducer } from "../../../../store/reducers";
import { GlobalState } from "../../../../store/reducers/types";
import { renderScreenWithNavigationStoreContext } from "../../../../utils/testWrapper";
-import { WalletCardsState } from "../../store/reducers/cards";
+import * as walletSelectors from "../../store/selectors";
import { WalletHomeScreen } from "../WalletHomeScreen";
jest.mock("react-native-reanimated", () => ({
@@ -18,98 +16,45 @@ jest.mock("react-native-reanimated", () => ({
}
}));
-const T_CARDS: WalletCardsState = {
- "1": {
- key: "1",
- type: "payment",
- category: "payment",
- walletId: ""
- },
- "2": {
- key: "2",
- type: "payment",
- category: "payment",
- walletId: ""
- },
- "3": {
- key: "3",
- type: "idPay",
- category: "bonus",
- amount: 1234,
- avatarSource: {
- uri: ""
- },
- expireDate: new Date(),
- initiativeId: "",
- name: "ABC"
- }
-};
-
describe("WalletHomeScreen", () => {
jest.useFakeTimers();
jest.runAllTimers();
- it("should correctly render empty screen", () => {
- const {
- component: { queryByTestId }
- } = renderComponent({});
+ it("should not render screen actions if the wallet is empty", () => {
+ jest
+ .spyOn(walletSelectors, "isWalletEmptySelector")
+ .mockImplementation(() => true);
+
+ const { queryByTestId } = renderComponent();
jest.runOnlyPendingTimers();
- expect(queryByTestId("walletPaymentsRedirectBannerTestID")).toBeNull();
- expect(queryByTestId("walletEmptyScreenContentTestID")).not.toBeNull();
- expect(queryByTestId("walletCardsContainerTestID")).toBeNull();
expect(queryByTestId("walletAddCardButtonTestID")).toBeNull();
});
- it("should correctly render card list screen", () => {
- const {
- component: { queryByTestId }
- } = renderComponent(T_CARDS);
+ it("should render screen actions if the wallet is not empty", () => {
+ jest
+ .spyOn(walletSelectors, "isWalletEmptySelector")
+ .mockImplementation(() => false);
+
+ const { queryByTestId } = renderComponent();
+
+ jest.runOnlyPendingTimers();
- expect(queryByTestId("walletPaymentsRedirectBannerTestID")).toBeNull();
- expect(queryByTestId("walletEmptyScreenContentTestID")).toBeNull();
- expect(queryByTestId("walletCardsContainerTestID")).not.toBeNull();
expect(queryByTestId("walletAddCardButtonTestID")).not.toBeNull();
});
});
-const renderComponent = (
- cards: WalletCardsState,
- options: {
- isLoading?: boolean;
- } = {}
-) => {
+const renderComponent = () => {
const globalState = appReducer(undefined, applicationChangeState("active"));
- const { isLoading = false } = options;
const mockStore = configureMockStore();
- const store: ReturnType = mockStore(
- _.merge(globalState, {
- features: {
- wallet: {
- cards,
- preferences: {},
- placeholders: {
- isLoading
- }
- },
- payments: {
- wallet: {
- userMethods: pot.some([])
- }
- }
- }
- })
- );
+ const store: ReturnType = mockStore(globalState);
- return {
- component: renderScreenWithNavigationStoreContext(
- WalletHomeScreen,
- ROUTES.WALLET_HOME,
- {},
- store
- ),
+ return renderScreenWithNavigationStoreContext(
+ WalletHomeScreen,
+ ROUTES.WALLET_HOME,
+ {},
store
- };
+ );
};
diff --git a/ts/features/wallet/store/reducers/preferences.ts b/ts/features/wallet/store/reducers/preferences.ts
index 49cf5f2c708..01b39b1dc87 100644
--- a/ts/features/wallet/store/reducers/preferences.ts
+++ b/ts/features/wallet/store/reducers/preferences.ts
@@ -1,9 +1,17 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
-import { PersistConfig, persistReducer } from "redux-persist";
+import _ from "lodash";
+import {
+ MigrationManifest,
+ PersistConfig,
+ PersistedState,
+ createMigrate,
+ persistReducer
+} from "redux-persist";
import { getType } from "typesafe-actions";
import { Action } from "../../../../store/actions/types";
-import { walletSetCategoryFilter } from "../actions/preferences";
+import { isDevEnv } from "../../../../utils/environment";
import { WalletCardCategoryFilter } from "../../types";
+import { walletSetCategoryFilter } from "../actions/preferences";
export type WalletPreferencesState = {
categoryFilter?: WalletCardCategoryFilter;
@@ -25,12 +33,20 @@ const reducer = (
return state;
};
-const CURRENT_REDUX_WALLET_PREFERENCES_STORE_VERSION = -1;
+const CURRENT_REDUX_WALLET_PREFERENCES_STORE_VERSION = 0;
+
+const migrations: MigrationManifest = {
+ // Removed categoryFilter persistance requirement
+ "0": (state: PersistedState): PersistedState =>
+ _.set(state, "preferences", {})
+};
const persistConfig: PersistConfig = {
key: "walletPreferences",
storage: AsyncStorage,
- version: CURRENT_REDUX_WALLET_PREFERENCES_STORE_VERSION
+ version: CURRENT_REDUX_WALLET_PREFERENCES_STORE_VERSION,
+ blacklist: ["categoryFilter"],
+ migrate: createMigrate(migrations, { debug: isDevEnv })
};
export const walletReducerPersistor = persistReducer<
diff --git a/ts/features/wallet/store/selectors/__tests__/index.test.ts b/ts/features/wallet/store/selectors/__tests__/index.test.ts
index bf524fdbf2d..c1030f3dc6d 100644
--- a/ts/features/wallet/store/selectors/__tests__/index.test.ts
+++ b/ts/features/wallet/store/selectors/__tests__/index.test.ts
@@ -1,10 +1,14 @@
-import * as O from "fp-ts/lib/Option";
import * as pot from "@pagopa/ts-commons/lib/pot";
+import * as O from "fp-ts/lib/Option";
import _ from "lodash";
import {
+ isWalletCategoryFilteringEnabledSelector,
isWalletEmptySelector,
selectWalletCards,
+ selectWalletCardsByCategory,
+ selectWalletCardsByType,
selectWalletCategories,
+ shouldRenderWalletCategorySelector,
shouldRenderWalletEmptyStateSelector
} from "..";
import { applicationChangeState } from "../../../../../store/actions/application";
@@ -15,9 +19,25 @@ import {
} from "../../../../itwallet/common/utils/itwMocksUtils";
import { ItwLifecycleState } from "../../../../itwallet/lifecycle/store/reducers";
import * as itwLifecycleSelectors from "../../../../itwallet/lifecycle/store/selectors";
+import { walletCardCategoryFilters } from "../../../types";
import { WalletCardsState } from "../../reducers/cards";
-const T_CARDS: WalletCardsState = {
+const T_ITW_CARDS: WalletCardsState = {
+ "4": {
+ key: "4",
+ category: "itw",
+ type: "itw",
+ credentialType: CredentialType.DRIVING_LICENSE
+ },
+ "5": {
+ key: "5",
+ category: "itw",
+ type: "itw",
+ credentialType: CredentialType.EUROPEAN_HEALTH_INSURANCE_CARD
+ }
+};
+
+const T_OTHER_CARDS: WalletCardsState = {
"1": {
key: "1",
category: "payment",
@@ -40,21 +60,14 @@ const T_CARDS: WalletCardsState = {
key: "3",
category: "cgn",
type: "cgn"
- },
- "4": {
- key: "4",
- category: "itw",
- type: "itw",
- credentialType: CredentialType.DRIVING_LICENSE
- },
- "5": {
- key: "5",
- category: "itw",
- type: "itw",
- credentialType: CredentialType.EUROPEAN_HEALTH_INSURANCE_CARD
}
};
+const T_CARDS: WalletCardsState = {
+ ...T_ITW_CARDS,
+ ...T_OTHER_CARDS
+};
+
describe("selectWalletCards", () => {
it("should return the correct cards", () => {
const globalState = appReducer(undefined, applicationChangeState("active"));
@@ -128,6 +141,34 @@ describe("selectWalletCategories", () => {
});
});
+describe("selectWalletCardsByType", () => {
+ it("should return the correct cards", () => {
+ const globalState = appReducer(undefined, applicationChangeState("active"));
+
+ const cards = selectWalletCardsByType(
+ _.set(globalState, "features.wallet", {
+ cards: T_CARDS
+ }),
+ "idPay"
+ );
+ expect(cards).toEqual([T_CARDS["2"]]);
+ });
+});
+
+describe("selectWalletCardsByCategory", () => {
+ it("should return the correct cards", () => {
+ const globalState = appReducer(undefined, applicationChangeState("active"));
+
+ const cards = selectWalletCardsByCategory(
+ _.set(globalState, "features.wallet", {
+ cards: T_CARDS
+ }),
+ "itw"
+ );
+ expect(cards).toEqual([T_CARDS["4"], T_CARDS["5"]]);
+ });
+});
+
describe("isWalletEmptySelector", () => {
it("should return true if there are no categories to display", () => {
const globalState = appReducer(undefined, applicationChangeState("active"));
@@ -220,3 +261,108 @@ describe("shouldRenderWalletEmptyStateSelector", () => {
}
);
});
+
+describe("isWalletCategoryFilteringEnabledSelector", () => {
+ it("should return true if the categories are ['itw', 'other']", () => {
+ const globalState = appReducer(undefined, applicationChangeState("active"));
+
+ const isWalletCategoryFilteringEnabled =
+ isWalletCategoryFilteringEnabledSelector(
+ _.merge(
+ globalState,
+ _.set(globalState, "features.wallet", {
+ cards: T_CARDS
+ })
+ )
+ );
+
+ expect(isWalletCategoryFilteringEnabled).toBe(true);
+ });
+
+ it("should return false if the categories are ['itw']", () => {
+ const globalState = appReducer(undefined, applicationChangeState("active"));
+
+ const isWalletCategoryFilteringEnabled =
+ isWalletCategoryFilteringEnabledSelector(
+ _.merge(
+ globalState,
+ _.set(globalState, "features.wallet", {
+ cards: T_ITW_CARDS
+ })
+ )
+ );
+
+ expect(isWalletCategoryFilteringEnabled).toBe(false);
+ });
+});
+
+describe("shouldRenderWalletCategorySelector", () => {
+ it("should return true if the category filter is undefined", () => {
+ const globalState = appReducer(undefined, applicationChangeState("active"));
+
+ const shouldRenderWalletCategory = shouldRenderWalletCategorySelector(
+ _.merge(
+ globalState,
+ _.set(globalState, "features.wallet", {
+ cards: T_CARDS,
+ preferences: {
+ categoryFilter: undefined
+ }
+ })
+ ),
+ "itw"
+ );
+
+ expect(shouldRenderWalletCategory).toBe(true);
+ });
+
+ it.each(walletCardCategoryFilters)(
+ "should return true if the category filter matches the given category when the category is %s",
+ categoryFilter => {
+ const globalState = appReducer(
+ undefined,
+ applicationChangeState("active")
+ );
+
+ const shouldRenderWalletCategory = shouldRenderWalletCategorySelector(
+ _.merge(
+ globalState,
+ _.set(globalState, "features.wallet", {
+ cards: T_CARDS,
+ preferences: {
+ categoryFilter
+ }
+ })
+ ),
+ categoryFilter
+ );
+
+ expect(shouldRenderWalletCategory).toBe(true);
+ }
+ );
+
+ it.each(walletCardCategoryFilters)(
+ "should return true if the category filtering is not enabled and the category filter is %s",
+ categoryFilter => {
+ const globalState = appReducer(
+ undefined,
+ applicationChangeState("active")
+ );
+
+ const shouldRenderWalletCategory = shouldRenderWalletCategorySelector(
+ _.merge(
+ globalState,
+ _.set(globalState, "features.wallet", {
+ cards: T_ITW_CARDS,
+ preferences: {
+ categoryFilter
+ }
+ })
+ ),
+ categoryFilter
+ );
+
+ expect(shouldRenderWalletCategory).toBe(true);
+ }
+ );
+});
diff --git a/ts/features/wallet/store/selectors/index.ts b/ts/features/wallet/store/selectors/index.ts
index 0fc70d8a3fd..5ee212b0cce 100644
--- a/ts/features/wallet/store/selectors/index.ts
+++ b/ts/features/wallet/store/selectors/index.ts
@@ -1,35 +1,31 @@
import * as pot from "@pagopa/ts-commons/lib/pot";
import { createSelector } from "reselect";
import { GlobalState } from "../../../../store/reducers/types";
+import { isSomeLoadingOrSomeUpdating } from "../../../../utils/pot";
import { cgnDetailSelector } from "../../../bonus/cgn/store/reducers/details";
import { idPayWalletInitiativeListSelector } from "../../../idpay/wallet/store/reducers";
import { itwLifecycleIsValidSelector } from "../../../itwallet/lifecycle/store/selectors";
import { paymentsWalletUserMethodsSelector } from "../../../payments/wallet/store/selectors";
-import { WalletCard, walletCardCategories } from "../../types";
-import { isSomeLoadingOrSomeUpdating } from "../../../../utils/pot";
-
-const selectWalletFeature = (state: GlobalState) => state.features.wallet;
-
-export const selectWalletPlaceholders = createSelector(
- selectWalletFeature,
- wallet =>
- Object.entries(wallet.placeholders.items).map(
- ([key, category]) =>
- ({ key, category, type: "placeholder" } as WalletCard)
- )
-);
+import {
+ WalletCard,
+ WalletCardCategory,
+ WalletCardType,
+ walletCardCategories
+} from "../../types";
+import { WalletCardCategoryFilter } from "../../types/index";
/**
* Returns the list of cards excluding hidden cards
*/
export const selectWalletCards = createSelector(
- selectWalletFeature,
- ({ cards }) => Object.values(cards).filter(({ hidden }) => !hidden)
+ (state: GlobalState) => state.features.wallet.cards,
+ cards => Object.values(cards).filter(({ hidden }) => !hidden)
);
/**
* Returns the list of card categories available in the wallet
* If there are categories other that ITW, they will become "other"
+ * If the ITW is valid, it will be counted as "itw" category, since we do not have eID card anymore
*/
export const selectWalletCategories = createSelector(
selectWalletCards,
@@ -66,47 +62,58 @@ export const selectSortedWalletCards = createSelector(
);
/**
- * Only gets cards which are part of the IT Wallet
+ * Selects the cards by their category
+ * @param category - The category of the cards to select
*/
-export const selectWalletItwCards = createSelector(
+export const selectWalletCardsByCategory = createSelector(
selectSortedWalletCards,
- cards => cards.filter(({ category }) => category === "itw")
+ (_: GlobalState, category: WalletCardCategory) => category,
+ (cards, category) =>
+ cards.filter(({ category: cardCategory }) => cardCategory === category)
);
/**
- * Only gets cards which are not part of the IT Wallet
+ * Selects the cards by their type
+ * @param type - The type of the cards to select
*/
-export const selectWalletOtherCards = createSelector(
+export const selectWalletCardsByType = createSelector(
selectSortedWalletCards,
- cards => cards.filter(({ category }) => category !== "itw")
+ (_: GlobalState, type: WalletCardType) => type,
+ (cards, type) => cards.filter(({ type: cardType }) => cardType === type)
);
-export const selectIsWalletCardsLoading = (state: GlobalState) =>
- state.features.wallet.placeholders.isLoading;
-
-export const selectWalletCategoryFilter = createSelector(
- selectWalletFeature,
- wallet => wallet.preferences.categoryFilter
-);
-
-export const selectWalletPaymentMethods = createSelector(
+/**
+ * Currently, if a card is not part of the IT Wallet, it is considered as "other"
+ * This selector returns the cards which are not part of the IT Wallet which must be displayed in the "other" section
+ */
+export const selectWalletOtherCards = createSelector(
selectSortedWalletCards,
- cards => cards.filter(({ category }) => category === "payment")
+ cards => cards.filter(({ category }) => category !== "itw")
);
-export const selectWalletCgnCard = createSelector(
- selectSortedWalletCards,
- cards => cards.filter(({ category }) => category === "cgn")
-);
+/**
+ * Selects the loading state of the wallet cards
+ */
+export const selectIsWalletLoading = (state: GlobalState) =>
+ state.features.wallet.placeholders.isLoading;
-export const selectBonusCards = createSelector(selectSortedWalletCards, cards =>
- cards.filter(({ category }) => category === "bonus")
+/**
+ * Selects the placeholders from the wallet
+ */
+export const selectWalletPlaceholderCards = createSelector(
+ (state: GlobalState) => state.features.wallet.placeholders.items,
+ placeholders =>
+ Object.entries(placeholders).map(
+ ([key, category]) =>
+ ({ key, category, type: "placeholder" } as WalletCard)
+ )
);
/**
* Gets if the wallet can be considered empty.
- * The wallet is empty if there are no categories to display
- * @see selectWalletCategories
+ * The wallet is empty if there are no categories to display (@see selectWalletCategories)
+ *
+ * Note: we check categories because if ITW is valid, it is considered as one category even if there are no cards
*/
export const isWalletEmptySelector = (state: GlobalState) =>
selectWalletCategories(state).size === 0;
@@ -127,3 +134,32 @@ export const isWalletScreenRefreshingSelector = (state: GlobalState) =>
isSomeLoadingOrSomeUpdating(paymentsWalletUserMethodsSelector(state)) ||
isSomeLoadingOrSomeUpdating(idPayWalletInitiativeListSelector(state)) ||
isSomeLoadingOrSomeUpdating(cgnDetailSelector(state));
+
+/**
+ * Selects if the wallet categories can be filtered.
+ * The filter is only enabled if there are more than one category available
+ */
+export const isWalletCategoryFilteringEnabledSelector = createSelector(
+ selectWalletCategories,
+ categories => categories.size > 1
+);
+
+/**
+ * Selects the category filter from the wallet preferences
+ */
+export const selectWalletCategoryFilter = (state: GlobalState) =>
+ state.features.wallet.preferences.categoryFilter;
+
+/**
+ * Checks if a wallet category section should be rendered. A category section is rendered if:
+ * - the category filtering is not enabled, or
+ * - no category filter is selected, or
+ * - the filter matches the given category
+ */
+export const shouldRenderWalletCategorySelector = createSelector(
+ isWalletCategoryFilteringEnabledSelector,
+ selectWalletCategoryFilter,
+ (_: GlobalState, category: WalletCardCategoryFilter) => category,
+ (isFilteringEnabled, filter, category) =>
+ !isFilteringEnabled || filter === undefined || filter === category
+);
diff --git a/ts/features/wallet/utils/__tests__/index.test.tsx b/ts/features/wallet/utils/__tests__/index.test.tsx
new file mode 100644
index 00000000000..534d6e66d93
--- /dev/null
+++ b/ts/features/wallet/utils/__tests__/index.test.tsx
@@ -0,0 +1,40 @@
+import { Body } from "@pagopa/io-app-design-system";
+import * as React from "react";
+import configureMockStore from "redux-mock-store";
+import { withWalletCategoryFilter } from "..";
+import ROUTES from "../../../../navigation/routes";
+import { applicationChangeState } from "../../../../store/actions/application";
+import { appReducer } from "../../../../store/reducers";
+import { GlobalState } from "../../../../store/reducers/types";
+import { renderScreenWithNavigationStoreContext } from "../../../../utils/testWrapper";
+import * as selectors from "../../store/selectors";
+
+describe("withWalletCategoryFilter", () => {
+ it("should return null if the category filter does not match", () => {
+ const WrappedComponent = () => (
+ Hello
+ );
+ const ComponentWithFilter = withWalletCategoryFilter(
+ "itw",
+ WrappedComponent
+ );
+
+ const globalState = appReducer(undefined, applicationChangeState("active"));
+
+ const mockStore = configureMockStore();
+ const store: ReturnType = mockStore(globalState);
+
+ jest
+ .spyOn(selectors, "shouldRenderWalletCategorySelector")
+ .mockImplementation(() => false);
+
+ const { queryByTestId } =
+ renderScreenWithNavigationStoreContext(
+ () => ,
+ ROUTES.WALLET_HOME,
+ {},
+ store
+ );
+ expect(queryByTestId("WrappedComponentTestID")).toBeNull();
+ });
+});
diff --git a/ts/features/wallet/utils/index.tsx b/ts/features/wallet/utils/index.tsx
index e2dad27dfdd..00a11ed90fe 100644
--- a/ts/features/wallet/utils/index.tsx
+++ b/ts/features/wallet/utils/index.tsx
@@ -1,11 +1,14 @@
import * as React from "react";
-import { WalletCard, WalletCardType } from "../types";
+import { WalletCard, WalletCardCategoryFilter, WalletCardType } from "../types";
import { WalletCardBaseComponent } from "../components/WalletCardBaseComponent";
import { CgnWalletCard } from "../../bonus/cgn/components/CgnWalletCard";
import { IdPayWalletCard } from "../../idpay/wallet/components/IdPayWalletCard";
import { PaymentWalletCard } from "../../payments/wallet/components/PaymentWalletCard";
import { WalletCardSkeleton } from "../components/WalletCardSkeleton";
import { ItwCredentialWalletCard } from "../../itwallet/wallet/components/ItwCredentialWalletCard";
+import { shouldRenderWalletCategorySelector } from "../store/selectors";
+import { useIOSelector } from "../../../store/hooks";
+import { GlobalState } from "../../../store/reducers/types";
/**
* Wallet card component mapper which translates a WalletCardType to a
@@ -24,6 +27,12 @@ export const walletCardComponentMapper: Record<
placeholder: WalletCardSkeleton
};
+/**
+ * Function that renders a wallet card using the mapped component inside {@see walletCardComponentMapper}
+ * @param card - The wallet card object to render
+ * @param stacked - Whether the card is stacked or not
+ * @returns The rendered card or null if the card is not found
+ */
export const renderWalletCardFn = (
card: WalletCard,
stacked: boolean = false
@@ -39,3 +48,24 @@ export const renderWalletCardFn = (
/>
) : null;
};
+
+/**
+ * A higher-order component which renders a component only if the category filter matches the given category
+ * @param category - The category to filter by
+ * @param WrappedComponent - The component to render
+ * @returns The component or null if the category filter does not match
+ */
+export const withWalletCategoryFilter =
+ >(
+ category: WalletCardCategoryFilter,
+ WrappedComponent: React.ComponentType
+ ) =>
+ (props: P) => {
+ const shouldRenderCategory = useIOSelector((state: GlobalState) =>
+ shouldRenderWalletCategorySelector(state, category)
+ );
+ if (!shouldRenderCategory) {
+ return null;
+ }
+ return ;
+ };
diff --git a/ts/mixpanelConfig/mixpanelPropertyUtils.ts b/ts/mixpanelConfig/mixpanelPropertyUtils.ts
index 1d0617f2898..19b3fbe8ed8 100644
--- a/ts/mixpanelConfig/mixpanelPropertyUtils.ts
+++ b/ts/mixpanelConfig/mixpanelPropertyUtils.ts
@@ -4,10 +4,7 @@ import { ServicesPreferencesModeEnum } from "../../definitions/backend/ServicesP
import { TrackCgnStatus } from "../features/bonus/cgn/analytics";
import { LoginSessionDuration } from "../features/fastLogin/analytics/optinAnalytics";
import { fastLoginOptInSelector } from "../features/fastLogin/store/selectors";
-import {
- selectBonusCards,
- selectWalletCgnCard
-} from "../features/wallet/store/selectors";
+import { selectWalletCardsByType } from "../features/wallet/store/selectors";
import { WalletCardBonus } from "../features/wallet/types";
import { paymentsWalletUserMethodsSelector } from "../features/payments/wallet/store/selectors";
import {
@@ -91,17 +88,16 @@ export const paymentMethodsHandler = (state: GlobalState): number | undefined =>
paymentsWalletUserMethodsNumberFromPotSelector(state)?.length;
export const cgnStatusHandler = (state: GlobalState): TrackCgnStatus => {
- const cgnCard = selectWalletCgnCard(state);
+ const cgnCard = selectWalletCardsByType(state, "cgn");
return cgnCard.length > 0 ? "active" : "not_active";
};
export const welfareStatusHandler = (
state: GlobalState
): ReadonlyArray => {
- const bonusCards = selectBonusCards(state);
- const idPayCards = bonusCards.filter(
- card => card.type === "idPay"
+ const idPayCards = selectWalletCardsByType(
+ state,
+ "idPay"
) as Array;
-
return idPayCards.map(card => card.name);
};
diff --git a/ts/store/reducers/debug.ts b/ts/store/reducers/debug.ts
index 79b127ba1ac..99c957ee9a4 100644
--- a/ts/store/reducers/debug.ts
+++ b/ts/store/reducers/debug.ts
@@ -1,4 +1,5 @@
import AsyncStorage from "@react-native-async-storage/async-storage";
+import _ from "lodash";
import { PersistConfig, PersistPartial, persistReducer } from "redux-persist";
import { getType } from "typesafe-actions";
import {
@@ -37,7 +38,7 @@ function debugReducer(
case getType(setDebugData):
return {
...state,
- debugData: action.payload
+ debugData: _.merge(state.debugData, action.payload)
};
case getType(resetDebugData):
return {
From f739c1008302f41e5a1b7da9d1466a64699b3ca4 Mon Sep 17 00:00:00 2001
From: Emanuele Dall'Ara <71103219+LeleDallas@users.noreply.github.com>
Date: Mon, 23 Dec 2024 10:47:18 +0100
Subject: [PATCH 8/9] refactor: [IOBP-1091] Paid in app empty state screen
(#6575)
## Short description
This pull request includes updates to localization files and
enhancements to the `ReceiptListScreen` component. The most important
changes is refactoring the empty state logic in the receipt list screen.
## List of changes proposed in this pull request
- Refactored the empty state logic to use a new `emptyProps` object
based on the `noticeCategory`.
- Added `emptyPayer` locale for displaying payment receipts made in the
app.
## How to test
- In `Pagamenti` tap on `Vedi tutte`
- Ensure that the `Pagate in app` tab is display correct empty state
## Preview
https://github.com/user-attachments/assets/8501fe55-1370-4613-9543-b929aa9907d6
---
locales/en/index.yml | 2 +
locales/it/index.yml | 2 +
.../receipts/screens/ReceiptListScreen.tsx | 56 ++++++++++++-------
3 files changed, 40 insertions(+), 20 deletions(-)
diff --git a/locales/en/index.yml b/locales/en/index.yml
index a10530a05a0..703e5bca753 100644
--- a/locales/en/index.yml
+++ b/locales/en/index.yml
@@ -3240,6 +3240,8 @@ features:
empty:
title: Nessuna ricevuta trovata
subtitle: Se stai cercando la ricevuta di un avviso pagoPA che hai pagato in passato, rivolgiti all’ente creditore.
+ emptyPayer:
+ title: Qui vedrai le ricevute dei pagamenti fatti in app
details:
payPal:
banner:
diff --git a/locales/it/index.yml b/locales/it/index.yml
index 3a5cbe020ce..283a728cec9 100644
--- a/locales/it/index.yml
+++ b/locales/it/index.yml
@@ -3240,6 +3240,8 @@ features:
empty:
title: Nessuna ricevuta trovata
subtitle: Se stai cercando la ricevuta di un avviso pagoPA che hai pagato in passato, rivolgiti all’ente creditore.
+ emptyPayer:
+ title: Qui vedrai le ricevute dei pagamenti fatti in app
details:
payPal:
banner:
diff --git a/ts/features/payments/receipts/screens/ReceiptListScreen.tsx b/ts/features/payments/receipts/screens/ReceiptListScreen.tsx
index 95d1f2d51f8..789b1386e7c 100644
--- a/ts/features/payments/receipts/screens/ReceiptListScreen.tsx
+++ b/ts/features/payments/receipts/screens/ReceiptListScreen.tsx
@@ -12,31 +12,39 @@ import Animated, {
useSharedValue
} from "react-native-reanimated";
import { useSafeAreaInsets } from "react-native-safe-area-context";
-import { useIODispatch, useIOSelector } from "../../../../store/hooks";
-import { PaymentsReceiptParamsList } from "../navigation/params";
-import { getPaymentsReceiptAction } from "../store/actions";
-import { walletReceiptListPotSelector } from "../store/selectors";
-import { useIONavigation } from "../../../../navigation/params/AppParamsList";
-import { isPaymentsTransactionsEmptySelector } from "../../home/store/selectors";
-import { ReceiptListItemTransaction } from "../components/ReceiptListItemTransaction";
+import { NoticeListItem } from "../../../../../definitions/pagopa/biz-events/NoticeListItem";
+import {
+ OperationResultScreenContent,
+ OperationResultScreenContentProps
+} from "../../../../components/screens/OperationResultScreenContent";
import { useHeaderSecondLevel } from "../../../../hooks/useHeaderSecondLevel";
-import { useOnFirstRender } from "../../../../utils/hooks/useOnFirstRender";
-import { groupTransactionsByMonth } from "../utils";
import I18n from "../../../../i18n";
-import { PaymentsReceiptRoutes } from "../navigation/routes";
-import { NoticeListItem } from "../../../../../definitions/pagopa/biz-events/NoticeListItem";
+import { useIONavigation } from "../../../../navigation/params/AppParamsList";
+import { useIODispatch, useIOSelector } from "../../../../store/hooks";
+import { useOnFirstRender } from "../../../../utils/hooks/useOnFirstRender";
+import { isPaymentsTransactionsEmptySelector } from "../../home/store/selectors";
import * as analytics from "../analytics";
-import { ReceiptsCategoryFilter } from "../types";
-import { OperationResultScreenContent } from "../../../../components/screens/OperationResultScreenContent";
import { ReceiptFadeInOutAnimationView } from "../components/ReceiptFadeInOutAnimationView";
+import { ReceiptListItemTransaction } from "../components/ReceiptListItemTransaction";
import { ReceiptLoadingList } from "../components/ReceiptLoadingList";
import { ReceiptSectionListHeader } from "../components/ReceiptSectionListHeader";
+import { PaymentsReceiptParamsList } from "../navigation/params";
+import { PaymentsReceiptRoutes } from "../navigation/routes";
+import { getPaymentsReceiptAction } from "../store/actions";
+import { walletReceiptListPotSelector } from "../store/selectors";
+import { ReceiptsCategoryFilter } from "../types";
+import { groupTransactionsByMonth } from "../utils";
export type ReceiptListScreenProps = RouteProp<
PaymentsReceiptParamsList,
"PAYMENT_RECEIPT_DETAILS"
>;
+type OperationResultEmptyProps = Pick<
+ OperationResultScreenContentProps,
+ "title" | "subtitle" | "pictogram"
+>;
+
const AnimatedSectionList = Animated.createAnimatedComponent(
SectionList as new () => SectionList
);
@@ -59,7 +67,6 @@ const ReceiptListScreen = () => {
const transactionsPot = useIOSelector(walletReceiptListPotSelector);
const isEmpty = useIOSelector(isPaymentsTransactionsEmptySelector);
-
const isLoading = pot.isLoading(transactionsPot);
const handleNavigateToTransactionDetails = (transaction: NoticeListItem) => {
@@ -163,14 +170,23 @@ const ReceiptListScreen = () => {
>
);
+ const emptyProps: OperationResultEmptyProps =
+ noticeCategory === "payer"
+ ? {
+ title: I18n.t("features.payments.transactions.list.emptyPayer.title"),
+ pictogram: "empty"
+ }
+ : {
+ title: I18n.t("features.payments.transactions.list.empty.title"),
+ subtitle: I18n.t(
+ "features.payments.transactions.list.empty.subtitle"
+ ),
+ pictogram: "emptyArchive"
+ };
+
const EmptyStateList = isEmpty ? (
-
+
) : undefined;
From 80d7bd563c8810002384c28a4677de923403bbd2 Mon Sep 17 00:00:00 2001
From: Daniel Hinterlechner <43072243+dhinterlechner@users.noreply.github.com>
Date: Mon, 23 Dec 2024 21:26:45 +0100
Subject: [PATCH 9/9] =?UTF-8?q?=F0=9F=87=A9=F0=9F=87=AA=20updates=20(#6578?=
=?UTF-8?q?)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
locales/de/index.yml | 611 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 576 insertions(+), 35 deletions(-)
diff --git a/locales/de/index.yml b/locales/de/index.yml
index b21a5e836c7..8a179fe8536 100644
--- a/locales/de/index.yml
+++ b/locales/de/index.yml
@@ -58,6 +58,7 @@ date:
- "am"
- "pm"
global:
+ why: "Warum?"
you: "DU"
id: "ID"
badges:
@@ -1090,7 +1091,7 @@ payment:
IUV: "IUV"
IUV_extended: "Einheitlicher Zahlungskodex (IUV)"
notice: "Zahlungsmitteilung"
- noticeCode: "Zahlungskodex"
+ noticeCode: "Zahlungsmitteilungskodex"
recipientFiscalCode: "Steuernummer des Empfängers"
paidConfirm: "Du hast {{amount}} gezahlt"
details:
@@ -1554,7 +1555,7 @@ wallet:
title: "Was möchtest du bezahlen?"
info: "Gib die Daten ein, die auf der Zahlungsmitteilung angegeben sind."
link: "Wo finde ich die Daten?"
- noticeCode: "Zahlungskodex"
+ noticeCode: "Zahlungsmitteilungskodex"
entityCode: "Steuernummer der Körperschaft"
amount: "Betrag (€)"
proceed: "Mit der Transaktion fortfahren"
@@ -1678,7 +1679,7 @@ wallet:
chooser: "Bild aus der Galerie wählen"
wrongQrCode: "QR-Code nicht gültig. Gib die Daten manuell ein."
byCameraTitle: "QR-Code scannen"
- cameraUsageInfo: "Scanne den QR-Code der Zahlungsmitteilung oder gib die Daten (Zahlungskodex und Steuernummer Körperschaft) manuell ein"
+ cameraUsageInfo: "Scanne den QR-Code der Zahlungsmitteilung oder gib die Daten (Zahlungsmitteilungskodex und Steuernummer Körperschaft) manuell ein"
setManually: "Manuell eingeben"
enroll_cta: "Um den QR-Code auf der Zahlungsmitteilung zu scannen, musst du IO zunächst erlauben, die Kamera zu verwenden. Du kannst dies über das Menü 'Einstellungen' deines Geräts tun."
readStorageDisclosure:
@@ -1794,12 +1795,14 @@ wallet:
title: "Es wurden mehrere Codes entdeckt. Welchen möchtest du verwenden?"
manual:
noticeNumber:
- title: "Gib den Zahlungskodex ein"
+ title: "Gib den Zahlungsmitteilungskodex ein"
subtitle: "Er hat 18 Ziffern und ist neben dem QR-Code zu finden."
- placeholder: "Zahlungskodex"
+ validationError: "18 Ziffern, die mit 0, 1 oder 3 beginnen."
+ placeholder: "Zahlungsmitteilungskodex"
fiscalCode:
title: "Gib die Steuernummer der Körperschaft ein"
subtitle: "Sie hat 11 Ziffern und ist neben dem QR-Code zu finden."
+ validationError: "11 Ziffern eingeben."
placeholder: "Steuernummer der Körperschaft"
abortDialog:
title: "Möchtest du den Vorgang abbrechen?"
@@ -1907,6 +1910,40 @@ wallet:
METHOD_NOT_ENABLED:
title: "Zahlungsmethode in der App aktivieren"
subtitle: "Bevor du die Zahlung erneut versuchst, wähle die Zahlungsmethode in deinem Konto aus und aktiviere die Funktion 'In-App-Zahlungen'."
+ PAYMENT_METHODS_NOT_AVAILABLE:
+ title: "Möchtest du mit Karte bezahlen? Füge sie jetzt hinzu!"
+ subtitle: "Die Methode wird im Konto gespeichert, so dass du beim nächsten Mal einfacher bezahlen kannst."
+ primaryAction: "Karte hinzufügen"
+ secondaryAction: "Andere Methoden verwenden"
+ PAYMENT_REVERSED:
+ title: "Die Zahlung ist fehlgeschlagen"
+ subtitle: "Der autorisierte Betrag wurde auf deine Zahlungsmethode zurücküberwiesen. Die Überweisung kann einige Zeit dauern."
+ primaryAction: "Mehr erfahren"
+ secondaryAction: "Schließen"
+ PAYPAL_REMOVED_ERROR:
+ title: "Autorisierung abgelehnt"
+ subtitle: "Möglicherweise hast du pagoPA von automatischen PayPal-Zahlungen ausgeschlossen. Lösche das PayPal-Konto aus deinem Konto, füge es wieder hinzu und versuche erneut, die Zahlung durchzuführen."
+ IN_APP_BROWSER_CLOSED_BY_USER:
+ title: "Du hast die Zahlung abgebrochen"
+ subtitle: "Überprüfe das Ergebnis im Tab Zahlungen. Wenn du eine Zahlung vornehmen möchtest, warte bitte mindestens 15 Minuten, bevor du es erneut versuchst."
+ INSUFFICIENT_AVAILABILITY_ERROR:
+ title: "Dein Guthaben auf der Karte ist nicht ausreichend."
+ subtitle: "Es wurde kein Betrag abgebucht. Bevor du es erneut versuchst, lade die Karte auf oder verwende eine andere Zahlungsmethode."
+ CVV_ERROR:
+ title: "Der eingegebene Sicherheitscode ist falsch"
+ subtitle: "Es wurde kein Betrag abgebucht. Der Code (CVV oder CVC) ist 3-stellig und befindet sich auf der Rückseite der Karte. Bei American Express hat der Code (CID) 4 Ziffern und befindet sich auf der Vorderseite."
+ PLAFOND_LIMIT_ERROR:
+ title: "Du hast das Ausgabenlimit deiner Karte überschritten"
+ subtitle: "Es wurde kein Betrag abgebucht. Bevor du es erneut versuchst, ändere das Ausgabenlimit oder verwende eine andere Zahlungsmethode."
+ BE_NODE_KO:
+ title: "Wir haben Probleme mit den Zahlungssystemen"
+ subtitle: "Überprüfe das Ergebnis der Zahlung im Tab Zahlungen, andernfalls warte einige Minuten, bevor du es erneut versuchst."
+ PSP_ERROR:
+ title: "Die Zahlung ist fehlgeschlagen"
+ subtitle: "Es wurde kein Betrag abgebucht. Sollte das Problem weiterhin bestehen, versuche es mit einer anderen Methode oder einem anderen Zahlungsanbieter."
+ AUTH_REQUEST_ERROR:
+ title: "Wir haben Probleme mit den Zahlungssystemen"
+ subtitle: "Versuche es später erneut."
support:
button: "Support kontaktieren"
supportTitle: "Support kontaktieren"
@@ -1915,7 +1952,7 @@ wallet:
additionalDataTitle: "Zusätzliche Daten"
copyAll: "Alles kopieren"
errorCode: "Fehlercode"
- noticeNumber: "Zahlungskodex"
+ noticeNumber: "Zahlungsmitteilungskodex"
entityCode: "Steuernummer Körperschaft"
saveCard:
saveCard: "Karte speichern"
@@ -1946,6 +1983,7 @@ messages:
description: "{{newMessage}}, erhalten von {{organizationName}}, {{serviceName}}. {{subject}}. {{receivedAt}}. {{state}}"
received_on: "erhalten am"
received_at: "erhalten um"
+ selected: "ausgewählt"
contextualHelpTitle: "Mitteilungen verwenden"
counting:
one: "Du hast eine Mitteilung"
@@ -1990,6 +2028,8 @@ messages:
reminderRemoveFailure: "Fehler beim Entfernen der Erinnerung, bitte versuche es erneut"
preferenceCalendarSelect: "Wähle deinen Standardkalender"
calendarPermDenied:
+ title: "Zugriff zulassen"
+ description: "Wir haben keinen Zugriff auf deinen Kalender. Bitte aktiviere die Berechtigungen, um fortzufahren."
ok: "Berechtigungen freigeben"
cancel: "Abbrechen"
errors:
@@ -2012,9 +2052,19 @@ messages:
archive:
success: "Erfolgreich archiviert!"
failure: "Die Archivierung ist fehlgeschlagen"
+ generic:
+ failure: "Der Vorgang ist fehlgeschlagen"
+ success: "Vorgang erfolgreich!"
restore:
success: "Wiederherstellung durchgeführt."
failure: "Die Wiederherstellung ist fehlgeschlagen"
+ search:
+ emptyState:
+ title: "Mindestens drei Zeichen eingeben"
+ input:
+ cancel: "Abbrechen"
+ clear: "Löschen"
+ placeholderShort: "Text eingeben"
messageDetails:
accessibilityAttachmentIcon: "Enthält Anhänge"
contextualHelpTitle: "Mitteilungsdetails"
@@ -2052,6 +2102,11 @@ messageDetails:
bottomSheet:
title: "Was ist eine dynamische Mitteilung?"
body: "Die versendende Körperschaft kann den Inhalt dieser Nachricht auch nach dem Versand aktualisieren, um sicherzustellen, dass die Informationen stets korrekt und relevant sind.\n\n Dies geschieht in bestimmten Fällen, wie z. B. bei der Aktualisierung veralteter Informationen oder nicht mehr gültiger Anhänge.\n\n Wenn die Körperschaft dich über neue Informationen oder wichtige Aktualisierungen informieren muss, wird sie dies mittels einer neuen Mitteilung tun."
+ bodyPt1: "Es handelt sich um eine Mitteilung, die die Körperschaft "
+ bodyPt2: "nach dem Senden ändern kann"
+ bodyPt3: ". Auf diese Weise sind die darin enthaltenen Informationen immer korrekt.\nEine Körperschaft kann die Informationen in einer dynamischen Mitteilung "
+ bodyPt4: "nur in bestimmten Fällen"
+ bodyPt5: " ändern, zum Beispiel um alte Informationen zu ändern oder eine nicht mehr gültige Anlage zu aktualisieren.\nWenn sie dir neue Informationen oder wichtige Aktualisierungen mitteilen muss, schickt sie dir eine neue Mitteilung."
footer:
contacts: "Absender kontaktieren"
showMoreData: "Mehr anzeigen"
@@ -2060,8 +2115,8 @@ messageDetails:
messageId: "MitteilungsID"
messageIdAccessibility: "MitteilungsID kopieren"
pagoPAHeader: "pagoPA Zahlungsmitteilung"
- noticeCode: "Zahlungskodex"
- noticeCodeAccessibility: "Zahlungskodex, kopieren"
+ noticeCode: "Zahlungsmitteilungskodex"
+ noticeCodeAccessibility: "Zahlungsmitteilungskodex, kopieren"
entityFiscalCode: "Steuernummer Körperschaft"
entityFiscalCodeAccessibility: "Steuernummer Körperschaft, kopieren"
contactsBottomSheet:
@@ -2089,9 +2144,17 @@ messagePDFPreview:
opening: "Beim Öffnen des Dokuments ist ein Fehler aufgetreten. Möglicherweise hast du keine PDF-App installiert."
saving: "Beim Speichern des Dokuments ist ein Fehler aufgetreten."
notifications:
+ profileBanner:
+ title: "Aktiviere Push-Benachrichtigungen, damit du weißt, wenn du eine Mitteilung auf IO erhältst."
+ cta: "Push-Benachrichtigungen aktivieren"
installation:
errorTitle: "Push-Benachrichtigungen"
errorMessage: "Bei der Registrierung des Push-Benachrichtigungsdienstes ist ein Fehler unterlaufen"
+ modal:
+ content: "Aktiviere Push-Benachrichtigungen, um sofort zu erfahren, wenn du eine neue Mitteilung in der App erhältst."
+ primaryButton: "Push-Benachrichtigungen aktivieren"
+ secondaryButton: "Jetzt nicht"
+ title: "Verpasse keine wichtigen Mitteilungen!"
biometric_recognition:
contextualHelpTitle: "So funktioniert die biometrische Erkennung"
switchLabel: "Biometrische Erkennung aktiveren"
@@ -2100,6 +2163,10 @@ biometric_recognition:
needed_to_disable: "Bestätigung zur Deaktivierung erforderlich"
send_email_messages:
title: "Mitteilungen mittels E-Mail weiterleiten"
+ subtitle: "Möchtest du, dass IO eine Vorschau der Mitteilung an die E-Mail-Adresse sendet:"
+ switch:
+ title: "Eine Vorschau per E-Mail senden"
+ subtitle: "Du erhältst eine Vorschau der Mitteilung an deine E-Mail-Adresse, sofern der Dienst dies zulässt."
services:
optIn:
preferences:
@@ -2150,7 +2217,7 @@ services:
title: "Hervorgehobene Körperschaften"
institutions:
title: "National"
- searchLink: "Suche nach allen verfügbaren lokalen Diensten"
+ searchLink: "Suche nach allen verfügbaren Diensten"
institution:
failure:
title: "Es liegt ein vorübergehendes Problem vor, bitte versuche es erneut"
@@ -2209,6 +2276,7 @@ identification:
congiunction: "oder"
title: "Hallo {{name}}!"
titleProfileName: "Hallo {{profileName}}!"
+ titleValidation: "Vorgang genehmigen"
logout: "Abmelden"
logoutProfileName: "Du bist nicht {{profileName}}?"
logoutDescription: "Du kannst dich mit deinem SPID oder deiner CIE anmelden. Diese Sitzung wird abgemeldet."
@@ -2253,6 +2321,7 @@ openMaps:
genericError: "Ein Fehler ist aufgetreten"
titleUpdateApp: "Aktualisiere IO!"
msgErrorUpdateApp: "Beim Öffnen des App-Stores ist ein Fehler aufgetreten"
+messageUpdateApp: "IO führt häufig kleine Verbesserungen und neue Funktionen ein: Um die App weiterhin nutzen zu können, ist es notwendig, sie auf die neueste Version zu aktualisieren."
titleUpdateAppAlert: "Um fortzufahren, aktualisiere IO"
messageUpdateAppAlert: "Es ist eine neue Version von IO auf {{storeName}} verfügbar, aktualisiere sie, um diese Funktion zu nutzen."
openStore: "Öffne {{storeName}}"
@@ -2299,20 +2368,37 @@ bonus:
code: "Durch Tippen auf das Elements wird der Code kopiert"
name: "Nationale Jugendkarte"
departmentName: "Präsidium des italienischen Ministerrates, Abteilung für Jugendpolitik und Zivildienst"
+ merchantSearch:
+ goToSearchAccessibilityLabel: "Zur Suche der Teilnehmer gehen"
+ emptyList:
+ shortQuery:
+ titleWithCount: "Suche unter {{merchantCount}} Partnern der Nationalen Jugendkarte"
+ titleWithoutCount: "Suche bei den Partnern der Nationalen Jugendkarte"
+ noResults:
+ title: "Wir haben nichts gefunden"
+ subtitle: "Versuche, mit anderen Begriffen zu suchen.\nWenn du nicht fündig wirst, ist der Partner möglicherweise nicht beigetreten oder hat keine aktiven Angebote."
+ input:
+ placeholder: "Suchen"
+ cancel: "Abbrechen"
+ clear: "Löschen"
merchantsList:
news: "Neu"
online: "Online"
places: "Orte"
navigationTitle: "Rabatte und Ermäßigungen"
- screenTitle: Scopri le opportunità
- merchantsAll: Tutti i partner
+ screenTitle: "Alle Vorteile entdecken"
+ merchantsAll: "Alle Partner"
tabs:
- perInitiative: Per categoria
- perMerchant: Per partner
+ perInitiative: "Nach Kategorie"
+ perMerchant: "Nach Partner"
cta:
filter: "Filtern"
categoriesList:
title: "Wähle eine Kategorie und entdecke Rabatte und Ermäßigungen"
+ bottomSheet:
+ cta: "Wie sind die Kategorien angeordnet?"
+ title: "Wie sind die Kategorien angeordnet?"
+ content: "Um deine Suche zu erleichtern und deine Erfahrung zu verbessern, haben wir die Kategorien nach der Häufigkeit der Nutzung geordnet. Diese Informationen sind nicht mit deinem Profil verknüpft, sondern beruhen auf den Gesamtdaten aller Nutzer, die die Nationale Jugendkarte nutzen und der Verarbeitung ihrer Daten zugestimmt haben."
filter:
title: "Anbieter filtern"
searchTitle: "Suche nach Name"
@@ -2334,11 +2420,11 @@ bonus:
byName: "Alphabetisch geordnet"
merchantDetail:
title:
- deals: Opportunità
+ deals: "Vorteil"
description: "Beschreibung"
contactInfo: "Adressen"
cta:
- website: Vai al sito del partner
+ website: "Geh zur Webseite des Partners"
categories:
counting: "und weitere {{count}}"
cultureAndEntertainment: "Kultur und Freizeit"
@@ -2351,20 +2437,39 @@ bonus:
travel: "Reisen und Transport"
mobility: "Nachhaltige Mobilität"
job: "Jobs und Ausbildungsplätze"
+ information:
+ address: "Adresse"
+ allNational: "Alle landesweiten Verkaufsstellen"
+ discount:
+ description: "Beschreibung"
+ conditions: "Bedingungen"
+ validity: "Gültigkeit"
+ cta:
+ api: "Rabattcode aktivieren"
+ static: "Zum Rabattcode"
+ bucket: "Zum Rabattcode"
+ landingpage: "Zum Rabatt gehen"
+ createNew: "Neuer Rabattcode"
+ secondaryCta: "Zum Rabatt gehen"
+ title: "Hier ist der Rabattcode!"
+ expired: "Der Code ist abgelaufen"
+ copyButton: "Rabattcode kopieren"
+ error: "Zurzeit ist es nicht möglich, einen Code zu generieren."
cta:
- activeBonus: Attiva Carta Giovani Nazionale
- back: Non ora
+ activeBonus: "Nationale Jugendkarte aktivieren"
+ back: "Jetzt nicht"
deactivateBonus: "Aus dem Konto entfernen"
- goToDetail: Usa la Carta
+ goToDetail: "Karte benützen"
detail:
cta:
- buyers: Scopri le opportunità CGN
+ buyers: "CGN-Vorteile entdecken"
+ discover: "Vorteile entdecken"
otp: "Code generieren"
eyca:
copy: "EYCA Kartennummer kopieren"
- pending: Scopri le opportunità EYCA
+ pending: "EYCA-Vorteile entdecken"
bottomSheet: "Besuche die EYCA Website"
- showEycaDiscounts: Scopri le opportunità EYCA
+ showEycaDiscounts: "EYCA-Vorteile entdecken"
information:
active: "Die Karte ist aktiv und kann bis zum {{date}} verwendet werden."
warning: "Achtung! "
@@ -2378,19 +2483,20 @@ bonus:
eycaNumber: "Kartennummer"
eycaPending: "Wir verknüpfen deine nationale Jugendkarte mit einer EYCA Nummer."
eycaError: "Wir hatten Probleme mit den EYCA Systemen."
- eycaBottomSheetTitle: "Cos’è il circuito EYCA?"
- eycaDescription: "Fino al compimento dei 31 anni, **la tua Carta Giovani Nazionale aderisce al circuito EYCA** (European Youth Card Association).\n\nPuoi usare la Carta presso i partner aderenti, per usufruire delle opportunità disponibili per attività culturali, negozi, trasporti, ristorazione e alloggio anche nei paesi europei aderenti al circuito."
+ eycaBottomSheetTitle: "Was ist EYCA?"
+ eycaDescription: "Bis zum Alter von 31 Jahren ist **deine Nationale Jugendkarte Mitglied der EYCA** (European Youth Card Association).\nDu kannst die Karte bei den teilnehmenden Partnern verwenden, um die Vorteile für kulturelle Aktivitäten, Einkaufen, Transport, Verpflegung und Unterkunft auch in den europäischen Ländern, die an dem Programm teilnehmen, zu nutzen."
badge:
active: "Aktiv"
revoked: "Widerrufen"
expired: "Abgelaufen"
date:
+ valid_until: "Gültig bis {{date}}"
activated: "Aktiviert am"
expired: "Abgelaufen am"
revoked: "Widerrufen am"
expiration:
- cgn: "Aktiv bis"
- eyca: "Aktiv bis"
+ cgn: "Gültig bis"
+ eyca: "Gültig bis"
activation:
eyca:
loading:
@@ -2401,19 +2507,19 @@ bonus:
body: "Wir entschuldigen uns für die Unannehmlichkeiten.\nBitte versuche es später noch einmal."
loading:
caption: "Wir aktivieren deine Nationale Jugendkarte"
- subCaption: "Attendi qualche secondo..."
+ subCaption: "Bitte warte ein paar Sekunden..."
error:
title: "Der Dienst Nationale Jugendkarte ist derzeit nicht verfügbar."
- body: "Ci dispiace, riprova più tardi."
+ body: "Es tut uns leid, bitte versuche es später noch einmal."
ineligible:
title: "Leider erfüllst du nicht die Voraussetzungen für die Nationale Jugendkarte."
body: "Die Nationale Jugendkarte ist nur für italienische und europäische Staatsbürger mit Wohnsitz in Italien im Alter von 18 bis 35 Jahren erhältlich."
timeout:
- title: "Stiamo lavorando la tua richiesta."
+ title: "Wir bearbeiten deine Anfrage."
body: "Wir werden dir eine Nachricht in der App schicken, wenn deine Jugendkarte aktiv ist."
alreadyActive:
title: "Deine Nationale Jugendkarte ist bereits aktiv!"
- body: "Puoi trovare la tua Carta nella sezione Portafoglio."
+ body: "Du findest sie im Tab Konto der App."
pending:
title: "Deine Nationale Jugendkarte wird gerade aktiviert."
body: "Du erhältst eine Nachricht, wenn sie aktiviert ist."
@@ -2424,8 +2530,8 @@ bonus:
toast: "Zahlungsmethode von deinem Konto entfernt!"
alert:
title: "Karte deaktivieren"
- message: "La Carta verrà disattivata e non potrai più accedere alle opportunità disponibili."
- expired: Rimuovi dal Portafoglio
+ message: "Die Karte wird deaktiviert und du hast keinen Zugang mehr zu den verfügbaren Vorteilen."
+ expired: "Vom Konto entfernen"
otp:
error: "Aufgrund eines technischen Problems war es uns nicht möglich, einen Rabattcode zu generieren. Bitte versuche es erneut."
code:
@@ -2439,6 +2545,16 @@ bonus:
other: "{{seconds}} Sekunden"
features:
messages:
+ pushNotifications:
+ banner:
+ title: "Verpasse keine wichtigen Mitteilungen"
+ body: "Aktiviere Push-Benachrichtigungen, damit du weißt, wenn du eine Mitteilung auf IO erhältst"
+ CTA: "Push-Benachrichtigungen aktivieren"
+ bottomSheet:
+ title: "Möchtest du diesen Hinweis nicht mehr sehen?"
+ body: "Bitte beachte, dass die Aktivierung von Push-Benachrichtigungen dazu beitragen kann, dass du wichtige Mitteilungen und Zahlungsfristen nicht verpasst."
+ cta: "Später erinnern"
+ cta2: "Nicht erneut anzeigen"
attachmentDownloadFeedback: "Download läuft"
attachments: "Anhänge"
loading:
@@ -2455,8 +2571,11 @@ features:
content: "Läuft am {{date}} um {{time}} ab"
payments:
title: "pagoPA-Zahlungsmitteilungen"
- noticeCode: "Zahlungskodex"
+ noticeCode: "Zahlungsmitteilungskodex"
pay: "Zahlen"
+ greenPass:
+ button: "Zurück"
+ title: "Dieser Dienst ist auf IO nicht mehr aktiv"
pn:
service:
activate: "Aktiviere den Dienst"
@@ -2468,13 +2587,14 @@ features:
badge:
legalValue: "Rechtsgültig"
title: "Details der Mitteilung"
- noticeCode: "Zahlungskodex"
+ noticeCode: "Zahlungsmitteilungskodex"
loadError:
title: "Etwas ist schief gelaufen"
body: "Die Details zu deiner Mitteilung konnten nicht abgerufen werden. Bitte versuche es erneut"
cancelledMessage:
body: "Diese Zustellung wurde vom Absender gelöscht. Du kannst dessen Inhalt ignorieren."
unpaidPayments: "Für die Erstattung von Zahlungen im Zusammenhang mit diesem Bescheid wende dich bitte an den Absender."
+ unpaidPaymentsNew: "Für die Erstattung von Zahlungen wende dich bitte an die Körperschaft."
payments: "Zahlungen"
paymentSection:
title: "pagoPA-Zahlungsmitteilungen"
@@ -2522,6 +2642,11 @@ features:
title: "Möchtest du eine Aufforderung bezahlen?"
action: "Geh zum Bereich Zahlungen"
close: "Schließen"
+ otherMethods:
+ error:
+ banner:
+ label: "Wir konnten einige Elemente der Liste nicht laden."
+ cta: "Erneut versuchen"
cards:
categories:
all: "Alle"
@@ -2532,11 +2657,24 @@ features:
other: "Mehr"
onboarding:
title: "Was möchtest du deinem Konto hinzufügen?"
+ sections:
+ itw: "Dokumente"
+ other: "Mehr"
+ badge:
+ active: "Bereits vorhanden"
+ unavailable: "Nicht verfügbar"
+ requested: "In Bearbeitung"
options:
cgn: "Nationale Jugendkarte"
welfare: "Initiativen für das Gemeinwohl"
payments: "Zahlungsmethoden"
payments:
+ backoff:
+ second: "1 Sekunde"
+ seconds: "{{seconds}} Sekunden"
+ minute: "1 Minute"
+ minutes: "{{minutes}} Minuten"
+ retryCountDown: "Du kannst es in {{time}} erneut versuchen."
title: "Zahlungen"
cta: "Aufforderung bezahlen"
remoteAlert:
@@ -2549,6 +2687,10 @@ features:
action: "Zahlungsmethode hinzufügen"
status:
expired: "Abgelaufen"
+ error:
+ banner:
+ label: "Das Laden der Zahlungsmethoden ist fehlgeschlagen."
+ retryButton: "Erneut versuchen"
transactions:
multiplePayment: "Mehrfache Zahlung"
title: "Transaktionsverlauf"
@@ -2565,17 +2707,32 @@ features:
shareButton: "Speichern oder teilen"
error: "Die Quittung konnte nicht abgerufen werden."
download: "Quittung abrufen"
- hideFromList: Von der Liste verstecken
+ hideFromList: "Von der Liste verstecken"
delete:
successful: "Die Quittung wurde ausgeblendet"
failed: "Es ist ein Fehler aufgetreten, bitte versuche es erneut"
hideBanner:
title: "Möchtest du diese Quittung aus deiner Liste ausblenden?"
content: "Dieser Vorgang ist unwiderruflich. Die Quittung wird nicht mehr in deiner Quittungsliste angezeigt."
- accept: "Ausblenden"
+ accept: "Ja, ausblenden"
details:
totalFeeUnknown: "Der Gesamtbetrag enthält keine Provisionskosten: du findest diese in dem Dokument, das du von {{pspName}} erhalten hast."
totalFeeUnknownPsp: "Die Gesamtsumme enthält keine Provisionskosten: du findest diese in dem Dokument, das du vom Zahlungsdienstleister (PSP) erhalten hast."
+ error:
+ banner:
+ label: "Das Laden der Qittungen ist fehlgeschlagen."
+ retryButton: "Erneut versuchen"
+ filters:
+ tabs:
+ all: "Alle"
+ payer: "In-App-Zahlung"
+ debtor: "Auf mich lautend"
+ list:
+ empty:
+ title: "Keine Quittung gefunden"
+ subtitle: "Wenn du eine Quittung für eine pagoPA-Zahlungsmitteilung suchst, die du in der Vergangenheit bezahlt hast, wende dich an den Gläubiger."
+ emptyPayer:
+ title: "Hier findest du Quittungen für Zahlungen, die mit der App getätigt wurden."
details:
payPal:
banner:
@@ -2588,6 +2745,323 @@ features:
explainationContent: "Wenn du diese Methode gespeichert hast, hast du {{pspBusinessName}} autorisiert, Transaktionen über 'PayPal-Schnellzahlung' abzuwickeln.\n\nWenn du einen anderen Anbieter verwenden möchtest, füge die Methode erneut zu deinem Konto hinzu.\n\nUm die Autorisierung zu widerrufen, entferne die Methode aus deinem Konto.\n\nVerwende die PayPal-App, um die Karte oder das Bankkonto zu ändern, von der/dem du die Gebühren abbuchen möchtest."
errors:
transactionCreationError: "Es gibt ein Problem mit den Bezahlsystemen."
+ checkout:
+ bottomSheet:
+ PAYMENT_REVERSED:
+ title: "Was tun, wenn die Zahlung fehlschlägt?"
+ payNotice: "**Bezahle die Zahlungsmitteilung**\nDenke daran, die Zahlungsmitteilung innerhalb der von der Körperschaft gesetzten Fristen zu bezahlen. Wenn du nicht über IO zahlen kannst, [entdecke andere pagoPA-fähige Kanäle]({{url}})"
+ waitRefund: "**Warte auf die Erstattung**\nNormalerweise wird der Betrag innerhalb weniger Minuten wieder gutgeschrieben. In anderen Fällen kann die Geldüberweisung auf dein Konto oder deine Karte länger dauern."
+ contactSupport: "**Kontaktiere den Support**\nWenn du nach 5 Werktagen immer noch keine Rückerstattung erhalten hast, kontaktiere bitte den Support."
+ itWallet:
+ credentialName:
+ eid: "Digitale Identität"
+ mdl: "Führerschein"
+ dc: "Europäische Behindertenkarte"
+ ts: "Gesundheitskarte - Europäische Krankenversicherungskarte"
+ ipzsPrivacy:
+ title: "Deine Dokumente in IO sind sicher"
+ warning: "Indem du auf **Weiter** tippst, erklärst du, dass du den **Datenschutzhinweis** gelesen und verstanden hast."
+ button:
+ label: "Weiter"
+ wallet:
+ active: "Aktiv"
+ inactive: "Nicht aktiv"
+ card:
+ status:
+ expired: "Abgelaufen"
+ expiring: "Ablaufend"
+ pending: "In Bearbeitung"
+ invalid: "Ungültig"
+ verificationExpiring: "Überprüfen"
+ verificationExpired: "Überprüfen"
+ digital: "Digitale Version"
+ generic:
+ error:
+ title: "Es gibt ein Problem mit unseren Systemen"
+ body: "Versuche es in ein paar Minuten erneut. Wenn das Problem erneut auftritt, wende dich an den Support."
+ alert:
+ title: "Möchtest du den Vorgang abbrechen?"
+ body: "Du musst alle Schritte erneut durchführen"
+ confirm: "Ja, unterbrechen"
+ cancel: "Nein, fortfahren"
+ dataSource:
+ multi: "Bereitgestellt von {{credentialSource}}"
+ single: "Bereitgestellt von {{credentialSource}}"
+ placeholders:
+ claimNotAvailable: "Eigenschaft nicht erkannt"
+ claimLabelNotAvailable: "Eigenschaft nicht vorhanden"
+ organizationName: "Körperschaft nicht verfügbar"
+ verifiableCredentials:
+ claims:
+ uniqueId: "Eindeutige ID"
+ givenName: "Name"
+ familyName: "Nachname"
+ taxIdCode: "Steuernummer"
+ birthdate: "Geburtsdatum"
+ placeOfBirth: "Geburtsort"
+ expirationDate: "Ablaufdatum"
+ securityLevel: "Sicherheitsstufe"
+ info: "Mehr über diese Daten"
+ releasedBy: "Ausstellung der digitalen Version"
+ attachments: "Anhänge"
+ authenticSource: "Quelle der Daten"
+ mdl:
+ category: "Führerschein {{category}}"
+ issuedDate: "Gültig von"
+ expirationDate: "Gültig bis"
+ restrictionConditions: "Beschränkungen"
+ discovery:
+ banner:
+ home:
+ title: "Neu: Dokumente in IO"
+ content: "Du kannst jetzt die digitale Version deiner Dokumente in dein IO-Konto aufnehmen!"
+ action: "Start"
+ onboarding:
+ content: "Aktiviere Dokumente in IO, um die digitale Version deiner Dokumente zum Konto hinzuzufügen"
+ action: "Start"
+ title: "Die digitale Version deiner Dokumente in IO"
+ content: "###### Dokumente in IO: So funktioniert es \n Du kannst jetzt die **digitale Version deiner persönlichen Dokumente**, wie z. B. deinen Führerschein und deine Gesundheitskarte, zu deinem IO-Konto hinzufügen.\n\nAktiviere die Funktion **Dokumente in IO**, um sie immer auf deinem Gerät zur Hand zu haben. \n ###### Es geht schnell und einfach \n Du benötigst deine **SPID** oder **CIE** (Elektronische Identitätskarte) Zugangsdaten, um die Aktivierung abzuschließen: dies ist ein notwendiger Sicherheitsschritt, um die Sicherheit deiner Daten zu gewährleisten."
+ tos: "Indem du auf **Weiter** tippst, bestätigst du, dass du die [Datenschutzbestimmungen und Nutzungsbedingungen]({{privacyAndTosUrl}}) gelesen und verstanden hast."
+ upcomingWalletBanner:
+ title: "Demnächst: deine Dokumente in IO"
+ content: "Bald kannst du digitale Versionen deiner persönlichen Dokumente wie Führerschein und Gesundheitskarte in dein IO-Konto einfügen!"
+ action: "Mehr erfahren"
+ alreadyActive:
+ title: "Dokumente in IO ist bereits aktiv"
+ content: "Füge weiterhin digitale Versionen deiner Dokumente zu deinem Konto hinzu."
+ action: "Gehe zum Konto"
+ identification:
+ mode:
+ title: "Überprüfe deine Identität"
+ description: "Dies ist ein notwendiger Schritt, um die Sicherheit deiner Daten zu gewährleisten."
+ header: "Wähle, wie du dich identifizieren willst"
+ method:
+ spid:
+ title: "SPID"
+ subtitle: "Zugangsdaten und App (oder SMS) verwenden"
+ ciePin:
+ title: "CIE + PIN"
+ subtitle: "Elektronische Identitätskarte und PIN verwenden"
+ cieId:
+ title: "CieID"
+ subtitle: "CieID-Zugangsdaten und -App verwenden"
+ nfc:
+ title: "NFC aktivieren, um fortzufahren"
+ description: "Damit IO deine CIE lesen kann, aktiviere NFC in den Einstellungen deines Geräts."
+ header: "Wie geht das"
+ steps:
+ label: "Schritt {{value}}"
+ 1: "Öffne 'Einstellungen'"
+ 2: "Suche nach 'NFC'"
+ 3: "Aktiviere die Funktion"
+ primaryAction: "Einstellungen öffnen"
+ secondaryAction: "Weiter"
+ notMatchingIdentityScreen:
+ title: "Du meldest dich mit einem neuen Gerät an"
+ message: "Wenn du dich von einem anderen Gerät als dem üblichen (z. B. dem einer anderen Person) in IO anmeldest, werden aus Sicherheitsgründen diese Funktionalitäten zurückgesetzt:\n\n- Dokumente in IO"
+ banner:
+ title: "Wir empfehlen, dass du nur von deinem Gerät aus auf die App zugreifst."
+ alert:
+ title: "Möchtest du dich wirklich abmelden?"
+ message: "Du musst dich erneut mit SPID oder CIE anmelden, um die App nutzen zu können."
+ loading:
+ cieId:
+ title: "Verbindung mit der CieID-App läuft..."
+ subtitle: "Bestätige den Zugang in der CieID-App, um die Verbindung fortzusetzen oder abzubrechen"
+ cancel: "Verbindung abbrechen"
+ issuance:
+ credentialAuth:
+ title: "{{credentialName}}: erforderliche Daten"
+ subtitle: "Sie werden mit **{{organization}}** für die Bereitstellung der digitalen Version des Dokuments geteilt."
+ requiredClaims: "Erforderliche Daten"
+ disclaimer:
+ 0: "Deine Daten sind sicher und werden nur zu den in der Datenschutzrichtlinie beschriebenen Zwecken verarbeitet."
+ 1: "Die Daten werden nur so lange weitergegeben, wie es dauert, bis die digitale Version des Dokuments bereitgestellt wird."
+ tos: "Indem du auf **Weiter** tippst, bestätigst du, dass du die [Datenschutzrichtlinie]({{privacyUrl}}) gelesen und verstanden hast."
+ eidPreview:
+ title: "Identität verifiziert"
+ subtitle: "Du aktivierst **Dokumente in IO** als:"
+ actions:
+ primary: "Weiter"
+ secondary: "Abbrechen"
+ credentialPreview:
+ loading: "Warte noch ein paar Sekunden, ohne die App zu beenden."
+ title: "{{credential}}: Hier eine Vorschau deiner Daten"
+ bottomSheet:
+ about:
+ title: "Wer ist das?"
+ subtitle: "Das ist die Körperschaft, die dir die digitale Version deiner Dokumente zur Verfügung stellt.\n\nUm zu erfahren, wie sie deine Daten verarbeitet, konsultiere bitte die [Datenschutzrichtlinie]({{privacyUrl}})."
+ authSource:
+ title: "Wer ist das?"
+ subtitle: "Es ist die Körperschaft, die die in deinem Dokument enthaltenen Daten bereitstellt."
+ actions:
+ primary: "Dem Konto hinzufügen"
+ secondary: "Abbrechen"
+ eidResult:
+ success:
+ title: "Alles ist bereit!"
+ subtitle: "Du kannst nun das erste Dokument in das IO-Konto aufnehmen."
+ toast: "Erledigt!"
+ actions:
+ continue: "Erstes Dokument hinzufügen"
+ continueAlt: "Dokument hinzufügen"
+ close: "Später fortfahren"
+ credentialResult:
+ toast: "Erledigt!"
+ notMatchingIdentityError:
+ title: "Unerkannte Identität"
+ body: "Aktiviere Dokumente in IO mit der gleichen Identität, die du für den Zugriff auf die IO-App verwendest. Überprüfe deine Anmeldedaten und versuche es erneut."
+ primaryAction: "Zugriff wiederholen"
+ secondaryAction: "Schließen"
+ genericError:
+ title: "Es ist ein unerwarteter Fehler aufgetreten"
+ body: "Die Körperschaft, die digitale Versionen von Dokumenten ausgibt, hat Probleme und arbeitet bereits an deren Lösung: Versuche es später noch einmal."
+ primaryAction: "Schließen"
+ notEntitledCredentialError:
+ title: "Das Dokument kann nicht hinzugefügt werden"
+ body: "Vergewissere dich, dass du im Besitz des gültigen physischen Dokuments bist, bevor du dessen digitale Version anforderst."
+ primaryAction: "Verstanden"
+ asyncCredentialError:
+ title: "Das Führerscheinamt bearbeitet deinen Antrag"
+ body: "Du erhältst in der App eine Mitteilung, dass du fortfahren kannst, sobald dein Antrag bearbeitet ist."
+ primaryAction: "Verstanden"
+ credentialAlreadyAdded:
+ title: "Du hast dieses Dokument bereits"
+ body: "Die digitale Version des Dokuments befindet sich bereits in deinem Konto."
+ primaryAction: "Gehe zum Dokument"
+ walletInstanceNotActive:
+ title: "Aktiviere Dokumente in IO, um fortzufahren"
+ body: "Um deine Dokumente zum Konto hinzuzufügen, musst du Folgendes aktivieren: "
+ bodyBold: "Dokumente in IO"
+ primaryAction: "Start"
+ secondaryAction: "Jetzt nicht"
+ credentialNotFound:
+ title: "Dokument zum Konto hinzufügen"
+ subtitle: "Um Dokumente in IO zu verwenden, füge sie zunächst dem Konto hinzu. Das geht schnell und einfach."
+ unsupportedDevice:
+ text: "Ab dem 02.07.2024 ist dein Gerät möglicherweise nicht mehr mit IO kompatibel."
+ moreInfo: "Mehr erfahren"
+ error:
+ title: "Dein Gerät unterstützt Dokumente in IO nicht"
+ body: "Dein Gerät verfügt nicht über die erforderlichen Sicherheitsanforderungen für diese Funktion."
+ primaryAction: "Schließen"
+ secondaryAction: "Mehr erfahren"
+ presentation:
+ alerts:
+ statusAction: "Was kann ich tun?"
+ mdl:
+ content: "Du kannst deinen Führerschein nur in Italien verwenden, um bei einer Polizeikontrolle deine Fahrtauglichkeit nachzuweisen."
+ ehc:
+ content: "Du kannst deine Gesundheitskarte - Europäische Krankenversicherungskarte auf IO verwenden, um Dienstleistungen des nationalen Gesundheitsdienstes in Anspruch zu nehmen."
+ edc:
+ content: "Du kannst deinen Europäischen Behindertenausweis auf IO verwenden, um Dienstleistungen auf italienischem Gebiet in Anspruch zu nehmen, und zwar in denselben Verwendungszusammenhängen wie dein physisches Dokument."
+ expired:
+ content: "Das Dokument ist nicht mehr gültig. Wenn du das neue gültige Dokument bereits hast, kannst du die digitale Version im Konto aktualisieren"
+ action: "Dokument aktualisieren"
+ expiring:
+ content: "Es verbleiben noch {{days}} Tage, bevor das Dokument abläuft."
+ verificationExpiring:
+ content: "Überprüfe die digitale Version deines Dokuments bis zum {{date}}."
+ bottomSheets:
+ eidInfo:
+ title: "Dokumente in IO:\nIdentität verifiziert"
+ titleExpired: "Dokumente in IO:\nVerifiziere deine Identität"
+ contentTop: "Mit **Dokumente in IO** speicherst du digitale Versionen deiner Dokumente im IO-Konto."
+ contentBottom: "###### Wie funktioniert das?\n\nDeine **Identität wird bei der Aktivierung über SPID oder CIE verifiziert**."
+ triggerLabel: "Was ist das?"
+ alert:
+ valid: "Die letzte Überprüfung ist vom {{date}}."
+ expiring: "Überprüfe deine Identität bis {{date}}."
+ expired: "Für die weitere Nutzung von Dokumente in IO ist ein kurzer Überprüfungsschritt erforderlich."
+ MDL:
+ expiring:
+ title: "Führerschein in IO: ablaufendes Dokument"
+ content: "Verlängere deinen Führerschein in den Büros des Ministeriums für Infrastruktur und Verkehr - Generaldirektion für Motorisierung oder bei einer autorisierten Stelle in deiner Nähe.\n\nDu musst dich einer medizinischen Untersuchung bei einem qualifizierten Arzt unterziehen und die vorgeschriebenen Formulare ausfüllen.\n\n###### Welche Dokumente sollte ich bereithalten?\n\n - den ablaufenden oder abgelaufenen Führerschein\n - ein Ausweisdokument\n - die Steuernummer\n - ein aktuelles Foto in Passgröße"
+ EuropeanHealthInsuranceCard:
+ expiring:
+ title: "Gesundheitskarte in IO: ablaufendes Dokument"
+ content: "Deine Gesundheitskarte wird automatisch erneuert und dann an deine bei der Agentur der Einnahmen registrierte Adresse geschickt.\n\nWenn du sie bereits erhalten hast, kannst du dieses Dokument aus deinem Konto löschen und die neue, aktualisierte digitale Version hinzufügen."
+ EuropeanDisabilityCard:
+ expiring:
+ title: "Europäischer Behindertenausweis in IO: ablaufendes Dokument"
+ content: "Du kannst die Verlängerung deines Europäischen Behindertenausweises bei der Stelle beantragen, die ihn ausgestellt hat.\n\n Informiere dich auf der offiziellen Website des INPS oder wende dich an deinen Sanitätsbetrieb, da die Verlängerung je nach Art der Behinderung und den Vorschriften in deinem Gebiet unterschiedlich ausfallen kann."
+ credentialDetails:
+ card:
+ front: "Vorderseite "
+ back: "Rückseite"
+ showFront: "Zeige Vorderseite "
+ showBack: "Zeige Rückseite"
+ personalDataTitle: "Persönliche Daten"
+ documentDataTitle: "Daten des Dokuments"
+ lastUpdated: "Daten zum {{lastUpdateTime}}"
+ boolClaim:
+ true: "Ja"
+ false: "Nein"
+ hiddenClaim: "Ausgeblendet"
+ fiscalCode:
+ label: "Deine Steuernummer"
+ action: "Tippe, um den Barcode zu vergrößern und im Vollbildmodus anzuzeigen."
+ status:
+ valid: "Gültig"
+ invalid: "Ungültig"
+ expired: "Abgelaufen"
+ expiring: "Ablaufend"
+ actions:
+ removeFromWallet: "Vom Konto entfernen"
+ requestAssistance: "Stimmt etwas nicht?"
+ showClaimValues: "Dokumentattribute anzeigen"
+ hideClaimValues: "Dokumentattribute ausblenden"
+ dialogs:
+ remove:
+ title: "Möchtest du das Dokument aus dem Konto entfernen?"
+ content: "Wenn du deine Meinung änderst, kannst du es später wieder hinzufügen."
+ confirm: "Ja, entfernen"
+ toast:
+ removed: "Erledigt!"
+ verificationExpired:
+ title: "Überprüfe die digitale Version des Dokuments"
+ content: "Dies ist ein notwendiger Sicherheitsschritt, um das Dokument '{{credentialName}}' in IO weiter zu verwenden."
+ primaryAction: "Start"
+ ctas:
+ openPdf: "Dokument anzeigen"
+ shareButton: "Speichern oder freigeben"
+ fiscalCode: "Deine Steuernummer"
+ trustmark:
+ cta: "Echtheitszertifikat anzeigen"
+ description: "Zeige den QR-Code vor, um die Echtheit des Dokuments zu bestätigen, wenn du dazu aufgefordert wirst."
+ expiration: "Der QR-Code erneuert sich in"
+ qrCode: "QR-Code zur Authentizität von Dokumenten"
+ walletRevocation:
+ cta: "Dokumente in IO deaktivieren"
+ confirmScreen:
+ title: "Möchtest du Dokumente in IO wirklich deaktivieren?"
+ subtitle: "Du löschst die Dokumente, die du dem Konto hinzugefügt hast.\nWenn du deine Meinung änderst, kannst du Dokumente in IO in Zukunft wieder aktivieren."
+ action: "Bestätige und fortfahren"
+ loadingScreen:
+ title: "Wir deaktivieren Dokumente in IO..."
+ subtitle: "Warte ein paar Sekunden"
+ failureScreen:
+ title: "Ein unerwarteter Fehler ist aufgetreten"
+ subtitle: "Der Dienst konnte nicht deaktiviert werden. Bitte versuche es erneut."
+ feedback:
+ banner:
+ title: "Sag uns, was du denkst"
+ content: "Erzähle uns von deinen Erfahrungen mit der Funktion Dokumente in IO."
+ action: "Start"
+ walletInstanceRevoked:
+ alert:
+ cta: "Mehr erfahren"
+ closeButton: "Schließen"
+ closeButtonAlt: "Verstanden"
+ revokedByWalletProvider:
+ title: "Dokumente in IO wurde deaktiviert"
+ content: "Um die Voraussetzungen für die weitere Nutzung der Funktionen auf deinem Gerät zu prüfen, tippe auf 'Mehr erfahren'."
+ newWalletInstanceCreated:
+ title: "Dokumente in IO wurde auf diesem Gerät deaktiviert"
+ content: "Aus Sicherheitsgründen kannst du deine IO-Dokumente immer nur auf einem Gerät gleichzeitig verwenden."
+ revokedByUser:
+ title: "Du hast Dokumente in IO deaktiviert"
+ content: "Wenn du deine Meinung änderst, kannst du Dokumente in IO in Zukunft wieder aktivieren."
support:
ticketList:
noTicket:
@@ -2605,6 +3079,9 @@ support:
panicMode:
title: "Leider können wir dir zur Zeit nicht helfen"
body: "Wir wissen, dass es ein Problem gibt, und wir arbeiten daran, es zu lösen. Wenn das Problem weiterhin besteht oder wenn du in einer anderen Angelegenheit Hilfe benötigst, versuche bitte, uns später erneut zu kontaktieren."
+ errorGetZendeskToken:
+ title: "Wir können derzeit kein Ticket erstellen"
+ subtitle: "Versuche es später erneut"
askPermissions:
nameSurname: "Vor- und Nachname"
fiscalCode: "Steuernummer"
@@ -2720,6 +3197,8 @@ transaction:
totalFee: "Der Gesamtbetrag umfasst "
totalFeePsp: "Provision, berechnet von {{pspName}}."
totalFeeNoPsp: "Provision, die vom Transaktionsdienstleister (PSP) erhoben wird."
+ bannerImported:
+ content: "Die pagoPA-Quittung ist nicht verfügbar. Wende dich an den Zahlungsempfängers, wenn du den Zahlungsbeleg, d. h. das Dokument, das die Begleichung einer Schuld bescheinigt, benötigst."
info:
title: "Informationen zur Transaktion"
pspName: "Zahlungsdienstleister (PSP)"
@@ -2758,3 +3237,65 @@ permissionRequest:
2: "Wähle 'IO'"
3: "Wähle 'Fotos' und erlaube den Zugriff"
cta: "Öffne Einstellungen"
+FIMS:
+ updateApp:
+ header: "Aktualisiere die App, um fortzufahren"
+ body: "Um weiterhin alle Funktionen nutzen zu können, lade die neue Version von IO aus dem Store herunter."
+ history:
+ errorStates:
+ dataUnavailable: "Daten nicht verfügbar"
+ ko:
+ title: "Es gibt ein vorübergehendes Problem"
+ body: "Hier kannst du den Verlauf deiner Zugriffe auf externe Dienste über IO einsehen und eine Kopie per E-Mail anfordern."
+ toast: "Beim Laden der Liste ist ein Problem aufgetreten. Bitte versuche es erneut"
+ emptyBody: "Du hast noch keine Dienste Dritter in Anspruch genommen"
+ exportData:
+ alerts:
+ areYouSure: "Willst du wirklich eine Kopie aller Zugänge exportieren?"
+ alreadyExporting:
+ title: "Wir bearbeiten bereits einen Exportantrag."
+ body: "Wenn die Bearbeitung abgeschlossen ist, erhältst du eine E-Mail mit allen Informationen zum Zugriffsverlauf."
+ CTA: "Eine Kopie per E-Mail anfordern"
+ successToast: "Erledigt! Prüfe dein Postfach."
+ errorToast: "Beim Senden der Anfrage ist ein Problem aufgetreten. Bitte versuche es erneut"
+ profileCTA:
+ title: "Kontrolle deiner Zugriffe"
+ subTitle: "Zugriffshistorie mit IO anzeigen"
+ historyScreen:
+ header: "Deine Zugänge auf Dienste Dritter"
+ body: "Hier kannst du die Historie deiner Zugänge auf externe Dienste über IO einsehen und eine Kopie per E-Mail anfordern."
+ loadingScreen:
+ abort:
+ title: "Du hast den Zugang zu diesem Dienst abgebrochen"
+ consents:
+ title: "Warte ein paar Sekunden"
+ idle:
+ title: "Warte ein paar Sekunden"
+ fastLogin_forced_restart:
+ title: "Warte ein paar Sekunden"
+ in-app-browser-loading:
+ title: "Wir leiten dich zum Dienst weiter"
+ subtitle: "Warte ein paar Sekunden"
+ consentsScreen:
+ errorStates:
+ authentication:
+ body: "Der Webservice der Körperschaft ist derzeit nicht verfügbar"
+ title: "Der Dienst konnte nicht erreicht werden"
+ general:
+ body: "Es gab ein Problem beim Abrufen der Daten: Wir arbeiten daran, es so schnell wie möglich zu lösen"
+ title: "Es liegt ein vorübergehendes Problem vor, bitte versuche es später noch einmal."
+ missingInAppBrowser:
+ body: "Um einen sicheren Zugriff zu gewährleisten, lade den auf deinem Gerät installierten Browser herunter oder aktualisiere ihn."
+ title: "Aktualisiere deinen Browser um fortzufahren"
+ inAppBrowserError: "Beim Senden der Anfrage ist ein Problem aufgetreten. Bitte versuche es erneut"
+ title: "Um auf den Dienst zugreifen zu können, müssen die folgenden Daten freigegeben werden"
+ subtitle: "IO wird die erforderlichen Daten an "
+ subtitle2: " weitergeben für deine Authentifizierung bei "
+ requiredData: "Erforderliche Daten"
+ privacy1: "Für weitere Informationen lies bitte die "
+ privacyCta: "Datenschutzrichtlinie "
+ bottomSheet:
+ title: "Dienste von Drittanbietern über IO: So funktioniert es"
+ body: "Damit du auf einen externen Dienst zugreifen kannst, ohne dich jedes Mal zu authentifizieren, gibt die IO-App einige deiner Daten an den Anbieter weiter."
+ body2: "Deine Daten sind sicher und werden nur zu den Zwecken verarbeitet, die von der Körperschaft angegeben sind."
+ bodyPrivacy: "Datenschutzrichtlinie"