Refactor the Passport Application flow by separating each step into its own component up to step 3, and complete the UI for step 7

This commit is contained in:
Mochammad Adhi Buchori
2025-04-24 17:07:15 +07:00
parent 388a400b32
commit 2c0ea70fb3
34 changed files with 1504 additions and 856 deletions

View File

@ -0,0 +1,9 @@
const destinationCountryOptions = [
{
label: 'Saya belum memiliki negara tujuan',
description: 'null',
value: 'destination_country_not_set',
},
];
export default destinationCountryOptions;

View File

@ -0,0 +1,9 @@
const destinationFamilyContactOptions = [
{
label: 'Saya tidak memiliki keluarga/kerabat di negara tujuan',
description: 'null',
value: 'no_family_in_destination_country',
},
];
export default destinationFamilyContactOptions;

View File

@ -0,0 +1,29 @@
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',
},
];
export default durationAbroadOptions;

View File

@ -0,0 +1,15 @@
const hasHadPassportBeforeOptions = [
{
label: 'Belum',
description:
'Belum pernah memiliki paspor atau belum pernah mengajukan permohonan paspor',
value: 'not_yet',
},
{
label: 'Sudah',
description: '',
value: 'already',
},
];
export default hasHadPassportBeforeOptions;

View File

@ -0,0 +1,39 @@
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',
},
];
export default passportApplicationPurposeOptions;

View File

@ -0,0 +1,14 @@
const passportForOptions = [
{
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',
},
];
export default passportForOptions;

View File

@ -0,0 +1,34 @@
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',
},
];
export default previousPassportConditionOptions;

View File

@ -0,0 +1,7 @@
const arrivalDateGuidelinesData = [
'Pastikan kehadiran Anda pada tanggal yang dipilih',
'Anda dapat melakukan ubah jadwal sebanyak 1 kali paling lambat 1 hari sebelum tanggal kedatangan',
'Apabila Anda tidak hadir pada tanggal kedatangan dan tidak melakukan ubah jadwal, permohonan Anda dinyatakan batal dan pembayaran tidak dapat dikembalikan',
];
export default arrivalDateGuidelinesData;

View File

