// apps/mobile/app/(tabs)/meetings.tsx // 회의 리스트 — @d3ro/ui-native 사용 import { useEffect, useState } from 'react' import { View, FlatList, StyleSheet, ActivityIndicator, RefreshControl, Pressable } from 'react-native' import { MetalCard, PhosphorText, Led, d3roNativePalette } from '@d3ro/ui-native' import { supabase } from '../../lib/supabase' interface Meeting { id: string title: string | null started_at: string status: string } function statusLedColor(status: string): 'amber' | 'green' | 'red' | 'orange' { if (status === 'recording') return 'red' if (status === 'processing') return 'orange' if (status === 'completed') return 'green' return 'amber' } 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 : styles.listContent} style={styles.list} refreshControl={ { setRefreshing(true) void load() }} tintColor={d3roNativePalette.accent.amber} /> } ListEmptyComponent={ 아직 회의가 없습니다. Record 탭에서 새 녹음을 시작하세요. } renderItem={({ item }) => ( {item.status.toUpperCase()} {item.title ?? '(제목 없음)'} {new Date(item.started_at).toLocaleString('ko-KR')} )} /> ) } const styles = StyleSheet.create({ list: { backgroundColor: d3roNativePalette.bg.app }, center: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 32, backgroundColor: d3roNativePalette.bg.app }, listContent: { padding: 16 }, empty: { textAlign: 'center' }, card: { marginBottom: 12 }, cardHeader: { flexDirection: 'row', alignItems: 'center' } })