From 3ee7ec87bee8f5f99969782080a1672522d4ebe8 Mon Sep 17 00:00:00 2001 From: Mekan1206 Date: Sat, 20 Sep 2025 13:21:20 +0500 Subject: [PATCH] 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. --- app/(tabs)/programs.tsx | 152 +++++++++++++++++++++++----------------- utils/programs.ts | 31 ++++++++ 2 files changed, 120 insertions(+), 63 deletions(-) create mode 100644 utils/programs.ts diff --git a/app/(tabs)/programs.tsx b/app/(tabs)/programs.tsx index 605a88a..7a363e7 100644 --- a/app/(tabs)/programs.tsx +++ b/app/(tabs)/programs.tsx @@ -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 ; + case 'FontAwesome5': + return ; + default: + return null; + } }; export default function Programs() { const colorScheme = 'dark'; - const [activeDay, setActiveDay] = useState('Day 1'); + const [activeDay, setActiveDay] = useState(null); const insets = useSafeAreaInsets(); + const [activities, setActivities] = useState({}); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); - const activities: Activities = { - 'Day 1': [ - { - time: '16:30 - 19:15', - title: 'Depart for Mecca', - description: 'From your location to Mecca', - icon: , - transport: 'Transport to hotel', - }, - { - time: '21:00 - 23:00', - title: 'Dinner at Al-Baik', - description: 'Masjid al-', - icon: , - }, - { - time: '00:00 - 04:00', - title: 'Tawaf', - description: 'Kaaba', - icon: , - }, - ], - 'Day 2': [ - { - time: '10:00 - 12:00', - title: 'Shopping', - description: 'Zamzam Tower', - icon: , - }, - ], - '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 ( + + + + ); + } + + if (error) { + return ( + + {error} + + ); + } return ( @@ -63,7 +82,7 @@ export default function Programs() { - {Object.keys(activities).map((day) => ( + {dayKeys.map((day) => ( - {activities[activeDay].map((activity, index) => ( - - - - {activity.time} - {activity.title} - {activity.description} + {activeDay && + activities[activeDay]?.map((activity, index) => ( + + + + {activity.time} + {activity.title} + {activity.description} + + + + - {activity.icon} + {activity.transport && ( + + + + + {activity.transport} + + )} - {activity.transport && ( - - - - - {activity.transport} - - )} - - ))} + ))} ); @@ -105,6 +127,10 @@ const styles = StyleSheet.create({ container: { flex: 1, }, + center: { + justifyContent: 'center', + alignItems: 'center', + }, header: { alignItems: 'center', paddingVertical: 10, diff --git a/utils/programs.ts b/utils/programs.ts new file mode 100644 index 0000000..f3e6a50 --- /dev/null +++ b/utils/programs.ts @@ -0,0 +1,31 @@ + +import { FontAwesome, FontAwesome5, MaterialCommunityIcons } from '@expo/vector-icons'; + +export type ProgramActivity = { + time: string; + title: string; + description: string; + iconSet: 'FontAwesome' | 'FontAwesome5' | 'MaterialCommunityIcons'; + iconName: React.ComponentProps['name'] | React.ComponentProps['name'] | React.ComponentProps['name']; + transport?: string; +}; + +export type ProgramActivities = { + [date: string]: ProgramActivity[]; +}; + +const PROGRAMS_URL = 'http://kepilhyzmat.com/assets/programs.json'; + +export const getPrograms = async (): Promise => { + try { + const response = await fetch(PROGRAMS_URL); + if (!response.ok) { + throw new Error(`Request failed with status ${response.status}`); + } + const data: ProgramActivities = await response.json(); + return data; + } catch (error) { + console.error('Failed to fetch programs:', error); + throw error; + } +};