@ -0,0 +1,38 @@
const termsAndConditionsData = [
{
id: 1,
text: 'Pemohon wajib hadir 15 menit sebelum jam kedatangan dimulai;',
},
{
id: 2,
text: 'Membawa dokumen persyaratan permohonan paspor asli sesuai tujuan permohonan paspor;',
},
{
id: 3,
text: 'Permohonan penggantian paspor wajib membawa paspor lama;',
},
{
id: 4,
text: 'Apabila anda tidak hadir sesuai jadwal kedatangan dan tidak melakukan ubah jadwal, maka permohonan paspor anda dibatalkan dan harus melakukan pendaftaran ulang',
},
{
id: 5,
text: 'Permohonan paspor dapat ditolak dalam hal:',
subItems: [
'Termasuk dalam daftar pencegahan dan penangkalan;',
'Terindikasi Pekerja Migran Indonesia (PMI) Non Prosedural;',
'Memberikan data tidak sah dan/atau keterangan tidak benar;',
'Hal lain yang dianggap oleh petugas akan dipergunakan untuk tujuan melawan hukum;',
],
},
{
id: 6,
text: 'Apabila terdapat kesalahan dari pihak pemohon paspor sebagaimana ketentuan di atas, pembayaran yang telah disetorkan pada Kas Negara tidak dapat dikembalikan;',
},
{
id: 7,
text: 'Dengan membaca dan menyetujui persyaratan dan ketentuan ini, pemohon telah siap dan mematuhi segala konsekuensi yang berakibat secara hukum.',
},
];
export default termsAndConditionsData;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,187 @@
import React from 'react';
import {ScrollView, View, Text, Pressable} from 'react-native';
import styles from '../styles';
import Colors from '../../../../../assets/styles/Colors';
import FontFamily from '../../../../../assets/styles/FontFamily';
import genderData from '../../../../data/DropdownData/GenderData';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import {Button} from 'react-native-paper';
import TextInputComponent from '../../../../components/TextInput';
interface BackButtonProps {
onPress: () => void;
}
interface DocumentUploadSectionProps {
title: string;
isRequired?: boolean;
}
interface Step3PaymentProps {
setStep: (step: number) => void;
setSubStep: (subStep: number) => void;
}
const BackButton = (props: BackButtonProps) => {
const {onPress} = props;
return (
<Pressable
onPress={onPress}
style={({pressed}) => [
styles.subStepButtonBackWrapper,
{
transform: [{scale: pressed ? 0.99 : 1}],
marginBottom: 8,
},
]}>
<Icon name="chevron-left" size={24} />
<Text style={styles.subStepButtonBackText}>Kembali</Text>
</Pressable>
);
};
const DocumentUploadSection = (props: DocumentUploadSectionProps) => {
const {title, isRequired = false} = props;
return (
<View>
<Text style={styles.subStepSectionButtonTextTitle}>
{title}{' '}
{isRequired && (
<Text style={{color: Colors.indicatorRed.color}}>*</Text>
)}
</Text>
<View style={styles.sectionButtonWrapper}>
<Button
icon="camera-outline"
mode="contained"
style={styles.buttonContainedSecondary}
textColor={Colors.neutral100.color}
labelStyle={{fontSize: 12}}>
Foto Dokumen
</Button>
<Button
icon="tray-arrow-up"
mode="contained"
style={styles.buttonContainedSecondary}
textColor={Colors.neutral100.color}
labelStyle={{fontSize: 12}}>
Unggah Dokumen
</Button>
</View>
</View>
);
};
const Step3Payment = (props: Step3PaymentProps) => {
const {setStep, setSubStep} = props;
return (
<ScrollView>
<View style={styles.subStepContainer}>
<BackButton
onPress={() => {
setStep(2);
setSubStep(11);
}}
/>
<View style={{marginBottom: 16, gap: 4}}>
<Text style={styles.subStepDesc}>
Layanan yang cocok untuk Anda adalah{' '}
<Text style={{...FontFamily.notoSansBold}}>Paspor Penggantian</Text>
. Silakan unggah kelengkapan dokumen berikut.
</Text>
<View>
<View style={styles.textInputBulletTextWrapper}>
<Text
style={[
styles.subStepDesc,
{fontSize: 10, ...FontFamily.notoSansBold},
]}>
</Text>
<Text
style={[
styles.subStepDesc,
{fontSize: 10, ...FontFamily.notoSansBold},
]}>
Unggah dokumen hanya bisa berbentuk JPG.
</Text>
</View>
<View style={styles.textInputBulletTextWrapper}>
<Text
style={[
styles.subStepDesc,
{fontSize: 10, ...FontFamily.notoSansBold},
]}>
</Text>
<Text
style={[
styles.subStepDesc,
{fontSize: 10, ...FontFamily.notoSansBold},
]}>
Data yang bertanda (
<Text style={{color: Colors.indicatorRed.color}}>*</Text>) wajib
diisi.
</Text>
</View>
</View>
</View>
<View style={{marginBottom: 16, gap: 16}}>
<TextInputComponent
title="Nama Pemohon"
placeholder="Salwa Aisyah Adhani"
isRequired
isDisabled
/>
<TextInputComponent
title="Tempat Lahir"
placeholder="Masukkan tempat lahir Anda"
isRequired
/>
<View style={styles.subStepTextInputRowContainer}>
<View style={styles.subStepTextInputFlex}>
<TextInputComponent
title="Tanggal Lahir"
placeholder="22/02/2002"
isRequired
isDate
isDisabled
/>
</View>
<View style={styles.subStepTextInputFlex}>
<TextInputComponent
title="Jenis Kelamin"
placeholder="Wanita"
isRequired
isDropdown
isDisabled
dropdownItemData={genderData}
/>
</View>
</View>
</View>
<View style={styles.subStepSectionButtonContainer}>
<DocumentUploadSection title="e-KTP" isRequired />
<DocumentUploadSection title="Kartu Keluarga" />
<DocumentUploadSection title="Akta kelahiran/ijazah/akta perkawinan/buku nikah/surat baptis" />
<DocumentUploadSection title="Paspor Lama" isRequired />
</View>
<Button
mode="contained"
onPress={() => {
setStep(4), setSubStep(1);
}}
style={styles.subStepButtonContained}
textColor={Colors.neutral100.color}>
Lanjut
</Button>
</View>
</ScrollView>
);
};
export default Step3Payment;

