Finalized profile flow, setup status bar color, and add some improvement

This commit is contained in:
Mochammad Adhi Buchori
2025-04-19 14:04:34 +07:00
parent ef2bc641ac
commit 608e03558d
25 changed files with 901 additions and 92 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -8,6 +8,11 @@ import DateTimePicker from '@react-native-community/datetimepicker';
import {useState} from 'react'; import {useState} from 'react';
import {Dropdown} from 'react-native-element-dropdown'; import {Dropdown} from 'react-native-element-dropdown';
type DropdownItem = {
label: string;
value: string | number;
};
interface TextInputComponentProps { interface TextInputComponentProps {
title?: string; title?: string;
placeholder?: string; placeholder?: string;
@ -15,13 +20,13 @@ interface TextInputComponentProps {
isRequired?: boolean; isRequired?: boolean;
isDate?: boolean; isDate?: boolean;
isDropdown?: boolean; isDropdown?: boolean;
dropdownItemData?: DropdownItem[];
isDisabled?: boolean;
supportText?: string;
containerHeight?: any;
isMultiline?: boolean;
} }
const genderData = [
{label: 'Laki-Laki', value: '1'},
{label: 'Perempuan', value: '2'},
];
const TextInputComponent: React.FC<TextInputComponentProps> = ({ const TextInputComponent: React.FC<TextInputComponentProps> = ({
title, title,
placeholder, placeholder,
@ -29,6 +34,11 @@ const TextInputComponent: React.FC<TextInputComponentProps> = ({
isRequired = false, isRequired = false,
isDate = false, isDate = false,
isDropdown = false, isDropdown = false,
dropdownItemData,
isDisabled = false,
supportText,
containerHeight,
isMultiline = false,
}) => { }) => {
const [secureText, setSecureText] = useState(isPassword); const [secureText, setSecureText] = useState(isPassword);
const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined); const [selectedDate, setSelectedDate] = useState<Date | undefined>(undefined);
@ -36,13 +46,11 @@ const TextInputComponent: React.FC<TextInputComponentProps> = ({
const [showPicker, setShowPicker] = useState(false); const [showPicker, setShowPicker] = useState(false);
const [genderValue, setGenderValue] = useState(null); const [genderValue, setGenderValue] = useState(null);
const renderGenderItem = (item: any) => { const inputStyle = [
return ( styles.containerBackground,
<View style={styles.genderItem}> styles.placeholderText,
<Text style={styles.genderTextItem}>{item.label}</Text> containerHeight && {height: containerHeight},
</View> ];
);
};
const handleDateChange = (event: any, date?: Date) => { const handleDateChange = (event: any, date?: Date) => {
if (event.type === 'dismissed') { if (event.type === 'dismissed') {
@ -60,6 +68,14 @@ const TextInputComponent: React.FC<TextInputComponentProps> = ({
} }
}; };
const renderDropdownItem = (item: any) => {
return (
<View style={styles.dropdownItem}>
<Text style={styles.dropdownTextItem}>{item.label}</Text>
</View>
);
};
const renderInput = () => { const renderInput = () => {
if (isDropdown) { if (isDropdown) {
return ( return (
@ -75,17 +91,17 @@ const TextInputComponent: React.FC<TextInputComponentProps> = ({
placeholderStyle={styles.placeholderDropdownStyle} placeholderStyle={styles.placeholderDropdownStyle}
selectedTextStyle={styles.selectedTextStyle} selectedTextStyle={styles.selectedTextStyle}
iconStyle={styles.iconStyle} iconStyle={styles.iconStyle}
data={genderData} data={dropdownItemData ?? []}
maxHeight={300} maxHeight={300}
labelField="label" labelField="label"
valueField="value" valueField="value"
placeholder="Jenis Kelamin" placeholder={placeholder}
value={genderValue} value={genderValue}
onChange={item => { onChange={item => {
setGenderValue(item.value); setGenderValue(item.value);
}} }}
renderRightIcon={() => <Icon name="arrow-drop-down" size={20} />} renderRightIcon={() => <Icon name="arrow-drop-down" size={20} />}
renderItem={renderGenderItem} renderItem={renderDropdownItem}
/> />
</View> </View>
); );
@ -102,7 +118,7 @@ const TextInputComponent: React.FC<TextInputComponentProps> = ({
<TextInput <TextInput
mode="outlined" mode="outlined"
placeholder={placeholder} placeholder={placeholder}
style={[styles.containerBackground, styles.placeholderText]} style={inputStyle}
theme={{roundness: 12}} theme={{roundness: 12}}
placeholderTextColor={Colors.primary60.color} placeholderTextColor={Colors.primary60.color}
editable={false} editable={false}
@ -134,11 +150,12 @@ const TextInputComponent: React.FC<TextInputComponentProps> = ({
<TextInput <TextInput
mode="outlined" mode="outlined"
placeholder={placeholder} placeholder={placeholder}
style={[styles.containerBackground, styles.placeholderText]} style={inputStyle}
theme={{roundness: 12}} theme={{roundness: 12}}
placeholderTextColor={Colors.primary60.color} placeholderTextColor={Colors.primary60.color}
activeOutlineColor={Colors.primary10.color} activeOutlineColor={Colors.primary10.color}
secureTextEntry={secureText} secureTextEntry={secureText}
disabled={isDisabled}
right={ right={
isPassword ? ( isPassword ? (
<TextInput.Icon <TextInput.Icon
@ -148,8 +165,9 @@ const TextInputComponent: React.FC<TextInputComponentProps> = ({
/> />
) : null ) : null
} }
multiline={false} multiline={isMultiline}
/> />
{supportText && <Text style={[styles.supportText]}>{supportText}</Text>}
</View> </View>
); );
}; };
@ -179,16 +197,6 @@ const styles = StyleSheet.create({
fontSize: 13, fontSize: 13,
...FontFamily.notoSansRegular, ...FontFamily.notoSansRegular,
}, },
genderItem: {
padding: 16,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
genderTextItem: {
flex: 1,
fontSize: 13,
},
dropdown: { dropdown: {
marginTop: 8, marginTop: 8,
backgroundColor: 'white', backgroundColor: 'white',
@ -212,6 +220,24 @@ const styles = StyleSheet.create({
width: 20, width: 20,
height: 20, height: 20,
}, },
dropdownItem: {
padding: 16,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
dropdownTextItem: {
flex: 1,
fontSize: 13,
},
supportText: {
marginTop: 8,
...FontFamily.notoSansRegular,
fontSize: 10,
textAlign: 'right',
includeFontPadding: false,
color: Colors.neutral70.color,
},
}); });
export default TextInputComponent; export default TextInputComponent;

View File

@ -0,0 +1,9 @@
const cityData = [
{label: 'Jakarta Selatan', value: '1'},
{label: 'Bandung', value: '2'},
{label: 'Semarang', value: '3'},
{label: 'Surabaya', value: '4'},
{label: 'Denpasar', value: '5'},
];
export default cityData;

View File

@ -0,0 +1,9 @@
const districtData = [
{label: 'Setiabudi', value: '1'},
{label: 'Coblong', value: '2'},
{label: 'Candisari', value: '3'},
{label: 'Wonokromo', value: '4'},
{label: 'Denpasar Barat', value: '5'},
];
export default districtData;

View File

@ -0,0 +1,6 @@
const genderData = [
{label: 'Laki-Laki', value: '1'},
{label: 'Perempuan', value: '2'},
];
export default genderData;

View File

@ -0,0 +1,9 @@
const postalCodeData = [
{label: '12920', value: '1'},
{label: '40131', value: '2'},
{label: '50256', value: '3'},
{label: '60243', value: '4'},
{label: '80119', value: '5'},
];
export default postalCodeData;

View File

@ -0,0 +1,9 @@
const provinceData = [
{label: 'DKI Jakarta', value: '1'},
{label: 'Jawa Barat', value: '2'},
{label: 'Jawa Tengah', value: '3'},
{label: 'Jawa Timur', value: '4'},
{label: 'Bali', value: '5'},
];
export default provinceData;

View File

@ -11,6 +11,8 @@ import EditProfileScreen from '../screens/editProfile';
import CloseAccountScreen from '../screens/closeAccount'; import CloseAccountScreen from '../screens/closeAccount';
import {RootStackParamList} from './type'; import {RootStackParamList} from './type';
import TermsAndConnditionsScreen from '../screens/termsAndConditions'; import TermsAndConnditionsScreen from '../screens/termsAndConditions';
import NavigationRouteScreen from '../screens/navigationRoute';
import SetPasswordScreen from '../screens/setPassword';
const Stack = createNativeStackNavigator<RootStackParamList>(); const Stack = createNativeStackNavigator<RootStackParamList>();
@ -37,6 +39,11 @@ function RootStack() {
component={TermsAndConnditionsScreen} component={TermsAndConnditionsScreen}
options={{headerShown: false}} options={{headerShown: false}}
/> />
<Stack.Screen
name="NavigationRoute"
component={NavigationRouteScreen}
options={{headerShown: false}}
/>
<Stack.Screen <Stack.Screen
name="Home" name="Home"
component={HomeScreen} component={HomeScreen}
@ -67,6 +74,11 @@ function RootStack() {
component={CloseAccountScreen} component={CloseAccountScreen}
options={{headerShown: false}} options={{headerShown: false}}
/> />
<Stack.Screen
name="SetPassword"
component={SetPasswordScreen}
options={{headerShown: false}}
/>
</Stack.Navigator> </Stack.Navigator>
); );
} }

View File

@ -1,5 +1,6 @@
export type RootStackParamList = { export type RootStackParamList = {
Login: undefined; Login: undefined;
NavigationRoute: undefined;
Home: undefined; Home: undefined;
Register: undefined; Register: undefined;
AccountVerification: undefined; AccountVerification: undefined;
@ -9,4 +10,5 @@ export type RootStackParamList = {
Profile: undefined; Profile: undefined;
EditProfile: undefined; EditProfile: undefined;
CloseAccount: undefined; CloseAccount: undefined;
SetPassword: undefined;
}; };

View File

@ -1,12 +1,20 @@
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 React, {useEffect, useRef, useState} from 'react'; import React, {useEffect, useRef, useState} from 'react';
import {Pressable, Text, View, TextInput, Keyboard} from 'react-native'; import {
Pressable,
Text,
View,
TextInput,
Keyboard,
StatusBar,
} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons'; import Icon from 'react-native-vector-icons/MaterialIcons';
import {RootStackParamList} from '../../navigation/type'; import {RootStackParamList} from '../../navigation/type';
import styles from './styles'; import styles from './styles';
import {Button} from 'react-native-paper'; import {Button} from 'react-native-paper';
import OTPTextInput from '../../components/OTPTextInput'; import OTPTextInput from '../../components/OTPTextInput';
import Colors from '../../../assets/styles/Colors';
type AccountVerificationScreenNavigationProp = NativeStackNavigationProp< type AccountVerificationScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList, RootStackParamList,
@ -50,6 +58,10 @@ function AccountVerificationScreen() {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<StatusBar
backgroundColor={Colors.neutral100.color}
barStyle="dark-content"
/>
<View style={styles.appBarContainer}> <View style={styles.appBarContainer}>
<Pressable onPress={() => navigation.goBack()}> <Pressable onPress={() => navigation.goBack()}>
<Icon name="arrow-back" size={24} style={styles.arrowBackIcon} /> <Icon name="arrow-back" size={24} style={styles.arrowBackIcon} />

View File

@ -1,21 +1,125 @@
import React from 'react'; import React, {useState} from 'react';
import {StyleSheet, Text, View} from 'react-native'; import {StatusBar, Text, View} from 'react-native';
import styles from './styles';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {RootStackParamList} from '../../navigation/type';
import {useNavigation} from '@react-navigation/native';
import Colors from '../../../assets/styles/Colors';
import TextInputComponent from '../../components/TextInput';
import {Button, Dialog, PaperProvider, Portal} from 'react-native-paper';
type CloseAccountScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'CloseAccount'
>;
function CloseAccountScreen() { function CloseAccountScreen() {
const navigation = useNavigation<CloseAccountScreenNavigationProp>();
const closeAccountDescItems = [
'Jika Anda membuat akun dengan email atau nomor telepon yang sama, Anda harus melakukan daftar akun ulang.',
'Beberapa data terkait transaksi dapat disimpan oleh M-Paspor berdasarkan ketentuan peraturan perundang-undangan.',
];
const [visible, setVisible] = useState(false);
const showDialog = () => setVisible(true);
const hideDialog = () => setVisible(false);
const handleCloseAccount = () => {
navigation.reset({
index: 0,
routes: [{name: 'Login'}],
});
};
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text>Close Screen</Text> <PaperProvider>
<View style={styles.contentContainer}>
<StatusBar
backgroundColor={visible ? '#ADADAF' : Colors.neutral100.color}
barStyle={visible ? 'light-content' : 'dark-content'}
/>
<View>
<View style={styles.appBarContainer}>
<Icon
name="arrow-left"
size={24}
style={styles.appBarIcon}
color={Colors.secondary30.color}
onPress={() => navigation.goBack()}
/>
<Text style={styles.appBarTitle}>Tutup Akun</Text>
</View>
<View style={styles.closeAccountInfoContainer}>
<Text style={styles.closeAccountTitle}>
Hal yang terjadi setelah tutup akun
</Text>
<View>
{closeAccountDescItems.map((item, index) => (
<View key={index} style={styles.closeAccountDescContainer}>
<Text style={styles.closeAccountNumber}>{index + 1}.</Text>
<Text style={styles.closeAccountDesc}>{item}</Text>
</View>
))}
</View>
</View>
<View style={styles.closeAccountReasonContainer}>
<TextInputComponent
title="Kenapa Anda ingin tutup akun?"
placeholder="Tuliskan alasan Anda menutup akun"
isRequired
supportText="0/100 karakter"
containerHeight={90}
isMultiline
/>
</View>
</View>
<View style={styles.closeAccountButtonContainer}>
<Button
mode="contained"
style={styles.buttonContinue}
textColor={Colors.neutral100.color}
onPress={showDialog}>
Lanjut
</Button>
<Button
mode="outlined"
textColor={Colors.primary30.color}
style={styles.butttonBack}
onPress={() => navigation.goBack()}>
Kembali
</Button>
</View>
</View>
<Portal>
<Dialog visible={visible} style={styles.dialogContainer}>
<Dialog.Title style={styles.dialogTitle}>
Apakah Anda yakin akan menutup akun?
</Dialog.Title>
<View style={styles.dialogButtonContainer}>
<Button
style={styles.buttonApproveCloseAccount}
mode="contained"
textColor={Colors.neutral100.color}
onPress={handleCloseAccount}>
Ya, lanjut tutup akun
</Button>
<Button
style={styles.buttonCancelCloseAccount}
mode="outlined"
textColor={Colors.indicatorRed.color}
onPress={hideDialog}>
Tidak, jangan tutup akun
</Button>
</View>
</Dialog>
</Portal>
</PaperProvider>
</View> </View>
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default CloseAccountScreen; export default CloseAccountScreen;

View File

@ -0,0 +1,95 @@
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',
},
appBarTitle: {
color: Colors.secondary30.color,
...FontFamily.notoSansRegular,
fontSize: 22,
marginStart: 16,
},
appBarIcon: {
marginLeft: 16,
},
appBarContainer: {
height: 64,
flexDirection: 'row',
alignItems: 'center',
},
contentContainer: {
flex: 1,
justifyContent: 'space-between',
},
closeAccountInfoContainer: {
marginVertical: 16,
marginHorizontal: 16,
},
closeAccountTitle: {
fontSize: 16,
...FontFamily.notoSansExtraBold,
color: Colors.secondary30.color,
marginBottom: 16,
},
closeAccountDescContainer: {
flexDirection: 'row',
gap: 6,
marginBottom: 16,
},
closeAccountNumber: {
...FontFamily.notoSansRegular,
fontSize: 12,
},
closeAccountDesc: {
flex: 1,
...FontFamily.notoSansRegular,
textAlign: 'justify',
fontSize: 12,
},
closeAccountReasonContainer: {
borderWidth: 1,
borderColor: Colors.secondary50.color,
padding: 12,
margin: 16,
borderRadius: 8,
height: 170,
},
closeAccountButtonContainer: {
gap: 16,
marginHorizontal: 16,
marginBottom: 48,
},
butttonBack: {
borderColor: Colors.primary30.color,
},
buttonContinue: {
backgroundColor: Colors.primary30.color,
},
dialogContainer: {
backgroundColor: 'white',
elevation: 0,
shadowColor: 'transparent',
borderRadius: 20,
},
dialogTitle: {
color: Colors.indicatorRed.color,
},
dialogButtonContainer: {
marginHorizontal: 24,
marginBottom: 24,
marginTop: 16,
gap: 16,
},
buttonApproveCloseAccount: {
backgroundColor: Colors.indicatorRed.color,
},
buttonCancelCloseAccount: {
borderColor: Colors.indicatorRed.color,
},
});
export default styles;

View File

@ -1,21 +1,131 @@
import React from 'react'; import React from 'react';
import {StyleSheet, Text, View} from 'react-native'; import {Image, ScrollView, StatusBar, Text, View} from 'react-native';
import styles from './styles';
import Colors from '../../../assets/styles/Colors';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import {RootStackParamList} from '../../navigation/type';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {useNavigation} from '@react-navigation/native';
import TextInputComponent from '../../components/TextInput';
import genderData from '../../model/DropdownData/GenderData';
import provinceData from '../../model/DropdownData/ProvinceData';
import cityData from '../../model/DropdownData/CityData';
import districtData from '../../model/DropdownData/DistrictData';
import postalCodeData from '../../model/DropdownData/PostalCodeData';
import {Button} from 'react-native-paper';
type EditProfileScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'EditProfile'
>;
function EditProfileScreen() { function EditProfileScreen() {
const placeholderProfileImage = require('../../../assets/images/placeholderProfileImage.png');
const navigation = useNavigation<EditProfileScreenNavigationProp>();
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text>Edit Screen</Text> <StatusBar
backgroundColor={Colors.secondary30.color}
barStyle="light-content"
/>
<View style={styles.appBarContainer}>
<Icon
name="arrow-left"
size={24}
style={styles.appBarIcon}
color={Colors.neutral100.color}
onPress={() => navigation.goBack()}
/>
<Text style={styles.appBarTitle}>Edit Profil</Text>
</View>
<ScrollView>
<View style={styles.topContainer}>
<Image source={placeholderProfileImage} style={styles.profileImage} />
<View style={styles.editProfileImageIconContainer}>
<Icon
name="pencil-outline"
size={18}
color={Colors.neutral100.color}
/>
</View>
</View>
<View style={styles.editProfileSectionFieldContainer}>
<TextInputComponent
title="Nama Lengkap"
placeholder="Masukkan Nama Lengkap Anda"
/>
<TextInputComponent title="NIK" placeholder="Masukkan NIK Anda" />
<View style={styles.textInputRowContainer}>
<View style={styles.textInputFlex}>
<TextInputComponent
title="Tanggal Lahir"
placeholder="DD/MM/YYYY"
isDate
/>
</View>
<View style={styles.textInputFlex}>
<TextInputComponent
title="Jenis Kelamin"
placeholder="Jenis Kelamin"
isDropdown
dropdownItemData={genderData}
/>
</View>
</View>
<TextInputComponent
title="Email"
placeholder="salwaadhani@gmail.com"
isDisabled
/>
<TextInputComponent
title="Alamat Rumah"
placeholder="Masukkan Alamat Rumah Anda"
supportText="0/100 karakter"
/>
<TextInputComponent
title="Provinsi Sesuai KTP"
placeholder="Provinsi"
isDropdown
dropdownItemData={provinceData}
/>
<TextInputComponent
title="Kabupaten/Kota Sesuai KTP"
placeholder="Kabupaten/Kota"
isDropdown
dropdownItemData={cityData}
/>
<TextInputComponent
title="Kecamatan Sesuai KTP"
placeholder="Kecamatan"
isDropdown
dropdownItemData={districtData}
/>
<TextInputComponent
title="Kode Pos Sesuai KTP"
placeholder="Kode Pos"
isDropdown
dropdownItemData={postalCodeData}
/>
</View>
<View style={styles.editProfileButtonContainer}>
<Button
mode="contained"
style={styles.editProfileButton}
onPress={() => navigation.goBack()}>
Simpan Perubahan
</Button>
<Button
mode="outlined"
textColor={Colors.indicatorRed.color}
style={styles.closeAccountButton}
onPress={() => navigation.navigate('CloseAccount')}>
Tutup Akun
</Button>
</View>
</ScrollView>
</View> </View>
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default EditProfileScreen; export default EditProfileScreen;

View File

@ -0,0 +1,72 @@
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',
},
appBarTitle: {
color: Colors.neutral100.color,
...FontFamily.notoSansRegular,
fontSize: 22,
marginStart: 16,
},
appBarIcon: {
marginLeft: 16,
},
appBarContainer: {
height: 64,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: Colors.secondary30.color,
},
topContainer: {
backgroundColor: Colors.secondary30.color,
height: 85,
alignItems: 'center',
},
profileImage: {
height: 125,
width: 100,
borderRadius: 8,
marginTop: 16,
position: 'absolute',
},
editProfileImageIconContainer: {
backgroundColor: Colors.primary30.color,
padding: 10,
borderRadius: 100,
position: 'absolute',
bottom: -50,
right: 125,
},
editProfileSectionFieldContainer: {
gap: 16,
marginTop: 72,
marginBottom: 32,
marginHorizontal: 16,
},
textInputRowContainer: {
justifyContent: 'center',
flexDirection: 'row',
gap: 12,
},
textInputFlex: {
flex: 1,
},
editProfileButtonContainer: {
gap: 16,
marginHorizontal: 16,
marginBottom: 48,
},
editProfileButton: {
backgroundColor: Colors.primary30.color,
},
closeAccountButton: {
borderColor: Colors.indicatorRed.color,
},
});
export default styles;

View File

@ -1,5 +1,6 @@
import React from 'react'; import * as React from 'react';
import {StyleSheet, Text, View} from 'react-native'; import styles from './styles';
import {View, Text} from 'react-native';
function HomeScreen() { function HomeScreen() {
return ( return (
@ -9,13 +10,4 @@ function HomeScreen() {
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default HomeScreen; export default HomeScreen;

View File

@ -0,0 +1,20 @@
import {StyleSheet} from 'react-native';
import Colors from '../../../assets/styles/Colors';
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
bottomNavLabel: {
color: Colors.neutral100.color,
textAlign: 'center',
alignSelf: 'center',
fontSize: 12,
position: 'absolute',
},
});
export default styles;

View File

@ -1,5 +1,12 @@
import React from 'react'; import React from 'react';
import {Image, Pressable, ScrollView, Text, View} from 'react-native'; import {
Image,
Pressable,
ScrollView,
StatusBar,
Text,
View,
} from 'react-native';
import styles from './styles'; import styles from './styles';
import {Button} from 'react-native-paper'; import {Button} from 'react-native-paper';
import TextInputComponent from '../../components/TextInput'; import TextInputComponent from '../../components/TextInput';
@ -7,6 +14,7 @@ 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 {RootStackParamList} from '../../navigation/type';
import Colors from '../../../assets/styles/Colors';
type LoginScreenNavigationProp = NativeStackNavigationProp< type LoginScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList, RootStackParamList,
@ -19,6 +27,10 @@ function LoginScreen() {
return ( return (
<ScrollView style={styles.container}> <ScrollView style={styles.container}>
<StatusBar
backgroundColor={Colors.secondary60.color}
barStyle="light-content"
/>
<Image source={welcomeImage} style={styles.welcomeImage} /> <Image source={welcomeImage} style={styles.welcomeImage} />
<View style={styles.contentContainer}> <View style={styles.contentContainer}>
<Text style={styles.welcomeText}> <Text style={styles.welcomeText}>
@ -27,16 +39,21 @@ function LoginScreen() {
<View style={styles.textInputContainer}> <View style={styles.textInputContainer}>
<TextInputComponent title="Email" placeholder="Masukkan Email" /> <TextInputComponent title="Email" placeholder="Masukkan Email" />
<TextInputComponent <TextInputComponent
title="Password" title="Kata Sandi"
placeholder="Masukkan Password" placeholder="Masukkan Kata Sandi"
isPassword={true} isPassword
/> />
</View> </View>
<Text style={styles.forgotPasswordText}>Lupa kata sandi?</Text> <Text style={styles.forgotPasswordText}>Lupa kata sandi?</Text>
<Button <Button
style={styles.loginButton} style={styles.loginButton}
mode="contained" mode="contained"
onPress={() => navigation.navigate('Home')}> onPress={() =>
navigation.reset({
index: 0,
routes: [{name: 'NavigationRoute'}],
})
}>
Masuk Masuk
</Button> </Button>
<View style={styles.registerAccountContainer}> <View style={styles.registerAccountContainer}>

View File

@ -0,0 +1,61 @@
import * as React from 'react';
import {BottomNavigation, Text} from 'react-native-paper';
import Colors from '../../../assets/styles/Colors';
import ProfileScreen from '../profile';
import styles from './styles';
import HomeScreen from '../home';
import HistoryScreen from '../history';
const HomeRoute = () => <HomeScreen />;
const HistoryRoute = () => <HistoryScreen />;
const ProfileRoute = () => <ProfileScreen />;
function NavigationRouteScreen() {
const [index, setIndex] = React.useState(0);
const [routes] = React.useState([
{
key: 'home',
title: 'Home',
focusedIcon: 'home',
unfocusedIcon: 'home-outline',
},
{
key: 'history',
title: 'History',
focusedIcon: 'history',
},
{
key: 'profile',
title: 'Profile',
focusedIcon: 'account-circle',
unfocusedIcon: 'account-circle-outline',
},
]);
const renderScene = BottomNavigation.SceneMap({
home: HomeRoute,
history: HistoryRoute,
profile: ProfileRoute,
});
return (
<BottomNavigation
navigationState={{index, routes}}
onIndexChange={setIndex}
renderScene={renderScene}
activeColor={Colors.primary30.color}
inactiveColor={Colors.neutral100.color}
barStyle={{backgroundColor: Colors.primary30.color}}
theme={{
colors: {
secondaryContainer: Colors.neutral100.color,
},
}}
renderLabel={({route}) => (
<Text style={styles.bottomNavLabel}>{route.title}</Text>
)}
/>
);
}
export default NavigationRouteScreen;

View File

@ -0,0 +1,14 @@
import {StyleSheet} from 'react-native';
import Colors from '../../../assets/styles/Colors';
const styles = StyleSheet.create({
bottomNavLabel: {
color: Colors.neutral100.color,
textAlign: 'center',
alignSelf: 'center',
fontSize: 12,
position: 'absolute',
},
});
export default styles;

View File

@ -1,21 +1,85 @@
import React from 'react'; import React from 'react';
import {StyleSheet, Text, View} from 'react-native'; import {Image, StatusBar, Text, View} from 'react-native';
import styles from './styles';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import Colors from '../../../assets/styles/Colors';
import {Button} from 'react-native-paper';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {RootStackParamList} from '../../navigation/type';
import {useNavigation} from '@react-navigation/native';
type ProfileScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'Profile'
>;
function ProfileScreen() { function ProfileScreen() {
const placeholderProfileImage = require('../../../assets/images/placeholderProfileImage.png');
const navigation = useNavigation<ProfileScreenNavigationProp>();
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text>Profile Screen</Text> <StatusBar
backgroundColor={Colors.secondary30.color}
barStyle="light-content"
/>
<View style={styles.appBarContainer}>
<Text style={styles.appBarTitle}>Profil</Text>
</View>
<View style={styles.topContainer}>
<Image source={placeholderProfileImage} style={styles.profileImage} />
<Text style={styles.accountName}>Salwa Aisyah Adhani</Text>
<Text style={styles.accountNumber}>3271234560009123456</Text>
</View>
<View style={styles.sectionProfileField}>
<Icon name="email-outline" size={20} color={Colors.secondary30.color} />
<Text style={styles.sectionProfileText}>salwaadhani@gmail.com</Text>
</View>
<View style={styles.sectionProfileField}>
<Icon name="phone-outline" size={20} color={Colors.secondary30.color} />
<Text style={styles.sectionProfileText}>085123456789</Text>
</View>
<View style={styles.sectionProfileField}>
<Icon
name="calendar-month"
size={20}
color={Colors.secondary30.color}
/>
<Text style={styles.sectionProfileText}>22 Februari 2002</Text>
</View>
<View style={styles.sectionProfileField}>
<Icon name="home-outline" size={20} color={Colors.secondary30.color} />
<Text style={styles.sectionProfileText}>Jl. Raya Muchtar</Text>
</View>
<View style={styles.sectionButtonContainer}>
<Button
icon="pencil-outline"
mode="contained"
style={styles.sectionButtonStyle}
onPress={() => navigation.navigate('EditProfile')}>
Edit Profil
</Button>
<Button
icon="lock-outline"
mode="contained"
style={styles.sectionButtonStyle}
onPress={() => navigation.navigate('SetPassword')}>
Atur Kata Sandi
</Button>
</View>
<Button
mode="outlined"
textColor={Colors.indicatorRed.color}
style={styles.logoutButton}
onPress={() =>
navigation.reset({
index: 0,
routes: [{name: 'Login'}],
})
}>
Keluar
</Button>
</View> </View>
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default ProfileScreen; export default ProfileScreen;

View File

@ -0,0 +1,74 @@
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',
},
topContainer: {
width: '100%',
backgroundColor: Colors.secondary30.color,
alignItems: 'center',
marginBottom: 16,
},
appBarTitle: {
color: Colors.neutral100.color,
...FontFamily.notoSansExtraBold,
fontSize: 28,
marginStart: 16,
marginVertical: 14,
},
appBarContainer: {
height: 64,
backgroundColor: Colors.secondary30.color,
justifyContent: 'center',
},
profileImage: {
height: 125,
width: 100,
borderRadius: 8,
marginTop: 16,
},
accountName: {
marginTop: 16,
...FontFamily.notoSansBold,
fontSize: 18,
color: Colors.neutral100.color,
},
accountNumber: {
...FontFamily.notoSansRegular,
fontSize: 14,
color: Colors.neutral100.color,
marginBottom: 16,
},
sectionProfileField: {
flexDirection: 'row',
gap: 16,
marginHorizontal: 16,
paddingVertical: 12,
},
sectionProfileText: {
...FontFamily.notoSansRegular,
fontSize: 12,
},
sectionButtonContainer: {
flexDirection: 'row',
justifyContent: 'center',
gap: 16,
marginHorizontal: 16,
marginTop: 32,
},
sectionButtonStyle: {
flex: 1,
backgroundColor: Colors.primary30.color,
},
logoutButton: {
marginTop: 16,
marginHorizontal: 16,
borderColor: Colors.indicatorRed.color,
},
});
export default styles;

View File

@ -1,6 +1,6 @@
import {NativeStackNavigationProp} from '@react-navigation/native-stack'; import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import React, {useState} from 'react'; import React, {useState} from 'react';
import {Pressable, ScrollView, Text, View} from 'react-native'; import {Pressable, ScrollView, StatusBar, Text, View} from 'react-native';
import {RootStackParamList} from '../../navigation/type'; import {RootStackParamList} from '../../navigation/type';
import {CommonActions, useNavigation} from '@react-navigation/native'; import {CommonActions, useNavigation} from '@react-navigation/native';
import Icon from 'react-native-vector-icons/MaterialIcons'; import Icon from 'react-native-vector-icons/MaterialIcons';
@ -8,6 +8,7 @@ import styles from './styles';
import TextInputComponent from '../../components/TextInput'; import TextInputComponent from '../../components/TextInput';
import {Button, Checkbox} from 'react-native-paper'; import {Button, Checkbox} from 'react-native-paper';
import Colors from '../../../assets/styles/Colors'; import Colors from '../../../assets/styles/Colors';
import genderData from '../../model/DropdownData/GenderData';
type RegisterScreenNavigationProp = NativeStackNavigationProp< type RegisterScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList, RootStackParamList,
@ -20,6 +21,10 @@ function RegisterScreen() {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<StatusBar
backgroundColor={Colors.neutral100.color}
barStyle="dark-content"
/>
<View style={styles.appBarContainer}> <View style={styles.appBarContainer}>
<Pressable onPress={() => navigation.goBack()}> <Pressable onPress={() => navigation.goBack()}>
<Icon name="arrow-back" size={24} style={styles.arrowBackIcon} /> <Icon name="arrow-back" size={24} style={styles.arrowBackIcon} />
@ -55,6 +60,7 @@ function RegisterScreen() {
placeholder="Jenis Kelamin" placeholder="Jenis Kelamin"
isRequired isRequired
isDropdown isDropdown
dropdownItemData={genderData}
/> />
</View> </View>
</View> </View>

View File

@ -1,21 +1,66 @@
import React from 'react'; import React from 'react';
import {StyleSheet, Text, View} from 'react-native'; import {StatusBar, Text, View} from 'react-native';
import styles from './styles';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import TextInputComponent from '../../components/TextInput';
import Colors from '../../../assets/styles/Colors';
import {Button} from 'react-native-paper';
import {useNavigation} from '@react-navigation/native';
import {RootStackParamList} from '../../navigation/type';
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
type SetPasswordScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList,
'SetPassword'
>;
function SetPasswordScreen() { function SetPasswordScreen() {
const navigation = useNavigation<SetPasswordScreenNavigationProp>();
return ( return (
<View style={styles.container}> <View style={styles.container}>
<Text>Set Password Screen</Text> <StatusBar
backgroundColor={Colors.neutral100.color}
barStyle="dark-content"
/>
<View style={styles.appBarContainer}>
<Icon
name="arrow-left"
size={24}
style={styles.appBarIcon}
color={Colors.secondary30.color}
onPress={() => navigation.goBack()}
/>
<Text style={styles.appBarTitle}>Atur Kata Sandi</Text>
</View>
<View style={styles.setPasswordSectionFieldContainer}>
<TextInputComponent
title="Kata Sandi Lama"
placeholder="Masukkan kata sandi lama"
isPassword
isRequired
/>
<TextInputComponent
title="Kata Sandi Baru"
placeholder="Masukkan kata sandi baru"
isPassword
isRequired
/>
<TextInputComponent
title="Ulang Kata Sandi Baru"
placeholder="Masukkan ulang kata sandi baru"
isPassword
isRequired
/>
</View>
<Button
mode="contained"
style={styles.buttonSetPassword}
onPress={() => {}}>
Simpan Perubahan
</Button>
</View> </View>
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'white',
},
});
export default SetPasswordScreen; export default SetPasswordScreen;

View File

@ -0,0 +1,36 @@
import {StyleSheet} from 'react-native';
import FontFamily from '../../../assets/styles/FontFamily';
import Colors from '../../../assets/styles/Colors';
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
appBarTitle: {
color: Colors.secondary30.color,
...FontFamily.notoSansRegular,
fontSize: 22,
marginStart: 16,
},
appBarIcon: {
marginLeft: 16,
},
appBarContainer: {
height: 64,
flexDirection: 'row',
alignItems: 'center',
},
setPasswordSectionFieldContainer: {
gap: 16,
marginTop: 16,
marginBottom: 32,
marginHorizontal: 16,
},
buttonSetPassword: {
marginHorizontal: 16,
backgroundColor: Colors.primary30.color,
},
});
export default styles;

View File

@ -1,10 +1,11 @@
import React from 'react'; import React from 'react';
import {Pressable, ScrollView, Text, View} from 'react-native'; import {Pressable, ScrollView, StatusBar, Text, View} from 'react-native';
import styles from './styles'; import styles from './styles';
import Icon from 'react-native-vector-icons/MaterialIcons'; import Icon from 'react-native-vector-icons/MaterialIcons';
import {RootStackParamList} from '../../navigation/type'; import {RootStackParamList} from '../../navigation/type';
import {NativeStackNavigationProp} from '@react-navigation/native-stack'; import {NativeStackNavigationProp} from '@react-navigation/native-stack';
import {useNavigation} from '@react-navigation/native'; import {useNavigation} from '@react-navigation/native';
import Colors from '../../../assets/styles/Colors';
type TermsAndConditionsScreenNavigationProp = NativeStackNavigationProp< type TermsAndConditionsScreenNavigationProp = NativeStackNavigationProp<
RootStackParamList, RootStackParamList,
@ -16,6 +17,10 @@ function TermsAndConnditionsScreen() {
return ( return (
<View style={styles.container}> <View style={styles.container}>
<StatusBar
backgroundColor={Colors.neutral100.color}
barStyle="dark-content"
/>
<View style={styles.appBarContainer}> <View style={styles.appBarContainer}>
<Pressable onPress={() => navigation.goBack()}> <Pressable onPress={() => navigation.goBack()}>
<Icon name="arrow-back" size={24} style={styles.arrowBackIcon} /> <Icon name="arrow-back" size={24} style={styles.arrowBackIcon} />