import React, { useEffect, useRef, useState } from 'react';
import {
View,
Text,
TouchableOpacity,
StyleSheet,
Animated,
} from 'react-native';
import { useLocalSearchParams, useRouter } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
import { SafeAreaView } from 'react-native-safe-area-context';
import { SvgXml } from 'react-native-svg';
import { colors, typography, spacing, radius } from '@shared/theme';
import { writeNFCTagUseCase, nfcRepository } from '@infrastructure/container';
import { Button } from '@presentation/components/ui/Button';
const NFC_SVG = ``;
type Status = 'waiting' | 'writing' | 'success' | 'error';
/**
* Tela de gravação NFC — acessada a partir do Detalhe do Filamento
*/
export default function WriteNFCScreen(): React.ReactElement {
const { id } = useLocalSearchParams<{ id: string }>();
const router = useRouter();
const [status, setStatus] = useState('waiting');
const [errorMessage, setErrorMessage] = useState('');
const ring1 = useRef(new Animated.Value(0)).current;
const ring2 = useRef(new Animated.Value(0)).current;
const ring3 = useRef(new Animated.Value(0)).current;
const animRef = useRef([]);
useEffect(() => {
startPulse();
startWriting();
return () => {
stopPulse();
nfcRepository.cancelSession().catch(() => {});
};
}, []);
function startPulse(): void {
const pulse = (ring: Animated.Value, delay: number) =>
Animated.loop(
Animated.sequence([
Animated.delay(delay),
Animated.timing(ring, { toValue: 1, duration: 1400, useNativeDriver: true }),
Animated.timing(ring, { toValue: 0, duration: 0, useNativeDriver: true }),
]),
);
const a1 = pulse(ring1, 0);
const a2 = pulse(ring2, 400);
const a3 = pulse(ring3, 800);
animRef.current = [a1, a2, a3];
a1.start(); a2.start(); a3.start();
}
function stopPulse(): void {
animRef.current.forEach((a) => a.stop());
ring1.setValue(0); ring2.setValue(0); ring3.setValue(0);
}
async function startWriting(): Promise {
setStatus('writing');
try {
await writeNFCTagUseCase.execute(id);
stopPulse();
setStatus('success');
} catch (err: unknown) {
stopPulse();
setErrorMessage(err instanceof Error ? err.message : 'Erro ao gravar a tag.');
setStatus('error');
}
}
const ringStyle = (anim: Animated.Value) => ({
opacity: anim.interpolate({ inputRange: [0, 0.5, 1], outputRange: [0.5, 0.15, 0] }),
transform: [{ scale: anim.interpolate({ inputRange: [0, 1], outputRange: [1, 2.2] }) }],
});
return (
{/* Header */}
{
nfcRepository.cancelSession().catch(() => {});
router.back();
}}>
Gravar NFC
{/* Content */}
{/* Icon with rings */}
{status === 'writing' && (
<>
>
)}
{status === 'success'
?
: status === 'error'
?
:
}
{/* Status text */}
{status === 'waiting' || status === 'writing' ? (
<>
Aproxime a tag NTAG215
Encoste a tag NFC ao sensor do dispositivo para gravar os dados do filamento
>
) : status === 'success' ? (
<>
Tag gravada!
A tag NFC foi configurada com sucesso para este filamento
>
) : (
<>
Falha na gravação
{errorMessage}
>
)}
{/* Footer actions */}
{status === 'success' ? (
);
}
const RING_SIZE = 120;
const styles = StyleSheet.create({
safe: { flex: 1, backgroundColor: colors.bgBase },
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingHorizontal: spacing[5],
paddingVertical: spacing[4],
},
headerTitle: {
fontFamily: typography.fontFamily.ui,
fontSize: typography.fontSize.md,
fontWeight: typography.fontWeight.semibold,
color: colors.textPrimary,
},
content: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
gap: spacing[4],
paddingHorizontal: spacing[6],
},
iconArea: {
width: RING_SIZE * 2.2,
height: RING_SIZE * 2.2,
alignItems: 'center',
justifyContent: 'center',
marginBottom: spacing[2],
},
ring: {
position: 'absolute',
width: RING_SIZE,
height: RING_SIZE,
borderRadius: RING_SIZE / 2,
borderWidth: 2,
borderColor: colors.accent,
},
iconCircle: {
width: RING_SIZE,
height: RING_SIZE,
borderRadius: RING_SIZE / 2,
backgroundColor: colors.bgHover,
borderWidth: 1,
borderColor: colors.border,
alignItems: 'center',
justifyContent: 'center',
},
iconCircleSuccess: {
borderColor: colors.stockOk,
backgroundColor: `${colors.stockOk}15`,
},
iconCircleError: {
borderColor: colors.error,
backgroundColor: `${colors.error}15`,
},
title: {
fontFamily: typography.fontFamily.ui,
fontSize: typography.fontSize.xl,
fontWeight: typography.fontWeight.semibold,
color: colors.textPrimary,
textAlign: 'center',
},
titleError: {
fontFamily: typography.fontFamily.ui,
fontSize: typography.fontSize.xl,
fontWeight: typography.fontWeight.semibold,
color: colors.error,
textAlign: 'center',
},
subtitle: {
fontFamily: typography.fontFamily.ui,
fontSize: typography.fontSize.sm,
color: colors.textSecondary,
textAlign: 'center',
lineHeight: 20,
},
footer: {
padding: spacing[5],
gap: spacing[3],
borderTopWidth: 1,
borderTopColor: colors.border,
},
cancelBtn: {
alignItems: 'center',
paddingVertical: spacing[3],
},
cancelText: {
fontFamily: typography.fontFamily.ui,
fontSize: typography.fontSize.base,
color: colors.textSecondary,
},
});