Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [#176825286,#176323469] Features Carousel: Items are now shown depending on local and remote feature flag. BPD item is shown only when user is not enrolled to the program, hidden if loading or the information is not available #2793

Merged
merged 10 commits into from
Feb 12, 2021
Merged
20 changes: 8 additions & 12 deletions ts/features/bonus/bonusVacanze/screens/AvailableBonusScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as pot from "italia-ts-commons/lib/pot";
import { Content, View } from "native-base";
import * as React from "react";
import {
Expand Down Expand Up @@ -33,7 +32,8 @@ import { bonusVacanzeStyle } from "../components/Styles";
import { navigateToBonusRequestInformation } from "../navigation/action";
import { loadAvailableBonuses } from "../store/actions/bonusVacanze";
import {
availableBonusTypesSelector,
isAvailableBonusNoneErrorSelector,
isAvailableBonusLoadingSelector,
visibleAvailableBonusSelector
} from "../store/reducers/availableBonusesTypes";
import {
Expand Down Expand Up @@ -189,16 +189,12 @@ class AvailableBonusScreen extends React.PureComponent<Props> {
}
}

const mapStateToProps = (state: GlobalState) => {
const potAvailableBonuses = availableBonusTypesSelector(state);
return {
// fallback to hardcode data if pot is none
availableBonusesList: visibleAvailableBonusSelector(state),
isLoading: pot.isLoading(potAvailableBonuses),
// show error only when we have an error and no data to show
isError: pot.isNone(potAvailableBonuses) && pot.isError(potAvailableBonuses)
};
};
const mapStateToProps = (state: GlobalState) => ({
availableBonusesList: visibleAvailableBonusSelector(state),
isLoading: isAvailableBonusLoadingSelector(state),
// show error only when we have an error and no data to show
isError: isAvailableBonusNoneErrorSelector(state)
});

const mapDispatchToProps = (dispatch: Dispatch) => ({
navigateBack: () => dispatch(navigateBack()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const reducer = (
};

// Selectors
export const availableBonusTypesSelector = (
const availableBonusTypesSelector = (
state: GlobalState
): AvailableBonusTypesState => state.bonus.availableBonusTypes;

Expand Down Expand Up @@ -80,6 +80,26 @@ export const visibleAvailableBonusSelector = createSelector(
)
);

// Returns true if information about Available Bonuses list is loading
export const isAvailableBonusLoadingSelector = createSelector(
availableBonusTypesSelector,
(abs: AvailableBonusTypesState) => pot.isLoading(abs)
);

// Returns true if information about Available Bonuses list is in error
export const isAvailableBonusErrorSelector = createSelector(
availableBonusTypesSelector,
(abs: AvailableBonusTypesState): boolean => pot.isError(abs)
);

// Returns true if information about Available Bonuses list
// is in error state and no data is available in list (NoneError type)
export const isAvailableBonusNoneErrorSelector = createSelector(
[availableBonusTypesSelector, isAvailableBonusErrorSelector],
(abs: AvailableBonusTypesState, hasError: boolean): boolean =>
hasError && pot.isNone(abs)
);

/**
* return the bonus type corresponding to the given idBonusType
* @param idBonusType
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import * as React from "react";
import { Dispatch } from "redux";
import { connect } from "react-redux";
import * as pot from "italia-ts-commons/lib/pot";
import { bpdOnboardingStart } from "../../store/actions/onboarding";
import { LoadingErrorComponent } from "../../../bonusVacanze/components/loadingErrorScreen/LoadingErrorComponent";
import I18n from "../../../../../i18n";
import { loadAvailableBonuses } from "../../../bonusVacanze/store/actions/bonusVacanze";
import { GlobalState } from "../../../../../store/reducers/types";
import { availableBonusTypesSelector } from "../../../bonusVacanze/store/reducers/availableBonusesTypes";
import {
isAvailableBonusErrorSelector,
visibleAvailableBonusSelector
} from "../../../bonusVacanze/store/reducers/availableBonusesTypes";
import { useActionOnFocus } from "../../../../../utils/hooks/useOnFocus";
import { isStrictSome } from "../../../../../utils/pot";
import BaseScreenComponent from "../../../../../components/screens/BaseScreenComponent";

export type Props = ReturnType<typeof mapDispatchToProps> &
Expand All @@ -20,22 +21,20 @@ const loadingCaption = () => I18n.t("global.remoteStates.loading");
* this is a dummy screen reachable only from a message CTA
*/
const BpdCTAStartOnboardingScreen: React.FC<Props> = (props: Props) => {
const hasError = () => pot.isError(props.availableBonus);

// load available bonus when component is focused
useActionOnFocus(props.loadAvailableBonus);

React.useEffect(() => {
// bpdOnboardingStart navigate to ToS screen that needs availableBonus data
if (isStrictSome(props.availableBonus)) {
if (props.availableBonus.length > 0) {
props.startBpd();
}
}, [props.availableBonus]);

return (
<BaseScreenComponent goBack={true} headerTitle={I18n.t("bonus.bpd.title")}>
<LoadingErrorComponent
isLoading={!hasError()}
isLoading={!props.hasError}
loadingCaption={loadingCaption()}
onRetry={props.loadAvailableBonus}
/>
Expand All @@ -51,7 +50,8 @@ const mapDispatchToProps = (dispatch: Dispatch) => ({
});

const mapStateToProps = (globalState: GlobalState) => ({
availableBonus: availableBonusTypesSelector(globalState)
availableBonus: visibleAvailableBonusSelector(globalState),
hasError: isAvailableBonusErrorSelector(globalState)
});

export default connect(
Expand Down
18 changes: 10 additions & 8 deletions ts/features/wallet/component/FeaturedCardCarousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { IOStyles } from "../../../components/core/variables/IOStyles";
import I18n from "../../../i18n";
import { Dispatch } from "../../../store/actions/types";
import { GlobalState } from "../../../store/reducers/types";
import { availableBonusTypesSelector } from "../../bonus/bonusVacanze/store/reducers/availableBonusesTypes";
import { visibleAvailableBonusSelector } from "../../bonus/bonusVacanze/store/reducers/availableBonusesTypes";
import { ID_BPD_TYPE, ID_CGN_TYPE } from "../../bonus/bonusVacanze/utils/bonus";
import { bpdOnboardingStart } from "../../bonus/bpd/store/actions/onboarding";
import { bpdEnabledSelector } from "../../bonus/bpd/store/reducers/details/activation";
Expand Down Expand Up @@ -52,9 +52,12 @@ const FeaturedCardCarousel: React.FunctionComponent<Props> = (props: Props) => {
});
}

const anyBonusNotActive =
(!pot.getOrElse(props.bpdActiveBonus, false) && bpdEnabled) ||
(!props.cgnActiveBonus && cgnEnabled);
const hasBpdActive: boolean | undefined = pot.getOrElse(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this expression never returns undefined. It returns always a boolean

we should implement this logic

if we have a value (pot some) we can say has bpd or not (true / false, depending of the pot value). Otherwise we can't say nothing (undefined)

Suggested change
const hasBpdActive: boolean | undefined = pot.getOrElse(
const hasBpdActive: boolean | undefined =
props.bpdActiveBonus.kind === "PotSome"
? props.bpdActiveBonus.value
: undefined;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right I thought to commit the previously suggested code:

const hasBpdActive: boolean | undefined =
    pot.isSome(props.bpdActiveBonus)
      ? props.bpdActiveBonus.value
      : undefined;

I'm fixing it asap!

props.bpdActiveBonus,
false
);
const anyBonusNotActive = hasBpdActive === false || !props.cgnActiveBonus;

return anyBonusNotActive ? (
<View style={styles.container}>
<View style={[IOStyles.horizontalContentPadding]}>
Expand Down Expand Up @@ -82,7 +85,7 @@ const FeaturedCardCarousel: React.FunctionComponent<Props> = (props: Props) => {
switch (b.id_type) {
case ID_BPD_TYPE:
return (
!pot.getOrElse(props.bpdActiveBonus, false) && (
hasBpdActive === false && (
<FeaturedCard
key={`featured_bonus_${i}`}
title={I18n.t("bonus.bpd.name")}
Expand All @@ -94,8 +97,7 @@ const FeaturedCardCarousel: React.FunctionComponent<Props> = (props: Props) => {
);
case ID_CGN_TYPE:
return (
!props.cgnActiveBonus &&
cgnEnabled && (
!props.cgnActiveBonus && (
<FeaturedCard
key={`featured_bonus_${i}`}
title={b[currentLocale].name}
Expand All @@ -118,7 +120,7 @@ const mapStateToProps = (state: GlobalState) => ({
bpdActiveBonus: bpdEnabledSelector(state),
// FIXME replace with Selector when the API implementation is completed.
cgnActiveBonus: false,
availableBonusesList: pot.getOrElse(availableBonusTypesSelector(state), [])
availableBonusesList: visibleAvailableBonusSelector(state)
Undermaken marked this conversation as resolved.
Show resolved Hide resolved
});

const mapDispatchToProps = (dispatch: Dispatch) => ({
Expand Down
5 changes: 2 additions & 3 deletions ts/screens/wallet/WalletHomeScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {
loadAvailableBonuses
} from "../../features/bonus/bonusVacanze/store/actions/bonusVacanze";
import { allBonusActiveSelector } from "../../features/bonus/bonusVacanze/store/reducers/allActive";
import { availableBonusTypesSelector } from "../../features/bonus/bonusVacanze/store/reducers/availableBonusesTypes";
import { visibleAvailableBonusSelector } from "../../features/bonus/bonusVacanze/store/reducers/availableBonusesTypes";
import BpdCardsInWalletContainer from "../../features/bonus/bpd/components/walletCardContainer/BpdCardsInWalletComponent";
import { bpdAllData } from "../../features/bonus/bpd/store/actions/details";
import { bpdPeriodsAmountWalletVisibleSelector } from "../../features/bonus/bpd/store/reducers/details/combiner";
Expand Down Expand Up @@ -578,11 +578,10 @@ const mapStateToProps = (state: GlobalState) => {
.map(si => !isUpdateNeeded(si, "min_app_version_pagopa"))
.getOrElse(true);

const potAvailableBonuses = availableBonusTypesSelector(state);
return {
periodsWithAmount: bpdPeriodsAmountWalletVisibleSelector(state),
allActiveBonus: allBonusActiveSelector(state),
availableBonusesList: pot.getOrElse(potAvailableBonuses, []),
availableBonusesList: visibleAvailableBonusSelector(state),
potWallets: pagoPaCreditCardWalletV1Selector(state),
anyHistoryPayments: paymentsHistorySelector(state).length > 0,
anyCreditCardAttempts: creditCardAttemptionsSelector(state).length > 0,
Expand Down