Implement program fetching and loading state in Programs component
- Added asynchronous fetching of program activities using getPrograms. - Introduced loading and error states to enhance user experience. - Refactored activity rendering to handle dynamic data and improved icon rendering logic.
This commit is contained in:
@@ -1,59 +1,78 @@
|
||||
import { useState } from 'react';
|
||||
import { StyleSheet, Text, View, TouchableOpacity, ScrollView } from 'react-native';
|
||||
import { StyleSheet, Text, View, TouchableOpacity, ScrollView, ActivityIndicator } from 'react-native';
|
||||
import Colors from '@/constants/Colors';
|
||||
import { FontAwesome, FontAwesome5 } from '@expo/vector-icons';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { getPrograms, ProgramActivities, ProgramActivity } from '@/utils/programs';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
type Activity = {
|
||||
time: string;
|
||||
title: string;
|
||||
description: string;
|
||||
icon: React.ReactNode;
|
||||
transport?: string;
|
||||
};
|
||||
const Icon = ({ iconSet, iconName }: { iconSet: ProgramActivity['iconSet']; iconName: ProgramActivity['iconName'] }) => {
|
||||
const color = "black";
|
||||
const size = 24;
|
||||
|
||||
type Activities = {
|
||||
[key: string]: Activity[];
|
||||
switch (iconSet) {
|
||||
case 'FontAwesome':
|
||||
return <FontAwesome name={iconName as any} size={size} color={color} />;
|
||||
case 'FontAwesome5':
|
||||
return <FontAwesome5 name={iconName as any} size={size} color={color} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export default function Programs() {
|
||||
const colorScheme = 'dark';
|
||||
const [activeDay, setActiveDay] = useState('Day 1');
|
||||
const [activeDay, setActiveDay] = useState<string | null>(null);
|
||||
const insets = useSafeAreaInsets();
|
||||
const [activities, setActivities] = useState<ProgramActivities>({});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const activities: Activities = {
|
||||
'Day 1': [
|
||||
{
|
||||
time: '16:30 - 19:15',
|
||||
title: 'Depart for Mecca',
|
||||
description: 'From your location to Mecca',
|
||||
icon: <FontAwesome name="plane" size={24} color="black" />,
|
||||
transport: 'Transport to hotel',
|
||||
},
|
||||
{
|
||||
time: '21:00 - 23:00',
|
||||
title: 'Dinner at Al-Baik',
|
||||
description: 'Masjid al-',
|
||||
icon: <FontAwesome name="cutlery" size={24} color="black" />,
|
||||
},
|
||||
{
|
||||
time: '00:00 - 04:00',
|
||||
title: 'Tawaf',
|
||||
description: 'Kaaba',
|
||||
icon: <FontAwesome5 name="kaaba" size={24} color="black" />,
|
||||
},
|
||||
],
|
||||
'Day 2': [
|
||||
{
|
||||
time: '10:00 - 12:00',
|
||||
title: 'Shopping',
|
||||
description: 'Zamzam Tower',
|
||||
icon: <FontAwesome name="shopping-bag" size={24} color="black" />,
|
||||
},
|
||||
],
|
||||
'Day 3': [],
|
||||
'Day 4': [],
|
||||
};
|
||||
useEffect(() => {
|
||||
const fetchPrograms = async () => {
|
||||
try {
|
||||
const data = await getPrograms();
|
||||
setActivities(data);
|
||||
if (Object.keys(data).length > 0) {
|
||||
const today = new Date();
|
||||
const day = String(today.getDate()).padStart(2, '0');
|
||||
const month = String(today.getMonth() + 1).padStart(2, '0');
|
||||
const year = today.getFullYear();
|
||||
const formattedDate = `${day}.${month}.${year}`;
|
||||
|
||||
if (data[formattedDate]) {
|
||||
setActiveDay(formattedDate);
|
||||
} else {
|
||||
setActiveDay(Object.keys(data)[0]);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
setError('Failed to load program activities.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchPrograms();
|
||||
}, []);
|
||||
|
||||
const dayKeys = Object.keys(activities);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<View style={[styles.container, styles.center]}>
|
||||
<ActivityIndicator size="large" color={Colors[colorScheme].text} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<View style={[styles.container, styles.center]}>
|
||||
<Text style={{ color: Colors[colorScheme].text }}>{error}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={[styles.container, { backgroundColor: Colors[colorScheme].background, paddingTop: insets.top }]}>
|
||||
@@ -63,7 +82,7 @@ export default function Programs() {
|
||||
|
||||
<View>
|
||||
<ScrollView horizontal showsHorizontalScrollIndicator={false} style={styles.daysScroll}>
|
||||
{Object.keys(activities).map((day) => (
|
||||
{dayKeys.map((day) => (
|
||||
<TouchableOpacity
|
||||
key={day}
|
||||
style={[styles.dayButton, activeDay === day && styles.activeDayButton]}
|
||||
@@ -76,26 +95,29 @@ export default function Programs() {
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.content}>
|
||||
{activities[activeDay].map((activity, index) => (
|
||||
<View key={index}>
|
||||
<View style={styles.activityCard}>
|
||||
<View style={styles.timeContainer}>
|
||||
<Text style={styles.timeText}>{activity.time}</Text>
|
||||
<Text style={styles.activityTitle}>{activity.title}</Text>
|
||||
<Text style={styles.activityDescription}>{activity.description}</Text>
|
||||
{activeDay &&
|
||||
activities[activeDay]?.map((activity, index) => (
|
||||
<View key={index}>
|
||||
<View style={styles.activityCard}>
|
||||
<View style={styles.timeContainer}>
|
||||
<Text style={styles.timeText}>{activity.time}</Text>
|
||||
<Text style={styles.activityTitle}>{activity.title}</Text>
|
||||
<Text style={styles.activityDescription}>{activity.description}</Text>
|
||||
</View>
|
||||
<View style={styles.iconContainer}>
|
||||
<Icon iconSet={activity.iconSet} iconName={activity.iconName} />
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.iconContainer}>{activity.icon}</View>
|
||||
{activity.transport && (
|
||||
<View style={styles.transportContainer}>
|
||||
<View style={styles.dot} />
|
||||
<View style={styles.dot} />
|
||||
<View style={styles.dot} />
|
||||
<Text style={styles.transportText}>{activity.transport}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
{activity.transport && (
|
||||
<View style={styles.transportContainer}>
|
||||
<View style={styles.dot} />
|
||||
<View style={styles.dot} />
|
||||
<View style={styles.dot} />
|
||||
<Text style={styles.transportText}>{activity.transport}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
))}
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
@@ -105,6 +127,10 @@ const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
center: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
header: {
|
||||
alignItems: 'center',
|
||||
paddingVertical: 10,
|
||||
|
||||
Reference in New Issue
Block a user