Add UI for the Notification and History screens, as well as several components on the Home screen
This commit is contained in:
196
src/components/PassportAppointmentCard.tsx
Normal file
196
src/components/PassportAppointmentCard.tsx
Normal file
@ -0,0 +1,196 @@
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import WaitingForPaymentIcon from '../../assets/icons/waiting_for_payment.svg';
|
||||
import {StyleSheet, Text, View} from 'react-native';
|
||||
import FontFamily from '../../assets/styles/FontFamily';
|
||||
import Colors from '../../assets/styles/Colors';
|
||||
|
||||
type PassportAppointmentCardProps = {
|
||||
applicantName: string;
|
||||
applicantCount: number;
|
||||
appointmentDate: string;
|
||||
appointmentTime: string;
|
||||
serviceUnit: string;
|
||||
status: string;
|
||||
};
|
||||
|
||||
const renderStatusContent = (status: string) => {
|
||||
let backgroundColor;
|
||||
let IconComponent;
|
||||
|
||||
switch (status) {
|
||||
case 'Permohonan Kadaluarsa':
|
||||
backgroundColor = Colors.indicatorRed.color;
|
||||
IconComponent = () => (
|
||||
<Icon name="close" size={18} color={Colors.neutral100.color} />
|
||||
);
|
||||
break;
|
||||
case 'Sudah Terbayar':
|
||||
backgroundColor = Colors.indicatorGreen.color;
|
||||
IconComponent = () => (
|
||||
<Icon name="check" size={18} color={Colors.neutral100.color} />
|
||||
);
|
||||
break;
|
||||
default:
|
||||
backgroundColor = Colors.indicatorOrange.color;
|
||||
IconComponent = () => <WaitingForPaymentIcon width={18} height={18} />;
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{status === 'Sudah Terbayar' && (
|
||||
<View style={styles.seeRequirementsWrapper}>
|
||||
<Text style={styles.appointmentStatusText}>Lihat Persyaratan</Text>
|
||||
</View>
|
||||
)}
|
||||
<View style={[styles.appointmentStatusWrapper, {backgroundColor}]}>
|
||||
<IconComponent />
|
||||
<Text style={styles.appointmentStatusText}>{status}</Text>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const PassportAppointmentCard: React.FC<PassportAppointmentCardProps> = ({
|
||||
applicantName,
|
||||
applicantCount,
|
||||
appointmentDate,
|
||||
appointmentTime,
|
||||
serviceUnit,
|
||||
status,
|
||||
}) => {
|
||||
return (
|
||||
<View style={styles.cardContainer}>
|
||||
<View style={styles.topCardContainer}>
|
||||
<View style={styles.topCardContentTextWrapper}>
|
||||
<Text style={styles.applicantNameText}>{applicantName}</Text>
|
||||
<Text style={styles.applicantCountText}>
|
||||
{applicantCount} Pemohon
|
||||
</Text>
|
||||
</View>
|
||||
<Icon name="menu-right" size={24} />
|
||||
</View>
|
||||
<View style={styles.midCardContainer}>
|
||||
<View style={styles.midCardContentWrapper}>
|
||||
<Icon
|
||||
name="calendar-today"
|
||||
size={24}
|
||||
color={Colors.secondary30.color}
|
||||
/>
|
||||
<Text style={styles.midCardContentTextStyle}>{appointmentDate}</Text>
|
||||
</View>
|
||||
<View style={styles.midCardContentWrapper}>
|
||||
<Icon
|
||||
name="clock-outline"
|
||||
size={24}
|
||||
color={Colors.secondary30.color}
|
||||
/>
|
||||
<Text style={styles.midCardContentTextStyle}>{appointmentTime}</Text>
|
||||
</View>
|
||||
<View style={styles.midCardContentWrapper}>
|
||||
<Icon
|
||||
name="map-marker-outline"
|
||||
size={24}
|
||||
color={Colors.secondary30.color}
|
||||
/>
|
||||
<Text style={styles.midCardContentTextStyle}>{serviceUnit}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View>
|
||||
{status === 'Menunggu Pembayaran' && (
|
||||
<View style={styles.appointmentAlertWrapper}>
|
||||
<Text style={styles.appointmentAlertText}>
|
||||
Selesaikan pembayaran sebelum
|
||||
</Text>
|
||||
<Text style={styles.appointmentAlertText}>16 April 2025 23:30</Text>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.appointmentStatusContainer}>
|
||||
{renderStatusContent(status)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default PassportAppointmentCard;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
cardContainer: {
|
||||
borderRadius: 20,
|
||||
padding: 16,
|
||||
backgroundColor: Colors.neutral100.color,
|
||||
borderWidth: 1,
|
||||
borderColor: Colors.secondary50.color,
|
||||
},
|
||||
topCardContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginVertical: 6,
|
||||
},
|
||||
topCardContentTextWrapper: {
|
||||
gap: 4,
|
||||
flex: 1,
|
||||
},
|
||||
applicantNameText: {
|
||||
fontSize: 14,
|
||||
...FontFamily.notoSansBold,
|
||||
textTransform: 'uppercase',
|
||||
color: Colors.secondary30.color,
|
||||
},
|
||||
applicantCountText: {
|
||||
fontSize: 12,
|
||||
...FontFamily.notoSansRegular,
|
||||
color: Colors.primary30.color,
|
||||
},
|
||||
midCardContainer: {
|
||||
gap: 8,
|
||||
marginVertical: 8,
|
||||
},
|
||||
midCardContentWrapper: {
|
||||
flexDirection: 'row',
|
||||
gap: 6,
|
||||
},
|
||||
midCardContentTextStyle: {
|
||||
fontSize: 12,
|
||||
...FontFamily.notoSansRegular,
|
||||
color: Colors.primary30.color,
|
||||
},
|
||||
appointmentAlertWrapper: {
|
||||
marginTop: 5,
|
||||
marginBottom: 13,
|
||||
},
|
||||
appointmentAlertText: {
|
||||
...FontFamily.notoSansRegular,
|
||||
fontSize: 10,
|
||||
color: Colors.indicatorRed.color,
|
||||
},
|
||||
appointmentStatusContainer: {
|
||||
alignItems: 'flex-end',
|
||||
justifyContent: 'flex-end',
|
||||
flexDirection: 'row',
|
||||
gap: 10,
|
||||
},
|
||||
appointmentStatusWrapper: {
|
||||
gap: 6,
|
||||
alignItems: 'center',
|
||||
backgroundColor: Colors.indicatorOrange.color,
|
||||
padding: 8,
|
||||
flexDirection: 'row',
|
||||
borderRadius: 8,
|
||||
},
|
||||
appointmentStatusText: {
|
||||
fontSize: 12,
|
||||
...FontFamily.notoSansMedium,
|
||||
color: Colors.neutral100.color,
|
||||
includeFontPadding: false,
|
||||
},
|
||||
seeRequirementsWrapper: {
|
||||
backgroundColor: Colors.primary30.color,
|
||||
borderRadius: 100,
|
||||
paddingHorizontal: 16,
|
||||
padding: 8,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
});
|
49
src/data/History/PassportAppointmentData.tsx
Normal file
49
src/data/History/PassportAppointmentData.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
const passportAppointmentData = [
|
||||
{
|
||||
id: '1',
|
||||
applicantName: 'Irma Wahyudini',
|
||||
applicantCount: 1,
|
||||
appointmentDate: 'Kamis, 17 April 2025',
|
||||
appointmentTime: '10.00 - 11.00 WIB',
|
||||
serviceUnit: 'Unit Layanan Paspor I Jakarta Selatan (Pondok Pinang)',
|
||||
status: 'Menunggu Pembayaran',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
applicantName: 'Salwa Aisyah Adhani',
|
||||
applicantCount: 2,
|
||||
appointmentDate: 'Senin, 14 April 2025',
|
||||
appointmentTime: '08:00 - 09:00 WIB',
|
||||
serviceUnit: 'Kantor Imigrasi Depok',
|
||||
status: 'Sudah Terbayar',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
applicantName: 'Salwa Aisyah Adhani',
|
||||
applicantCount: 2,
|
||||
appointmentDate: 'Senin, 14 April 2025',
|
||||
appointmentTime: '08:00 - 09:00 WIB',
|
||||
serviceUnit: 'Kantor Imigrasi Depok',
|
||||
status: 'Menunggu Pembayaran',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
applicantName: 'Salwa Aisyah Adhani',
|
||||
applicantCount: 2,
|
||||
appointmentDate: 'Senin, 23 September 2024',
|
||||
appointmentTime: '10:00 - 11:00 WIB',
|
||||
serviceUnit: 'Kantor Imigrasi Depok',
|
||||
status: 'Permohonan Kadaluarsa',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
applicantName: 'Yulfarisa Hasnah',
|
||||
applicantCount: 2,
|
||||
appointmentDate: 'Senin, 14 April 2025',
|
||||
appointmentTime: '08:00 - 09:00 WIB',
|
||||
serviceUnit: 'Kantor Imigrasi Depok',
|
||||
status: 'Sudah Terbayar',
|
||||
},
|
||||
];
|
||||
|
||||
export default passportAppointmentData;
|
91
src/data/Notification/NotificationData.tsx
Normal file
91
src/data/Notification/NotificationData.tsx
Normal file
@ -0,0 +1,91 @@
|
||||
const notificationData = [
|
||||
{
|
||||
id: '1',
|
||||
title: 'Pembayaran Permohonan',
|
||||
message:
|
||||
'Anda belum melakukan pembayaran untuk IRMA WAHYUDINI. Silakan melakukan pembayaran sebelum Selasa, 8 April 2025, pukul 23:33:03 WIB.',
|
||||
details:
|
||||
'Bila tidak melakukan pembayaran, maka permohonan Anda akan otomatis ditolak oleh sistem.',
|
||||
timestamp: '2025-04-19T10:50:00+07:00',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: 'Pembayaran Permohonan',
|
||||
message:
|
||||
'Anda belum melakukan pembayaran untuk MUHAMMAD AMMAR. Silakan melakukan pembayaran sebelum Minggu, 29 September 2024, pukul 23:33:03 WIB.',
|
||||
details:
|
||||
'Bila tidak melakukan pembayaran, maka permohonan Anda akan otomatis ditolak oleh sistem.',
|
||||
timestamp: '2024-09-27T00:00:00+07:00',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: 'Hari Penjadwalan',
|
||||
message:
|
||||
'Halo SALWA AISYAH ADHANI, hari ini adalah jadwal kunjungan Anda ke KANTOR IMIGRASI DEPOK pada sesi Senin, 7 November 2022, pukul 12:30-15:00 WIB.',
|
||||
details:
|
||||
'Kode Permohonan Anda adalah 2068000001633869. Pastikan Anda membawa dokumen yang dibutuhkan.',
|
||||
timestamp: '2022-11-07T00:00:00+07:00',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: 'Dokumen Siap Diambil',
|
||||
message:
|
||||
'Dokumen paspor atas nama NURUL HUDA telah selesai diproses dan siap untuk diambil di KANTOR IMIGRASI YOGYAKARTA.',
|
||||
details:
|
||||
'Harap ambil dokumen dalam waktu 14 hari kerja sejak pemberitahuan ini.',
|
||||
timestamp: '2025-04-18T14:20:00+07:00',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: 'Jadwal Ulang Permohonan',
|
||||
message:
|
||||
'Permohonan atas nama LUTFI HAKIM perlu dijadwalkan ulang karena adanya gangguan sistem.',
|
||||
details:
|
||||
'Silakan pilih jadwal baru melalui aplikasi sebelum Jumat, 21 April 2025.',
|
||||
timestamp: '2025-04-17T09:10:00+07:00',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: 'Verifikasi Berhasil',
|
||||
message:
|
||||
'Verifikasi identitas untuk ANISA FITRIANI telah berhasil dilakukan.',
|
||||
details:
|
||||
'Anda dapat melanjutkan ke tahap selanjutnya yaitu pembayaran permohonan.',
|
||||
timestamp: '2025-04-16T13:45:00+07:00',
|
||||
},
|
||||
{
|
||||
id: '7',
|
||||
title: 'Permohonan Ditolak',
|
||||
message:
|
||||
'Permohonan atas nama RAKA ARDIANSYAH ditolak karena dokumen tidak lengkap.',
|
||||
details: 'Silakan ajukan ulang permohonan dengan dokumen yang sesuai.',
|
||||
timestamp: '2025-04-14T11:30:00+07:00',
|
||||
},
|
||||
{
|
||||
id: '8',
|
||||
title: 'Batas Waktu Pembayaran',
|
||||
message:
|
||||
'Pembayaran untuk permohonan atas nama SITI AMINAH akan berakhir dalam 1 jam.',
|
||||
details:
|
||||
'Pastikan pembayaran dilakukan sebelum batas waktu agar permohonan tidak dibatalkan.',
|
||||
timestamp: '2025-04-19T21:00:00+07:00',
|
||||
},
|
||||
{
|
||||
id: '9',
|
||||
title: 'Sesi Foto dan Biometrik',
|
||||
message:
|
||||
'Jadwal sesi foto dan biometrik atas nama DANIL MAULANA adalah pada Rabu, 23 April 2025 pukul 09:00 WIB.',
|
||||
details: 'Mohon hadir 15 menit lebih awal dengan membawa dokumen asli.',
|
||||
timestamp: '2025-04-20T08:00:00+07:00',
|
||||
},
|
||||
{
|
||||
id: '10',
|
||||
title: 'Pembayaran Berhasil',
|
||||
message:
|
||||
'Pembayaran untuk permohonan atas nama TIA ROSMAWATI telah berhasil.',
|
||||
details: 'Silakan menunggu informasi jadwal kedatangan.',
|
||||
timestamp: '2025-04-15T10:00:00+07:00',
|
||||
},
|
||||
];
|
||||
|
||||
export default notificationData;
|
@ -7,11 +7,11 @@ 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 genderData from '../../data/DropdownData/GenderData';
|
||||
import provinceData from '../../data/DropdownData/ProvinceData';
|
||||
import cityData from '../../data/DropdownData/CityData';
|
||||
import districtData from '../../data/DropdownData/DistrictData';
|
||||
import postalCodeData from '../../data/DropdownData/PostalCodeData';
|
||||
import {Button} from 'react-native-paper';
|
||||
|
||||
type EditProfileScreenNavigationProp = NativeStackNavigationProp<
|
||||
|
@ -1,21 +1,72 @@
|
||||
import React from 'react';
|
||||
import {StyleSheet, Text, View} from 'react-native';
|
||||
import {FlatList, StatusBar, Text, View} from 'react-native';
|
||||
import styles from './styles';
|
||||
import Colors from '../../../assets/styles/Colors';
|
||||
import passportAppointmentData from '../../data/History/PassportAppointmentData';
|
||||
import PassportAppointmentCard from '../../components/PassportAppointmentCard';
|
||||
import {useNavigation, useNavigationState} from '@react-navigation/native';
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import {RootStackParamList} from '../../navigation/type';
|
||||
import {NativeStackNavigationProp} from '@react-navigation/native-stack';
|
||||
|
||||
type HistoryScreenNavigationProp = NativeStackNavigationProp<
|
||||
RootStackParamList,
|
||||
'History'
|
||||
>;
|
||||
|
||||
const ItemSeparator = () => <View style={styles.flatllistGap} />;
|
||||
|
||||
function HistoryScreen() {
|
||||
const navigation = useNavigation<HistoryScreenNavigationProp>();
|
||||
const previousRoute = useNavigationState(state => {
|
||||
const index = state.index;
|
||||
return index > 0 ? state.routes[index - 1].name : null;
|
||||
});
|
||||
|
||||
const showNavBackAppBar = previousRoute === 'NavigationRoute';
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>History Screen</Text>
|
||||
<StatusBar
|
||||
backgroundColor={Colors.secondary30.color}
|
||||
barStyle="light-content"
|
||||
/>
|
||||
{showNavBackAppBar ? (
|
||||
<View style={styles.appBarNavBackContainer}>
|
||||
<Icon
|
||||
name="arrow-left"
|
||||
size={24}
|
||||
style={styles.appBarNavBackIcon}
|
||||
color={Colors.neutral100.color}
|
||||
onPress={() => navigation.goBack()}
|
||||
/>
|
||||
<Text style={styles.appBarNavBackTitle}>Riwayat</Text>
|
||||
</View>
|
||||
) : (
|
||||
<View style={styles.appBarContainer}>
|
||||
<Text style={styles.appBarTitle}>Riwayat</Text>
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.topBackground} />
|
||||
<View style={styles.cardWrapper}>
|
||||
<FlatList
|
||||
data={passportAppointmentData}
|
||||
renderItem={({item}) => (
|
||||
<PassportAppointmentCard
|
||||
applicantName={item.applicantName}
|
||||
applicantCount={item.applicantCount}
|
||||
appointmentDate={item.appointmentDate}
|
||||
appointmentTime={item.appointmentTime}
|
||||
serviceUnit={item.serviceUnit}
|
||||
status={item.status}
|
||||
/>
|
||||
)}
|
||||
keyExtractor={item => item.id}
|
||||
ItemSeparatorComponent={ItemSeparator}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
});
|
||||
|
||||
export default HistoryScreen;
|
||||
|
52
src/screens/history/styles.tsx
Normal file
52
src/screens/history/styles.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
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.notoSansExtraBold,
|
||||
fontSize: 28,
|
||||
marginStart: 16,
|
||||
includeFontPadding: false,
|
||||
},
|
||||
appBarContainer: {
|
||||
height: 64,
|
||||
backgroundColor: Colors.secondary30.color,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
appBarNavBackContainer: {
|
||||
height: 64,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: Colors.secondary30.color,
|
||||
},
|
||||
appBarNavBackTitle: {
|
||||
color: Colors.neutral100.color,
|
||||
...FontFamily.notoSansRegular,
|
||||
fontSize: 22,
|
||||
marginStart: 16,
|
||||
},
|
||||
appBarNavBackIcon: {
|
||||
marginLeft: 16,
|
||||
},
|
||||
topBackground: {
|
||||
backgroundColor: Colors.secondary30.color,
|
||||
height: 85,
|
||||
alignItems: 'center',
|
||||
},
|
||||
cardWrapper: {
|
||||
margin: 16,
|
||||
marginBottom: 165,
|
||||
marginTop: -69,
|
||||
},
|
||||
flatllistGap: {
|
||||
height: 8,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
@ -1,11 +1,109 @@
|
||||
import * as React from 'react';
|
||||
import styles from './styles';
|
||||
import {View, Text} from 'react-native';
|
||||
import {View, Text, StatusBar, FlatList} from 'react-native';
|
||||
import Colors from '../../../assets/styles/Colors';
|
||||
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 RegularPassportIcon from '../../../assets/icons/regular_passport.svg';
|
||||
import ExpressPassportIcon from '../../../assets/icons/express_passport.svg';
|
||||
import GuidebookIcon from '../../../assets/icons/guidebook.svg';
|
||||
import EazyPassportIcon from '../../../assets/icons/eazy_passport.svg';
|
||||
import passportAppointmentData from '../../data/History/PassportAppointmentData';
|
||||
import PassportAppointmentCard from '../../components/PassportAppointmentCard';
|
||||
|
||||
type HomeScreenNavigationProp = NativeStackNavigationProp<
|
||||
RootStackParamList,
|
||||
'Home'
|
||||
>;
|
||||
|
||||
const ItemSeparator = () => <View style={styles.flatllistGap} />;
|
||||
|
||||
const RenderContent = () => {
|
||||
const navigation = useNavigation<HomeScreenNavigationProp>();
|
||||
|
||||
return (
|
||||
<>
|
||||
<View style={styles.topContainer} />
|
||||
<View style={styles.serviceContainer}>
|
||||
<Text style={styles.serviceText}>Layanan</Text>
|
||||
<View style={styles.serviceOptionWrapper}>
|
||||
<View style={styles.serviceOptionContainer}>
|
||||
<View style={styles.serviceIcon}>
|
||||
<RegularPassportIcon />
|
||||
</View>
|
||||
<Text style={styles.serviceDesc}>Paspor Reguler</Text>
|
||||
</View>
|
||||
<View style={styles.serviceOptionContainer}>
|
||||
<View style={styles.serviceIcon}>
|
||||
<ExpressPassportIcon />
|
||||
</View>
|
||||
<Text style={styles.serviceDesc}>Paspor Percepatan</Text>
|
||||
</View>
|
||||
<View style={styles.serviceOptionContainer}>
|
||||
<View style={styles.serviceIcon}>
|
||||
<GuidebookIcon />
|
||||
</View>
|
||||
<Text style={styles.serviceDesc}>Buku Panduan</Text>
|
||||
</View>
|
||||
<View style={styles.serviceOptionContainer}>
|
||||
<View style={styles.serviceIcon}>
|
||||
<EazyPassportIcon />
|
||||
</View>
|
||||
<Text style={styles.serviceDesc}>EAZY Pasport</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.applicationStatusContainer}>
|
||||
<View style={styles.applicationStatusTextWrapper}>
|
||||
<Text style={styles.applicationStatusTitle}>Status Permohonan</Text>
|
||||
<Text
|
||||
style={styles.applicationStatusSeeAll}
|
||||
onPress={() => navigation.navigate('History')}>
|
||||
Lihat semua
|
||||
</Text>
|
||||
</View>
|
||||
<View style={styles.cardWrapper}>
|
||||
<FlatList
|
||||
data={passportAppointmentData.slice(0, 2)}
|
||||
renderItem={({item}) => (
|
||||
<PassportAppointmentCard
|
||||
applicantName={item.applicantName}
|
||||
applicantCount={item.applicantCount}
|
||||
appointmentDate={item.appointmentDate}
|
||||
appointmentTime={item.appointmentTime}
|
||||
serviceUnit={item.serviceUnit}
|
||||
status={item.status}
|
||||
/>
|
||||
)}
|
||||
keyExtractor={item => item.id}
|
||||
ItemSeparatorComponent={ItemSeparator}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
function HomeScreen() {
|
||||
const navigation = useNavigation<HomeScreenNavigationProp>();
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Home Screen</Text>
|
||||
<StatusBar
|
||||
backgroundColor={Colors.secondary30.color}
|
||||
barStyle="light-content"
|
||||
/>
|
||||
<View style={styles.appBarContainer}>
|
||||
<Text style={styles.appBarTitle}>Halo, Salwa!</Text>
|
||||
<Icon
|
||||
name="bell-outline"
|
||||
size={24}
|
||||
color={Colors.neutral100.color}
|
||||
onPress={() => navigation.navigate('Notification')}
|
||||
/>
|
||||
</View>
|
||||
<FlatList data={[{}]} renderItem={() => <RenderContent />} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
@ -1,19 +1,87 @@
|
||||
import {StyleSheet} from 'react-native';
|
||||
import Colors from '../../../assets/styles/Colors';
|
||||
import FontFamily from '../../../assets/styles/FontFamily';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
bottomNavLabel: {
|
||||
appBarTitle: {
|
||||
color: Colors.neutral100.color,
|
||||
...FontFamily.notoSansExtraBold,
|
||||
fontSize: 28,
|
||||
marginVertical: 14,
|
||||
},
|
||||
appBarContainer: {
|
||||
height: 64,
|
||||
backgroundColor: Colors.secondary30.color,
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 16,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
topContainer: {
|
||||
backgroundColor: Colors.secondary30.color,
|
||||
height: 245,
|
||||
alignItems: 'center',
|
||||
},
|
||||
serviceContainer: {
|
||||
marginVertical: 12,
|
||||
marginHorizontal: 16,
|
||||
gap: 12,
|
||||
},
|
||||
serviceText: {
|
||||
color: Colors.primary30.color,
|
||||
...FontFamily.notoSansExtraBold,
|
||||
fontSize: 18,
|
||||
},
|
||||
serviceOptionWrapper: {
|
||||
flexDirection: 'row',
|
||||
gap: 10,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
serviceOptionContainer: {
|
||||
alignItems: 'center',
|
||||
marginHorizontal: 12,
|
||||
},
|
||||
serviceIcon: {
|
||||
padding: 8,
|
||||
backgroundColor: Colors.secondary70.color,
|
||||
borderRadius: 4,
|
||||
},
|
||||
serviceDesc: {
|
||||
width: 60,
|
||||
textAlign: 'center',
|
||||
alignSelf: 'center',
|
||||
fontSize: 10,
|
||||
marginTop: 8,
|
||||
color: Colors.primary30.color,
|
||||
...FontFamily.notoSansRegular,
|
||||
},
|
||||
applicationStatusContainer: {
|
||||
marginHorizontal: 16,
|
||||
},
|
||||
applicationStatusTextWrapper: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
marginVertical: 12,
|
||||
alignItems: 'center',
|
||||
},
|
||||
applicationStatusTitle: {
|
||||
color: Colors.primary30.color,
|
||||
...FontFamily.notoSansExtraBold,
|
||||
fontSize: 18,
|
||||
},
|
||||
applicationStatusSeeAll: {
|
||||
color: Colors.secondary30.color,
|
||||
fontSize: 12,
|
||||
position: 'absolute',
|
||||
...FontFamily.notoSansSemiBold,
|
||||
},
|
||||
cardWrapper: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
flatllistGap: {
|
||||
height: 8,
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -1,21 +1,86 @@
|
||||
import React from 'react';
|
||||
import {StyleSheet, Text, View} from 'react-native';
|
||||
import {FlatList, StatusBar, Text, View} from 'react-native';
|
||||
import Colors from '../../../assets/styles/Colors';
|
||||
import styles from './styles';
|
||||
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 dayjs from 'dayjs';
|
||||
import 'dayjs/locale/id';
|
||||
import notificationData from '../../data/Notification/NotificationData';
|
||||
|
||||
type NotificationScreenNavigationProp = NativeStackNavigationProp<
|
||||
RootStackParamList,
|
||||
'Notification'
|
||||
>;
|
||||
|
||||
type NotificationCardProps = {
|
||||
title: string;
|
||||
message: string;
|
||||
details: string;
|
||||
timestamp: string;
|
||||
};
|
||||
|
||||
const NotificationCard: React.FC<NotificationCardProps> = ({
|
||||
title,
|
||||
message,
|
||||
details,
|
||||
timestamp,
|
||||
}) => {
|
||||
dayjs.locale('id');
|
||||
const formattedTime = dayjs(timestamp).format('D MMMM YYYY');
|
||||
return (
|
||||
<View style={styles.cardContainer}>
|
||||
<View style={styles.topCardContentWrapper}>
|
||||
<Text style={styles.notificationTitle}>{title}</Text>
|
||||
<Text style={styles.notificationTime}>{formattedTime}</Text>
|
||||
</View>
|
||||
<Text style={styles.notificationMessage}>{message}</Text>
|
||||
<Text style={styles.notificationDetail}>{details}</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const ItemSeparator = () => <View style={styles.flatllistGap} />;
|
||||
|
||||
function NotificationScreen() {
|
||||
const navigation = useNavigation<NotificationScreenNavigationProp>();
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text>Notification 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}>Notifikasi</Text>
|
||||
</View>
|
||||
<View style={styles.topBackground} />
|
||||
<View style={styles.cardWrapper}>
|
||||
<FlatList
|
||||
data={notificationData}
|
||||
renderItem={({item}) => (
|
||||
<NotificationCard
|
||||
title={item.title}
|
||||
message={item.message}
|
||||
details={item.details}
|
||||
timestamp={item.timestamp}
|
||||
/>
|
||||
)}
|
||||
keyExtractor={item => item.id}
|
||||
ItemSeparatorComponent={ItemSeparator}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
});
|
||||
|
||||
export default NotificationScreen;
|
||||
|
70
src/screens/notification/styles.tsx
Normal file
70
src/screens/notification/styles.tsx
Normal file
@ -0,0 +1,70 @@
|
||||
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.neutral100.color,
|
||||
...FontFamily.notoSansRegular,
|
||||
fontSize: 22,
|
||||
marginStart: 16,
|
||||
},
|
||||
appBarIcon: {
|
||||
marginLeft: 16,
|
||||
},
|
||||
appBarContainer: {
|
||||
height: 64,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: Colors.secondary30.color,
|
||||
},
|
||||
topBackground: {
|
||||
backgroundColor: Colors.secondary30.color,
|
||||
height: 85,
|
||||
alignItems: 'center',
|
||||
},
|
||||
cardWrapper: {
|
||||
margin: 16,
|
||||
marginBottom: 165,
|
||||
marginTop: -69,
|
||||
},
|
||||
cardContainer: {
|
||||
borderRadius: 8,
|
||||
padding: 16,
|
||||
backgroundColor: Colors.neutral100.color,
|
||||
borderWidth: 1,
|
||||
borderColor: Colors.secondary50.color,
|
||||
},
|
||||
topCardContentWrapper: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
flatllistGap: {
|
||||
height: 8,
|
||||
},
|
||||
notificationTitle: {
|
||||
fontSize: 14,
|
||||
...FontFamily.notoSansBold,
|
||||
},
|
||||
notificationMessage: {
|
||||
fontSize: 12,
|
||||
marginTop: 4,
|
||||
...FontFamily.notoSansRegular,
|
||||
},
|
||||
notificationDetail: {
|
||||
fontSize: 12,
|
||||
marginTop: 4,
|
||||
...FontFamily.notoSansRegular,
|
||||
},
|
||||
notificationTime: {
|
||||
fontSize: 10,
|
||||
...FontFamily.notoSansRegular,
|
||||
},
|
||||
});
|
||||
|
||||
export default styles;
|
@ -8,7 +8,7 @@ import styles from './styles';
|
||||
import TextInputComponent from '../../components/TextInput';
|
||||
import {Button, Checkbox} from 'react-native-paper';
|
||||
import Colors from '../../../assets/styles/Colors';
|
||||
import genderData from '../../model/DropdownData/GenderData';
|
||||
import genderData from '../../data/DropdownData/GenderData';
|
||||
|
||||
type RegisterScreenNavigationProp = NativeStackNavigationProp<
|
||||
RootStackParamList,
|
||||
|
Reference in New Issue
Block a user