// apps/mobile/app/(tabs)/meetings.tsx // 회의 리스트 — Supabase에서 fetch import { useEffect, useState } from 'react' import { View, Text, FlatList, Pressable, StyleSheet, ActivityIndicator, RefreshControl } from 'react-native' import { supabase } from '../../lib/supabase' interface Meeting { id: string title: string | null started_at: string status: string } export default function MeetingsScreen(): React.ReactElement { const [meetings, setMeetings] = useState([]) const [loading, setLoading] = useState(true) const [refreshing, setRefreshing] = useState(false) async function load(): Promise { try { const { data, error } = await supabase .from('meetings') .select('id, title, started_at, status') .order('started_at', { ascending: false }) .limit(50) if (!error && data) { setMeetings(data as Meeting[]) } } finally { setLoading(false) setRefreshing(false) } } useEffect(() => { void load() }, []) if (loading) { return ( ) } return ( item.id} contentContainerStyle={meetings.length === 0 ? styles.center : { padding: 16 }} refreshControl={ { setRefreshing(true) void load() }} tintColor="#f25b29" /> } ListEmptyComponent={ 아직 회의가 없습니다. Record 탭에서 새 녹음을 시작하세요. } renderItem={({ item }) => ( {item.title ?? '(제목 없음)'} {new Date(item.started_at).toLocaleString('ko-KR')} · {item.status} )} /> ) } const styles = StyleSheet.create({ center: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 32 }, empty: { color: '#8e8e93', textAlign: 'center', fontSize: 13 }, card: { backgroundColor: '#242427', padding: 16, borderRadius: 12, marginBottom: 12, borderWidth: 1, borderColor: 'rgba(255,255,255,0.04)' }, title: { color: '#ffffff', fontSize: 14, fontWeight: '500', marginBottom: 4 }, meta: { color: '#8e8e93', fontSize: 11 } })