View File

@ -0,0 +1,165 @@
import React from 'react';
import {ScrollView, View, Pressable, Text} from 'react-native';
import {Checkbox, Button} from 'react-native-paper';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Colors from '../../../../../assets/styles/Colors';
import styles from '../styles';
import TextInputComponent from '../../../../components/TextInput';
import postalCodeData from '../../../../data/DropdownData/PostalCodeData';
import districtData from '../../../../data/DropdownData/DistrictData';
import cityData from '../../../../data/DropdownData/CityData';
import provinceData from '../../../../data/DropdownData/ProvinceData';
type Step4DataConfirmationSubStep1Props = {
setStep: (step: number) => void;
setSubStep: (subStep: number) => void;
checkedOption: boolean;
setCheckedOption: React.Dispatch<React.SetStateAction<boolean>>;
};
const Step4DataConfirmationSubStep1: React.FC<
Step4DataConfirmationSubStep1Props
> = ({setStep, setSubStep, checkedOption, setCheckedOption}) => {
return (
<ScrollView>
<View style={styles.subStepContainer}>
<Pressable
onPress={() => {
setStep(3);
}}
style={({pressed}) => [
styles.subStepButtonBackWrapper,
{transform: [{scale: pressed ? 0.99 : 1}], marginBottom: 8},
]}>
<Icon name="chevron-left" size={24} />
<Text style={styles.subStepButtonBackText}>Kembali</Text>
</Pressable>
<Text style={styles.subStepDesc}>
Data di bawah ini harus sesuai dengan keterangan pada KTP pemohon.
Data yang bertanda (
<Text style={{color: Colors.indicatorRed.color}}>*</Text>) wajib
diisi.
</Text>
<View
style={[
styles.subStepQuestionnaireOptionContainer,
{marginBottom: 0},
]}>
<Text style={styles.questionnaireDataSecondary}>
Alamat sesuai KTP
</Text>
<TextInputComponent
title="Tanggal Dikeluarkan KTP"
placeholder="DD/MM/YYYY"
isRequired
isDate
/>
<TextInputComponent
title="Kewarganegaraan"
placeholder="Indonesia"
isRequired
isDisabled
/>
<TextInputComponent
title="Alamat Sesuai KTP"
placeholder="Masukkan alamat sesuai KTP"
isRequired
supportText="0/100 karakter"
containerHeight={90}
isMultiline
/>
<TextInputComponent
title="Provinsi Sesuai KTP"
placeholder="Cari Provinsi"
isDropdown
dropdownItemData={provinceData}
/>
<TextInputComponent
title="Kabupaten/Kota Sesuai KTP"
placeholder="Cari Kabupaten/Kota"
isDropdown
dropdownItemData={cityData}
/>
<TextInputComponent
title="Kecamatan Sesuai KTP"
placeholder="Cari Kecamatan"
isDropdown
dropdownItemData={districtData}
/>
<TextInputComponent
title="Kode Pos Sesuai KTP"
placeholder="Cari Kode Pos"
isDropdown
dropdownItemData={postalCodeData}
/>
</View>
<View
style={[
styles.subStepQuestionnaireOptionContainer,
{marginBottom: 32},
]}>
<Text style={styles.questionnaireDataSecondary}>
Alamat Sekarang (Domisili)
</Text>
<View style={styles.subStepCheckWrapper}>
<Checkbox
status={checkedOption ? 'checked' : 'unchecked'}
color={Colors.secondary20.color}
uncheckedColor={Colors.secondary20.color}
onPress={() => setCheckedOption(prev => !prev)}
/>
<Text style={styles.subStepDesc}>Alamat sekarang sesuai KTP</Text>
</View>
<TextInputComponent
title="Alamat Sesuai Domisili"
placeholder="Masukkan alamat sesuai Domisili"
isRequired
supportText="0/100 karakter"
containerHeight={90}
isMultiline
/>
<TextInputComponent
title="Provinsi Sesuai Domisili"
placeholder="Cari Provinsi"
isDropdown
dropdownItemData={provinceData}
/>
<TextInputComponent
title="Kabupaten/Kota Sesuai Domisili"
placeholder="Cari Kabupaten/Kota"
isDropdown
dropdownItemData={cityData}
/>
<TextInputComponent
title="Kecamatan Sesuai Domisili"
placeholder="Cari Kecamatan"
isDropdown
dropdownItemData={districtData}
/>
<TextInputComponent
title="Kode Pos Sesuai Domisili"
placeholder="Cari Kode Pos"
isDropdown
dropdownItemData={postalCodeData}
/>
</View>
<Button
mode="contained"
onPress={() => {
setStep(4);
setSubStep(2);
}}
style={[styles.subStepButtonContained, {marginBottom: 8}]}
textColor={Colors.neutral100.color}>
Lanjut
</Button>
</View>
</ScrollView>
);
};
export default Step4DataConfirmationSubStep1;

