From 5f513257d633e098c3bc1bdf86c5a665be857243 Mon Sep 17 00:00:00 2001 From: Mochammad Adhi Buchori Date: Wed, 23 Apr 2025 16:44:30 +0700 Subject: [PATCH] Add Eazy Passport screen and add passport application flow until step 5 'Verifikasi' --- src/components/StepIndicator.tsx | 2 +- src/components/TextInput.tsx | 22 +- .../dialog/DialogApplicationPassport.tsx | 79 + .../dialog/DialogDontHaveYetPassport.tsx | 84 + .../dialog/DialogLostOrDamagedPassport.tsx | 125 ++ src/components/dialog/DialogPassportInfo.tsx | 91 + .../DropdownData/DestinationCountryData.tsx | 14 + .../DropdownData/FamilyRelationshipData.tsx | 13 + src/screens/eazyPassport/index.tsx | 115 +- src/screens/eazyPassport/styles.tsx | 30 +- src/screens/regularPassport/index.tsx | 1460 +++++++++++++++-- src/screens/regularPassport/styles.tsx | 114 +- 12 files changed, 2006 insertions(+), 143 deletions(-) create mode 100644 src/components/dialog/DialogApplicationPassport.tsx create mode 100644 src/components/dialog/DialogDontHaveYetPassport.tsx create mode 100644 src/components/dialog/DialogLostOrDamagedPassport.tsx create mode 100644 src/components/dialog/DialogPassportInfo.tsx create mode 100644 src/data/DropdownData/DestinationCountryData.tsx create mode 100644 src/data/DropdownData/FamilyRelationshipData.tsx diff --git a/src/components/StepIndicator.tsx b/src/components/StepIndicator.tsx index b566469..d8ea4b4 100644 --- a/src/components/StepIndicator.tsx +++ b/src/components/StepIndicator.tsx @@ -24,7 +24,7 @@ const StepIndicator = ({currentStep, totalSteps, completedSteps}: any) => { const textStyle = isCompleted ? FontFamily.notoSansBold : isCurrent - ? FontFamily.notoSansRegular + ? FontFamily.notoSansSemiBold : FontFamily.notoSansRegular; return ( diff --git a/src/components/TextInput.tsx b/src/components/TextInput.tsx index bd8e359..d65d6d8 100644 --- a/src/components/TextInput.tsx +++ b/src/components/TextInput.tsx @@ -87,7 +87,7 @@ const TextInputComponent: React.FC = ({ )} = ({ onChange={item => { setGenderValue(item.value); }} + disable={isDisabled} renderRightIcon={() => } renderItem={renderDropdownItem} /> @@ -114,18 +115,19 @@ const TextInputComponent: React.FC = ({ {title && {title}} {isRequired && *} - setShowPicker(true)}> + !isDisabled && setShowPicker(true)}> } + right={} multiline={false} - textColor='#48454E' + textColor="#48454E" + disabled={isDisabled} /> {showPicker && ( @@ -151,7 +153,7 @@ const TextInputComponent: React.FC = ({ = ({ ) : null } multiline={isMultiline} - textColor='#48454E' + textColor="#48454E" /> {supportText && {supportText}} @@ -243,6 +245,12 @@ const styles = StyleSheet.create({ includeFontPadding: false, color: Colors.neutral70.color, }, + outlineColorDisabled: { + backgroundColor: '#F8F9FE', + borderWidth: 1, + borderRadius: 12, + borderColor: '#e3e3e5', + }, }); export default TextInputComponent; diff --git a/src/components/dialog/DialogApplicationPassport.tsx b/src/components/dialog/DialogApplicationPassport.tsx new file mode 100644 index 0000000..f47d6c7 --- /dev/null +++ b/src/components/dialog/DialogApplicationPassport.tsx @@ -0,0 +1,79 @@ +import React from 'react'; +import {View, Text, StyleSheet} from 'react-native'; +import {Portal, Dialog, Button} from 'react-native-paper'; +import Colors from '../../../assets/styles/Colors'; +import FontFamily from '../../../assets/styles/FontFamily'; + +type Props = { + visible: boolean; + onClose: () => void; + onContinue: () => void; +}; + +const DialogApplicationPassport = (props: Props) => { + const {visible, onClose, onContinue} = props; + return ( + + + Pemberitahuan + + + 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. + + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + 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, + }, + buttonAgree: { + backgroundColor: Colors.primary30.color, + marginTop: 12, + }, + buttonDontAgree: { + borderColor: Colors.primary30.color, + marginTop: 12, + }, +}); + +export default DialogApplicationPassport; diff --git a/src/components/dialog/DialogDontHaveYetPassport.tsx b/src/components/dialog/DialogDontHaveYetPassport.tsx new file mode 100644 index 0000000..99aa65d --- /dev/null +++ b/src/components/dialog/DialogDontHaveYetPassport.tsx @@ -0,0 +1,84 @@ +import {StyleSheet, Text, View} from 'react-native'; +import {Dialog, Portal, Button} from 'react-native-paper'; +import Colors from '../../../assets/styles/Colors'; +import FontFamily from '../../../assets/styles/FontFamily'; + +type Props = { + visible: boolean; + onClose: () => void; + onContinue: () => void; +}; + +const DialogDontHaveYetPassport = (props: Props) => { + const {visible, onClose, onContinue} = props; + + return ( + + + Peringatan + + + Apabila Anda sudah memiliki paspor atau sudah pernah mengajukan + permohonan paspor pada Kantor Imigrasi namun Anda memilih permohonan + paspor baru, maka data anda akan{' '} + tertolak oleh sistem dan{' '} + + pembayaran yang telah masuk kas negara tidak dapat dikembalikan. + + + + Silakan menghubungi hotline atau datang langsung ke Kantor Imigrasi + terdekat untuk informasi dan arahan lebih lanjut. + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + 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, + }, + dialogDescRed: { + ...FontFamily.notoSansBold, + color: Colors.indicatorRed.color, + includeFontPadding: false, + }, + buttonContinue: { + backgroundColor: Colors.primary30.color, + marginTop: 12, + }, +}); + +export default DialogDontHaveYetPassport; diff --git a/src/components/dialog/DialogLostOrDamagedPassport.tsx b/src/components/dialog/DialogLostOrDamagedPassport.tsx new file mode 100644 index 0000000..29d7cfb --- /dev/null +++ b/src/components/dialog/DialogLostOrDamagedPassport.tsx @@ -0,0 +1,125 @@ +import React from 'react'; +import {View, Text, StyleSheet} from 'react-native'; +import {Portal, Dialog, Button} from 'react-native-paper'; +import Colors from '../../../assets/styles/Colors'; +import FontFamily from '../../../assets/styles/FontFamily'; + +type Props = { + visible: boolean; + onBackToHome: () => void; + onBackToFirstStep: () => void; +}; + +const DialogLostOrDamagedPassport = (props: Props) => { + const {visible, onBackToHome, onBackToFirstStep} = props; + return ( + + + Pemberitahuan + + + Silakan langsung datang ke Kantor Imigrasi terdekat untuk melakukan + permohonan penggantian paspor hilang atau rusak dengan membawa + dokumen sebagai berikut: + + + + 1. Untuk Paspor Hilang + + + • e-КТР + • Kartu Keluarga + + + + Akta kelahiran/ijazah/akta perkawinan/buku nikah/surat baptis + + + + • Surat kehilangan dari Kepolisian + + + + + + 2. Untuk Paspor Rusak + + + • e-КТР + • Kartu Keluarga + + + + Akta kelahiran/ijazah/akta perkawinan/buku nikah/surat baptis + + + • Paspor lama + + + + Harap membawa semua dokumen asli dan fotokopi dalam kertas A4. + + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + 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, + }, + dialogBulletPointWrapper: { + marginStart: 8, + gap: 6, + marginTop: 8, + }, + dialogLongBulletPointWrapper: { + flexDirection: 'row', + gap: 6, + }, + buttonContained: { + backgroundColor: Colors.primary30.color, + marginTop: 12, + }, + buttonOutlined: { + borderColor: Colors.primary30.color, + marginTop: 12, + }, +}); + +export default DialogLostOrDamagedPassport; diff --git a/src/components/dialog/DialogPassportInfo.tsx b/src/components/dialog/DialogPassportInfo.tsx new file mode 100644 index 0000000..f64ee4e --- /dev/null +++ b/src/components/dialog/DialogPassportInfo.tsx @@ -0,0 +1,91 @@ +import {StyleSheet, Text, View} from 'react-native'; +import {Dialog, Portal, Button} from 'react-native-paper'; +import Colors from '../../../assets/styles/Colors'; +import FontFamily from '../../../assets/styles/FontFamily'; + +type Props = { + visible: boolean; + onClose: () => void; +}; + +const DialogPassportInfo = (props: Props) => { + const {visible, onClose} = props; + + return ( + + + + + Keterangan di dalamnya menjadi tidak jelas atau memberi kesan yang + tidak pantas lagi sebagai dokumen resmi (pasal 36 ayat (1) huruf + (d.2) Permenkumham RI no 8 tahun 2014 ttg Paspor Biasa dan SPLP) + + Informasi Keadaan Paspor: + + 1. Keadaan Baik + + + Paspor masih dalam keadaan baik atau sangat baik, tanpa ada + kerusakan apapun. + + + 2. Keadaan Rusak + + + Paspor ada kerusakan (contoh: tersobek, terbakar, dll) dan bagian + data diri tidak dapat terbaca. + + + 3. Hilang + + + Paspor hilang dan tidak dapat ditemukan karena suatu keadaan + (tertinggal, dicuri, dan lain-lain). + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + dialogContainer: { + backgroundColor: 'white', + elevation: 0, + shadowColor: 'transparent', + borderRadius: 20, + }, + dialogContentContainer: { + marginHorizontal: 24, + marginBottom: 24, + gap: 16, + }, + dialogDesc: { + fontSize: 14, + ...FontFamily.notoSansRegular, + includeFontPadding: false, + color: Colors.primary30.color, + }, + dialogDescRed: { + ...FontFamily.notoSansBold, + color: Colors.indicatorRed.color, + includeFontPadding: false, + }, + buttonContinue: { + backgroundColor: Colors.primary30.color, + marginTop: 12, + }, +}); + +export default DialogPassportInfo; diff --git a/src/data/DropdownData/DestinationCountryData.tsx b/src/data/DropdownData/DestinationCountryData.tsx new file mode 100644 index 0000000..99437b2 --- /dev/null +++ b/src/data/DropdownData/DestinationCountryData.tsx @@ -0,0 +1,14 @@ +const destinationCountryData = [ + {label: 'Japan', value: '1'}, + {label: 'South Korea', value: '2'}, + {label: 'Thailand', value: '3'}, + {label: 'Singapore', value: '4'}, + {label: 'Australia', value: '5'}, + {label: 'United States', value: '6'}, + {label: 'United Kingdom', value: '7'}, + {label: 'France', value: '8'}, + {label: 'Germany', value: '9'}, + {label: 'Canada', value: '10'}, +]; + +export default destinationCountryData; diff --git a/src/data/DropdownData/FamilyRelationshipData.tsx b/src/data/DropdownData/FamilyRelationshipData.tsx new file mode 100644 index 0000000..7059b95 --- /dev/null +++ b/src/data/DropdownData/FamilyRelationshipData.tsx @@ -0,0 +1,13 @@ +const familyRelationshipData = [ + {label: 'Suami/Istri', value: '1'}, + {label: 'Ayah', value: '2'}, + {label: 'Ibu', value: '3'}, + {label: 'Kakak/Adik', value: '4'}, + {label: 'Anak', value: '5'}, + {label: 'Tante', value: '6'}, + {label: 'Paman', value: '7'}, + {label: 'Saudara', value: '8'}, + {label: 'Keluarga/Kerabat Lainnya', value: '9'}, +]; + +export default familyRelationshipData; diff --git a/src/screens/eazyPassport/index.tsx b/src/screens/eazyPassport/index.tsx index e47e169..2ed38dd 100644 --- a/src/screens/eazyPassport/index.tsx +++ b/src/screens/eazyPassport/index.tsx @@ -1,12 +1,119 @@ import React from 'react'; -import {Text, View} from 'react-native'; +import {ScrollView, StatusBar, Text, View} from 'react-native'; import styles from './styles'; +import {RootStackParamList} from '../../navigation/type'; +import {NativeStackNavigationProp} from '@react-navigation/native-stack'; +import {useNavigation} from '@react-navigation/native'; +import Colors from '../../../assets/styles/Colors'; +import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; + +type EazyPassportScreenNavigationProp = NativeStackNavigationProp< + RootStackParamList, + 'EazyPassport' +>; function EazyPassportScreen() { + const navigation = useNavigation(); + return ( - - Eazy Passport Screen - + + + + + navigation.goBack()} + /> + Eazy Passport + + + + Layanan Eazy Passport yaitu pelayanan paspor yang dilaksanakan di + luar kantor dan menuju lokasi pemohon dengan menggunakan mobil + layanan paspor keliling dan/atau mobile unit Surat Perjalanan + Republik Indonesia (SPRI). + + + Ketentuan dan prosedur pemberian layanan paspor dalam pelaksanaan + Layanan Eazy Passport adalah sebagai berikut: + + + + 1. + + Layanan Eazy Passport melayani minimal 50 (lima puluh) + permohonan per hari; + + + + 2. + + Keluarga dari para pegawai di lingkungan Perkantoran Pemerintah/ + TNI /POLRI / BUMN/BUMD/Swasta dan institusi pendidikan dapat + diberikan pelayanan paspor dalam pelaksanaan Layanan Eazy + Passport; + + + + 3. + + Layanan Eazy Passport hanya melayani pembuatan paspor baru dan + penggantian paspor karena habis masa berlaku dan halaman penuh, + tidak melayani penggantian paspor karena hilang atau rusak; + + + + 4. + + Jadwal layanan ditentukan oleh Kantor Imigrasi setempat dan + dilayani di hari kerja (pukul 08.00 s/d 16.00 waktu setempat) + atau di luar jam/hari kerja; + + + + 5. + + Pelaksanaan input data dan pengambilan biometrik dilakukan + dengan mobile unit SPRI baik secara online atau offline; + + + + 6. + + Proses penyelesaian paspor 4 (empat) hari kerja setelah pemohon + melakukan pembayaran PNBP sesuai dengan jenis paspor yang + dipilih; + + + + 7. + + Pemohon Layanan Eazy Passport dapat diberikan layanan percepatan + paspor selesai pada hari yang sama dengan syarat pembayaran PNBP + dilakukan sebelum pukul 13.00 waktu setempat; + + + + 8. + + Pengambilan paspor yang sudah dicetak pada Kantor Imigrasi dapat + diambil langsung oleh pemohon paspor, diambil oleh perwakilan + instansi/kantor/komunitas sebagaimana tersebut pada angka 1 + dengan melampirkan surat kuasa/ surat perintah dari + pimpinan/para pemohon atau dikirim melalui jasa PT. Pos + Indonesia. + + + + + + ); } diff --git a/src/screens/eazyPassport/styles.tsx b/src/screens/eazyPassport/styles.tsx index 1f6a290..a1304cc 100644 --- a/src/screens/eazyPassport/styles.tsx +++ b/src/screens/eazyPassport/styles.tsx @@ -1,12 +1,36 @@ import {StyleSheet} from 'react-native'; +import FontFamily from '../../../assets/styles/FontFamily'; +import Colors from '../../../assets/styles/Colors'; const styles = StyleSheet.create({ container: { flex: 1, - alignContent: 'center', - alignItems: 'center', backgroundColor: 'white', - justifyContent: 'center', + }, + textContainer: { + gap: 8, + margin: 16 + }, + textDesc: { + ...FontFamily.notoSansRegular, + fontSize: 12, + includeFontPadding: false, + textAlign: 'justify', + }, + appBarTitle: { + color: Colors.neutral100.color, + ...FontFamily.notoSansRegular, + fontSize: 22, + marginStart: 16, + }, + appBarIcon: { + marginLeft: 16, + }, + appBarContainer: { + height: 64, + flexDirection: 'row', + alignItems: 'center', + backgroundColor: Colors.secondary30.color, }, }); diff --git a/src/screens/regularPassport/index.tsx b/src/screens/regularPassport/index.tsx index 23fee0d..d5e43db 100644 --- a/src/screens/regularPassport/index.tsx +++ b/src/screens/regularPassport/index.tsx @@ -14,11 +14,23 @@ 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 {Button, Checkbox, PaperProvider} 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'; +import DialogApplicationPassport from '../../components/dialog/DialogApplicationPassport'; +import DialogDontHaveYetPassport from '../../components/dialog/DialogDontHaveYetPassport'; +import DialogPassportInfo from '../../components/dialog/DialogPassportInfo'; +import DialogLostOrDamagedPassport from '../../components/dialog/DialogLostOrDamagedPassport'; +import destinationCountryData from '../../data/DropdownData/DestinationCountryData'; +import familyRelationshipData from '../../data/DropdownData/FamilyRelationshipData'; +import FontFamily from '../../../assets/styles/FontFamily'; +import provinceData from '../../data/DropdownData/ProvinceData'; +import cityData from '../../data/DropdownData/CityData'; +import districtData from '../../data/DropdownData/DistrictData'; +import postalCodeData from '../../data/DropdownData/PostalCodeData'; +import passportAppointmentData from '../../data/History/PassportAppointmentData'; type RegularPassportScreenNavigationProp = NativeStackNavigationProp< RootStackParamList, @@ -85,6 +97,88 @@ const previousPassportConditionOptions = [ }, ]; +const passportApplicationPurposeOptions = [ + { + label: 'Wisata', + description: 'null', + value: 'tourism', + }, + { + label: 'Umroh', + description: 'null', + value: 'umrah', + }, + { + label: 'Haji', + description: 'null', + value: 'hajj', + }, + { + label: 'Bekerja Formal', + description: 'null', + value: 'formal_work', + }, + { + label: 'Pekerja Imigran Indonesia (PMI)', + description: 'null', + value: 'indonesian_migrant_worker', + }, + { + label: 'Belajar', + description: 'null', + value: 'study', + }, + { + label: 'Berobat', + description: 'null', + value: 'medical', + }, +]; + +const destinationCountryOptions = [ + { + label: 'Saya belum memiliki negara tujuan', + description: 'null', + value: 'destination_country_not_set', + }, +]; + +const durationAbroadOptions = [ + { + label: '< 1 Bulan', + description: 'null', + value: 'less_than_1_month', + }, + { + label: '< 6 Bulan', + description: 'null', + value: 'less_than_6_months', + }, + { + label: '< 1 Tahun', + description: 'null', + value: 'less_than_1_year', + }, + { + label: '< 5 Tahun', + description: 'null', + value: 'less_than_5_years', + }, + { + label: '> 5 Tahun', + description: 'null', + value: 'more_than_5_years', + }, +]; + +const familyContactNumberInDestinationCountryOptions = [ + { + label: 'Saya tidak memiliki keluarga/kerabat di negara tujuan', + description: 'null', + value: 'no_family_in_destination_country', + }, +]; + const renderApplicationStepsContent = ( step: number, subStep: number, @@ -92,47 +186,99 @@ const renderApplicationStepsContent = ( setSubStep: (step: number) => void, selectedOption: string, setSelectedOption: (val: string) => void, + checkedOption: boolean, + setCheckedOption: React.Dispatch>, + showDontHaveYetDialog: () => void, + showPassportInfoDialog: () => void, + showLostOrDamagedPassportDialog: () => void, ) => { + const lastAppointment = + passportAppointmentData[passportAppointmentData.length - 1]; + if (step === 1) { switch (subStep) { case 1: return ( - - - - Ambil/Upload Foto KTP Anda - - - Pastikan pencahayaan cukup, tulisan pada identitas terlihat - jelas, dan jangan gunakan foto dari Live Mode sebelum - melanjutkan. - + + + + + Ambil/Upload Foto KTP Anda + + + Pastikan pencahayaan cukup, tulisan pada identitas terlihat + jelas, dan jangan gunakan foto dari Live Mode sebelum + melanjutkan. + + + + Foto KTP + + + + + + - - - - - - + ); case 2: return ( - - + + + Ambil/Upload Foto KTP Anda + + + Pastikan pencahayaan cukup, tulisan pada identitas terlihat + jelas, dan jangan gunakan foto dari Live Mode sebelum + melanjutkan. + + + + + + + + + + ); + case 3: + return ( + + + + @@ -180,14 +326,14 @@ const renderApplicationStepsContent = ( setStep(2); setSubStep(1); }} - style={styles.subStepButtonActive} + style={styles.subStepButtonContained} textColor={Colors.neutral100.color}> Lanjut @@ -208,7 +354,7 @@ const renderApplicationStepsContent = ( { setStep(1); - setSubStep(2); + setSubStep(3); }} style={({pressed}) => [ styles.subStepButtonBackWrapper, @@ -232,7 +378,9 @@ const renderApplicationStepsContent = ( selectedValue={selectedOption} onSelect={value => { setSelectedOption(value); - value === 'already' && setSubStep(2); + value === 'already' + ? setSubStep(2) + : showDontHaveYetDialog(); }} /> ))} @@ -258,8 +406,29 @@ const renderApplicationStepsContent = ( - Apakah Anda sudah pernah memiliki paspor? + Bagaimana kondisi paspor lama Anda? + showPassportInfoDialog()} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + }, + ]}> + + + Klik di sini untuk melihat informasi kondisi paspor + + {previousPassportConditionOptions.map(options => ( { setSelectedOption(value); - value === 'already' && setSubStep(2); }} /> ))} @@ -277,9 +445,16 @@ const renderApplicationStepsContent = ( @@ -288,50 +463,1051 @@ const renderApplicationStepsContent = ( ); case 3: return ( - - Step 2.3 - - - + + + { + setSubStep(2); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + marginBottom: 8, + }, + ]}> + + Kembali + + + + Ambil/Upload Foto Paspor Lama Anda (Halaman 2 Paspor) + + + Pastikan pencahayaan cukup, tulisan pada identitas terlihat + jelas, dan jangan gunakan foto dari Live Mode sebelum + melanjutkan. + + + + + Foto Halaman 2 Paspor Lama + + + + + + + + + + ); + case 4: + return ( + + + { + setSubStep(3); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + marginBottom: 8, + }, + ]}> + + Kembali + + + + Ambil/Upload Foto Paspor Lama Anda (Halaman 2 Paspor) + + + Pastikan pencahayaan cukup, tulisan pada identitas terlihat + jelas, dan jangan gunakan foto dari Live Mode sebelum + melanjutkan. + + + + + + + + + + ); + case 5: + return ( + + + { + setSubStep(4); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + }, + ]}> + + Kembali + + + + + + + + Nomor paspor lama minimal 7 karakter + + + + + + Tulis nomor paspor tanpa menggunakan spasi. Contoh: + B12345678 + + + + + + + + ); + case 6: + return ( + + + { + setSubStep(5); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + }, + ]}> + + Kembali + + + + Apakah tujuan Anda membuat paspor? + + {passportApplicationPurposeOptions.map(options => ( + { + setSelectedOption(value); + }} + /> + ))} + + + + + ); + case 7: + return ( + + + { + setSubStep(6); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + }, + ]}> + + Kembali + + + + {destinationCountryOptions.map(options => ( + { + setSelectedOption(value); + }} + /> + ))} + + + + + ); + case 8: + return ( + + + { + setSubStep(7); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + }, + ]}> + + Kembali + + + + + + + + ); + case 9: + return ( + + + { + setSubStep(8); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + }, + ]}> + + Kembali + + + + Berapa lama Anda berencana berada di luar negeri? + + {durationAbroadOptions.map(options => ( + setSelectedOption(value)} + /> + ))} + + + + + ); + case 10: + return ( + + + { + setSubStep(9); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + marginBottom: 8, + }, + ]}> + + Kembali + + + + Nomor telepon keluarga/kerabat terdekat Anda di Indonesia yang + dapat dihubungi + + + + + + + + + ); + case 11: + return ( + + + { + setSubStep(10); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + marginBottom: 8, + }, + ]}> + + Kembali + + + + + Nomor telepon keluarga/kerabat di negara tujuan + + + (Opsional) + + + + + + {familyContactNumberInDestinationCountryOptions.map(options => ( + { + setSelectedOption(value); + }} + /> + ))} + + + + ); default: return null; } } + if (step === 4) { + switch (subStep) { + case 1: + return ( + + + { + setStep(3); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + marginBottom: 8, + }, + ]}> + + Kembali + + + Data di bawah ini harus sesuai dengan keterangan pada KTP + pemohon. Data yang bertanda ( + *) wajib + diisi. + + + + Alamat sesuai KTP + + + + + + + + + + + + Alamat Sekarang (Domisili) + + + setCheckedOption(prev => !prev)} + /> + + Alamat sekarang sesuai KTP + + + + + + + + + + + + ); + case 2: + return ( + + + { + setStep(4); + setSubStep(1); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + marginBottom: 8, + }, + ]}> + + Kembali + + + Data di bawah ini harus sesuai dengan keterangan pada KTP + pemohon. Data yang bertanda ( + *) wajib + diisi. + + + + Keterangan Pemohon + + + + + + + Keterangan Ibu Pemohon + + + + + + + + Keterangan Ayah Pemohon (Opsional) + + + + + + + + Keterangan Pasangan Pemohon (Opsional) + + + + + + + + + ); + } + } switch (step) { case 3: return ( - - - - - ); - case 4: - return ( - - - - + + + { + setStep(2); + setSubStep(11); + }} + style={({pressed}) => [ + styles.subStepButtonBackWrapper, + { + transform: [{scale: pressed ? 0.99 : 1}], + marginBottom: 8, + }, + ]}> + + Kembali + + + + Layanan yang cocok untuk Anda adalah{' '} + + Paspor Penggantian + + . Silakan unggah kelengkapan dokumen berikut. + + + + + • + + + Unggah dokumen hanya bisa berbentuk JPG.{' '} + + + + + • + + + Data yang bertanda ( + *) + wajib diisi. + + + + + + + + + + + + + + + + + + + + e-KTP{' '} + * + + + + + + + + + Kartu Keluarga + + + + + + + + + + Akta kelahiran/ijazah/akta perkawinan/buku nikah/surat + baptis + + + + + + + + + + + Paspor Lama{' '} + * + + + + + + + + + + ); case 5: return ( - - - + + + Data pemohon berikut tidak akan terhapus dan sudah tersimpan di + beranda. Silakan lanjut untuk memilih jenis paspor, lokasi dan + jadwal pengambilan, serta pembayaran. + + + + + + Pemohon + + + {lastAppointment.applicantName} + + + + + + + + + + NIK + + {lastAppointment.applicationDetails.nationalIdNumber} + + + + + Jenis Kelamin + + + {lastAppointment.applicationDetails.gender} + + + + + Jenis Permohonan + + + {lastAppointment.applicationDetails.applicationType} + + + + + Alasan Penggantian + + + {lastAppointment.applicationDetails.replacementReason} + + + + + Tujuan Permohonan + + + {lastAppointment.applicationDetails.applicationPurpose} + + + + + Jenis Paspor + + + {lastAppointment.applicationDetails.passportType} + + + + + + + + ); case 6: @@ -357,14 +1533,38 @@ const renderApplicationStepsContent = ( function RegularPassportScreen() { const navigation = useNavigation(); const [selectedOption, setSelectedOption] = useState(''); - const [visible, setVisible] = useState(false); + const [checkedOption, setCheckedOption] = useState(false); + const [showApplicationStepsContent, setShowApplicationStepsContent] = useState(false); + const [step, setStep] = useState(1); const [subStep, setSubStep] = useState(1); + const [visible, setVisible] = useState(false); + const [visibleDontHaveYetDialog, setVisibleDontHaveYetDialog] = + useState(false); + const [visiblePassportInfoDialog, setVisiblePassportInfoDialog] = + useState(false); + const [ + visibleLostOrDamagedPassportDialog, + setVisibleLostOrDamagedPassportDialog, + ] = useState(false); + const showDialog = () => setVisible(true); const hideDialog = () => setVisible(false); + + const showDontHaveYetDialog = () => setVisibleDontHaveYetDialog(true); + const hideDontHaveYetDialog = () => setVisibleDontHaveYetDialog(false); + + const showPassportInfoDialog = () => setVisiblePassportInfoDialog(true); + const hidePassportInfoDialog = () => setVisiblePassportInfoDialog(false); + + const showVisibleLostOrDamagedPassportDialog = () => + setVisibleLostOrDamagedPassportDialog(true); + const hideVisibleLostOrDamagedPassportDialog = () => + setVisibleLostOrDamagedPassportDialog(false); + const completedSteps = [...Array(step - 1)].map((_, i) => i + 1); const stepTitles: {[key: number]: string} = { @@ -397,7 +1597,14 @@ function RegularPassportScreen() { @@ -411,22 +1618,56 @@ function RegularPassportScreen() { Pengajuan Paspor Regular {showApplicationStepsContent ? ( - - {stepTitles[step]} - - {renderApplicationStepsContent( - step, - subStep, - setStep, - setSubStep, - selectedOption, - setSelectedOption, + <> + + {stepTitles[step]} + + {renderApplicationStepsContent( + step, + subStep, + setStep, + setSubStep, + selectedOption, + setSelectedOption, + checkedOption, + setCheckedOption, + showDontHaveYetDialog, + showPassportInfoDialog, + showVisibleLostOrDamagedPassportDialog, + )} + + {visibleDontHaveYetDialog && ( + setSubStep(2)} + /> )} - + {visiblePassportInfoDialog && ( + + )} + {visibleLostOrDamagedPassportDialog && ( + { + navigation.goBack(); + }} + onBackToFirstStep={() => { + setShowApplicationStepsContent(false); + setStep(1); + setSubStep(1); + hideVisibleLostOrDamagedPassportDialog(); + }} + /> + )} + ) : ( <> @@ -452,39 +1693,14 @@ function RegularPassportScreen() { /> ))} - - - - Pemberitahuan - - - - 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. - - - - - - - - + { + hideDialog(); + setShowApplicationStepsContent(true); + }} + /> )} diff --git a/src/screens/regularPassport/styles.tsx b/src/screens/regularPassport/styles.tsx index fd4a2b1..0bd6019 100644 --- a/src/screens/regularPassport/styles.tsx +++ b/src/screens/regularPassport/styles.tsx @@ -45,6 +45,12 @@ const styles = StyleSheet.create({ color: Colors.primary30.color, includeFontPadding: false, }, + questionnaireDataSecondary: { + ...FontFamily.notoSansBold, + fontSize: 12, + color: Colors.secondary30.color, + includeFontPadding: false, + }, dialogContainer: { backgroundColor: 'white', elevation: 0, @@ -90,7 +96,9 @@ const styles = StyleSheet.create({ backgroundColor: Colors.neutral100.color, padding: 16, }, - nationalIdImage: { + documentImage: { + alignItems: 'center', + justifyContent: 'center', marginVertical: 16, height: 350, backgroundColor: Colors.primary70.color, @@ -99,10 +107,10 @@ const styles = StyleSheet.create({ subStepButtonContainer: { gap: 16, }, - subStepButtonActive: { + subStepButtonContained: { backgroundColor: Colors.primary30.color, }, - subStepButtonInActive: { + subStepButtonOutlined: { borderColor: Colors.primary30.color, }, subStepTextWrapper: { @@ -121,15 +129,15 @@ const styles = StyleSheet.create({ ...FontFamily.notoSansRegular, lineHeight: 20, }, - nationalIdImageContainer: { + documentImageContainer: { alignItems: 'center', }, - nationalIdImageCropped: { + documentImageCropped: { marginBottom: 16, width: 225, height: 140, backgroundColor: Colors.primary70.color, - borderRadius: 20, + borderRadius: 8, }, subStepTextInputContainer: { gap: 16, @@ -159,6 +167,100 @@ const styles = StyleSheet.create({ padding: 16, marginVertical: 16, gap: 16, + backgroundColor: Colors.neutral100.color, + }, + documentImageSupportText: { + ...FontFamily.notoSansRegular, + color: Colors.neutral100.color, + includeFontPadding: false, + fontSize: 14, + marginBottom: 10, + }, + textInputBulletTextWrapper: { + flexDirection: 'row', + gap: 6, + }, + textInputSupportText: { + fontSize: 10, + ...FontFamily.notoSansRegular, + color: '#8F9098', + }, + sectionButtonWrapper: { + flexDirection: 'row', + gap: 16, + }, + buttonContainedSecondary: { + flex: 1, + backgroundColor: Colors.secondary30.color, + }, + subStepSectionButtonContainer: { + marginBottom: 24, + gap: 16, + }, + subStepSectionButtonTextTitle: { + marginBottom: 8, + fontSize: 12, + includeFontPadding: false, + ...FontFamily.notoSansBold, + color: Colors.primary30.color, + flex: 1, + }, + subStepSectionButtonTextWrapper: { + flexDirection: 'row', + }, + subStepCheckWrapper: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, + }, + applicantDetailContentContainer: { + borderRadius: 16, + backgroundColor: Colors.neutral100.color, + borderWidth: 1, + borderColor: Colors.primary70.color, + marginVertical: 12, + padding: 16, + gap: 8, + }, + applicantDetailTextContentWrapper: { + flexDirection: 'row', + justifyContent: 'space-between', + gap: 8, + }, + applicantDetailTopContentWrapper: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + }, + applicantDetailIconContentWrapper: { + flexDirection: 'row', + gap: 16, + }, + applicantDetailTextTitle: { + fontSize: 12, + ...FontFamily.notoSansRegular, + includeFontPadding: false, + color: Colors.primary30.color, + flex: 1, + }, + applicantDetailTextDesc: { + fontSize: 12, + ...FontFamily.notoSansBold, + includeFontPadding: false, + color: Colors.primary30.color, + flex: 1.2, + }, + applicantDetailContentChildContainer: { + padding: 16, + borderWidth: 1, + marginVertical: 8, + borderColor: Colors.primary70.color, + borderRadius: 8, + gap: 12, + }, + applicantDetailBottomContentWrapper: { + flexDirection: 'row', + justifyContent: 'space-between', }, });