guardia-messenger/app/(tabs)/change_calendar.tsx

118 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react'
import {
View, Text, TouchableOpacity, StyleSheet, FlatList, ActivityIndicator,
} from 'react-native'
import { COLORS } from '../../constants/Config'
import { getChangeCalendar } from '../../services/api'
const WEEKDAYS = ['일', '월', '화', '수', '목', '금', '토']
export default function ChangeCalendarScreen() {
const [now] = useState(new Date())
const [year, setYear] = useState(now.getFullYear())
const [month, setMonth] = useState(now.getMonth() + 1)
const [changes, setChanges] = useState<any[]>([])
const [selectedDay, setSelectedDay] = useState<number | null>(null)
const [loading, setLoading] = useState(false)
useEffect(() => {
setLoading(true)
getChangeCalendar(`${year}-${String(month).padStart(2, '0')}`)
.then(r => setChanges(r.data?.items ?? r.data ?? []))
.catch(() => setChanges([]))
.finally(() => setLoading(false))
}, [year, month])
const prevMonth = () => { if (month === 1) { setYear(y => y-1); setMonth(12) } else setMonth(m => m-1) }
const nextMonth = () => { if (month === 12) { setYear(y => y+1); setMonth(1) } else setMonth(m => m+1) }
const daysInMonth = new Date(year, month, 0).getDate()
const firstDay = new Date(year, month - 1, 1).getDay()
const hasChange = (day: number) =>
changes.some(c => new Date(c.scheduled_at ?? c.created_at).getDate() === day)
const dayChanges = selectedDay
? changes.filter(c => new Date(c.scheduled_at ?? c.created_at).getDate() === selectedDay)
: []
const cells: (number | null)[] = [
...Array(firstDay).fill(null),
...Array.from({ length: daysInMonth }, (_, i) => i + 1),
]
return (
<View style={s.container}>
{/* 헤더 */}
<View style={s.header}>
<TouchableOpacity onPress={prevMonth}><Text style={s.arrow}></Text></TouchableOpacity>
<Text style={s.month}>{year} {month}</Text>
<TouchableOpacity onPress={nextMonth}><Text style={s.arrow}></Text></TouchableOpacity>
</View>
{/* 요일 */}
<View style={s.weekRow}>
{WEEKDAYS.map(d => <Text key={d} style={[s.weekDay, d==='일'&&{color:COLORS.danger}, d==='토'&&{color:COLORS.accent}]}>{d}</Text>)}
</View>
{/* 날짜 그리드 */}
{loading ? <ActivityIndicator color={COLORS.accent} style={{ marginTop: 20 }} /> : (
<View style={s.grid}>
{cells.map((day, idx) => (
<TouchableOpacity
key={idx}
style={[s.cell, day === selectedDay && s.cellSelected]}
onPress={() => day && setSelectedDay(day === selectedDay ? null : day)}
disabled={!day}
>
{day && (
<>
<Text style={[s.dayText, day === selectedDay && s.dayTextSelected]}>{day}</Text>
{hasChange(day) && <View style={s.dot} />}
</>
)}
</TouchableOpacity>
))}
</View>
)}
{/* 선택 날짜 변경 목록 */}
{selectedDay && (
<View style={s.list}>
<Text style={s.listTitle}>{month}/{selectedDay} </Text>
{dayChanges.length === 0
? <Text style={s.empty}> .</Text>
: dayChanges.map((c, i) => (
<View key={i} style={s.changeCard}>
<Text style={s.changeTitle}>{c.title ?? c.subject}</Text>
<Text style={s.changeMeta}>{c.status} · {c.requester ?? c.requested_by}</Text>
</View>
))
}
</View>
)}
</View>
)
}
const s = StyleSheet.create({
container: { flex: 1, backgroundColor: COLORS.bg },
header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', padding: 16, backgroundColor: '#fff', borderBottomWidth: 1, borderBottomColor: COLORS.border },
arrow: { fontSize: 24, color: COLORS.accent, paddingHorizontal: 8 },
month: { fontSize: 16, fontWeight: '700', color: COLORS.text },
weekRow: { flexDirection: 'row', backgroundColor: '#fff', paddingVertical: 6 },
weekDay: { flex: 1, textAlign: 'center', fontSize: 12, fontWeight: '600', color: COLORS.muted },
grid: { flexDirection: 'row', flexWrap: 'wrap', backgroundColor: '#fff', borderBottomWidth: 1, borderBottomColor: COLORS.border },
cell: { width: '14.28%', aspectRatio: 1, alignItems: 'center', justifyContent: 'center' },
cellSelected: { backgroundColor: COLORS.light },
dayText: { fontSize: 14, color: COLORS.text },
dayTextSelected: { color: COLORS.accent, fontWeight: '700' },
dot: { width: 4, height: 4, borderRadius: 2, backgroundColor: COLORS.accent, marginTop: 2 },
list: { flex: 1, padding: 14 },
listTitle: { fontSize: 15, fontWeight: '700', color: COLORS.text, marginBottom: 10 },
empty: { color: COLORS.muted, fontSize: 14 },
changeCard: { backgroundColor: '#fff', borderRadius: 8, padding: 10, marginBottom: 6, elevation: 1 },
changeTitle: { fontSize: 14, fontWeight: '600', color: COLORS.text },
changeMeta: { fontSize: 12, color: COLORS.muted, marginTop: 2 },
})