View File

@ -0,0 +1,99 @@
import React from 'react';
import { ScrollView, View, Text, Pressable } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import styles from '../styles';
import TextInputComponent from '../../../../components/TextInput';
import { Button } from 'react-native-paper';
import Colors from '../../../../../assets/styles/Colors';
const Step4DataConfirmationSubStep2 = ({
setStep,
setSubStep,
}: {
setStep: (step: number) => void;
setSubStep: (subStep: number) => void;
}) => {
return (
<ScrollView>
<View style={styles.subStepContainer}>
<Pressable
onPress={() => {
setStep(4);
setSubStep(1);
}}
style={({ pressed }) => [
styles.subStepButtonBackWrapper,
{
transform: [{ scale: pressed ? 0.99 : 1 }],
marginBottom: 8,
},
]}
>
<Icon name="chevron-left" size={24} />
<Text style={styles.subStepButtonBackText}>Kembali</Text>
</Pressable>
<Text style={styles.subStepDesc}>
Data di bawah ini harus sesuai dengan keterangan pada KTP pemohon. Data yang bertanda (
<Text style={{ color: Colors.indicatorRed.color }}>*</Text>) wajib diisi.
</Text>
<View style={[styles.subStepQuestionnaireOptionContainer, { marginBottom: 0 }]}>
<Text style={styles.questionnaireDataSecondary}>Keterangan Pemohon</Text>
<TextInputComponent title="Pekerjaan" placeholder="Pilih pekerjaan" isRequired isDropdown />
<TextInputComponent title="Nomor Telepon" placeholder="Contoh: 08513456789" isRequired />
</View>
<View style={[styles.subStepQuestionnaireOptionContainer, { marginBottom: 0 }]}>
<Text style={styles.questionnaireDataSecondary}>Keterangan Ibu Pemohon</Text>
<TextInputComponent title="Nama Ibu" placeholder="Masukkan nama lengkap ibu" isRequired />
<TextInputComponent title="Kewarganegaraan Ibu" placeholder="Pilih kewarganegaraan ibu" isRequired isDropdown />
<TextInputComponent
title="Alamat Ibu"
placeholder="Masukkan alamat ibu"
isRequired
supportText="0/100 karakter"
containerHeight={90}
isMultiline
/>
</View>
<View style={[styles.subStepQuestionnaireOptionContainer, { marginBottom: 0 }]}>
<Text style={styles.questionnaireDataSecondary}>Keterangan Ayah Pemohon (Opsional)</Text>
<TextInputComponent title="Nama Ayah" placeholder="Masukkan nama lengkap ayah" />
<TextInputComponent title="Kewarganegaraan Ayah" placeholder="Pilih kewarganegaraan ayah" isDropdown />
<TextInputComponent
title="Alamat Ayah"
placeholder="Masukkan alamat ayah"
supportText="0/100 karakter"
containerHeight={90}
isMultiline
/>
</View>
<View style={[styles.subStepQuestionnaireOptionContainer, { marginBottom: 32 }]}>
<Text style={styles.questionnaireDataSecondary}>Keterangan Pasangan Pemohon (Opsional)</Text>
<TextInputComponent title="Nama Pasangan" placeholder="Masukkan nama lengkap pasangan" />
<TextInputComponent title="Kewarganegaraan Pasangan" placeholder="Pilih kewarganegaraan pasangan" isDropdown />
<TextInputComponent
title="Alamat Pasangan"
placeholder="Masukkan alamat pasangan"
supportText="0/100 karakter"
containerHeight={90}
isMultiline
/>
</View>
<Button
mode="contained"
onPress={() => setStep(5)}
style={[styles.subStepButtonContained, { marginBottom: 8 }]}
textColor={Colors.neutral100.color}
>
Simpan Draft
</Button>
</View>
</ScrollView>
);
};
export default Step4DataConfirmationSubStep2;

