Fakultas Ilmu Komputer UI

Commit 1f89cc9d authored by Wulan Mantiri's avatar Wulan Mantiri
Browse files

Implement Choose Plan UI layout and integrate with API

parent a372f3fa
import React from 'react';
import { render, fireEvent, waitFor } from 'utils/testing';
import axios from 'axios';
import * as ROUTES from 'constants/routes';
import ChoosePlan from '.';
jest.mock('axios');
describe('ChoosePlan', () => {
const nutritionists = [
{
id: 1,
full_name_and_degree: 'Wendy',
registration_certificate_no: '123',
university: 'UI',
mastered_nutritional_problems: 'diet',
handled_age_group: '18',
another_practice_place: '-',
languages: 'English',
},
];
const retrieveNutritionistsApi = () =>
Promise.resolve({
status: 200,
data: nutritionists,
});
const mockAxios = axios as jest.Mocked<typeof axios>;
mockAxios.request.mockImplementation(retrieveNutritionistsApi);
it('redirects to cart page when user clicks Bayar button', async () => {
const { getByText } = render(<ChoosePlan />, ROUTES.choosePlan);
await waitFor(() => expect(mockAxios.request).toBeCalled());
const nextButton = getByText(/Lanjut/i);
expect(nextButton).toBeTruthy();
fireEvent.press(nextButton);
const payButton = getByText(/Bayar/i);
expect(payButton).toBeTruthy();
await waitFor(() => fireEvent.press(payButton));
const cartPage = getByText(/Coming Soon/i);
expect(cartPage).toBeTruthy();
});
it('redirects to program detail page when user clicks Baca selengkapnya button for program', async () => {
const { getAllByText, getByText } = render(
<ChoosePlan />,
ROUTES.choosePlan,
);
await waitFor(() => expect(mockAxios.request).toBeCalled());
const readMoreButton = getAllByText(/Baca selengkapnya/i)[0];
expect(readMoreButton).toBeTruthy();
fireEvent.press(readMoreButton);
const programDetailPage = getByText(/Coming Soon/i);
expect(programDetailPage).toBeTruthy();
});
it('redirects to nutritionist detail page when user clicks Baca selengkapnya button for nutritionist', async () => {
const { getAllByText, getByText } = render(
<ChoosePlan />,
ROUTES.choosePlan,
);
await waitFor(() => expect(mockAxios.request).toBeCalled());
const nextButton = getByText(/Lanjut/i);
expect(nextButton).toBeTruthy();
fireEvent.press(nextButton);
const readMoreButton = getAllByText(/Baca selengkapnya/i)[0];
expect(readMoreButton).toBeTruthy();
fireEvent.press(readMoreButton);
const nutritionistDetailPage = getByText(/Coming Soon/i);
expect(nutritionistDetailPage).toBeTruthy();
});
afterAll(() => {
jest.clearAllMocks();
});
});
import React, { FC, useState } from 'react';
import { ScrollView } from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import { useNavigation } from '@react-navigation/native';
import { WizardContainer, Loader } from 'components/core';
import CACHE_KEYS from 'constants/cacheKeys';
import * as ROUTES from 'constants/routes';
import { useForm, useApi } from 'hooks';
import { dietPrograms } from 'constants/dietelaProgram';
import { retrieveNutritionistsApi } from 'services/nutritionists';
import { Nutritionist } from 'services/nutritionists/models';
import { layoutStyles } from 'styles';
import { PricingList } from './components';
import { initialValues, sample } from './schema';
const ChoosePlan: FC = () => {
const navigation = useNavigation();
const [currentStep, setCurrentStep] = useState(1);
const { handleSubmit, getFormFieldProps } = useForm({
initialValues,
onSubmit: async (values) => {
await AsyncStorage.setItem(
CACHE_KEYS.selectedProgramId,
`${values.program}`,
);
await AsyncStorage.setItem(
CACHE_KEYS.selectedNutritionistId,
`${values.nutritionist}`,
);
navigation.navigate(ROUTES.cart);
},
});
const { isLoading, data: nutritionists = [] } = useApi(
retrieveNutritionistsApi,
);
if (isLoading) {
return <Loader />;
}
return (
<WizardContainer
currentStep={currentStep}
setCurrentStep={setCurrentStep}
components={[
<ScrollView contentContainerStyle={layoutStyles}>
<PricingList
headerText="Pilih Rekomendasi Program Dietela"
items={sample.map((code) => ({
...dietPrograms[code],
value: code,
onReadMore: () =>
navigation.navigate(ROUTES.programDetail, { id: code }),
}))}
{...getFormFieldProps('program')}
/>
</ScrollView>,
<ScrollView contentContainerStyle={layoutStyles}>
<PricingList
headerText="Pilih Nutrisionis Anda"
items={nutritionists.map((nutritionist: Nutritionist) => ({
title: nutritionist.full_name_and_degree,
value: nutritionist.id,
info: nutritionist.handled_age_group.split(','),
onReadMore: () =>
navigation.navigate(ROUTES.nutritionistDetail, {
id: nutritionist.id,
}),
}))}
{...getFormFieldProps('nutritionist')}
/>
</ScrollView>,
]}
onFinish={handleSubmit}
finishButtonLabel="Bayar"
/>
);
};
export default ChoosePlan;
import { FieldType, FieldValidation } from 'utils/form';
import { DietelaProgram } from 'services/cart/models';
export const initialValues = {
program: '',
nutritionist: '',
};
export const validations: FieldValidation[] = [
{
name: 'program',
required: true,
type: FieldType.TEXT,
},
{
name: 'nutritionist',
required: true,
type: FieldType.TEXT,
},
];
export const sample: DietelaProgram[] = [
DietelaProgram.TRIAL,
DietelaProgram.BABY_3,
];
import React from 'react';
import { render } from '@testing-library/react-native';
import ComingSoonPage from '.';
describe('ComingSoonPage', () => {
it('renders correctly', () => {
const { getByText } = render(<ComingSoonPage />);
expect(getByText(/Coming Soon/i)).toBeTruthy();
});
});
import React, { FC } from 'react';
import { View, Text, StyleSheet } from 'react-native';
const ComingSoonPage: FC = () => (
<View style={styles.container}>
<Text>Coming Soon</Text>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
export default ComingSoonPage;
export { default as AllAccessQuestionnaire } from './questionnaire/AllAccessQuestionnaire'; export { default as AllAccessQuestionnaire } from './questionnaire/AllAccessQuestionnaire';
export { default as ChoosePlan } from './cart/ChoosePlan';
export { default as ComingSoonPage } from './common/ComingSoonPage';
export { default as DietelaQuizResult } from './questionnaire/DietelaQuizResult'; export { default as DietelaQuizResult } from './questionnaire/DietelaQuizResult';
export { default as InitialPage } from './common/InitialPage'; export { default as InitialPage } from './common/InitialPage';
export enum DietelaProgram {
TRIAL = 'TRIAL',
BABY_1 = 'BABY_1',
BABY_3 = 'BABY_3',
GOALS_1 = 'GOALS_1',
GOALS_3 = 'GOALS_3',
GOALS_6 = 'GOALS_6',
BALANCED_1 = 'BALANCED_1',
BALANCED_3 = 'BALANCED_3',
BALANCED_6 = 'BALANCED_6',
}
import { api, RequestMethod, ApiResponse } from '../api';
import * as apiUrls from './urls';
import { Nutritionist } from './models';
export const retrieveNutritionistsApi = (): ApiResponse<Nutritionist[]> => {
return api(RequestMethod.GET, apiUrls.nutritionists);
};
export interface Nutritionist {
id: number;
full_name_and_degree: string;
registration_certificate_no: string;
university: string;
mastered_nutritional_problems: string;
handled_age_group: string;
another_practice_place: string;
languages: string;
}
export const nutritionists = 'nutritionists/';
...@@ -3688,10 +3688,10 @@ human-signals@^1.1.1: ...@@ -3688,10 +3688,10 @@ human-signals@^1.1.1:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
husky@^5.1.3: husky@^5.2.0:
version "5.1.3" version "5.2.0"
resolved "https://registry.yarnpkg.com/husky/-/husky-5.1.3.tgz#1a0645a4fe3ffc006c4d0d8bd0bcb4c98787cc9d" resolved "https://registry.yarnpkg.com/husky/-/husky-5.2.0.tgz#fc5e1c2300d34855d47de4753607d00943fc0802"
integrity sha512-fbNJ+Gz5wx2LIBtMweJNY1D7Uc8p1XERi5KNRMccwfQA+rXlxWNSdUxswo0gT8XqxywTIw7Ywm/F4v/O35RdMg== integrity sha512-AM8T/auHXRBxlrfPVLKP6jt49GCM2Zz47m8G3FOMsLmTv8Dj/fKVWE0Rh2d4Qrvmy131xEsdQnb3OXRib67PGg==
iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24: iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24:
version "0.4.24" version "0.4.24"
...@@ -4521,6 +4521,11 @@ jest-snapshot@^25.5.1: ...@@ -4521,6 +4521,11 @@ jest-snapshot@^25.5.1:
pretty-format "^25.5.0" pretty-format "^25.5.0"
semver "^6.3.0" semver "^6.3.0"
jest-transform-stub@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/jest-transform-stub/-/jest-transform-stub-2.0.0.tgz#19018b0851f7568972147a5d60074b55f0225a7d"
integrity sha512-lspHaCRx/mBbnm3h4uMMS3R5aZzMwyNpNIJLXj4cEsV0mIUtS4IjYJLSoyjRCtnxb6RIGJ4NL2quZzfIeNhbkg==
jest-util@^24.9.0: jest-util@^24.9.0:
version "24.9.0" version "24.9.0"
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162"
...@@ -6168,6 +6173,7 @@ react-native-snap-carousel@^3.9.1: ...@@ -6168,6 +6173,7 @@ react-native-snap-carousel@^3.9.1:
dependencies: dependencies:
prop-types "^15.6.1" prop-types "^15.6.1"
react-addons-shallow-compare "15.6.2" react-addons-shallow-compare "15.6.2"
react-native-toast-message@^1.4.9: react-native-toast-message@^1.4.9:
version "1.4.9" version "1.4.9"
resolved "https://registry.yarnpkg.com/react-native-toast-message/-/react-native-toast-message-1.4.9.tgz#47f33ac312fe2aee5dbdd4ae14745fa0d354102e" resolved "https://registry.yarnpkg.com/react-native-toast-message/-/react-native-toast-message-1.4.9.tgz#47f33ac312fe2aee5dbdd4ae14745fa0d354102e"
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment