Skip to content

Commit

Permalink
chore(IT Wallet): [SIW-1927] Add pull-to-refresh to the wallet screen (
Browse files Browse the repository at this point in the history
  • Loading branch information
mastro993 authored Dec 17, 2024
1 parent b8229dc commit 31f4df0
Show file tree
Hide file tree
Showing 9 changed files with 228 additions and 145 deletions.
7 changes: 6 additions & 1 deletion ts/components/ui/IOScrollView.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable sonarjs/cognitive-complexity */
/* eslint-disable functional/immutable-data */
import {
ButtonLink,
Expand Down Expand Up @@ -292,7 +293,11 @@ export const IOScrollView = ({
testID={testID}
onScroll={handleScroll}
scrollEventThrottle={8}
snapToOffsets={[0, snapOffset || 0]}
snapToOffsets={
// If there is a refresh control, don't snap to offsets
// This is a react-native bug: https://github.com/facebook/react-native/issues/27324
RefreshControlComponent ? undefined : [0, snapOffset || 0]
}
snapToEnd={false}
decelerationRate="normal"
refreshControl={RefreshControlComponent}
Expand Down
56 changes: 56 additions & 0 deletions ts/features/wallet/saga/handleWalletAnalyticsSaga.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { SagaIterator } from "redux-saga";
import { all, call, select, take } from "typed-redux-saga/macro";
import { updateMixpanelProfileProperties } from "../../../mixpanelConfig/profileProperties";
import { updateMixpanelSuperProperties } from "../../../mixpanelConfig/superProperties";
import { isIdPayEnabledSelector } from "../../../store/reducers/backendStatus/remoteConfig";
import { GlobalState } from "../../../store/reducers/types";
import { cgnDetails } from "../../bonus/cgn/store/actions/details";
import { idPayWalletGet } from "../../idpay/wallet/store/actions";
import { getPaymentsWalletUserMethods } from "../../payments/wallet/store/actions";

/**
* Saga that handles the Mixpanel properties update based on the wallet screen content.
* It waits for all wallet-related API calls to complete before updating analytics.
*/
export function* handleWalletAnalyticsSaga() {
const isIdPayEnabled = yield* select(isIdPayEnabledSelector);

// Prerequisites for the analytics update
const analyticsPrerequisites = [
waitForPaymentMethods,
waitForCgnDetails,
...(isIdPayEnabled ? [waitForIdPay] : [])
];

// Call and wait for all prerequisite sagas to complete
yield* all(analyticsPrerequisites.map(call));

// Update analytics
const state: GlobalState = yield* select();
void updateMixpanelProfileProperties(state);
void updateMixpanelSuperProperties(state);
}

/**
* Wait for payment methods request to complete (success or failure)
*/
function* waitForPaymentMethods(): SagaIterator {
yield* take([
getPaymentsWalletUserMethods.success,
getPaymentsWalletUserMethods.failure
]);
}

/**
* Wait for IDPay wallet request to complete (success or failure)
*/
function* waitForIdPay(): SagaIterator {
yield* take([idPayWalletGet.success, idPayWalletGet.failure]);
}

/**
* Wait for CGN details request to complete (success or failure)
*/
function* waitForCgnDetails(): SagaIterator {
yield* take([cgnDetails.success, cgnDetails.failure]);
}
17 changes: 17 additions & 0 deletions ts/features/wallet/saga/handleWalletUpdateSaga.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { put } from "typed-redux-saga/macro";
import { cgnDetails } from "../../bonus/cgn/store/actions/details";
import { idPayWalletGet } from "../../idpay/wallet/store/actions";
import { getPaymentsWalletUserMethods } from "../../payments/wallet/store/actions";

/**
* This saga handles the update of the wallet screen
* Extend this function to add calls that the wallet screen needs to perform to update/refresh its content
*/
export function* handleWalletUpdateSaga() {
// Updates the user methods
yield* put(getPaymentsWalletUserMethods.request());
// Updates the IDPay wallet, if active
yield* put(idPayWalletGet.request());
// Updates the CGN details
yield* put(cgnDetails.request());
}
62 changes: 12 additions & 50 deletions ts/features/wallet/saga/index.ts
Original file line number Diff line number Diff line change
@@ -1,81 +1,43 @@
import { Millisecond } from "@pagopa/ts-commons/lib/units";
import { SagaIterator } from "redux-saga";
import {
all,
call,
fork,
put,
select,
take,
takeLatest,
takeLeading
} from "typed-redux-saga/macro";
// We need to disable the eslint rule because the types are not available for the following imports
// eslint-disable-next-line @jambit/typed-redux-saga/use-typed-effects
import { StrictEffect } from "redux-saga/effects";
import { walletUpdate } from "../store/actions";
import { walletAddCards } from "../store/actions/cards";
import { walletToggleLoadingState } from "../store/actions/placeholders";
import {
selectWalletCards,
selectWalletPlaceholders
} from "../store/selectors";
import { getPaymentsWalletUserMethods } from "../../payments/wallet/store/actions";
import { idPayWalletGet } from "../../idpay/wallet/store/actions";
import { cgnDetails } from "../../bonus/cgn/store/actions/details";
import { GlobalState } from "../../../store/reducers/types";
import { isIdPayEnabledSelector } from "../../../store/reducers/backendStatus/remoteConfig";
import { updateMixpanelProfileProperties } from "../../../mixpanelConfig/profileProperties";
import { updateMixpanelSuperProperties } from "../../../mixpanelConfig/superProperties";
import { selectWalletPlaceholders } from "../store/selectors";
import { handleWalletAnalyticsSaga } from "./handleWalletAnalyticsSaga";
import { handleWalletPlaceholdersTimeout } from "./handleWalletLoadingPlaceholdersTimeout";
import { handleWalletLoadingStateSaga } from "./handleWalletLoadingStateSaga";
import { handleWalletUpdateSaga } from "./handleWalletUpdateSaga";

const LOADING_STATE_TIMEOUT = 2000 as Millisecond;

export function* watchWalletSaga(): SagaIterator {
// Adds persisted placeholders as cards in the wallet
const currentCards = yield* select(selectWalletCards);
if (currentCards.length === 0) {
const placeholders = yield* select(selectWalletPlaceholders);
yield* put(walletAddCards(placeholders));
}
// to be displayed while waiting for the actual cards
const placeholders = yield* select(selectWalletPlaceholders);
yield* put(walletAddCards(placeholders));

yield* takeLatest(
walletToggleLoadingState,
handleWalletLoadingStateSaga,
LOADING_STATE_TIMEOUT
);

// Any remaining placeholders are removed after the timeout
yield* takeLeading(
walletToggleLoadingState,
handleWalletPlaceholdersTimeout,
LOADING_STATE_TIMEOUT
);

const isIdPayEnabled = yield* select(isIdPayEnabledSelector);

const bonusAndPaymentsSagas = [
call(waitForPaymentMethods),
call(waitForCgnDetails),
...(isIdPayEnabled ? [call(waitForIdPay)] : [])
] as unknown as Array<StrictEffect>;

yield* all(bonusAndPaymentsSagas);

const state: GlobalState = yield* select();

void updateMixpanelProfileProperties(state);
void updateMixpanelSuperProperties(state);
}

function* waitForPaymentMethods(): SagaIterator {
yield* take([
getPaymentsWalletUserMethods.success,
getPaymentsWalletUserMethods.failure
]);
}

function* waitForIdPay(): SagaIterator {
yield* take([idPayWalletGet.success, idPayWalletGet.failure]);
}
yield* takeLeading(walletUpdate, handleWalletUpdateSaga);

function* waitForCgnDetails(): SagaIterator {
yield* take([cgnDetails.success, cgnDetails.failure]);
yield* fork(handleWalletAnalyticsSaga);
}
Loading

0 comments on commit 31f4df0

Please sign in to comment.