View File

@ -0,0 +1,113 @@
import React from 'react';
import {View, Text} from 'react-native';
import {Button} from 'react-native-paper';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import Colors from '../../../../../assets/styles/Colors';
import styles from '../styles';
type Step5VerificationProps = {
setStep: (step: number) => void;
setSubStep: (subStep: number) => void;
passportAppointmentData: any[];
};
const Step5Content = ({
setStep,
setSubStep,
passportAppointmentData,
}: Step5VerificationProps) => {
const lastAppointment =
passportAppointmentData[passportAppointmentData.length - 1];
return (
<View style={styles.subStepContainer}>
<Text style={styles.subStepDesc}>
Data pemohon berikut tidak akan terhapus dan sudah tersimpan di beranda.
Silakan lanjut untuk memilih jenis paspor, lokasi dan jadwal
pengambilan, serta pembayaran.
</Text>
<View style={styles.applicantDetailContentContainer}>
<View style={styles.applicantDetailTopContentWrapper}>
<View style={{gap: 4}}>
<Text style={[styles.applicantDetailTextTitle, {flex: 0}]}>
Pemohon
</Text>
<Text
style={[
styles.applicantDetailTextDesc,
{textTransform: 'uppercase', flex: 0},
]}>
{lastAppointment.applicantName}
</Text>
</View>
<View style={styles.applicantDetailIconContentWrapper}>
<Icon
name="trash-can-outline"
size={24}
color={Colors.indicatorRed.color}
/>
<Icon
name="square-edit-outline"
size={24}
color={Colors.primary30.color}
/>
</View>
</View>
<View style={styles.applicantDetailContentChildContainer}>
<DetailRow
label="NIK"
value={lastAppointment.applicationDetails.nationalIdNumber}
/>
<DetailRow
label="Jenis Kelamin"
value={lastAppointment.applicationDetails.gender}
/>
<DetailRow
label="Jenis Permohonan"
value={lastAppointment.applicationDetails.applicationType}
/>
<DetailRow
label="Alasan Penggantian"
value={lastAppointment.applicationDetails.replacementReason}
/>
<DetailRow
label="Tujuan Permohonan"
value={lastAppointment.applicationDetails.applicationPurpose}
/>
<DetailRow
label="Jenis Paspor"
value={lastAppointment.applicationDetails.passportType}
/>
</View>
</View>
<View style={[styles.subStepButtonContainer, {marginTop: 12}]}>
<Button
mode="contained"
onPress={() => setStep(6)}
style={styles.subStepButtonContained}
textColor={Colors.neutral100.color}>
Lanjut
</Button>
<Button
mode="outlined"
onPress={() => {
setStep(4);
setSubStep(2);
}}
style={styles.subStepButtonOutlined}
textColor={Colors.primary30.color}>
Kembali
</Button>
</View>
</View>
);
};
const DetailRow = ({label, value}: {label: string; value: string}) => (
<View style={styles.applicantDetailTextContentWrapper}>
<Text style={styles.applicantDetailTextTitle}>{label}</Text>
<Text style={styles.applicantDetailTextDesc}>{value}</Text>
</View>
);
export default Step5Content;

View File

