import { useEffect, useRef, useState } from 'react' import { Text, StyleSheet, Vibration } from 'react-native' interface Props { deadline: string // ISO 문자열 onExpire?: () => void } const URGENT_MS = 30 * 60 * 1000 // 30분 /** * 기능 #3 — SLA 카운트다운 타이머 * 매 초 갱신, 임박(30분 이내) 시 빨간색 + 1회 진동 */ export default function SlaTimer({ deadline, onExpire }: Props) { const [remaining, setRemaining] = useState( () => new Date(deadline).getTime() - Date.now() ) const buzzedRef = useRef(false) const expiredRef = useRef(false) useEffect(() => { buzzedRef.current = false expiredRef.current = false const tick = () => { const r = new Date(deadline).getTime() - Date.now() setRemaining(r) if (r < URGENT_MS && r > 0 && !buzzedRef.current) { buzzedRef.current = true try { Vibration.vibrate([0, 500, 200, 500]) } catch {} } if (r <= 0 && !expiredRef.current) { expiredRef.current = true onExpire?.() } } tick() const interval = setInterval(tick, 1000) return () => clearInterval(interval) }, [deadline, onExpire]) const overdue = remaining < 0 const abs = Math.abs(remaining) const hours = Math.floor(abs / 3600000) const minutes = Math.floor((abs % 3600000) / 60000) const seconds = Math.floor((abs % 60000) / 1000) const isUrgent = remaining < URGENT_MS const pad = (n: number) => String(n).padStart(2, '0') const label = overdue ? `초과 ${pad(hours)}:${pad(minutes)}:${pad(seconds)}` : `${pad(hours)}:${pad(minutes)}:${pad(seconds)}` return ( {label} ) } const styles = StyleSheet.create({ timer: { fontVariant: ['tabular-nums'], fontWeight: '700', fontSize: 15, color: '#64748B' }, urgent: { color: '#f59e0b' }, overdue: { color: '#ef4444' }, })