Skip to content

Commit

Permalink
feat: scooter help screen (#4936)
Browse files Browse the repository at this point in the history
* fix: update config-specs version

* feat: add ScooterHelpScreen using data from firestore

* feat: update markdown-renderer to handle numbered lists

* fix: only one expandable section is open at the time

* fix: revert markdown renderer updates, should be separate PR

* fix: revert markdown renderer

* fix: rename index state and handle undefined operator
  • Loading branch information
jorunnl authored Jan 20, 2025
1 parent d59aa35 commit 2e785b9
Show file tree
Hide file tree
Showing 20 changed files with 191 additions and 17 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
},
"dependencies": {
"@adrianso/react-native-device-brightness": "^1.2.7",
"@atb-as/config-specs": "^5.2.0",
"@atb-as/config-specs": "^5.3.0",
"@atb-as/generate-assets": "^14.0.3",
"@atb-as/theme": "^13.1.2",
"@bugsnag/react-native": "^7.25.0",
Expand Down Expand Up @@ -167,8 +167,8 @@
"conventional-changelog-cli": "^5.0.0",
"eslint": "8.47.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-jsx-no-leaked-values": "0.1.24",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-no-leaked-values": "0.1.24",
"eslint-plugin-prettier": "5.0.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
Expand Down
21 changes: 21 additions & 0 deletions src/components/map/components/mobility/ShmoTesting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ import {Button} from '@atb/components/button';
import {ScrollView} from 'react-native-gesture-handler';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {useVehicle} from '@atb/mobility/use-vehicle';
import {useNavigation} from '@react-navigation/native';
import {RootNavigationProps} from '@atb/stacks-hierarchy';
import {useBottomSheetContext} from '@atb/components/bottom-sheet';

type ShmoTestingProps = {selectedVehicleId?: string};

Expand All @@ -31,6 +34,7 @@ export const ShmoTesting = ({selectedVehicleId}: ShmoTestingProps) => {
const destructiveColor = theme.color.interactive.destructive;

const {operatorId} = useVehicle(vehicleId ?? '');
const navigation = useNavigation<RootNavigationProps>();

const styles = useStyles();
const {height: windowHeight} = useWindowDimensions();
Expand All @@ -50,6 +54,8 @@ export const ShmoTesting = ({selectedVehicleId}: ShmoTestingProps) => {
const {data: activeShmoBooking} = useActiveShmoBookingQuery();
const {data: shmoBooking} = useShmoBookingQuery(previousBookingId);

const {close: closeBottomSheet} = useBottomSheetContext();

useEffect(() => {
if (selectedVehicleId) {
setVehicleId(selectedVehicleId);
Expand Down Expand Up @@ -199,6 +205,21 @@ export const ShmoTesting = ({selectedVehicleId}: ShmoTestingProps) => {
loading={getIdsFromQrCodeIsLoading}
hasShadow={true}
/>
<Button
expanded={false}
style={styles.filterButton}
compact={true}
interactiveColor={interactiveColor}
accessibilityRole="button"
onPress={() => {
closeBottomSheet();
navigation.navigate('Root_ScooterHelpScreen', {
vehicleId,
});
}}
text="Help"
hasShadow={true}
/>
</View>
);

Expand Down
18 changes: 18 additions & 0 deletions src/configuration/FirestoreConfigurationContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
TariffZone,
UserProfile,
MobilityOperatorType,
ScooterFaqType,
OperatorBenefitIdType,
FirestoreConfigStatus,
NotificationConfigType,
Expand All @@ -33,6 +34,7 @@ import {
mapToFlexibleTransportOption,
mapToHarborConnectionOverride,
mapToMobilityOperators,
mapToScooterFaqs,
mapToBenefitIdsRequiringValueCode,
mapToNotificationConfig,
mapToTransportModeFilterOptions,
Expand Down Expand Up @@ -68,6 +70,7 @@ type ConfigurationContextState = {
appTexts: AppTexts | undefined;
configurableLinks: ConfigurableLinksType | undefined;
mobilityOperators: MobilityOperatorType[] | undefined;
scooterFaqs: ScooterFaqType[] | undefined;
benefitIdsRequiringValueCode: OperatorBenefitIdType[] | undefined;
harborConnectionOverrides: HarborConnectionOverrideType[] | undefined;
firestoreConfigStatus: FirestoreConfigStatus;
Expand Down Expand Up @@ -109,6 +112,7 @@ export const FirestoreConfigurationContextProvider: React.FC = ({children}) => {
const [mobilityOperators, setMobilityOperators] = useState<
MobilityOperatorType[]
>([]);
const [scooterFaqs, setScooterFaqs] = useState<ScooterFaqType[]>([]);
const [benefitIdsRequiringValueCode, setBenefitIdsRequiringValueCode] =
useState<OperatorBenefitIdType[]>([]);
const [harborConnectionOverrides, setHarborConnectionOverrides] = useState<
Expand Down Expand Up @@ -201,6 +205,11 @@ export const FirestoreConfigurationContextProvider: React.FC = ({children}) => {
setMobilityOperators(mobilityOperators);
}

const scooterFaqs = getScooterFaqsFromSnapshot(snapshot);
if (scooterFaqs) {
setScooterFaqs(scooterFaqs);
}

const benefitIdsRequiringValueCode =
getBenefitIdsRequiringValueCodeFromSnapshot(snapshot);
if (benefitIdsRequiringValueCode) {
Expand Down Expand Up @@ -279,6 +288,7 @@ export const FirestoreConfigurationContextProvider: React.FC = ({children}) => {
appTexts,
configurableLinks,
mobilityOperators,
scooterFaqs,
benefitIdsRequiringValueCode,
harborConnectionOverrides,
notificationConfig,
Expand All @@ -300,6 +310,7 @@ export const FirestoreConfigurationContextProvider: React.FC = ({children}) => {
appTexts,
configurableLinks,
mobilityOperators,
scooterFaqs,
benefitIdsRequiringValueCode,
harborConnectionOverrides,
notificationConfig,
Expand Down Expand Up @@ -574,6 +585,13 @@ function getMobilityOperatorsFromSnapshot(
return mapToMobilityOperators(operators?.get('operators'));
}

function getScooterFaqsFromSnapshot(
snapshot: FirebaseFirestoreTypes.QuerySnapshot,
): ScooterFaqType[] | undefined {
const faqs = snapshot.docs.find((doc) => doc.id == 'mobility');
return mapToScooterFaqs(faqs?.get('scooterFaqs'));
}

function getBenefitIdsRequiringValueCodeFromSnapshot(
snapshot: FirebaseFirestoreTypes.QuerySnapshot,
): OperatorBenefitIdType[] | undefined {
Expand Down
15 changes: 15 additions & 0 deletions src/configuration/converters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
FareProductGroup,
FareProductGroupType,
OperatorBenefitId,
ScooterFaq,
} from './types';
import {LanguageAndTextType} from '@atb/translations/types';
import Bugsnag from '@bugsnag/react-native';
Expand Down Expand Up @@ -141,6 +142,20 @@ export function mapToMobilityOperators(operators?: any) {
.filter(isDefined);
}

export function mapToScooterFaqs(scooterFaqs?: any) {
if (!scooterFaqs) return;
if (!Array.isArray(scooterFaqs)) return;
return scooterFaqs
.map((scooterFaq) => {
const parseResult = ScooterFaq.safeParse(scooterFaq);
if (!parseResult.success) {
return;
}
return parseResult.data;
})
.filter(isDefined);
}

export function mapToBenefitIdsRequiringValueCode(
benefitIdsRequiringValueCode?: any,
) {
Expand Down
2 changes: 1 addition & 1 deletion src/configuration/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export * from '@atb-as/config-specs';
export * from '@atb-as/config-specs/lib/mobility-operators';
export * from '@atb-as/config-specs/lib/mobility';

export type FirestoreConfigStatus = 'loading' | 'success';

Expand Down
2 changes: 1 addition & 1 deletion src/mobility/__tests__/use-is-eligible-for-benefit.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {renderHook} from '@testing-library/react-hooks';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility-operators';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility';
import {UserBenefitsType} from '../api/api';
import {useIsEligibleForBenefit} from '@atb/mobility/use-is-eligible-for-benefit';

Expand Down
2 changes: 1 addition & 1 deletion src/mobility/api/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {client} from '@atb/api';
import {OperatorBenefitId} from '@atb-as/config-specs/lib/mobility-operators';
import {OperatorBenefitId} from '@atb-as/config-specs/lib/mobility';
import {getAxiosErrorMetadata} from '@atb/api/utils';
import {z} from 'zod';
import {PreassignedFareProduct} from '@atb/configuration/types';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {View} from 'react-native';
import {screenReaderPause, ThemeText} from '@atb/components/text';
import {BorderedInfoBox} from '@atb/components/bordered-info-box';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility-operators';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility';
import {getTextForLanguage, useTranslation} from '@atb/translations';
import {BenefitImageAsset} from '@atb/mobility/components/BenefitImage';
import React from 'react';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {View} from 'react-native';
import {ThemeText} from '@atb/components/text';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility-operators';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility';
import {getTextForLanguage, useTranslation} from '@atb/translations';
import {BenefitImageAsset} from '@atb/mobility/components/BenefitImage';
import React from 'react';
Expand Down
2 changes: 1 addition & 1 deletion src/mobility/components/OperatorActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {showAppMissingAlert} from '@atb/mobility/show-app-missing-alert';
import React, {useCallback} from 'react';
import {Button} from '@atb/components/button';
import {MobilityTexts} from '@atb/translations/screens/subscreens/MobilityTexts';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility-operators';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility';
import {ExternalLink} from '@atb/assets/svg/mono-icons/navigation';
import {ActivityIndicator, Linking} from 'react-native';
import {useValueCodeMutation} from '@atb/mobility/queries/use-value-code-mutation';
Expand Down
2 changes: 1 addition & 1 deletion src/mobility/components/OperatorBenefit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {GenericSectionItem, Section} from '@atb/components/sections';
import {View, ViewStyle} from 'react-native';
import {ThemeText} from '@atb/components/text';
import React from 'react';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility-operators';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility';
import {getTextForLanguage, useTranslation} from '@atb/translations';
import {useIsEligibleForBenefit} from '@atb/mobility/use-is-eligible-for-benefit';
import {FormFactor} from '@atb/api/types/generated/mobility-types_v2';
Expand Down
2 changes: 1 addition & 1 deletion src/mobility/components/PricingPlan.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {formatDecimalNumber} from '@atb/utils/numbers';
import {hasMultiplePricingPlans} from '@atb/mobility/utils';
import {OperatorBenefitIdType} from '@atb/configuration';
import {useIsEligibleForBenefit} from '@atb/mobility/use-is-eligible-for-benefit';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility-operators';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility';

type PricingPlanProps = {
operator: string;
Expand Down
2 changes: 1 addition & 1 deletion src/mobility/use-is-eligible-for-benefit.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {useUserBenefitsQuery} from '@atb/mobility/queries/use-user-benefits-query';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility-operators';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility';
import {isDefined} from '@atb/utils/presence';
import {useFirestoreConfigurationContext} from '@atb/configuration';

Expand Down
2 changes: 1 addition & 1 deletion src/mobility/use-operator-benefits-for-fare-product.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {PreassignedFareProduct} from '@atb/configuration/types';
import {useFareProductBenefitsQuery} from '@atb/mobility/queries/use-fare-product-benefits-query';
import {useOperators} from '@atb/mobility/use-operators';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility-operators';
import {OperatorBenefitType} from '@atb-as/config-specs/lib/mobility';
import {LanguageAndTextType} from '@atb-as/config-specs';
import {FormFactor} from '@atb/api/types/generated/mobility-types_v2';
import {UseQueryResult} from '@tanstack/react-query';
Expand Down
2 changes: 1 addition & 1 deletion src/mobility/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
import {Language} from '@atb/translations';
import {formatDecimalNumber} from '@atb/utils/numbers';
import {enumFromString} from '@atb/utils/enum-from-string';
import {MobilityOperatorType} from '@atb-as/config-specs/lib/mobility-operators';
import {MobilityOperatorType} from '@atb-as/config-specs/lib/mobility';

export const isScooter = (
feature: Feature<Point> | undefined,
Expand Down
5 changes: 5 additions & 0 deletions src/stacks-hierarchy/RootStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import {useRegisterIntercomUser} from '@atb/chat/use-register-intercom-user';
import {useRemoteConfigContext} from '@atb/RemoteConfigContext';
import {ForceUpdateScreen} from '@atb/force-update-screen';
import {compareVersion} from '@atb/utils/compare-version';
import {Root_ScooterHelpScreen} from './Root_ParkingViolationsReporting/Root_ScooterHelpScreen';

type ResultState = PartialState<NavigationState> & {
state?: ResultState;
Expand Down Expand Up @@ -387,6 +388,10 @@ export const RootStack = () => {
name="Root_ActiveTokenOnPhoneRequiredForFareProductScreen"
component={Root_ActiveTokenOnPhoneRequiredForFareProductScreen}
/>
<Stack.Screen
name="Root_ScooterHelpScreen"
component={Root_ScooterHelpScreen}
/>
<Stack.Screen
name="Root_ParkingViolationsSelectScreen"
component={Root_ParkingViolationsSelectScreen}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import React, {useState} from 'react';
import {View} from 'react-native';
import {StyleSheet} from '@atb/theme';
import {ThemeText} from '@atb/components/text';
import {getTextForLanguage, useTranslation} from '@atb/translations';
import {RootNavigationProps, RootStackScreenProps} from '@atb/stacks-hierarchy';
import {ScooterHelpTexts} from '@atb/translations/screens/ScooterHelp';
import {ScreenContainer} from './components/ScreenContainer';
import {
ExpandableSectionItem,
LinkSectionItem,
Section,
} from '@atb/components/sections';
import {ContentHeading} from '@atb/components/heading';
import {useNavigation} from '@react-navigation/native';
import {useVehicle} from '@atb/mobility/use-vehicle';
import {useFirestoreConfigurationContext} from '@atb/configuration';

export type ScooterHelpScreenProps =
RootStackScreenProps<'Root_ScooterHelpScreen'>;

export const Root_ScooterHelpScreen = ({route}: ScooterHelpScreenProps) => {
const {vehicleId} = route.params;
const style = useStyles();
const {t, language} = useTranslation();
const navigation = useNavigation<RootNavigationProps>();
const {scooterFaqs} = useFirestoreConfigurationContext();
const [currentlyOpenFaqIndex, setCurrentlyOpenFaqIndex] = useState<number>();

const {operatorName, operatorId} = useVehicle(vehicleId);

return (
<ScreenContainer
leftHeaderButton={{type: 'close'}}
title={t(ScooterHelpTexts.title)}
>
<View style={style.container}>
<ContentHeading text={t(ScooterHelpTexts.contactAndReport)} />
<Section>
{operatorId != undefined && (
<LinkSectionItem
text={t(ScooterHelpTexts.contactOperator(operatorName))}
/>
)}
<LinkSectionItem
text={t(ScooterHelpTexts.reportParking)}
onPress={() =>
navigation.navigate('Root_ParkingViolationsSelectScreen')
}
/>
</Section>
<ContentHeading text={t(ScooterHelpTexts.faq)} />
<Section>
{scooterFaqs?.map((item, index) => (
<ExpandableSectionItem
key={item.id}
text={getTextForLanguage(item.title, language) ?? ''}
textType="body__primary--bold"
showIconText={false}
expanded={currentlyOpenFaqIndex === index}
onPress={() => {
setCurrentlyOpenFaqIndex(index);
}}
expandContent={
<ThemeText isMarkdown={true}>
{getTextForLanguage(item.description, language)}
</ThemeText>
}
/>
))}
</Section>
</View>
</ScreenContainer>
);
};

const useStyles = StyleSheet.createThemeHook((theme) => ({
container: {
rowGap: theme.spacing.small,
margin: theme.spacing.medium,
},
}));
5 changes: 5 additions & 0 deletions src/stacks-hierarchy/navigation-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ type Root_ParkingViolationsConfirmationParams = {
providerName: string | undefined;
};

type Root_ScooterHelpScreenParams = {
vehicleId: string;
};

type Root_PurchaseAsAnonymousConsequencesScreenParams = {
showLoginButton: boolean | undefined;
};
Expand Down Expand Up @@ -120,6 +124,7 @@ export type RootStackParamList = StackParams<{
Root_ParkingViolationsPhotoScreen: Root_ParkingViolationsPhotoParams;
Root_ParkingViolationsQrScreen: Root_ParkingViolationsQrParams;
Root_ParkingViolationsConfirmationScreen: Root_ParkingViolationsConfirmationParams;
Root_ScooterHelpScreen: Root_ScooterHelpScreenParams;
Root_NotificationPermissionScreen: undefined;
Root_LocationWhenInUsePermissionScreen: undefined;
Root_ChooseTicketRecipientScreen: Root_ChooseTicketRecipientScreenParams;
Expand Down
Loading

0 comments on commit 2e785b9

Please sign in to comment.