import { Capacitor } from '@capacitor/core' import { CheckCircle, ContentCopy, ErrorOutline, Nfc, } from '@mui/icons-material' import { Box, Button, CircularProgress, IconButton, Input, Switch, Typography, } from '@mui/joy' import { useRef, useState } from 'react' import { useResponsiveModal } from '../../../hooks/useResponsiveModal' import { startNativeNFCWrite } from '../../../service/NFCWriter' const pulseKeyframes = ` @keyframes nfc-pulse { 0% { transform: scale(1); opacity: 0.6; } 70% { transform: scale(1.6); opacity: 0; } 100% { transform: scale(1.6); opacity: 0; } } @keyframes nfc-pulse-2 { 0% { transform: scale(1); opacity: 0.4; } 70% { transform: scale(2.1); opacity: 0; } 100% { transform: scale(2.1); opacity: 0; } } @media (prefers-reduced-motion: reduce) { .nfc-pulse-ring { animation: none !important; } } ` function NFCIcon({ status }) { const isWaiting = status === 'waiting_for_tag' const isSuccess = status === 'success' const isError = status === 'error' return ( {isWaiting && ( <> )} {isSuccess ? ( ) : isError ? ( ) : ( )} ) } function WriteNFCModal({ config }) { const { ResponsiveModal } = useResponsiveModal() const [nfcStatus, setNfcStatus] = useState('idle') const [errorMessage, setErrorMessage] = useState('') const [isAutoCompleteWhenScan, setIsAutoCompleteWhenScan] = useState(false) const [copied, setCopied] = useState(false) const cancelScanRef = useRef(null) const isNative = Capacitor.isNativePlatform() const getURL = () => { let url = config.url if (isAutoCompleteWhenScan) url += '?auto_complete=true' return url } const handleClose = async () => { if (cancelScanRef.current) { await cancelScanRef.current() cancelScanRef.current = null } config.onClose() setNfcStatus('idle') setErrorMessage('') } const handleCancel = async () => { if (cancelScanRef.current) { await cancelScanRef.current() cancelScanRef.current = null } setNfcStatus('idle') } const handleCopy = () => { navigator.clipboard.writeText(getURL()) setCopied(true) setTimeout(() => setCopied(false), 2000) } const writeToNFC = async () => { const url = getURL() if (isNative) { setNfcStatus('writing') const cancel = await startNativeNFCWrite(url, { onWaiting: () => setNfcStatus('waiting_for_tag'), onSuccess: () => { cancelScanRef.current = null setNfcStatus('success') }, onError: msg => { cancelScanRef.current = null setNfcStatus('error') setErrorMessage(msg) }, }) cancelScanRef.current = cancel } else { if ('NDEFReader' in window) { try { setNfcStatus('writing') const ndef = new window.NDEFReader() await ndef.write({ records: [{ recordType: 'url', data: url }] }) setNfcStatus('success') } catch (error) { console.error('Error writing to NFC tag:', error) setNfcStatus('error') setErrorMessage('Error writing to NFC tag. Please try again.') } } else { setNfcStatus('error') setErrorMessage( 'NFC is not supported by this browser. Copy the URL and write it to an NFC tag using a compatible device.', ) } } } const isWaiting = nfcStatus === 'waiting_for_tag' || nfcStatus === 'writing' const isSuccess = nfcStatus === 'success' const isError = nfcStatus === 'error' const title = isSuccess ? 'Tag written!' : isError ? 'Something went wrong' : isWaiting ? 'Hold near NFC tag' : 'Write to NFC' const subtitle = isSuccess ? 'Your NFC tag is ready to use.' : isError ? errorMessage : isWaiting ? 'Keep your device near the tag until complete.' : 'Encode this task link onto any NFC tag.' return ( <> {/* Icon */} {/* Heading */} {title} {subtitle} {/* Idle / Error: URL + toggle + CTA */} {!isWaiting && !isSuccess && ( <> Tag URL } /> {copied && ( Copied! )} Auto-complete on scan Mark task done when tag is tapped setIsAutoCompleteWhenScan(e.target.checked)} size='sm' /> )} {/* Waiting state */} {isWaiting && ( )} {/* Success state */} {isSuccess && ( )} ) } export default WriteNFCModal