77 lines
2.4 KiB
TypeScript
77 lines
2.4 KiB
TypeScript
/**
|
|
* #37 Zero Trust 상태 뱃지
|
|
* GET /api/auth/network-status → { via: 'vpn'|'opennet'|'internal', level: 1|2|3 }
|
|
* 🟢 Internal / 🟡 VPN / 🟠 OpenNet
|
|
*/
|
|
import { useEffect, useState } from 'react'
|
|
import { View, Text, StyleSheet, ActivityIndicator } from 'react-native'
|
|
import { getNetworkStatus } from '../services/api'
|
|
|
|
type Via = 'vpn' | 'opennet' | 'internal' | string
|
|
|
|
interface NetStatus {
|
|
via: Via
|
|
level: 1 | 2 | 3 | number
|
|
}
|
|
|
|
const META: Record<string, { dot: string; label: string; color: string; bg: string }> = {
|
|
internal: { dot: '🟢', label: 'Internal', color: '#15803d', bg: '#dcfce7' },
|
|
vpn: { dot: '🟡', label: 'VPN', color: '#a16207', bg: '#fef9c3' },
|
|
opennet: { dot: '🟠', label: 'OpenNet', color: '#c2410c', bg: '#ffedd5' },
|
|
}
|
|
|
|
export default function ZeroTrustBadge() {
|
|
const [status, setStatus] = useState<NetStatus | null>(null)
|
|
const [loading, setLoading] = useState(true)
|
|
|
|
useEffect(() => {
|
|
let active = true
|
|
;(async () => {
|
|
try {
|
|
const r = await getNetworkStatus()
|
|
if (active) setStatus(r.data)
|
|
} catch {
|
|
// 서버 미응답 시 알 수 없음 처리
|
|
if (active) setStatus(null)
|
|
} finally {
|
|
if (active) setLoading(false)
|
|
}
|
|
})()
|
|
return () => { active = false }
|
|
}, [])
|
|
|
|
if (loading) {
|
|
return (
|
|
<View style={[s.badge, { backgroundColor: '#f1f5f9' }]}>
|
|
<ActivityIndicator size="small" color="#94a3b8" />
|
|
<Text style={[s.label, { color: '#94a3b8' }]}>네트워크 확인 중</Text>
|
|
</View>
|
|
)
|
|
}
|
|
|
|
const meta = (status && META[status.via]) || {
|
|
dot: '⚪', label: '알 수 없음', color: '#64748b', bg: '#f1f5f9',
|
|
}
|
|
|
|
return (
|
|
<View style={[s.badge, { backgroundColor: meta.bg }]}>
|
|
<Text style={s.dot}>{meta.dot}</Text>
|
|
<Text style={[s.label, { color: meta.color }]}>Zero Trust · {meta.label}</Text>
|
|
{status?.level != null && (
|
|
<Text style={[s.level, { color: meta.color }]}>Lv.{status.level}</Text>
|
|
)}
|
|
</View>
|
|
)
|
|
}
|
|
|
|
const s = StyleSheet.create({
|
|
badge: {
|
|
flexDirection: 'row', alignItems: 'center', gap: 6,
|
|
paddingHorizontal: 12, paddingVertical: 8, borderRadius: 12,
|
|
marginHorizontal: 16, marginTop: 12,
|
|
},
|
|
dot: { fontSize: 13 },
|
|
label: { fontSize: 13, fontWeight: '700', flex: 1 },
|
|
level: { fontSize: 11, fontWeight: '700', opacity: 0.8 },
|
|
})
|