85 lines
2.8 KiB
TypeScript
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 },
|
|
})
|