import { useEffect, useState } from 'react' import { ScrollView, StyleSheet, Text, View } from 'react-native' import { useLocalSearchParams } from 'expo-router' import { useTheme } from '../constants/ThemeContext' import { type ThemeTokens } from '../constants/ItmsTheme' import { Card, Loading, ErrText, SectionTitle } from '../components/ui' import { rowTitle, rowDate, rowAuthor, pick, rowEntries } from '../constants/rows' import { itmsBoardArticle, itmsErrorMessage, type RowMap } from './itmsApi' /* * 공지 상세(BBSAdminManageController /bbs/admin/selectBoardArticle.do — body {board:{...}}). * 목록 raw(게시글 식별자 포함)를 그대로 board 로 넘겨 본문 보강. */ export default function NoticeDetail() { const { raw } = useLocalSearchParams<{ raw?: string }>() const { t } = useTheme() const s = makeStyles(t) const seed: RowMap = raw ? safeParse(raw) : {} const [row, setRow] = useState(seed) const [loading, setLoading] = useState(Object.keys(seed).length > 0) const [err, setErr] = useState('') useEffect(() => { let alive = true if (Object.keys(seed).length === 0) { setLoading(false); return } ;(async () => { try { const detail = await itmsBoardArticle(seed) const merged = { ...seed, ...(detail?.resultVo ?? detail?.board ?? detail ?? {}) } if (alive) setRow(merged) } catch (e) { if (alive) setErr(itmsErrorMessage(e)) } finally { if (alive) setLoading(false) } })() return () => { alive = false } // eslint-disable-next-line react-hooks/exhaustive-deps }, [raw]) if (loading && !pick(seed, ['nttCn', 'contents', 'cn'])) return const content = pick(row, ['nttCn', 'contents', 'cn', 'articleCn', 'bdwrCn']) return ( {rowTitle(row)} {[rowAuthor(row), rowDate(row)].filter(Boolean).join(' · ')} {!!content && ( {content} )} 항목 {rowEntries(row).map((e) => ( {e.key} {e.value} ))} ) } function safeParse(raw: string): RowMap { try { return JSON.parse(raw) as RowMap } catch { return {} } } const makeStyles = (t: ThemeTokens) => StyleSheet.create({ wrap: { flex: 1, backgroundColor: t.bg }, content: { padding: 16 }, title: { color: t.text, fontSize: 19, fontWeight: '900' }, meta: { color: t.muted, fontSize: 12, marginTop: 6 }, body: { color: t.text, fontSize: 14, lineHeight: 21 }, mt: { marginTop: 20 }, row: { flexDirection: 'row', justifyContent: 'space-between', gap: 12, paddingVertical: 8, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: t.border }, k: { color: t.muted, fontSize: 12, flexShrink: 0, maxWidth: '40%' }, v: { color: t.text, fontSize: 13, fontWeight: '600', flex: 1, textAlign: 'right' }, })