@ -0,0 +1,99 @@
import React from 'react';
import {ScrollView, View, Text} from 'react-native';
import {Button, Divider} from 'react-native-paper';
import TextInputComponent from '../../../../components/TextInput';
import styles from '../styles';
import Colors from '../../../../../assets/styles/Colors';
import FontFamily from '../../../../../assets/styles/FontFamily';
type Step6ProcessingProps = {
setStep: (step: number) => void;
arrivalDateGuidelines: string[];
};
const Step6Processing = ({
setStep,
arrivalDateGuidelines,
}: Step6ProcessingProps) => {
return (
<ScrollView>
<View style={styles.subStepContainer}>
<View style={styles.subStepTextWrapper}>
<Text style={styles.subStepTitle}>
Pilih Lokasi Pengambilan dan Jenis Paspor
</Text>
<Text style={styles.subStepDesc}>
Anda dapat membuat paspor di kantor imigrasi manapun di seluruh
Indonesia. Silakan pilih lokasi permohonan paspor.
</Text>
</View>
<View style={[styles.subStepTextInputContainer, {marginVertical: 16}]}>
<TextInputComponent
title="Lokasi Kantor Imigrasi"
placeholder="Pilih lokasi kantor imigrasi"
isRequired
isDropdown
/>
{/* TODO: Add button information */}
<TextInputComponent
title="Jenis Paspor"
placeholder="Pilih satu jenis paspor"
isRequired
isDropdown
/>
</View>
<Divider />
<View style={[styles.subStepTextInputContainer, {marginVertical: 16}]}>
<View style={styles.subStepTextWrapper}>
<Text style={styles.subStepTitle}>
Pilih Tanggal dan Waktu Kedatangan
</Text>
<Text style={styles.subStepDesc}>
Setiap lokasi kantor imigrasi memiliki ketersediaan kuota yang
berbeda. Silakan pilih tanggal dan waktu kedatangan.
</Text>
</View>
<View>
{arrivalDateGuidelines.map((item, index) => (
<View key={index} style={styles.subStepListTextRowContainer}>
<Text style={[styles.subStepDesc, FontFamily.notoSansBold]}>
</Text>
<Text
style={[
styles.subStepDesc,
styles.subStepListTextFlex,
FontFamily.notoSansBold,
]}>
{item}
</Text>
</View>
))}
</View>
</View>
{/* TODO: Add calendar functionality here. */}
<TextInputComponent
title="Tanggal dan Waktu Kedatangan"
placeholder="Pilih tanggal dan waktu kedatangan"
isRequired
isDate
/>
<Button
mode="contained"
style={[styles.subStepButtonContained, {marginTop: 24}]}
textColor={Colors.neutral100.color}
onPress={() => setStep(7)}>
Lanjut
</Button>
</View>
</ScrollView>
);
};
export default Step6Processing;

View File

