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
9fd365e4
Commit
9fd365e4
authored
May 12, 2021
by
Kefas Satrio Bangkit Solidedantyo
Browse files
Merge branch 'PBI-9-read-diet-profile' into 'staging'
read-only diet profile See merge request
!49
parents
94bfdc25
1838bdd9
Pipeline
#76531
passed with stages
in 51 minutes and 17 seconds
Changes
31
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
package.json
View file @
9fd365e4
...
...
@@ -24,7 +24,7 @@
"
@testing-library/react-native
"
:
"
^7.2.0
"
,
"
axios
"
:
"
^0.21.1
"
,
"
dayjs
"
:
"
^1.10.4
"
,
"
formik
"
:
"
^
2.
2.6
"
,
"
formik
"
:
"
2.
0.7
"
,
"
react
"
:
"
16.13.1
"
,
"
react-native
"
:
"
0.63.4
"
,
"
react-native-dotenv
"
:
"
^2.5.5
"
,
...
...
src/__mocks__/dietQuestionnaire.ts
View file @
9fd365e4
...
...
@@ -2,6 +2,7 @@ import {
DietQuestionnaireResponse
,
DietQuestionnaireRequest
,
}
from
'
services/dietQuestionnaire/models
'
;
import
{
authResponse
}
from
'
./auth
'
;
const
validFormValues
:
DietQuestionnaireRequest
=
{
agree_to_all_statements_consent
:
1
,
...
...
@@ -57,5 +58,5 @@ export const mockDietQuestionnaire: DietQuestionnaireResponse = {
id
:
7
,
...
validFormValues
,
finished_steps
:
[],
user
:
30
,
user
:
authResponse
.
user
,
};
src/app/schema.ts
View file @
9fd365e4
...
...
@@ -3,6 +3,7 @@ import {
publicNavigation
,
unpaidClientNavigation
,
clientNavigation
,
nutritionistNavigation
,
}
from
'
constants/navigation
'
;
import
{
UserRole
,
AuthUserResponse
}
from
'
services/auth/models
'
;
import
{
TransactionStatus
}
from
'
services/payment/models
'
;
...
...
@@ -26,6 +27,12 @@ export const getNavigation = (
navigation
:
clientNavigation
,
};
}
if
(
user
.
role
===
UserRole
.
NUTRITIONIST
)
{
return
{
initialRoute
:
ROUTES
.
clientListForNutritionist
,
navigation
:
nutritionistNavigation
,
};
}
}
return
{
initialRoute
:
ROUTES
.
initial
,
...
...
src/constants/navigation.ts
View file @
9fd365e4
...
...
@@ -23,7 +23,9 @@ import {
// Private
Checkout
,
PaymentResult
,
ReadOnlyDietProfile
,
ClientListNutritionist
,
ComingSoonPage
,
ClientProfile
,
ClientProfileForAdmin
,
}
from
'
scenes
'
;
...
...
@@ -63,29 +65,6 @@ const navigation: NavRoute[] = [
},
];
export
const
nutritionistNavigation
:
NavRoute
[]
=
[
{
name
:
ROUTES
.
clientListNutritionist
,
component
:
ClientListNutritionist
,
header
:
'
Client List
'
,
},
{
name
:
ROUTES
.
clientChatNutritionist
,
component
:
ClientListNutritionist
,
//TODO next sprint
header
:
'
Chat Client
'
,
},
{
name
:
ROUTES
.
clientDietReportNutritionist
,
component
:
ClientListNutritionist
,
//TODO next sprint
header
:
"
Client's Diet Report
"
,
},
{
name
:
ROUTES
.
clientProfileNutritionist
,
component
:
ClientListNutritionist
,
//TODO next sprint
header
:
"
Client's Profile
"
,
},
];
export
const
publicNavigation
:
NavRoute
[]
=
[
{
name
:
ROUTES
.
initial
,
...
...
@@ -165,6 +144,29 @@ export const clientNavigation: NavRoute[] = [
})),
];
export
const
nutritionistNavigation
:
NavRoute
[]
=
[
{
name
:
ROUTES
.
clientListForNutritionist
,
component
:
ClientListNutritionist
,
header
:
'
List Klien
'
,
},
{
name
:
ROUTES
.
clientChatNutritionist
,
component
:
ComingSoonPage
,
header
:
'
Chat Klien
'
,
},
{
name
:
ROUTES
.
clientDietReportNutritionist
,
component
:
ComingSoonPage
,
header
:
'
Laporan Klien
'
,
},
{
name
:
ROUTES
.
clientProfileNutritionist
,
component
:
ReadOnlyDietProfile
,
header
:
'
Profil Klien
'
,
},
];
export
const
adminNavigation
:
NavRoute
[]
=
[
{
name
:
ROUTES
.
clientProfile
,
...
...
src/constants/questionnaire.ts
View file @
9fd365e4
...
...
@@ -10,6 +10,11 @@ export const pageHeaders: string[] = [
'
Kondisi Pribadi
'
,
];
export
const
dateField
:
{
label
:
string
;
name
:
string
}
=
{
label
:
'
Tanggal Lahir
'
,
name
:
'
date_of_birth
'
,
};
export
const
textFields
:
{
[
_
:
string
]:
TextFieldSchema
[]
}
=
{
identity
:
[
{
...
...
@@ -158,7 +163,7 @@ export const textFields: { [_: string]: TextFieldSchema[] } = {
],
};
export
const
selectFields
=
{
export
const
selectFields
:
{
[
_
:
string
]:
any
[]
}
=
{
identity
:
[
{
name
:
'
profession
'
,
...
...
@@ -301,7 +306,7 @@ export const selectFields = {
},
{
name
:
'
cigarette_alcohol_condition
'
,
label
:
'
A
d
akah Anda
t
er
masuk salah satu dibawah ini
?
'
,
label
:
'
A
p
akah Anda
m
er
okok/minum minuman beralkohol
?
'
,
choiceList
:
[
'
Saat ini merokok
'
,
'
Pernah merokok tetapi sudah berhenti
'
,
...
...
src/constants/routes.ts
View file @
9fd365e4
...
...
@@ -25,7 +25,7 @@ const payment = 'payment';
export
const
paymentResult
=
`
${
payment
}
/result`
;
const
nutritionist
=
'
nutritionist
'
;
export
const
clientListNutritionist
=
`
${
nutritionist
}
/client-list`
;
export
const
clientList
For
Nutritionist
=
`
${
nutritionist
}
/client-list`
;
export
const
clientProfileNutritionist
=
`
${
nutritionist
}
/client-profile`
;
export
const
clientDietReportNutritionist
=
`
${
nutritionist
}
/client-diet-report`
;
export
const
clientChatNutritionist
=
`
${
nutritionist
}
/client-chat`
;
src/scenes/index.ts
View file @
9fd365e4
...
...
@@ -8,6 +8,7 @@ export { default as ComingSoonPage } from './common/ComingSoonPage';
export
{
default
as
AllAccessQuestionnaire
}
from
'
./questionnaire/AllAccessQuestionnaire
'
;
export
{
default
as
DietelaQuizResult
}
from
'
./questionnaire/DietelaQuizResult
'
;
export
{
default
as
ExtendedQuestionnaire
}
from
'
./questionnaire/ExtendedQuestionnaire
'
;
export
{
default
as
ReadOnlyDietProfile
}
from
'
./questionnaire/ReadOnlyDietProfile
'
;
export
*
from
'
./questionnaire/ExtendedQuestionnaire/components
'
;
export
{
default
as
Checkout
}
from
'
./cart/Checkout
'
;
...
...
src/scenes/nutritionist/ClientListNutritionist/index.test.tsx
View file @
9fd365e4
...
...
@@ -16,7 +16,7 @@ describe('ClientListNutritionist', () => {
data
:
[],
}),
);
render
(<
ClientListNutritionist
/>,
ROUTES
.
clientListNutritionist
);
render
(<
ClientListNutritionist
/>,
ROUTES
.
clientList
For
Nutritionist
);
await
waitFor
(()
=>
expect
(
mockAxios
.
request
).
toBeCalled
());
});
});
src/scenes/nutritionist/ClientListNutritionist/index.tsx
View file @
9fd365e4
...
...
@@ -20,21 +20,17 @@ const ClientListNutritionist: FC = () => {
{
clients
.
map
((
client
,
idx
)
=>
(
<
ClientCardNutritionist
key
=
{
idx
}
clientName
=
{
client
.
name
}
clientName
=
{
client
.
user
.
name
}
onPressClientProfile
=
{
()
=>
{
navigation
.
navigate
(
ROUTES
.
clientProfileNutritionist
,
{
id
:
client
.
id
,
id
:
client
.
diet_questionnaire_
id
,
});
}
}
onPressClientDietReport
=
{
()
=>
{
navigation
.
navigate
(
ROUTES
.
clientDietReportNutritionist
,
{
id
:
client
.
id
,
});
navigation
.
navigate
(
ROUTES
.
clientDietReportNutritionist
,
{});
}
}
onPressClientChat
=
{
()
=>
{
navigation
.
navigate
(
ROUTES
.
clientChatNutritionist
,
{
id
:
client
.
id
,
});
navigation
.
navigate
(
ROUTES
.
clientChatNutritionist
,
{});
}
}
/>
))
}
...
...
src/scenes/questionnaire/ReadOnlyDietProfile/components/DietProfilePage/index.test.tsx
0 → 100644
View file @
9fd365e4
import
React
from
'
react
'
;
import
{
render
}
from
'
utils/testing
'
;
import
*
as
ROUTES
from
'
constants/routes
'
;
import
{
pages
}
from
'
../../pages
'
;
import
DietProfilePage
from
'
.
'
;
import
{
mockDietQuestionnaire
}
from
'
__mocks__/dietQuestionnaire
'
;
describe
(
'
DietProfilePage
'
,
()
=>
{
it
(
'
identity page renders correctly
'
,
()
=>
{
render
(
<
DietProfilePage
content
=
{
pages
[
0
](
mockDietQuestionnaire
)
}
/>,
ROUTES
.
clientProfileNutritionist
,
);
});
it
(
'
eating pattern page renders correctly
'
,
()
=>
{
render
(
<
DietProfilePage
content
=
{
pages
[
1
](
mockDietQuestionnaire
)
}
/>,
ROUTES
.
clientProfileNutritionist
,
);
});
it
(
'
daily food consumption page renders correctly
'
,
()
=>
{
render
(
<
DietProfilePage
content
=
{
pages
[
2
](
mockDietQuestionnaire
)
}
/>,
ROUTES
.
clientProfileNutritionist
,
);
});
it
(
'
lifestyle page renders correctly
'
,
()
=>
{
render
(
<
DietProfilePage
content
=
{
pages
[
3
](
mockDietQuestionnaire
)
}
/>,
ROUTES
.
clientProfileNutritionist
,
);
});
it
(
'
health condition page renders correctly
'
,
()
=>
{
render
(
<
DietProfilePage
content
=
{
pages
[
4
](
mockDietQuestionnaire
)
}
/>,
ROUTES
.
clientProfileNutritionist
,
);
});
});
src/scenes/questionnaire/ReadOnlyDietProfile/components/DietProfilePage/index.tsx
0 → 100644
View file @
9fd365e4
import
{
FC
}
from
'
react
'
;
import
{
Text
,
ScrollView
}
from
'
react-native
'
;
import
{
typography
}
from
'
styles
'
;
import
{
styles
}
from
'
./styles
'
;
import
React
from
'
react
'
;
import
QuestionAnswerCard
from
'
../QuestionAnswerCard
'
;
import
{
DietProfilePageContent
}
from
'
../../pages/types
'
;
const
DietProfilePage
:
FC
<
{
content
:
DietProfilePageContent
;
}
>
=
({
content
})
=>
{
return
(
<
ScrollView
style
=
{
styles
.
container
}
>
<
Text
style
=
{
[
typography
.
headingLarge
,
styles
.
nameMargin
]
}
>
{
content
.
title
}
</
Text
>
{
content
.
questions
.
map
((
qst
,
idx
)
=>
(
<
QuestionAnswerCard
key
=
{
idx
}
question
=
{
qst
.
label
}
answer
=
{
qst
.
answer
}
/>
))
}
</
ScrollView
>
);
};
export
default
DietProfilePage
;
src/scenes/questionnaire/ReadOnlyDietProfile/components/DietProfilePage/styles.ts
0 → 100644
View file @
9fd365e4
import
{
StyleSheet
,
Dimensions
}
from
'
react-native
'
;
export
const
styles
=
StyleSheet
.
create
({
nameMargin
:
{
marginBottom
:
15
,
},
container
:
{
width
:
Dimensions
.
get
(
'
window
'
).
width
-
40
,
},
});
src/scenes/questionnaire/ReadOnlyDietProfile/components/QuestionAnswerCard/index.test.tsx
0 → 100644
View file @
9fd365e4
import
React
from
'
react
'
;
import
{
render
}
from
'
utils/testing
'
;
import
*
as
ROUTES
from
'
constants/routes
'
;
import
QuestionAnswerCard
from
'
.
'
;
describe
(
'
QuestionAnswerCard
'
,
()
=>
{
it
(
'
renders correctly
'
,
()
=>
{
render
(
<
QuestionAnswerCard
question
=
"apa?"
answer
=
"yes"
/>,
ROUTES
.
clientProfileNutritionist
,
);
});
it
(
'
renders correctly with testID
'
,
()
=>
{
render
(
<
QuestionAnswerCard
testID
=
"question answer"
question
=
"apa?"
answer
=
"yes"
/>,
ROUTES
.
clientProfileNutritionist
,
);
});
});
src/scenes/questionnaire/ReadOnlyDietProfile/components/QuestionAnswerCard/index.tsx
0 → 100644
View file @
9fd365e4
import
{
FC
}
from
'
react
'
;
import
{
View
,
Text
}
from
'
react-native
'
;
import
React
from
'
react
'
;
import
{
InfoCard
}
from
'
components/core
'
;
import
{
typographyStyles
}
from
'
styles
'
;
import
{
styles
}
from
'
./styles
'
;
interface
Props
{
question
:
string
;
answer
:
string
;
testID
?:
string
;
}
const
QuestionAnswerCard
:
FC
<
Props
>
=
({
question
,
answer
,
testID
})
=>
{
return
(
<
View
style
=
{
styles
.
labelContainer
}
testID
=
{
testID
}
>
<
Text
style
=
{
[
typographyStyles
.
bodyLarge
,
styles
.
label
]
}
>
{
question
}
</
Text
>
<
InfoCard
content
=
{
answer
}
/>
</
View
>
);
};
export
default
QuestionAnswerCard
;
src/scenes/questionnaire/ReadOnlyDietProfile/components/QuestionAnswerCard/styles.ts
0 → 100644
View file @
9fd365e4
import
{
StyleSheet
}
from
'
react-native
'
;
export
const
styles
=
StyleSheet
.
create
({
label
:
{
marginBottom
:
5
,
marginTop
:
15
,
},
labelContainer
:
{
alignSelf
:
'
stretch
'
,
},
answer
:
{
flexDirection
:
'
row
'
,
},
});
src/scenes/questionnaire/ReadOnlyDietProfile/components/index.ts
0 → 100644
View file @
9fd365e4
export
{
default
as
QuestionAnswerCard
}
from
'
./QuestionAnswerCard
'
;
export
{
default
as
DietProfilePage
}
from
'
./DietProfilePage
'
;
src/scenes/questionnaire/ReadOnlyDietProfile/index.test.tsx
0 → 100644
View file @
9fd365e4
import
React
from
'
react
'
;
import
{
render
}
from
'
utils/testing
'
;
import
*
as
ROUTES
from
'
constants/routes
'
;
import
ReadOnlyDietProfile
from
'
.
'
;
import
{
mockDietQuestionnaire
}
from
'
__mocks__/dietQuestionnaire
'
;
describe
(
'
ReadOnlyDietProfile
'
,
()
=>
{
it
(
'
renders correctly
'
,
()
=>
{
render
(<
ReadOnlyDietProfile
/>,
ROUTES
.
clientProfileNutritionist
,
{
routeParams
:
mockDietQuestionnaire
,
});
});
});
src/scenes/questionnaire/ReadOnlyDietProfile/index.tsx
0 → 100644
View file @
9fd365e4
import
{
FC
,
useState
}
from
'
react
'
;
import
{
Dimensions
,
ScrollView
}
from
'
react-native
'
;
import
{
styles
}
from
'
./styles
'
;
import
{
layoutStyles
}
from
'
styles
'
;
import
{
useRoute
}
from
'
@react-navigation/native
'
;
import
React
from
'
react
'
;
import
{
DietProfilePage
}
from
'
./components
'
;
import
{
CarouselPagination
,
BigButton
,
Loader
}
from
'
components/core
'
;
import
Carousel
from
'
react-native-snap-carousel
'
;
import
{
pages
}
from
'
./pages
'
;
import
{
useApi
}
from
'
hooks
'
;
import
{
retrieveDietQuestionnaireByIdApi
}
from
'
services/dietQuestionnaire
'
;
import
{
DietQuestionnaireResponse
}
from
'
services/dietQuestionnaire/models
'
;
interface
QuestionnaireID
{
id
:
number
;
}
const
ReadOnlyDietProfile
:
FC
=
()
=>
{
const
[
activeSlide
,
setActiveSlide
]
=
useState
(
0
);
const
route
=
useRoute
();
const
{
id
}
=
route
.
params
as
QuestionnaireID
;
const
{
isLoading
,
data
}
=
useApi
(()
=>
retrieveDietQuestionnaireByIdApi
(
id
),
);
if
(
isLoading
)
{
return
<
Loader
/>;
}
return
(
<
ScrollView
contentContainerStyle
=
{
[
layoutStyles
,
styles
.
container
]
}
>
<
Carousel
data
=
{
pages
.
map
((
page
,
idx
)
=>
(
<
DietProfilePage
key
=
{
idx
}
content
=
{
page
(
data
as
DietQuestionnaireResponse
)
}
/>
))
}
renderItem
=
{
({
item
}:
any
)
=>
item
}
sliderWidth
=
{
Dimensions
.
get
(
'
window
'
).
width
}
itemWidth
=
{
Dimensions
.
get
(
'
window
'
).
width
}
onSnapToItem
=
{
setActiveSlide
}
/>
<
CarouselPagination
index
=
{
activeSlide
}
length
=
{
5
}
/>
<
BigButton
title
=
"Berikan Rekomendasi"
onPress
=
{
()
=>
{
// TODO: Doan
}
}
/>
</
ScrollView
>
);
};
export
default
ReadOnlyDietProfile
;
src/scenes/questionnaire/ReadOnlyDietProfile/pages/DailyFoodConsumption/index.ts
0 → 100644
View file @
9fd365e4
import
{
DietProfilePageContent
,
answerTypes
}
from
'
../types
'
;
import
{
getQuestionAnswerString
}
from
'
../utils
'
;
import
{
DietQuestionnaireResponse
}
from
'
services/dietQuestionnaire/models
'
;
import
{
pageHeaders
}
from
'
constants/questionnaire
'
;
export
const
dailyFoodConsumption
=
({
breakfast_meal_explanation
,
morning_snack_explanation
,
lunch_meal_explanation
,
evening_snack_explanation
,
dinner_meal_explanation
,
night_snack_explanation
,
}:
DietQuestionnaireResponse
):
DietProfilePageContent
=>
{
const
page
=
'
foodConsumption
'
;
return
{
title
:
pageHeaders
[
3
],
questions
:
[
getQuestionAnswerString
(
page
,
'
breakfast_meal_explanation
'
,
breakfast_meal_explanation
,
answerTypes
.
TEXT
,
),
getQuestionAnswerString
(
page
,
'
morning_snack_explanation
'
,
morning_snack_explanation
,
answerTypes
.
TEXT
,
),
getQuestionAnswerString
(
page
,
'
lunch_meal_explanation
'
,
lunch_meal_explanation
,
answerTypes
.
TEXT
,
),
getQuestionAnswerString
(
page
,
'
evening_snack_explanation
'
,
evening_snack_explanation
,
answerTypes
.
TEXT
,
),
getQuestionAnswerString
(
page
,
'
dinner_meal_explanation
'
,
dinner_meal_explanation
,
answerTypes
.
TEXT
,
),
getQuestionAnswerString
(
page
,
'
night_snack_explanation
'
,
night_snack_explanation
,
answerTypes
.
TEXT
,
),
],
};
};
src/scenes/questionnaire/ReadOnlyDietProfile/pages/EatingPattern/index.ts
0 → 100644
View file @
9fd365e4
import
{
DietProfilePageContent
,
answerTypes
}
from
'
../types
'
;
import
{
getQuestionAnswerString
}
from
'
../utils
'
;
import
{
DietQuestionnaireResponse
}
from
'
services/dietQuestionnaire/models
'
;
import
{
pageHeaders
}
from
'
constants/questionnaire
'
;
export
const
eatingPattern
=
({
breakfast_frequency
,
breakfast_meal_type
,
sweet_tea_consumption_frequency
,
coffee_consumption_frequency
,
milk_consumption_frequency
,
other_drink_consumption_frequency
,
additional_sugar_in_a_day
,
liquid_consumption_frequency
,
meal_consumed_almost_every_day
,
unliked_food
,
preferred_food_taste
,
expected_food_on_breakfast
,
expected_food_on_lunch_dinner
,
}:
DietQuestionnaireResponse
):
DietProfilePageContent
=>
{
const
page
=
'
eatingPattern
'
;
return
{
title
:
pageHeaders
[
2
],
questions
:
[
getQuestionAnswerString
(
page
,
'
breakfast_frequency
'
,
breakfast_frequency
,
answerTypes
.
SELECT
,
),
getQuestionAnswerString
(
page
,
'
breakfast_meal_type
'
,
breakfast_meal_type
,
answerTypes
.
SELECT
,
),
getQuestionAnswerString
(
page
,
'
sweet_tea_consumption_frequency
'
,
sweet_tea_consumption_frequency
,
answerTypes
.
SELECT
,
),
getQuestionAnswerString
(
page
,
'
coffee_consumption_frequency
'
,
coffee_consumption_frequency
,
answerTypes
.
SELECT
,
),
getQuestionAnswerString
(
page
,
'
milk_consumption_frequency
'
,
milk_consumption_frequency
,
answerTypes
.
SELECT
,
),
getQuestionAnswerString
(
page
,
'
other_drink_consumption_frequency
'
,
other_drink_consumption_frequency
,
answerTypes
.
SELECT
,
),
getQuestionAnswerString
(
page
,
'
additional_sugar_in_a_day
'
,
additional_sugar_in_a_day
,
answerTypes
.
SELECT
,
),
getQuestionAnswerString
(
page
,
'
liquid_consumption_frequency
'
,
liquid_consumption_frequency
,
answerTypes
.
SELECT
,
),
getQuestionAnswerString
(
page
,
'
meal_consumed_almost_every_day
'
,
meal_consumed_almost_every_day
,
answerTypes
.
TEXT
,
),
getQuestionAnswerString
(
page
,
'
unliked_food
'
,
unliked_food
,
answerTypes
.
TEXT
,
),
getQuestionAnswerString
(
page
,