Update step feature to allow users to jump to any step regardless of completion status

This commit is contained in:
Mochammad Adhi Buchori
2025-06-16 22:09:35 +07:00
parent e2b74911f2
commit 91e93d4c10
6 changed files with 325 additions and 58 deletions

View File

@ -10,12 +10,38 @@ import Colors from '../../../../../assets/styles/Colors';
type Step1VerifyNikSubStep3Props = {
setStep: (val: number) => void;
setSubStep: (val: number) => void;
onSubStepValidation: (isValid: boolean) => void;
};
const Step1VerifyNikSubStep3 = ({
setStep,
setSubStep,
onSubStepValidation,
}: 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 onNextPress = () => {
const isFormValid =
fullName.trim() !== '' &&
nik.trim() !== '' &&
birthDate.trim() !== '' &&
gender.trim() !== '' &&
civilStatus.trim() !== '';
if (isFormValid) {
onSubStepValidation(true);
} else {
onSubStepValidation(false);
}
setStep(2);
setSubStep(1);
};
return (
<ScrollView>
<View style={styles.subStepContainer}>
@ -28,11 +54,15 @@ const Step1VerifyNikSubStep3 = ({
title="Nama Lengkap Pemohon"
placeholder="Nama Lengkap Anda"
isRequired
value={fullName}
onChangeText={setFullName}
/>
<TextInputComponent
title="NIK"
placeholder="Nama NIK Anda"
isRequired
value={nik}
onChangeText={setNik}
/>
<View style={styles.subStepTextInputRowContainer}>
<View style={styles.subStepTextInputFlex}>
@ -41,6 +71,8 @@ const Step1VerifyNikSubStep3 = ({
placeholder="DD/MM/YYYY"
isRequired
isDate
value={birthDate}
onChangeText={setBirthDate}
/>
</View>
<View style={styles.subStepTextInputFlex}>
@ -50,6 +82,8 @@ const Step1VerifyNikSubStep3 = ({
isRequired
isDropdown
dropdownItemData={genderData}
value={gender}
onChangeText={setGender}
/>
</View>
</View>
@ -59,16 +93,15 @@ const Step1VerifyNikSubStep3 = ({
isRequired
isDropdown
dropdownItemData={civilStatusData}
value={civilStatus}
onChangeText={setCivilStatus}
/>
</View>
<View style={styles.subStepButtonContainer}>
<Button
mode="contained"
onPress={() => {
setStep(2);
setSubStep(1);
}}
onPress={onNextPress}
style={styles.subStepButtonContained}
textColor={Colors.neutral100.color}>
Lanjut

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, {useState} from 'react';
import {ScrollView, View, Text, Pressable} from 'react-native';
import {Button} from 'react-native-paper';
import styles from '../styles';
@ -14,6 +14,7 @@ type Step2PassportApplicationQuestionnaireSubStep11Props = {
setSubStep: (subStep: number) => void;
selectedOption: string;
setSelectedOption: (value: string) => void;
onSubStepValidation: (isValid: boolean) => void;
};
const Step2PassportApplicationQuestionnaireSubStep11 = ({
@ -21,7 +22,28 @@ const Step2PassportApplicationQuestionnaireSubStep11 = ({
setSubStep,
selectedOption,
setSelectedOption,
onSubStepValidation,
}: Step2PassportApplicationQuestionnaireSubStep11Props) => {
const [relativeName, setRelativeName] = useState('');
const [phoneNumber, setPhoneNumber] = useState('');
const [relationship, setRelationship] = useState('');
const onNextPress = () => {
const isFormValid =
relativeName.trim() !== '' &&
phoneNumber.trim() !== '' &&
relationship.trim() !== '' &&
selectedOption.trim() !== '';
if (isFormValid) {
onSubStepValidation(true);
} else {
onSubStepValidation(false);
}
setStep(3);
};
return (
<ScrollView>
<View style={styles.subStepContainer}>
@ -56,11 +78,15 @@ const Step2PassportApplicationQuestionnaireSubStep11 = ({
<TextInputComponent
title="Nama Kerabat"
placeholder="Masukkan Nama Kerabat Anda"
value={relativeName}
onChangeText={setRelativeName}
/>
<TextInputComponent
title="Nomor Telepon"
placeholder="Contoh: 08513456789"
value={phoneNumber}
onChangeText={setPhoneNumber}
/>
<TextInputComponent
@ -68,6 +94,8 @@ const Step2PassportApplicationQuestionnaireSubStep11 = ({
placeholder="Pilih Hubungan"
isDropdown
dropdownItemData={familyRelationshipData}
value={relationship}
onChangeText={setRelationship}
/>
{destinationFamilyContactOptions.map(options => (
@ -84,10 +112,7 @@ const Step2PassportApplicationQuestionnaireSubStep11 = ({
<Button
mode="contained"
onPress={() => {
setStep(3);
setSubStep(1);
}}
onPress={onNextPress}
style={styles.subStepButtonContained}
textColor={Colors.neutral100.color}>
Lanjut

View File

@ -17,6 +17,8 @@ interface DocumentUploadSectionProps {
isRequired?: boolean;
isIcon?: boolean;
showDialogCivilStatusDocumentsInfo?: () => void;
onUploadSuccess?: () => void;
onDelete?: () => void;
}
interface Step3UploadDocumentsProps {
@ -25,6 +27,7 @@ interface Step3UploadDocumentsProps {
selectedPassportOption: string;
selectedDestinationCountryOption: string;
showCivilStatusDocumentsInfoDialog: () => void;
onSubStepValidation: (isValid: boolean) => void;
}
const BackButton = (props: BackButtonProps) => {
@ -47,7 +50,15 @@ const BackButton = (props: BackButtonProps) => {
};
const DocumentUploadSection = (props: DocumentUploadSectionProps) => {
const {title, isRequired, isIcon, showDialogCivilStatusDocumentsInfo} = props;
const {
title,
isRequired,
isIcon,
showDialogCivilStatusDocumentsInfo,
onUploadSuccess,
onDelete,
} = props;
const [uploadedFileName, setUploadedFileName] = useState<string | null>(null);
const handleUpload = (p0: string) => {
@ -60,10 +71,12 @@ const DocumentUploadSection = (props: DocumentUploadSectionProps) => {
}
setUploadedFileName(fileName);
onUploadSuccess?.();
};
const handleDelete = () => {
setUploadedFileName(null);
onDelete?.();
};
return (
@ -141,7 +154,31 @@ const Step3UploadDocuments = (props: Step3UploadDocumentsProps) => {
selectedPassportOption,
selectedDestinationCountryOption,
showCivilStatusDocumentsInfoDialog,
onSubStepValidation,
} = props;
const [isKTPUploaded, setIsKTPUploaded] = useState(false);
const [isFamilyCardUploaded, setIsFamilyCardUploaded] = useState(false);
const [isCivilStatusUploaded, setIsCivilStatusUploaded] = useState(false);
const [isOldPassportUploaded, setIsOldPassportUploaded] = useState(false);
const onNextPress = () => {
const isFormValid =
isKTPUploaded &&
isFamilyCardUploaded &&
isCivilStatusUploaded &&
(selectedPassportOption !== 'already' || isOldPassportUploaded);
if (isFormValid) {
onSubStepValidation(true);
} else {
onSubStepValidation(false);
}
setStep(4);
setSubStep(1);
};
return (
<ScrollView>
<View style={styles.subStepContainer}>
@ -242,26 +279,39 @@ const Step3UploadDocuments = (props: Step3UploadDocumentsProps) => {
</View>
<View style={styles.subStepSectionButtonContainer}>
<DocumentUploadSection title="e-KTP" isRequired />
<DocumentUploadSection title="Kartu Keluarga" />
<DocumentUploadSection
title="e-KTP"
isRequired
onUploadSuccess={() => setIsKTPUploaded(true)}
onDelete={() => setIsKTPUploaded(false)}
/>
<DocumentUploadSection
title="Kartu Keluarga"
onUploadSuccess={() => setIsFamilyCardUploaded(true)}
onDelete={() => setIsFamilyCardUploaded(false)}
/>
<DocumentUploadSection
title="Akta kelahiran/ijazah/akta perkawinan/buku nikah/surat baptis"
isIcon
showDialogCivilStatusDocumentsInfo={
showCivilStatusDocumentsInfoDialog
}
onUploadSuccess={() => setIsCivilStatusUploaded(true)}
onDelete={() => setIsCivilStatusUploaded(false)}
/>
{selectedPassportOption === 'already' && (
<DocumentUploadSection title="Paspor Lama" isRequired />
<DocumentUploadSection
title="Paspor Lama"
isRequired
onUploadSuccess={() => setIsOldPassportUploaded(true)}
onDelete={() => setIsOldPassportUploaded(false)}
/>
)}
</View>
<Button
mode="contained"
onPress={() => {
setStep(4);
setSubStep(1);
}}
onPress={onNextPress}
style={styles.subStepButtonContained}
textColor={Colors.neutral100.color}>
Lanjut