@ -0,0 +1,203 @@
import React from 'react';
import {ScrollView, View} from 'react-native';
import {Button, Divider, Text} from 'react-native-paper';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import Colors from '../../../../../assets/styles/Colors';
import styles from '../styles';
import passportAppointmentData from '../../../../data/History/PassportAppointmentData';
import Accordion from '../../../../components/Accordion';
import termsAndConditionsData from '../../../../data/Steps/TermsAndContionsData';
type Step7CompletionProps = {
setStep: (step: number) => void;
};
const Step7Completion = ({setStep}: Step7CompletionProps) => {
const lastAppointment =
passportAppointmentData[passportAppointmentData.length - 1];
return (
<ScrollView>
<View style={[styles.subStepContainer, {paddingBottom: 0}]}>
<View style={styles.midContainer}>
<Text style={styles.midTextTitle}>Jadwal Kedatangan</Text>
<View style={styles.midIconContainer}>
<View style={styles.midIconContentWrapper}>
<Icon
name="calendar-today"
size={24}
color={Colors.secondary30.color}
/>
<Text style={styles.midIconContentTextStyle}>
{lastAppointment.appointmentDate}
</Text>
</View>
<View style={styles.midIconContentWrapper}>
<Icon
name="clock-outline"
size={24}
color={Colors.secondary30.color}
/>
<Text style={styles.midIconContentTextStyle}>
{lastAppointment.appointmentTime}
</Text>
</View>
<View style={styles.midIconContentWrapper}>
<Icon
name="map-marker-outline"
size={24}
color={Colors.secondary30.color}
/>
<Text style={styles.midIconContentTextStyle}>
{lastAppointment.serviceUnit}
</Text>
</View>
</View>
<Divider />
<View style={styles.midTextContentContainer}>
<View style={styles.midTextContentWrapper}>
<Text style={styles.midTextContentTitle}>Tanggal Pengajuan</Text>
<Text style={styles.midTextContentData}>
{lastAppointment.submissionDate}
</Text>
</View>
<View style={styles.midTextContentWrapper}>
<Text style={styles.midTextContentTitle}>Kode Layanan</Text>
<Text style={styles.midTextContentData}>
{lastAppointment.serviceCode}
</Text>
</View>
</View>
<Divider />
</View>
<View style={styles.accordionContainer}>
<Accordion title={'Persyaratan dan Ketentuan'}>
<View style={styles.accordionOptionDataWrapper}>
{termsAndConditionsData.map((item, index) => (
<View key={index}>
<View style={styles.accordionTextContentWrapper}>
<Text
style={[
styles.accordionTextContentDesc,
styles.accordionListFlex,
]}>
{item.id}.
</Text>
<Text style={styles.accordionTextContentDesc}>
{item.text}
</Text>
</View>
{item.subItems && (
<View style={styles.accordionTextContentAlphabetWrapper}>
{item.subItems.map((sub, subIndex) => (
<View
key={subIndex}
style={styles.accordionTextContentWrapper}>
<Text
style={[
styles.accordionTextContentDesc,
styles.accordionListFlex,
]}>
{String.fromCharCode(97 + subIndex)}.
</Text>
<Text style={styles.accordionTextContentDesc}>
{sub}
</Text>
</View>
))}
</View>
)}
</View>
))}
</View>
</Accordion>
</View>
</View>
<View
style={{
backgroundColor: Colors.secondary70.color,
padding: 16,
borderRadius: 0,
borderWidth: 0,
}}>
<View style={styles.applicantDetailContentContainer}>
<View style={styles.applicantDetailTextContentWrapper}>
<Text style={styles.applicantDetailTextTitle}>Pemohon</Text>
<Text
style={[
styles.applicantDetailTextDesc,
styles.applicantDetailTexDescName,
]}>
{lastAppointment.applicantName}
</Text>
</View>
<View style={styles.applicantDetailTextContentWrapper}>
<Text style={styles.applicantDetailTextTitle}>Kode Permohonan</Text>
<Text
style={[
styles.applicantDetailTextDesc,
styles.applicantDetailTexDescCode,
]}>
{lastAppointment.applicantCode}
</Text>
</View>
<View style={styles.applicantDetailContentChildContainer}>
<View style={styles.applicantDetailTextContentWrapper}>
<Text style={styles.applicantDetailTextTitle}>NIK</Text>
<Text style={styles.applicantDetailTextDesc}>
{lastAppointment.applicationDetails.nationalIdNumber}
</Text>
</View>
<View style={styles.applicantDetailTextContentWrapper}>
<Text style={styles.applicantDetailTextTitle}>Jenis Kelamin</Text>
<Text style={styles.applicantDetailTextDesc}>
{lastAppointment.applicationDetails.gender}
</Text>
</View>
<View style={styles.applicantDetailTextContentWrapper}>
<Text style={styles.applicantDetailTextTitle}>
Jenis Permohonan
</Text>
<Text style={styles.applicantDetailTextDesc}>
{lastAppointment.applicationDetails.applicationType}
</Text>
</View>
<View style={styles.applicantDetailTextContentWrapper}>
<Text style={styles.applicantDetailTextTitle}>
Alasan Penggantian
</Text>
<Text style={styles.applicantDetailTextDesc}>
{lastAppointment.applicationDetails.replacementReason}
</Text>
</View>
<View style={styles.applicantDetailTextContentWrapper}>
<Text style={styles.applicantDetailTextTitle}>
Tujuan Permohonan
</Text>
<Text style={styles.applicantDetailTextDesc}>
{lastAppointment.applicationDetails.applicationPurpose}
</Text>
</View>
<View style={styles.applicantDetailTextContentWrapper}>
<Text style={styles.applicantDetailTextTitle}>Jenis Paspor</Text>
<Text style={styles.applicantDetailTextDesc}>
{lastAppointment.applicationDetails.passportType}
</Text>
</View>
</View>
</View>
</View>
<View style={{margin: 16}}>
<Button
mode="contained"
style={styles.subStepButtonContained}
textColor={Colors.neutral100.color}
onPress={() => setStep(6)}>
Kembali ke Halaman Utama
</Button>
</View>
</ScrollView>
);
};
export default Step7Completion;

View File

