Add passport application flow until step 2 'Kuesioner Layanan Permohonan'
This commit is contained in:
102
src/components/RadioButtonOption.tsx
Normal file
102
src/components/RadioButtonOption.tsx
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {StyleSheet, Text, View, Pressable} from 'react-native';
|
||||||
|
import Colors from '../../assets/styles/Colors';
|
||||||
|
import {RadioButton} from 'react-native-paper';
|
||||||
|
import FontFamily from '../../assets/styles/FontFamily';
|
||||||
|
|
||||||
|
interface RadioButtonOptionProps {
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
value: string;
|
||||||
|
selectedValue: string;
|
||||||
|
onSelect: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RadioButtonOptionComponent = ({
|
||||||
|
label,
|
||||||
|
description,
|
||||||
|
value,
|
||||||
|
selectedValue,
|
||||||
|
onSelect,
|
||||||
|
}: RadioButtonOptionProps) => {
|
||||||
|
const isSelected = selectedValue === value;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
onPress={() => onSelect(value)}
|
||||||
|
style={[
|
||||||
|
styles.container,
|
||||||
|
isSelected && {backgroundColor: Colors.secondary30.color},
|
||||||
|
]}>
|
||||||
|
<RadioButton
|
||||||
|
value={value}
|
||||||
|
status={isSelected ? 'checked' : 'unchecked'}
|
||||||
|
onPress={() => onSelect(value)}
|
||||||
|
color={Colors.neutral100.color}
|
||||||
|
uncheckedColor={Colors.secondary30.color}
|
||||||
|
/>
|
||||||
|
<View style={styles.textContainer}>
|
||||||
|
{description === 'null' ? (
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.textTitle,
|
||||||
|
isSelected && {color: Colors.neutral100.color},
|
||||||
|
{...FontFamily.notoSansRegular},
|
||||||
|
]}>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
) : (
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.textTitle,
|
||||||
|
isSelected && {color: Colors.neutral100.color},
|
||||||
|
]}>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
{description && description !== 'null' && (
|
||||||
|
<Text
|
||||||
|
style={[
|
||||||
|
styles.textDesc,
|
||||||
|
isSelected && {color: Colors.neutral100.color},
|
||||||
|
]}>
|
||||||
|
{description}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
</Pressable>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
paddingVertical: 16,
|
||||||
|
paddingStart: 12,
|
||||||
|
paddingEnd: 16,
|
||||||
|
borderWidth: 1,
|
||||||
|
gap: 8,
|
||||||
|
borderRadius: 8,
|
||||||
|
borderColor: Colors.primary70.color,
|
||||||
|
},
|
||||||
|
textContainer: {
|
||||||
|
gap: 6,
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
textTitle: {
|
||||||
|
...FontFamily.notoSansBold,
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.primary30.color,
|
||||||
|
includeFontPadding: false,
|
||||||
|
},
|
||||||
|
textDesc: {
|
||||||
|
...FontFamily.notoSansMedium,
|
||||||
|
color: Colors.primary30.color,
|
||||||
|
fontSize: 10.5,
|
||||||
|
includeFontPadding: false,
|
||||||
|
textAlign: 'justify',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default RadioButtonOptionComponent;
|
99
src/components/StepIndicator.tsx
Normal file
99
src/components/StepIndicator.tsx
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {StyleSheet, Text, View} from 'react-native';
|
||||||
|
import Colors from '../../assets/styles/Colors';
|
||||||
|
import FontFamily from '../../assets/styles/FontFamily';
|
||||||
|
|
||||||
|
const StepIndicator = ({currentStep, totalSteps, completedSteps}: any) => {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
{[...Array(totalSteps)].map((_, index) => {
|
||||||
|
const stepNumber = index + 1;
|
||||||
|
const isCompleted = completedSteps.includes(stepNumber);
|
||||||
|
const isCurrent = currentStep === stepNumber;
|
||||||
|
|
||||||
|
const backgroundColor = isCompleted
|
||||||
|
? Colors.secondary30.color
|
||||||
|
: Colors.neutral100.color;
|
||||||
|
|
||||||
|
const textColor = isCompleted
|
||||||
|
? Colors.neutral100.color
|
||||||
|
: isCurrent
|
||||||
|
? Colors.secondary30.color
|
||||||
|
: Colors.secondary50.color;
|
||||||
|
|
||||||
|
const textStyle = isCompleted
|
||||||
|
? FontFamily.notoSansBold
|
||||||
|
: isCurrent
|
||||||
|
? FontFamily.notoSansRegular
|
||||||
|
: FontFamily.notoSansRegular;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment key={index}>
|
||||||
|
<View style={{alignItems: 'center'}}>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.stepIndicatorContainer,
|
||||||
|
{
|
||||||
|
backgroundColor: backgroundColor,
|
||||||
|
borderColor: isCompleted
|
||||||
|
? Colors.secondary30.color
|
||||||
|
: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Text
|
||||||
|
style={{
|
||||||
|
includeFontPadding: false,
|
||||||
|
fontSize: 12,
|
||||||
|
color: textColor,
|
||||||
|
...textStyle,
|
||||||
|
}}>
|
||||||
|
{stepNumber}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
{index < totalSteps - 1 && (
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.stepIndicatorLine,
|
||||||
|
{
|
||||||
|
backgroundColor: isCompleted
|
||||||
|
? Colors.secondary30.color
|
||||||
|
: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: 16,
|
||||||
|
backgroundColor: Colors.secondary70.color,
|
||||||
|
},
|
||||||
|
stepIndicatorContainer: {
|
||||||
|
width: 30,
|
||||||
|
height: 30,
|
||||||
|
borderRadius: 15,
|
||||||
|
borderWidth: 1,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
stepIndicatorText: {
|
||||||
|
includeFontPadding: false,
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
|
stepIndicatorLine: {
|
||||||
|
flex: 1,
|
||||||
|
height: 2,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default StepIndicator;
|
@ -123,8 +123,9 @@ const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||||||
placeholderTextColor={Colors.primary60.color}
|
placeholderTextColor={Colors.primary60.color}
|
||||||
editable={false}
|
editable={false}
|
||||||
value={formattedDate}
|
value={formattedDate}
|
||||||
right={<TextInput.Icon icon="calendar" />}
|
right={<TextInput.Icon icon="calendar" color='#48454E' />}
|
||||||
multiline={false}
|
multiline={false}
|
||||||
|
textColor='#48454E'
|
||||||
/>
|
/>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
{showPicker && (
|
{showPicker && (
|
||||||
@ -166,6 +167,7 @@ const TextInputComponent: React.FC<TextInputComponentProps> = ({
|
|||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
multiline={isMultiline}
|
multiline={isMultiline}
|
||||||
|
textColor='#48454E'
|
||||||
/>
|
/>
|
||||||
{supportText && <Text style={[styles.supportText]}>{supportText}</Text>}
|
{supportText && <Text style={[styles.supportText]}>{supportText}</Text>}
|
||||||
</View>
|
</View>
|
||||||
@ -196,6 +198,7 @@ const styles = StyleSheet.create({
|
|||||||
placeholderText: {
|
placeholderText: {
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
...FontFamily.notoSansRegular,
|
...FontFamily.notoSansRegular,
|
||||||
|
includeFontPadding: false,
|
||||||
},
|
},
|
||||||
dropdown: {
|
dropdown: {
|
||||||
marginTop: 8,
|
marginTop: 8,
|
||||||
@ -205,16 +208,18 @@ const styles = StyleSheet.create({
|
|||||||
paddingStart: 16,
|
paddingStart: 16,
|
||||||
paddingEnd: 8,
|
paddingEnd: 8,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
borderColor: Colors.primary40.color,
|
borderColor: '#98989A',
|
||||||
},
|
},
|
||||||
placeholderDropdownStyle: {
|
placeholderDropdownStyle: {
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
...FontFamily.notoSansRegular,
|
...FontFamily.notoSansRegular,
|
||||||
|
includeFontPadding: false,
|
||||||
color: Colors.primary60.color,
|
color: Colors.primary60.color,
|
||||||
},
|
},
|
||||||
selectedTextStyle: {
|
selectedTextStyle: {
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
...FontFamily.notoSansRegular,
|
...FontFamily.notoSansRegular,
|
||||||
|
includeFontPadding: false,
|
||||||
},
|
},
|
||||||
iconStyle: {
|
iconStyle: {
|
||||||
width: 20,
|
width: 20,
|
||||||
|
9
src/data/DropdownData/CivilStatus.tsx
Normal file
9
src/data/DropdownData/CivilStatus.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
const civilStatusData = [
|
||||||
|
{label: 'Cerai Hidup', value: '1'},
|
||||||
|
{label: 'Cerai Mati', value: '2'},
|
||||||
|
{label: 'Kawin', value: '3'},
|
||||||
|
{label: 'Belum Kawin', value: '4'},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default civilStatusData;
|
||||||
|
|
@ -49,11 +49,9 @@ function RootStack() {
|
|||||||
component={NavigationRouteScreen}
|
component={NavigationRouteScreen}
|
||||||
options={{headerShown: false}}
|
options={{headerShown: false}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen name="Home" options={{headerShown: false}}>
|
||||||
name="Home"
|
{() => <HomeScreen showDialog={() => console.log('Show dialog!')} />}
|
||||||
component={HomeScreen}
|
</Stack.Screen>
|
||||||
options={{headerShown: false}}
|
|
||||||
/>
|
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="History"
|
name="History"
|
||||||
component={HistoryScreen}
|
component={HistoryScreen}
|
||||||
|
@ -37,10 +37,9 @@ function CloseAccountScreen() {
|
|||||||
<PaperProvider>
|
<PaperProvider>
|
||||||
<View style={styles.contentContainer}>
|
<View style={styles.contentContainer}>
|
||||||
<StatusBar
|
<StatusBar
|
||||||
backgroundColor={visible ? '#ADADAF' : Colors.neutral100.color}
|
backgroundColor={visible ? Colors.primary30.color : Colors.primary30.color}
|
||||||
barStyle={visible ? 'light-content' : 'dark-content'}
|
barStyle={visible ? 'light-content' : 'dark-content'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<View>
|
<View>
|
||||||
<View style={styles.appBarContainer}>
|
<View style={styles.appBarContainer}>
|
||||||
<Icon
|
<Icon
|
||||||
|
@ -76,6 +76,7 @@ const styles = StyleSheet.create({
|
|||||||
borderRadius: 20,
|
borderRadius: 20,
|
||||||
},
|
},
|
||||||
dialogTitle: {
|
dialogTitle: {
|
||||||
|
fontSize: 22,
|
||||||
color: Colors.indicatorRed.color,
|
color: Colors.indicatorRed.color,
|
||||||
},
|
},
|
||||||
dialogButtonContainer: {
|
dialogButtonContainer: {
|
||||||
|
@ -1,11 +1,160 @@
|
|||||||
import React from 'react';
|
import React, {useState} from 'react';
|
||||||
import {Text, View} from 'react-native';
|
import {Button, Text, View} from 'react-native';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import Colors from '../../../assets/styles/Colors';
|
||||||
|
import StepIndicator from '../../components/StepIndicator';
|
||||||
|
|
||||||
|
const renderContent = (
|
||||||
|
step: number,
|
||||||
|
subStep: number,
|
||||||
|
setStep: (step: number) => void,
|
||||||
|
setSubStep: (step: number) => void,
|
||||||
|
) => {
|
||||||
|
if (step === 1) {
|
||||||
|
switch (subStep) {
|
||||||
|
case 1:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Text>Step 1.1</Text>
|
||||||
|
<Button title="Next" onPress={() => setSubStep(2)} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 2:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Text>Step 1.2</Text>
|
||||||
|
<Button title="Next" onPress={() => setSubStep(3)} />
|
||||||
|
<Button title="Back" onPress={() => setSubStep(1)} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 3:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Text>Step 1.3</Text>
|
||||||
|
<Button
|
||||||
|
title="Next"
|
||||||
|
onPress={() => {
|
||||||
|
setStep(2);
|
||||||
|
setSubStep(1);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button title="Back" onPress={() => setSubStep(2)} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step === 2) {
|
||||||
|
switch (subStep) {
|
||||||
|
case 1:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Text>Step 2.1</Text>
|
||||||
|
<Button title="Next" onPress={() => setSubStep(2)} />
|
||||||
|
<Button
|
||||||
|
title="Back"
|
||||||
|
onPress={() => {
|
||||||
|
setStep(1);
|
||||||
|
setSubStep(3);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 2:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Text>Step 2.2</Text>
|
||||||
|
<Button title="Next" onPress={() => setSubStep(3)} />
|
||||||
|
<Button title="Back" onPress={() => setSubStep(1)} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 3:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Text>Step 2.3</Text>
|
||||||
|
<Button
|
||||||
|
title="Next"
|
||||||
|
onPress={() => {
|
||||||
|
setStep(3);
|
||||||
|
setSubStep(1);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button title="Back" onPress={() => setSubStep(2)} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (step) {
|
||||||
|
case 3:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Button title="Next" onPress={() => setStep(4)} />
|
||||||
|
<Button title="Back" onPress={() => setStep(2)} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 4:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Button title="Next" onPress={() => setStep(5)} />
|
||||||
|
<Button title="Back" onPress={() => setStep(3)} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 5:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Button title="Next" onPress={() => setStep(6)} />
|
||||||
|
<Button title="Back" onPress={() => setStep(4)} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 6:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Button title="Next" onPress={() => setStep(7)} />
|
||||||
|
<Button title="Back" onPress={() => setStep(5)} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 7:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Button title="Back" onPress={() => setStep(6)} />
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function ExpressPassportScreen() {
|
function ExpressPassportScreen() {
|
||||||
|
const [step, setStep] = useState(1);
|
||||||
|
const [subStep, setSubStep] = useState(1);
|
||||||
|
|
||||||
|
const completedSteps = [...Array(step - 1)].map((_, i) => i + 1);
|
||||||
|
const stepTitles: {[key: number]: string} = {
|
||||||
|
1: 'Informasi Pribadi',
|
||||||
|
2: 'Dokumen Pendukung',
|
||||||
|
3: 'Pembayaran',
|
||||||
|
4: 'Konfirmasi Data',
|
||||||
|
5: 'Verifikasi',
|
||||||
|
6: 'Pemrosesan',
|
||||||
|
7: 'Selesai',
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={{flex: 1}}>
|
||||||
<Text>Express Passport Screen</Text>
|
<View>
|
||||||
|
<Text>{stepTitles[step]}</Text>
|
||||||
|
</View>
|
||||||
|
<StepIndicator
|
||||||
|
currentStep={step}
|
||||||
|
totalSteps={7}
|
||||||
|
completedSteps={completedSteps}
|
||||||
|
/>
|
||||||
|
{renderContent(step, subStep, setStep, setSubStep)}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,11 @@ const data = [1, 2, 3, 4];
|
|||||||
|
|
||||||
const ItemSeparator = () => <View style={styles.flatllistGap} />;
|
const ItemSeparator = () => <View style={styles.flatllistGap} />;
|
||||||
|
|
||||||
const RenderContent = () => {
|
type RenderContentProps = {
|
||||||
|
showDialog: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const RenderContent = ({showDialog}: RenderContentProps) => {
|
||||||
const navigation = useNavigation<HomeScreenNavigationProp>();
|
const navigation = useNavigation<HomeScreenNavigationProp>();
|
||||||
const scrollX = useRef(new Animated.Value(0)).current;
|
const scrollX = useRef(new Animated.Value(0)).current;
|
||||||
|
|
||||||
@ -131,7 +135,7 @@ const RenderContent = () => {
|
|||||||
<View style={styles.serviceOptionWrapper}>
|
<View style={styles.serviceOptionWrapper}>
|
||||||
<View style={styles.serviceOptionContainer}>
|
<View style={styles.serviceOptionContainer}>
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={() => navigation.navigate('RegularPassport')}
|
onPress={showDialog}
|
||||||
style={({pressed}) => [
|
style={({pressed}) => [
|
||||||
styles.serviceIcon,
|
styles.serviceIcon,
|
||||||
{
|
{
|
||||||
@ -224,13 +228,18 @@ const RenderContent = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function HomeScreen() {
|
type HomeScreenProps = {
|
||||||
|
showDialog: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function HomeScreen({showDialog}: HomeScreenProps) {
|
||||||
const navigation = useNavigation<HomeScreenNavigationProp>();
|
const navigation = useNavigation<HomeScreenNavigationProp>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<StatusBar
|
<StatusBar
|
||||||
backgroundColor={Colors.secondary30.color}
|
backgroundColor={Colors.secondary30.color}
|
||||||
barStyle="light-content"
|
barStyle={'light-content'}
|
||||||
/>
|
/>
|
||||||
<View style={styles.appBarContainer}>
|
<View style={styles.appBarContainer}>
|
||||||
<Text style={styles.appBarTitle}>Halo, X!</Text>
|
<Text style={styles.appBarTitle}>Halo, X!</Text>
|
||||||
@ -241,7 +250,10 @@ function HomeScreen() {
|
|||||||
onPress={() => navigation.navigate('Notification')}
|
onPress={() => navigation.navigate('Notification')}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<FlatList data={[{}]} renderItem={() => <RenderContent />} />
|
<FlatList
|
||||||
|
data={[{}]}
|
||||||
|
renderItem={() => <RenderContent showDialog={showDialog} />}
|
||||||
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,34 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {BottomNavigation, Text} from 'react-native-paper';
|
import {
|
||||||
|
BottomNavigation,
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
PaperProvider,
|
||||||
|
Portal,
|
||||||
|
Text,
|
||||||
|
} from 'react-native-paper';
|
||||||
import Colors from '../../../assets/styles/Colors';
|
import Colors from '../../../assets/styles/Colors';
|
||||||
import ProfileScreen from '../profile';
|
import ProfileScreen from '../profile';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import HomeScreen from '../home';
|
import HomeScreen from '../home';
|
||||||
import HistoryScreen from '../history';
|
import HistoryScreen from '../history';
|
||||||
|
import {StatusBar, View} from 'react-native';
|
||||||
|
import {useState} from 'react';
|
||||||
|
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
||||||
|
import {RootStackParamList} from '../../navigation/type';
|
||||||
|
import {useNavigation} from '@react-navigation/native';
|
||||||
|
import FontFamily from '../../../assets/styles/FontFamily';
|
||||||
|
|
||||||
const HomeRoute = () => <HomeScreen />;
|
type NavigationRouteScreenNavigationProp = NativeStackNavigationProp<
|
||||||
const HistoryRoute = () => <HistoryScreen />;
|
RootStackParamList,
|
||||||
const ProfileRoute = () => <ProfileScreen />;
|
'NavigationRoute'
|
||||||
|
>;
|
||||||
|
|
||||||
function NavigationRouteScreen() {
|
function NavigationRouteScreen() {
|
||||||
const [index, setIndex] = React.useState(0);
|
const navigation = useNavigation<NavigationRouteScreenNavigationProp>();
|
||||||
const [routes] = React.useState([
|
const [visible, setVisible] = useState(false);
|
||||||
|
const [index, setIndex] = useState(0);
|
||||||
|
const [routes] = useState([
|
||||||
{
|
{
|
||||||
key: 'home',
|
key: 'home',
|
||||||
title: 'Home',
|
title: 'Home',
|
||||||
@ -32,29 +48,70 @@ function NavigationRouteScreen() {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const renderScene = BottomNavigation.SceneMap({
|
const showDialog = () => setVisible(true);
|
||||||
home: HomeRoute,
|
const hideDialog = () => setVisible(false);
|
||||||
history: HistoryRoute,
|
|
||||||
profile: ProfileRoute,
|
const renderScene = ({route}: {route: {key: string}}) => {
|
||||||
});
|
switch (route.key) {
|
||||||
|
case 'home':
|
||||||
|
return <HomeScreen showDialog={showDialog} />;
|
||||||
|
case 'history':
|
||||||
|
return <HistoryScreen />;
|
||||||
|
case 'profile':
|
||||||
|
return <ProfileScreen />;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BottomNavigation
|
<PaperProvider>
|
||||||
navigationState={{index, routes}}
|
<BottomNavigation
|
||||||
onIndexChange={setIndex}
|
navigationState={{index, routes}}
|
||||||
renderScene={renderScene}
|
onIndexChange={setIndex}
|
||||||
activeColor={Colors.primary30.color}
|
renderScene={renderScene}
|
||||||
inactiveColor={Colors.neutral100.color}
|
activeColor={Colors.primary30.color}
|
||||||
barStyle={{backgroundColor: Colors.primary30.color}}
|
inactiveColor={Colors.neutral100.color}
|
||||||
theme={{
|
barStyle={{backgroundColor: Colors.primary30.color}}
|
||||||
colors: {
|
theme={{
|
||||||
secondaryContainer: Colors.neutral100.color,
|
colors: {
|
||||||
},
|
secondaryContainer: Colors.neutral100.color,
|
||||||
}}
|
},
|
||||||
renderLabel={({route}) => (
|
}}
|
||||||
<Text style={styles.bottomNavLabel}>{route.title}</Text>
|
renderLabel={({route}) => (
|
||||||
)}
|
<Text style={styles.bottomNavLabel}>{route.title}</Text>
|
||||||
/>
|
)}
|
||||||
|
/>
|
||||||
|
<Portal>
|
||||||
|
<Dialog visible={visible} style={styles.dialogContainer}>
|
||||||
|
<Dialog.Title style={styles.dialogTitle}>Peringatan</Dialog.Title>
|
||||||
|
<View style={styles.dialogContentContainer}>
|
||||||
|
<Text style={styles.dialogDesc}>
|
||||||
|
Silakan melakukan pengisian kuesioner.
|
||||||
|
</Text>
|
||||||
|
<Text style={[styles.dialogDesc, {...FontFamily.notoSansBold}]}>
|
||||||
|
Pastikan data dan jawaban yang Anda berikan benar.
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.dialogDesc}>
|
||||||
|
Pemberian keterangan yang tidak benar merupakan pelanggaran
|
||||||
|
keimigrasian sebagaimana ketentuan Pasal 126 huruf c UU No. 6
|
||||||
|
tahun 2011 tentang Keimigrasian dan akan mengakibatkan permohonan
|
||||||
|
paspor Anda ditolak dan pembayaran tidak dapat dikembalikan.
|
||||||
|
</Text>
|
||||||
|
<Button
|
||||||
|
style={styles.buttonContinue}
|
||||||
|
mode="contained"
|
||||||
|
textColor={Colors.neutral100.color}
|
||||||
|
onPress={() => {
|
||||||
|
hideDialog();
|
||||||
|
navigation.navigate('RegularPassport');
|
||||||
|
}}>
|
||||||
|
Lanjut
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</Dialog>
|
||||||
|
</Portal>
|
||||||
|
</PaperProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {StyleSheet} from 'react-native';
|
import {StyleSheet} from 'react-native';
|
||||||
import Colors from '../../../assets/styles/Colors';
|
import Colors from '../../../assets/styles/Colors';
|
||||||
|
import FontFamily from '../../../assets/styles/FontFamily';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
bottomNavLabel: {
|
bottomNavLabel: {
|
||||||
@ -9,6 +10,31 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
},
|
},
|
||||||
|
dialogContainer: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
elevation: 0,
|
||||||
|
shadowColor: 'transparent',
|
||||||
|
borderRadius: 20,
|
||||||
|
},
|
||||||
|
dialogTitle: {
|
||||||
|
fontSize: 22,
|
||||||
|
color: Colors.secondary30.color,
|
||||||
|
},
|
||||||
|
dialogContentContainer: {
|
||||||
|
marginHorizontal: 24,
|
||||||
|
marginBottom: 24,
|
||||||
|
gap: 16,
|
||||||
|
},
|
||||||
|
dialogDesc: {
|
||||||
|
fontSize: 14,
|
||||||
|
...FontFamily.notoSansRegular,
|
||||||
|
includeFontPadding: false,
|
||||||
|
color: Colors.primary30.color,
|
||||||
|
},
|
||||||
|
buttonContinue: {
|
||||||
|
backgroundColor: Colors.primary30.color,
|
||||||
|
marginTop: 12,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export default styles;
|
export default styles;
|
||||||
|
@ -55,6 +55,7 @@ function ProfileScreen() {
|
|||||||
icon="pencil-outline"
|
icon="pencil-outline"
|
||||||
mode="contained"
|
mode="contained"
|
||||||
style={styles.sectionButtonStyle}
|
style={styles.sectionButtonStyle}
|
||||||
|
textColor={Colors.neutral100.color}
|
||||||
onPress={() => navigation.navigate('EditProfile')}>
|
onPress={() => navigation.navigate('EditProfile')}>
|
||||||
Edit Profil
|
Edit Profil
|
||||||
</Button>
|
</Button>
|
||||||
@ -62,6 +63,7 @@ function ProfileScreen() {
|
|||||||
icon="lock-outline"
|
icon="lock-outline"
|
||||||
mode="contained"
|
mode="contained"
|
||||||
style={styles.sectionButtonStyle}
|
style={styles.sectionButtonStyle}
|
||||||
|
textColor={Colors.neutral100.color}
|
||||||
onPress={() => navigation.navigate('SetPassword')}>
|
onPress={() => navigation.navigate('SetPassword')}>
|
||||||
Atur Kata Sandi
|
Atur Kata Sandi
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -1,11 +1,493 @@
|
|||||||
import React from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import {Text, View} from 'react-native';
|
import {
|
||||||
|
BackHandler,
|
||||||
|
Pressable,
|
||||||
|
ScrollView,
|
||||||
|
StatusBar,
|
||||||
|
Text,
|
||||||
|
View,
|
||||||
|
} from 'react-native';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
|
import {useNavigation} from '@react-navigation/native';
|
||||||
|
import Colors from '../../../assets/styles/Colors';
|
||||||
|
import RadioButtonOptionComponent from '../../components/RadioButtonOption';
|
||||||
|
import {RootStackParamList} from '../../navigation/type';
|
||||||
|
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
||||||
|
import {Button, Dialog, PaperProvider, Portal} from 'react-native-paper';
|
||||||
|
import StepIndicator from '../../components/StepIndicator';
|
||||||
|
import TextInputComponent from '../../components/TextInput';
|
||||||
|
import genderData from '../../data/DropdownData/GenderData';
|
||||||
|
import civilStatusData from '../../data/DropdownData/CivilStatus';
|
||||||
|
|
||||||
|
type RegularPassportScreenNavigationProp = NativeStackNavigationProp<
|
||||||
|
RootStackParamList,
|
||||||
|
'RegularPassport'
|
||||||
|
>;
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
label: 'Dewasa',
|
||||||
|
description: 'WNI berusia di atas 17 tahun atau sudah menikah',
|
||||||
|
value: 'adult',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Anak',
|
||||||
|
description: 'WNI berusia di bawah 17 tahun dan belum menikah',
|
||||||
|
value: 'child',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const hasHadPassportBeforeOptions = [
|
||||||
|
{
|
||||||
|
label: 'Belum',
|
||||||
|
description:
|
||||||
|
'Belum pernah memiliki paspor atau belum pernah mengajukan permohonan paspor',
|
||||||
|
value: 'not_yet',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Sudah',
|
||||||
|
description: '',
|
||||||
|
value: 'already',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const previousPassportConditionOptions = [
|
||||||
|
{
|
||||||
|
label: 'Habis masa berlaku',
|
||||||
|
description: 'null',
|
||||||
|
value: 'expired',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Penuh/Halaman Penuh',
|
||||||
|
description: 'null',
|
||||||
|
value: 'full_pages',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hilang',
|
||||||
|
description: 'null',
|
||||||
|
value: 'lost',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Rusak',
|
||||||
|
description: 'null',
|
||||||
|
value: 'damaged',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Hilang karena keadaan kahar',
|
||||||
|
description: 'null',
|
||||||
|
value: 'lost_due_to_force_majeure',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Rusak karena keadaan kahar',
|
||||||
|
description: 'null',
|
||||||
|
value: 'damaged_due_to_force_majeure',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const renderApplicationStepsContent = (
|
||||||
|
step: number,
|
||||||
|
subStep: number,
|
||||||
|
setStep: (step: number) => void,
|
||||||
|
setSubStep: (step: number) => void,
|
||||||
|
selectedOption: string,
|
||||||
|
setSelectedOption: (val: string) => void,
|
||||||
|
) => {
|
||||||
|
if (step === 1) {
|
||||||
|
switch (subStep) {
|
||||||
|
case 1:
|
||||||
|
return (
|
||||||
|
<View style={styles.subStepContainer}>
|
||||||
|
<View style={styles.subStepTextWrapper}>
|
||||||
|
<Text style={styles.subStepTitle}>
|
||||||
|
Ambil/Upload Foto KTP Anda
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.subStepDesc}>
|
||||||
|
Pastikan pencahayaan cukup, tulisan pada identitas terlihat
|
||||||
|
jelas, dan jangan gunakan foto dari Live Mode sebelum
|
||||||
|
melanjutkan.
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.nationalIdImage} />
|
||||||
|
<View style={styles.subStepButtonContainer}>
|
||||||
|
<Button
|
||||||
|
mode="contained"
|
||||||
|
onPress={() => setSubStep(2)}
|
||||||
|
style={styles.subStepButtonActive}
|
||||||
|
textColor={Colors.neutral100.color}>
|
||||||
|
Pilih Foto
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
mode="outlined"
|
||||||
|
onPress={() => {}}
|
||||||
|
style={styles.subStepButtonInActive}
|
||||||
|
textColor={Colors.primary30.color}>
|
||||||
|
Ulangi
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 2:
|
||||||
|
return (
|
||||||
|
<ScrollView>
|
||||||
|
<View style={styles.subStepContainer}>
|
||||||
|
<View style={styles.nationalIdImageContainer}>
|
||||||
|
<View style={styles.nationalIdImageCropped} />
|
||||||
|
</View>
|
||||||
|
<View
|
||||||
|
style={[styles.subStepTextInputContainer, {marginBottom: 24}]}>
|
||||||
|
<TextInputComponent
|
||||||
|
title="Nama Lengkap Pemohon"
|
||||||
|
placeholder="Nama Lengkap Anda"
|
||||||
|
isRequired
|
||||||
|
/>
|
||||||
|
<TextInputComponent
|
||||||
|
title="NIK"
|
||||||
|
placeholder="Nama NIK Anda"
|
||||||
|
isRequired
|
||||||
|
/>
|
||||||
|
<View style={styles.subStepTextInputRowContainer}>
|
||||||
|
<View style={styles.subStepTextInputFlex}>
|
||||||
|
<TextInputComponent
|
||||||
|
title="Tanggal Lahir"
|
||||||
|
placeholder="DD/MM/YYYY"
|
||||||
|
isRequired
|
||||||
|
isDate
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.subStepTextInputFlex}>
|
||||||
|
<TextInputComponent
|
||||||
|
title="Jenis Kelamin"
|
||||||
|
placeholder="Jenis Kelamin"
|
||||||
|
isRequired
|
||||||
|
isDropdown
|
||||||
|
dropdownItemData={genderData}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<TextInputComponent
|
||||||
|
title="Status Sipil"
|
||||||
|
placeholder="Pilih Status Sipil Anda"
|
||||||
|
isRequired
|
||||||
|
isDropdown
|
||||||
|
dropdownItemData={civilStatusData}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.subStepButtonContainer}>
|
||||||
|
<Button
|
||||||
|
mode="contained"
|
||||||
|
onPress={() => {
|
||||||
|
setStep(2);
|
||||||
|
setSubStep(1);
|
||||||
|
}}
|
||||||
|
style={styles.subStepButtonActive}
|
||||||
|
textColor={Colors.neutral100.color}>
|
||||||
|
Lanjut
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
mode="outlined"
|
||||||
|
onPress={() => setSubStep(1)}
|
||||||
|
style={styles.subStepButtonInActive}
|
||||||
|
textColor={Colors.primary30.color}>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (step === 2) {
|
||||||
|
switch (subStep) {
|
||||||
|
case 1:
|
||||||
|
return (
|
||||||
|
<View style={styles.subStepContainer}>
|
||||||
|
<Pressable
|
||||||
|
onPress={() => {
|
||||||
|
setStep(1);
|
||||||
|
setSubStep(2);
|
||||||
|
}}
|
||||||
|
style={({pressed}) => [
|
||||||
|
styles.subStepButtonBackWrapper,
|
||||||
|
{
|
||||||
|
transform: [{scale: pressed ? 0.99 : 1}],
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Icon name="chevron-left" size={24} />
|
||||||
|
<Text style={styles.subStepButtonBackText}>Kembali</Text>
|
||||||
|
</Pressable>
|
||||||
|
<View style={styles.subStepQuestionnaireOptionContainer}>
|
||||||
|
<Text style={styles.questionnaireData}>
|
||||||
|
Apakah Anda sudah pernah memiliki paspor?
|
||||||
|
</Text>
|
||||||
|
{hasHadPassportBeforeOptions.map(options => (
|
||||||
|
<RadioButtonOptionComponent
|
||||||
|
key={options.value}
|
||||||
|
label={options.label}
|
||||||
|
description={options.description}
|
||||||
|
value={options.value}
|
||||||
|
selectedValue={selectedOption}
|
||||||
|
onSelect={value => {
|
||||||
|
setSelectedOption(value);
|
||||||
|
value === 'already' && setSubStep(2);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 2:
|
||||||
|
return (
|
||||||
|
<ScrollView>
|
||||||
|
<View style={styles.subStepContainer}>
|
||||||
|
<Pressable
|
||||||
|
onPress={() => {
|
||||||
|
setSubStep(1);
|
||||||
|
}}
|
||||||
|
style={({pressed}) => [
|
||||||
|
styles.subStepButtonBackWrapper,
|
||||||
|
{
|
||||||
|
transform: [{scale: pressed ? 0.99 : 1}],
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Icon name="chevron-left" size={24} />
|
||||||
|
<Text style={styles.subStepButtonBackText}>Kembali</Text>
|
||||||
|
</Pressable>
|
||||||
|
<View style={styles.subStepQuestionnaireOptionContainer}>
|
||||||
|
<Text style={styles.questionnaireData}>
|
||||||
|
Apakah Anda sudah pernah memiliki paspor?
|
||||||
|
</Text>
|
||||||
|
{previousPassportConditionOptions.map(options => (
|
||||||
|
<RadioButtonOptionComponent
|
||||||
|
key={options.value}
|
||||||
|
label={options.label}
|
||||||
|
description={options.description}
|
||||||
|
value={options.value}
|
||||||
|
selectedValue={selectedOption}
|
||||||
|
onSelect={value => {
|
||||||
|
setSelectedOption(value);
|
||||||
|
value === 'already' && setSubStep(2);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
<Button
|
||||||
|
mode="contained"
|
||||||
|
onPress={() => {
|
||||||
|
setSubStep(3);
|
||||||
|
}}
|
||||||
|
style={styles.subStepButtonActive}
|
||||||
|
textColor={Colors.neutral100.color}>
|
||||||
|
Lanjut
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
case 3:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Text>Step 2.3</Text>
|
||||||
|
<Button
|
||||||
|
mode="contained"
|
||||||
|
onPress={() => {
|
||||||
|
setStep(3);
|
||||||
|
setSubStep(1);
|
||||||
|
}}>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
<Button onPress={() => setSubStep(2)}>Back</Button>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (step) {
|
||||||
|
case 3:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Button mode="contained" onPress={() => setStep(4)}>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
<Button onPress={() => setStep(2)}>Back</Button>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 4:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Button mode="contained" onPress={() => setStep(5)}>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
<Button onPress={() => setStep(3)}>Back</Button>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 5:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Button mode="contained" onPress={() => setStep(6)}>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
<Button onPress={() => setStep(4)}>Back</Button>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 6:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Button mode="contained" onPress={() => setStep(7)}>
|
||||||
|
Next
|
||||||
|
</Button>
|
||||||
|
<Button onPress={() => setStep(5)}>Back</Button>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
case 7:
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Button onPress={() => setStep(6)}>Back</Button>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function RegularPassportScreen() {
|
function RegularPassportScreen() {
|
||||||
|
const navigation = useNavigation<RegularPassportScreenNavigationProp>();
|
||||||
|
const [selectedOption, setSelectedOption] = useState('');
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const [showApplicationStepsContent, setShowApplicationStepsContent] =
|
||||||
|
useState(false);
|
||||||
|
const [step, setStep] = useState(1);
|
||||||
|
const [subStep, setSubStep] = useState(1);
|
||||||
|
|
||||||
|
const showDialog = () => setVisible(true);
|
||||||
|
const hideDialog = () => setVisible(false);
|
||||||
|
const completedSteps = [...Array(step - 1)].map((_, i) => i + 1);
|
||||||
|
|
||||||
|
const stepTitles: {[key: number]: string} = {
|
||||||
|
1: 'Informasi Pribadi',
|
||||||
|
2: 'Dokumen Pendukung',
|
||||||
|
3: 'Pembayaran',
|
||||||
|
4: 'Konfirmasi Data',
|
||||||
|
5: 'Verifikasi',
|
||||||
|
6: 'Pemrosesan',
|
||||||
|
7: 'Selesai',
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (showApplicationStepsContent) {
|
||||||
|
const backAction = () => {
|
||||||
|
setShowApplicationStepsContent(false);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const backHandler = BackHandler.addEventListener(
|
||||||
|
'hardwareBackPress',
|
||||||
|
backAction,
|
||||||
|
);
|
||||||
|
|
||||||
|
return () => backHandler.remove();
|
||||||
|
}
|
||||||
|
}, [showApplicationStepsContent]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<Text>Regular Passport Screen</Text>
|
<PaperProvider>
|
||||||
|
<StatusBar
|
||||||
|
backgroundColor={visible ? '#295E70' : Colors.secondary30.color}
|
||||||
|
barStyle="light-content"
|
||||||
|
/>
|
||||||
|
<View style={styles.appBarContainer}>
|
||||||
|
<Icon
|
||||||
|
name="arrow-left"
|
||||||
|
size={24}
|
||||||
|
style={styles.appBarIcon}
|
||||||
|
color={Colors.neutral100.color}
|
||||||
|
onPress={() => navigation.goBack()}
|
||||||
|
/>
|
||||||
|
<Text style={styles.appBarTitle}>Pengajuan Paspor Regular</Text>
|
||||||
|
</View>
|
||||||
|
{showApplicationStepsContent ? (
|
||||||
|
<View style={styles.applicationStepsContainer}>
|
||||||
|
<Text style={styles.stepTitle}>{stepTitles[step]}</Text>
|
||||||
|
<StepIndicator
|
||||||
|
currentStep={step}
|
||||||
|
totalSteps={7}
|
||||||
|
completedSteps={completedSteps}
|
||||||
|
/>
|
||||||
|
{renderApplicationStepsContent(
|
||||||
|
step,
|
||||||
|
subStep,
|
||||||
|
setStep,
|
||||||
|
setSubStep,
|
||||||
|
selectedOption,
|
||||||
|
setSelectedOption,
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Text style={styles.questionnaireTitle}>
|
||||||
|
Kuesioner Layanan Permohonan
|
||||||
|
</Text>
|
||||||
|
<View style={styles.questionnaireOptionContainer}>
|
||||||
|
<Text style={styles.questionnaireData}>
|
||||||
|
Untuk siapa paspor ini?
|
||||||
|
</Text>
|
||||||
|
{options.map(option => (
|
||||||
|
<RadioButtonOptionComponent
|
||||||
|
key={option.value}
|
||||||
|
label={option.label}
|
||||||
|
description={option.description}
|
||||||
|
value={option.value}
|
||||||
|
selectedValue={selectedOption}
|
||||||
|
onSelect={value => {
|
||||||
|
setSelectedOption(value);
|
||||||
|
value === 'child'
|
||||||
|
? showDialog()
|
||||||
|
: setShowApplicationStepsContent(true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
<Portal>
|
||||||
|
<Dialog visible={visible} style={styles.dialogContainer}>
|
||||||
|
<Dialog.Title style={styles.dialogTitle}>
|
||||||
|
Pemberitahuan
|
||||||
|
</Dialog.Title>
|
||||||
|
<View style={styles.dialogContentContainer}>
|
||||||
|
<Text style={styles.dialogDesc}>
|
||||||
|
Permohonan paspor anak diwajibkan untuk didampingi oleh
|
||||||
|
orang tua/wali yang sah pada saat datang ke Kantor Imigrasi
|
||||||
|
untuk pelaksanaan wawancara dan pengambilan foto sidik jari.
|
||||||
|
</Text>
|
||||||
|
<View>
|
||||||
|
<Button
|
||||||
|
style={styles.buttonAgree}
|
||||||
|
mode="contained"
|
||||||
|
textColor={Colors.neutral100.color}
|
||||||
|
onPress={() => {
|
||||||
|
hideDialog();
|
||||||
|
setShowApplicationStepsContent(true);
|
||||||
|
}}>
|
||||||
|
Lanjut
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
style={styles.buttonDontAgree}
|
||||||
|
mode="outlined"
|
||||||
|
textColor={Colors.primary30.color}
|
||||||
|
onPress={() => hideDialog()}>
|
||||||
|
Kembali
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Dialog>
|
||||||
|
</Portal>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</PaperProvider>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,164 @@
|
|||||||
import {StyleSheet} from 'react-native';
|
import {StyleSheet} from 'react-native';
|
||||||
|
import Colors from '../../../assets/styles/Colors';
|
||||||
|
import FontFamily from '../../../assets/styles/FontFamily';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
alignContent: 'center',
|
backgroundColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
appBarTitle: {
|
||||||
|
color: Colors.neutral100.color,
|
||||||
|
...FontFamily.notoSansRegular,
|
||||||
|
fontSize: 16,
|
||||||
|
marginStart: 16,
|
||||||
|
},
|
||||||
|
appBarIcon: {
|
||||||
|
marginLeft: 16,
|
||||||
|
},
|
||||||
|
appBarContainer: {
|
||||||
|
height: 64,
|
||||||
|
flexDirection: 'row',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
backgroundColor: Colors.secondary30.color,
|
||||||
|
},
|
||||||
|
questionnaireTitle: {
|
||||||
|
...FontFamily.notoSansExtraBold,
|
||||||
|
fontSize: 18,
|
||||||
|
marginTop: 24,
|
||||||
|
marginBottom: 8,
|
||||||
|
marginHorizontal: 16,
|
||||||
|
color: Colors.secondary30.color,
|
||||||
|
includeFontPadding: false,
|
||||||
|
},
|
||||||
|
questionnaireOptionContainer: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: Colors.secondary50.color,
|
||||||
|
borderRadius: 8,
|
||||||
|
padding: 16,
|
||||||
|
margin: 16,
|
||||||
|
gap: 16,
|
||||||
|
},
|
||||||
|
questionnaireData: {
|
||||||
|
...FontFamily.notoSansBold,
|
||||||
|
fontSize: 14,
|
||||||
|
color: Colors.primary30.color,
|
||||||
|
includeFontPadding: false,
|
||||||
|
},
|
||||||
|
dialogContainer: {
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
|
elevation: 0,
|
||||||
|
shadowColor: 'transparent',
|
||||||
|
borderRadius: 20,
|
||||||
|
},
|
||||||
|
dialogTitle: {
|
||||||
|
fontSize: 22,
|
||||||
|
color: Colors.secondary30.color,
|
||||||
|
},
|
||||||
|
dialogContentContainer: {
|
||||||
|
marginHorizontal: 24,
|
||||||
|
marginBottom: 24,
|
||||||
|
gap: 16,
|
||||||
|
},
|
||||||
|
dialogDesc: {
|
||||||
|
fontSize: 14,
|
||||||
|
...FontFamily.notoSansRegular,
|
||||||
|
includeFontPadding: false,
|
||||||
|
color: Colors.primary30.color,
|
||||||
|
},
|
||||||
|
buttonAgree: {
|
||||||
|
backgroundColor: Colors.primary30.color,
|
||||||
|
marginTop: 12,
|
||||||
|
},
|
||||||
|
buttonDontAgree: {
|
||||||
|
borderColor: Colors.primary30.color,
|
||||||
|
marginTop: 12,
|
||||||
|
},
|
||||||
|
applicationStepsContainer: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
stepTitle: {
|
||||||
|
fontSize: 14,
|
||||||
|
...FontFamily.notoSansBold,
|
||||||
|
includeFontPadding: false,
|
||||||
|
color: Colors.secondary30.color,
|
||||||
|
paddingTop: 16,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
backgroundColor: Colors.secondary70.color,
|
||||||
|
},
|
||||||
|
subStepContainer: {
|
||||||
|
backgroundColor: Colors.neutral100.color,
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
nationalIdImage: {
|
||||||
|
marginVertical: 16,
|
||||||
|
height: 350,
|
||||||
|
backgroundColor: Colors.primary70.color,
|
||||||
|
borderRadius: 20,
|
||||||
|
},
|
||||||
|
subStepButtonContainer: {
|
||||||
|
gap: 16,
|
||||||
|
},
|
||||||
|
subStepButtonActive: {
|
||||||
|
backgroundColor: Colors.primary30.color,
|
||||||
|
},
|
||||||
|
subStepButtonInActive: {
|
||||||
|
borderColor: Colors.primary30.color,
|
||||||
|
},
|
||||||
|
subStepTextWrapper: {
|
||||||
|
gap: 10,
|
||||||
|
},
|
||||||
|
subStepTitle: {
|
||||||
|
fontSize: 16,
|
||||||
|
...FontFamily.notoSansExtraBold,
|
||||||
|
color: Colors.secondary30.color,
|
||||||
|
includeFontPadding: false,
|
||||||
|
},
|
||||||
|
subStepDesc: {
|
||||||
|
includeFontPadding: false,
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.primary10.color,
|
||||||
|
...FontFamily.notoSansRegular,
|
||||||
|
lineHeight: 20,
|
||||||
|
},
|
||||||
|
nationalIdImageContainer: {
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
nationalIdImageCropped: {
|
||||||
|
marginBottom: 16,
|
||||||
|
width: 225,
|
||||||
|
height: 140,
|
||||||
|
backgroundColor: Colors.primary70.color,
|
||||||
|
borderRadius: 20,
|
||||||
|
},
|
||||||
|
subStepTextInputContainer: {
|
||||||
|
gap: 16,
|
||||||
|
},
|
||||||
|
subStepTextInputRowContainer: {
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
subStepTextInputFlex: {
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
subStepButtonBackWrapper: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 4,
|
||||||
|
},
|
||||||
|
subStepButtonBackText: {
|
||||||
|
...FontFamily.notoSansRegular,
|
||||||
|
includeFontPadding: false,
|
||||||
|
fontSize: 10,
|
||||||
|
},
|
||||||
|
subStepQuestionnaireOptionContainer: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: Colors.secondary50.color,
|
||||||
|
borderRadius: 8,
|
||||||
|
padding: 16,
|
||||||
|
marginVertical: 16,
|
||||||
|
gap: 16,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user