guardia-messenger/components/RelatedSR.tsx

85 lines
2.8 KiB
TypeScript

import { useEffect, useState } from 'react'
import { View, Text, TouchableOpacity, StyleSheet, ActivityIndicator } from 'react-native'
import { router } from 'expo-router'
import { COLORS, PRIORITY_COLOR, STATUS_COLOR } from '../constants/Config'
import { getRelatedSR } from '../services/api'
interface Props {
srId: number
}
interface RelatedItem {
id: number
sr_id?: string
title: string
status?: string
priority?: string
}
/**
* 기능 #7 — 관련 SR 자동 연결 표시
* GET /api/tasks?related_to={id} → 최대 3개 카드, 탭 시 상세 이동
*/
export default function RelatedSR({ srId }: Props) {
const [items, setItems] = useState<RelatedItem[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
let alive = true
;(async () => {
try {
const res = await getRelatedSR(srId)
const list: RelatedItem[] =
res.data?.content ?? res.data?.items ?? res.data ?? []
if (alive) setItems(list.slice(0, 3))
} catch {
if (alive) setItems([])
} finally {
if (alive) setLoading(false)
}
})()
return () => { alive = false }
}, [srId])
if (loading) return <ActivityIndicator style={{ marginVertical: 12 }} color={COLORS.accent} />
if (items.length === 0) {
return <Text style={s.empty}> SR이 .</Text>
}
return (
<View>
{items.map(it => (
<TouchableOpacity
key={it.id}
style={s.card}
onPress={() => router.push({ pathname: '/(tabs)/sr_detail', params: { id: String(it.id) } })}
>
<View style={s.head}>
<Text style={s.srId}>{it.sr_id ?? `#${it.id}`}</Text>
{!!it.status && (
<View style={[s.badge, { backgroundColor: (STATUS_COLOR[it.status] ?? COLORS.muted) + '22' }]}>
<Text style={[s.badgeText, { color: STATUS_COLOR[it.status] ?? COLORS.muted }]}>{it.status}</Text>
</View>
)}
</View>
<Text style={s.title} numberOfLines={1}>{it.title}</Text>
{!!it.priority && (
<Text style={[s.pri, { color: PRIORITY_COLOR[it.priority] ?? COLORS.muted }]}> {it.priority}</Text>
)}
</TouchableOpacity>
))}
</View>
)
}
const s = StyleSheet.create({
empty: { color: COLORS.muted, fontSize: 12, paddingVertical: 8 },
card: { backgroundColor: COLORS.light, borderRadius: 8, padding: 10, marginBottom: 8 },
head: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' },
srId: { fontSize: 11, color: COLORS.accent, fontWeight: '700' },
badge: { paddingHorizontal: 7, paddingVertical: 2, borderRadius: 9 },
badgeText: { fontSize: 9, fontWeight: '700' },
title: { fontSize: 13, color: COLORS.text, marginTop: 4 },
pri: { fontSize: 10, fontWeight: '700', marginTop: 4 },
})