/* * SCR-M1 [모바일] 시공업체 현장 체크리스트 — 48px 터치·오프라인 배지·사진 첨부. * 아코디언 그룹(반입 전 / 시공 중 / 구조 확인 / 완료) + 금지작업 경고 + 검수 요청 CTA. * 위반(높이 5m 초과) 즉시 빨간 안내. 오프라인 시 로컬 저장 안내(배지). */ import { Ionicons } from '@expo/vector-icons'; import * as ImagePicker from 'expo-image-picker'; import { router } from 'expo-router'; import React, { useMemo, useState } from 'react'; import { Alert, Image, Pressable, ScrollView, StyleSheet, Text, TextInput, View } from 'react-native'; import { Banner } from '../components/Banner'; import { Button } from '../components/Button'; import { useAuth } from '../context/AuthContext'; import { colors, radius, spacing, touch, type } from '../theme'; interface Item { id: string; label: string; hint?: string; required: boolean; photo: boolean; // 사진 첨부 가능 } interface Group { id: string; title: string; items: Item[]; } const GROUPS: Group[] = [ { id: 'before', title: '반입 전', items: [ { id: 'flame', label: '방염 확인서 지참', required: true, photo: true }, { id: 'helmet', label: '안전모·보호장구 착용', required: true, photo: false }, ], }, { id: 'during', title: '시공 중', items: [ { id: 'floor', label: '바닥 마감·단차 확인', hint: '테이핑 및 단차', required: true, photo: true }, { id: 'wire', label: '전기 배선 안전 확인', hint: '노출 전선 정리', required: false, photo: true }, ], }, { id: 'done', title: '완료', items: [{ id: 'final', label: '완료 사진 업로드', required: true, photo: true }], }, ]; export default function ChecklistScreen() { const { activeWorkspace } = useAuth(); const [checked, setChecked] = useState>({}); const [photos, setPhotos] = useState>({}); const [open, setOpen] = useState>({ before: true, during: true, done: true }); const [height, setHeight] = useState(''); const heightValue = parseFloat(height); const heightViolation = !Number.isNaN(heightValue) && heightValue > 5; const requiredIds = useMemo( () => GROUPS.flatMap((g) => g.items.filter((i) => i.required).map((i) => i.id)), [], ); const remaining = requiredIds.filter((id) => !checked[id]).length; const heightOk = !Number.isNaN(heightValue) && heightValue > 0 && heightValue <= 5; const canSubmit = remaining === 0 && heightOk; async function attachPhoto(itemId: string) { try { const perm = await ImagePicker.requestMediaLibraryPermissionsAsync(); if (!perm.granted) { Alert.alert('권한 필요', '사진 첨부를 위해 갤러리 접근 권한이 필요합니다.'); return; } const res = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ImagePicker.MediaTypeOptions.Images, quality: 0.6, }); if (!res.canceled && res.assets[0]) { setPhotos((p) => ({ ...p, [itemId]: res.assets[0].uri })); } } catch { Alert.alert('오류', '사진을 첨부하지 못했습니다.'); } } function submit() { // 스캐폴드: 실제 검수 요청 API 연동은 백엔드 M6/C-4 확장 시 배선. Alert.alert('검수 요청', '검수 요청이 대기열에 저장되었습니다. (오프라인 시 연결되면 동기화)'); router.back(); } return ( {/* 상단 컨텍스트 */} 부스 A-102 {activeWorkspace?.hallLabel ?? '홀7'} · 장치 1일차 오프라인 저장 도면 예상 사진 (참고용) 필수 항목 {remaining}개 남음 {/* 금지작업 경고 (상시) */} 장내 금지 작업 • 금지: 전기톱 · 용접 · 페인트 작업 • 소음 한도: 70~75dB 준수 {GROUPS.map((g) => ( setOpen((o) => ({ ...o, [g.id]: !o[g.id] }))}> {g.title} {open[g.id] ? g.items.map((it) => ( setChecked((c) => ({ ...c, [it.id]: !c[it.id] }))} style={[styles.checkbox, checked[it.id] && styles.checkboxOn]} > {checked[it.id] ? : null} {it.label} {it.required ? * : null} {it.hint ? {it.hint} : null} {photos[it.id] ? ( ) : null} {it.photo ? ( attachPhoto(it.id)}> ) : null} )) : null} ))} {/* 구조 확인 — 높이 실측 */} 구조 확인 장치물 최고 높이 실측 m 규정: 5m 이하 {heightViolation ? ( 높이 5m 초과 — 위반 시 홀매니저에게 자동 통지됩니다. ) : null} {/* 하단 고정 CTA */} 오프라인 — 연결 시 동기화