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
8854d559
Commit
8854d559
authored
May 12, 2021
by
Wulan Mantiri
Committed by
Muzaki Azami
May 12, 2021
Browse files
Integrate client profile with read only diet recommendation API
parent
5d91ad27
Changes
17
Hide whitespace changes
Inline
Side-by-side
src/__mocks__/dietRecommendation.ts
0 → 100644
View file @
8854d559
export
const
mockDietRecommendation
=
{
id
:
1
,
client_plan_meal
:
''
,
nutritional_advice
:
'
good job
'
,
lifestyle_advice
:
'
haiya
'
,
nutritionist
:
1
,
client
:
1
,
};
src/constants/navigation.ts
View file @
8854d559
...
@@ -8,22 +8,24 @@ import {
...
@@ -8,22 +8,24 @@ import {
Questionnaire3
,
Questionnaire3
,
Questionnaire4
,
Questionnaire4
,
Questionnaire5
,
Questionnaire5
,
ClientProfile
,
//
Others
//
Public
AllAccessQuestionnaire
,
AllAccessQuestionnaire
,
Checkout
,
ChoosePlan
,
ChoosePlan
,
DietelaQuizResult
,
DietelaQuizResult
,
InitialPage
,
InitialPage
,
ManualRegistrationPage
,
ManualRegistrationPage
,
LoginPage
,
LoginPage
,
NutritionistAdminLogin
,
ProgramDetail
,
ProgramDetail
,
NutritionistDetail
,
NutritionistDetail
,
// Private
Checkout
,
PaymentResult
,
PaymentResult
,
ClientListNutritionist
,
ClientListNutritionist
,
ReadOnlyNutritionistRecommendation
,
ClientProfile
,
NutritionistAdminLog
in
,
ClientProfileForAdm
in
,
}
from
'
scenes
'
;
}
from
'
scenes
'
;
import
{
FC
}
from
'
react
'
;
import
{
FC
}
from
'
react
'
;
...
@@ -166,7 +168,7 @@ export const clientNavigation: NavRoute[] = [
...
@@ -166,7 +168,7 @@ export const clientNavigation: NavRoute[] = [
export
const
adminNavigation
:
NavRoute
[]
=
[
export
const
adminNavigation
:
NavRoute
[]
=
[
{
{
name
:
ROUTES
.
clientProfile
,
name
:
ROUTES
.
clientProfile
,
component
:
ReadOnlyNutritionistRecommendatio
n
,
component
:
ClientProfileForAdmi
n
,
header
:
'
Profil Klien
'
,
header
:
'
Profil Klien
'
,
},
},
];
];
...
...
src/hooks/useDownloadFiles/index.ts
View file @
8854d559
...
@@ -2,7 +2,7 @@ import { downloadFile, DocumentDirectoryPath } from 'react-native-fs';
...
@@ -2,7 +2,7 @@ import { downloadFile, DocumentDirectoryPath } from 'react-native-fs';
import
{
Toast
}
from
'
components/core
'
;
import
{
Toast
}
from
'
components/core
'
;
import
{
PermissionsAndroid
}
from
'
react-native
'
;
import
{
PermissionsAndroid
}
from
'
react-native
'
;
const
useDownloadFiles
=
(
url
:
string
)
=>
{
const
useDownloadFiles
=
(
url
=
''
)
=>
{
const
fileName
=
url
.
split
(
'
/
'
).
pop
();
const
fileName
=
url
.
split
(
'
/
'
).
pop
();
const
extension
=
fileName
?.
split
(
'
.
'
).
pop
()?.
toUpperCase
()
||
'
-
'
;
const
extension
=
fileName
?.
split
(
'
.
'
).
pop
()?.
toUpperCase
()
||
'
-
'
;
...
...
src/scenes/index.ts
View file @
8854d559
...
@@ -9,7 +9,6 @@ export { default as AllAccessQuestionnaire } from './questionnaire/AllAccessQues
...
@@ -9,7 +9,6 @@ export { default as AllAccessQuestionnaire } from './questionnaire/AllAccessQues
export
{
default
as
DietelaQuizResult
}
from
'
./questionnaire/DietelaQuizResult
'
;
export
{
default
as
DietelaQuizResult
}
from
'
./questionnaire/DietelaQuizResult
'
;
export
{
default
as
ExtendedQuestionnaire
}
from
'
./questionnaire/ExtendedQuestionnaire
'
;
export
{
default
as
ExtendedQuestionnaire
}
from
'
./questionnaire/ExtendedQuestionnaire
'
;
export
*
from
'
./questionnaire/ExtendedQuestionnaire/components
'
;
export
*
from
'
./questionnaire/ExtendedQuestionnaire/components
'
;
export
*
from
'
./questionnaire/NutritionistRecommendation
'
;
export
{
default
as
Checkout
}
from
'
./cart/Checkout
'
;
export
{
default
as
Checkout
}
from
'
./cart/Checkout
'
;
export
{
default
as
ChoosePlan
}
from
'
./cart/ChoosePlan
'
;
export
{
default
as
ChoosePlan
}
from
'
./cart/ChoosePlan
'
;
...
@@ -21,3 +20,4 @@ export { default as PaymentResult } from './payment/PaymentResult';
...
@@ -21,3 +20,4 @@ export { default as PaymentResult } from './payment/PaymentResult';
export
{
default
as
ClientListNutritionist
}
from
'
./nutritionist/ClientListNutritionist
'
;
export
{
default
as
ClientListNutritionist
}
from
'
./nutritionist/ClientListNutritionist
'
;
export
{
default
as
ClientProfile
}
from
'
./profile/ClientProfile
'
;
export
{
default
as
ClientProfile
}
from
'
./profile/ClientProfile
'
;
export
{
default
as
ClientProfileForAdmin
}
from
'
./profile/ClientProfileForAdmin
'
;
src/scenes/profile/ClientProfile/index.test.tsx
View file @
8854d559
import
React
from
'
react
'
;
import
React
from
'
react
'
;
import
{
render
,
fireEvent
}
from
'
@testing-library/react-native
'
;
import
{
render
,
fireEvent
,
waitFor
}
from
'
@testing-library/react-native
'
;
import
axios
from
'
axios
'
;
import
ClientProfile
from
'
.
'
;
import
ClientProfile
from
'
.
'
;
import
{
mockDietRecommendation
}
from
'
__mocks__/dietRecommendation
'
;
jest
.
mock
(
'
axios
'
);
const
mockAxios
=
axios
as
jest
.
Mocked
<
typeof
axios
>
;
const
mockedNavigate
=
jest
.
fn
();
const
mockedNavigate
=
jest
.
fn
();
...
@@ -14,9 +19,35 @@ jest.mock('@react-navigation/native', () => {
...
@@ -14,9 +19,35 @@ jest.mock('@react-navigation/native', () => {
});
});
describe
(
'
ClientProfile
'
,
()
=>
{
describe
(
'
ClientProfile
'
,
()
=>
{
it
(
'
renders correctly
'
,
()
=>
{
const
retrievedietRecommendationApi
=
()
=>
Promise
.
resolve
({
status
:
200
,
data
:
[
mockDietRecommendation
],
});
it
(
'
fetches data from backend and renders correctly
'
,
async
()
=>
{
mockAxios
.
request
.
mockImplementationOnce
(
retrievedietRecommendationApi
);
render
(<
ClientProfile
/>);
await
waitFor
(()
=>
expect
(
mockAxios
.
request
).
toBeCalled
());
});
it
(
'
fetches empty list from backend and still renders correctly
'
,
async
()
=>
{
mockAxios
.
request
.
mockImplementationOnce
(()
=>
Promise
.
resolve
({
status
:
200
,
data
:
[],
}),
);
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
/>);
const
{
getByText
}
=
render
(<
ClientProfile
/>);
await
waitFor
(()
=>
expect
(
mockAxios
.
request
).
toBeCalled
());
const
changeProfileButton
=
getByText
(
/ubah profil/i
);
const
changeProfileButton
=
getByText
(
/ubah profil/i
);
expect
(
changeProfileButton
).
toBeTruthy
();
expect
(
changeProfileButton
).
toBeTruthy
();
fireEvent
.
press
(
changeProfileButton
);
fireEvent
.
press
(
changeProfileButton
);
...
...
src/scenes/profile/ClientProfile/index.tsx
View file @
8854d559
...
@@ -2,18 +2,33 @@ import React, { FC } from 'react';
...
@@ -2,18 +2,33 @@ import React, { FC } from 'react';
import
{
useNavigation
}
from
'
@react-navigation/native
'
;
import
{
useNavigation
}
from
'
@react-navigation/native
'
;
import
{
Button
}
from
'
react-native-elements
'
;
import
{
Button
}
from
'
react-native-elements
'
;
import
{
Loader
}
from
'
components/core
'
;
import
*
as
ROUTES
from
'
constants/routes
'
;
import
*
as
ROUTES
from
'
constants/routes
'
;
import
{
ReadOnly
Nutritionis
tRecommendation
}
from
'
scenes/questionnaire/
Nutritionis
tRecommendation
'
;
import
ReadOnly
Die
tRecommendation
from
'
scenes/questionnaire/
ReadOnlyDie
tRecommendation
'
;
import
{
Section
}
from
'
components/layout
'
;
import
{
Section
}
from
'
components/layout
'
;
import
{
typographyStyles
}
from
'
styles
'
;
import
{
typographyStyles
}
from
'
styles
'
;
import
{
useApi
}
from
'
hooks
'
;
import
{
retrieveDietRecommendationApi
}
from
'
services/dietRecommendation
'
;
import
{
styles
}
from
'
./styles
'
;
import
{
styles
}
from
'
./styles
'
;
const
ClientProfile
:
FC
=
()
=>
{
const
ClientProfile
:
FC
=
()
=>
{
const
navigation
=
useNavigation
();
const
navigation
=
useNavigation
();
const
{
isLoading
,
data
:
recommendation
}
=
useApi
(
retrieveDietRecommendationApi
,
);
if
(
isLoading
)
{
return
<
Loader
/>;
}
return
(
return
(
<
ReadOnlyNutritionistRecommendation
>
<
ReadOnlyDietRecommendation
data
=
{
recommendation
&&
recommendation
.
length
>
0
?
recommendation
[
0
]
:
undefined
}
>
<
Section
>
<
Section
>
<
Button
<
Button
title
=
"ubah profil"
title
=
"ubah profil"
...
@@ -23,7 +38,7 @@ const ClientProfile: FC = () => {
...
@@ -23,7 +38,7 @@ const ClientProfile: FC = () => {
titleStyle
=
{
[
typographyStyles
.
overlineBig
,
styles
.
titleStyle
]
}
titleStyle
=
{
[
typographyStyles
.
overlineBig
,
styles
.
titleStyle
]
}
/>
/>
</
Section
>
</
Section
>
</
ReadOnly
Nutritionis
tRecommendation
>
</
ReadOnly
Die
tRecommendation
>
);
);
};
};
...
...
src/scenes/profile/ClientProfileForAdmin/index.test.tsx
0 → 100644
View file @
8854d559
import
React
from
'
react
'
;
import
{
render
,
waitFor
}
from
'
@testing-library/react-native
'
;
import
axios
from
'
axios
'
;
import
ClientProfileForAdmin
from
'
.
'
;
import
{
mockDietRecommendation
}
from
'
__mocks__/dietRecommendation
'
;
jest
.
mock
(
'
axios
'
);
const
mockAxios
=
axios
as
jest
.
Mocked
<
typeof
axios
>
;
jest
.
mock
(
'
@react-navigation/native
'
,
()
=>
{
return
{
useRoute
:
()
=>
({
params
:
{
id
:
1
,
},
}),
};
});
describe
(
'
ClientProfileForAdmin
'
,
()
=>
{
const
retrievedietRecommendationByIdApi
=
()
=>
Promise
.
resolve
({
status
:
200
,
data
:
mockDietRecommendation
,
});
it
(
'
fetches data from backend and renders correctly
'
,
async
()
=>
{
mockAxios
.
request
.
mockImplementationOnce
(
retrievedietRecommendationByIdApi
);
render
(<
ClientProfileForAdmin
/>);
await
waitFor
(()
=>
expect
(
mockAxios
.
request
).
toBeCalled
());
});
});
src/scenes/profile/ClientProfileForAdmin/index.tsx
0 → 100644
View file @
8854d559
import
React
,
{
FC
}
from
'
react
'
;
import
{
useRoute
}
from
'
@react-navigation/native
'
;
import
{
Loader
}
from
'
components/core
'
;
import
ReadOnlyDietRecommendation
from
'
scenes/questionnaire/ReadOnlyDietRecommendation
'
;
import
{
useApi
}
from
'
hooks
'
;
import
{
retrieveDietRecommendationByIdApi
}
from
'
services/dietRecommendation
'
;
import
{
DietRecommendationResponse
}
from
'
services/dietRecommendation/models
'
;
const
ClientProfileForAdmin
:
FC
=
()
=>
{
const
route
=
useRoute
();
const
{
id
}
=
route
.
params
as
DietRecommendationResponse
;
const
{
isLoading
,
data
}
=
useApi
(()
=>
retrieveDietRecommendationByIdApi
(
id
),
);
if
(
isLoading
)
{
return
<
Loader
/>;
}
return
<
ReadOnlyDietRecommendation
data
=
{
data
}
/>;
};
export
default
ClientProfileForAdmin
;
src/scenes/questionnaire/NutritionistRecommendation/ReadOnly/index.test.tsx
deleted
100644 → 0
View file @
5d91ad27
import
React
from
'
react
'
;
import
{
render
}
from
'
@testing-library/react-native
'
;
import
ReadOnlyNutritionistRecommendation
from
'
.
'
;
describe
(
'
ReadOnlyNutritionistRecommendation
'
,
()
=>
{
it
(
'
renders correctly
'
,
()
=>
{
render
(<
ReadOnlyNutritionistRecommendation
/>);
});
});
src/scenes/questionnaire/NutritionistRecommendation/index.ts
deleted
100644 → 0
View file @
5d91ad27
export
{
default
as
ReadOnlyNutritionistRecommendation
}
from
'
./ReadOnly
'
;
src/scenes/questionnaire/ReadOnlyDietRecommendation/index.test.tsx
0 → 100644
View file @
8854d559
import
React
from
'
react
'
;
import
{
render
}
from
'
@testing-library/react-native
'
;
import
ReadOnlyDietRecommendation
from
'
.
'
;
import
{
mockDietRecommendation
}
from
'
__mocks__/dietRecommendation
'
;
describe
(
'
ReadOnlyDietRecommendation
'
,
()
=>
{
it
(
'
shows "Belum ada rekomendasi" text if no recommendation is provided yet
'
,
()
=>
{
const
{
getByText
}
=
render
(<
ReadOnlyDietRecommendation
/>);
expect
(
getByText
(
/Belum ada rekomendasi/i
)).
toBeTruthy
();
});
it
(
'
shows recommendation when provided
'
,
()
=>
{
const
{
getByText
}
=
render
(
<
ReadOnlyDietRecommendation
data
=
{
mockDietRecommendation
}
/>,
);
expect
(
getByText
(
/haiya/i
)).
toBeTruthy
();
});
});
src/scenes/questionnaire/
Nutritionis
tRecommendation/
ReadOnly/
index.tsx
→
src/scenes/questionnaire/
ReadOnlyDie
tRecommendation/index.tsx
View file @
8854d559
import
React
,
{
FC
}
from
'
react
'
;
import
React
,
{
FC
}
from
'
react
'
;
import
{
ScrollView
,
View
}
from
'
react-native
'
;
import
{
ScrollView
,
View
}
from
'
react-native
'
;
import
{
Text
,
Button
}
from
'
react-native-elements
'
;
import
{
Text
,
Button
,
Icon
}
from
'
react-native-elements
'
;
import
{
WebView
}
from
'
react-native-webview
'
;
import
{
WebView
}
from
'
react-native-webview
'
;
import
{
InfoCard
,
Loader
}
from
'
components/core
'
;
import
{
InfoCard
,
Loader
}
from
'
components/core
'
;
import
{
layoutStyles
}
from
'
styles
'
;
import
{
layoutStyles
,
colors
}
from
'
styles
'
;
import
{
useDownloadFiles
}
from
'
hooks
'
;
import
{
useDownloadFiles
}
from
'
hooks
'
;
import
{
styles
}
from
'
./styles
'
;
import
{
styles
}
from
'
./styles
'
;
import
{
Props
}
from
'
./types
'
;
const
ReadOnly
Nutritionis
tRecommendation
:
FC
=
({
children
})
=>
{
const
ReadOnly
Die
tRecommendation
:
FC
<
Props
>
=
({
children
,
data
})
=>
{
const
url
=
'
http://www.africau.edu/images/default/sample.pdf
'
;
const
{
download
,
pdfViewUrl
,
fileName
}
=
useDownloadFiles
(
data
?.
client_plan_meal
,
const
{
download
,
pdfViewUrl
,
fileName
}
=
useDownloadFiles
(
url
);
);
if
(
!
data
)
{
return
(
<
View
style
=
{
styles
.
center
}
>
<
Icon
name
=
"emoticon-sad-outline"
type
=
"material-community"
size
=
{
75
}
color
=
{
colors
.
danger
}
/>
<
Text
style
=
{
styles
.
noRecomText
}
>
Belum ada rekomendasi dari nutritionis
</
Text
>
</
View
>
);
}
return
(
return
(
<
ScrollView
contentContainerStyle
=
{
layoutStyles
}
>
<
ScrollView
contentContainerStyle
=
{
layoutStyles
}
>
<
Text
style
=
{
styles
.
header
}
>
Saran Gizi
</
Text
>
<
Text
style
=
{
styles
.
header
}
>
Saran Gizi
</
Text
>
<
InfoCard
content
=
"Anda butuh sayurand buahde fhhehfkwhefkuhbweijkfcbewujkfdc wjdbf"
/>
<
InfoCard
content
=
{
data
.
nutritional_advice
}
/>
<
Text
style
=
{
[
styles
.
header
,
styles
.
spacing
]
}
>
Saran Gaya Hidup
</
Text
>
<
Text
style
=
{
[
styles
.
header
,
styles
.
spacing
]
}
>
Saran Gaya Hidup
</
Text
>
<
InfoCard
content
=
"Anda butuh istirahat"
/>
<
InfoCard
content
=
{
data
.
lifestyle_advice
}
/>
<
View
style
=
{
styles
.
spacing
}
>
<
View
style
=
{
styles
.
spacing
}
>
<
Text
style
=
{
styles
.
header
}
>
Rencana Menu dan Porsi Makan
</
Text
>
<
Text
style
=
{
styles
.
header
}
>
Rencana Menu dan Porsi Makan
</
Text
>
</
View
>
</
View
>
...
@@ -45,4 +61,4 @@ const ReadOnlyNutritionistRecommendation: FC = ({ children }) => {
...
@@ -45,4 +61,4 @@ const ReadOnlyNutritionistRecommendation: FC = ({ children }) => {
);
);
};
};
export
default
ReadOnly
Nutritionis
tRecommendation
;
export
default
ReadOnly
Die
tRecommendation
;
src/scenes/questionnaire/
Nutritionis
tRecommendation/
ReadOnly/
styles.ts
→
src/scenes/questionnaire/
ReadOnlyDie
tRecommendation/styles.ts
View file @
8854d559
...
@@ -12,7 +12,6 @@ export const styles = StyleSheet.create({
...
@@ -12,7 +12,6 @@ export const styles = StyleSheet.create({
},
},
pdfView
:
{
pdfView
:
{
height
:
Dimensions
.
get
(
'
window
'
).
height
*
0.6
,
height
:
Dimensions
.
get
(
'
window
'
).
height
*
0.6
,
flex
:
1
,
marginBottom
:
10
,
marginBottom
:
10
,
},
},
buttonStyle
:
{
buttonStyle
:
{
...
@@ -22,4 +21,15 @@ export const styles = StyleSheet.create({
...
@@ -22,4 +21,15 @@ export const styles = StyleSheet.create({
color
:
'
black
'
,
color
:
'
black
'
,
paddingRight
:
6
,
paddingRight
:
6
,
},
},
center
:
{
flex
:
1
,
justifyContent
:
'
center
'
,
alignItems
:
'
center
'
,
paddingHorizontal
:
30
,
},
noRecomText
:
{
...
typography
.
headingMedium
,
textAlign
:
'
center
'
,
marginTop
:
10
,
},
});
});
src/scenes/questionnaire/ReadOnlyDietRecommendation/types.ts
0 → 100644
View file @
8854d559
import
{
DietRecommendationResponse
}
from
'
services/dietRecommendation/models
'
;
export
interface
Props
{
data
?:
DietRecommendationResponse
;
}
src/services/dietRecommendation/index.ts
0 → 100644
View file @
8854d559
import
{
api
,
RequestMethod
,
ApiResponse
}
from
'
../api
'
;
import
*
as
apiUrls
from
'
./urls
'
;
import
{
DietRecommendationResponse
}
from
'
./models
'
;
export
const
retrieveDietRecommendationApi
=
():
ApiResponse
<
DietRecommendationResponse
[]
>
=>
{
return
api
(
RequestMethod
.
GET
,
apiUrls
.
dietRecommendation
);
};
export
const
retrieveDietRecommendationByIdApi
=
(
id
:
number
,
):
ApiResponse
<
DietRecommendationResponse
>
=>
{
return
api
(
RequestMethod
.
GET
,
apiUrls
.
dietRecommendationById
(
id
));
};
src/services/dietRecommendation/models.ts
0 → 100644
View file @
8854d559
export
interface
DietRecommendationResponse
{
id
:
number
;
client_plan_meal
:
string
;
nutritional_advice
:
string
;
lifestyle_advice
:
string
;
nutritionist
:
number
;
client
:
number
;
}
src/services/dietRecommendation/urls.ts
0 → 100644
View file @
8854d559
export
const
dietRecommendation
=
'
diet-recommendation/
'
;
export
const
dietRecommendationById
=
(
id
:
number
)
=>
`
${
dietRecommendation
}${
id
}
/`
;
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