From ad67df1461cffc0cd0f3d76335b26e68593ad28a Mon Sep 17 00:00:00 2001 From: Mochammad Adhi Buchori Date: Fri, 25 Apr 2025 17:27:12 +0700 Subject: [PATCH] Finalized all of the passport application flow feature except for step 6 --- src/components/TextInput.tsx | 181 +++++++--- .../dialog/DialogApplicationPassport.tsx | 1 + .../dialog/DialogCivilStatusDocumentsInfo.tsx | 69 ++++ .../dialog/DialogFinalizationConfirmation.tsx | 89 +++++ .../dialog/DialogLostOrDamagedPassport.tsx | 1 + ...fo.tsx => DialogPassportConditionInfo.tsx} | 5 +- .../dialog/DialogPassportTypeInfo.tsx | 96 ++++++ .../dialog/DialogPersonalDataRequirement.tsx | 0 src/components/dialog/DialogSubmitSuccess.tsx | 73 ++++ src/components/sheet/SheetEditData.tsx | 321 ++++++++++++++++++ src/components/sheet/SheetSearchLocation.tsx | 241 +++++++++++++ src/components/sheet/SheetSelectDate.tsx | 96 ++++++ src/data/Steps/ImmigrationOfficesData.tsx | 67 ++++ src/screens/navigationRoute/styles.tsx | 1 + src/screens/regularPassport/index.tsx | 204 +++++++++-- .../steps/Step3Payment/Step3Payment.tsx | 23 +- .../Step5Verification/Step5Verification.tsx | 29 +- .../steps/Step6Processing/Step6Processing.tsx | 24 +- .../steps/Step7Completion/Step7Completion.tsx | 11 +- src/screens/regularPassport/styles.tsx | 1 + 20 files changed, 1418 insertions(+), 115 deletions(-) create mode 100644 src/components/dialog/DialogCivilStatusDocumentsInfo.tsx create mode 100644 src/components/dialog/DialogFinalizationConfirmation.tsx rename src/components/dialog/{DialogPassportInfo.tsx => DialogPassportConditionInfo.tsx} (95%) create mode 100644 src/components/dialog/DialogPassportTypeInfo.tsx delete mode 100644 src/components/dialog/DialogPersonalDataRequirement.tsx create mode 100644 src/components/sheet/SheetEditData.tsx create mode 100644 src/components/sheet/SheetSearchLocation.tsx create mode 100644 src/components/sheet/SheetSelectDate.tsx create mode 100644 src/data/Steps/ImmigrationOfficesData.tsx diff --git a/src/components/TextInput.tsx b/src/components/TextInput.tsx index 13d275f..e4b0056 100644 --- a/src/components/TextInput.tsx +++ b/src/components/TextInput.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import {Image, Platform, Pressable, StyleSheet, Text, View} from 'react-native'; import {TextInput} from 'react-native-paper'; import Icon from 'react-native-vector-icons/MaterialIcons'; +import IconMaterialCommunity from 'react-native-vector-icons/MaterialCommunityIcons'; import Colors from '../../assets/styles/Colors'; import FontFamily from '../../assets/styles/FontFamily'; import DateTimePicker from '@react-native-community/datetimepicker'; @@ -23,6 +24,8 @@ type DropdownCountryItem = { interface TextInputComponentProps { title?: string; + iconButton?: boolean; + onIconButtonPress?: () => void; placeholder?: string; isPassword?: boolean; isRequired?: boolean; @@ -35,23 +38,31 @@ interface TextInputComponentProps { supportText?: string; containerHeight?: any; isMultiline?: boolean; + isDropdownSearchLocation?: boolean; + handlePressSearchLocation?: () => void; } -const TextInputComponent: React.FC = ({ - title, - placeholder, - isPassword = false, - isRequired = false, - isDate = false, - isDropdown = false, - isDropdownCountry = false, - dropdownItemData, - dropdownCountryItemData, - isDisabled = false, - supportText, - containerHeight, - isMultiline = false, -}) => { +const TextInputComponent = (props: TextInputComponentProps) => { + const { + title, + iconButton = false, + onIconButtonPress, + placeholder, + isPassword = false, + isRequired = false, + isDate = false, + isDropdown = false, + isDropdownCountry = false, + dropdownItemData, + dropdownCountryItemData, + isDisabled = false, + supportText, + containerHeight, + isMultiline = false, + isDropdownSearchLocation = false, + handlePressSearchLocation, + } = props; + const [secureText, setSecureText] = useState(isPassword); const [selectedDate, setSelectedDate] = useState(undefined); const [formattedDate, setFormattedDate] = useState(''); @@ -97,7 +108,10 @@ const TextInputComponent: React.FC = ({ const renderDropdownCountryItem = (item: any) => { return ( - + {item.label} ); @@ -145,6 +159,90 @@ const TextInputComponent: React.FC = ({ }; const renderInput = () => { + if (isDropdown) { + return ( + + + {title && ( + + {title} + {isRequired && *} + + )} + {iconButton && ( + ({ + transform: [{scale: pressed ? 0.925 : 1}], + })} + onPress={onIconButtonPress}> + + + )} + + { + setDropdownValue(item.value); + }} + disable={isDisabled} + renderRightIcon={() => } + renderItem={renderDropdownItem} + /> + + ); + } + + if (isDate) { + return ( + + + {title && {title}} + {isRequired && *} + + !isDisabled && setShowPicker(true)} + style={({pressed}) => ({ + transform: [{scale: pressed ? 0.99 : 1}], + })}> + } + multiline={false} + textColor="#48454E" + disabled={isDisabled} + /> + + {showPicker && ( + + )} + + ); + } + if (isDropdownCountry) { return ( @@ -183,7 +281,7 @@ const TextInputComponent: React.FC = ({ ); } - if (isDropdown) { + if (isDropdownSearchLocation) { return ( {title && ( @@ -192,36 +290,11 @@ const TextInputComponent: React.FC = ({ {isRequired && *} )} - { - setDropdownValue(item.value); - }} - disable={isDisabled} - renderRightIcon={() => } - renderItem={renderDropdownItem} - /> - - ); - } - - if (isDate) { - return ( - - - {title && {title}} - {isRequired && *} - - !isDisabled && setShowPicker(true)}> + ({ + transform: [{scale: pressed ? 0.99 : 1}], + })}> = ({ placeholderTextColor={Colors.primary60.color} editable={false} value={formattedDate} - right={} + right={} multiline={false} textColor="#48454E" disabled={isDisabled} /> - {showPicker && ( - - )} ); } @@ -290,6 +355,10 @@ const styles = StyleSheet.create({ backgroundColor: Colors.neutral100.color, marginTop: 8, }, + headerContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + }, title: { ...FontFamily.notoSansBold, fontSize: 12, diff --git a/src/components/dialog/DialogApplicationPassport.tsx b/src/components/dialog/DialogApplicationPassport.tsx index f47d6c7..4435d60 100644 --- a/src/components/dialog/DialogApplicationPassport.tsx +++ b/src/components/dialog/DialogApplicationPassport.tsx @@ -64,6 +64,7 @@ const styles = StyleSheet.create({ fontSize: 14, ...FontFamily.notoSansRegular, includeFontPadding: false, + lineHeight: 22, color: Colors.primary30.color, }, buttonAgree: { diff --git a/src/components/dialog/DialogCivilStatusDocumentsInfo.tsx b/src/components/dialog/DialogCivilStatusDocumentsInfo.tsx new file mode 100644 index 0000000..bbe3143 --- /dev/null +++ b/src/components/dialog/DialogCivilStatusDocumentsInfo.tsx @@ -0,0 +1,69 @@ +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 DialogCivilStatusDocumentsInfo = (props: Props) => { + const {visible, onClose} = props; + + return ( + + + + + Dokumen identitas diri harus memuat nama, tempat tanggal lahir, dan + nama orang tua. + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + dialogContainer: { + backgroundColor: 'white', + elevation: 0, + shadowColor: 'transparent', + borderRadius: 20, + }, + dialogContentContainer: { + marginHorizontal: 24, + marginBottom: 24, + gap: 16, + }, + dialogDesc: { + fontSize: 14, + lineHeight: 22, + ...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 DialogCivilStatusDocumentsInfo; diff --git a/src/components/dialog/DialogFinalizationConfirmation.tsx b/src/components/dialog/DialogFinalizationConfirmation.tsx new file mode 100644 index 0000000..3d79e29 --- /dev/null +++ b/src/components/dialog/DialogFinalizationConfirmation.tsx @@ -0,0 +1,89 @@ +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 DialogFinalizationConfirmation = (props: Props) => { + const {visible, onClose, onContinue} = props; + return ( + + + + Apakah data yang Anda input sudah benar? + + + + Permohonan Anda akan diajukan dan Anda tidak dapat mengubah kembali + data Anda.{' '} + + Biaya yang sudah dibayarkan tidak bisa kembali apabila Anda + memberikan keterangan tidak benar. + + + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + dialogContainer: { + backgroundColor: 'white', + elevation: 0, + shadowColor: 'transparent', + borderRadius: 20, + }, + dialogTitle: { + fontSize: 22, + color: Colors.secondary30.color, + }, + dialogDescBold: { + includeFontPadding: false, + ...FontFamily.notoSansBold, + }, + dialogContentContainer: { + marginHorizontal: 24, + marginBottom: 24, + gap: 16, + }, + dialogDesc: { + fontSize: 14, + ...FontFamily.notoSansRegular, + includeFontPadding: false, + lineHeight: 22, + color: Colors.primary30.color, + }, + buttonContained: { + backgroundColor: Colors.primary30.color, + marginTop: 12, + }, + buttonOutlined: { + borderColor: Colors.primary30.color, + marginTop: 12, + }, +}); + +export default DialogFinalizationConfirmation; diff --git a/src/components/dialog/DialogLostOrDamagedPassport.tsx b/src/components/dialog/DialogLostOrDamagedPassport.tsx index 29d7cfb..643630e 100644 --- a/src/components/dialog/DialogLostOrDamagedPassport.tsx +++ b/src/components/dialog/DialogLostOrDamagedPassport.tsx @@ -101,6 +101,7 @@ const styles = StyleSheet.create({ fontSize: 14, ...FontFamily.notoSansRegular, includeFontPadding: false, + lineHeight: 22, color: Colors.primary30.color, }, dialogBulletPointWrapper: { diff --git a/src/components/dialog/DialogPassportInfo.tsx b/src/components/dialog/DialogPassportConditionInfo.tsx similarity index 95% rename from src/components/dialog/DialogPassportInfo.tsx rename to src/components/dialog/DialogPassportConditionInfo.tsx index f64ee4e..a39105a 100644 --- a/src/components/dialog/DialogPassportInfo.tsx +++ b/src/components/dialog/DialogPassportConditionInfo.tsx @@ -8,7 +8,7 @@ type Props = { onClose: () => void; }; -const DialogPassportInfo = (props: Props) => { +const DialogPassportConditionInfo = (props: Props) => { const {visible, onClose} = props; return ( @@ -76,6 +76,7 @@ const styles = StyleSheet.create({ ...FontFamily.notoSansRegular, includeFontPadding: false, color: Colors.primary30.color, + lineHeight: 22, }, dialogDescRed: { ...FontFamily.notoSansBold, @@ -88,4 +89,4 @@ const styles = StyleSheet.create({ }, }); -export default DialogPassportInfo; +export default DialogPassportConditionInfo; diff --git a/src/components/dialog/DialogPassportTypeInfo.tsx b/src/components/dialog/DialogPassportTypeInfo.tsx new file mode 100644 index 0000000..45757cf --- /dev/null +++ b/src/components/dialog/DialogPassportTypeInfo.tsx @@ -0,0 +1,96 @@ +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 DialogPassportTypeInfo = (props: Props) => { + const {visible, onClose} = props; + + return ( + + + + Jenis dan Manfaat Paspor + + + + 1. Paspor Biasa + + + Biaya pemrosesan lebih murah, tersedia di seluruh lokasi Kanim. + {'\n'}Biaya pembuatan: Rp350.000 + + + 2. Paspor Elektronik + + + Terdapat chip pada cover paspor yang menyimpan data pemegang paspor + sehingga meningkatkan fitur keamanan, tersedia di 35 Kanim.{'\n'} + Biaya pembuatan: Rp650.000 + + + 3. Paspor Elektronik Polikarbonat + + + Berbahan polikarbonat (PC) pada halaman data pemegang paspor + (halaman 2) yang memiliki fitur keamanan tinggi dan lebih kuat, + tersedia di Kanim Jakarta Selatan, Kanim Jakarta Barat, dan Kanim + Soekarno Hatta.{'\n'}Biaya pembuatan: Rp650.000 + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + dialogContainer: { + backgroundColor: 'white', + elevation: 0, + shadowColor: 'transparent', + borderRadius: 20, + }, + dialogContentContainer: { + marginHorizontal: 24, + marginBottom: 24, + gap: 16, + }, + dialogTitle: { + fontSize: 22, + color: Colors.secondary30.color, + }, + dialogDesc: { + fontSize: 14, + ...FontFamily.notoSansRegular, + includeFontPadding: false, + color: Colors.primary30.color, + lineHeight: 22, + }, + dialogDescRed: { + ...FontFamily.notoSansBold, + color: Colors.indicatorRed.color, + includeFontPadding: false, + }, + buttonContinue: { + backgroundColor: Colors.primary30.color, + marginTop: 12, + }, +}); + +export default DialogPassportTypeInfo; diff --git a/src/components/dialog/DialogPersonalDataRequirement.tsx b/src/components/dialog/DialogPersonalDataRequirement.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/src/components/dialog/DialogSubmitSuccess.tsx b/src/components/dialog/DialogSubmitSuccess.tsx index e69de29..1f6babf 100644 --- a/src/components/dialog/DialogSubmitSuccess.tsx +++ b/src/components/dialog/DialogSubmitSuccess.tsx @@ -0,0 +1,73 @@ +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; + onSubmitSuccess: () => void; +}; + +const DialogSubmitSuccess = (props: Props) => { + const {visible, onSubmitSuccess} = props; + + return ( + + + + Pengajuan Permohonan Sukses! + + + + Permohonan telah diajukan, klik kartu pada beranda untuk melihat + kode layanan, kode QR, kode billing, serta tata cara pembayarannya. + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + dialogContainer: { + backgroundColor: 'white', + elevation: 0, + shadowColor: 'transparent', + borderRadius: 20, + }, + dialogContentContainer: { + marginHorizontal: 24, + marginBottom: 24, + gap: 16, + }, + dialogTitle: { + fontSize: 22, + color: Colors.secondary30.color, + ...FontFamily.notoSansBold, + includeFontPadding: false, + }, + dialogDesc: { + fontSize: 14, + ...FontFamily.notoSansRegular, + lineHeight: 22, + includeFontPadding: false, + color: Colors.primary30.color, + }, + buttonContinue: { + backgroundColor: Colors.primary30.color, + marginTop: 12, + }, +}); + +export default DialogSubmitSuccess; diff --git a/src/components/sheet/SheetEditData.tsx b/src/components/sheet/SheetEditData.tsx new file mode 100644 index 0000000..abc75e5 --- /dev/null +++ b/src/components/sheet/SheetEditData.tsx @@ -0,0 +1,321 @@ +import React, {useState} from 'react'; +import { + StyleSheet, + Text, + View, + Modal, + Pressable, + ScrollView, +} from 'react-native'; +import {Portal, Button} from 'react-native-paper'; +import Colors from '../../../assets/styles/Colors'; +import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; +import FontFamily from '../../../assets/styles/FontFamily'; +import TextInputComponent from '../TextInput'; +import genderData from '../../data/DropdownData/GenderData'; + +type SheetEditDataProps = { + visible: boolean; + onClose: () => void; + showCivilStatusDocumentsInfoDialog: () => void; + selectedPassportOption: string; +}; + +interface DocumentUploadSectionProps { + title: string; + isRequired?: boolean; + isIcon?: boolean; + showDialogCivilStatusDocumentsInfo?: () => void; +} + +const DocumentUploadSection = (props: DocumentUploadSectionProps) => { + const {title, isRequired, isIcon, showDialogCivilStatusDocumentsInfo} = props; + const [uploadedFileName, setUploadedFileName] = useState(null); + + const handleUpload = () => { + let fileName = `${title.toLowerCase().replace(/ /g, '')}.jpg`; + + if ( + title === 'Akta kelahiran/ijazah/akta perkawinan/buku nikah/surat baptis' + ) { + fileName = 'ijazah.jpg'; + } + + setUploadedFileName(fileName); + }; + + const handleDelete = () => setUploadedFileName(null); + + return ( + + + + {title} {isRequired && *} + + {isIcon && ( + ({ + transform: [{scale: pressed ? 0.925 : 1}], + })} + onPress={showDialogCivilStatusDocumentsInfo}> + + + )} + + + {!uploadedFileName ? ( + + + + + + ) : ( + + + Berhasil dipilih + {uploadedFileName} + + + + )} + + ); +}; + +const SheetEditData = (props: SheetEditDataProps) => { + const { + visible, + onClose, + showCivilStatusDocumentsInfoDialog, + selectedPassportOption, + } = props; + return ( + + + + + + + Ubah Data Pemohon + ({ + transform: [{scale: pressed ? 0.925 : 1}], + })} + onPress={onClose}> + + + + + + + + + Unggah dokumen hanya bisa berbentuk JPG. + + + + + + Data yang bertanda *{' '} + wajib diisi. + + + + + + + + + + + + + + + + + + + {selectedPassportOption !== 'already' && ( + + )} + + + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + backdrop: { + flex: 1, + backgroundColor: 'rgba(0,0,0,0.3)', + }, + modalContainer: { + backgroundColor: 'white', + borderTopLeftRadius: 20, + borderTopRightRadius: 20, + paddingTop: 24, + paddingHorizontal: 16, + position: 'absolute', + bottom: 0, + width: '100%', + maxHeight: '90%', + }, + modalHeader: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + }, + modalTitle: { + fontSize: 12, + color: Colors.primary30.color, + ...FontFamily.notoSansBold, + }, + infoList: { + marginVertical: 16, + }, + infoItem: { + flexDirection: 'row', + alignItems: 'flex-start', + gap: 6, + }, + bullet: { + fontSize: 10, + ...FontFamily.notoSansBold, + color: Colors.primary10.color, + lineHeight: 20, + }, + infoText: { + fontSize: 10, + ...FontFamily.notoSansBold, + color: Colors.primary10.color, + lineHeight: 20, + flex: 1, + textAlign: 'justify', + }, + required: { + color: Colors.indicatorRed.color, + }, + row: { + flexDirection: 'row', + gap: 12, + }, + flex: { + flex: 1, + }, + sectionHeader: { + flexDirection: 'row', + alignItems: 'center', + }, + sectionTitle: { + marginBottom: 8, + fontSize: 12, + color: Colors.primary30.color, + ...FontFamily.notoSansBold, + flex: 1, + }, + uploadButtonGroup: { + flexDirection: 'row', + gap: 16, + }, + uploadButton: { + flex: 1, + backgroundColor: Colors.secondary30.color, + }, + uploadedContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + borderWidth: 1, + borderColor: Colors.secondary50.color, + borderRadius: 8, + paddingHorizontal: 16, + paddingVertical: 8, + }, + uploadedTextWrapper: { + gap: 4, + }, + uploadedTitle: { + color: Colors.primary30.color, + fontSize: 12, + ...FontFamily.notoSansMedium, + }, + uploadedFilename: { + color: Colors.primary40.color, + fontSize: 10, + ...FontFamily.notoSansRegular, + }, + saveButtonWrapper: { + marginTop: 24, + }, + saveButton: { + backgroundColor: Colors.primary30.color, + }, +}); + +export default SheetEditData; diff --git a/src/components/sheet/SheetSearchLocation.tsx b/src/components/sheet/SheetSearchLocation.tsx new file mode 100644 index 0000000..4921d30 --- /dev/null +++ b/src/components/sheet/SheetSearchLocation.tsx @@ -0,0 +1,241 @@ +import { + FlatList, + Modal, + Pressable, + ScrollView, + StyleSheet, + Text, + View, +} from 'react-native'; +import {Button, Portal, TextInput} from 'react-native-paper'; +import Colors from '../../../assets/styles/Colors'; +import FontFamily from '../../../assets/styles/FontFamily'; +import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; +import immigrationOfficesData from '../../data/Steps/ImmigrationOfficesData'; +import {useState} from 'react'; + +type SheetSearchLocationProps = { + visible: boolean; + onClose: () => void; +}; + +const ItemSeparator = () => ; + +const renderSearchInput = () => { + return ( + + + } + /> + + ); +}; + +const renderCurrentLocation = (onPress: () => void) => { + return ( + [ + styles.currentLocationContainer, + { + transform: [{scale: pressed ? 0.985 : 1}], + }, + ]}> + + + + Pakai lokasi saya saat ini + + + Jl. Raya Muchtar No. 8, Depok, 16511 + + + + ); +}; + +const renderNearestLocationItem = ({ + item, + onPress, +}: { + item: any; + onPress: () => void; +}) => { + return ( + [ + styles.nearestLocationContainer, + { + transform: [{scale: pressed ? 0.985 : 1}], + }, + ]}> + + + {item.name} + {item.distance} + + {item.address} + + + + + + + ); +}; + +const SheetSearchLocation = (props: SheetSearchLocationProps) => { + const {visible, onClose} = props; + const [showNearestLocations, setShowNearestLocations] = useState(false); + + return ( + + + + + {renderSearchInput()} + {!showNearestLocations && + renderCurrentLocation(() => setShowNearestLocations(true))} + + {showNearestLocations && ( + item.id} + renderItem={({item}) => + renderNearestLocationItem({item, onPress: onClose}) + } + contentContainerStyle={{marginVertical: 16, paddingBottom: 32}} + showsVerticalScrollIndicator={false} + ItemSeparatorComponent={ItemSeparator} + /> + )} + + + + ); +}; + +const styles = StyleSheet.create({ + backdrop: { + flex: 1, + backgroundColor: 'rgba(0,0,0,0.3)', + }, + modalContainer: { + backgroundColor: 'white', + borderTopLeftRadius: 20, + borderTopRightRadius: 20, + paddingTop: 24, + paddingHorizontal: 16, + position: 'absolute', + bottom: 0, + height: '90%', + width: '100%', + maxHeight: '90%', + }, + searchInput: { + backgroundColor: Colors.neutral100.color, + fontSize: 13, + ...FontFamily.notoSansRegular, + includeFontPadding: false, + }, + currentLocationContainer: { + marginVertical: 16, + padding: 16, + flexDirection: 'row', + gap: 12, + alignItems: 'center', + borderWidth: 1, + borderRadius: 8, + borderColor: Colors.primary30.color, + }, + currentLocationTextContainer: { + gap: 6, + }, + currentLocationTitle: { + includeFontPadding: false, + fontSize: 14, + ...FontFamily.notoSansMedium, + color: Colors.primary30.color, + }, + currentLocationSubtitle: { + includeFontPadding: false, + fontSize: 12, + ...FontFamily.notoSansRegular, + color: Colors.primary40.color, + }, + nearestLocationContainer: { + padding: 16, + borderRadius: 8, + gap: 16, + borderWidth: 1, + borderColor: Colors.secondary30.color, + }, + nearestLocationInfoWrapper: { + gap: 8, + }, + nearestLocationHeader: { + flexDirection: 'row', + justifyContent: 'space-between', + }, + locationName: { + color: Colors.secondary30.color, + includeFontPadding: false, + ...FontFamily.notoSansBold, + fontSize: 14, + flex: 1, + }, + locationDistance: { + color: Colors.primary60.color, + includeFontPadding: false, + fontSize: 12, + ...FontFamily.notoSansMedium, + }, + locationAddress: { + color: Colors.primary40.color, + includeFontPadding: false, + fontSize: 12, + ...FontFamily.notoSansRegular, + }, + buttonWrapper: { + flexDirection: 'row', + gap: 12, + }, + selectButton: { + backgroundColor: Colors.primary30.color, + flex: 1, + }, + viewButton: { + borderColor: Colors.primary30.color, + flex: 1, + }, + flatllistGap: { + height: 16, + }, +}); + +export default SheetSearchLocation; diff --git a/src/components/sheet/SheetSelectDate.tsx b/src/components/sheet/SheetSelectDate.tsx new file mode 100644 index 0000000..569cff1 --- /dev/null +++ b/src/components/sheet/SheetSelectDate.tsx @@ -0,0 +1,96 @@ +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 SheetSelectDate = (props: Props) => { + const {visible, onClose} = props; + + return ( + + + + Jenis dan Manfaat Paspor + + + + 1. Paspor Biasa + + + Biaya pemrosesan lebih murah, tersedia di seluruh lokasi Kanim. + {'\n'}Biaya pembuatan: Rp350.000 + + + 2. Paspor Elektronik + + + Terdapat chip pada cover paspor yang menyimpan data pemegang paspor + sehingga meningkatkan fitur keamanan, tersedia di 35 Kanim.{'\n'} + Biaya pembuatan: Rp650.000 + + + 3. Paspor Elektronik Polikarbonat + + + Berbahan polikarbonat (PC) pada halaman data pemegang paspor + (halaman 2) yang memiliki fitur keamanan tinggi dan lebih kuat, + tersedia di Kanim Jakarta Selatan, Kanim Jakarta Barat, dan Kanim + Soekarno Hatta.{'\n'}Biaya pembuatan: Rp650.000 + + + + + + + + ); +}; + +const styles = StyleSheet.create({ + dialogContainer: { + backgroundColor: 'white', + elevation: 0, + shadowColor: 'transparent', + borderRadius: 20, + }, + dialogContentContainer: { + marginHorizontal: 24, + marginBottom: 24, + gap: 16, + }, + dialogTitle: { + fontSize: 22, + color: Colors.secondary30.color, + }, + dialogDesc: { + fontSize: 14, + ...FontFamily.notoSansRegular, + includeFontPadding: false, + color: Colors.primary30.color, + lineHeight: 22, + }, + dialogDescRed: { + ...FontFamily.notoSansBold, + color: Colors.indicatorRed.color, + includeFontPadding: false, + }, + buttonContinue: { + backgroundColor: Colors.primary30.color, + marginTop: 12, + }, +}); + +export default SheetSelectDate; diff --git a/src/data/Steps/ImmigrationOfficesData.tsx b/src/data/Steps/ImmigrationOfficesData.tsx new file mode 100644 index 0000000..072c0c9 --- /dev/null +++ b/src/data/Steps/ImmigrationOfficesData.tsx @@ -0,0 +1,67 @@ +const immigrationOfficesData = [ + { + id: '1', + name: 'MAL PELAYANAN PUBLIK KOTA DEPOK', + address: + 'JL. MARGONDA NO. 54, DEPOK, KEC. PANCORAN MAS, KOTA DEPOK, JAWA BARAT.', + distance: '1.5 Km', + }, + { + id: '2', + name: 'KANTOR IMIGRASI DEPOK', + address: + 'JALAN BOULEVARD RAYA, KOMPLEK PERKANTORAN PEMDA DEPOK, GRAND DEPOK CITY, KOTA DEPOK, JAWA BARAT.', + distance: '2.2 Km', + }, + { + id: '3', + name: 'IMMIGRATION LOUNGE PESONA SQUARE', + address: + 'MALL PESONA SQUARE LANTAI 3, JL. IR. H. JUANDA NO. 22A, BAKTI JAYA, KOTA DEPOK, JAWA BARAT.', + distance: '4.4 Km', + }, + { + id: '4', + name: 'ULP DEPOK', + address: 'DEPOK TOWN SQUARE', + distance: '4.5 Km', + }, + { + id: '5', + name: 'KANTOR IMIGRASI KABUPATEN BOGOR', + address: 'JL. RAYA KESATUAN NO. 45, BOGOR, JAWA BARAT.', + distance: '5.0 Km', + }, + { + id: '6', + name: 'IMMIGRATION LOUNGE CIBINONG', + address: 'CIBINONG SQUARE, JALAN RAYA CIBINONG NO. 8, BOGOR, JAWA BARAT.', + distance: '6.3 Km', + }, + { + id: '7', + name: 'KANTOR IMIGRASI KOTA BOGOR', + address: 'JL. PELABUHAN NO. 10, BOGOR, JAWA BARAT.', + distance: '7.1 Km', + }, + { + id: '8', + name: 'MAL PELAYANAN PUBLIK KOTA BOGOR', + address: 'JL. SUKABUMI NO. 12, BOGOR, JAWA BARAT.', + distance: '7.8 Km', + }, + { + id: '9', + name: 'KANTOR IMIGRASI CILEUNGSI', + address: 'JALAN RAYA CILEUNGSI NO. 17, CILEUNGSI, JAWA BARAT.', + distance: '8.4 Km', + }, + { + id: '10', + name: 'IMMIGRATION LOUNGE PUNCAK', + address: 'PUNCAK RESORT, JALAN RAYA PUNCAK NO. 30, BOGOR, JAWA BARAT.', + distance: '9.2 Km', + }, +]; + +export default immigrationOfficesData; diff --git a/src/screens/navigationRoute/styles.tsx b/src/screens/navigationRoute/styles.tsx index 7f297df..efe44d1 100644 --- a/src/screens/navigationRoute/styles.tsx +++ b/src/screens/navigationRoute/styles.tsx @@ -29,6 +29,7 @@ const styles = StyleSheet.create({ fontSize: 14, ...FontFamily.notoSansRegular, includeFontPadding: false, + lineHeight: 22, color: Colors.primary30.color, }, buttonContinue: { diff --git a/src/screens/regularPassport/index.tsx b/src/screens/regularPassport/index.tsx index 9364bc1..4934ee5 100644 --- a/src/screens/regularPassport/index.tsx +++ b/src/screens/regularPassport/index.tsx @@ -1,12 +1,5 @@ import React, {useEffect, useState} from 'react'; -import { - BackHandler, - Pressable, - ScrollView, - StatusBar, - Text, - View, -} from 'react-native'; +import {BackHandler, StatusBar, Text, View} from 'react-native'; import styles from './styles'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; import {useNavigation} from '@react-navigation/native'; @@ -14,28 +7,19 @@ 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, PaperProvider} from 'react-native-paper'; +import {PaperProvider} from 'react-native-paper'; import StepIndicator from '../../components/StepIndicator'; -import TextInputComponent from '../../components/TextInput'; 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 familyRelationshipData from '../../data/DropdownData/FamilyRelationshipData'; -import FontFamily from '../../../assets/styles/FontFamily'; import passportAppointmentData from '../../data/History/PassportAppointmentData'; import Step7Completion from './steps/Step7Completion/Step7Completion'; import Step6Processing from './steps/Step6Processing/Step6Processing'; import Step5Verification from './steps/Step5Verification/Step5Verification'; import Step3Payment from './steps/Step3Payment/Step3Payment'; -// Data -import arrivalDateGuidelinesData from '../../data/Steps/ArrivalDateGuidelinesData'; - // Options Data import passportForOptions from '../../data/Options/PassportForOptions'; -import durationAbroadOptions from '../../data/Options/DurationAbroadOptions'; -import destinationFamilyContactOptions from '../../data/Options/DestinationFamilyContactOptions'; import Step4DataConfirmationSubStep2 from './steps/Step4DataConfirmation/Step4DataConfirmationSubStep2'; import Step4DataConfirmationSubStep1 from './steps/Step4DataConfirmation/Step4DataConfirmationSubStep1'; import Step1PersonalInfoSubStep1 from './steps/Step1PersonalInfo/Step1PersonalInfoSubStep1'; @@ -52,6 +36,13 @@ import Step2SupportingDocsSubStep8 from './steps/Step2SupportingDocs/Step2Suppor import Step2SupportingDocsSubStep9 from './steps/Step2SupportingDocs/Step2SupportingDocsSubStep9'; import Step2SupportingDocsSubStep10 from './steps/Step2SupportingDocs/Step2SupportingDocsSubStep10'; import Step2SupportingDocsSubStep11 from './steps/Step2SupportingDocs/Step2SupportingDocsSubStep11'; +import DialogCivilStatusDocumentsInfo from '../../components/dialog/DialogCivilStatusDocumentsInfo'; +import DialogSubmitSuccess from '../../components/dialog/DialogSubmitSuccess'; +import DialogFinalizationConfirmation from '../../components/dialog/DialogFinalizationConfirmation'; +import DialogPassportConditionInfo from '../../components/dialog/DialogPassportConditionInfo'; +import DialogPassportTypeInfo from '../../components/dialog/DialogPassportTypeInfo'; +import SheetEditData from '../../components/sheet/SheetEditData'; +import SheetSearchLocation from '../../components/sheet/SheetSearchLocation'; type RegularPassportScreenNavigationProp = NativeStackNavigationProp< RootStackParamList, @@ -72,6 +63,13 @@ type RenderApplicationStepsContentProps = { showDontHaveYetDialog: () => void; showPassportInfoDialog: () => void; showLostOrDamagedPassportDialog: () => void; + showCivilStatusDocumentsInfoDialog: () => void; + showSubmitSuccessDialog: () => void; + setLastCompletedSteps: () => void; + showFinalizationConfirmationDialog: () => void; + showPassportTypeInfoDialog: () => void; + showEditDataSheet: () => void; + showSearchLocationSheet: () => void; }; const RenderApplicationStepsContent = ( @@ -91,6 +89,13 @@ const RenderApplicationStepsContent = ( showDontHaveYetDialog, showPassportInfoDialog, showLostOrDamagedPassportDialog, + showCivilStatusDocumentsInfoDialog, + showSubmitSuccessDialog, + setLastCompletedSteps, + showFinalizationConfirmationDialog, + showPassportTypeInfoDialog, + showEditDataSheet, + showSearchLocationSheet, } = props; if (step === 1) { @@ -208,6 +213,9 @@ const RenderApplicationStepsContent = ( setStep={setStep} setSubStep={setSubStep} selectedPassportOption={selectedPassportOption} + showCivilStatusDocumentsInfoDialog={ + showCivilStatusDocumentsInfoDialog + } /> ); case 5: @@ -216,17 +224,26 @@ const RenderApplicationStepsContent = ( setStep={setStep} setSubStep={setSubStep} passportAppointmentData={passportAppointmentData} + showEditDataSheet={showEditDataSheet} /> ); case 6: return ( ); case 7: - return ; + return ( + + ); default: return null; } @@ -288,6 +305,9 @@ function RegularPassportScreen() { useState(false); const [step, setStep] = useState(1); const [subStep, setSubStep] = useState(1); + const [completedSteps, setCompletedSteps] = useState( + [...Array(step - 1)].map((_, i) => i + 1), + ); // Dialog visibility states const [visible, setVisible] = useState(false); @@ -299,6 +319,23 @@ function RegularPassportScreen() { visibleLostOrDamagedPassportDialog, setVisibleLostOrDamagedPassportDialog, ] = useState(false); + const [ + visibleCivilStatusDocumentsInfoDialog, + setVisibleCivilStatusDocumentsInfoDialog, + ] = useState(false); + const [visibleSubmitSuccessDialog, setVisibleSubmitSuccessDialog] = + useState(false); + const [ + visibleFinalizationConfirmationDialog, + setVisibleFinalizationConfirmationDialog, + ] = useState(false); + const [visiblePassportTypeInfoDialog, setVisiblePassportTypeInfoDialog] = + useState(false); + + // Sheet visibility states + const [visibleEditDataSheet, setVisibleEditDataSheet] = useState(false); + const [visibleSearchLocationSheet, setVisibleSearchLocationSheet] = + useState(false); // Dialog visibility function const showDialog = () => setVisible(true); @@ -310,12 +347,35 @@ function RegularPassportScreen() { const showPassportInfoDialog = () => setVisiblePassportInfoDialog(true); const hidePassportInfoDialog = () => setVisiblePassportInfoDialog(false); - const showVisibleLostOrDamagedPassportDialog = () => + const showLostOrDamagedPassportDialog = () => setVisibleLostOrDamagedPassportDialog(true); - const hideVisibleLostOrDamagedPassportDialog = () => + const hideLostOrDamagedPassportDialog = () => setVisibleLostOrDamagedPassportDialog(false); - const completedSteps = [...Array(step - 1)].map((_, i) => i + 1); + const showCivilStatusDocumentsInfoDialog = () => + setVisibleCivilStatusDocumentsInfoDialog(true); + const hideCivilStatusDocumentsInfoDialog = () => + setVisibleCivilStatusDocumentsInfoDialog(false); + + const showSubmitSuccessDialog = () => setVisibleSubmitSuccessDialog(true); + const hideSubmitSuccessDialog = () => setVisibleSubmitSuccessDialog(false); + + const showFinalizationConfirmationDialog = () => + setVisibleFinalizationConfirmationDialog(true); + const hideFinalizationConfirmationDialog = () => + setVisibleFinalizationConfirmationDialog(false); + + const showPassportTypeInfoDialog = () => + setVisiblePassportTypeInfoDialog(true); + const hidePassportTypeInfoDialog = () => + setVisiblePassportTypeInfoDialog(false); + + // Sheet visibility function + const showEditDataSheet = () => setVisibleEditDataSheet(true); + const hideEditDataSheet = () => setVisibleEditDataSheet(false); + + const showSearchLocationSheet = () => setVisibleSearchLocationSheet(true); + const hideSearchLocationSheet = () => setVisibleSearchLocationSheet(false); const stepTitles: {[key: number]: string} = { 1: 'Informasi Pribadi', @@ -344,6 +404,24 @@ function RegularPassportScreen() { } }, [showApplicationStepsContent]); + useEffect(() => { + if (step > 1) { + const updatedCompletedSteps = [...Array(step - 1)].map((_, i) => i + 1); + setCompletedSteps(updatedCompletedSteps); + } else { + setCompletedSteps([]); + } + }, [step]); + + const setLastCompletedSteps = () => { + setCompletedSteps(prevCompletedSteps => { + if (!prevCompletedSteps.includes(7)) { + return [...prevCompletedSteps, 7]; + } + return prevCompletedSteps; + }); + }; + // Render steps or questionnaire const renderApplicationStepsContent = showApplicationStepsContent ? ( <> @@ -367,9 +445,18 @@ function RegularPassportScreen() { setCheckedOption={setCheckedOption} showDontHaveYetDialog={showDontHaveYetDialog} showPassportInfoDialog={showPassportInfoDialog} - showLostOrDamagedPassportDialog={ - showVisibleLostOrDamagedPassportDialog + showLostOrDamagedPassportDialog={showLostOrDamagedPassportDialog} + showCivilStatusDocumentsInfoDialog={ + showCivilStatusDocumentsInfoDialog } + showSubmitSuccessDialog={showSubmitSuccessDialog} + setLastCompletedSteps={setLastCompletedSteps} + showFinalizationConfirmationDialog={ + showFinalizationConfirmationDialog + } + showPassportTypeInfoDialog={showPassportTypeInfoDialog} + showEditDataSheet={showEditDataSheet} + showSearchLocationSheet={showSearchLocationSheet} /> @@ -382,7 +469,7 @@ function RegularPassportScreen() { )} {visiblePassportInfoDialog && ( - @@ -398,10 +485,63 @@ function RegularPassportScreen() { setShowApplicationStepsContent(false); setStep(1); setSubStep(1); - hideVisibleLostOrDamagedPassportDialog(); + hideLostOrDamagedPassportDialog(); }} /> )} + + {visibleCivilStatusDocumentsInfoDialog && ( + + )} + + {visibleSubmitSuccessDialog && ( + { + navigation.goBack(), hideSubmitSuccessDialog(); + }} + /> + )} + + {visibleFinalizationConfirmationDialog && ( + { + setStep(7); + hideFinalizationConfirmationDialog(); + }} + /> + )} + + {visiblePassportTypeInfoDialog && ( + + )} + + {visibleEditDataSheet && ( + { + hideEditDataSheet(); + showCivilStatusDocumentsInfoDialog(); + }} + selectedPassportOption={selectedPassportOption} + /> + )} + + {visibleSearchLocationSheet && ( + + )} ) : ( void; } interface Step3PaymentProps { setStep: (step: number) => void; setSubStep: (subStep: number) => void; selectedPassportOption: string; + showCivilStatusDocumentsInfoDialog: () => void; } const BackButton = (props: BackButtonProps) => { @@ -43,7 +45,7 @@ const BackButton = (props: BackButtonProps) => { }; const DocumentUploadSection = (props: DocumentUploadSectionProps) => { - const {title, isRequired, isIcon} = props; + const {title, isRequired, isIcon, showDialogCivilStatusDocumentsInfo} = props; const [uploadedFileName, setUploadedFileName] = useState(null); const handleUpload = (p0: string) => { @@ -72,7 +74,13 @@ const DocumentUploadSection = (props: DocumentUploadSectionProps) => { )} {isIcon && ( - + ({ + transform: [{scale: pressed ? 0.925 : 1}], + })} + onPress={showDialogCivilStatusDocumentsInfo}> + + )} @@ -125,8 +133,12 @@ const DocumentUploadSection = (props: DocumentUploadSectionProps) => { }; const Step3Payment = (props: Step3PaymentProps) => { - const {setStep, setSubStep, selectedPassportOption} = props; - console.log('selectedPassportOption', selectedPassportOption); + const { + setStep, + setSubStep, + selectedPassportOption, + showCivilStatusDocumentsInfoDialog, + } = props; return ( @@ -228,6 +240,9 @@ const Step3Payment = (props: Step3PaymentProps) => { {selectedPassportOption !== 'already' && ( diff --git a/src/screens/regularPassport/steps/Step5Verification/Step5Verification.tsx b/src/screens/regularPassport/steps/Step5Verification/Step5Verification.tsx index 4f08ec3..e09f374 100644 --- a/src/screens/regularPassport/steps/Step5Verification/Step5Verification.tsx +++ b/src/screens/regularPassport/steps/Step5Verification/Step5Verification.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import {View, Text} from 'react-native'; +import {View, Text, Pressable} from 'react-native'; import {Button} from 'react-native-paper'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; import Colors from '../../../../../assets/styles/Colors'; @@ -9,13 +9,12 @@ type Step5VerificationProps = { setStep: (step: number) => void; setSubStep: (subStep: number) => void; passportAppointmentData: any[]; + showEditDataSheet: () => void; }; -const Step5Content = ({ - setStep, - setSubStep, - passportAppointmentData, -}: Step5VerificationProps) => { +const Step5Content = (props: Step5VerificationProps) => { + const {setStep, setSubStep, passportAppointmentData, showEditDataSheet} = + props; const lastAppointment = passportAppointmentData[passportAppointmentData.length - 1]; @@ -46,11 +45,19 @@ const Step5Content = ({ size={24} color={Colors.indicatorRed.color} /> - + [ + { + transform: [{scale: pressed ? 0.925 : 1}], + }, + ]}> + + diff --git a/src/screens/regularPassport/steps/Step6Processing/Step6Processing.tsx b/src/screens/regularPassport/steps/Step6Processing/Step6Processing.tsx index efb7f1b..0adb0f9 100644 --- a/src/screens/regularPassport/steps/Step6Processing/Step6Processing.tsx +++ b/src/screens/regularPassport/steps/Step6Processing/Step6Processing.tsx @@ -5,16 +5,17 @@ import TextInputComponent from '../../../../components/TextInput'; import styles from '../styles'; import Colors from '../../../../../assets/styles/Colors'; import FontFamily from '../../../../../assets/styles/FontFamily'; +import arrivalDateGuidelinesData from '../../../../data/Steps/ArrivalDateGuidelinesData'; type Step6ProcessingProps = { - setStep: (step: number) => void; - arrivalDateGuidelines: string[]; + showFinalizationConfirmationDialog: () => void; + showPassportTypeInfoDialog: () => void; + showSearchLocationSheet: () => void; }; -const Step6Processing = ({ - setStep, - arrivalDateGuidelines, -}: Step6ProcessingProps) => { +const Step6Processing = (props: Step6ProcessingProps) => { + const {showFinalizationConfirmationDialog, showPassportTypeInfoDialog, showSearchLocationSheet} = + props; return ( @@ -29,18 +30,21 @@ const Step6Processing = ({ + {/* Trigger Search Location Bottom Sheet */} - {/* TODO: Add button information */} @@ -58,7 +62,7 @@ const Step6Processing = ({ - {arrivalDateGuidelines.map((item, index) => ( + {arrivalDateGuidelinesData.map((item, index) => ( • @@ -88,7 +92,7 @@ const Step6Processing = ({ mode="contained" style={[styles.subStepButtonContained, {marginTop: 24}]} textColor={Colors.neutral100.color} - onPress={() => setStep(7)}> + onPress={showFinalizationConfirmationDialog}> Lanjut diff --git a/src/screens/regularPassport/steps/Step7Completion/Step7Completion.tsx b/src/screens/regularPassport/steps/Step7Completion/Step7Completion.tsx index 0d6181d..8ba2757 100644 --- a/src/screens/regularPassport/steps/Step7Completion/Step7Completion.tsx +++ b/src/screens/regularPassport/steps/Step7Completion/Step7Completion.tsx @@ -9,10 +9,12 @@ import Accordion from '../../../../components/Accordion'; import termsAndConditionsData from '../../../../data/Steps/TermsAndContionsData'; type Step7CompletionProps = { - setStep: (step: number) => void; + showSubmitSuccessDialog: () => void; + setLastCompletedSteps: () => void; }; -const Step7Completion = ({setStep}: Step7CompletionProps) => { +const Step7Completion = (props: Step7CompletionProps) => { + const {showSubmitSuccessDialog, setLastCompletedSteps} = props; const lastAppointment = passportAppointmentData[passportAppointmentData.length - 1]; @@ -192,7 +194,10 @@ const Step7Completion = ({setStep}: Step7CompletionProps) => { mode="contained" style={styles.subStepButtonContained} textColor={Colors.neutral100.color} - onPress={() => setStep(6)}> + onPress={() => { + showSubmitSuccessDialog(); + setLastCompletedSteps(); + }}> Kembali ke Halaman Utama diff --git a/src/screens/regularPassport/styles.tsx b/src/screens/regularPassport/styles.tsx index aac3f70..70952e6 100644 --- a/src/screens/regularPassport/styles.tsx +++ b/src/screens/regularPassport/styles.tsx @@ -71,6 +71,7 @@ const styles = StyleSheet.create({ fontSize: 14, ...FontFamily.notoSansRegular, includeFontPadding: false, + lineHeight: 22, color: Colors.primary30.color, }, buttonAgree: {