/* * QR 풀스크린 뷰어(SCR-M15 3) — 대형 QR + 이름·유형 + 밝기 부스트 안내. * 하단 스와이프 인디케이터로 다른 티켓 전환(좌우 버튼). 예매번호 마스킹 노출. * ※ 자동 밝기 상승은 expo-brightness 미설치 → 안내 문구 + 갭 기록(placeholder). */ import { Ionicons } from '@expo/vector-icons'; import React from 'react'; import { Modal, Pressable, ScrollView, StyleSheet, Text, View } from 'react-native'; import { colors, radius, spacing, touch, type } from '../../theme'; import { QrPlaceholder } from './QrPlaceholder'; import type { SampleTicket } from './sampleTickets'; export function QrViewerModal({ visible, tickets, index, onChangeIndex, onClose, }: { visible: boolean; tickets: SampleTicket[]; index: number; onChangeIndex: (i: number) => void; onClose: () => void; }) { const ticket = tickets[index]; if (!ticket) return null; const canPrev = index > 0; const canNext = index < tickets.length - 1; return ( {/* 헤더 (그라디언트 대체: 브랜드 딥블루 단색) */} 입장 QR 코드 {ticket.eventName} {ticket.holderName} {ticket.ticketType} {ticket.bookingNoMasked} {/* 밝기 부스트 안내 */} 입장 시 화면을 최대 밝기로 유지하세요 {/* 스와이프(버튼) 전환 */} {tickets.length > 1 ? ( onChangeIndex(index - 1)} style={[styles.navBtn, !canPrev && styles.navBtnOff]} > {tickets.map((t, i) => ( ))} onChangeIndex(index + 1)} style={[styles.navBtn, !canNext && styles.navBtnOff]} > ) : null} 다른 티켓 보기 ); } const styles = StyleSheet.create({ backdrop: { flex: 1, backgroundColor: 'rgba(16,24,40,0.6)', alignItems: 'center', justifyContent: 'center', padding: spacing.lg, }, sheet: { width: '100%', maxWidth: 360, backgroundColor: colors.white, borderRadius: radius.md, overflow: 'hidden', }, header: { backgroundColor: colors.primary700, paddingVertical: spacing.lg, alignItems: 'center', gap: 4, }, closeBtn: { position: 'absolute', top: 8, right: 8, width: touch.min, height: touch.min, alignItems: 'center', justifyContent: 'center', }, headerTitle: { color: colors.white, fontSize: type.h2.fontSize, fontWeight: '700' }, headerSub: { color: 'rgba(255,255,255,0.85)', fontSize: type.caption.fontSize, maxWidth: 260 }, content: { alignItems: 'center', padding: spacing.lg, gap: spacing.md }, nameRow: { flexDirection: 'row', alignItems: 'baseline' }, holderName: { fontSize: type.h1.fontSize, fontWeight: '700', color: colors.neutral900 }, holderType: { fontSize: type.body.fontSize, fontWeight: '500', color: colors.neutral500 }, bookingChip: { backgroundColor: colors.primary050, borderRadius: radius.pill, paddingHorizontal: 12, paddingVertical: 4, }, bookingText: { color: colors.primary700, fontSize: type.caption.fontSize, fontVariant: ['tabular-nums'] }, hint: { flexDirection: 'row', alignItems: 'center', gap: 8, backgroundColor: colors.neutral050, borderRadius: radius.md, padding: spacing.md, width: '100%', }, hintText: { flex: 1, fontSize: type.caption.fontSize, color: colors.neutral700 }, hintBold: { fontWeight: '700', color: colors.neutral900 }, swipeRow: { flexDirection: 'row', alignItems: 'center', gap: 12, marginTop: 4 }, navBtn: { width: touch.min, height: touch.min, borderRadius: radius.sm, borderWidth: 1, borderColor: colors.neutral200, alignItems: 'center', justifyContent: 'center', }, navBtnOff: { opacity: 0.5 }, dots: { flexDirection: 'row', alignItems: 'center', gap: 6 }, dot: { width: 6, height: 6, borderRadius: 3, backgroundColor: colors.neutral200 }, dotOn: { width: 20, backgroundColor: colors.primary600 }, swipeHint: { fontSize: 11, color: colors.neutral500, letterSpacing: 1 }, });