@ -0,0 +1,240 @@
import {StyleSheet} from 'react-native';
import Colors from '../../../../assets/styles/Colors';
import FontFamily from '../../../../assets/styles/FontFamily';
const styles = StyleSheet.create({
subStepContainer: {
backgroundColor: Colors.neutral100.color,
padding: 16,
},
subStepButtonContainer: {
gap: 16,
},
subStepButtonContained: {
backgroundColor: Colors.primary30.color,
},
subStepButtonOutlined: {
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,
textAlign: 'justify',
},
subStepTextInputContainer: {
gap: 16,
},
subStepListTextRowContainer: {
flexDirection: 'row',
gap: 6,
},
subStepListTextFlex: {
flex: 1,
},
subStepButtonBackWrapper: {
flexDirection: 'row',
alignItems: 'center',
gap: 4,
},
subStepButtonBackText: {
...FontFamily.notoSansRegular,
includeFontPadding: false,
fontSize: 10,
},
subStepSectionButtonTextTitle: {
marginBottom: 8,
fontSize: 12,
includeFontPadding: false,
...FontFamily.notoSansBold,
color: Colors.primary30.color,
flex: 1,
},
subStepSectionButtonTextWrapper: {
flexDirection: 'row',
},
sectionButtonWrapper: {
flexDirection: 'row',
gap: 16,
},
buttonContainedSecondary: {
flex: 1,
backgroundColor: Colors.secondary30.color,
},
textInputBulletTextWrapper: {
flexDirection: 'row',
gap: 6,
},
subStepTextInputRowContainer: {
justifyContent: 'center',
flexDirection: 'row',
gap: 12,
},
subStepTextInputFlex: {
flex: 1,
},
subStepSectionButtonContainer: {
marginBottom: 24,
gap: 16,
},
subStepQuestionnaireOptionContainer: {
borderWidth: 1,
borderColor: Colors.secondary50.color,
borderRadius: 8,
padding: 16,
marginVertical: 16,
gap: 16,
backgroundColor: Colors.neutral100.color,
},
subStepCheckWrapper: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
questionnaireDataSecondary: {
...FontFamily.notoSansBold,
fontSize: 12,
color: Colors.secondary30.color,
includeFontPadding: false,
},
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',
},
applicantDetailTexDescName: {
textTransform: 'uppercase',
textAlign: 'right',
},
applicantDetailTexDescCode: {
textAlign: 'right',
},
midContainer: {
backgroundColor: Colors.neutral100.color,
},
midTextTitle: {
...FontFamily.notoSansExtraBold,
fontSize: 18,
includeFontPadding: false,
marginBottom: 6,
color: Colors.primary30.color,
},
midIconContainer: {
gap: 8,
marginVertical: 12,
},
midIconContentWrapper: {
flexDirection: 'row',
alignItems: 'center',
gap: 6,
},
midIconContentTextStyle: {
fontSize: 12,
...FontFamily.notoSansRegular,
color: Colors.primary30.color,
flex: 1,
},
midTextContentWrapper: {
flexDirection: 'row',
justifyContent: 'space-between',
},
midTextContentContainer: {
marginVertical: 12,
gap: 12,
},
midTextContentTitle: {
fontSize: 12,
...FontFamily.notoSansRegular,
includeFontPadding: false,
color: Colors.primary30.color,
},
midTextContentData: {
fontSize: 12,
...FontFamily.notoSansSemiBold,
includeFontPadding: false,
color: Colors.primary30.color,
},
accordionContainer: {
marginTop: 8,
marginBottom: 8,
},
accordionOptionDataWrapper: {
marginBottom: 16,
},
accordionTextContentWrapper: {
flexDirection: 'row',
gap: 6,
},
accordionTextContentDesc: {
flex: 1,
color: Colors.primary30.color,
...FontFamily.notoSansRegular,
fontSize: 12,
textAlign: 'justify',
includeFontPadding: false,
lineHeight: 24,
},
accordionListFlex: {
flex: 0,
},
accordionTextContentAlphabetWrapper: {
marginStart: 16,
}
});
export default styles;

View File

@ -129,6 +129,7 @@ const styles = StyleSheet.create({
color: Colors.primary10.color,
...FontFamily.notoSansRegular,
lineHeight: 20,
textAlign: 'justify',
},
documentImageContainer: {
alignItems: 'center',
@ -151,6 +152,13 @@ const styles = StyleSheet.create({
subStepTextInputFlex: {
flex: 1,
},
subStepListTextRowContainer: {
flexDirection: 'row',
gap: 6,
},
subStepListTextFlex: {
flex: 1,
},
subStepButtonBackWrapper: {
flexDirection: 'row',
alignItems: 'center',