/** * useGPSTag — GPS 위치 태깅 훅 (기능 #59) * * SR 등록 / 현장 체크인 시 현재 좌표를 자동 첨부한다. * expo-location 미설치 환경(개발/시뮬레이터)에서도 빌드/런타임이 깨지지 않도록 * 동적 require + graceful fallback 처리한다. * * 빌드 금기 준수: app.json 플러그인 등록 없이 런타임 권한 요청만 사용. */ import { useState, useCallback } from 'react' export interface GeoTag { lat: number lng: number accuracy?: number | null ts: string } type PermState = 'unknown' | 'granted' | 'denied' // 동적 로드 — 모듈이 없으면 null function loadLocation(): any | null { try { // eslint-disable-next-line @typescript-eslint/no-var-requires return require('expo-location') } catch { return null } } export function useGPSTag() { const [tag, setTag] = useState(null) const [perm, setPerm] = useState('unknown') const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const requestPermission = useCallback(async (): Promise => { const Location = loadLocation() if (!Location) { setError('위치 모듈을 사용할 수 없습니다 (EAS 빌드 필요)') setPerm('denied') return false } try { const { status } = await Location.requestForegroundPermissionsAsync() const granted = status === 'granted' setPerm(granted ? 'granted' : 'denied') if (!granted) setError('위치 권한이 거부되었습니다') return granted } catch (e: any) { setPerm('denied') setError(e?.message ?? '권한 요청 실패') return false } }, []) /** 현재 위치 1회 획득 → GeoTag 반환(실패 시 null) */ const capture = useCallback(async (): Promise => { setLoading(true) setError(null) const Location = loadLocation() if (!Location) { setError('위치 모듈을 사용할 수 없습니다 (EAS 빌드 필요)') setLoading(false) return null } try { const ok = perm === 'granted' || (await requestPermission()) if (!ok) { setLoading(false) return null } const pos = await Location.getCurrentPositionAsync({ accuracy: Location.Accuracy?.Balanced ?? 3, }) const t: GeoTag = { lat: pos.coords.latitude, lng: pos.coords.longitude, accuracy: pos.coords.accuracy ?? null, ts: new Date().toISOString(), } setTag(t) setLoading(false) return t } catch (e: any) { setError(e?.message ?? '위치 획득 실패') setLoading(false) return null } }, [perm, requestPermission]) return { tag, perm, loading, error, requestPermission, capture, available: !!loadLocation() } } export default useGPSTag