Fakultas Ilmu Komputer UI
Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
ppl-fasilkom-ui
2021
Kelas D
PT Gizi Sehat - Dietela
Dietela Mobile
Commits
b6c6e618
Commit
b6c6e618
authored
Jun 01, 2021
by
Wulan Mantiri
Browse files
Integrate client weekly report API and implement bottom navbar
parent
f7e12547
Changes
52
Show whitespace changes
Inline
Side-by-side
src/scenes/index.ts
View file @
b6c6e618
...
...
@@ -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
'
;
src/scenes/navigation/ClientNavigation/index.test.tsx
0 → 100644
View file @
b6c6e618
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
>,
);
});
});
src/scenes/navigation/ClientNavigation/index.tsx
0 → 100644
View file @
b6c6e618
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
;
src/scenes/navigation/ClientNavigation/styles.ts
0 → 100644
View file @
b6c6e618
import
{
StyleSheet
}
from
'
react-native
'
;
export
const
styles
=
StyleSheet
.
create
({
sceneStyle
:
{
backgroundColor
:
'
transparent
'
,
},
});
src/scenes/payment/PaymentResult/index.tsx
View file @
b6c6e618
...
...
@@ -29,7 +29,7 @@ const PaymentResult: FC = () => {
const
redirectToQuestionnaire
=
()
=>
{
navigation
.
reset
({
index
:
0
,
routes
:
[{
name
:
ROUTES
.
extendedQuestionnaire
}],
routes
:
[{
name
:
ROUTES
.
clientTabNavigation
}],
});
};
...
...
src/scenes/questionnaire/ExtendedQuestionnaire/index.test.tsx
View file @
b6c6e618
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
());
});
});
src/scenes/questionnaire/ExtendedQuestionnaire/index.tsx
View file @
b6c6e618
...
...
@@ -26,7 +26,6 @@ const ExtendedQuestionnaire: FC = () => {
name
,
route
:
ROUTES
.
extendedQuestionnaireById
(
i
),
}))
}
finishRedirectRoute
=
{
ROUTES
.
clientProfile
}
defaultValues
=
{
data
}
/>
);
...
...
src/scenes/questionnaire/ReadOnlyDietRecommendation/index.tsx
View file @
b6c6e618
...
...
@@ -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 nutri
t
ionis"
/>
<
EmptyDataPage
text
=
"Belum ada rekomendasi dari nutri
s
ionis"
/>
{
children
}
</
View
>
);
...
...
src/scenes/questionnaire/WeeklyReport/index.tsx
deleted
100644 → 0
View file @
f7e12547
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
;
src/scenes/
profile
/ClientDietRecommendationForAdmin/index.test.tsx
→
src/scenes/
recommendation
/ClientDietRecommendationForAdmin/index.test.tsx
View file @
b6c6e618
File moved
src/scenes/
profile
/ClientDietRecommendationForAdmin/index.tsx
→
src/scenes/
recommendation
/ClientDietRecommendationForAdmin/index.tsx
View file @
b6c6e618
File moved
src/scenes/
profile/ClientProfile
/index.test.tsx
→
src/scenes/
recommendation/ClientRecommendation
/index.test.tsx
View file @
b6c6e618
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
();
});
});
src/scenes/
profile/ClientProfile
/index.tsx
→
src/scenes/
recommendation/ClientRecommendation
/index.tsx
View file @
b6c6e618
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
Client
Profile
;
export
default
Client
Recommendation
;
src/scenes/
profile/ClientProfile
/styles.ts
→
src/scenes/
recommendation/ClientRecommendation
/styles.ts
View file @
b6c6e618
File moved
src/scenes/
questionnaire/WeeklyReport
/index.test.tsx
→
src/scenes/
report/WeeklyReport/components/Report1
/index.test.tsx
View file @
b6c6e618
import
React
from
'
react
'
;
import
{
render
}
from
'
@testing-library/react-native
'
;
import
Weekly
Report
from
'
.
'
;
import
Report
1
from
'
.
'
;
describe
(
'
Weekly
Report
'
,
()
=>
{
describe
(
'
Report
1
'
,
()
=>
{
it
(
'
renders correctly
'
,
()
=>
{
render
(<
WeeklyReport
/>);
render
(
<
Report1
getTextInputProps
=
{
jest
.
fn
()
}
getFormFieldProps
=
{
jest
.
fn
()
}
/>,
);
});
});
src/scenes/
questionnaire
/WeeklyReport/components/Report1/index.tsx
→
src/scenes/
report
/WeeklyReport/components/Report1/index.tsx
View file @
b6c6e618
import
React
,
{
FC
}
from
'
react
'
;
import
{
Scroll
View
}
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
contentContainerS
tyle
=
{
layoutStyles
}
>
<
View
s
tyle
=
{
layoutStyles
}
>
{
dietReportTextFields
.
dietReportPage1
.
map
((
props
,
i
)
=>
(
<
TextField
{
...
props
}
...
...
@@ -15,7 +15,7 @@ const Report1: FC<ReportProps> = ({ getTextInputProps }) => (
key
=
{
`report1-textfield
${
i
}
`
}
/>
))
}
</
Scroll
View
>
</
View
>
);
export
default
Report1
;
src/scenes/report/WeeklyReport/components/Report2/index.test.tsx
0 → 100644
View file @
b6c6e618
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
()
}
/>,
);
});
});
src/scenes/
questionnaire
/WeeklyReport/components/Report2/index.tsx
→
src/scenes/
report
/WeeklyReport/components/Report2/index.tsx
View file @
b6c6e618
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
contentContainerS
tyle
=
{
layoutStyles
}
>
<
View
s
tyle
=
{
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
}
`
}
/>
))
}
</
Scroll
View
>
</
View
>
);
export
const
styles
=
StyleSheet
.
create
({
...
...
src/scenes/report/WeeklyReport/components/Report3/index.test.tsx
0 → 100644
View file @
b6c6e618
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
()
}
/>,
);
});
});
src/scenes/
questionnaire
/WeeklyReport/components/Report3/index.tsx
→
src/scenes/
report
/WeeklyReport/components/Report3/index.tsx
View file @
b6c6e618
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
contentContainerS
tyle
=
{
layoutStyles
}
>
<
View
s
tyle
=
{
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
>
))
}
</
Scroll
View
>
</
View
>
);
export
const
styles
=
StyleSheet
.
create
({
...
...
Prev
1
2
3
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment