diff --git a/android/app/src/main/ic_launcher-playstore.png b/android/app/src/main/ic_launcher-playstore.png
index 9ceea19..8fe4db3 100644
Binary files a/android/app/src/main/ic_launcher-playstore.png and b/android/app/src/main/ic_launcher-playstore.png differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
index d8481cd..54d98d7 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp
index be724f3..f6263b7 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp differ
diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
index 2babee9..8932e00 100644
Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
index ccc1963..5ad29bb 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp
index 961c967..bc27e0d 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp differ
diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
index 6959a8b..e7b3544 100644
Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
index b4e44ac..a6de76e 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp
index 3b09d20..76927b1 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp differ
diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
index 36b15d2..6dcfa91 100644
Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
index cd1e48d..08c7228 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp
index 2a80790..ea9279a 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
index acce0ad..8805178 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
index e723bbd..32d8e53 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp
index 60b5469..01dfd84 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
index a392476..dd48628 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/android/app/src/main/res/values/ic_launcher_background.xml b/android/app/src/main/res/values/ic_launcher_background.xml
index f4d1d22..c5d5899 100644
--- a/android/app/src/main/res/values/ic_launcher_background.xml
+++ b/android/app/src/main/res/values/ic_launcher_background.xml
@@ -1,4 +1,4 @@
- #2B3A51
+ #FFFFFF
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 855c4f2..9767741 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -30,7 +30,7 @@
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/runtime": "^7.25.0",
- "@react-native-community/cli": "15.0.1",
+ "@react-native-community/cli": "^15.0.1",
"@react-native-community/cli-platform-android": "15.0.1",
"@react-native-community/cli-platform-ios": "15.0.1",
"@react-native/babel-preset": "0.78.0",
diff --git a/package.json b/package.json
index 3625145..26b783e 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
"@babel/core": "^7.25.2",
"@babel/preset-env": "^7.25.3",
"@babel/runtime": "^7.25.0",
- "@react-native-community/cli": "15.0.1",
+ "@react-native-community/cli": "^15.0.1",
"@react-native-community/cli-platform-android": "15.0.1",
"@react-native-community/cli-platform-ios": "15.0.1",
"@react-native/babel-preset": "0.78.0",
diff --git a/src/components/InfoToast.tsx b/src/components/InfoToast.tsx
new file mode 100644
index 0000000..b3ddc81
--- /dev/null
+++ b/src/components/InfoToast.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import {StyleSheet, Text, View} from 'react-native';
+import {Snackbar} from 'react-native-paper';
+import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
+import Colors from '../../assets/styles/Colors';
+
+type InfoToastProps = {
+ visible: boolean;
+ message: string;
+ onDismiss: () => void;
+ duration?: number;
+};
+
+const InfoToast = ({
+ visible,
+ message,
+ onDismiss,
+ duration = 2000,
+}: InfoToastProps) => {
+ return (
+
+
+
+ {message}
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ snackbar: {
+ backgroundColor: Colors.secondary10.color,
+ borderRadius: 100,
+ margin: 16,
+ alignSelf: 'center',
+ },
+ contentContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ icon: {
+ marginRight: 8,
+ },
+ message: {
+ color: 'white',
+ },
+});
+
+export default InfoToast;
diff --git a/src/components/TextInput.tsx b/src/components/TextInput.tsx
index 40a5e30..2aec2bc 100644
--- a/src/components/TextInput.tsx
+++ b/src/components/TextInput.tsx
@@ -194,7 +194,10 @@ const TextInputComponent = (props: TextInputComponentProps) => {
)}
{
)}
{
;
type RenderApplicationStepsContentProps = {
+ navigation: any;
step: number;
subStep: number;
setStep: (step: number) => void;
@@ -74,15 +93,16 @@ type RenderApplicationStepsContentProps = {
showSelectDateSheet: () => void;
selectedDestinationCountryOption: string;
setSelectedDestinationCountryOption: (val: string) => void;
- setStepValidationStatus: React.Dispatch<
- React.SetStateAction>
- >;
+ stepValidationStatus: StepValidationStatus;
+ setStepValidationStatus: StepValidationStatusSetter;
+ editedCompletedRef: RefObject>;
};
const RenderApplicationStepsContent = (
props: RenderApplicationStepsContentProps,
) => {
const {
+ navigation,
step,
subStep,
setStep,
@@ -107,6 +127,7 @@ const RenderApplicationStepsContent = (
showSearchLocationSheet,
showSelectDateSheet,
setStepValidationStatus,
+ editedCompletedRef,
} = props;
if (step === 1) {
@@ -118,14 +139,17 @@ const RenderApplicationStepsContent = (
case 3:
return (
{
setStepValidationStatus(prev => ({
...prev,
1: isValid ? 'completed' : 'invalid',
}));
}}
+ editedCompletedRef={editedCompletedRef}
/>
);
default:
@@ -138,11 +162,14 @@ const RenderApplicationStepsContent = (
case 1:
return (
);
case 2:
@@ -209,16 +236,27 @@ const RenderApplicationStepsContent = (
case 10:
return (
{
+ setStepValidationStatus(prev => ({
+ ...prev,
+ 2: isValid ? 'completed' : 'invalid',
+ }));
+ }}
+ editedCompletedRef={editedCompletedRef}
/>
);
case 11:
return (
{
@@ -227,6 +265,7 @@ const RenderApplicationStepsContent = (
2: isValid ? 'completed' : 'invalid',
}));
}}
+ editedCompletedRef={editedCompletedRef}
/>
);
default:
@@ -239,17 +278,29 @@ const RenderApplicationStepsContent = (
case 1:
return (
);
case 2:
return (
{
+ setStepValidationStatus(prev => ({
+ ...prev,
+ 4: isValid ? 'completed' : 'invalid',
+ }));
+ }}
+ editedCompletedRef={editedCompletedRef}
/>
);
}
@@ -258,8 +309,10 @@ const RenderApplicationStepsContent = (
case 3:
return (
);
case 5:
return (
{
+ setStepValidationStatus(prev => ({
+ ...prev,
+ 5: 'completed',
+ }));
+ }}
/>
);
case 6:
@@ -297,6 +357,12 @@ const RenderApplicationStepsContent = (
{
+ setStepValidationStatus(prev => ({
+ ...prev,
+ 7: 'completed',
+ }));
+ }}
/>
);
default:
@@ -362,9 +428,12 @@ function RegularPassportScreen() {
const [checkedOption, setCheckedOption] = useState(false);
const [showApplicationStepsContent, setShowApplicationStepsContent] =
useState(false);
+
+ const [toastVisible, setToastVisible] = useState(false);
+ const [toastMessage, setToastMessage] = useState('');
+
const [step, setStep] = useState(1);
const [subStep, setSubStep] = useState(1);
-
const [completedSteps, setCompletedSteps] = useState(
[...Array(step - 1)].map((_, i) => i + 1),
);
@@ -512,6 +581,11 @@ function RegularPassportScreen() {
});
};
+ const showInfoToast = (msg: string) => {
+ setToastMessage(msg);
+ setToastVisible(true);
+ };
+
// Render steps or questionnaire
const renderApplicationStepsContent = showApplicationStepsContent ? (
<>
@@ -523,67 +597,33 @@ function RegularPassportScreen() {
completedSteps={completedSteps}
validationStatus={stepValidationStatus}
onStepPress={(targetStep: number) => {
- const isCurrentStepIn5to7 = step >= 5 && step <= 7;
- const isTargetStepIn1to4 = targetStep >= 1 && targetStep <= 4;
- const isTargetStepIn5to7 = targetStep >= 5 && targetStep <= 7;
+ const isCurrentStep7 = step === 7;
+ const isTargetStepIn1to6 = targetStep >= 1 && targetStep <= 6;
- const isStep1to4Completed = [1, 2, 3, 4].every(
- s => stepValidationStatus[s] === 'completed',
- );
+ const toastMessage = isCurrentStep7
+ ? 'Tak dapat kembali – langkah terakhir.'
+ : !isTargetStepIn1to6
+ ? 'Lengkapi langkah 1 – 6 dulu'
+ : null;
- if (!isCurrentStepIn5to7 && isTargetStepIn5to7) {
- ToastAndroid.show(
- 'Lengkapi langkah 1 – 4 dulu',
- ToastAndroid.SHORT,
- );
+ if (toastMessage) {
+ showInfoToast(toastMessage);
return;
}
- if (
- isCurrentStepIn5to7 &&
- isStep1to4Completed &&
- isTargetStepIn1to4
- ) {
- ToastAndroid.show(
- 'Hanya dapat berpindah di langkah 5 – 7.',
- ToastAndroid.SHORT,
- );
- return;
- }
-
- setStepValidationStatus(prev => {
- const next = {...prev};
-
- if (step !== targetStep && editedCompletedRef.current.has(step)) {
- next[step] = 'completed';
- editedCompletedRef.current.delete(step);
- }
-
- if (prev[targetStep] === 'completed') {
- editedCompletedRef.current.add(targetStep);
- }
-
- next[targetStep] = 'incomplete';
-
- if (targetStep > step) {
- for (let s = 1; s < targetStep; s++) {
- if (next[s] !== 'completed') next[s] = 'invalid';
- }
- } else if (targetStep < step) {
- for (let s = step; s > targetStep; s--) {
- if (next[s] !== 'completed') next[s] = 'invalid';
- }
- }
-
- return next;
+ changeStep({
+ currentStep: step,
+ targetStep: targetStep,
+ setStep,
+ setSubStep: () => setSubStep(1),
+ setStepValidationStatus,
+ editedCompletedRef,
});
-
- setStep(targetStep);
- setSubStep(1);
}}
/>
@@ -672,7 +714,19 @@ function RegularPassportScreen() {
visible={visibleFinalizationConfirmationDialog}
onClose={hideFinalizationConfirmationDialog}
onContinue={() => {
- setStep(7);
+ setStepValidationStatus(prev => ({
+ ...prev,
+ 6: 'completed',
+ }));
+
+ const canProceedToStep7 = [1, 2, 3, 4, 5, 6].every(
+ s => stepValidationStatus[s] === 'completed',
+ );
+
+ !canProceedToStep7
+ ? showInfoToast('Lengkapi semua langkah terlebih dahulu.')
+ : setStep(7);
+
hideFinalizationConfirmationDialog();
}}
/>
@@ -753,6 +807,11 @@ function RegularPassportScreen() {
setShowApplicationStepsContent(true);
}}
/>
+ setToastVisible(false)}
+ />
);
diff --git a/src/screens/regularPassport/steps/Step1VerifyNik/Step1VerifyNikSubStep3.tsx b/src/screens/regularPassport/steps/Step1VerifyNik/Step1VerifyNikSubStep3.tsx
index 26cd7ce..15100d4 100644
--- a/src/screens/regularPassport/steps/Step1VerifyNik/Step1VerifyNikSubStep3.tsx
+++ b/src/screens/regularPassport/steps/Step1VerifyNik/Step1VerifyNikSubStep3.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {RefObject, useState} from 'react';
import {ScrollView, View} from 'react-native';
import {Button} from 'react-native-paper';
import styles from '../styles';
@@ -6,23 +6,31 @@ import TextInputComponent from '../../../../components/TextInput';
import genderData from '../../../../data/DropdownData/GenderData';
import civilStatusData from '../../../../data/DropdownData/CivilStatusData';
import Colors from '../../../../../assets/styles/Colors';
+import {changeStep} from '../../../../utils/stepNavigation';
+import {StepValidationStatusSetter} from '../../../../../types/step';
type Step1VerifyNikSubStep3Props = {
+ step: number;
setStep: (val: number) => void;
setSubStep: (val: number) => void;
+ setStepValidationStatus: StepValidationStatusSetter;
onSubStepValidation: (isValid: boolean) => void;
+ editedCompletedRef: RefObject>;
};
const Step1VerifyNikSubStep3 = ({
+ step,
setStep,
setSubStep,
+ setStepValidationStatus,
onSubStepValidation,
+ editedCompletedRef,
}: Step1VerifyNikSubStep3Props) => {
- const [fullName, setFullName] = React.useState('');
- const [nik, setNik] = React.useState('');
- const [birthDate, setBirthDate] = React.useState('');
- const [gender, setGender] = React.useState('');
- const [civilStatus, setCivilStatus] = React.useState('');
+ const [fullName, setFullName] = useState('');
+ const [nik, setNik] = useState('');
+ const [birthDate, setBirthDate] = useState('');
+ const [gender, setGender] = useState('');
+ const [civilStatus, setCivilStatus] = useState('');
const onNextPress = () => {
const isFormValid =
@@ -38,8 +46,14 @@ const Step1VerifyNikSubStep3 = ({
onSubStepValidation(false);
}
- setStep(2);
- setSubStep(1);
+ changeStep({
+ currentStep: step,
+ targetStep: 2,
+ setStep,
+ setSubStep: () => setSubStep(1),
+ setStepValidationStatus,
+ editedCompletedRef,
+ });
};
return (
diff --git a/src/screens/regularPassport/steps/Step2PassportApplicationQuestionnaire/Step2PassportApplicationQuestionnaireSubStep1.tsx b/src/screens/regularPassport/steps/Step2PassportApplicationQuestionnaire/Step2PassportApplicationQuestionnaireSubStep1.tsx
index a8eb2e7..00318cb 100644
--- a/src/screens/regularPassport/steps/Step2PassportApplicationQuestionnaire/Step2PassportApplicationQuestionnaireSubStep1.tsx
+++ b/src/screens/regularPassport/steps/Step2PassportApplicationQuestionnaire/Step2PassportApplicationQuestionnaireSubStep1.tsx
@@ -1,36 +1,52 @@
-import React from 'react';
+import React, {RefObject, useRef} from 'react';
import {View, Pressable, Text} from 'react-native';
import styles from '../styles';
import RadioButtonOptionComponent from '../../../../components/RadioButtonOption';
import hasHadPassportBeforeOptions from '../../../../data/Options/HasHadPassportBeforeOptions';
import {Button} from 'react-native-paper';
import Colors from '../../../../../assets/styles/Colors';
+import {changeStep} from '../../../../utils/stepNavigation';
+import {StepValidationStatusSetter} from '../../../../../types/step';
type Step2PassportApplicationQuestionnaireSubStep1Props = {
+ step: number;
setStep: (step: number) => void;
setSubStep: (subStep: number) => void;
+ setStepValidationStatus: StepValidationStatusSetter;
selectedPassportOption: string;
setSelectedPassportOption: (value: string) => void;
showDontHaveYetDialog: () => void;
+ editedCompletedRef: RefObject>;
};
const Step2PassportApplicationQuestionnaireSubStep1 = ({
+ step,
setStep,
setSubStep,
+ setStepValidationStatus,
selectedPassportOption,
setSelectedPassportOption,
showDontHaveYetDialog,
+ editedCompletedRef,
}: Step2PassportApplicationQuestionnaireSubStep1Props) => {
+ const onBackPress = () => {
+ changeStep({
+ currentStep: step,
+ targetStep: 1,
+ setStep,
+ setSubStep: () => setSubStep(3),
+ setStepValidationStatus,
+ editedCompletedRef,
+ });
+ };
+
return (
({
transform: [{scale: pressed ? 0.99 : 1}],
})}
- onPress={() => {
- setStep(1);
- setSubStep(3);
- }}>
+ onPress={onBackPress}>
+
Data di bawah ini harus sesuai dengan keterangan pada KTP pemohon.
Data yang bertanda (
@@ -58,11 +140,15 @@ const Step4ApplicantAdditionalDataSubStep2 = ({
isRequired
isDropdown
dropdownItemData={jobData}
+ value={job}
+ onChangeText={setJob}
/>
@@ -78,6 +164,8 @@ const Step4ApplicantAdditionalDataSubStep2 = ({
title="Nama Ibu"
placeholder="Masukkan nama lengkap ibu"
isRequired
+ value={motherName}
+ onChangeText={setMotherName}
/>
@@ -152,49 +244,7 @@ const Step4ApplicantAdditionalDataSubStep2 = ({
{
- // Ambil data appointment yang sudah tersimpan
- const storedAppointments: PassportAppointment[] =
- (await getData('passportAppointments')) || [];
-
- // Ambil ID terakhir dan hitung ID baru
- const lastId = storedAppointments.length
- ? Math.max(...storedAppointments.map(item => Number(item.id)))
- : 0;
- const nextId = (lastId + 1).toString();
-
- // Buat appointment baru dengan ID yang sudah dihitung
- const newAppointment: PassportAppointment = {
- id: nextId,
- applicantName: 'Salwa Aisyah Adhani',
- applicantCode: '1038000008887777',
- appointmentDate: 'Selasa, 20 Mei 2025',
- appointmentTime: '10:00-11:00 WIB',
- serviceUnit: 'Kantor Imigrasi Depok',
- status: 'Menunggu Pembayaran',
- submissionDate: 'Kamis, 15 Mei 2025 21:30',
- serviceCode: 'EH-LP7RNC',
- applicationDetails: {
- nationalIdNumber: '3271234560009123456',
- gender: 'Wanita',
- applicationType: 'Penggantian Paspor',
- replacementReason: 'Penuh/Halaman Penuh',
- applicationPurpose: 'Wisata/Liburan',
- passportType: 'PASPOR ELEKTRONIK POLIKARBONAT 5 TAHUN',
- fee: '650.000',
- },
- };
-
- // Simpan appointment baru
- await addData(
- 'passportAppointments',
- newAppointment,
- );
-
- const updatedAppointments = await getData('passportAppointments');
- console.log('Data yang berhasil ditambahkan:', updatedAppointments);
- setStep(5);
- }}
+ onPress={handleSaveDraft}
style={[styles.subStepButtonContained, {marginBottom: 8}]}
textColor={Colors.neutral100.color}>
Simpan Draft
diff --git a/src/screens/regularPassport/steps/Step5ApplicationTypeAndApplicantData/Step5ApplicationTypeAndApplicantData.tsx b/src/screens/regularPassport/steps/Step5ApplicationTypeAndApplicantData/Step5ApplicationTypeAndApplicantData.tsx
index b604129..021bf89 100644
--- a/src/screens/regularPassport/steps/Step5ApplicationTypeAndApplicantData/Step5ApplicationTypeAndApplicantData.tsx
+++ b/src/screens/regularPassport/steps/Step5ApplicationTypeAndApplicantData/Step5ApplicationTypeAndApplicantData.tsx
@@ -9,12 +9,15 @@ import {PassportAppointment} from '../../../../navigation/type';
type Step5ApplicationTypeAndApplicantDataProps = {
setStep: (step: number) => void;
- setSubStep: (subStep: number) => void;
showEditDataSheet: () => void;
+ navigation: any;
+ onSubStepValidation: (isValid: boolean) => void;
};
-const Step5Content = (props: Step5ApplicationTypeAndApplicantDataProps) => {
- const {setStep, setSubStep, showEditDataSheet} = props;
+const Step5ApplicationTypeAndApplicantData = (
+ props: Step5ApplicationTypeAndApplicantDataProps,
+) => {
+ const {setStep, showEditDataSheet, navigation, onSubStepValidation} = props;
const [lastAppointment, setLastAppointment] = useState();
@@ -32,6 +35,18 @@ const Step5Content = (props: Step5ApplicationTypeAndApplicantDataProps) => {
fetchData();
}, []);
+ const onNextPress = () => {
+ onSubStepValidation(true);
+ setStep(6);
+ };
+
+ const onBackHomePress = () => {
+ navigation.reset({
+ index: 0,
+ routes: [{name: 'NavigationRoute'}],
+ });
+ };
+
return (
@@ -104,20 +119,17 @@ const Step5Content = (props: Step5ApplicationTypeAndApplicantDataProps) => {
setStep(6)}
+ onPress={onNextPress}
style={styles.subStepButtonContained}
textColor={Colors.neutral100.color}>
Lanjut
{
- setStep(4);
- setSubStep(2);
- }}
+ onPress={onBackHomePress}
style={styles.subStepButtonOutlined}
textColor={Colors.primary30.color}>
- Kembali
+ Beranda
@@ -137,4 +149,4 @@ const DetailRow = ({
);
-export default Step5Content;
+export default Step5ApplicationTypeAndApplicantData;
diff --git a/src/screens/regularPassport/steps/Step6ApplicationTypeAndApplicantData/Step6ApplicationTypeAndApplicantData.tsx b/src/screens/regularPassport/steps/Step6ApplicationTypeAndApplicantData/Step6ApplicationTypeAndApplicantData.tsx
index 30b8cff..678c25d 100644
--- a/src/screens/regularPassport/steps/Step6ApplicationTypeAndApplicantData/Step6ApplicationTypeAndApplicantData.tsx
+++ b/src/screens/regularPassport/steps/Step6ApplicationTypeAndApplicantData/Step6ApplicationTypeAndApplicantData.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {useState} from 'react';
import {ScrollView, View, Text} from 'react-native';
import {Button, Divider} from 'react-native-paper';
import TextInputComponent from '../../../../components/TextInput';
@@ -15,13 +15,16 @@ type Step6ApplicationTypeAndApplicantDataProps = {
showSelectDateSheet: () => void;
};
-const Step6ApplicationTypeAndApplicantData = (props: Step6ApplicationTypeAndApplicantDataProps) => {
+const Step6ApplicationTypeAndApplicantData = (
+ props: Step6ApplicationTypeAndApplicantDataProps,
+) => {
const {
showFinalizationConfirmationDialog,
showPassportTypeInfoDialog,
showSearchLocationSheet,
showSelectDateSheet,
} = props;
+
return (
diff --git a/src/screens/regularPassport/steps/Step7ApplicationFeeDetails/Step7ApplicationFeeDetails.tsx b/src/screens/regularPassport/steps/Step7ApplicationFeeDetails/Step7ApplicationFeeDetails.tsx
index b0e93e8..1ed39e4 100644
--- a/src/screens/regularPassport/steps/Step7ApplicationFeeDetails/Step7ApplicationFeeDetails.tsx
+++ b/src/screens/regularPassport/steps/Step7ApplicationFeeDetails/Step7ApplicationFeeDetails.tsx
@@ -12,10 +12,12 @@ import {getData} from '../../../../helper/asyncStorageHelper';
type Step7ApplicationFeeDetailsProps = {
showSubmitSuccessDialog: () => void;
setLastCompletedSteps: () => void;
+ onSubStepValidation: (isValid: boolean) => void;
};
const Step7ApplicationFeeDetails = (props: Step7ApplicationFeeDetailsProps) => {
- const {showSubmitSuccessDialog, setLastCompletedSteps} = props;
+ const {showSubmitSuccessDialog, setLastCompletedSteps, onSubStepValidation} =
+ props;
const [lastAppointment, setLastAppointment] = useState();
useEffect(() => {
@@ -32,6 +34,12 @@ const Step7ApplicationFeeDetails = (props: Step7ApplicationFeeDetailsProps) => {
fetchData();
}, []);
+ const onNextPress = () => {
+ onSubStepValidation(true);
+ showSubmitSuccessDialog();
+ setLastCompletedSteps();
+ };
+
return (
@@ -215,10 +223,7 @@ const Step7ApplicationFeeDetails = (props: Step7ApplicationFeeDetailsProps) => {
mode="contained"
style={styles.subStepButtonContained}
textColor={Colors.neutral100.color}
- onPress={() => {
- showSubmitSuccessDialog();
- setLastCompletedSteps();
- }}>
+ onPress={onNextPress}>
Kembali ke Halaman Utama
diff --git a/src/utils/stepNavigation.ts b/src/utils/stepNavigation.ts
new file mode 100644
index 0000000..0ba07fa
--- /dev/null
+++ b/src/utils/stepNavigation.ts
@@ -0,0 +1,53 @@
+import {RefObject} from 'react';
+export type StepStatus = 'completed' | 'incomplete' | 'invalid';
+
+interface StepChangeParams {
+ currentStep: number;
+ targetStep: number;
+ setStep: (step: number) => void;
+ setSubStep?: (sub: number) => void;
+ setStepValidationStatus: React.Dispatch<
+ React.SetStateAction>
+ >;
+ editedCompletedRef: RefObject>;
+}
+
+export function changeStep({
+ currentStep,
+ targetStep,
+ setStep,
+ setSubStep,
+ setStepValidationStatus,
+ editedCompletedRef,
+}: StepChangeParams) {
+ setStepValidationStatus(prev => {
+ const next = {...prev};
+
+ if (currentStep !== targetStep &&
+ editedCompletedRef.current?.has(currentStep)) {
+ next[currentStep] = 'completed';
+ editedCompletedRef.current.delete(currentStep);
+ }
+
+ if (prev[targetStep] === 'completed') {
+ editedCompletedRef.current?.add(targetStep);
+ }
+
+ next[targetStep] = 'incomplete';
+
+ if (targetStep > currentStep) {
+ for (let s = 1; s < targetStep; s++) {
+ if (next[s] !== 'completed') next[s] = 'invalid';
+ }
+ } else if (targetStep < currentStep) {
+ for (let s = currentStep; s > targetStep; s--) {
+ if (next[s] !== 'completed') next[s] = 'invalid';
+ }
+ }
+
+ return next;
+ });
+
+ setStep(targetStep);
+ if (setSubStep) setSubStep(1);
+}
diff --git a/types/step.ts b/types/step.ts
new file mode 100644
index 0000000..67a91ed
--- /dev/null
+++ b/types/step.ts
@@ -0,0 +1,7 @@
+export type StepStatus = 'incomplete' | 'completed' | 'invalid';
+
+export type StepValidationStatus = Record;
+
+export type StepValidationStatusSetter = React.Dispatch<
+ React.SetStateAction
+>;