import React, { useState, useRef, useEffect } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faChevronDown, faTimes } from '@fortawesome/free-solid-svg-icons'; import Select from 'react-select' import { ServerDownAnimation } from '../../../../assets/images'; import { FileUploader } from 'react-drag-drop-files'; const Verify = () => { const BASE_URL = process.env.REACT_APP_BASE_URL; const API_KEY = process.env.REACT_APP_API_KEY; const fileTypes = ["JPG", "JPEG"]; const [file, setFile] = useState(null); const [errorMessage, setErrorMessage] = useState(''); const [uploadError, setUploadError] = useState(''); const [applicationError, setApplicationError] = useState(''); const [subjectError, setSubjectError] = useState(''); const [thresholdError, setThresholdError] = useState(''); const [selectedImageName, setSelectedImageName] = useState(''); const [resultImageLabel, setResultImageLabel] = useState(''); const inputRef = useRef(null); const [showResult, setShowResult] = useState(false); const [applicationId, setApplicationId] = useState(''); const [thresholdId, setThresholdId] = useState(''); const [selectedQuota, setSelectedQuota] = useState(0); const [subjectId, setSubjectId] = useState(''); const [isLoading, setIsLoading] = useState(false); const [verified, setVerified] = useState(null); const [imageUrl, setImageUrl] = useState(''); const [applicationIds, setApplicationIds] = useState([]); const [subjectIds, setSubjectIds] = useState([]); const [subjectAvailabilityMessage, setSubjectAvailabilityMessage] = useState(''); // Message for subject availability const [inputValueApplication, setInputValueApplication] = useState(''); // Controlled input value for Application ID const [isMobile, setIsMobile] = useState(window.innerWidth <= 768); const [isServer, setIsServer] = useState(true); const [imageError, setImageError] = useState(''); const thresholdIds = [ { id: 1, name: 'cosine', displayName: 'Basic' }, { id: 2, name: 'euclidean', displayName: 'Medium' }, { id: 3, name: 'euclidean_l2', displayName: 'High' }, ]; const [inputValue, setInputValue] = useState(''); const options = subjectIds.map(id => ({ value: id, label: id })); const applicationOptions = applicationIds.map(app => ({ value: app.id, label: app.name })); const fetchApplicationIds = async () => { try { const url = `${BASE_URL}/application/list`; const response = await fetch(url, { method: 'GET', headers: { 'accept': 'application/json', 'x-api-key': `${API_KEY}`, }, }); const data = await response.json(); setIsServer(true) return data.details.data; // assuming the API returns an array of applications } catch (error) { console.error('Error fetching application IDs:', error); setIsServer(false) return []; } }; // Sample function to fetch Subject IDs based on applicationId const fetchSubjectIds = async (appId) => { try { const response = await fetch(`${BASE_URL}/trx_face/list/subject?application_id=${appId}&limit=99`, { method: 'GET', headers: { 'accept': 'application/json', 'x-api-key': `${API_KEY}`, }, }); const data = await response.json(); return data.details.data; // assuming the API returns an array of subjects } catch (error) { console.error('Error fetching subject IDs:', error); return []; } }; useEffect(() => { const fetchData = async () => { setIsLoading(true); const data = await fetchApplicationIds(); setApplicationIds(data); setIsLoading(false); }; fetchData(); const handleResize = () => setIsMobile(window.innerWidth <= 768); window.addEventListener('resize', handleResize); return () => window.removeEventListener('resize', handleResize); }, []); // Empty dependency array, so this runs only once when the component mounts // Fetch Subject IDs when applicationId changes useEffect(() => { const fetchSubjects = async () => { if (applicationId) { setIsLoading(true); const subjects = await fetchSubjectIds(applicationId); setSubjectIds(subjects); setIsLoading(false); } else { setSubjectIds([]); // Clear subjects if no applicationId is selected } }; fetchSubjects(); }, [applicationId]); // Runs whenever applicationId changes // Handler for changing applicationId const handleApplicationChange = (selectedOption) => { const selectedId = selectedOption.value; const selectedApp = applicationIds.find(app => app.id === parseInt(selectedId)); if (selectedApp) { setSelectedQuota(selectedApp.quota); } setApplicationId(selectedOption.value); // Update applicationId when user selects a new option }; const handleImageUpload = (file) => { if (!file) { setImageError('Please select a file'); return; } // Check file size (2MB = 2 * 1024 * 1024 bytes) const maxSize = 2 * 1024 * 1024; if (file.size > maxSize) { setImageError('File size exceeds 2MB limit'); setFile(null); setSelectedImageName(''); return; } // Check file type using both extension and MIME type const fileExtension = file.name.split('.').pop().toLowerCase(); const validExtensions = ['jpg', 'jpeg']; const validMimeTypes = ['image/jpeg', 'image/jpg']; if (!validExtensions.includes(fileExtension) || !validMimeTypes.includes(file.type)) { setImageError('Only JPG/JPEG files are allowed'); setFile(null); setSelectedImageName(''); return; } // Check image dimensions const img = new Image(); const objectUrl = URL.createObjectURL(file); img.onload = () => { URL.revokeObjectURL(objectUrl); if (img.width > 300 || img.height > 300) { setImageError('Image dimensions must not exceed 300x300 pixels'); setFile(null); setSelectedImageName(''); return; } // All validations passed setSelectedImageName(file.name); setFile(file); setImageError(''); }; img.onerror = () => { URL.revokeObjectURL(objectUrl); setImageError('Invalid image file'); setFile(null); setSelectedImageName(''); }; img.src = objectUrl; }; const handleImageCancel = () => { setSelectedImageName(''); setFile(null); if (inputRef.current) { inputRef.current.value = ''; } }; const handleCheckClick = async () => { // Reset previous error messages setErrorMessage(''); setApplicationError(''); setSubjectError(''); setThresholdError(''); setUploadError(''); let hasError = false; // Track if any errors occur // Validate the applicationId if (!applicationId) { setApplicationError('Please select an Application ID before enrolling.'); hasError = true; // Mark that an error occurred } // Validate the subjectId if (!subjectId) { setSubjectError('Please enter a Subject ID before enrolling.'); hasError = true; // Mark that an error occurred } // Validate thresholdId const selectedThreshold = thresholdIds.find(threshold => threshold.name === thresholdId)?.name; if (!selectedThreshold) { setThresholdError('Invalid threshold selected.'); hasError = true; // Mark that an error occurred } // Validate image upload if (!selectedImageName) { setUploadError('Please upload a face photo before verifying.'); hasError = true; // Mark that an error occurred } // If there are any errors, stop the function if (hasError) { return; } // Log the input values for debugging console.log('Selected Image Name:', selectedImageName); console.log('Application ID:', applicationId); console.log('Subject ID:', subjectId); console.log('Selected Threshold:', selectedThreshold); // Prepare FormData for the API request const formData = new FormData(); formData.append('application_id', applicationId); formData.append('threshold', selectedThreshold); formData.append('subject_id', subjectId); if (file) { formData.append('file', file, file.name); } else { setUploadError('Please upload an image file.'); return; } setIsLoading(true); try { const response = await fetch(`${BASE_URL}/face_recognition/verifiy`, { method: 'POST', headers: { 'accept': 'application/json', 'x-api-key': API_KEY, }, body: formData, }); const data = await response.json(); // Log the response data for debugging console.log('API Response Data:', data); if (response.ok) { if (data.details && data.details.data && data.details.data.result) { const result = data.details.data.result; // Update selectedQuota with the quota received from API setSelectedQuota(result.quota); if (result.image_url) { const imageFileName = result.image_url.split('/').pop(); await fetchImage(imageFileName); } setShowResult(true); setVerified(result.verified); setResultImageLabel(selectedImageName); } } else { const errorMessage = data.message || data.detail || data.details?.message || 'An unknown error occurred.'; setErrorMessage(errorMessage); } } catch (error) { console.error('Error:', error); setErrorMessage('An error occurred while making the request.'); } finally { setIsLoading(false); } }; const fetchImage = async (imageFileName) => { setIsLoading(true); try { const response = await fetch(`${BASE_URL}/preview/image/${imageFileName}`, { method: 'GET', headers: { 'accept': 'application/json', 'x-api-key': API_KEY, }, }); if (!response.ok) { setErrorMessage('Failed to fetch image, please try again.'); return; } const imageBlob = await response.blob(); const imageData = URL.createObjectURL(imageBlob); setImageUrl(imageData); } catch (error) { console.error('Error fetching image:', error); setErrorMessage(error.message); } finally { setIsLoading(false); } }; const CustomLabel = ({ overRide, children, ...props }) => { // We intentionally don't pass `overRide` to the label return ( ); }; const handleInputChangeApplication = (newInputValue) => { // Limit input to 15 characters for Application ID if (newInputValue.length <= 15) { setInputValueApplication(newInputValue); } }; if (!isServer) { return (
Silakan periksa koneksi internet Anda atau coba lagi nanti.
Loading...
Remaining Quota
Drag and Drop Here
Or
BrowseRecommended size: 300x300 (Max File Size: 2MB)
Supported file types: JPG, JPEG
File: {selectedImageName}
Similarity | {verified !== null ? (verified ? 'True' : 'False') : 'N/A'} |
File Name: {resultImageLabel}