Intial commit

This commit is contained in:
Mochammad Adhi Buchori
2025-04-18 17:33:44 +07:00
parent a17842fc9e
commit ef2bc641ac
175 changed files with 2904 additions and 137 deletions

View File

@ -0,0 +1,54 @@
import React, {forwardRef} from 'react';
import {TextInput, StyleSheet, View} from 'react-native';
import Colors from '../../assets/styles/Colors';
import FontFamily from '../../assets/styles/FontFamily';
const OTPTextInput = forwardRef((props: any, ref: any) => {
const {value, onChangeText, onKeyPress} = props;
const handleChange = (text: string) => {
if (/^\d?$/.test(text)) {
onChangeText(text);
}
};
return (
<View style={styles.box}>
<TextInput
ref={ref}
value={value}
onChangeText={handleChange}
onKeyPress={onKeyPress}
style={styles.input}
keyboardType="number-pad"
maxLength={1}
selectionColor={Colors.primary30.color}
/>
</View>
);
});
const styles = StyleSheet.create({
box: {
width: 48,
height: 48,
borderRadius: 12,
borderWidth: 1,
borderColor: Colors.primary60.color,
justifyContent: 'center',
alignItems: 'center',
},
input: {
fontSize: 16,
color: 'black',
textAlign: 'center',
padding: 0,
margin: 0,
width: '100%',
height: '100%',
...FontFamily.notoSansBold,
includeFontPadding: false,
},
});
export default OTPTextInput;

View File

