diff --git a/src/screens/Biometric/FaceRecognition/Section/Compare.jsx b/src/screens/Biometric/FaceRecognition/Section/Compare.jsx
index 8509a2e..0a3e9f6 100644
--- a/src/screens/Biometric/FaceRecognition/Section/Compare.jsx
+++ b/src/screens/Biometric/FaceRecognition/Section/Compare.jsx
@@ -113,6 +113,7 @@ const Compare = () => {
};
const handleImageUpload = (file) => {
+ setShowResult(false);
if (!file) {
setUploadError('Please select a file');
return;
@@ -140,12 +141,15 @@ const Compare = () => {
}
// Set file and filename if validation passes
+ const previewUrl = URL.createObjectURL(file);
+ setImageUrl(previewUrl);
setFile(file);
setSelectedImageName(file.name); // Add this line
- setUploadError(''); // Clear any previous errors
+ setUploadError(''); // Clear any previous errors
};
const handleCompareImageUpload = (file) => {
+ setShowResult(false);
if (!file) {
setCompareUploadError('Please select a file');
return;
@@ -173,6 +177,8 @@ const Compare = () => {
}
// Set file and filename if validation passes
+ const previewUrl = URL.createObjectURL(file);
+ setImageCompareUrl(previewUrl);
setCompareFile(file);
setSelectedCompareImageName(file.name); // Add this line
setCompareUploadError(''); // Clear any previous errors
@@ -181,13 +187,17 @@ const Compare = () => {
const handleImageCancel = () => {
setSelectedImageName('');
+ setFile(null);
setImageUrl('');
+ setShowResult(false);
if (fileInputRef.current) fileInputRef.current.value = '';
};
const handleCompareImageCancel = () => {
setSelectedCompareImageName('');
+ setCompareFile(null);
setImageCompareUrl('');
+ setShowResult(false);
if (fileCompareInputRef.current) fileCompareInputRef.current.value = '';
};
@@ -534,6 +544,17 @@ const Compare = () => {
{/* Display uploaded image name */}
{selectedImageName && (
+
File: {selectedImageName}
{file && (
@@ -583,6 +604,17 @@ const Compare = () => {
{/* Display uploaded image name */}
{selectedCompareImageName && (
+
File: {selectedCompareImageName}
{compareFile && (
diff --git a/src/screens/Biometric/FaceRecognition/Section/Enroll.jsx b/src/screens/Biometric/FaceRecognition/Section/Enroll.jsx
index daff7c7..4ec16ac 100644
--- a/src/screens/Biometric/FaceRecognition/Section/Enroll.jsx
+++ b/src/screens/Biometric/FaceRecognition/Section/Enroll.jsx
@@ -606,6 +606,16 @@ const Enroll = () => {
{selectedImageName && (
+
File: {selectedImageName}
Cancel
diff --git a/src/screens/Biometric/FaceRecognition/Section/Search.jsx b/src/screens/Biometric/FaceRecognition/Section/Search.jsx
index 459c2a3..940f069 100644
--- a/src/screens/Biometric/FaceRecognition/Section/Search.jsx
+++ b/src/screens/Biometric/FaceRecognition/Section/Search.jsx
@@ -128,12 +128,16 @@ const Search = () => {
// Add this after your existing state declarations
const handleImageUpload = (file) => {
+ setShowResult(false);
if (!file) {
setImageError('Please select a file');
return;
}
// Store the uploaded file
+ const previewUrl = URL.createObjectURL(file);
+ setImageUrls([previewUrl]);
+
setUploadedFile(file);
setFile(file);
setSelectedImageName(file.name);
@@ -160,9 +164,6 @@ const Search = () => {
setUploadedFile(null);
return;
}
-
- // Create preview URL
- const previewUrl = URL.createObjectURL(file);
// Check image dimensions
const img = new Image();
@@ -752,6 +753,17 @@ const Search = () => {
{selectedImageName && (
+
File: {selectedImageName}
{file && (
diff --git a/src/screens/Biometric/FaceRecognition/Section/Verify.jsx b/src/screens/Biometric/FaceRecognition/Section/Verify.jsx
index 96134b1..f84db28 100644
--- a/src/screens/Biometric/FaceRecognition/Section/Verify.jsx
+++ b/src/screens/Biometric/FaceRecognition/Section/Verify.jsx
@@ -795,6 +795,17 @@ const Verify = () => {
{/* Display uploaded image name */}
{selectedImageName && (
+
File: {selectedImageName}
Cancel
diff --git a/src/screens/Wa/Verify/Section/Auth.jsx b/src/screens/Wa/Verify/Section/Auth.jsx
index d3ef028..5aa0c21 100644
--- a/src/screens/Wa/Verify/Section/Auth.jsx
+++ b/src/screens/Wa/Verify/Section/Auth.jsx
@@ -1,35 +1,60 @@
import React, { useState, useRef, useEffect } from 'react'
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faChevronLeft, faChevronDown } from '@fortawesome/free-solid-svg-icons';
+import { ServerDownAnimation } from '../../../../assets/images';
import Select from 'react-select'
const BASE_URL = process.env.REACT_APP_BASE_URL
const API_KEY = process.env.REACT_APP_API_KEY
-const Verify = ({ phoneId, onVerify }) => {
+const Verify = ({ onVerify, generateId }) => {
const [otpCode, setOtpCode] = useState('');
- const [generateCode, setGenerateCode] = useState('');
+ const [generateCode, setGenerateCode] = useState(generateId);
const [error, setError] = useState('');
+ useEffect(() => {
+ setGenerateCode(generateId);
+ }, [generateId]);
+
const handleClick = async () => {
- console.log('Verify Click');
- console.log('otp code: ', otpCode);
- console.log('generate code: ', generateCode);
- console.log('phone number: ', phoneId);
-
// Validation logic
if (!otpCode) {
- setError("OTP Code is required."); // Set error message directly
- return; // Exit the function if there are errors
- } else if (otpCode.length !== 6) {
- setError("OTP Code must be exactly 6 characters long."); // Set error message directly
- return; // Exit the function if there are errors
+ setError("OTP Code is required.");
+ return;
}
- setError(''); // Clear error if validation passes
- onVerify(); // Call the onVerify function passed from Auth
+ const requestData = {
+ id: generateId,
+ otp: otpCode
+ };
+
+ fetch(`${BASE_URL}/wa/otp-verify`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-api-key': API_KEY
+ },
+ body: JSON.stringify(requestData)
+ })
+ .then(response => response.json())
+ .then(data => {
+ if (data.status_code === 201) {
+ setError(''); // Clear any existing error message
+ alert('OTP verification successful!'); // Show success alert
+ onVerify(); // Trigger verify callback
+ } else {
+ setError(data.details.message || "Verification failed");
+ }
+ })
+ .catch(error => {
+ console.error('Verification failed:', error);
+ setError("Failed to verify OTP");
+ });
};
+ const generateTimestampId = () => {
+ const timestamp = new Date().getTime().toString(16); // Convert timestamp to hex
+ const randomPart = Math.random().toString(16).substr(2, 8);
+ return `${timestamp}-${randomPart}-${randomPart}-${randomPart}`;
+ };
return (
@@ -41,29 +66,13 @@ const Verify = ({ phoneId, onVerify }) => {
type="text"
id="generateCode"
className="form-control"
- placeholder="e133d538-dc40-4c43-b042-06aad864d634"
- value={generateCode}
+ placeholder="Generated Code"
+ value={`${generateTimestampId()}-${generateCode}`}
onChange={(e) => setGenerateCode(e.target.value)}
readOnly
/>
-
-
{/* OTP Code */}
@@ -77,14 +86,12 @@ const Verify = ({ phoneId, onVerify }) => {
value={otpCode}
onChange={(e) => {
const value = e.target.value;
- // Allow only digits and enforce exactly 6 digits
if (/^\d{0,6}$/.test(value)) {
setOtpCode(value);
}
}}
- maxLength={6} // Prevents entering more than 6 digits
+ maxLength={6}
/>
-
{error && {error} }
@@ -100,9 +107,24 @@ const Verify = ({ phoneId, onVerify }) => {
}
-const Preview = () => {
+const Preview = ({ otpLength }) => {
+ // Generate OTP when otpLength changes
+ const generateOTP = (length) => {
+ let otp = '';
+ for (let i = 0; i < length; i++) {
+ otp += Math.floor(Math.random() * 10);
+ }
+ return otp;
+ };
+
+ // State to store the generated OTP
const [inputValue, setInputValue] = useState('');
+ // Update OTP whenever otpLength changes
+ useEffect(() => {
+ setInputValue(generateOTP(parseInt(otpLength))); // Re-generate OTP on otpLength change
+ }, [otpLength]); // Dependency array with otpLength
+
const handleCopy = () => {
navigator.clipboard.writeText(inputValue);
console.log('Copied');
@@ -112,38 +134,36 @@ const Preview = () => {
- )
-}
+ );
+};
+
const Auth = () => {
-
- const [isSelectOpen, setIsSelectOpen] = useState(false);
const [applicationId, setApplicationId] = useState('');
const [expiryId, setExpiryId] = useState(0);
const [otpId, setOtpId] = useState('');
const [phoneId, setPhoneId] = useState('');
const [templateId, setTemplateId] = useState('');
const [isLoading, setIsLoading] = useState(false);
-
+ const [errorMessage, setErrorMessage] = useState('');
const [applicationIds, setApplicationIds] = useState([]);
const [showVerify, setShowVerify] = useState(false);
@@ -159,6 +179,9 @@ const Auth = () => {
label: app.name
}));
+ const [templateOptions, setTemplateOptions] = useState([]);
+ const [generateId, setgenerateId] = useState('');
+
const handleApplicationChange = (selectedOption) => {
const selectedId = selectedOption.value;
const selectedApp = applicationIds.find(app => app.id === parseInt(selectedId));
@@ -170,58 +193,97 @@ const Auth = () => {
}
};
+ const handleTemplateChange = (selectedOption) => {
+ setTemplateId(selectedOption ? selectedOption.value : '');
+ };
+
const handleInputChangeApplication = (newInputValue) => {
// Limit input to 15 characters for Application ID
if (newInputValue.length <= 15) {
setInputValueApplication(newInputValue);
}
};
-
useEffect(() => {
- const fetchApplicationIds = async () => {
- try {
- setIsLoading(true);
- const response = await fetch(`${BASE_URL}/application/list`, {
- method: 'GET',
- headers: {
- 'accept': 'application/json',
- 'x-api-key': API_KEY,
- },
- });
-
- if (!response.ok) {
- throw new Error('Failed to fetch application IDs');
+ const fetchData = () => {
+ setIsLoading(true);
+
+ fetch(`${BASE_URL}/application/list`, {
+ method: 'GET',
+ headers: {
+ 'accept': 'application/json',
+ 'x-api-key': API_KEY,
+ },
+ })
+ .then(response => response.json())
+ .then(appData => {
+ if (appData.status_code === 200) {
+ setApplicationIds(appData.details.data);
+ return fetch(`${BASE_URL}/template/list?type=1`, {
+ method: 'GET',
+ headers: {
+ 'accept': 'application/json',
+ 'x-api-key': API_KEY,
+ },
+ });
}
-
- const data = await response.json();
- console.log('Response Data:', data);
-
- if (data.status_code === 200) {
- setApplicationIds(data.details.data);
+ setIsServer(false);
+ setErrorMessage('Failed to fetch application IDs');
+ throw new Error('Failed to fetch application IDs');
+ })
+ .then(response => response.json())
+ .then(templateData => {
+ if (templateData.status_code === 200) {
+ const templates = templateData.details.data.map(template => ({
+ value: template.id,
+ label: template.name
+ }));
+ setTemplateOptions(templates);
setIsServer(true);
} else {
setIsServer(false);
- throw new Error(data.details.message || 'Failed to fetch application IDs');
+ setErrorMessage('Failed to fetch templates');
+ throw new Error('Failed to fetch templates');
}
- } catch (error) {
- setErrors(error.message || 'Error fetching application IDs');
+ })
+ .catch(error => {
+ console.error('Error:', error);
setIsServer(false);
- } finally {
+ setErrorMessage(error.message || 'Server connection failed');
+ })
+ .finally(() => {
setIsLoading(false);
- }
- };
-
- fetchApplicationIds();
+ });
+ };
+
+ fetchData();
}, []);
-
- const handleFocus = () => {
- setIsSelectOpen(true);
- };
-
- const handleBlur = () => {
- setIsSelectOpen(false);
- };
-
+
+ // Server Down Component
+ if (!isServer) {
+ return (
+
+
+
Server tidak dapat diakses
+
{errorMessage || 'Silakan periksa koneksi internet Anda atau coba lagi nanti.'}
+
window.location.reload()}
+ style={{
+ padding: '10px 20px',
+ backgroundColor: '#0542cc',
+ color: '#fff',
+ border: 'none',
+ borderRadius: '5px',
+ cursor: 'pointer'
+ }}>
+ Coba Lagi
+
+
+ );
+ }
const handleVerify = () => {
setShowPreview(true); // Show the preview when verified
};
@@ -239,18 +301,55 @@ const Auth = () => {
const handleClick = async () => {
if (validate()) {
- // Log the input data
- console.log('Application ID:', applicationId);
- console.log('Expiry ID:', expiryId);
- console.log('OTP Length:', otpId);
- console.log('Phone Number:', '08' + phoneId); // Prepend "08" to the phone number
- console.log('Template ID:', templateId);
-
- console.log('Make Auth Demo');
- setShowVerify(true);
+ setIsLoading(true);
+
+ const requestData = {
+ application_id: parseInt(applicationId),
+ phone: phoneId,
+ digits: parseInt(otpId),
+ interval: parseInt(expiryId),
+ template_id: parseInt(templateId),
+ is_test: true,
+ mode_id: 9
+ };
+
+ console.log('Request Data:', requestData);
+
+ // Add timeout to ensure channel stays open
+ const timeoutPromise = new Promise((_, reject) =>
+ setTimeout(() => reject(new Error('Request timeout')), 30000)
+ );
+
+ Promise.race([
+ fetch(`${BASE_URL}/wa/otp`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'x-api-key': API_KEY
+ },
+ body: JSON.stringify(requestData)
+ }),
+ timeoutPromise
+ ])
+ .then(response => response.json())
+ .then(data => {
+ console.log('API Response:', data);
+ if (data.status_code === 201 && data.details.message === "Successfully") {
+ setgenerateId(data.details.data.id);
+ setShowVerify(false);
+ alert('Authentication request successful!');
+ }
+ })
+ .catch(error => {
+ console.error('Request failed:', error);
+ })
+ .finally(() => {
+ setIsLoading(false);
+ });
}
};
+
return (
<>
@@ -299,62 +398,61 @@ const Auth = () => {
{/* Expiry and OTP */}
+ {/* Expiry ID/Interval */}
+ {/* Digits */}
- {
- const value = e.target.value;
- // Allow only digits and enforce length constraints
- if (/^\d{0,6}$/.test(value)) {
- setOtpId(value);
- }
- }}
- minLength={6} // Enforce minimum length (for validation)
- maxLength={6} // Enforce maximum length
- />
+ onChange={(e) => setOtpId(e.target.value)}
+ >
+ Select OTP Length
+ {[1, 2, 3, 4, 5, 6, 7, 8].map(length => (
+
+ {length}
+
+ ))}
+
{errors.otpId && {errors.otpId} }
+
{/* Message and Phone */}
- setTemplateId(e.target.value)}
+ value={templateOptions.find(option => option.value === templateId)}
+ onChange={handleTemplateChange}
+ options={templateOptions}
+ placeholder="Select Template"
+ isSearchable
+ menuPortalTarget={document.body}
+ menuPlacement="auto"
/>
{errors.templateId && {errors.templateId} }
@@ -363,7 +461,7 @@ const Auth = () => {
- {showVerify &&
}
- {showPreview &&
}
+ {showVerify &&
}
+
>
);
}
@@ -408,9 +506,6 @@ const styles = {
section: {
margin: '1rem 0 1rem 0'
},
- formGroup: {
- marginTop: '-45px',
- },
selectWrapper: {
position: 'relative',
marginTop: '0',
@@ -423,13 +518,6 @@ const styles = {
border: 'none',
outline: 'none',
},
- chevronIcon: {
- position: 'absolute',
- right: '10px',
- top: '50%',
- transform: 'translateY(-50%)',
- pointerEvents: 'none',
- },
remainingQuota: {
display: 'flex',
flexDirection: 'row',
@@ -446,17 +534,6 @@ const styles = {
verticalAlign: 'super',
fontSize: '20px',
},
- buttonContainer: {
- display: 'flex',
- flexDirection: 'column',
- justifyContent: 'center', // Center vertically within container
- position: 'absolute',
- right: '10px',
- top: '0',
- bottom: '0',
- height: '47px',
- margin: 'auto 0',
- },
button: {
background: 'none',
border: 'none',
@@ -475,41 +552,6 @@ const styles = {
position: 'relative',
zIndex: 1,
},
- uploadError: {
- color: 'red',
- fontSize: '12px',
- marginTop: '5px',
- },
-
- containerResultStyle: {
- padding: '20px',
- border: '1px solid #0053b3',
- borderRadius: '5px',
- width: '100%',
- margin: '20px auto',
- },
- resultContainer: {
- display: 'flex',
- justifyContent: 'flex-start',
- alignItems: 'center',
- width: '100%',
- },
- tableStyle: {
- width: '60%',
- borderCollapse: 'collapse',
- },
- imageContainer: {
- display: 'flex',
- flexDirection: 'column',
- alignItems: 'flex-start',
- width: '30%',
- marginLeft: '10px'
- },
- imageStyle: {
- width: '193px',
- height: '242px',
- borderRadius: '5px',
- },
loadingOverlay: {
position: 'fixed',
top: 0,