Skip to content

Commit

Permalink
feat: Disable toggling to t card when using boat tickets (#3655)
Browse files Browse the repository at this point in the history
  • Loading branch information
jorelosorio committed Jun 23, 2023
1 parent 95f810c commit 980ec19
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 16 deletions.
4 changes: 4 additions & 0 deletions src/reference-data/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export const findReferenceDataById = <
id: string,
) => elements.find((p) => p.id === id);

export function isOfFareProductRef(a: any): a is {fareProductRef: string} {
return 'fareProductRef' in a;
}

export const productIsSellableInApp = (product: PreassignedFareProduct) => {
if (
(product.limitations.appVersionMin &&
Expand Down
89 changes: 78 additions & 11 deletions src/select-travel-token-screen/SelectTravelTokenScreenComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,35 @@ import {
isCarnetTravelRight,
useTicketingState,
} from '@atb/ticketing';
import {TravelTokenTexts, useTranslation} from '@atb/translations';
import {
TravelTokenTexts,
getTextForLanguage,
useTranslation,
} from '@atb/translations';
import {animateNextChange} from '@atb/utils/animation';
import {flatMap} from '@atb/utils/array';
import React, {useCallback, useState} from 'react';
import {ActivityIndicator, View} from 'react-native';
import {ScrollView} from 'react-native-gesture-handler';
import {RadioGroupSection, Section} from '@atb/components/sections';
import {useRemoteConfig} from '@atb/RemoteConfigContext';
import {useFirestoreConfiguration} from '@atb/configuration';
import {onlyUniquesBasedOnField} from '@atb/utils/only-uniques';
import {
findReferenceDataById,
isOfFareProductRef,
} from '@atb/reference-data/utils';

type Props = {onAfterSave: () => void};

export const SelectTravelTokenScreenComponent = ({onAfterSave}: Props) => {
const styles = useStyles();
const {t} = useTranslation();
const {t, language} = useTranslation();

const {fareContracts} = useTicketingState();
const {disable_travelcard} = useRemoteConfig();
const {fareProductTypeConfigs, preassignedFareProducts} =
useFirestoreConfiguration();

const {token, remoteTokens, toggleToken} = useMobileTokenContextState();
const inspectableToken = findInspectable(remoteTokens);
Expand All @@ -47,10 +59,36 @@ export const SelectTravelTokenScreenComponent = ({onAfterSave}: Props) => {
inspectableToken,
);

const hasActiveCarnetFareContract = flatMap(
const activeFareContracts = flatMap(
filterActiveOrCanBeUsedFareContracts(fareContracts),
(i) => i.travelRights,
).some(isCarnetTravelRight);
);

const hasActiveCarnetFareContract =
activeFareContracts.some(isCarnetTravelRight);

// Filter for unique travel rights config types
const activeFareContractsTypes = activeFareContracts
.filter(onlyUniquesBasedOnField('type'))
.map((travelRight) => {
const preassignedFareProduct = findReferenceDataById(
preassignedFareProducts,
isOfFareProductRef(travelRight) ? travelRight.fareProductRef : '',
);

return (
preassignedFareProduct &&
fareProductTypeConfigs.find(
(c) => c.type === preassignedFareProduct.type,
)
);
});

const fareProductConfigWhichRequiresTokenOnMobile =
activeFareContractsTypes.find(
(fareProductTypeConfig) =>
fareProductTypeConfig?.configuration.requiresTokenOnMobile === true,
);

const [saveState, setSaveState] = useState({
saving: false,
Expand All @@ -76,6 +114,14 @@ export const SelectTravelTokenScreenComponent = ({onAfterSave}: Props) => {
const travelCardToken = remoteTokens?.find(isTravelCardToken);
const mobileTokens = remoteTokens?.filter(isMobileToken);

// Shows an error message if switching to a t:card,
// but the current inspectable token is in the mobile AND
// requires mobile token
const requiresTokenOnMobile =
selectedType === 'travelCard' &&
isMobileToken(inspectableToken) &&
!!fareProductConfigWhichRequiresTokenOnMobile;

return (
<View style={styles.container}>
<FullScreenHeader
Expand Down Expand Up @@ -167,6 +213,25 @@ export const SelectTravelTokenScreenComponent = ({onAfterSave}: Props) => {
isMarkdown={false}
/>
)}

{requiresTokenOnMobile && (
<MessageBox
type={'error'}
title={t(
TravelTokenTexts.toggleToken.notAllowedToUseCarnetError.title,
)}
message={t(
TravelTokenTexts.toggleToken.notAllowedToUseCarnetError.message(
getTextForLanguage(
fareProductConfigWhichRequiresTokenOnMobile.name,
language,
) ?? '',
),
)}
style={styles.errorMessageBox}
isMarkdown={false}
/>
)}
{selectedType === 'mobile' && mobileTokens?.length ? (
<Section type="spacious" style={styles.selectDeviceSection}>
<RadioGroupSection<RemoteToken>
Expand Down Expand Up @@ -202,13 +267,15 @@ export const SelectTravelTokenScreenComponent = ({onAfterSave}: Props) => {
{saveState.saving ? (
<ActivityIndicator size="large" />
) : (
<Button
onPress={onSave}
text={t(TravelTokenTexts.toggleToken.saveButton)}
interactiveColor="interactive_0"
disabled={!selectedToken}
testID="confirmSelectionButton"
/>
!requiresTokenOnMobile && (
<Button
onPress={onSave}
text={t(TravelTokenTexts.toggleToken.saveButton)}
interactiveColor="interactive_0"
disabled={!!selectedToken}
testID="confirmSelectionButton"
/>
)
)}
</ScrollView>
</View>
Expand Down
9 changes: 4 additions & 5 deletions src/stacks-hierarchy/Root_FareContractDetailsScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {MessageBox} from '@atb/components/message-box';
import {FullScreenHeader} from '@atb/components/screen-header';
import {useFirestoreConfiguration} from '@atb/configuration/FirestoreConfigurationContext';
import {findReferenceDataById} from '@atb/reference-data/utils';
import {
findReferenceDataById,
isOfFareProductRef,
} from '@atb/reference-data/utils';
import {StyleSheet} from '@atb/theme';
import {isPreActivatedTravelRight, useTicketingState} from '@atb/ticketing';
import {FareContractTexts, useTranslation} from '@atb/translations';
Expand All @@ -14,10 +17,6 @@ import {RootStackScreenProps} from '../stacks-hierarchy/navigation-types';

type Props = RootStackScreenProps<'Root_FareContractDetailsScreen'>;

function isOfFareProductRef(a: any): a is {fareProductRef: string} {
return 'fareProductRef' in a;
}

export function Root_FareContractDetailsScreen({navigation, route}: Props) {
const styles = useStyles();
const [now, setNow] = useState<number>(Date.now());
Expand Down
8 changes: 8 additions & 0 deletions src/translations/screens/subscreens/TravelToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,14 @@ const SelectTravelTokenTexts = {
'Du har et klippekort. Foreløpig fungerer ikke klippekort på mobil. Hvis du bytter til mobil vil du ikke kunne bruke klippekortet ditt.',
`You have an active punch card. Currently punch cards cannot be activated using a phone. If you change to a phone now, you will not be able to use your punch card.`,
),
notAllowedToUseCarnetError: {
title: _('Kan ikke brukes på t:kort', 'Cannot be used on t:cards'),
message: (ticketName: string) =>
_(
`Du har en aktiv ${ticketName}. Det er derfor ikke mulig å bytte til t:kort.`,
`You have an active ${ticketName}. It is therefore not possible to switch to a t:card.`,
),
},
unnamedDevice: _('Enhet uten navn', 'Unnamed device'),
},
};
Expand Down

0 comments on commit 980ec19

Please sign in to comment.