Finalized all of the passport application flow feature and and adding a feature to add data
This commit is contained in:
110
package-lock.json
generated
110
package-lock.json
generated
@ -8,13 +8,16 @@
|
|||||||
"name": "mpaspor",
|
"name": "mpaspor",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@react-native-async-storage/async-storage": "^2.1.2",
|
||||||
"@react-native-community/datetimepicker": "^8.3.0",
|
"@react-native-community/datetimepicker": "^8.3.0",
|
||||||
"@react-navigation/elements": "^2.3.8",
|
"@react-navigation/elements": "^2.3.8",
|
||||||
"@react-navigation/native": "^7.1.6",
|
"@react-navigation/native": "^7.1.6",
|
||||||
"@react-navigation/native-stack": "^7.3.10",
|
"@react-navigation/native-stack": "^7.3.10",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
|
"moment": "^2.30.1",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-native": "0.78.0",
|
"react-native": "0.78.0",
|
||||||
|
"react-native-calendars": "^1.1311.1",
|
||||||
"react-native-element-dropdown": "^2.12.4",
|
"react-native-element-dropdown": "^2.12.4",
|
||||||
"react-native-paper": "^5.13.2",
|
"react-native-paper": "^5.13.2",
|
||||||
"react-native-safe-area-context": "^5.4.0",
|
"react-native-safe-area-context": "^5.4.0",
|
||||||
@ -2609,6 +2612,18 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-native-async-storage/async-storage": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-dvlNq4AlGWC+ehtH12p65+17V0Dx7IecOWl6WanF2ja38O1Dcjjvn7jVzkUHJ5oWkQBlyASurTPlTHgKXyYiow==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"merge-options": "^3.0.4"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-native": "^0.0.0-0 || >=0.65 <1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@react-native-community/cli": {
|
"node_modules/@react-native-community/cli": {
|
||||||
"version": "15.0.1",
|
"version": "15.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-15.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-15.0.1.tgz",
|
||||||
@ -7576,6 +7591,15 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-plain-obj": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-plain-object": {
|
"node_modules/is-plain-object": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
|
||||||
@ -9182,6 +9206,18 @@
|
|||||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||||
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
|
"integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/merge-options": {
|
||||||
|
"version": "3.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
|
||||||
|
"integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"is-plain-obj": "^2.1.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/merge-stream": {
|
"node_modules/merge-stream": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||||
@ -9678,6 +9714,15 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/moment": {
|
||||||
|
"version": "2.30.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||||
|
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
@ -10557,6 +10602,38 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-calendars": {
|
||||||
|
"version": "1.1311.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-calendars/-/react-native-calendars-1.1311.1.tgz",
|
||||||
|
"integrity": "sha512-/he1+4irh/643SOnnWlEfoAsHhKq2v8WFRMbcXr+dGgf5hcl/TeVgUINw3Vb2SsAxYM2dV+mVCaNJTbMjS025Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"hoist-non-react-statics": "^3.3.1",
|
||||||
|
"lodash": "^4.17.15",
|
||||||
|
"memoize-one": "^5.2.1",
|
||||||
|
"prop-types": "^15.5.10",
|
||||||
|
"react-native-safe-area-context": "4.5.0",
|
||||||
|
"react-native-swipe-gestures": "^1.0.5",
|
||||||
|
"recyclerlistview": "^4.0.0",
|
||||||
|
"xdate": "^0.8.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"moment": "^2.29.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-native-calendars/node_modules/react-native-safe-area-context": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-0WORnk9SkREGUg2V7jHZbuN5x4vcxj/1B0QOcXJjdYWrzZHgLcUzYWWIUecUPJh747Mwjt/42RZDOaFn3L8kPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "*",
|
||||||
|
"react-native": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-native-element-dropdown": {
|
"node_modules/react-native-element-dropdown": {
|
||||||
"version": "2.12.4",
|
"version": "2.12.4",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-element-dropdown/-/react-native-element-dropdown-2.12.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-element-dropdown/-/react-native-element-dropdown-2.12.4.tgz",
|
||||||
@ -10662,6 +10739,12 @@
|
|||||||
"react-native-svg": ">=12.0.0"
|
"react-native-svg": ">=12.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-native-swipe-gestures": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-Ns7Bn9H/Tyw278+5SQx9oAblDZ7JixyzeOczcBK8dipQk2pD7Djkcfnf1nB/8RErAmMLL9iXgW0QHqiII8AhKw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/react-native-vector-icons": {
|
"node_modules/react-native-vector-icons": {
|
||||||
"version": "10.2.0",
|
"version": "10.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-native-vector-icons/-/react-native-vector-icons-10.2.0.tgz",
|
||||||
@ -10832,6 +10915,21 @@
|
|||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/recyclerlistview": {
|
||||||
|
"version": "4.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/recyclerlistview/-/recyclerlistview-4.2.3.tgz",
|
||||||
|
"integrity": "sha512-STR/wj/FyT8EMsBzzhZ1l2goYirMkIgfV3gYEPxI3Kf3lOnu6f7Dryhyw7/IkQrgX5xtTcDrZMqytvteH9rL3g==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash.debounce": "4.0.8",
|
||||||
|
"prop-types": "15.8.1",
|
||||||
|
"ts-object-utils": "0.0.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">= 15.2.1",
|
||||||
|
"react-native": ">= 0.30.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/reflect.getprototypeof": {
|
"node_modules/reflect.getprototypeof": {
|
||||||
"version": "1.0.10",
|
"version": "1.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
|
||||||
@ -12058,6 +12156,12 @@
|
|||||||
"typescript": ">=4.2.0"
|
"typescript": ">=4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ts-object-utils": {
|
||||||
|
"version": "0.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/ts-object-utils/-/ts-object-utils-0.0.5.tgz",
|
||||||
|
"integrity": "sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA==",
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.8.1",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
@ -12569,6 +12673,12 @@
|
|||||||
"async-limiter": "~1.0.0"
|
"async-limiter": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/xdate": {
|
||||||
|
"version": "0.8.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/xdate/-/xdate-0.8.3.tgz",
|
||||||
|
"integrity": "sha512-1NhJWPJwN+VjbkACT9XHbQK4o6exeSVtS2CxhMPwUE7xQakoEFTlwra9YcqV/uHQVyeEUYoYC46VGDJ+etnIiw==",
|
||||||
|
"license": "(MIT OR GPL-2.0)"
|
||||||
|
},
|
||||||
"node_modules/y18n": {
|
"node_modules/y18n": {
|
||||||
"version": "5.0.8",
|
"version": "5.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||||
|
@ -10,13 +10,16 @@
|
|||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@react-native-async-storage/async-storage": "^2.1.2",
|
||||||
"@react-native-community/datetimepicker": "^8.3.0",
|
"@react-native-community/datetimepicker": "^8.3.0",
|
||||||
"@react-navigation/elements": "^2.3.8",
|
"@react-navigation/elements": "^2.3.8",
|
||||||
"@react-navigation/native": "^7.1.6",
|
"@react-navigation/native": "^7.1.6",
|
||||||
"@react-navigation/native-stack": "^7.3.10",
|
"@react-navigation/native-stack": "^7.3.10",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
|
"moment": "^2.30.1",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-native": "0.78.0",
|
"react-native": "0.78.0",
|
||||||
|
"react-native-calendars": "^1.1311.1",
|
||||||
"react-native-element-dropdown": "^2.12.4",
|
"react-native-element-dropdown": "^2.12.4",
|
||||||
"react-native-paper": "^5.13.2",
|
"react-native-paper": "^5.13.2",
|
||||||
"react-native-safe-area-context": "^5.4.0",
|
"react-native-safe-area-context": "^5.4.0",
|
||||||
|
@ -5,15 +5,15 @@ import FontFamily from '../../assets/styles/FontFamily';
|
|||||||
import Colors from '../../assets/styles/Colors';
|
import Colors from '../../assets/styles/Colors';
|
||||||
|
|
||||||
type PassportAppointmentCardProps = {
|
type PassportAppointmentCardProps = {
|
||||||
applicantName: string;
|
applicantName: string | undefined;
|
||||||
applicantCode: string;
|
applicantCode: string | undefined;
|
||||||
appointmentDate: string;
|
appointmentDate: string | undefined;
|
||||||
appointmentTime: string;
|
appointmentTime: string | undefined;
|
||||||
serviceUnit: string;
|
serviceUnit: string | undefined;
|
||||||
status: string;
|
status: string | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderStatusContent = (status: string) => {
|
const renderStatusContent = (status: string | undefined) => {
|
||||||
let backgroundColor;
|
let backgroundColor;
|
||||||
let IconComponent;
|
let IconComponent;
|
||||||
|
|
||||||
|
@ -38,8 +38,8 @@ interface TextInputComponentProps {
|
|||||||
supportText?: string;
|
supportText?: string;
|
||||||
containerHeight?: any;
|
containerHeight?: any;
|
||||||
isMultiline?: boolean;
|
isMultiline?: boolean;
|
||||||
isDropdownSearchLocation?: boolean;
|
isDropdownPressedSheet?: boolean;
|
||||||
handlePressSearchLocation?: () => void;
|
handleDropdownPressed?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TextInputComponent = (props: TextInputComponentProps) => {
|
const TextInputComponent = (props: TextInputComponentProps) => {
|
||||||
@ -59,8 +59,8 @@ const TextInputComponent = (props: TextInputComponentProps) => {
|
|||||||
supportText,
|
supportText,
|
||||||
containerHeight,
|
containerHeight,
|
||||||
isMultiline = false,
|
isMultiline = false,
|
||||||
isDropdownSearchLocation = false,
|
isDropdownPressedSheet = false,
|
||||||
handlePressSearchLocation,
|
handleDropdownPressed,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [secureText, setSecureText] = useState(isPassword);
|
const [secureText, setSecureText] = useState(isPassword);
|
||||||
@ -281,7 +281,7 @@ const TextInputComponent = (props: TextInputComponentProps) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isDropdownSearchLocation) {
|
if (isDropdownPressedSheet) {
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
{title && (
|
{title && (
|
||||||
@ -291,7 +291,7 @@ const TextInputComponent = (props: TextInputComponentProps) => {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={handlePressSearchLocation}
|
onPress={handleDropdownPressed}
|
||||||
style={({pressed}) => ({
|
style={({pressed}) => ({
|
||||||
transform: [{scale: pressed ? 0.99 : 1}],
|
transform: [{scale: pressed ? 0.99 : 1}],
|
||||||
})}>
|
})}>
|
||||||
@ -303,7 +303,14 @@ const TextInputComponent = (props: TextInputComponentProps) => {
|
|||||||
placeholderTextColor={Colors.primary60.color}
|
placeholderTextColor={Colors.primary60.color}
|
||||||
editable={false}
|
editable={false}
|
||||||
value={formattedDate}
|
value={formattedDate}
|
||||||
right={<TextInput.Icon icon="menu-down" color="#48454E" size={20} style={{marginLeft: 24}}/>}
|
right={
|
||||||
|
<TextInput.Icon
|
||||||
|
icon="menu-down"
|
||||||
|
color="#48454E"
|
||||||
|
size={20}
|
||||||
|
style={{marginLeft: 24}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
multiline={false}
|
multiline={false}
|
||||||
textColor="#48454E"
|
textColor="#48454E"
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
|
79
src/components/dialog/DialogLogout.tsx
Normal file
79
src/components/dialog/DialogLogout.tsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {View, Text, StyleSheet} from 'react-native';
|
||||||
|
import {Dialog, Portal, Button} from 'react-native-paper';
|
||||||
|
import Colors from '../../../assets/styles/Colors';
|
||||||
|
import FontFamily from '../../../assets/styles/FontFamily';
|
||||||
|
|
||||||
|
interface DialogLogoutProps {
|
||||||
|
visible: boolean;
|
||||||
|
hideDialog: () => void;
|
||||||
|
onNavigate: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DialogLogout = (props: DialogLogoutProps) => {
|
||||||
|
const {visible, hideDialog, onNavigate} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Portal>
|
||||||
|
<Dialog visible={visible} style={styles.container}>
|
||||||
|
<Dialog.Title style={styles.title}>
|
||||||
|
Apakah Anda yakin akan menutup akun?
|
||||||
|
</Dialog.Title>
|
||||||
|
<View style={styles.content}>
|
||||||
|
<Button
|
||||||
|
style={styles.buttonContained}
|
||||||
|
mode="contained"
|
||||||
|
textColor={Colors.neutral100.color}
|
||||||
|
onPress={() => {
|
||||||
|
hideDialog();
|
||||||
|
onNavigate();
|
||||||
|
}}>
|
||||||
|
Ya, lanjut tutup akun
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
style={styles.buttonOutlined}
|
||||||
|
mode="outlined"
|
||||||
|
textColor={Colors.indicatorRed.color}
|
||||||
|
onPress={() => {
|
||||||
|
hideDialog();
|
||||||
|
}}>
|
||||||
|
Tidak, jangan tutup akun
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</Dialog>
|
||||||
|
</Portal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DialogLogout;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
elevation: 0,
|
||||||
|
shadowColor: 'transparent',
|
||||||
|
borderRadius: 20,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 22,
|
||||||
|
color: Colors.indicatorRed.color,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
marginHorizontal: 24,
|
||||||
|
marginBottom: 24,
|
||||||
|
gap: 16,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
fontSize: 14,
|
||||||
|
...FontFamily.notoSansRegular,
|
||||||
|
includeFontPadding: false,
|
||||||
|
lineHeight: 22,
|
||||||
|
color: Colors.primary30.color,
|
||||||
|
},
|
||||||
|
buttonContained: {
|
||||||
|
backgroundColor: Colors.indicatorRed.color,
|
||||||
|
},
|
||||||
|
buttonOutlined: {
|
||||||
|
borderColor: Colors.indicatorRed.color,
|
||||||
|
},
|
||||||
|
});
|
78
src/components/dialog/DialogWarningApplication.tsx
Normal file
78
src/components/dialog/DialogWarningApplication.tsx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {View, Text, StyleSheet} from 'react-native';
|
||||||
|
import {Dialog, Portal, Button} from 'react-native-paper';
|
||||||
|
import Colors from '../../../assets/styles/Colors';
|
||||||
|
import FontFamily from '../../../assets/styles/FontFamily';
|
||||||
|
|
||||||
|
interface DialogWarningApplicationProps {
|
||||||
|
visible: boolean;
|
||||||
|
hideDialog: () => void;
|
||||||
|
onNavigate: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DialogWarningApplication = (props: DialogWarningApplicationProps) => {
|
||||||
|
const {visible, hideDialog, onNavigate} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Portal>
|
||||||
|
<Dialog visible={visible} style={styles.container}>
|
||||||
|
<Dialog.Title style={styles.title}>Peringatan</Dialog.Title>
|
||||||
|
<View style={styles.content}>
|
||||||
|
<Text style={styles.message}>
|
||||||
|
Silakan melakukan pengisian kuesioner.
|
||||||
|
</Text>
|
||||||
|
<Text style={[styles.message, {...FontFamily.notoSansBold}]}>
|
||||||
|
Pastikan data dan jawaban yang Anda berikan benar.
|
||||||
|
</Text>
|
||||||
|
<Text style={styles.message}>
|
||||||
|
Pemberian keterangan yang tidak benar merupakan pelanggaran
|
||||||
|
keimigrasian sebagaimana ketentuan Pasal 126 huruf c UU No. 6 tahun
|
||||||
|
2011 tentang Keimigrasian dan akan mengakibatkan permohonan paspor
|
||||||
|
Anda ditolak dan pembayaran tidak dapat dikembalikan.
|
||||||
|
</Text>
|
||||||
|
<Button
|
||||||
|
style={styles.button}
|
||||||
|
mode="contained"
|
||||||
|
textColor={Colors.neutral100.color}
|
||||||
|
onPress={() => {
|
||||||
|
hideDialog();
|
||||||
|
onNavigate();
|
||||||
|
}}>
|
||||||
|
Lanjut
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</Dialog>
|
||||||
|
</Portal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DialogWarningApplication;
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
container: {
|
||||||
|
backgroundColor: 'white',
|
||||||
|
elevation: 0,
|
||||||
|
shadowColor: 'transparent',
|
||||||
|
borderRadius: 20,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
fontSize: 22,
|
||||||
|
color: Colors.secondary30.color,
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
marginHorizontal: 24,
|
||||||
|
marginBottom: 24,
|
||||||
|
gap: 16,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
fontSize: 14,
|
||||||
|
...FontFamily.notoSansRegular,
|
||||||
|
includeFontPadding: false,
|
||||||
|
lineHeight: 22,
|
||||||
|
color: Colors.primary30.color,
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
backgroundColor: Colors.primary30.color,
|
||||||
|
marginTop: 12,
|
||||||
|
},
|
||||||
|
});
|
@ -1,95 +1,353 @@
|
|||||||
import {StyleSheet, Text, View} from 'react-native';
|
import {
|
||||||
import {Dialog, Portal, Button} from 'react-native-paper';
|
FlatList,
|
||||||
|
Modal,
|
||||||
|
Pressable,
|
||||||
|
ScrollView,
|
||||||
|
StyleSheet,
|
||||||
|
Text,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
} from 'react-native';
|
||||||
|
import {Portal, Button, Divider, RadioButton} from 'react-native-paper';
|
||||||
import Colors from '../../../assets/styles/Colors';
|
import Colors from '../../../assets/styles/Colors';
|
||||||
import FontFamily from '../../../assets/styles/FontFamily';
|
import FontFamily from '../../../assets/styles/FontFamily';
|
||||||
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
|
import {useState} from 'react';
|
||||||
|
import {Calendar} from 'react-native-calendars';
|
||||||
|
import moment from 'moment';
|
||||||
|
import markedDatesData from '../../data/Steps/MarkedDatesData';
|
||||||
|
import arrivalTimesData from '../../data/Steps/ArrivalTimesData';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
|
onContinue: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const LegendItem = ({color, label, border}: any) => (
|
||||||
|
<View style={styles.legendItemContainer}>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.legendColorBox,
|
||||||
|
{backgroundColor: color},
|
||||||
|
border && styles.legendColorBoxBorder,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Text style={styles.legendLabel}>{label}</Text>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
|
||||||
const SheetSelectDate = (props: Props) => {
|
const SheetSelectDate = (props: Props) => {
|
||||||
const {visible, onClose} = props;
|
const {visible, onClose, onContinue} = props;
|
||||||
|
const [selectedDate, setSelectedDate] = useState('');
|
||||||
|
const [currentMonth, setCurrentMonth] = useState('2025-05-01');
|
||||||
|
const [selectedTimeSlot, setSelectedTimeSlot] = useState('');
|
||||||
|
|
||||||
|
const markedDates = {
|
||||||
|
...markedDatesData,
|
||||||
|
[selectedDate]: {
|
||||||
|
selected: true,
|
||||||
|
selectedColor: Colors.indicatorOrange.color,
|
||||||
|
selectedTextColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderHeaderCalendar = () => {
|
||||||
|
const headerText = moment(currentMonth).format('MMMM YYYY');
|
||||||
|
|
||||||
|
const handleMonthChange = (amount: number) => {
|
||||||
|
const updatedMonth = moment(currentMonth)
|
||||||
|
.add(amount, 'months')
|
||||||
|
.format('YYYY-MM-DD');
|
||||||
|
setCurrentMonth(updatedMonth);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={styles.calendarHeaderContainer}>
|
||||||
|
<Text style={styles.calendarHeaderText}>{headerText}</Text>
|
||||||
|
<View style={styles.calendarNavigation}>
|
||||||
|
<TouchableOpacity onPress={() => handleMonthChange(-1)}>
|
||||||
|
<Icon
|
||||||
|
name="chevron-left"
|
||||||
|
size={24}
|
||||||
|
color={Colors.secondary30.color}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
<TouchableOpacity onPress={() => handleMonthChange(1)}>
|
||||||
|
<Icon
|
||||||
|
name="chevron-right"
|
||||||
|
size={24}
|
||||||
|
color={Colors.secondary30.color}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderTimeSlotItem = ({item}: any) => {
|
||||||
|
return (
|
||||||
|
<View>
|
||||||
|
<Text style={styles.timeSlotTitle}>Jam Kedatangan</Text>
|
||||||
|
<View style={styles.timeSlotRadioGroup}>
|
||||||
|
<View style={styles.timeSlotItem}>
|
||||||
|
<RadioButton
|
||||||
|
value={item.id}
|
||||||
|
status={
|
||||||
|
selectedTimeSlot === item.id ? 'checked' : 'unchecked'
|
||||||
|
}
|
||||||
|
onPress={() => setSelectedTimeSlot(item.id)}
|
||||||
|
color={Colors.secondary30.color}
|
||||||
|
uncheckedColor={Colors.secondary30.color}
|
||||||
|
/>
|
||||||
|
<Text style={styles.timeSlotLabel}>{item.arrivalTime}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.timeSlotQueueInfo}>
|
||||||
|
<View style={styles.queueDetail}>
|
||||||
|
<Text style={styles.queueDetailTitle}>Jumlah Antrian</Text>
|
||||||
|
<Text style={styles.queueDetailValue}>{item.queueCount}</Text>
|
||||||
|
</View>
|
||||||
|
<View style={styles.queueDetail}>
|
||||||
|
<Text style={styles.queueDetailTitle}>Sisa Kuota</Text>
|
||||||
|
<Text style={styles.queueDetailValue}>{item.remainingQuota}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Portal>
|
<Portal>
|
||||||
<Dialog visible={visible} style={styles.dialogContainer}>
|
<Modal visible={visible} transparent animationType="slide">
|
||||||
<Dialog.Title style={styles.dialogTitle}>
|
<Pressable style={styles.modalBackdrop} onPress={onClose} />
|
||||||
Jenis dan Manfaat Paspor
|
<View style={styles.modalContentContainer}>
|
||||||
</Dialog.Title>
|
<ScrollView
|
||||||
<View style={styles.dialogContentContainer}>
|
keyboardShouldPersistTaps="handled"
|
||||||
<Text style={[styles.dialogDesc, {...FontFamily.notoSansBold}]}>
|
showsVerticalScrollIndicator={false}
|
||||||
1. Paspor Biasa
|
contentContainerStyle={styles.modalScrollViewContent}>
|
||||||
</Text>
|
<View style={styles.modalCloseButtonContainer}>
|
||||||
<Text style={styles.dialogDesc}>
|
<Pressable
|
||||||
Biaya pemrosesan lebih murah, tersedia di seluruh lokasi Kanim.
|
style={({pressed}) => [
|
||||||
{'\n'}Biaya pembuatan: Rp350.000
|
styles.closeButton,
|
||||||
</Text>
|
pressed && styles.closeButtonPressed,
|
||||||
<Text style={[styles.dialogDesc, {...FontFamily.notoSansBold}]}>
|
]}
|
||||||
2. Paspor Elektronik
|
onPress={onClose}>
|
||||||
</Text>
|
<Icon name="close" size={24} color={Colors.primary30.color} />
|
||||||
<Text style={styles.dialogDesc}>
|
</Pressable>
|
||||||
Terdapat chip pada cover paspor yang menyimpan data pemegang paspor
|
</View>
|
||||||
sehingga meningkatkan fitur keamanan, tersedia di 35 Kanim.{'\n'}
|
|
||||||
Biaya pembuatan: Rp650.000
|
<View style={styles.calendarContainer}>
|
||||||
</Text>
|
<Calendar
|
||||||
<Text style={[styles.dialogDesc, {...FontFamily.notoSansBold}]}>
|
key={currentMonth}
|
||||||
3. Paspor Elektronik Polikarbonat
|
theme={{
|
||||||
</Text>
|
textDayFontSize: 14,
|
||||||
<Text style={styles.dialogDesc}>
|
textDayStyle: {
|
||||||
Berbahan polikarbonat (PC) pada halaman data pemegang paspor
|
includeFontPadding: false,
|
||||||
(halaman 2) yang memiliki fitur keamanan tinggi dan lebih kuat,
|
marginTop: 6,
|
||||||
tersedia di Kanim Jakarta Selatan, Kanim Jakarta Barat, dan Kanim
|
...FontFamily.notoSansRegular,
|
||||||
Soekarno Hatta.{'\n'}Biaya pembuatan: Rp650.000
|
},
|
||||||
</Text>
|
textDayHeaderFontFamily: 'NotoSans-Medium',
|
||||||
<View>
|
textDayHeaderFontSize: 14,
|
||||||
<Button
|
textSectionTitleColor: Colors.primary30.color,
|
||||||
style={styles.buttonContinue}
|
arrowColor: Colors.secondary30.color,
|
||||||
mode="contained"
|
}}
|
||||||
textColor={Colors.neutral100.color}
|
onDayPress={day => setSelectedDate(day.dateString)}
|
||||||
onPress={() => {
|
markedDates={markedDates}
|
||||||
onClose();
|
hideArrows={true}
|
||||||
}}>
|
current={currentMonth}
|
||||||
Lanjut
|
onMonthChange={month => {
|
||||||
</Button>
|
const newMonth = `${month.year}-${String(
|
||||||
</View>
|
month.month,
|
||||||
|
).padStart(2, '0')}-01`;
|
||||||
|
setCurrentMonth(newMonth);
|
||||||
|
}}
|
||||||
|
renderHeader={renderHeaderCalendar}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Divider style={styles.divider} />
|
||||||
|
|
||||||
|
<View style={styles.legendMainContainer}>
|
||||||
|
<View style={styles.legendColumn}>
|
||||||
|
<LegendItem
|
||||||
|
color={Colors.indicatorGreen.color}
|
||||||
|
label="Kuota tersedia"
|
||||||
|
/>
|
||||||
|
<LegendItem
|
||||||
|
color={Colors.indicatorRed.color}
|
||||||
|
label="Kuota penuh"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View style={styles.legendColumn}>
|
||||||
|
<LegendItem
|
||||||
|
color={Colors.indicatorOrange.color}
|
||||||
|
label="Tanggal terpilih"
|
||||||
|
/>
|
||||||
|
<LegendItem
|
||||||
|
color={Colors.neutral100.color}
|
||||||
|
border
|
||||||
|
label="Kuota belum dibuka"
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<Divider style={styles.divider} />
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<FlatList
|
||||||
|
data={arrivalTimesData}
|
||||||
|
keyExtractor={item => item.id}
|
||||||
|
scrollEnabled={false}
|
||||||
|
renderItem={renderTimeSlotItem}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<View style={styles.continueButtonWrapper}>
|
||||||
|
<Button
|
||||||
|
style={styles.continueButton}
|
||||||
|
mode="contained"
|
||||||
|
textColor={Colors.neutral100.color}
|
||||||
|
onPress={onContinue}>
|
||||||
|
Simpan
|
||||||
|
</Button>
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
</Dialog>
|
</Modal>
|
||||||
</Portal>
|
</Portal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
dialogContainer: {
|
modalBackdrop: {
|
||||||
backgroundColor: 'white',
|
flex: 1,
|
||||||
elevation: 0,
|
backgroundColor: 'rgba(0,0,0,0.3)',
|
||||||
shadowColor: 'transparent',
|
|
||||||
borderRadius: 20,
|
|
||||||
},
|
},
|
||||||
dialogContentContainer: {
|
modalContentContainer: {
|
||||||
marginHorizontal: 24,
|
backgroundColor: 'white',
|
||||||
marginBottom: 24,
|
borderTopLeftRadius: 20,
|
||||||
|
borderTopRightRadius: 20,
|
||||||
|
paddingTop: 24,
|
||||||
|
paddingHorizontal: 16,
|
||||||
|
position: 'absolute',
|
||||||
|
bottom: 0,
|
||||||
|
height: '90%',
|
||||||
|
width: '100%',
|
||||||
|
maxHeight: '90%',
|
||||||
|
},
|
||||||
|
modalScrollViewContent: {
|
||||||
|
paddingBottom: 24,
|
||||||
|
},
|
||||||
|
modalCloseButtonContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
},
|
||||||
|
closeButton: {
|
||||||
|
transform: [{scale: 1}],
|
||||||
|
},
|
||||||
|
closeButtonPressed: {
|
||||||
|
transform: [{scale: 0.925}],
|
||||||
|
},
|
||||||
|
calendarContainer: {
|
||||||
|
marginTop: 8,
|
||||||
|
},
|
||||||
|
calendarHeaderContainer: {
|
||||||
|
width: '100%',
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
marginBottom: 16,
|
||||||
|
},
|
||||||
|
calendarHeaderText: {
|
||||||
|
fontSize: 14,
|
||||||
|
...FontFamily.notoSansBold,
|
||||||
|
color: Colors.secondary30.color,
|
||||||
|
includeFontPadding: false,
|
||||||
|
},
|
||||||
|
calendarNavigation: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
divider: {
|
||||||
|
marginVertical: 16,
|
||||||
|
height: 1,
|
||||||
|
backgroundColor: Colors.primary70.color,
|
||||||
|
},
|
||||||
|
legendMainContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: 32,
|
||||||
|
},
|
||||||
|
legendColumn: {
|
||||||
gap: 16,
|
gap: 16,
|
||||||
},
|
},
|
||||||
dialogTitle: {
|
legendItemContainer: {
|
||||||
fontSize: 22,
|
flexDirection: 'row',
|
||||||
color: Colors.secondary30.color,
|
alignItems: 'center',
|
||||||
|
gap: 4,
|
||||||
},
|
},
|
||||||
dialogDesc: {
|
legendColorBox: {
|
||||||
fontSize: 14,
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
marginRight: 6,
|
||||||
|
borderRadius: 8,
|
||||||
|
},
|
||||||
|
legendColorBoxBorder: {
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: '#ccc',
|
||||||
|
},
|
||||||
|
legendLabel: {
|
||||||
|
fontSize: 11,
|
||||||
...FontFamily.notoSansRegular,
|
...FontFamily.notoSansRegular,
|
||||||
includeFontPadding: false,
|
includeFontPadding: false,
|
||||||
color: Colors.primary30.color,
|
color: Colors.primary30.color,
|
||||||
lineHeight: 22,
|
|
||||||
},
|
},
|
||||||
dialogDescRed: {
|
continueButtonWrapper: {
|
||||||
...FontFamily.notoSansBold,
|
marginTop: 16,
|
||||||
color: Colors.indicatorRed.color,
|
|
||||||
includeFontPadding: false,
|
|
||||||
},
|
},
|
||||||
buttonContinue: {
|
continueButton: {
|
||||||
backgroundColor: Colors.primary30.color,
|
backgroundColor: Colors.primary30.color,
|
||||||
marginTop: 12,
|
},
|
||||||
|
timeSlotTitle: {
|
||||||
|
color: Colors.primary30.color,
|
||||||
|
includeFontPadding: false,
|
||||||
|
fontSize: 12,
|
||||||
|
...FontFamily.notoSansSemiBold,
|
||||||
|
},
|
||||||
|
timeSlotRadioGroup: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
},
|
||||||
|
timeSlotItem: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: 12,
|
||||||
|
alignItems: 'center',
|
||||||
|
marginVertical: 8,
|
||||||
|
},
|
||||||
|
timeSlotLabel: {
|
||||||
|
...FontFamily.notoSansMedium,
|
||||||
|
fontSize: 12,
|
||||||
|
includeFontPadding: false,
|
||||||
|
color: Colors.secondary30.color,
|
||||||
|
marginStart: -8,
|
||||||
|
},
|
||||||
|
timeSlotQueueInfo: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
gap: 12,
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
queueDetail: {
|
||||||
|
gap: 6,
|
||||||
|
},
|
||||||
|
queueDetailTitle: {
|
||||||
|
fontSize: 10.5,
|
||||||
|
includeFontPadding: false,
|
||||||
|
color: Colors.primary30.color,
|
||||||
|
...FontFamily.notoSansBold,
|
||||||
|
},
|
||||||
|
queueDetailValue: {
|
||||||
|
fontSize: 10.5,
|
||||||
|
includeFontPadding: false,
|
||||||
|
color: Colors.primary30.color,
|
||||||
|
...FontFamily.notoSansRegular,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
7
src/data/DropdownData/PassportTypeData.tsx
Normal file
7
src/data/DropdownData/PassportTypeData.tsx
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
const passportTypeData = [
|
||||||
|
{label: 'Paspor Biasa', value: '1'},
|
||||||
|
{label: 'Paspor Elektronik', value: '2'},
|
||||||
|
{label: 'Paspor Elektronik Polikarbonat', value: '3'},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default passportTypeData;
|
@ -41,17 +41,17 @@ const passportAppointmentData = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '3',
|
id: '3',
|
||||||
applicantName: 'Salwa Aisyah Adhani',
|
applicantName: 'Mochammad Adhi Buchori',
|
||||||
applicantCode: '1038000002223344',
|
applicantCode: '1038000002223344',
|
||||||
appointmentDate: 'Senin, 14 April 2025',
|
appointmentDate: 'Senin, 14 April 2025',
|
||||||
appointmentTime: '08:00 - 09:00 WIB',
|
appointmentTime: '08:00 - 09:00 WIB',
|
||||||
serviceUnit: 'Kantor Imigrasi Depok',
|
serviceUnit: 'Kantor Imigrasi Jakarta',
|
||||||
status: 'Menunggu Pembayaran',
|
status: 'Menunggu Pembayaran',
|
||||||
submissionDate: 'Sabtu, 12 April 2025 18:30',
|
submissionDate: 'Sabtu, 12 April 2025 18:30',
|
||||||
serviceCode: 'EH-GT4JWR',
|
serviceCode: 'EH-GT4JWR',
|
||||||
applicationDetails: {
|
applicationDetails: {
|
||||||
nationalIdNumber: '3271234560009120003',
|
nationalIdNumber: '3271234560009120003',
|
||||||
gender: 'Wanita',
|
gender: 'Pria',
|
||||||
applicationType: 'Baru',
|
applicationType: 'Baru',
|
||||||
replacementReason: 'Sekolah di Luar Negeri',
|
replacementReason: 'Sekolah di Luar Negeri',
|
||||||
applicationPurpose: 'Wisata/Liburan',
|
applicationPurpose: 'Wisata/Liburan',
|
||||||
@ -101,26 +101,6 @@ const passportAppointmentData = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '6',
|
id: '6',
|
||||||
applicantName: 'Fadlan Ramadhan',
|
|
||||||
applicantCode: '1038000008885566',
|
|
||||||
appointmentDate: 'Selasa, 18 April 2025',
|
|
||||||
appointmentTime: '09:00 - 10:00 WIB',
|
|
||||||
serviceUnit: 'Kantor Imigrasi Jakarta Barat',
|
|
||||||
status: 'Sudah Terbayar',
|
|
||||||
submissionDate: 'Senin, 14 April 2025 20:00',
|
|
||||||
serviceCode: 'EH-QZ5TVN',
|
|
||||||
applicationDetails: {
|
|
||||||
nationalIdNumber: '3271234560009120006',
|
|
||||||
gender: 'Pria',
|
|
||||||
applicationType: 'Baru',
|
|
||||||
replacementReason: 'Hilang',
|
|
||||||
applicationPurpose: 'Tugas Kantor',
|
|
||||||
passportType: 'PASPOR BIASA NON ELEKTRONIK',
|
|
||||||
fee: '350.000',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '7',
|
|
||||||
applicantName: 'Nabila Khairunisa',
|
applicantName: 'Nabila Khairunisa',
|
||||||
applicantCode: '1038000007773344',
|
applicantCode: '1038000007773344',
|
||||||
appointmentDate: 'Rabu, 19 April 2025',
|
appointmentDate: 'Rabu, 19 April 2025',
|
||||||
@ -139,6 +119,26 @@ const passportAppointmentData = [
|
|||||||
fee: '650.000',
|
fee: '650.000',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: '7',
|
||||||
|
applicantName: 'Ayaka Haishima',
|
||||||
|
applicantCode: '1038000008885566',
|
||||||
|
appointmentDate: 'Selasa, 18 April 2025',
|
||||||
|
appointmentTime: '09:00 - 10:00 WIB',
|
||||||
|
serviceUnit: 'Kantor Imigrasi Jakarta Barat',
|
||||||
|
status: 'Sudah Terbayar',
|
||||||
|
submissionDate: 'Senin, 14 April 2025 20:00',
|
||||||
|
serviceCode: 'EH-QZ5TVN',
|
||||||
|
applicationDetails: {
|
||||||
|
nationalIdNumber: '3271234560009120006',
|
||||||
|
gender: 'Wanita',
|
||||||
|
applicationType: 'Baru',
|
||||||
|
replacementReason: 'Hilang',
|
||||||
|
applicationPurpose: 'Kuliah di Luar Negeri',
|
||||||
|
passportType: 'PASPOR BIASA NON ELEKTRONIK',
|
||||||
|
fee: '350.000',
|
||||||
|
},
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export default passportAppointmentData;
|
export default passportAppointmentData;
|
||||||
|
64
src/data/Steps/ArrivalTimesData.tsx
Normal file
64
src/data/Steps/ArrivalTimesData.tsx
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
const arrivalTimesData = [
|
||||||
|
{
|
||||||
|
id: '1',
|
||||||
|
arrivalTime: '09:01-10:00',
|
||||||
|
queueCount: '4 people',
|
||||||
|
remainingQuota: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
arrivalTime: '10:01-11:00',
|
||||||
|
queueCount: '4 people',
|
||||||
|
remainingQuota: '1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
arrivalTime: '11:01-12:00',
|
||||||
|
queueCount: '3 people',
|
||||||
|
remainingQuota: '2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '4',
|
||||||
|
arrivalTime: '13:01-14:00',
|
||||||
|
queueCount: '1 person',
|
||||||
|
remainingQuota: '4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '5',
|
||||||
|
arrivalTime: '14:01-15:00',
|
||||||
|
queueCount: '2 people',
|
||||||
|
remainingQuota: '3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '6',
|
||||||
|
arrivalTime: '15:01-16:00',
|
||||||
|
queueCount: '5 people',
|
||||||
|
remainingQuota: '0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '7',
|
||||||
|
arrivalTime: '16:01-17:00',
|
||||||
|
queueCount: '3 people',
|
||||||
|
remainingQuota: '2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '8',
|
||||||
|
arrivalTime: '17:01-18:00',
|
||||||
|
queueCount: '2 people',
|
||||||
|
remainingQuota: '3',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '9',
|
||||||
|
arrivalTime: '18:01-19:00',
|
||||||
|
queueCount: '1 person',
|
||||||
|
remainingQuota: '4',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '10',
|
||||||
|
arrivalTime: '19:01-20:00',
|
||||||
|
queueCount: '0 people',
|
||||||
|
remainingQuota: '5',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default arrivalTimesData;
|
129
src/data/Steps/MarkedDatesData.tsx
Normal file
129
src/data/Steps/MarkedDatesData.tsx
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import Colors from '../../../assets/styles/Colors';
|
||||||
|
|
||||||
|
const markedDatesData = {
|
||||||
|
// Kuota penuh (merah)
|
||||||
|
'2025-05-02': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-03': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-04': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-08': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-09': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-10': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-11': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-17': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-18': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-24': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-25': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-30': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-31': {
|
||||||
|
selectedColor: Colors.indicatorRed.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Kuota tersedia (hijau)
|
||||||
|
'2025-05-05': {
|
||||||
|
selectedColor: Colors.indicatorGreen.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-14': {
|
||||||
|
selectedColor: Colors.indicatorGreen.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-15': {
|
||||||
|
selectedColor: Colors.indicatorGreen.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-16': {
|
||||||
|
selectedColor: Colors.indicatorGreen.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-20': {
|
||||||
|
selectedColor: Colors.indicatorGreen.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-28': {
|
||||||
|
selectedColor: Colors.indicatorGreen.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
'2025-05-29': {
|
||||||
|
selectedColor: Colors.indicatorGreen.color,
|
||||||
|
disableTouchEvent: true,
|
||||||
|
selected: true,
|
||||||
|
textColor: Colors.neutral100.color,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default markedDatesData;
|
40
src/helper/asyncStorageHelper.tsx
Normal file
40
src/helper/asyncStorageHelper.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
|
||||||
|
// Fungsi untuk menyimpan data
|
||||||
|
export const storeData = async <T,>(key: string, value: T): Promise<void> => {
|
||||||
|
try {
|
||||||
|
await AsyncStorage.setItem(key, JSON.stringify(value));
|
||||||
|
console.log('Data berhasil disimpan!');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Gagal menyimpan data:', e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fungsi untuk mengambil data
|
||||||
|
export const getData = async <T,>(key: string): Promise<T | null> => {
|
||||||
|
try {
|
||||||
|
const storedData = await AsyncStorage.getItem(key);
|
||||||
|
if (storedData !== null) {
|
||||||
|
return JSON.parse(storedData) as T;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Gagal mengambil data:', e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fungsi untuk menambah data
|
||||||
|
export const addData = async <T,>(key: string, newData: T): Promise<void> => {
|
||||||
|
try {
|
||||||
|
const storedData = await AsyncStorage.getItem(key);
|
||||||
|
if (storedData !== null) {
|
||||||
|
const parsedData: T[] = JSON.parse(storedData);
|
||||||
|
parsedData.push(newData);
|
||||||
|
await AsyncStorage.setItem(key, JSON.stringify(parsedData));
|
||||||
|
console.log('Data berhasil ditambahkan!');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Gagal menambah data:', e);
|
||||||
|
}
|
||||||
|
};
|
@ -54,7 +54,9 @@ function RootStack() {
|
|||||||
options={{headerShown: false}}
|
options={{headerShown: false}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen name="Home" options={{headerShown: false}}>
|
<Stack.Screen name="Home" options={{headerShown: false}}>
|
||||||
{() => <HomeScreen showDialog={() => console.log('Show dialog!')} visible />}
|
{() => (
|
||||||
|
<HomeScreen showDialog={() => {}} visible />
|
||||||
|
)}
|
||||||
</Stack.Screen>
|
</Stack.Screen>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="History"
|
name="History"
|
||||||
@ -66,11 +68,11 @@ function RootStack() {
|
|||||||
component={NotificationScreen}
|
component={NotificationScreen}
|
||||||
options={{headerShown: false}}
|
options={{headerShown: false}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen name="Profile" options={{headerShown: false}}>
|
||||||
name="Profile"
|
{() => (
|
||||||
component={ProfileScreen}
|
<ProfileScreen showDialog={() => {}} visible />
|
||||||
options={{headerShown: false}}
|
)}
|
||||||
/>
|
</Stack.Screen>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
name="EditProfile"
|
name="EditProfile"
|
||||||
component={EditProfileScreen}
|
component={EditProfileScreen}
|
||||||
|
@ -23,3 +23,26 @@ export type RootStackParamList = {
|
|||||||
OtherMethod: undefined;
|
OtherMethod: undefined;
|
||||||
BillingCode: undefined;
|
BillingCode: undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface ApplicationDetails {
|
||||||
|
nationalIdNumber?: string | undefined;
|
||||||
|
gender?: string | undefined;
|
||||||
|
applicationType?: string | undefined;
|
||||||
|
replacementReason?: string | undefined;
|
||||||
|
applicationPurpose?: string | undefined;
|
||||||
|
passportType?: string | undefined;
|
||||||
|
fee?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PassportAppointment {
|
||||||
|
id?: string | undefined;
|
||||||
|
applicantName?: string | undefined;
|
||||||
|
applicantCode?: string | undefined;
|
||||||
|
appointmentDate?: string | undefined;
|
||||||
|
appointmentTime?: string | undefined;
|
||||||
|
serviceUnit?: string | undefined;
|
||||||
|
status?: string | undefined;
|
||||||
|
submissionDate?: string | undefined;
|
||||||
|
serviceCode?: string | undefined;
|
||||||
|
applicationDetails?: ApplicationDetails;
|
||||||
|
}
|
||||||
|
@ -154,6 +154,7 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
...FontFamily.notoSansBold,
|
...FontFamily.notoSansBold,
|
||||||
color: Colors.primary30.color,
|
color: Colors.primary30.color,
|
||||||
|
includeFontPadding: false,
|
||||||
},
|
},
|
||||||
applicantDetailContentChildButton: {
|
applicantDetailContentChildButton: {
|
||||||
marginTop: 8,
|
marginTop: 8,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, {useCallback} from 'react';
|
import React, {useCallback, useEffect, useState} from 'react';
|
||||||
import {FlatList, Pressable, StatusBar, Text, View} from 'react-native';
|
import {FlatList, Pressable, StatusBar, Text, View} from 'react-native';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import Colors from '../../../assets/styles/Colors';
|
import Colors from '../../../assets/styles/Colors';
|
||||||
@ -10,8 +10,10 @@ import {
|
|||||||
useNavigationState,
|
useNavigationState,
|
||||||
} from '@react-navigation/native';
|
} from '@react-navigation/native';
|
||||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
import {RootStackParamList} from '../../navigation/type';
|
import {PassportAppointment, RootStackParamList} from '../../navigation/type';
|
||||||
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
||||||
|
import {getData} from '../../helper/asyncStorageHelper';
|
||||||
|
import {ActivityIndicator} from 'react-native-paper';
|
||||||
|
|
||||||
type HistoryScreenNavigationProp = NativeStackNavigationProp<
|
type HistoryScreenNavigationProp = NativeStackNavigationProp<
|
||||||
RootStackParamList,
|
RootStackParamList,
|
||||||
@ -29,6 +31,28 @@ function HistoryScreen() {
|
|||||||
|
|
||||||
const showNavBackAppBar = previousRoute === 'NavigationRoute';
|
const showNavBackAppBar = previousRoute === 'NavigationRoute';
|
||||||
|
|
||||||
|
const [appointments, setAppointments] = useState<PassportAppointment[]>([]);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
setIsLoading(true); // mulai loading
|
||||||
|
const data = await getData('passportAppointments');
|
||||||
|
if (Array.isArray(data) && data.length > 0) {
|
||||||
|
setAppointments(data);
|
||||||
|
} else {
|
||||||
|
setAppointments([]); // kosongin kalau tidak ada
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching data: ', error);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false); // selesai loading
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
StatusBar.setBackgroundColor(Colors.secondary30.color);
|
StatusBar.setBackgroundColor(Colors.secondary30.color);
|
||||||
@ -60,31 +84,37 @@ function HistoryScreen() {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
<View style={styles.topBackground} />
|
<View style={styles.topBackground} />
|
||||||
<View style={styles.cardWrapper}>
|
{isLoading ? (
|
||||||
<FlatList
|
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
|
||||||
data={passportAppointmentData}
|
<ActivityIndicator size="large" color={Colors.secondary30.color} />
|
||||||
renderItem={({item}) => (
|
</View>
|
||||||
<Pressable
|
) : (
|
||||||
onPress={() =>
|
<View style={styles.cardWrapper}>
|
||||||
navigation.navigate('ApplicationDetail', {data: item})
|
<FlatList
|
||||||
}
|
data={appointments}
|
||||||
style={({pressed}) => ({
|
renderItem={({item}: any) => (
|
||||||
transform: [{scale: pressed ? 0.975 : 1}],
|
<Pressable
|
||||||
})}>
|
onPress={() =>
|
||||||
<PassportAppointmentCard
|
navigation.navigate('ApplicationDetail', {data: item})
|
||||||
applicantName={item.applicantName}
|
}
|
||||||
applicantCode={item.applicantCode}
|
style={({pressed}) => ({
|
||||||
appointmentDate={item.appointmentDate}
|
transform: [{scale: pressed ? 0.975 : 1}],
|
||||||
appointmentTime={item.appointmentTime}
|
})}>
|
||||||
serviceUnit={item.serviceUnit}
|
<PassportAppointmentCard
|
||||||
status={item.status}
|
applicantName={item.applicantName}
|
||||||
/>
|
applicantCode={item.applicantCode}
|
||||||
</Pressable>
|
appointmentDate={item.appointmentDate}
|
||||||
)}
|
appointmentTime={item.appointmentTime}
|
||||||
keyExtractor={item => item.id}
|
serviceUnit={item.serviceUnit}
|
||||||
ItemSeparatorComponent={ItemSeparator}
|
status={item.status}
|
||||||
/>
|
/>
|
||||||
</View>
|
</Pressable>
|
||||||
|
)}
|
||||||
|
keyExtractor={item => item.id ?? ''}
|
||||||
|
ItemSeparatorComponent={ItemSeparator}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -13,15 +13,15 @@ import {
|
|||||||
import Colors from '../../../assets/styles/Colors';
|
import Colors from '../../../assets/styles/Colors';
|
||||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
||||||
import {RootStackParamList} from '../../navigation/type';
|
import {PassportAppointment, RootStackParamList} from '../../navigation/type';
|
||||||
import {useFocusEffect, useNavigation} from '@react-navigation/native';
|
import {useFocusEffect, useNavigation} from '@react-navigation/native';
|
||||||
import RegularPassportIcon from '../../../assets/icons/regular_passport.svg';
|
import RegularPassportIcon from '../../../assets/icons/regular_passport.svg';
|
||||||
import ExpressPassportIcon from '../../../assets/icons/express_passport.svg';
|
import ExpressPassportIcon from '../../../assets/icons/express_passport.svg';
|
||||||
import GuidebookIcon from '../../../assets/icons/guidebook.svg';
|
import GuidebookIcon from '../../../assets/icons/guidebook.svg';
|
||||||
import EazyPassportIcon from '../../../assets/icons/eazy_passport.svg';
|
import EazyPassportIcon from '../../../assets/icons/eazy_passport.svg';
|
||||||
import passportAppointmentData from '../../data/History/PassportAppointmentData';
|
|
||||||
import PassportAppointmentCard from '../../components/PassportAppointmentCard';
|
import PassportAppointmentCard from '../../components/PassportAppointmentCard';
|
||||||
import {useCallback, useRef} from 'react';
|
import {useCallback, useEffect, useRef, useState} from 'react';
|
||||||
|
import {getData} from '../../helper/asyncStorageHelper';
|
||||||
|
|
||||||
type HomeScreenNavigationProp = NativeStackNavigationProp<
|
type HomeScreenNavigationProp = NativeStackNavigationProp<
|
||||||
RootStackParamList,
|
RootStackParamList,
|
||||||
@ -32,6 +32,7 @@ const ItemSeparator = () => <View style={styles.flatllistGap} />;
|
|||||||
|
|
||||||
type RenderContentProps = {
|
type RenderContentProps = {
|
||||||
showDialog: () => void;
|
showDialog: () => void;
|
||||||
|
lastTwoAppointments: PassportAppointment[];
|
||||||
};
|
};
|
||||||
|
|
||||||
const RenderBanner = () => {
|
const RenderBanner = () => {
|
||||||
@ -147,7 +148,10 @@ const RenderBanner = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const RenderContent = ({showDialog}: RenderContentProps) => {
|
const RenderContent = ({
|
||||||
|
showDialog,
|
||||||
|
lastTwoAppointments,
|
||||||
|
}: RenderContentProps) => {
|
||||||
const navigation = useNavigation<HomeScreenNavigationProp>();
|
const navigation = useNavigation<HomeScreenNavigationProp>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -223,8 +227,8 @@ const RenderContent = ({showDialog}: RenderContentProps) => {
|
|||||||
</View>
|
</View>
|
||||||
<View style={styles.cardWrapper}>
|
<View style={styles.cardWrapper}>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={passportAppointmentData.slice(-2)}
|
data={lastTwoAppointments}
|
||||||
renderItem={({item}) => (
|
renderItem={({item}: any) => (
|
||||||
<Pressable
|
<Pressable
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
navigation.navigate('ApplicationDetail', {data: item})
|
navigation.navigate('ApplicationDetail', {data: item})
|
||||||
@ -242,7 +246,7 @@ const RenderContent = ({showDialog}: RenderContentProps) => {
|
|||||||
/>
|
/>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)}
|
)}
|
||||||
keyExtractor={item => item.id}
|
keyExtractor={item => item.id ?? ''}
|
||||||
ItemSeparatorComponent={ItemSeparator}
|
ItemSeparatorComponent={ItemSeparator}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -256,9 +260,28 @@ type HomeScreenProps = {
|
|||||||
readonly visible: boolean;
|
readonly visible: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function HomeScreen({showDialog, visible}: HomeScreenProps) {
|
function HomeScreen(props: HomeScreenProps) {
|
||||||
|
const {showDialog, visible} = props;
|
||||||
const navigation = useNavigation<HomeScreenNavigationProp>();
|
const navigation = useNavigation<HomeScreenNavigationProp>();
|
||||||
|
|
||||||
|
const [lastTwoAppointments, setLastTwoAppointments] = useState<
|
||||||
|
PassportAppointment[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const data = await getData('passportAppointments');
|
||||||
|
if (Array.isArray(data) && data.length > 0) {
|
||||||
|
setLastTwoAppointments(data.slice(-2));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching data: ', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
StatusBar.setBackgroundColor(
|
StatusBar.setBackgroundColor(
|
||||||
@ -276,7 +299,9 @@ function HomeScreen({showDialog, visible}: HomeScreenProps) {
|
|||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.appBarContainer}>
|
<View style={styles.appBarContainer}>
|
||||||
<Text style={styles.appBarTitle}>Halo, X!</Text>
|
<Text style={styles.appBarTitle} numberOfLines={1} ellipsizeMode="tail">
|
||||||
|
Halo, Salwa Aisyah Adhani!
|
||||||
|
</Text>
|
||||||
<Icon
|
<Icon
|
||||||
name="bell-outline"
|
name="bell-outline"
|
||||||
size={24}
|
size={24}
|
||||||
@ -286,7 +311,12 @@ function HomeScreen({showDialog, visible}: HomeScreenProps) {
|
|||||||
</View>
|
</View>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={[{}]}
|
data={[{}]}
|
||||||
renderItem={() => <RenderContent showDialog={showDialog} />}
|
renderItem={() => (
|
||||||
|
<RenderContent
|
||||||
|
showDialog={showDialog}
|
||||||
|
lastTwoAppointments={lastTwoAppointments}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
|
@ -16,6 +16,8 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 28,
|
fontSize: 28,
|
||||||
marginVertical: 14,
|
marginVertical: 14,
|
||||||
includeFontPadding: false,
|
includeFontPadding: false,
|
||||||
|
flex: 1,
|
||||||
|
marginEnd: 16,
|
||||||
},
|
},
|
||||||
appBarContainer: {
|
appBarContainer: {
|
||||||
height: 72,
|
height: 72,
|
||||||
|
@ -13,8 +13,10 @@ import TextInputComponent from '../../components/TextInput';
|
|||||||
import Icon from 'react-native-vector-icons/MaterialIcons';
|
import Icon from 'react-native-vector-icons/MaterialIcons';
|
||||||
import {useNavigation} from '@react-navigation/native';
|
import {useNavigation} from '@react-navigation/native';
|
||||||
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
||||||
import {RootStackParamList} from '../../navigation/type';
|
import {PassportAppointment, RootStackParamList} from '../../navigation/type';
|
||||||
import Colors from '../../../assets/styles/Colors';
|
import Colors from '../../../assets/styles/Colors';
|
||||||
|
import {getData, storeData} from '../../helper/asyncStorageHelper';
|
||||||
|
import passportAppointmentData from '../../data/History/PassportAppointmentData';
|
||||||
|
|
||||||
type LoginScreenNavigationProp = NativeStackNavigationProp<
|
type LoginScreenNavigationProp = NativeStackNavigationProp<
|
||||||
RootStackParamList,
|
RootStackParamList,
|
||||||
@ -48,12 +50,18 @@ function LoginScreen() {
|
|||||||
<Button
|
<Button
|
||||||
style={styles.loginButton}
|
style={styles.loginButton}
|
||||||
mode="contained"
|
mode="contained"
|
||||||
onPress={() =>
|
onPress={async () => {
|
||||||
|
storeData<PassportAppointment[]>(
|
||||||
|
'passportAppointments',
|
||||||
|
passportAppointmentData,
|
||||||
|
);
|
||||||
|
const storedData = await getData('passportAppointments');
|
||||||
|
console.log('Data yang tersimpan:', storedData);
|
||||||
navigation.reset({
|
navigation.reset({
|
||||||
index: 0,
|
index: 0,
|
||||||
routes: [{name: 'NavigationRoute'}],
|
routes: [{name: 'NavigationRoute'}],
|
||||||
})
|
});
|
||||||
}>
|
}}>
|
||||||
Masuk
|
Masuk
|
||||||
</Button>
|
</Button>
|
||||||
<View style={styles.registerAccountContainer}>
|
<View style={styles.registerAccountContainer}>
|
||||||
|
@ -1,23 +1,16 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {
|
import {BottomNavigation, PaperProvider, Text} from 'react-native-paper';
|
||||||
BottomNavigation,
|
|
||||||
Button,
|
|
||||||
Dialog,
|
|
||||||
PaperProvider,
|
|
||||||
Portal,
|
|
||||||
Text,
|
|
||||||
} from 'react-native-paper';
|
|
||||||
import Colors from '../../../assets/styles/Colors';
|
import Colors from '../../../assets/styles/Colors';
|
||||||
import ProfileScreen from '../profile';
|
import ProfileScreen from '../profile';
|
||||||
import styles from './styles';
|
import styles from './styles';
|
||||||
import HomeScreen from '../home';
|
import HomeScreen from '../home';
|
||||||
import HistoryScreen from '../history';
|
import HistoryScreen from '../history';
|
||||||
import {View} from 'react-native';
|
|
||||||
import {useState} from 'react';
|
import {useState} from 'react';
|
||||||
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
||||||
import {RootStackParamList} from '../../navigation/type';
|
import {RootStackParamList} from '../../navigation/type';
|
||||||
import {useNavigation} from '@react-navigation/native';
|
import {useNavigation} from '@react-navigation/native';
|
||||||
import FontFamily from '../../../assets/styles/FontFamily';
|
import DialogWarningApplication from '../../components/dialog/DialogWarningApplication';
|
||||||
|
import DialogLogout from '../../components/dialog/DialogLogout';
|
||||||
|
|
||||||
type NavigationRouteScreenNavigationProp = NativeStackNavigationProp<
|
type NavigationRouteScreenNavigationProp = NativeStackNavigationProp<
|
||||||
RootStackParamList,
|
RootStackParamList,
|
||||||
@ -26,7 +19,11 @@ type NavigationRouteScreenNavigationProp = NativeStackNavigationProp<
|
|||||||
|
|
||||||
function NavigationRouteScreen() {
|
function NavigationRouteScreen() {
|
||||||
const navigation = useNavigation<NavigationRouteScreenNavigationProp>();
|
const navigation = useNavigation<NavigationRouteScreenNavigationProp>();
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
|
const [visibleWarningApplicationDialog, setVisibleWarningApplicationDialog] =
|
||||||
|
useState(false);
|
||||||
|
const [visibleLogoutDialog, setVisibleLogoutDialog] = useState(false);
|
||||||
|
|
||||||
const [index, setIndex] = useState(0);
|
const [index, setIndex] = useState(0);
|
||||||
const [routes] = useState([
|
const [routes] = useState([
|
||||||
{
|
{
|
||||||
@ -48,17 +45,32 @@ function NavigationRouteScreen() {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const showDialog = () => setVisible(true);
|
const showWarningApplicationDialog = () =>
|
||||||
const hideDialog = () => setVisible(false);
|
setVisibleWarningApplicationDialog(true);
|
||||||
|
const hideWarningApplicationDialog = () =>
|
||||||
|
setVisibleWarningApplicationDialog(false);
|
||||||
|
|
||||||
|
const showLogoutDialog = () => setVisibleLogoutDialog(true);
|
||||||
|
const hideLogoutDialog = () => setVisibleLogoutDialog(false);
|
||||||
|
|
||||||
const renderScene = ({route}: {route: {key: string}}) => {
|
const renderScene = ({route}: {route: {key: string}}) => {
|
||||||
switch (route.key) {
|
switch (route.key) {
|
||||||
case 'home':
|
case 'home':
|
||||||
return <HomeScreen showDialog={showDialog} visible={visible} />;
|
return (
|
||||||
|
<HomeScreen
|
||||||
|
visible={visibleWarningApplicationDialog}
|
||||||
|
showDialog={showWarningApplicationDialog}
|
||||||
|
/>
|
||||||
|
);
|
||||||
case 'history':
|
case 'history':
|
||||||
return <HistoryScreen />;
|
return <HistoryScreen />;
|
||||||
case 'profile':
|
case 'profile':
|
||||||
return <ProfileScreen />;
|
return (
|
||||||
|
<ProfileScreen
|
||||||
|
visible={visibleLogoutDialog}
|
||||||
|
showDialog={showLogoutDialog}
|
||||||
|
/>
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -82,35 +94,25 @@ function NavigationRouteScreen() {
|
|||||||
<Text style={styles.bottomNavLabel}>{route.title}</Text>
|
<Text style={styles.bottomNavLabel}>{route.title}</Text>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Portal>
|
{visibleWarningApplicationDialog && (
|
||||||
<Dialog visible={visible} style={styles.dialogContainer}>
|
<DialogWarningApplication
|
||||||
<Dialog.Title style={styles.dialogTitle}>Peringatan</Dialog.Title>
|
visible={visibleWarningApplicationDialog}
|
||||||
<View style={styles.dialogContentContainer}>
|
hideDialog={hideWarningApplicationDialog}
|
||||||
<Text style={styles.dialogDesc}>
|
onNavigate={() => navigation.navigate('RegularPassport')}
|
||||||
Silakan melakukan pengisian kuesioner.
|
/>
|
||||||
</Text>
|
)}
|
||||||
<Text style={[styles.dialogDesc, {...FontFamily.notoSansBold}]}>
|
{visibleLogoutDialog && (
|
||||||
Pastikan data dan jawaban yang Anda berikan benar.
|
<DialogLogout
|
||||||
</Text>
|
visible={visibleLogoutDialog}
|
||||||
<Text style={styles.dialogDesc}>
|
hideDialog={hideLogoutDialog}
|
||||||
Pemberian keterangan yang tidak benar merupakan pelanggaran
|
onNavigate={() =>
|
||||||
keimigrasian sebagaimana ketentuan Pasal 126 huruf c UU No. 6
|
navigation.reset({
|
||||||
tahun 2011 tentang Keimigrasian dan akan mengakibatkan permohonan
|
index: 0,
|
||||||
paspor Anda ditolak dan pembayaran tidak dapat dikembalikan.
|
routes: [{name: 'Login'}],
|
||||||
</Text>
|
})
|
||||||
<Button
|
}
|
||||||
style={styles.buttonContinue}
|
/>
|
||||||
mode="contained"
|
)}
|
||||||
textColor={Colors.neutral100.color}
|
|
||||||
onPress={() => {
|
|
||||||
hideDialog();
|
|
||||||
navigation.navigate('RegularPassport');
|
|
||||||
}}>
|
|
||||||
Lanjut
|
|
||||||
</Button>
|
|
||||||
</View>
|
|
||||||
</Dialog>
|
|
||||||
</Portal>
|
|
||||||
</PaperProvider>
|
</PaperProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -10,32 +10,6 @@ const styles = StyleSheet.create({
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
},
|
},
|
||||||
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,
|
|
||||||
lineHeight: 22,
|
|
||||||
color: Colors.primary30.color,
|
|
||||||
},
|
|
||||||
buttonContinue: {
|
|
||||||
backgroundColor: Colors.primary30.color,
|
|
||||||
marginTop: 12,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default styles;
|
export default styles;
|
||||||
|
@ -13,20 +13,29 @@ type ProfileScreenNavigationProp = NativeStackNavigationProp<
|
|||||||
'Profile'
|
'Profile'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
function ProfileScreen() {
|
type ProfileScreenProps = {
|
||||||
|
readonly showDialog: () => void;
|
||||||
|
readonly visible: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
function ProfileScreen(props: ProfileScreenProps) {
|
||||||
|
const {showDialog, visible} = props;
|
||||||
|
|
||||||
const placeholderProfileImage = require('../../../assets/images/placeholderProfileImage.png');
|
const placeholderProfileImage = require('../../../assets/images/placeholderProfileImage.png');
|
||||||
const navigation = useNavigation<ProfileScreenNavigationProp>();
|
const navigation = useNavigation<ProfileScreenNavigationProp>();
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
StatusBar.setBackgroundColor(Colors.secondary30.color);
|
StatusBar.setBackgroundColor(
|
||||||
|
visible ? '#295E70' : Colors.secondary30.color,
|
||||||
|
);
|
||||||
StatusBar.setBarStyle('light-content');
|
StatusBar.setBarStyle('light-content');
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
StatusBar.setBackgroundColor(Colors.secondary30.color);
|
StatusBar.setBackgroundColor(Colors.secondary30.color);
|
||||||
StatusBar.setBarStyle('light-content');
|
StatusBar.setBarStyle('light-content');
|
||||||
};
|
};
|
||||||
}, []),
|
}, [visible]),
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
@ -35,7 +44,7 @@ function ProfileScreen() {
|
|||||||
</View>
|
</View>
|
||||||
<View style={styles.topContainer}>
|
<View style={styles.topContainer}>
|
||||||
<Image source={placeholderProfileImage} style={styles.profileImage} />
|
<Image source={placeholderProfileImage} style={styles.profileImage} />
|
||||||
<Text style={styles.accountName}>X</Text>
|
<Text style={styles.accountName}>Salwa Aisyah Adhani</Text>
|
||||||
<Text style={styles.accountNumber}>3271234560009123456</Text>
|
<Text style={styles.accountNumber}>3271234560009123456</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.sectionProfileField}>
|
<View style={styles.sectionProfileField}>
|
||||||
@ -80,12 +89,7 @@ function ProfileScreen() {
|
|||||||
mode="outlined"
|
mode="outlined"
|
||||||
textColor={Colors.indicatorRed.color}
|
textColor={Colors.indicatorRed.color}
|
||||||
style={styles.logoutButton}
|
style={styles.logoutButton}
|
||||||
onPress={() =>
|
onPress={showDialog}>
|
||||||
navigation.reset({
|
|
||||||
index: 0,
|
|
||||||
routes: [{name: 'Login'}],
|
|
||||||
})
|
|
||||||
}>
|
|
||||||
Keluar
|
Keluar
|
||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
|
@ -43,6 +43,7 @@ import DialogPassportConditionInfo from '../../components/dialog/DialogPassportC
|
|||||||
import DialogPassportTypeInfo from '../../components/dialog/DialogPassportTypeInfo';
|
import DialogPassportTypeInfo from '../../components/dialog/DialogPassportTypeInfo';
|
||||||
import SheetEditData from '../../components/sheet/SheetEditData';
|
import SheetEditData from '../../components/sheet/SheetEditData';
|
||||||
import SheetSearchLocation from '../../components/sheet/SheetSearchLocation';
|
import SheetSearchLocation from '../../components/sheet/SheetSearchLocation';
|
||||||
|
import SheetSelectDate from '../../components/sheet/SheetSelectDate';
|
||||||
|
|
||||||
type RegularPassportScreenNavigationProp = NativeStackNavigationProp<
|
type RegularPassportScreenNavigationProp = NativeStackNavigationProp<
|
||||||
RootStackParamList,
|
RootStackParamList,
|
||||||
@ -70,6 +71,7 @@ type RenderApplicationStepsContentProps = {
|
|||||||
showPassportTypeInfoDialog: () => void;
|
showPassportTypeInfoDialog: () => void;
|
||||||
showEditDataSheet: () => void;
|
showEditDataSheet: () => void;
|
||||||
showSearchLocationSheet: () => void;
|
showSearchLocationSheet: () => void;
|
||||||
|
showSelectDateSheet: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const RenderApplicationStepsContent = (
|
const RenderApplicationStepsContent = (
|
||||||
@ -96,6 +98,7 @@ const RenderApplicationStepsContent = (
|
|||||||
showPassportTypeInfoDialog,
|
showPassportTypeInfoDialog,
|
||||||
showEditDataSheet,
|
showEditDataSheet,
|
||||||
showSearchLocationSheet,
|
showSearchLocationSheet,
|
||||||
|
showSelectDateSheet,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
if (step === 1) {
|
if (step === 1) {
|
||||||
@ -235,6 +238,7 @@ const RenderApplicationStepsContent = (
|
|||||||
}
|
}
|
||||||
showPassportTypeInfoDialog={showPassportTypeInfoDialog}
|
showPassportTypeInfoDialog={showPassportTypeInfoDialog}
|
||||||
showSearchLocationSheet={showSearchLocationSheet}
|
showSearchLocationSheet={showSearchLocationSheet}
|
||||||
|
showSelectDateSheet={showSelectDateSheet}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 7:
|
case 7:
|
||||||
@ -336,6 +340,7 @@ function RegularPassportScreen() {
|
|||||||
const [visibleEditDataSheet, setVisibleEditDataSheet] = useState(false);
|
const [visibleEditDataSheet, setVisibleEditDataSheet] = useState(false);
|
||||||
const [visibleSearchLocationSheet, setVisibleSearchLocationSheet] =
|
const [visibleSearchLocationSheet, setVisibleSearchLocationSheet] =
|
||||||
useState(false);
|
useState(false);
|
||||||
|
const [visibleSelectDateSheet, setVisibleSelectDateSheet] = useState(false);
|
||||||
|
|
||||||
// Dialog visibility function
|
// Dialog visibility function
|
||||||
const showDialog = () => setVisible(true);
|
const showDialog = () => setVisible(true);
|
||||||
@ -377,6 +382,9 @@ function RegularPassportScreen() {
|
|||||||
const showSearchLocationSheet = () => setVisibleSearchLocationSheet(true);
|
const showSearchLocationSheet = () => setVisibleSearchLocationSheet(true);
|
||||||
const hideSearchLocationSheet = () => setVisibleSearchLocationSheet(false);
|
const hideSearchLocationSheet = () => setVisibleSearchLocationSheet(false);
|
||||||
|
|
||||||
|
const showSelectDateSheet = () => setVisibleSelectDateSheet(true);
|
||||||
|
const hideSelectDateSheet = () => setVisibleSelectDateSheet(false);
|
||||||
|
|
||||||
const stepTitles: {[key: number]: string} = {
|
const stepTitles: {[key: number]: string} = {
|
||||||
1: 'Informasi Pribadi',
|
1: 'Informasi Pribadi',
|
||||||
2: 'Dokumen Pendukung',
|
2: 'Dokumen Pendukung',
|
||||||
@ -457,6 +465,7 @@ function RegularPassportScreen() {
|
|||||||
showPassportTypeInfoDialog={showPassportTypeInfoDialog}
|
showPassportTypeInfoDialog={showPassportTypeInfoDialog}
|
||||||
showEditDataSheet={showEditDataSheet}
|
showEditDataSheet={showEditDataSheet}
|
||||||
showSearchLocationSheet={showSearchLocationSheet}
|
showSearchLocationSheet={showSearchLocationSheet}
|
||||||
|
showSelectDateSheet={showSelectDateSheet}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
@ -501,7 +510,11 @@ function RegularPassportScreen() {
|
|||||||
<DialogSubmitSuccess
|
<DialogSubmitSuccess
|
||||||
visible={visibleSubmitSuccessDialog}
|
visible={visibleSubmitSuccessDialog}
|
||||||
onSubmitSuccess={() => {
|
onSubmitSuccess={() => {
|
||||||
navigation.goBack(), hideSubmitSuccessDialog();
|
navigation.reset({
|
||||||
|
index: 0,
|
||||||
|
routes: [{name: 'NavigationRoute'}],
|
||||||
|
});
|
||||||
|
hideSubmitSuccessDialog();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -542,6 +555,14 @@ function RegularPassportScreen() {
|
|||||||
onClose={hideSearchLocationSheet}
|
onClose={hideSearchLocationSheet}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{visibleSelectDateSheet && (
|
||||||
|
<SheetSelectDate
|
||||||
|
visible={visibleSelectDateSheet}
|
||||||
|
onClose={hideSelectDateSheet}
|
||||||
|
onContinue={hideSelectDateSheet}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Questionnaire
|
<Questionnaire
|
||||||
@ -566,7 +587,9 @@ function RegularPassportScreen() {
|
|||||||
visibleFinalizationConfirmationDialog ||
|
visibleFinalizationConfirmationDialog ||
|
||||||
visiblePassportTypeInfoDialog
|
visiblePassportTypeInfoDialog
|
||||||
? '#295E70'
|
? '#295E70'
|
||||||
: visibleEditDataSheet || visibleSearchLocationSheet
|
: visibleEditDataSheet ||
|
||||||
|
visibleSearchLocationSheet ||
|
||||||
|
visibleSelectDateSheet
|
||||||
? '#185769'
|
? '#185769'
|
||||||
: Colors.secondary30.color
|
: Colors.secondary30.color
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,12 @@ import {Button} from 'react-native-paper';
|
|||||||
import Colors from '../../../../../assets/styles/Colors';
|
import Colors from '../../../../../assets/styles/Colors';
|
||||||
import jobData from '../../../../data/DropdownData/JobData';
|
import jobData from '../../../../data/DropdownData/JobData';
|
||||||
import nationalityData from '../../../../data/DropdownData/NationalityData';
|
import nationalityData from '../../../../data/DropdownData/NationalityData';
|
||||||
|
import {PassportAppointment} from '../../../../navigation/type';
|
||||||
|
import {
|
||||||
|
addData,
|
||||||
|
getData,
|
||||||
|
storeData,
|
||||||
|
} from '../../../../helper/asyncStorageHelper';
|
||||||
|
|
||||||
const Step4DataConfirmationSubStep2 = ({
|
const Step4DataConfirmationSubStep2 = ({
|
||||||
setStep,
|
setStep,
|
||||||
@ -148,7 +154,49 @@ const Step4DataConfirmationSubStep2 = ({
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
mode="contained"
|
mode="contained"
|
||||||
onPress={() => setStep(5)}
|
onPress={async () => {
|
||||||
|
// Ambil data appointment yang sudah tersimpan
|
||||||
|
const storedAppointments: PassportAppointment[] =
|
||||||
|
(await getData('passportAppointments')) || [];
|
||||||
|
|
||||||
|
// Ambil ID terakhir dan hitung ID baru
|
||||||
|
const lastId = storedAppointments.length
|
||||||
|
? Math.max(...storedAppointments.map(item => Number(item.id)))
|
||||||
|
: 0;
|
||||||
|
const nextId = (lastId + 1).toString();
|
||||||
|
|
||||||
|
// Buat appointment baru dengan ID yang sudah dihitung
|
||||||
|
const newAppointment: PassportAppointment = {
|
||||||
|
id: nextId,
|
||||||
|
applicantName: 'Salwa Aisyah Adhani',
|
||||||
|
applicantCode: '1038000008887777',
|
||||||
|
appointmentDate: 'Selasa, 20 Mei 2025',
|
||||||
|
appointmentTime: '10:00-11:00 WIB',
|
||||||
|
serviceUnit: 'Kantor Imigrasi Depok',
|
||||||
|
status: 'Menunggu Pembayaran',
|
||||||
|
submissionDate: 'Kamis, 15 Mei 2025 21:30',
|
||||||
|
serviceCode: 'EH-LP7RNC',
|
||||||
|
applicationDetails: {
|
||||||
|
nationalIdNumber: '3271234560009123456',
|
||||||
|
gender: 'Wanita',
|
||||||
|
applicationType: 'Penggantian Paspor',
|
||||||
|
replacementReason: 'Penuh/Halaman Penuh',
|
||||||
|
applicationPurpose: 'Wisata/Liburan',
|
||||||
|
passportType: 'PASPOR ELEKTRONIK POLIKARBONAT 5 TAHUN',
|
||||||
|
fee: '650.000',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simpan appointment baru
|
||||||
|
await addData<PassportAppointment>(
|
||||||
|
'passportAppointments',
|
||||||
|
newAppointment,
|
||||||
|
);
|
||||||
|
|
||||||
|
const updatedAppointments = await getData('passportAppointments');
|
||||||
|
console.log('Data yang berhasil ditambahkan:', updatedAppointments);
|
||||||
|
setStep(5);
|
||||||
|
}}
|
||||||
style={[styles.subStepButtonContained, {marginBottom: 8}]}
|
style={[styles.subStepButtonContained, {marginBottom: 8}]}
|
||||||
textColor={Colors.neutral100.color}>
|
textColor={Colors.neutral100.color}>
|
||||||
Simpan Draft
|
Simpan Draft
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import React from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import {View, Text, Pressable} from 'react-native';
|
import {View, Text, Pressable} from 'react-native';
|
||||||
import {Button} from 'react-native-paper';
|
import {Button} from 'react-native-paper';
|
||||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
import Colors from '../../../../../assets/styles/Colors';
|
import Colors from '../../../../../assets/styles/Colors';
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
|
import {getData} from '../../../../helper/asyncStorageHelper';
|
||||||
|
import {PassportAppointment} from '../../../../navigation/type';
|
||||||
|
|
||||||
type Step5VerificationProps = {
|
type Step5VerificationProps = {
|
||||||
setStep: (step: number) => void;
|
setStep: (step: number) => void;
|
||||||
@ -15,8 +17,23 @@ type Step5VerificationProps = {
|
|||||||
const Step5Content = (props: Step5VerificationProps) => {
|
const Step5Content = (props: Step5VerificationProps) => {
|
||||||
const {setStep, setSubStep, passportAppointmentData, showEditDataSheet} =
|
const {setStep, setSubStep, passportAppointmentData, showEditDataSheet} =
|
||||||
props;
|
props;
|
||||||
const lastAppointment =
|
|
||||||
passportAppointmentData[passportAppointmentData.length - 1];
|
const [lastAppointment, setLastAppointment] =
|
||||||
|
useState<PassportAppointment>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const data = await getData('passportAppointments');
|
||||||
|
if (Array.isArray(data) && data.length > 0) {
|
||||||
|
setLastAppointment(data[data.length - 1]);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching data: ', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.subStepContainer}>
|
<View style={styles.subStepContainer}>
|
||||||
@ -36,7 +53,7 @@ const Step5Content = (props: Step5VerificationProps) => {
|
|||||||
styles.applicantDetailTextDesc,
|
styles.applicantDetailTextDesc,
|
||||||
{textTransform: 'uppercase', flex: 0},
|
{textTransform: 'uppercase', flex: 0},
|
||||||
]}>
|
]}>
|
||||||
{lastAppointment.applicantName}
|
{lastAppointment?.applicantName}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.applicantDetailIconContentWrapper}>
|
<View style={styles.applicantDetailIconContentWrapper}>
|
||||||
@ -63,27 +80,27 @@ const Step5Content = (props: Step5VerificationProps) => {
|
|||||||
<View style={styles.applicantDetailContentChildContainer}>
|
<View style={styles.applicantDetailContentChildContainer}>
|
||||||
<DetailRow
|
<DetailRow
|
||||||
label="NIK"
|
label="NIK"
|
||||||
value={lastAppointment.applicationDetails.nationalIdNumber}
|
value={lastAppointment?.applicationDetails?.nationalIdNumber}
|
||||||
/>
|
/>
|
||||||
<DetailRow
|
<DetailRow
|
||||||
label="Jenis Kelamin"
|
label="Jenis Kelamin"
|
||||||
value={lastAppointment.applicationDetails.gender}
|
value={lastAppointment?.applicationDetails?.gender}
|
||||||
/>
|
/>
|
||||||
<DetailRow
|
<DetailRow
|
||||||
label="Jenis Permohonan"
|
label="Jenis Permohonan"
|
||||||
value={lastAppointment.applicationDetails.applicationType}
|
value={lastAppointment?.applicationDetails?.applicationType}
|
||||||
/>
|
/>
|
||||||
<DetailRow
|
<DetailRow
|
||||||
label="Alasan Penggantian"
|
label="Alasan Penggantian"
|
||||||
value={lastAppointment.applicationDetails.replacementReason}
|
value={lastAppointment?.applicationDetails?.replacementReason}
|
||||||
/>
|
/>
|
||||||
<DetailRow
|
<DetailRow
|
||||||
label="Tujuan Permohonan"
|
label="Tujuan Permohonan"
|
||||||
value={lastAppointment.applicationDetails.applicationPurpose}
|
value={lastAppointment?.applicationDetails?.applicationPurpose}
|
||||||
/>
|
/>
|
||||||
<DetailRow
|
<DetailRow
|
||||||
label="Jenis Paspor"
|
label="Jenis Paspor"
|
||||||
value={lastAppointment.applicationDetails.passportType}
|
value={lastAppointment?.applicationDetails?.passportType}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@ -110,7 +127,7 @@ const Step5Content = (props: Step5VerificationProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const DetailRow = ({label, value}: {label: string; value: string}) => (
|
const DetailRow = ({label, value}: {label: string; value: string | undefined}) => (
|
||||||
<View style={styles.applicantDetailTextContentWrapper}>
|
<View style={styles.applicantDetailTextContentWrapper}>
|
||||||
<Text style={styles.applicantDetailTextTitle}>{label}</Text>
|
<Text style={styles.applicantDetailTextTitle}>{label}</Text>
|
||||||
<Text style={styles.applicantDetailTextDesc}>{value}</Text>
|
<Text style={styles.applicantDetailTextDesc}>{value}</Text>
|
||||||
|
@ -6,16 +6,22 @@ import styles from '../styles';
|
|||||||
import Colors from '../../../../../assets/styles/Colors';
|
import Colors from '../../../../../assets/styles/Colors';
|
||||||
import FontFamily from '../../../../../assets/styles/FontFamily';
|
import FontFamily from '../../../../../assets/styles/FontFamily';
|
||||||
import arrivalDateGuidelinesData from '../../../../data/Steps/ArrivalDateGuidelinesData';
|
import arrivalDateGuidelinesData from '../../../../data/Steps/ArrivalDateGuidelinesData';
|
||||||
|
import passportTypeData from '../../../../data/DropdownData/PassportTypeData';
|
||||||
|
|
||||||
type Step6ProcessingProps = {
|
type Step6ProcessingProps = {
|
||||||
showFinalizationConfirmationDialog: () => void;
|
showFinalizationConfirmationDialog: () => void;
|
||||||
showPassportTypeInfoDialog: () => void;
|
showPassportTypeInfoDialog: () => void;
|
||||||
showSearchLocationSheet: () => void;
|
showSearchLocationSheet: () => void;
|
||||||
|
showSelectDateSheet: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Step6Processing = (props: Step6ProcessingProps) => {
|
const Step6Processing = (props: Step6ProcessingProps) => {
|
||||||
const {showFinalizationConfirmationDialog, showPassportTypeInfoDialog, showSearchLocationSheet} =
|
const {
|
||||||
props;
|
showFinalizationConfirmationDialog,
|
||||||
|
showPassportTypeInfoDialog,
|
||||||
|
showSearchLocationSheet,
|
||||||
|
showSelectDateSheet,
|
||||||
|
} = props;
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
<View style={styles.subStepContainer}>
|
<View style={styles.subStepContainer}>
|
||||||
@ -30,13 +36,12 @@ const Step6Processing = (props: Step6ProcessingProps) => {
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={[styles.subStepTextInputContainer, {marginVertical: 16}]}>
|
<View style={[styles.subStepTextInputContainer, {marginVertical: 16}]}>
|
||||||
{/* Trigger Search Location Bottom Sheet */}
|
|
||||||
<TextInputComponent
|
<TextInputComponent
|
||||||
title="Lokasi Kantor Imigrasi"
|
title="Lokasi Kantor Imigrasi"
|
||||||
placeholder="Pilih lokasi kantor imigrasi"
|
placeholder="Pilih lokasi kantor imigrasi"
|
||||||
isRequired
|
isRequired
|
||||||
isDropdownSearchLocation
|
isDropdownPressedSheet
|
||||||
handlePressSearchLocation={showSearchLocationSheet}
|
handleDropdownPressed={showSearchLocationSheet}
|
||||||
/>
|
/>
|
||||||
<TextInputComponent
|
<TextInputComponent
|
||||||
title="Jenis Paspor"
|
title="Jenis Paspor"
|
||||||
@ -44,6 +49,7 @@ const Step6Processing = (props: Step6ProcessingProps) => {
|
|||||||
placeholder="Pilih satu jenis paspor"
|
placeholder="Pilih satu jenis paspor"
|
||||||
isRequired
|
isRequired
|
||||||
isDropdown
|
isDropdown
|
||||||
|
dropdownItemData={passportTypeData}
|
||||||
onIconButtonPress={showPassportTypeInfoDialog}
|
onIconButtonPress={showPassportTypeInfoDialog}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@ -80,12 +86,12 @@ const Step6Processing = (props: Step6ProcessingProps) => {
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* TODO: Add calendar functionality here. */}
|
|
||||||
<TextInputComponent
|
<TextInputComponent
|
||||||
title="Tanggal dan Waktu Kedatangan"
|
title="Tanggal dan Waktu Kedatangan"
|
||||||
placeholder="Pilih tanggal dan waktu kedatangan"
|
placeholder="Pilih tanggal dan waktu kedatangan"
|
||||||
isRequired
|
isRequired
|
||||||
isDate
|
isDropdownPressedSheet
|
||||||
|
handleDropdownPressed={showSelectDateSheet}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import React from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import {ScrollView, View} from 'react-native';
|
import {ScrollView, View} from 'react-native';
|
||||||
import {Button, Divider, Text} from 'react-native-paper';
|
import {Button, Divider, Text} from 'react-native-paper';
|
||||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
import Colors from '../../../../../assets/styles/Colors';
|
import Colors from '../../../../../assets/styles/Colors';
|
||||||
import styles from '../styles';
|
import styles from '../styles';
|
||||||
import passportAppointmentData from '../../../../data/History/PassportAppointmentData';
|
|
||||||
import Accordion from '../../../../components/Accordion';
|
import Accordion from '../../../../components/Accordion';
|
||||||
import termsAndConditionsData from '../../../../data/Steps/TermsAndContionsData';
|
import termsAndConditionsData from '../../../../data/Steps/TermsAndContionsData';
|
||||||
|
import {PassportAppointment} from '../../../../navigation/type';
|
||||||
|
import {getData} from '../../../../helper/asyncStorageHelper';
|
||||||
|
|
||||||
type Step7CompletionProps = {
|
type Step7CompletionProps = {
|
||||||
showSubmitSuccessDialog: () => void;
|
showSubmitSuccessDialog: () => void;
|
||||||
@ -15,8 +16,21 @@ type Step7CompletionProps = {
|
|||||||
|
|
||||||
const Step7Completion = (props: Step7CompletionProps) => {
|
const Step7Completion = (props: Step7CompletionProps) => {
|
||||||
const {showSubmitSuccessDialog, setLastCompletedSteps} = props;
|
const {showSubmitSuccessDialog, setLastCompletedSteps} = props;
|
||||||
const lastAppointment =
|
const [lastAppointment, setLastAppointment] = useState<PassportAppointment>();
|
||||||
passportAppointmentData[passportAppointmentData.length - 1];
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const data = await getData('passportAppointments');
|
||||||
|
if (Array.isArray(data) && data.length > 0) {
|
||||||
|
setLastAppointment(data[data.length - 1]);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching data: ', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollView>
|
<ScrollView>
|
||||||
@ -31,7 +45,7 @@ const Step7Completion = (props: Step7CompletionProps) => {
|
|||||||
color={Colors.secondary30.color}
|
color={Colors.secondary30.color}
|
||||||
/>
|
/>
|
||||||
<Text style={styles.midIconContentTextStyle}>
|
<Text style={styles.midIconContentTextStyle}>
|
||||||
{lastAppointment.appointmentDate}
|
{lastAppointment?.appointmentDate}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.midIconContentWrapper}>
|
<View style={styles.midIconContentWrapper}>
|
||||||
@ -41,7 +55,7 @@ const Step7Completion = (props: Step7CompletionProps) => {
|
|||||||
color={Colors.secondary30.color}
|
color={Colors.secondary30.color}
|
||||||
/>
|
/>
|
||||||
<Text style={styles.midIconContentTextStyle}>
|
<Text style={styles.midIconContentTextStyle}>
|
||||||
{lastAppointment.appointmentTime}
|
{lastAppointment?.appointmentTime}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.midIconContentWrapper}>
|
<View style={styles.midIconContentWrapper}>
|
||||||
@ -51,7 +65,7 @@ const Step7Completion = (props: Step7CompletionProps) => {
|
|||||||
color={Colors.secondary30.color}
|
color={Colors.secondary30.color}
|
||||||
/>
|
/>
|
||||||
<Text style={styles.midIconContentTextStyle}>
|
<Text style={styles.midIconContentTextStyle}>
|
||||||
{lastAppointment.serviceUnit}
|
{lastAppointment?.serviceUnit}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@ -60,13 +74,13 @@ const Step7Completion = (props: Step7CompletionProps) => {
|
|||||||
<View style={styles.midTextContentWrapper}>
|
<View style={styles.midTextContentWrapper}>
|
||||||
<Text style={styles.midTextContentTitle}>Tanggal Pengajuan</Text>
|
<Text style={styles.midTextContentTitle}>Tanggal Pengajuan</Text>
|
||||||
<Text style={styles.midTextContentData}>
|
<Text style={styles.midTextContentData}>
|
||||||
{lastAppointment.submissionDate}
|
{lastAppointment?.submissionDate}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.midTextContentWrapper}>
|
<View style={styles.midTextContentWrapper}>
|
||||||
<Text style={styles.midTextContentTitle}>Kode Layanan</Text>
|
<Text style={styles.midTextContentTitle}>Kode Layanan</Text>
|
||||||
<Text style={styles.midTextContentData}>
|
<Text style={styles.midTextContentData}>
|
||||||
{lastAppointment.serviceCode}
|
{lastAppointment?.serviceCode}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
@ -130,7 +144,7 @@ const Step7Completion = (props: Step7CompletionProps) => {
|
|||||||
styles.applicantDetailTextDesc,
|
styles.applicantDetailTextDesc,
|
||||||
styles.applicantDetailTexDescName,
|
styles.applicantDetailTexDescName,
|
||||||
]}>
|
]}>
|
||||||
{lastAppointment.applicantName}
|
{lastAppointment?.applicantName}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.applicantDetailTextContentWrapper}>
|
<View style={styles.applicantDetailTextContentWrapper}>
|
||||||
@ -140,20 +154,20 @@ const Step7Completion = (props: Step7CompletionProps) => {
|
|||||||
styles.applicantDetailTextDesc,
|
styles.applicantDetailTextDesc,
|
||||||
styles.applicantDetailTexDescCode,
|
styles.applicantDetailTexDescCode,
|
||||||
]}>
|
]}>
|
||||||
{lastAppointment.applicantCode}
|
{lastAppointment?.applicantCode}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.applicantDetailContentChildContainer}>
|
<View style={styles.applicantDetailContentChildContainer}>
|
||||||
<View style={styles.applicantDetailTextContentWrapper}>
|
<View style={styles.applicantDetailTextContentWrapper}>
|
||||||
<Text style={styles.applicantDetailTextTitle}>NIK</Text>
|
<Text style={styles.applicantDetailTextTitle}>NIK</Text>
|
||||||
<Text style={styles.applicantDetailTextDesc}>
|
<Text style={styles.applicantDetailTextDesc}>
|
||||||
{lastAppointment.applicationDetails.nationalIdNumber}
|
{lastAppointment?.applicationDetails?.nationalIdNumber}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.applicantDetailTextContentWrapper}>
|
<View style={styles.applicantDetailTextContentWrapper}>
|
||||||
<Text style={styles.applicantDetailTextTitle}>Jenis Kelamin</Text>
|
<Text style={styles.applicantDetailTextTitle}>Jenis Kelamin</Text>
|
||||||
<Text style={styles.applicantDetailTextDesc}>
|
<Text style={styles.applicantDetailTextDesc}>
|
||||||
{lastAppointment.applicationDetails.gender}
|
{lastAppointment?.applicationDetails?.gender}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.applicantDetailTextContentWrapper}>
|
<View style={styles.applicantDetailTextContentWrapper}>
|
||||||
@ -161,7 +175,7 @@ const Step7Completion = (props: Step7CompletionProps) => {
|
|||||||
Jenis Permohonan
|
Jenis Permohonan
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.applicantDetailTextDesc}>
|
<Text style={styles.applicantDetailTextDesc}>
|
||||||
{lastAppointment.applicationDetails.applicationType}
|
{lastAppointment?.applicationDetails?.applicationType}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.applicantDetailTextContentWrapper}>
|
<View style={styles.applicantDetailTextContentWrapper}>
|
||||||
@ -169,7 +183,7 @@ const Step7Completion = (props: Step7CompletionProps) => {
|
|||||||
Alasan Penggantian
|
Alasan Penggantian
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.applicantDetailTextDesc}>
|
<Text style={styles.applicantDetailTextDesc}>
|
||||||
{lastAppointment.applicationDetails.replacementReason}
|
{lastAppointment?.applicationDetails?.replacementReason}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.applicantDetailTextContentWrapper}>
|
<View style={styles.applicantDetailTextContentWrapper}>
|
||||||
@ -177,16 +191,23 @@ const Step7Completion = (props: Step7CompletionProps) => {
|
|||||||
Tujuan Permohonan
|
Tujuan Permohonan
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={styles.applicantDetailTextDesc}>
|
<Text style={styles.applicantDetailTextDesc}>
|
||||||
{lastAppointment.applicationDetails.applicationPurpose}
|
{lastAppointment?.applicationDetails?.applicationPurpose}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.applicantDetailTextContentWrapper}>
|
<View style={styles.applicantDetailTextContentWrapper}>
|
||||||
<Text style={styles.applicantDetailTextTitle}>Jenis Paspor</Text>
|
<Text style={styles.applicantDetailTextTitle}>Jenis Paspor</Text>
|
||||||
<Text style={styles.applicantDetailTextDesc}>
|
<Text style={styles.applicantDetailTextDesc}>
|
||||||
{lastAppointment.applicationDetails.passportType}
|
{lastAppointment?.applicationDetails?.passportType}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
<Divider style={styles.applicantDetailDividerMargin} />
|
||||||
|
<View style={styles.applicantDetailBottomContentWrapper}>
|
||||||
|
<Text style={styles.applicantDetailBottomText}>Biaya</Text>
|
||||||
|
<Text style={styles.applicantDetailBottomText}>
|
||||||
|
{lastAppointment?.applicationDetails?.fee}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View style={{margin: 16}}>
|
<View style={{margin: 16}}>
|
||||||
|
@ -200,6 +200,15 @@ const styles = StyleSheet.create({
|
|||||||
applicantDetailTexDescCode: {
|
applicantDetailTexDescCode: {
|
||||||
textAlign: 'right',
|
textAlign: 'right',
|
||||||
},
|
},
|
||||||
|
applicantDetailBottomText: {
|
||||||
|
fontSize: 14,
|
||||||
|
...FontFamily.notoSansBold,
|
||||||
|
color: Colors.primary30.color,
|
||||||
|
includeFontPadding: false,
|
||||||
|
},
|
||||||
|
applicantDetailDividerMargin: {
|
||||||
|
marginVertical: 4,
|
||||||
|
},
|
||||||
midContainer: {
|
midContainer: {
|
||||||
backgroundColor: Colors.neutral100.color,
|
backgroundColor: Colors.neutral100.color,
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user