guardia-messenger/components/SRSolutionHint.tsx

97 lines
2.9 KiB
TypeScript

/**
* SRSolutionHint (#24) — 과거 유사 SR 해결책 제안
*
* GET /api/tasks/?similar_to={sr_id}&status=closed&limit=3
* "유사 해결 사례" 섹션: 각 사례의 제목 / 해결 방법 / 해결 시간 표시.
*/
import { useState, useEffect } from 'react'
import { View, Text, Pressable, StyleSheet, ActivityIndicator } from 'react-native'
import { COLORS, API_BASE } from '../constants/Config'
import { authFetch } from '../utils/auth'
interface SimilarSR {
id: number
title: string
resolution?: string
resolved_at?: string
resolution_time?: string
}
interface Props {
srId: number | string
onOpen?: (id: number) => void
}
export function SRSolutionHint({ srId, onOpen }: Props) {
const [items, setItems] = useState<SimilarSR[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
let alive = true
;(async () => {
setLoading(true)
try {
const res = await authFetch(
`${API_BASE}/api/tasks/?similar_to=${encodeURIComponent(String(srId))}&status=closed&limit=3`,
)
if (res.ok) {
const d = await res.json()
const list: SimilarSR[] = Array.isArray(d) ? d : d.items ?? d.results ?? []
if (alive) setItems(list.slice(0, 3))
} else if (alive) {
setItems([])
}
} catch {
if (alive) setItems([])
} finally {
if (alive) setLoading(false)
}
})()
return () => {
alive = false
}
}, [srId])
if (loading) {
return (
<View style={S.wrap}>
<Text style={S.title}>🔁 </Text>
<ActivityIndicator color={COLORS.accent} style={{ marginTop: 6 }} />
</View>
)
}
if (items.length === 0) return null
return (
<View style={S.wrap}>
<Text style={S.title}>🔁 </Text>
{items.map(sr => (
<Pressable key={sr.id} style={S.card} onPress={() => onOpen?.(sr.id)}>
<Text style={S.cardTitle} numberOfLines={1}>
#{sr.id} {sr.title}
</Text>
{sr.resolution ? (
<Text style={S.cardSol} numberOfLines={3}>
💡 {sr.resolution}
</Text>
) : null}
{sr.resolution_time || sr.resolved_at ? (
<Text style={S.cardTime}> : {sr.resolution_time ?? sr.resolved_at}</Text>
) : null}
</Pressable>
))}
</View>
)
}
export default SRSolutionHint
const S = StyleSheet.create({
wrap: { backgroundColor: COLORS.card, borderRadius: 14, padding: 14, borderWidth: 1, borderColor: COLORS.border },
title: { fontSize: 13, fontWeight: '700', color: COLORS.text, marginBottom: 8 },
card: { backgroundColor: COLORS.light, borderRadius: 10, padding: 11, marginBottom: 6 },
cardTitle: { fontSize: 13, fontWeight: '600', color: COLORS.blue },
cardSol: { fontSize: 12, color: COLORS.text, marginTop: 4, lineHeight: 17 },
cardTime: { fontSize: 11, color: COLORS.muted, marginTop: 4 },
})