Fakultas Ilmu Komputer UI

Commit b6c6e618 authored by Wulan Mantiri's avatar Wulan Mantiri
Browse files

Integrate client weekly report API and implement bottom navbar

parent f7e12547
......@@ -12,7 +12,6 @@ export { default as ExtendedQuestionnaire } from './questionnaire/ExtendedQuesti
export { default as ProfileDietRecommendation } from './questionnaire/ProfileDietRecommendation';
export { default as ReadOnlyDietProfile } from './questionnaire/ReadOnlyDietProfile';
export * from './questionnaire/ExtendedQuestionnaire/components';
export { default as WeeklyReport } from './questionnaire/WeeklyReport';
export { default as Checkout } from './cart/Checkout';
export { default as ChoosePlan } from './cart/ChoosePlan';
......@@ -26,5 +25,9 @@ export { default as ClientListNutritionist } from './nutritionist/ClientListNutr
export { default as ClientListAdmin } from './admin/ClientListAdmin';
export { default as ClientProfile } from './profile/ClientProfile';
export { default as ClientDietRecommendationForAdmin } from './profile/ClientDietRecommendationForAdmin';
export { default as ClientRecommendation } from './recommendation/ClientRecommendation';
export { default as ClientDietRecommendationForAdmin } from './recommendation/ClientDietRecommendationForAdmin';
export { default as WeeklyReport } from './report/WeeklyReport';
export { default as ClientNavigation } from './navigation/ClientNavigation';
import React from 'react';
import { render } from '@testing-library/react-native';
import ClientNavigation, {
WeeklyReportStackScreen,
ExtQuestionnaireStackScreen,
} from '.';
import { NavigationContainer } from '@react-navigation/native';
describe('ClientNavigation', () => {
it('renders correctly', () => {
render(
<NavigationContainer>
<ClientNavigation />
</NavigationContainer>,
);
});
test('weekly report renders correctly', () => {
render(
<NavigationContainer>
<WeeklyReportStackScreen />
</NavigationContainer>,
);
});
test('profile renders correctly', () => {
render(
<NavigationContainer>
<ExtQuestionnaireStackScreen />
</NavigationContainer>,
);
});
});
import React, { FC } from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Icon } from 'react-native-elements';
import { colors, typography } from 'styles';
import * as ROUTES from 'constants/routes';
import ClientRecommendation from 'scenes/recommendation/ClientRecommendation';
import WeeklyReport from 'scenes/report/WeeklyReport';
import ComingSoonPage from 'scenes/common/ComingSoonPage';
import ExtendedQuestionnaire from 'scenes/questionnaire/ExtendedQuestionnaire';
import {
ConsentForm,
Questionnaire1,
Questionnaire2,
Questionnaire3,
Questionnaire4,
Questionnaire5,
} from 'scenes/questionnaire/ExtendedQuestionnaire/components';
import { screenOptions } from 'app/styles';
import { styles } from './styles';
interface NavRoute<T = any> {
name: string;
component: FC<T>;
header?: string;
}
const profileClientNavigation: NavRoute[] = [
{
name: ROUTES.extendedQuestionnaire,
component: ExtendedQuestionnaire,
},
...[
{
component: ConsentForm,
},
{
component: Questionnaire1,
},
{
component: Questionnaire2,
},
{
component: Questionnaire3,
},
{
component: Questionnaire4,
},
{
component: Questionnaire5,
},
].map((nav, id) => ({
...nav,
name: ROUTES.extendedQuestionnaireById(id),
})),
];
const ExtQuestionnaireStack = createStackNavigator();
export const ExtQuestionnaireStackScreen: FC = () => (
<ExtQuestionnaireStack.Navigator screenOptions={screenOptions}>
{profileClientNavigation.map((nav, i) => (
<ExtQuestionnaireStack.Screen
key={`ext-questionnaire-nav-${i}`}
name={nav.name}
component={nav.component}
options={{
headerShown: false,
}}
/>
))}
</ExtQuestionnaireStack.Navigator>
);
const reportClientNavigation: NavRoute[] = [
{
name: ROUTES.weeklyReportForm,
component: WeeklyReport,
},
{
name: ROUTES.weeklyReportChooseWeek,
component: ComingSoonPage,
},
];
const WeeklyReportStack = createStackNavigator();
export const WeeklyReportStackScreen: FC = () => (
<WeeklyReportStack.Navigator screenOptions={screenOptions}>
{reportClientNavigation.map((nav, i) => (
<WeeklyReportStack.Screen
key={`report-client-nav-${i}`}
name={nav.name}
component={nav.component}
options={{
headerShown: false,
}}
/>
))}
</WeeklyReportStack.Navigator>
);
const ClientTab = createBottomTabNavigator();
const ClientNavigation: FC = () => {
return (
<ClientTab.Navigator
initialRouteName={ROUTES.clientProfile}
sceneContainerStyle={styles.sceneStyle}
tabBarOptions={{
activeTintColor: colors.primaryVariant,
labelStyle: {
paddingVertical: 0,
marginVertical: 0,
...typography.headingMedium,
fontSize: 14,
},
style: {
height: 66,
paddingTop: 8,
paddingBottom: 8,
},
}}>
<ClientTab.Screen
name={ROUTES.clientProfile}
component={ExtQuestionnaireStackScreen}
options={{
tabBarLabel: 'Profil',
tabBarIcon: ({ color, size }) => (
<Icon name="home" color={color} size={size} />
),
}}
/>
<ClientTab.Screen
name={ROUTES.clientRecommendation}
component={ClientRecommendation}
options={{
tabBarLabel: 'Rekomendasi',
tabBarIcon: ({ color, size }) => (
<Icon
name="nutrition"
type="material-community"
color={color}
size={size}
/>
),
}}
/>
<ClientTab.Screen
name={ROUTES.clientWeeklyReport}
component={WeeklyReportStackScreen}
options={{
tabBarLabel: 'Laporan Diet',
tabBarIcon: ({ color, size }) => (
<Icon
name="file-document-edit-outline"
type="material-community"
color={color}
size={size}
/>
),
}}
/>
<ClientTab.Screen
name={ROUTES.clientChat}
component={ComingSoonPage}
options={{
tabBarLabel: 'Chat',
tabBarIcon: ({ color, size }) => (
<Icon name="chatbox" type="ionicon" color={color} size={size} />
),
}}
/>
</ClientTab.Navigator>
);
};
export default ClientNavigation;
import { StyleSheet } from 'react-native';
export const styles = StyleSheet.create({
sceneStyle: {
backgroundColor: 'transparent',
},
});
......@@ -29,7 +29,7 @@ const PaymentResult: FC = () => {
const redirectToQuestionnaire = () => {
navigation.reset({
index: 0,
routes: [{ name: ROUTES.extendedQuestionnaire }],
routes: [{ name: ROUTES.clientTabNavigation }],
});
};
......
import React from 'react';
import { render, waitFor } from 'utils/testing';
import * as ROUTES from 'constants/routes';
import { render, waitFor } from '@testing-library/react-native';
import axios from 'axios';
import { mockDietQuestionnaire } from 'mocks/dietQuestionnaire';
......@@ -19,7 +18,7 @@ describe('ExtendedQuestionnaire', () => {
it('renders correctly', async () => {
mockAxios.request.mockImplementationOnce(retrieveDietQuestionnaireApi);
render(<ExtendedQuestionnaire />, ROUTES.extendedQuestionnaire);
render(<ExtendedQuestionnaire />);
await waitFor(() => expect(mockAxios.request).toBeCalled());
});
});
......@@ -26,7 +26,6 @@ const ExtendedQuestionnaire: FC = () => {
name,
route: ROUTES.extendedQuestionnaireById(i),
}))}
finishRedirectRoute={ROUTES.clientProfile}
defaultValues={data}
/>
);
......
......@@ -28,7 +28,7 @@ const ReadOnlyDietRecommendation: FC<Props> = ({ children, data }) => {
if (!data || !hasValues(data)) {
return (
<View style={styles.noRecom}>
<EmptyDataPage text="Belum ada rekomendasi dari nutritionis" />
<EmptyDataPage text="Belum ada rekomendasi dari nutrisionis" />
{children}
</View>
);
......
import React, { FC, useState } from 'react';
import { View, Dimensions } from 'react-native';
import Carousel from 'react-native-snap-carousel';
import { CarouselPagination } from 'components/core';
import { useForm } from 'hooks';
import { generateValidationSchema } from 'utils/form';
import { initialValues, fieldValidations } from './schema';
import { styles } from './styles';
import { pages } from './components';
const WeeklyReport: FC = () => {
const [activeSlide, setActiveSlide] = useState(0);
const {
getTextInputProps,
getFormFieldProps,
handleSubmit,
isSubmitting,
} = useForm({
initialValues,
validationSchema: generateValidationSchema(fieldValidations),
onSubmit: (values) => {
console.log(values);
},
});
return (
<View style={styles.view}>
<Carousel
data={pages.map((Component) => (
<Component
getFormFieldProps={getFormFieldProps}
getTextInputProps={getTextInputProps}
isSubmitting={isSubmitting}
handleSubmit={handleSubmit}
/>
))}
renderItem={({ item }: any) => item}
sliderWidth={Dimensions.get('window').width}
itemWidth={Dimensions.get('window').width}
onSnapToItem={setActiveSlide}
/>
<CarouselPagination index={activeSlide} length={pages.length} />
</View>
);
};
export default WeeklyReport;
import React from 'react';
import { render, fireEvent, waitFor } from '@testing-library/react-native';
import { render, waitFor } from '@testing-library/react-native';
import axios from 'axios';
import ClientProfile from '.';
......@@ -8,16 +8,6 @@ import { mockDietRecommendation } from 'mocks/dietRecommendation';
jest.mock('axios');
const mockAxios = axios as jest.Mocked<typeof axios>;
const mockedNavigate = jest.fn();
jest.mock('@react-navigation/native', () => {
return {
useNavigation: () => ({
navigate: mockedNavigate,
}),
};
});
describe('ClientProfile', () => {
const retrievedietRecommendationApi = () =>
Promise.resolve({
......@@ -41,17 +31,4 @@ describe('ClientProfile', () => {
render(<ClientProfile />);
await waitFor(() => expect(mockAxios.request).toBeCalled());
});
it('redirects to extended questionnaire when "Ubah profil" button is pressed', async () => {
mockAxios.request.mockImplementationOnce(retrievedietRecommendationApi);
const { getByText } = render(<ClientProfile />);
await waitFor(() => expect(mockAxios.request).toBeCalled());
const changeProfileButton = getByText(/ubah profil/i);
expect(changeProfileButton).toBeTruthy();
fireEvent.press(changeProfileButton);
expect(mockedNavigate).toBeCalled();
});
});
import React, { FC } from 'react';
import { useNavigation } from '@react-navigation/native';
import { Button } from 'react-native-elements';
import { Loader } from 'components/core';
import * as ROUTES from 'constants/routes';
import ReadOnlyDietRecommendation from 'scenes/questionnaire/ReadOnlyDietRecommendation';
import { Section } from 'components/layout';
import { typographyStyles } from 'styles';
import { useApi } from 'hooks';
import { retrieveDietRecommendationApi } from 'services/dietRecommendation';
import { styles } from './styles';
const ClientProfile: FC = () => {
const navigation = useNavigation();
const ClientRecommendation: FC = () => {
const { isLoading, data: recommendation } = useApi(
retrieveDietRecommendationApi,
);
......@@ -28,18 +19,9 @@ const ClientProfile: FC = () => {
recommendation && recommendation.length > 0
? recommendation[0]
: undefined
}>
<Section>
<Button
title="ubah profil"
type="outline"
onPress={() => navigation.navigate(ROUTES.extendedQuestionnaire)}
buttonStyle={styles.buttonStyle}
titleStyle={[typographyStyles.overlineBig, styles.titleStyle]}
}
/>
</Section>
</ReadOnlyDietRecommendation>
);
};
export default ClientProfile;
export default ClientRecommendation;
import React from 'react';
import { render } from '@testing-library/react-native';
import WeeklyReport from '.';
import Report1 from '.';
describe('WeeklyReport', () => {
describe('Report1', () => {
it('renders correctly', () => {
render(<WeeklyReport />);
render(
<Report1 getTextInputProps={jest.fn()} getFormFieldProps={jest.fn()} />,
);
});
});
import React, { FC } from 'react';
import { ScrollView } from 'react-native';
import { View } from 'react-native';
import { TextField } from 'components/form';
import { dietReportTextFields } from 'constants/weeklyReport';
......@@ -7,7 +7,7 @@ import { ReportProps } from '../../types';
import { layoutStyles } from 'styles';
const Report1: FC<ReportProps> = ({ getTextInputProps }) => (
<ScrollView contentContainerStyle={layoutStyles}>
<View style={layoutStyles}>
{dietReportTextFields.dietReportPage1.map((props, i) => (
<TextField
{...props}
......@@ -15,7 +15,7 @@ const Report1: FC<ReportProps> = ({ getTextInputProps }) => (
key={`report1-textfield${i}`}
/>
))}
</ScrollView>
</View>
);
export default Report1;
import React from 'react';
import { render } from '@testing-library/react-native';
import Report2 from '.';
describe('Report2', () => {
it('renders correctly', () => {
render(
<Report2 getTextInputProps={jest.fn()} getFormFieldProps={jest.fn()} />,
);
});
});
import React, { FC } from 'react';
import { ScrollView, View, StyleSheet } from 'react-native';
import { View, StyleSheet } from 'react-native';
import { LikertScale, RadioButtonGroup, TextField } from 'components/form';
import {
......@@ -10,7 +10,7 @@ import { ReportProps } from '../../types';
import { layoutStyles } from 'styles';
const Report2: FC<ReportProps> = ({ getTextInputProps, getFormFieldProps }) => (
<ScrollView contentContainerStyle={layoutStyles}>
<View style={layoutStyles}>
{dietReportSelectFields.dietReportPage2.map((props, i) => {
const FormField = props.scaleDescription ? LikertScale : RadioButtonGroup;
return (
......@@ -34,7 +34,7 @@ const Report2: FC<ReportProps> = ({ getTextInputProps, getFormFieldProps }) => (
key={`report2-textfield${i}`}
/>
))}
</ScrollView>
</View>
);
export const styles = StyleSheet.create({
......
import React from 'react';
import { render } from '@testing-library/react-native';
import Report3 from '.';
describe('Report3', () => {
it('renders correctly', () => {
render(
<Report3 getTextInputProps={jest.fn()} getFormFieldProps={jest.fn()} />,
);
});
});
import React, { FC } from 'react';
import { ScrollView, View, StyleSheet } from 'react-native';
import { View, StyleSheet } from 'react-native';
import { Text } from 'react-native-elements';
import { LikertScale } from 'components/form';
......@@ -8,7 +8,7 @@ import { ReportProps } from '../../types';
import { layoutStyles, typographyStyles } from 'styles';
const Report3: FC<ReportProps> = ({ getFormFieldProps }) => (
<ScrollView contentContainerStyle={layoutStyles}>
<View style={layoutStyles}>
<Text style={[typographyStyles.bodyMedium, styles.spacing]}>
Selama 1 minggu terakhir, berapa rata-rata Anda mengonsumsi jenis makanan
atau minuman dibawah ini selama seharian:
......@@ -26,7 +26,7 @@ const Report3: FC<ReportProps> = ({ getFormFieldProps }) => (
/>
</View>
))}
</ScrollView>
</View>
);
export const styles = StyleSheet.create({
......
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