UNPKG

@safepassage/sdk

Version:

SafePassage SDK - Lightweight redirect-based age verification

197 lines (181 loc) 7.22 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { useSafePassage } from '../hooks/useSafePassage'; const SafePassageVerification = ({ wsUrl, mode = 'enhanced_verification', maxReconnectAttempts = 5, reconnectDelay = 3000, frameRate = 10, imageQuality = 0.8, config_overrides, onSuccess, onFailure, onStateChange, customMessages, className = '', style = {} }) => { const { error, feedback, processingStep, zoneTransition, qualityScore, videoRef, canvasRef, isSessionStarted } = useSafePassage({ wsUrl, mode, maxReconnectAttempts, reconnectDelay, frameRate, imageQuality, config_overrides }, { onSuccess, onFailure, onStateChange }, customMessages); const getDisplayMessage = () => { if (zoneTransition) { return zoneTransition.message; } if (feedback && !processingStep) { return feedback; } if (processingStep) { return processingStep; } if (!isSessionStarted) { return 'Starting camera...'; } return 'Position your face in the camera and look forward'; }; const getMessageClass = () => { if (zoneTransition) return 'safepassage-instruction-zone-transition'; if (feedback && !processingStep) return 'safepassage-instruction-feedback'; if (processingStep) return 'safepassage-instruction-processing'; return 'safepassage-instruction-default'; }; // Calculate glow intensity based on quality score and feedback const getGlowIntensity = () => { // Base glow on quality score (0-1) let intensity = qualityScore; // Boost intensity for positive feedback (both generic and zone-specific) if (feedback === 'good_position' || feedback === 'good_wide_position' || feedback === 'good_close_position') { intensity = Math.max(intensity, 0.9); } // Medium intensity for zone positioning messages if (feedback === 'position_at_comfortable_distance' || feedback === 'move_closer_to_camera') { intensity = Math.max(intensity, 0.6); } // Reduce intensity for negative feedback if (feedback === 'no_face_detected' || feedback === 'move_closer' || feedback === 'move_further' || feedback === 'center_face' || feedback === 'improve_lighting') { intensity = Math.min(intensity, 0.3); } // Special handling for zone transitions - pulse effect if (zoneTransition) { intensity = Math.max(intensity, 0.7); } // Clamp between 0 and 1 return Math.max(0, Math.min(1, intensity)); }; const glowIntensity = getGlowIntensity(); return (_jsxs("div", { className: `safepassage-verification-container ${className}`, style: style, children: [_jsxs("div", { className: "safepassage-video-container", children: [_jsx("video", { ref: videoRef, autoPlay: true, playsInline: true, className: "safepassage-verification-video" }), _jsx("div", { className: "safepassage-video-overlay", children: _jsx("div", { className: "safepassage-oval-frame", style: { '--glow-intensity': glowIntensity, '--glow-opacity': glowIntensity > 0.1 ? glowIntensity : 0 } }) })] }), _jsx("div", { className: "safepassage-instructions-area", children: _jsx("div", { className: `safepassage-instruction-text ${getMessageClass()}`, children: getDisplayMessage() }) }), _jsx("canvas", { ref: canvasRef, style: { display: 'none' } }), error && (_jsx("div", { className: "safepassage-error-message", children: error })), _jsx("style", { children: ` .safepassage-verification-container { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%; min-height: 100vh; margin: 0; padding: 40px 20px; text-align: center; background-color: #2a2a2a; position: fixed; top: 0; left: 0; right: 0; bottom: 0; } .safepassage-video-container { position: relative; width: 320px; height: 320px; margin-bottom: 40px; } .safepassage-verification-video { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; background-color: #000; } .safepassage-video-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; } .safepassage-oval-frame { width: 100%; height: 100%; border: 3px solid #ffffff; border-radius: 50%; box-shadow: 0 0 20px rgba(255, 255, 255, 0.3), 0 0 calc(30px * var(--glow-intensity, 0)) rgba(34, 197, 94, calc(var(--glow-opacity, 0) * 0.8)), 0 0 calc(50px * var(--glow-intensity, 0)) rgba(34, 197, 94, calc(var(--glow-opacity, 0) * 0.4)), 0 0 calc(80px * var(--glow-intensity, 0)) rgba(34, 197, 94, calc(var(--glow-opacity, 0) * 0.2)); transition: box-shadow 0.3s ease-out; } .safepassage-instructions-area { width: 100%; max-width: 400px; } .safepassage-instruction-text { font-size: 18px; font-weight: 500; color: #ffffff; text-align: center; line-height: 1.4; min-height: 50px; display: flex; align-items: center; justify-content: center; } .safepassage-instruction-zone-transition { color: #4fc3f7; font-weight: 600; animation: safepassage-pulse 0.5s ease-in-out; } .safepassage-instruction-feedback { color: #ffffff; } .safepassage-instruction-processing { color: #81c784; } .safepassage-instruction-default { color: #ffffff; opacity: 0.9; } .safepassage-error-message { color: #e53e3e; margin-top: 10px; } @keyframes safepassage-pulse { 0% { opacity: 0.7; transform: scale(1); } 50% { opacity: 1; transform: scale(1.02); } 100% { opacity: 0.9; transform: scale(1); } } @media (max-width: 480px) { .safepassage-verification-container { padding: 20px 15px; } .safepassage-video-container { width: 280px; height: 280px; margin-bottom: 30px; } .safepassage-instruction-text { font-size: 16px; min-height: 45px; } } ` })] })); }; export default SafePassageVerification;