@ -0,0 +1,217 @@
import * as React from 'react';
import {Platform, Pressable, StyleSheet, Text, View} from 'react-native';
import {TextInput} from 'react-native-paper';
import Icon from 'react-native-vector-icons/MaterialIcons';
import Colors from '../../assets/styles/Colors';
import FontFamily from '../../assets/styles/FontFamily';
import DateTimePicker from '@react-native-community/datetimepicker';
import {useState} from 'react';
import {Dropdown} from 'react-native-element-dropdown';
interface TextInputComponentProps {
title?: string;
placeholder?: string;
isPassword?: boolean;
isRequired?: boolean;
isDate?: boolean;
isDropdown?: boolean;
}
const genderData = [
{label: 'Laki-Laki', value: '1'},
{label: 'Perempuan', value: '2'},
];
const TextInputComponent: React.FC<TextInputComponentProps> = ({
title,
placeholder,
isPassword = false,
isRequired = false,
isDate = false,
isDropdown = false,
}) => {
const [secureText, setSecureText] = useState(isPassword);
const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined);
const [formattedDate, setFormattedDate] = useState<string>('');
const [showPicker, setShowPicker] = useState(false);
const [genderValue, setGenderValue] = useState(null);
const renderGenderItem = (item: any) => {
return (
<View style={styles.genderItem}>
<Text style={styles.genderTextItem}>{item.label}</Text>
</View>
);
};
const handleDateChange = (event: any, date?: Date) => {
if (event.type === 'dismissed') {
setShowPicker(false);
return;
}
if (date) {
setShowPicker(Platform.OS === 'ios');
setSelectedDate(date);
const formatted = `${String(date.getDate()).padStart(2, '0')}/${String(
date.getMonth() + 1,
).padStart(2, '0')}/${date.getFullYear()}`;
setFormattedDate(formatted);
}
};
const renderInput = () => {
if (isDropdown) {
return (
<View>
{title && (
<View style={styles.titleContainer}>
<Text style={styles.title}>{title}</Text>
{isRequired && <Text style={styles.required}>*</Text>}
</View>
)}
<Dropdown
style={styles.dropdown}
placeholderStyle={styles.placeholderDropdownStyle}
selectedTextStyle={styles.selectedTextStyle}
iconStyle={styles.iconStyle}
data={genderData}
maxHeight={300}
labelField="label"
valueField="value"
placeholder="Jenis Kelamin"
value={genderValue}
onChange={item => {
setGenderValue(item.value);
}}
renderRightIcon={() => <Icon name="arrow-drop-down" size={20} />}
renderItem={renderGenderItem}
/>
</View>
);
}
if (isDate) {
return (
<View>
<View style={styles.titleContainer}>
{title && <Text style={styles.title}>{title}</Text>}
{isRequired && <Text style={styles.required}>*</Text>}
</View>
<Pressable onPress={() => setShowPicker(true)}>
<TextInput
mode="outlined"
placeholder={placeholder}
style={[styles.containerBackground, styles.placeholderText]}
theme={{roundness: 12}}
placeholderTextColor={Colors.primary60.color}
editable={false}
value={formattedDate}
right={<TextInput.Icon icon="calendar" />}
multiline={false}
/>
</Pressable>
{showPicker && (
<DateTimePicker
value={selectedDate || new Date()}
mode="date"
display="calendar"
onChange={handleDateChange}
/>
)}
</View>
);
}
return (
<View>
{title && (
<View style={styles.titleContainer}>
<Text style={styles.title}>{title}</Text>
{isRequired && <Text style={styles.required}>*</Text>}
</View>
)}
<TextInput
mode="outlined"
placeholder={placeholder}
style={[styles.containerBackground, styles.placeholderText]}
theme={{roundness: 12}}
placeholderTextColor={Colors.primary60.color}
activeOutlineColor={Colors.primary10.color}
secureTextEntry={secureText}
right={
isPassword ? (
<TextInput.Icon
icon={secureText ? 'eye-off' : 'eye'}
onPress={() => setSecureText(prev => !prev)}
forceTextInputFocus={false}
/>
) : null
}
multiline={false}
/>
</View>
);
};
return <View>{renderInput()}</View>;
};
const styles = StyleSheet.create({
containerBackground: {
backgroundColor: Colors.neutral100.color,
marginTop: 8,
},
title: {
...FontFamily.notoSansBold,
fontSize: 12,
},
titleContainer: {
flexDirection: 'row',
gap: 5,
},
required: {
...FontFamily.notoSansBold,
fontSize: 12,
color: Colors.indicatorRed.color,
},
placeholderText: {
fontSize: 13,
...FontFamily.notoSansRegular,
},
genderItem: {
padding: 16,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
genderTextItem: {
flex: 1,
fontSize: 13,
},
dropdown: {
marginTop: 8,
backgroundColor: 'white',
borderRadius: 12,
paddingVertical: 16,
paddingStart: 16,
paddingEnd: 8,
borderWidth: 1,
borderColor: Colors.primary40.color,
},
placeholderDropdownStyle: {
fontSize: 13,
...FontFamily.notoSansRegular,
color: Colors.primary60.color,
},
selectedTextStyle: {
fontSize: 13,
...FontFamily.notoSansRegular,
},
iconStyle: {
width: 20,
height: 20,
},
});
export default TextInputComponent;

View File

@ -0,0 +1,74 @@
import React from 'react';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import LoginScreen from '../screens/login';
import RegisterScreen from '../screens/register';
import AccountVerificationScreen from '../screens/accountVerification';
import HomeScreen from '../screens/home';
import HistoryScreen from '../screens/history';
import NotificationScreen from '../screens/notification';
import ProfileScreen from '../screens/profile';
import EditProfileScreen from '../screens/editProfile';
import CloseAccountScreen from '../screens/closeAccount';
import {RootStackParamList} from './type';
import TermsAndConnditionsScreen from '../screens/termsAndConditions';
const Stack = createNativeStackNavigator<RootStackParamList>();
function RootStack() {
return (
<Stack.Navigator initialRouteName="Login">
<Stack.Screen
name="Login"
component={LoginScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="Register"
component={RegisterScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="AccountVerification"
component={AccountVerificationScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="TermsAndConditions"
component={TermsAndConnditionsScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="Home"
component={HomeScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="History"
component={HistoryScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="Notification"
component={NotificationScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="Profile"
component={ProfileScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="EditProfile"
component={EditProfileScreen}
options={{headerShown: false}}
/>
<Stack.Screen
name="CloseAccount"
component={CloseAccountScreen}
options={{headerShown: false}}
/>
</Stack.Navigator>
);
}
export default RootStack;

12
src/navigation/type.ts Normal file
View File

@ -0,0 +1,12 @@
export type RootStackParamList = {
Login: undefined;
Home: undefined;
Register: undefined;
AccountVerification: undefined;
TermsAndConditions: undefined;
History: undefined;
Notification: undefined;
Profile: undefined;
EditProfile: undefined;
CloseAccount: undefined;
};

View File

@ -0,0 +1,92 @@
import {useNavigation} from '@react-navigation/native';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import React, {useEffect, useRef, useState} from 'react';
import {Pressable, Text, View, TextInput, Keyboard} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import {RootStackParamList} from '../../navigation/type';
import styles from './styles';
import {Button} from 'react-native-paper';
import OTPTextInput from '../../components/OTPTextInput';
type AccountVerificationScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'AccountVerification'
>;
function AccountVerificationScreen() {
const navigation = useNavigation<AccountVerificationScreenNavigationProp>();
const [otp, setOtp] = useState(Array(6).fill(''));
const inputRefs = useRef<TextInput[]>([]);
const handleChange = (text: string, index: number) => {
const newOtp = [...otp];
newOtp[index] = text;
setOtp(newOtp);
if (text && index < 5) {
inputRefs.current[index + 1]?.focus();
}
};
const handleKeyPress = (e: any, index: number) => {
if (e.nativeEvent.key === 'Backspace') {
const newOtp = [...otp];
newOtp[index] = '';
setOtp(newOtp);
if (index > 0) {
inputRefs.current[index - 1]?.focus();
}
}
};
useEffect(() => {
Keyboard.dismiss();
setTimeout(() => {
inputRefs.current[0]?.focus();
}, 100);
}, []);
return (
<View style={styles.container}>
<View style={styles.appBarContainer}>
<Pressable onPress={() => navigation.goBack()}>
<Icon name="arrow-back" size={24} style={styles.arrowBackIcon} />
</Pressable>
</View>
<View style={styles.accountVerificationTextWrapper}>
<Text style={styles.accountVerificationTitleText}>Verifikasi Akun</Text>
<Text style={styles.accountVerificationDescText}>
Kode OTP telah dikirim ke email Anda. Mohon masukkan kode tersebut
untuk verifikasi akun.
</Text>
</View>
<View style={styles.OTPTextInputContainer}>
<View style={styles.OTPTextInputRowContainer}>
{otp.map((digit: any, index: any) => (
<OTPTextInput
key={index}
ref={(ref: any) => (inputRefs.current[index] = ref!)}
value={digit}
onChangeText={(text: string) => handleChange(text, index)}
onKeyPress={(e: any) => handleKeyPress(e, index)}
/>
))}
</View>
<Text style={styles.OTPTimeText}>
Kirim ulang kode OTP dalam 10 detik
</Text>
</View>
<Text style={styles.sendOTPText}>Kirim Ulang Kode OTP</Text>
<Button
mode="contained"
style={styles.accountVerificationButton}
onPress={() => navigation.navigate('Home')}>
Lanjut
</Button>
</View>
);
}
export default AccountVerificationScreen;

View File

@ -0,0 +1,61 @@
import {StyleSheet} from 'react-native';
import FontFamily from '../../../assets/styles/FontFamily';
import Colors from '../../../assets/styles/Colors';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
appBarContainer: {
height: 64,
justifyContent: 'center',
},
arrowBackIcon: {
marginLeft: 16,
color: Colors.secondary30.color,
},
accountVerificationTextWrapper: {
marginHorizontal: 16,
},
accountVerificationTitleText: {
color: Colors.secondary30.color,
...FontFamily.notoSansExtraBold,
fontSize: 18,
},
accountVerificationDescText: {
...FontFamily.notoSansRegular,
fontSize: 12,
textAlign: 'justify',
},
OTPTextInputContainer: {
marginTop: 40,
marginHorizontal: 16,
},
OTPTimeText: {
marginTop: 16,
textAlign: 'center',
...FontFamily.notoSansRegular,
color: Colors.primary50.color,
},
sendOTPText: {
marginTop: 40,
marginHorizontal: 16,
textAlign: 'center',
color: Colors.primary30.color,
...FontFamily.notoSansSemiBold,
fontSize: 12,
},
accountVerificationButton: {
marginHorizontal: 16,
marginTop: 16,
backgroundColor: Colors.primary30.color,
},
OTPTextInputRowContainer: {
flexDirection: 'row',
gap: 6,
justifyContent: 'center',
},
});
export default styles;

View File

@ -0,0 +1,21 @@
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
function CloseAccountScreen() {
return (
<View style={styles.container}>
<Text>Close Screen</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default CloseAccountScreen;

View File

@ -0,0 +1,21 @@
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
function EditProfileScreen() {
return (
<View style={styles.container}>
<Text>Edit Screen</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default EditProfileScreen;

View File

@ -0,0 +1,21 @@
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
function HistoryScreen() {
return (
<View style={styles.container}>
<Text>History Screen</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default HistoryScreen;

View File

@ -0,0 +1,21 @@
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
function HomeScreen() {
return (
<View style={styles.container}>
<Text>Home Screen</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default HomeScreen;

View File

@ -0,0 +1,80 @@
import React from 'react';
import {Image, Pressable, ScrollView, Text, View} from 'react-native';
import styles from './styles';
import {Button} from 'react-native-paper';
import TextInputComponent from '../../components/TextInput';
import Icon from 'react-native-vector-icons/MaterialIcons';
import {useNavigation} from '@react-navigation/native';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {RootStackParamList} from '../../navigation/type';
type LoginScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'Login'
>;
function LoginScreen() {
const welcomeImage = require('../../../assets/images/welcomeImage.png');
const navigation = useNavigation<LoginScreenNavigationProp>();
return (
<ScrollView style={styles.container}>
<Image source={welcomeImage} style={styles.welcomeImage} />
<View style={styles.contentContainer}>
<Text style={styles.welcomeText}>
Selamat Datang di Aplikasi M-Paspor!
</Text>
<View style={styles.textInputContainer}>
<TextInputComponent title="Email" placeholder="Masukkan Email" />
<TextInputComponent
title="Password"
placeholder="Masukkan Password"
isPassword={true}
/>
</View>
<Text style={styles.forgotPasswordText}>Lupa kata sandi?</Text>
<Button
style={styles.loginButton}
mode="contained"
onPress={() => navigation.navigate('Home')}>
Masuk
</Button>
<View style={styles.registerAccountContainer}>
<Text style={styles.dontHaveAccountText}>Belum memiliki akun?</Text>
<Pressable onPress={() => navigation.navigate('Register')}>
<Text style={styles.registerAccountText}>Daftar akun</Text>
</Pressable>
</View>
</View>
<Pressable
onPress={() => navigation.navigate('TermsAndConditions')}
style={({pressed}) => [{transform: [{scale: pressed ? 0.975 : 1}]}]}>
<View style={styles.termsAndConditionsContainer}>
<Icon
name="person"
size={20}
color="#000"
style={styles.personIcon}
/>
<View style={styles.termsAndConditionsTextContainer}>
<Text style={styles.termsAndConditionsTitle}>
Syarat & Ketentuan
</Text>
<Text style={styles.termsAndConditionsDescription}>
Panduan pendaftaran dan informasi untuk mengajukan permohonan
paspor
</Text>
</View>
<Icon
name="arrow-right"
size={20}
color="#000"
style={styles.arrowRightIcon}
/>
</View>
</Pressable>
</ScrollView>
);
}
export default LoginScreen;

View File

@ -0,0 +1,92 @@
import {StyleSheet} from 'react-native';
import Colors from '../../../assets/styles/Colors';
import FontFamily from '../../../assets/styles/FontFamily';
const styles = StyleSheet.create({
container: {
backgroundColor: Colors.secondary70.color,
flex: 1,
},
contentContainer: {
alignSelf: 'stretch',
backgroundColor: Colors.neutral100.color,
marginHorizontal: 16,
padding: 20,
borderRadius: 20,
},
welcomeImage: {
width: '100%',
height: 275,
resizeMode: 'stretch',
},
welcomeText: {
color: Colors.secondary30.color,
...FontFamily.notoSansExtraBold,
fontSize: 24,
marginBottom: 24,
},
loginButton: {
marginTop: 24,
backgroundColor: Colors.primary30.color,
},
registerAccountContainer: {
flexDirection: 'row',
justifyContent: 'center',
gap: 5,
marginTop: 16,
},
forgotPasswordText: {
marginTop: 16,
fontSize: 12,
...FontFamily.notoSansSemiBold,
color: Colors.secondary40.color,
},
textInputContainer: {
gap: 16,
},
registerAccountText: {
color: Colors.secondary40.color,
fontSize: 12,
...FontFamily.notoSansSemiBold,
},
dontHaveAccountText: {
color: Colors.primary30.color,
fontSize: 12,
...FontFamily.notoSansRegular,
},
termsAndConditionsContainer: {
alignSelf: 'stretch',
backgroundColor: Colors.neutral100.color,
flexDirection: 'row',
marginHorizontal: 16,
justifyContent: 'center',
alignItems: 'center',
paddingVertical: 16,
borderRadius: 20,
marginTop: 16,
marginBottom: 40,
},
termsAndConditionsTitle: {
...FontFamily.notoSansMedium,
fontSize: 14,
color: Colors.primary30.color,
},
termsAndConditionsDescription: {
...FontFamily.notoSansRegular,
fontSize: 11,
marginTop: 4,
color: Colors.primary40.color,
},
termsAndConditionsTextContainer: {
marginHorizontal: 10,
flex: 1,
},
arrowRightIcon: {
marginRight: 20,
},
personIcon: {
marginLeft: 20,
},
});
export default styles;

View File

@ -0,0 +1,21 @@
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
function NotificationScreen() {
return (
<View style={styles.container}>
<Text>Notification Screen</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default NotificationScreen;

View File

@ -0,0 +1,21 @@
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
function ProfileScreen() {
return (
<View style={styles.container}>
<Text>Profile Screen</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default ProfileScreen;

View File

@ -0,0 +1,126 @@
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import React, {useState} from 'react';
import {Pressable, ScrollView, Text, View} from 'react-native';
import {RootStackParamList} from '../../navigation/type';
import {CommonActions, useNavigation} from '@react-navigation/native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import styles from './styles';
import TextInputComponent from '../../components/TextInput';
import {Button, Checkbox} from 'react-native-paper';
import Colors from '../../../assets/styles/Colors';
type RegisterScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'Register'
>;
function RegisterScreen() {
const navigation = useNavigation<RegisterScreenNavigationProp>();
const [checked, setChecked] = useState(false);
return (
<View style={styles.container}>
<View style={styles.appBarContainer}>
<Pressable onPress={() => navigation.goBack()}>
<Icon name="arrow-back" size={24} style={styles.arrowBackIcon} />
</Pressable>
</View>
<ScrollView>
<View style={styles.registerTextWrapper}>
<Text style={styles.accountRegistrationTitleText}>
Pendaftaran Akun
</Text>
<Text style={styles.accountRegistrationDescText}>
Buat akun untuk dapat masuk ke aplikasi
</Text>
</View>
<View style={styles.textInputContainer}>
<TextInputComponent
title="Nama Lengkap"
placeholder="Masukkan Nama Lengkap"
isRequired
/>
<View style={styles.textInputRowContainer}>
<View style={styles.textInputFlex}>
<TextInputComponent
title="Tanggal Lahir"
placeholder="DD/MM/YYYY"
isRequired
isDate
/>
</View>
<View style={styles.textInputFlex}>
<TextInputComponent
title="Jenis Kelamin"
placeholder="Jenis Kelamin"
isRequired
isDropdown
/>
</View>
</View>
<TextInputComponent
title="Email"
placeholder="Masukkan Email"
isRequired
/>
<TextInputComponent
title="Nomor Telepon"
placeholder="Masukkan Nomor Telepon"
isRequired
/>
<TextInputComponent
title="Kata Sandi"
placeholder="Masukkan Kata Sandi"
isPassword
isRequired
/>
<TextInputComponent
title="Ulang Kata Sandi"
placeholder="Konfirmasi Kata Sandi"
isPassword
isRequired
/>
</View>
<View style={styles.acceptTermsAndConditionsContainer}>
<Checkbox
status={checked ? 'checked' : 'unchecked'}
onPress={() => setChecked(!checked)}
color={Colors.primary30.color}
/>
<Text style={styles.termsAndConditionsDesc}>
Saya telah membaca dan menyetujui{' '}
<Text
style={styles.termsHighlight}
onPress={() => navigation.navigate('TermsAndConditions')}>
Syarat & Ketentuan
</Text>{' '}
yang berlaku
</Text>
</View>
<Button
style={styles.registerButton}
mode="contained"
onPress={() => navigation.navigate('AccountVerification')}>
Daftar Akun
</Button>
<View style={styles.loginDescContainer}>
<Text style={styles.loginDescText}>Sudah memiliki akun?</Text>
<Text
style={styles.loginHighlight}
onPress={() =>
navigation.dispatch(
CommonActions.reset({
index: 0,
routes: [{name: 'Login'}],
}),
)
}>
Masuk
</Text>
</View>
</ScrollView>
</View>
);
}
export default RegisterScreen;

View File

@ -0,0 +1,83 @@
import {StyleSheet} from 'react-native';
import Colors from '../../../assets/styles/Colors';
import FontFamily from '../../../assets/styles/FontFamily';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
appBarContainer: {
height: 64,
justifyContent: 'center',
},
arrowBackIcon: {
marginLeft: 16,
color: Colors.secondary30.color,
},
registerTextWrapper: {
marginHorizontal: 16,
},
accountRegistrationTitleText: {
color: Colors.secondary30.color,
...FontFamily.notoSansExtraBold,
fontSize: 18,
},
accountRegistrationDescText: {
...FontFamily.notoSansRegular,
fontSize: 12,
},
textInputContainer: {
marginTop: 30,
marginHorizontal: 16,
gap: 16,
},
textInputRowContainer: {
justifyContent: 'center',
flexDirection: 'row',
gap: 12,
},
textInputFlex: {
flex: 1,
},
acceptTermsAndConditionsContainer: {
flexDirection: 'row',
marginHorizontal: 16,
marginTop: 20,
},
termsAndConditionsDesc: {
marginLeft: 4,
flex: 1,
fontSize: 12,
...FontFamily.notoSansRegular,
textAlign: 'justify',
},
termsHighlight: {
color: Colors.secondary40.color,
...FontFamily.notoSansBold,
fontSize: 12,
},
registerButton: {
marginHorizontal: 16,
marginTop: 24,
backgroundColor: Colors.primary30.color,
},
loginDescContainer: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: 16,
marginBottom: 20,
gap: 5,
},
loginDescText: {
...FontFamily.notoSansRegular,
fontSize: 12,
},
loginHighlight: {
color: Colors.secondary40.color,
...FontFamily.notoSansBold,
fontSize: 12,
},
});
export default styles;

View File

@ -0,0 +1,21 @@
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
function SetPasswordScreen() {
return (
<View style={styles.container}>
<Text>Set Password Screen</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default SetPasswordScreen;

View File

@ -0,0 +1,123 @@
import React from 'react';
import {Pressable, ScrollView, Text, View} from 'react-native';
import styles from './styles';
import Icon from 'react-native-vector-icons/MaterialIcons';
import {RootStackParamList} from '../../navigation/type';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {useNavigation} from '@react-navigation/native';
type TermsAndConditionsScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'Register'
>;
function TermsAndConnditionsScreen() {
const navigation = useNavigation<TermsAndConditionsScreenNavigationProp>();
return (
<View style={styles.container}>
<View style={styles.appBarContainer}>
<Pressable onPress={() => navigation.goBack()}>
<Icon name="arrow-back" size={24} style={styles.arrowBackIcon} />
</Pressable>
</View>
<ScrollView>
<View style={styles.termsAndConditionsTextWrapper}>
<Text style={styles.termsAndConditionsTitleText}>
Syarat & Ketentuan
</Text>
<Text style={styles.termsAndConditionsDescText}>
Panduan pendaftaran dan informasi untuk mengajukan permohonan paspor
</Text>
</View>
<View style={styles.termsAndConditionsDetailWrapper}>
<Text style={styles.heading}>
1. Mohon persiapkan terlebih dahulu persyaratan permohonan paspor
berikut:
</Text>
<Text style={styles.subheading}>a. Permohonan paspor baru:</Text>
<Text style={styles.bullet}> KTP</Text>
<Text style={styles.bullet}> Kartu keluarga</Text>
<Text style={styles.bullet}>
Akta kelahiran/ijazah/buku nikah/akte perkawinan/surat baptis
</Text>
<Text style={styles.bullet}>
Jika tidak ada, surat keterangan dari instansi
</Text>
<Text style={styles.subheading}>
b. Permohonan penggantian paspor:
</Text>
<Text style={styles.bullet}> KTP</Text>
<Text style={styles.bullet}> Paspor lama</Text>
<Text style={styles.subheading}>
c. Dokumen tambahan untuk paspor sesuai tujuan:
</Text>
<Text style={styles.bullet}>
1. Haji/Umrah: Surat rekomendasi Kemenag
</Text>
<Text style={styles.bullet}>
2. Belajar di luar negeri: Surat dari lembaga pendidikan
</Text>
<Text style={styles.bullet}>
3. Magang/kerja: Surat rekomendasi Kemnaker
</Text>
<Text style={styles.heading}>2. Pernyataan kesesuaian data</Text>
<Text style={styles.paragraph}>
Data yang ada pada seluruh dokumen harus sesuai dan dapat
dipertanggungjawabkan kebenarannya.
</Text>
<Text style={styles.heading}>
3. Aplikasi ini hanya dapat melayani permohonan paspor baru dan
penggantian
</Text>
<Text style={styles.paragraph}>
Untuk penggantian karena rusak atau hilang, langsung datang ke
Kantor Imigrasi.
</Text>
<Text style={styles.heading}>4. Ketentuan pembayaran</Text>
<Text style={styles.paragraph}>
Pembayaran dilakukan terlebih dahulu sesuai pilihan jadwal dan
kantor.
</Text>
<Text style={styles.heading}>5. Perubahan jadwal</Text>
<Text style={styles.paragraph}>
Jadwal bisa diubah sebelum kedatangan, tapi tidak bisa dipastikan
slot tersedia kembali.
</Text>
<Text style={styles.heading}>
6. Kehadiran dan pembatalan otomatis
</Text>
<Text style={styles.paragraph}>
Tidak hadir tanpa konfirmasi akan dibatalkan otomatis dan tidak
dapat digunakan kembali.
</Text>
<Text style={styles.heading}>
7. Permohonan paspor dapat ditolak dalam hal:
</Text>
<Text style={styles.bullet}> Termasuk dalam daftar pencekalan</Text>
<Text style={styles.bullet}> Tersangkut kasus pidana</Text>
<Text style={styles.bullet}>
Hal-hal lain yang dianggap oleh petugas
</Text>
<Text style={styles.heading}>8. Tanggung jawab pemohon</Text>
<Text style={styles.paragraph}>
Kesalahan data menjadi tanggung jawab pemohon. Biaya yang telah
dibayarkan tidak dapat dikembalikan.
</Text>
</View>
</ScrollView>
</View>
);
}
export default TermsAndConnditionsScreen;

View File

@ -0,0 +1,64 @@
import {StyleSheet} from 'react-native';
import Colors from '../../../assets/styles/Colors';
import FontFamily from '../../../assets/styles/FontFamily';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
appBarContainer: {
height: 64,
justifyContent: 'center',
},
arrowBackIcon: {
marginLeft: 16,
color: Colors.secondary30.color,
},
termsAndConditionsTextWrapper: {
marginHorizontal: 16,
},
termsAndConditionsTitleText: {
color: Colors.secondary30.color,
...FontFamily.notoSansExtraBold,
fontSize: 18,
},
termsAndConditionsDescText: {
...FontFamily.notoSansRegular,
fontSize: 12,
textAlign: 'justify',
},
termsAndConditionsDetailWrapper: {
marginHorizontal: 16,
marginVertical: 32,
},
content: {
padding: 16,
paddingBottom: 32,
},
heading: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 6,
color: '#222',
},
subheading: {
fontSize: 15,
fontWeight: '600',
marginTop: 10,
color: '#444',
},
bullet: {
fontSize: 14,
marginLeft: 12,
marginBottom: 4,
color: '#333',
},
paragraph: {
fontSize: 14,
marginBottom: 8,
color: '#333',
},
});
export default styles;