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
80fb39ac
Commit
80fb39ac
authored
May 06, 2021
by
Wulan Mantiri
Browse files
Implement step-by step form
parent
43018dfb
Changes
14
Hide whitespace changes
Inline
Side-by-side
src/app/index.tsx
View file @
80fb39ac
...
...
@@ -4,6 +4,7 @@ import { createStackNavigator } from '@react-navigation/stack';
import
{
ThemeProvider
}
from
'
react-native-elements
'
;
import
Toast
from
'
react-native-toast-message
'
;
import
{
DietelaCoverLoader
}
from
'
components/core
'
;
import
ContextProvider
,
{
UserContext
}
from
'
provider
'
;
import
{
theme
}
from
'
styles/theme
'
;
...
...
@@ -14,13 +15,18 @@ import { getNavigation } from './schema';
const
Stack
=
createStackNavigator
();
const
NavigationStack
:
FC
=
()
=>
{
const
{
isAuthenticated
,
isUnpaidClient
}
=
useContext
(
UserContext
);
const
{
isAuthenticated
,
isUnpaidClient
,
isFirstLoading
}
=
useContext
(
UserContext
,
);
const
{
initialRoute
,
navigation
}
=
getNavigation
(
isAuthenticated
,
isUnpaidClient
,
);
if
(
isFirstLoading
)
{
return
<
DietelaCoverLoader
/>;
}
return
(
<
NavigationContainer
>
<
Stack
.
Navigator
...
...
src/components/form/StepByStepForm/index.test.tsx
0 → 100644
View file @
80fb39ac
import
React
from
'
react
'
;
import
{
fireEvent
,
render
}
from
'
@testing-library/react-native
'
;
import
StepByStepForm
from
'
.
'
;
const
mockedNavigate
=
jest
.
fn
();
jest
.
mock
(
'
@react-navigation/native
'
,
()
=>
{
return
{
useNavigation
:
()
=>
({
navigate
:
mockedNavigate
,
}),
};
});
describe
(
'
StepByStepForm component
'
,
()
=>
{
const
pages
=
[
'
hai
'
,
'
hello
'
,
'
hei
'
];
const
props
=
{
pages
:
pages
.
map
((
name
)
=>
({
name
,
route
:
name
,
})),
title
:
'
title
'
,
currentPage
:
0
,
finishRedirectRoute
:
'
finishroute
'
,
};
it
(
'
only has "Lanjut" button when form is never filled
'
,
()
=>
{
const
{
getByText
,
queryByText
}
=
render
(<
StepByStepForm
{
...
props
}
/>);
const
nextButton
=
getByText
(
/Lanjut/i
);
expect
(
nextButton
).
toBeTruthy
();
expect
(
queryByText
(
/Ubah/i
)).
toBeFalsy
();
});
it
(
'
has "Ubah" button when form has been filled
'
,
()
=>
{
const
{
queryByText
}
=
render
(
<
StepByStepForm
{
...
props
}
currentPage
=
{
1
}
/>,
);
expect
(
queryByText
(
/Ubah/i
)).
toBeTruthy
();
});
it
(
'
redirects to designated route when button "Ubah" or "Lanjut" is pressed
'
,
()
=>
{
const
{
getByText
}
=
render
(<
StepByStepForm
{
...
props
}
currentPage
=
{
1
}
/>);
const
nextButton
=
getByText
(
/Lanjut/i
);
expect
(
nextButton
).
toBeTruthy
();
fireEvent
.
press
(
nextButton
);
expect
(
mockedNavigate
).
toHaveBeenCalled
();
});
it
(
'
redirects to finish route when button "Selesai" is pressed
'
,
()
=>
{
const
{
getByText
}
=
render
(
<
StepByStepForm
{
...
props
}
currentPage
=
{
pages
.
length
}
/>,
);
const
finishButton
=
getByText
(
/Selesai/i
);
expect
(
finishButton
).
toBeTruthy
();
fireEvent
.
press
(
finishButton
);
expect
(
mockedNavigate
).
toHaveBeenCalled
();
});
});
src/components/form/StepByStepForm/index.tsx
0 → 100644
View file @
80fb39ac
import
React
,
{
FC
}
from
'
react
'
;
import
{
useNavigation
}
from
'
@react-navigation/native
'
;
import
{
View
}
from
'
react-native
'
;
import
{
Button
,
Text
}
from
'
react-native-elements
'
;
import
{
styles
}
from
'
./styles
'
;
import
{
Props
}
from
'
./types
'
;
const
StepByStepForm
:
FC
<
Props
>
=
({
title
,
pages
,
currentPage
,
defaultValues
,
finishRedirectRoute
,
})
=>
{
const
navigation
=
useNavigation
();
const
getButton
=
(
i
:
number
,
route
:
string
)
=>
{
let
buttonLabel
;
if
(
i
<
currentPage
)
{
buttonLabel
=
'
Ubah
'
;
}
else
if
(
i
===
currentPage
)
{
buttonLabel
=
'
Lanjut
'
;
}
return
buttonLabel
?
(
<
Button
title
=
{
buttonLabel
}
onPress
=
{
()
=>
navigation
.
navigate
(
route
,
defaultValues
)
}
buttonStyle
=
{
styles
.
button
}
titleStyle
=
{
styles
.
buttonTitle
}
/>
)
:
null
;
};
return
(
<
View
style
=
{
styles
.
container
}
>
<
View
style
=
{
styles
.
titleContainer
}
>
<
Text
style
=
{
styles
.
title
}
>
{
title
}
</
Text
>
</
View
>
<
View
style
=
{
styles
.
pageContainer
}
>
{
pages
.
map
((
page
,
i
)
=>
(
<
View
style
=
{
styles
.
page
}
key
=
{
i
}
>
<
Text
style
=
{
[
styles
.
number
,
currentPage
<
i
?
styles
.
notfilled
:
styles
.
filled
,
]
}
>
{
i
+
1
}
</
Text
>
<
Text
style
=
{
[
styles
.
md
,
currentPage
<
i
?
styles
.
notfilled
:
styles
.
filled
,
]
}
>
{
page
.
name
}
</
Text
>
<
View
style
=
{
styles
.
buttonContainer
}
>
{
getButton
(
i
,
page
.
route
)
}
</
View
>
</
View
>
))
}
</
View
>
<
View
style
=
{
styles
.
titleContainer
}
>
<
Button
title
=
"Selesai"
onPress
=
{
()
=>
navigation
.
navigate
(
finishRedirectRoute
)
}
buttonStyle
=
{
styles
.
finishButton
}
titleStyle
=
{
styles
.
buttonTitle
}
disabled
=
{
currentPage
!==
pages
.
length
}
/>
</
View
>
</
View
>
);
};
export
default
StepByStepForm
;
src/components/form/StepByStepForm/styles.ts
0 → 100644
View file @
80fb39ac
import
{
StyleSheet
}
from
'
react-native
'
;
import
{
colors
,
typography
}
from
'
styles
'
;
export
const
styles
=
StyleSheet
.
create
({
container
:
{
flex
:
1
,
paddingHorizontal
:
20
,
},
titleContainer
:
{
display
:
'
flex
'
,
alignItems
:
'
center
'
,
justifyContent
:
'
center
'
,
flex
:
1
,
},
title
:
{
...
typography
.
headingLarge
,
textAlign
:
'
center
'
,
},
pageContainer
:
{
flex
:
3
,
},
notfilled
:
{
color
:
colors
.
formLabel
,
},
filled
:
{
color
:
colors
.
textBlack
,
...
typography
.
headingMedium
,
fontSize
:
18
,
},
page
:
{
display
:
'
flex
'
,
flexDirection
:
'
row
'
,
alignItems
:
'
center
'
,
padding
:
14
,
borderBottomColor
:
colors
.
border
,
borderBottomWidth
:
1
,
},
number
:
{
...
typography
.
bodyLarge
,
flex
:
0.1
,
},
buttonContainer
:
{
paddingLeft
:
10
,
flex
:
0.27
,
},
md
:
{
...
typography
.
bodyLarge
,
flex
:
0.63
,
},
button
:
{
padding
:
10
,
backgroundColor
:
colors
.
primaryYellow
,
},
finishButton
:
{
borderRadius
:
20
,
width
:
150
,
backgroundColor
:
colors
.
secondaryVariant
,
},
buttonTitle
:
{
color
:
colors
.
textBlack
,
},
});
src/components/form/StepByStepForm/types.ts
0 → 100644
View file @
80fb39ac
export
interface
Props
{
title
:
string
;
pages
:
{
name
:
string
;
route
:
string
;
}[];
currentPage
:
number
;
defaultValues
?:
any
;
finishRedirectRoute
:
string
;
}
src/components/form/index.ts
View file @
80fb39ac
export
{
default
as
MultipleCheckbox
}
from
'
./MultipleCheckbox
'
;
export
{
default
as
MultipleChoice
}
from
'
./MultipleChoice
'
;
export
{
default
as
RadioButton
,
RadioButtonGroup
}
from
'
./RadioButton
'
;
export
{
default
as
StepByStepForm
}
from
'
./StepByStepForm
'
;
export
{
default
as
TextField
}
from
'
./TextField
'
;
src/constants/navigation.ts
View file @
80fb39ac
...
...
@@ -11,6 +11,7 @@ import {
ProgramDetail
,
NutritionistDetail
,
PaymentResult
,
ExtendedQuestionnaire
,
}
from
'
scenes
'
;
import
{
FC
}
from
'
react
'
;
...
...
@@ -86,6 +87,11 @@ export const privateNavigation: NavRoute[] = [
component
:
ComingSoonPage
,
header
:
'
Profile
'
,
},
{
name
:
ROUTES
.
extendedQuestionnaire
,
component
:
ExtendedQuestionnaire
,
header
:
'
Diet Questionnaire
'
,
},
];
export
const
testNavigation
:
NavRoute
[]
=
[
...
...
src/constants/routes.ts
View file @
80fb39ac
...
...
@@ -4,6 +4,10 @@ export const comingSoon = '*';
const
questionnaire
=
'
questionnaire
'
;
export
const
allAccessQuestionnaire
=
`
${
questionnaire
}
/all-access`
;
export
const
dietelaQuizResult
=
`
${
questionnaire
}
/dietela-quiz-result`
;
export
const
consentForm
=
`
${
questionnaire
}
/consent`
;
export
const
extendedQuestionnaire
=
`
${
questionnaire
}
/extended`
;
export
const
extendedQuestionnaireById
=
(
id
:
number
)
=>
`
${
extendedQuestionnaire
}
/
${
id
}
`
;
export
const
checkout
=
'
checkout
'
;
export
const
choosePlan
=
`
${
checkout
}
/choose-plan`
;
...
...
src/scenes/common/InitialPage/index.test.tsx
View file @
80fb39ac
...
...
@@ -5,14 +5,6 @@ import * as ROUTES from 'constants/routes';
import
InitialPage
from
'
.
'
;
describe
(
'
InitialPage
'
,
()
=>
{
test
(
'
shows dietela cover loader when is loading
'
,
async
()
=>
{
const
{
queryByTestId
}
=
render
(<
InitialPage
/>,
ROUTES
.
initial
,
{
userContext
:
{
isFirstLoading
:
true
},
});
expect
(
queryByTestId
(
'
background
'
)).
toBeFalsy
();
});
test
(
'
has background image
'
,
()
=>
{
const
{
queryByTestId
}
=
render
(<
InitialPage
/>,
ROUTES
.
initial
);
...
...
src/scenes/common/InitialPage/index.tsx
View file @
80fb39ac
import
React
,
{
FC
,
useContext
}
from
'
react
'
;
import
React
,
{
FC
}
from
'
react
'
;
import
{
useNavigation
}
from
'
@react-navigation/native
'
;
import
{
View
,
Text
,
ImageBackground
,
Image
}
from
'
react-native
'
;
import
{
BigButton
,
Link
,
DietelaCoverLoader
}
from
'
components/core
'
;
import
{
BigButton
,
Link
}
from
'
components/core
'
;
import
{
banner_girl_eating
,
logo_white_small
}
from
'
assets/images
'
;
import
*
as
ROUTES
from
'
constants/routes
'
;
import
{
UserContext
}
from
'
provider
'
;
import
{
layoutStyles
,
typographyStyles
}
from
'
styles
'
;
import
{
styles
}
from
'
./styles
'
;
const
InitialPage
:
FC
=
()
=>
{
const
navigation
=
useNavigation
();
const
{
isFirstLoading
}
=
useContext
(
UserContext
);
if
(
isFirstLoading
)
{
return
<
DietelaCoverLoader
/>;
}
return
(
<
ImageBackground
source
=
{
banner_girl_eating
}
...
...
src/scenes/index.ts
View file @
80fb39ac
...
...
@@ -6,6 +6,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
Checkout
}
from
'
./cart/Checkout
'
;
export
{
default
as
ChoosePlan
}
from
'
./cart/ChoosePlan
'
;
...
...
src/scenes/questionnaire/ExtendedQuestionnaire/index.test.tsx
0 → 100644
View file @
80fb39ac
import
React
from
'
react
'
;
import
{
render
}
from
'
utils/testing
'
;
import
*
as
ROUTES
from
'
constants/routes
'
;
import
ExtendedQuestionnaire
from
'
.
'
;
describe
(
'
ExtendedQuestionnaire
'
,
()
=>
{
it
(
'
renders correctly
'
,
()
=>
{
render
(<
ExtendedQuestionnaire
/>,
ROUTES
.
extendedQuestionnaire
);
});
});
src/scenes/questionnaire/ExtendedQuestionnaire/index.tsx
0 → 100644
View file @
80fb39ac
import
React
,
{
FC
,
useState
}
from
'
react
'
;
import
*
as
ROUTES
from
'
constants/routes
'
;
import
{
StepByStepForm
}
from
'
components/form
'
;
import
{
pages
}
from
'
./schema
'
;
const
ExtendedQuestionnaire
:
FC
=
()
=>
{
const
[
currentPage
]
=
useState
(
1
);
return
(
<
StepByStepForm
currentPage
=
{
currentPage
}
title
=
{
'
Lengkapi Profil Anda
'
}
pages
=
{
pages
.
map
((
name
,
i
)
=>
({
name
,
route
:
ROUTES
.
extendedQuestionnaireById
(
i
),
}))
}
finishRedirectRoute
=
{
ROUTES
.
profile
}
/>
);
};
export
default
ExtendedQuestionnaire
;
src/scenes/questionnaire/ExtendedQuestionnaire/schema.ts
0 → 100644
View file @
80fb39ac
export
const
pages
:
string
[]
=
[
'
Identitas Diri
'
,
'
Pola Makan
'
,
'
Konsumsi Makanan Seharian
'
,
'
Gaya Hidup dan Kebiasaan Diet
'
,
'
Kondisi Pribadi
'
,
];
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