diff --git a/src/components/Sidebar/dataMenu.js b/src/components/Sidebar/dataMenu.js
index 19332cd..b786a10 100644
--- a/src/components/Sidebar/dataMenu.js
+++ b/src/components/Sidebar/dataMenu.js
@@ -1,263 +1,193 @@
// src/components/dataMenu.js
-const dataMenu = [
- {
- items: [
- {
- name: 'Main Dashboard', // Changed the name
- target: 'collapseHome',
- subMenus: [
- {
- name: 'Getting Started',
- link: '/getting-started'
- },
- {
- name: 'Dashboard Overview', // Changed the name
- link: '/dashboard'
- },
- {
- name: 'Application Settings', // Changed the name
- link: '/application'
- },
- ],
- },
- ],
- iconClass: 'fas fa-tachometer-alt',
- },
- {
- items: [
- {
- name: 'Biometric Systems', // Changed the name
- target: 'collapseBiometric',
- subMenus: [
- {
- name: 'Face Recognition System', // Changed the name
- target: 'collapseFaceRecog',
- subMenus: [
- { name: 'Verify Identity', link: '/face-verify'}, // Changed the name
- { name: 'Summary Report', link: '/face-summary'}, // Changed the name
- { name: 'Transaction Log', link: '/face-transaction'}, // Changed the name
- ],
- },
- {
- name: 'KTP OCR', // Changed the name
- target: 'collapseOcrKtp',
- subMenus: [
- { name: 'Verify KTP', link: '/ktp-verify'}, // Changed the name
- { name: 'Manage Basic Auth', link: '/ktp-manage'},
- { name: 'Summary of KTPs', link: '/ktp-summary'}, // Changed the name
- { name: 'KTP Transaction History', link: '/ktp-transaction'}, // Changed the name
- ],
- },
- {
- name: 'NPWP OCR', // Changed the name
- target: 'collapseOcrNpwp',
- subMenus: [
- { name: 'Verify NPWP', link: '/npwp-verify'}, // Changed the name
- { name: 'NPWP Summary', link: '/npwp-summary'}, // Changed the name
- { name: 'NPWP Transaction Log', link: '/npwp-transaction'}, // Changed the name
- ],
- },
- {
- name: 'SIM OCR', // Changed the name
- target: 'collapseOcrSim',
- subMenus: [
- { name: 'Verify SIM', link: '/sim-verify'}, // Changed the name
- { name: 'SIM Summary', link: '/sim-summary'}, // Changed the name
- { name: 'SIM Transaction Log', link: '/sim-transaction'}, // Changed the name
- ],
- },
- {
- name: 'Document OCR', // Changed the name
- target: 'collapseOcrDocument',
- subMenus: [
- { name: 'Verify Document', link: '/document-verify'}, // Changed the name
- { name: 'Document Summary', link: '/document-summary'}, // Changed the name
- { name: 'Document Transaction History', link: '/document-transaction'}, // Changed the name
- ],
- },
- ],
- },
- ],
- iconClass: 'fas fa-user',
- },
- {
- items: [
- {
- name: 'SMS Services', // Changed the name
- target: 'collapseSms',
- subMenus: [
- {
- name: 'SMS Verification', // Changed the name
- link: '/sms-verify'
- },
- {
- name: 'SMS OTP Management', // Changed the name
- target: 'collapseSmsOtp',
- subMenus: [
- { name: 'Settings', link: '/sms-otp-settings'},
- { name: 'Summary Report', link: '/sms-otp-summary'}, // Changed the name
- { name: 'Transaction Log', link: '/sms-otp-transaction'}, // Changed the name
- { name: 'Detail View', link: '/sms-otp-detail'}, // Changed the name
- ],
- },
- {
- name: 'SMS Announcements', // Changed the name
- target: 'collapseAnnouncement',
- subMenus: [
- { name: 'Bulk Message', link: '/sms-announcement-bulk'}, // Changed the name
- { name: 'Announcement Summary', link: '/sms-announcement-summary'}, // Changed the name
- { name: 'Transaction Logs', link: '/sms-announcement-transaction'},
- ],
- },
- {
- name: 'Blocked Numbers', // Changed the name
- link: '/sms-block'
- },
- {
- name: 'SMS Anomaly Report', // Changed the name
- link: '/sms-anomaly'
- },
- ],
- },
- ],
- iconClass: 'fas fa-phone',
- },
- {
- items: [
- {
- name: 'WhatsApp Communication', // Changed the name
- target: 'collapseWa',
- subMenus: [
- {
- name: 'Verify WhatsApp Account', // Changed the name
- link: '/wa-verify'
- },
- {
- name: 'WhatsApp Management', // Changed the name
- target: 'collapseWaManage',
- subMenus: [
- { name: 'Register Business Account', link: '/wa-registration'}, // Changed the name
- { name: 'WhatsApp Profile Settings', link: '/wa-profile'}, // Changed the name
- { name: 'Message Templates', link: '/wa-template'}, // Changed the name
- { name: 'Integration Settings', link: '/wa-integration'}, // Changed the name
- ],
- },
- {
- name: 'WhatsApp Activity', // Changed the name
- target: 'collapseActivity',
- subMenus: [
- { name: 'Settings', link: '/wa-settings'}, // Changed the name
- { name: 'Activity Summary', link: '/wa-summary'}, // Changed the name
- { name: 'WA Transaction Logs', link: '/wa-transaction'},
- { name: 'Bulk Sending', link: '/wa-bulk'}, // Changed the name
- ],
- },
- {
- name: 'WhatsApp Inbox', // Changed the name
- link: '/wa-inbox'
- },
- {
- name: 'Blocked WhatsApp Numbers', // Changed the name
- link: '/wa-block'
- },
- ],
- },
- ],
- iconClass: 'fab fa-whatsapp',
- },
- {
- items: [
- {
- name: 'Identity Verification', // Changed the name
- target: 'collapseIdentify',
- subMenus: [
- {
- name: 'Electronic Certificate Verification', // Changed the name
- target: 'collapseElectro',
- subMenus: [
- { name: 'Verify Certificate', link: '/identity-electro-verify'}, // Changed the name
- { name: 'Electronic Transaction', link: '/identity-electro-transaction'},
- ],
- },
- {
- name: 'NPWP Verification', // Changed the name
- target: 'collapseIdentifyNpwp',
- subMenus: [
- { name: 'Npwp Transaction', link: '/identity-npwp-transaction'}
- ],
- },
- {
- name: 'Tax Number Verification', // Changed the name
- target: 'collapseTax',
- subMenus: [
- { name: 'Verify Tax Number', link: '/identity-tax-verify'}, // Changed the name
- { name: 'Tax Transaction', link: '/identity-tax-transaction'}
- ],
- },
- {
- name: 'Income Verification', // Changed the name
- target: 'collapseIncome',
- subMenus: [
- { name: 'Verify Income', link: '/identity-income-verify'}, // Changed the name
- { name: 'Income Transaction', link: '/identity-income-transaction'}
- ],
- },
- {
- name: 'ID Verification', // Changed the name
- target: 'collapseIdVerification',
- subMenus: [
- { name: 'Verify ID', link: '/identity-id-verify'}, // Changed the name
- { name: 'Verify ID Transaction', link: '/identity-id-transaction'}
- ],
- },
- ],
- },
- ],
- iconClass: 'fas fa-edit',
- },
- {
- items: [
- {
- name: 'Watchlist Management', // Changed the name
- target: 'collapseWatchlist',
- subMenus: [
- {
- name: 'Watchlist Screening', // Changed the name
- target: 'collapseScreening',
- subMenus: [
- { name: 'Verify Watchlist', link: '/watchlist-screening-verify'}, // Changed the name
- { name: 'Admin Settings', link: '/watchlist-screening-admin'},
- { name: 'Search Watchlist', link: '/watchlist-screening-search'}, // Changed the name
- { name: 'Transaction Logs', link: '/watchlist-screening-transaction'},
- { name: 'Monitor Watchlist', link: '/watchlist-screening-monitor'},
- ],
- },
- ],
- },
- ],
- iconClass: 'fas fa-calendar',
- },
- {
- items: [
- {
- name: 'File Management', // Changed the name
- target: 'collapseFiles',
- subMenus: [
- {
- name: 'File Screening', // Changed the name
- target: 'collapseScreening',
- subMenus: [
- { name: 'Verify File', link: '/files-screening-verify'}, // Changed the name
- { name: 'Search Files', link: '/files-screening-search'}, // Changed the name
- { name: 'File Management Settings', link: '/files-screening-admin'},
- ],
- },
- ],
- },
- ],
- iconClass: 'fas fa-cogs',
- }
+const createMenuItem = (name, link) => ({ name, link });
+const createSubMenu = (name, target, subMenus) => ({ name, target, subMenus });
+
+const mainDashboardMenus = [
+ createMenuItem('Getting Started', '/getting-started'),
+ createMenuItem('Dashboard Overview', '/dashboard'),
+ createMenuItem('Application Settings', '/application')
];
-export default dataMenu;
+const biometricSubMenus = {
+ faceRecognition: [
+ createMenuItem('Verify Identity', '/face-verify'),
+ createMenuItem('Summary Report', '/face-summary'),
+ createMenuItem('Transaction Log', '/face-transaction')
+ ],
+ ktpOcr: [
+ createMenuItem('Verify KTP', '/ktp-verify'),
+ createMenuItem('Manage Basic Auth', '/ktp-manage'),
+ createMenuItem('Summary of KTPs', '/ktp-summary'),
+ createMenuItem('KTP Transaction History', '/ktp-transaction')
+ ],
+ npwpOcr: [
+ createMenuItem('Verify NPWP', '/npwp-verify'),
+ createMenuItem('NPWP Summary', '/npwp-summary'),
+ createMenuItem('NPWP Transaction Log', '/npwp-transaction')
+ ],
+ simOcr: [
+ createMenuItem('Verify SIM', '/sim-verify'),
+ createMenuItem('SIM Summary', '/sim-summary'),
+ createMenuItem('SIM Transaction Log', '/sim-transaction')
+ ],
+ documentOcr: [
+ createMenuItem('Verify Document', '/document-verify'),
+ createMenuItem('Document Summary', '/document-summary'),
+ createMenuItem('Document Transaction History', '/document-transaction')
+ ]
+};
+
+const smsServiceMenus = {
+ smsOtp: [
+ createMenuItem('Settings', '/sms-otp-settings'),
+ createMenuItem('Summary Report', '/sms-otp-summary'),
+ createMenuItem('Transaction Log', '/sms-otp-transaction'),
+ createMenuItem('Detail View', '/sms-otp-detail')
+ ],
+ announcement: [
+ createMenuItem('Bulk Message', '/sms-announcement-bulk'),
+ createMenuItem('Announcement Summary', '/sms-announcement-summary'),
+ createMenuItem('Transaction Logs', '/sms-announcement-transaction')
+ ]
+};
+
+const whatsAppMenus = {
+ management: [
+ createMenuItem('Register Business Account', '/wa-registration'),
+ createMenuItem('WhatsApp Profile Settings', '/wa-profile'),
+ createMenuItem('Message Templates', '/wa-template'),
+ createMenuItem('Integration Settings', '/wa-integration')
+ ],
+ activity: [
+ createMenuItem('Settings', '/wa-settings'),
+ createMenuItem('Activity Summary', '/wa-summary'),
+ createMenuItem('WA Transaction Logs', '/wa-transaction'),
+ createMenuItem('Bulk Sending', '/wa-bulk')
+ ]
+};
+
+const identityMenus = {
+ electronic: [
+ createMenuItem('Verify Certificate', '/identity-electro-verify'),
+ createMenuItem('Electronic Transaction', '/identity-electro-transaction')
+ ],
+ npwp: [
+ createMenuItem('Npwp Transaction', '/identity-npwp-transaction')
+ ],
+ tax: [
+ createMenuItem('Verify Tax Number', '/identity-tax-verify'),
+ createMenuItem('Tax Transaction', '/identity-tax-transaction')
+ ],
+ income: [
+ createMenuItem('Verify Income', '/identity-income-verify'),
+ createMenuItem('Income Transaction', '/identity-income-transaction')
+ ],
+ id: [
+ createMenuItem('Verify ID', '/identity-id-verify'),
+ createMenuItem('Verify ID Transaction', '/identity-id-transaction')
+ ]
+};
+
+const watchlistMenus = {
+ screening: [
+ createMenuItem('Verify Watchlist', '/watchlist-screening-verify'),
+ createMenuItem('Admin Settings', '/watchlist-screening-admin'),
+ createMenuItem('Search Watchlist', '/watchlist-screening-search'),
+ createMenuItem('Transaction Logs', '/watchlist-screening-transaction'),
+ createMenuItem('Monitor Watchlist', '/watchlist-screening-monitor')
+ ]
+};
+
+const fileMenus = {
+ screening: [
+ createMenuItem('Verify File', '/files-screening-verify'),
+ createMenuItem('Search Files', '/files-screening-search'),
+ createMenuItem('File Management Settings', '/files-screening-admin')
+ ]
+};
+
+const dataMenu = [
+ {
+ items: [createSubMenu('Home', 'collapseHome', mainDashboardMenus)],
+ iconClass: 'fas fa-tachometer-alt'
+ },
+ {
+ items: [{
+ name: 'Biometric',
+ target: 'collapseBiometric',
+ subMenus: [
+ createSubMenu('Face Recognition System', 'collapseFaceRecog', biometricSubMenus.faceRecognition),
+ createSubMenu('KTP OCR', 'collapseOcrKtp', biometricSubMenus.ktpOcr),
+ createSubMenu('NPWP OCR', 'collapseOcrNpwp', biometricSubMenus.npwpOcr),
+ createSubMenu('SIM OCR', 'collapseOcrSim', biometricSubMenus.simOcr),
+ createSubMenu('Document OCR', 'collapseOcrDocument', biometricSubMenus.documentOcr)
+ ]
+ }],
+ iconClass: 'fas fa-user'
+ },
+ {
+ items: [{
+ name: 'SMS',
+ target: 'collapseSms',
+ subMenus: [
+ createMenuItem('SMS Verification', '/sms-verify'),
+ createSubMenu('SMS OTP Management', 'collapseSmsOtp', smsServiceMenus.smsOtp),
+ createSubMenu('SMS Announcements', 'collapseAnnouncement', smsServiceMenus.announcement),
+ createMenuItem('Blocked Numbers', '/sms-block'),
+ createMenuItem('SMS Anomaly Report', '/sms-anomaly')
+ ]
+ }],
+ iconClass: 'fas fa-phone'
+ },
+ {
+ items: [{
+ name: 'WhatsApp',
+ target: 'collapseWa',
+ subMenus: [
+ createMenuItem('Verify WhatsApp Account', '/wa-verify'),
+ createSubMenu('WhatsApp Management', 'collapseWaManage', whatsAppMenus.management),
+ createSubMenu('WhatsApp Activity', 'collapseActivity', whatsAppMenus.activity),
+ createMenuItem('WhatsApp Inbox', '/wa-inbox'),
+ createMenuItem('Blocked WhatsApp Numbers', '/wa-block')
+ ]
+ }],
+ iconClass: 'fab fa-whatsapp'
+ },
+ {
+ items: [{
+ name: 'Identity',
+ target: 'collapseIdentify',
+ subMenus: [
+ createSubMenu('Electronic Certificate Verification', 'collapseElectro', identityMenus.electronic),
+ createSubMenu('NPWP Verification', 'collapseIdentifyNpwp', identityMenus.npwp),
+ createSubMenu('Tax Number Verification', 'collapseTax', identityMenus.tax),
+ createSubMenu('Income Verification', 'collapseIncome', identityMenus.income),
+ createSubMenu('ID Verification', 'collapseIdVerification', identityMenus.id)
+ ]
+ }],
+ iconClass: 'fas fa-edit'
+ },
+ {
+ items: [{
+ name: 'Watchlist',
+ target: 'collapseWatchlist',
+ subMenus: [
+ createSubMenu('Watchlist Screening', 'collapseScreening', watchlistMenus.screening)
+ ]
+ }],
+ iconClass: 'fas fa-calendar'
+ },
+ {
+ items: [{
+ name: 'File',
+ target: 'collapseFiles',
+ subMenus: [
+ createSubMenu('File Screening', 'collapseScreening', fileMenus.screening)
+ ]
+ }],
+ iconClass: 'fas fa-cogs'
+ }
+];
+
+export default dataMenu;
\ No newline at end of file
diff --git a/src/screens/Biometric/FaceRecognition/Section/Compare.jsx b/src/screens/Biometric/FaceRecognition/Section/Compare.jsx
index a02d065..0e3c39e 100644
--- a/src/screens/Biometric/FaceRecognition/Section/Compare.jsx
+++ b/src/screens/Biometric/FaceRecognition/Section/Compare.jsx
@@ -28,7 +28,7 @@ const Compare = () => {
const [imageCompareUrl, setImageCompareUrl] = useState('');
const [verified, setVerified] = useState(null);
- const fileTypes = ["JPG", "JPEG", "PNG"];
+ const fileTypes = ["JPG", "JPEG"];
const [file, setFile] = useState(null); // For the first image
const [compareFile, setCompareFile] = useState(null); // For the second imag
@@ -113,20 +113,119 @@ const Compare = () => {
};
const handleImageUpload = (file) => {
- if (file && fileTypes.includes(file.name.split('.').pop().toUpperCase())) {
- setSelectedImageName(file.name);
- setFile(file); // Store the file directly in state
- setUploadError(''); // Clear error if valid
+ if (!file) {
+ setUploadError('Please select a file');
+ return;
}
+
+ // Check file size (2MB = 2 * 1024 * 1024 bytes)
+ const maxSize = 2 * 1024 * 1024;
+ if (file.size > maxSize) {
+ setUploadError('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)) {
+ setUploadError('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) {
+ setUploadError('Image dimensions must not exceed 300x300 pixels');
+ setFile(null);
+ setSelectedImageName('');
+ return;
+ }
+
+ // All validations passed
+ setSelectedImageName(file.name);
+ setFile(file);
+ setUploadError('');
+ };
+
+ img.onerror = () => {
+ URL.revokeObjectURL(objectUrl);
+ setUploadError('Invalid image file');
+ setFile(null);
+ setSelectedImageName('');
+ };
+
+ img.src = objectUrl;
};
const handleCompareImageUpload = (file) => {
- if (file && fileTypes.includes(file.name.split('.').pop().toUpperCase())) {
- setSelectedCompareImageName(file.name);
- setCompareFile(file); // Store the compare file directly in state
- setCompareUploadError(''); // Clear error if valid
+ if (!file) {
+ setCompareUploadError('Please select a file');
+ return;
}
- };
+
+ // Check file size (2MB = 2 * 1024 * 1024 bytes)
+ const maxSize = 2 * 1024 * 1024;
+ if (file.size > maxSize) {
+ setCompareUploadError('File size exceeds 2MB limit');
+ setCompareFile(null);
+ setSelectedCompareImageName('');
+ 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)) {
+ setCompareUploadError('Only JPG/JPEG files are allowed');
+ setCompareFile(null);
+ setSelectedCompareImageName('');
+ 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) {
+ setCompareUploadError('Image dimensions must not exceed 300x300 pixels');
+ setCompareFile(null);
+ setSelectedCompareImageName('');
+ return;
+ }
+
+ // All validations passed
+ setSelectedCompareImageName(file.name);
+ setCompareFile(file);
+ setCompareUploadError('');
+ };
+
+ img.onerror = () => {
+ URL.revokeObjectURL(objectUrl);
+ setCompareUploadError('Invalid image file');
+ setCompareFile(null);
+ setSelectedCompareImageName('');
+ };
+
+ img.src = objectUrl;
+ };
+
const handleImageCancel = () => {
setSelectedImageName('');
@@ -289,23 +388,23 @@ const Compare = () => {
-
+
-

-
File Name: {resultImageLabel}
+
File Name: {resultImageLabel}
-
-

+

-
File Name: {resultCompareImageLabel}
+
File Name: {resultCompareImageLabel}
@@ -445,18 +544,27 @@ const Compare = () => {
name="file"
types={fileTypes}
multiple={false}
+ onTypeError={(err) => {
+ setUploadError('Only JPG/JPEG files are allowed');
+ setFile(null);
+ setSelectedImageName('');
+ }}
children={
Drag and Drop Here
Or
Browse
-
Recommended size: 250x250 (Max File Size: 2MB)
+
Recommended size: 300x300 (Max File Size: 2MB)
Supported file types: JPG, JPEG
}
/>
- {uploadError && {uploadError}}
+ {uploadError && (
+
+ {uploadError}
+
+ )}
{/* Display uploaded image name */}
@@ -485,18 +593,27 @@ const Compare = () => {
name="file"
types={fileTypes}
multiple={false}
+ onTypeError={(err) => {
+ setCompareUploadError('Only JPG/JPEG files are allowed');
+ setCompareFile(null);
+ setSelectedCompareImageName('');
+ }}
children={
Drag and Drop Here
Or
Browse
-
Recommended size: 250x250 (Max File Size: 2MB)
+
Recommended size: 300x300 (Max File Size: 2MB)
Supported file types: JPG, JPEG
}
/>
- {compareUploadError && {compareUploadError}}
+ {compareUploadError && (
+
+ {compareUploadError}
+
+ )}
{/* Display uploaded image name */}
@@ -678,25 +795,42 @@ const styles = {
borderCollapse: 'collapse',
marginBottom: '20px',
},
+ imagesWrapper: {
+ display: 'flex',
+ flexWrap: 'wrap',
+ justifyContent: 'center',
+ gap: '2rem',
+ width: '100%',
+ margin: '2rem 0',
+ },
imageContainer: {
+ flex: '1 1 300px',
+ maxWidth: '500px',
+ minWidth: '280px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
- flex: 1,
- padding: '10px',
},
- imageCompareContainer: {
- display: 'flex',
- flexDirection: 'column',
- alignItems: 'center',
- flex: 1,
- padding: '10px',
- },
- imageStyle: {
+
+ responsiveImage: {
width: '100%',
height: 'auto',
- maxWidth: '150px', // Limit image width
+ maxHeight: '500px',
+ objectFit: 'contain',
borderRadius: '8px',
+ boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
+ transition: 'transform 0.3s ease',
+ cursor: 'pointer',
+ '&:hover': {
+ transform: 'scale(1.02)',
+ },
+ },
+
+ imageLabel: {
+ marginTop: '1rem',
+ textAlign: 'center',
+ fontSize: '0.9rem',
+ color: '#666',
},
similarityText: (verified) => ({
border: '0.1px solid gray',
diff --git a/src/screens/Biometric/FaceRecognition/Section/Enroll.jsx b/src/screens/Biometric/FaceRecognition/Section/Enroll.jsx
index e94a6e1..dd0ec6a 100644
--- a/src/screens/Biometric/FaceRecognition/Section/Enroll.jsx
+++ b/src/screens/Biometric/FaceRecognition/Section/Enroll.jsx
@@ -10,7 +10,7 @@ const Enroll = () => {
const BASE_URL = process.env.REACT_APP_BASE_URL
const API_KEY = process.env.REACT_APP_API_KEY
- const fileTypes = ["JPG", "JPEG", "PNG"];
+ const fileTypes = ["JPG", "JPEG"];
const [file, setFile] = useState(null);
const [errorMessage, setErrorMessage] = useState('');
@@ -137,24 +137,63 @@ const Enroll = () => {
};
const handleImageUpload = (file) => {
- // Ensure the file is not undefined or null before accessing its properties
- if (file && file.name) {
- const fileExtension = file.name.split('.').pop().toUpperCase();
- if (fileTypes.includes(fileExtension)) {
- setSelectedImageName(file.name);
- setFile(file);
- setImageError(''); // Clear any previous errors
- } else {
- alert('Image format is not supported');
- setImageError('Image format is not supported');
- setFile(null);
- }
- } else {
- console.error('No file selected or invalid file object.');
- }
+ 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);
@@ -336,17 +375,6 @@ const Enroll = () => {
}
};
- // Fungsi untuk mengonversi ukuran file dari byte ke KB/MB
- const formatFileSize = (sizeInBytes) => {
- if (sizeInBytes < 1024) {
- return `${sizeInBytes} bytes`; // Jika ukuran lebih kecil dari 1 KB
- } else if (sizeInBytes < 1048576) {
- return `${(sizeInBytes / 1024).toFixed(2)} KB`; // Jika ukuran lebih kecil dari 1 MB
- } else {
- return `${(sizeInBytes / 1048576).toFixed(2)} MB`; // Jika ukuran lebih besar dari 1 MB
- }
- };
-
const styles = {
formGroup: {
marginTop: '-45px',
@@ -633,6 +661,12 @@ const Enroll = () => {
color: 'white',
marginTop: '10px',
},
+ errorText: {
+ color: '#dc3545',
+ fontSize: '12px',
+ marginTop: '5px',
+ display: 'block'
+ }
};
if (!isServer) {
@@ -745,6 +779,11 @@ const Enroll = () => {
name="file"
types={fileTypes}
multiple={false}
+ onTypeError={(err) => {
+ setImageError('Only JPG/JPEG files are allowed');
+ setFile(null);
+ setSelectedImageName('');
+ }}
onDrop={(files) => {
if (files && files[0]) {
handleImageUpload(files[0]);
@@ -761,26 +800,18 @@ const Enroll = () => {
}
/>
- handleImageUpload(e.target.files[0])}
- />
- {imageError && {imageError}}
+
+ {imageError && (
+
+ {imageError}
+
+ )}
-
+
{selectedImageName && (
File: {selectedImageName}
- {file && (
-
- Size: {formatFileSize(file.size)}
-
- )}
@@ -810,10 +841,15 @@ const Enroll = () => {
- {resultImageLabel} {/* Display resultImageLabel instead of selectedImageName */}
+ {resultImageLabel}
diff --git a/src/screens/Biometric/FaceRecognition/Section/Search.jsx b/src/screens/Biometric/FaceRecognition/Section/Search.jsx
index 60ab6a2..da520ec 100644
--- a/src/screens/Biometric/FaceRecognition/Section/Search.jsx
+++ b/src/screens/Biometric/FaceRecognition/Section/Search.jsx
@@ -5,7 +5,7 @@ import { FileUploader } from 'react-drag-drop-files';
import Select from 'react-select'
import { ServerDownAnimation } from '../../../../assets/images';
-const fileTypes = ["JPG", "JPEG", "PNG"]; // Allowed file types
+const fileTypes = ["JPG", "JPEG"]; // Allowed file types
const Search = () => {
@@ -126,34 +126,83 @@ const Search = () => {
setIsSelectOpen(false);
};
+ // Add this after your existing state declarations
const handleImageUpload = (file) => {
- // Ensure the file is not undefined or null before accessing its properties
- if (file && file.name) {
- const fileExtension = file.name.split('.').pop().toUpperCase();
- if (fileTypes.includes(fileExtension)) {
+ if (!file) {
+ setImageError('Please select a file');
+ return;
+ }
+
+ // Store the uploaded file
+ setUploadedFile(file);
+
+ // 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('');
+ setUploadedFile(null);
+ 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('');
+ setUploadedFile(null);
+ return;
+ }
+
+ // Create preview URL for the uploaded image
+ const previewUrl = URL.createObjectURL(file);
+
+ // Check image dimensions
+ const img = new Image();
+ img.onload = () => {
+ URL.revokeObjectURL(previewUrl);
+
+ if (img.width > 300 || img.height > 300) {
+ setImageError('Image dimensions must not exceed 300x300 pixels');
+ setFile(null);
+ setSelectedImageName('');
+ setUploadedFile(null);
+ return;
+ }
+
+ // All validations passed
setSelectedImageName(file.name);
setFile(file);
- setUploadedFile(file); // Set uploadedFile to the selected file
- setImageError(''); // Clear any previous errors
- } else {
- alert('Image format is not supported');
- setImageError('Image format is not supported');
+ setImageError('');
+ };
+
+ img.onerror = () => {
+ URL.revokeObjectURL(previewUrl);
+ setImageError('Invalid image file');
setFile(null);
- setUploadedFile(null); // Clear uploadedFile if the file is unsupported
- }
- } else {
- console.error('No file selected or invalid file object.');
- }
+ setSelectedImageName('');
+ setUploadedFile(null);
+ };
+
+ img.src = previewUrl;
};
+ // Update the handleImageCancel function
const handleImageCancel = () => {
setSelectedImageName('');
setFile(null);
+ setUploadedFile(null);
if (fileInputRef.current) {
fileInputRef.current.value = '';
}
};
+
const handleCheckClick = async () => {
// Clear existing errors
setApplicationIdError('');
@@ -355,17 +404,31 @@ const Search = () => {
fontSize: '20px',
},
uploadArea: {
+ backgroundColor: '#e6f2ff',
+ height: '250px',
+ cursor: 'pointer',
+ marginTop: '1rem',
+ paddingTop: '22px',
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+ border: '1px solid #ced4da',
+ borderRadius: '0.25rem',
+ },
+ uploadAreaMobile: {
backgroundColor: '#e6f2ff',
- height: '40svh',
+ height: '50svh', // Use viewport height for a more responsive size
cursor: 'pointer',
marginTop: '1rem',
- padding: '1rem',
+ paddingTop: '18px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
border: '1px solid #ced4da',
borderRadius: '0.25rem',
+ padding: '20px',
},
uploadIcon: {
fontSize: '40px',
@@ -377,7 +440,7 @@ const Search = () => {
fontWeight: '400',
fontSize: '16px',
lineHeight: '13px',
- },
+ },
wrapper: {
border: '1px solid #ddd',
borderRadius: '6px',
@@ -479,14 +542,37 @@ const Search = () => {
gridTemplateColumns: isMobile ? 'repeat(2, 1fr)' : 'repeat(5, 1fr)', // Adjust based on isMobile
gap: '16px',
},
- resultItem: {
- border: '1px solid #ddd',
+ imageWrapper: {
+ width: '100%',
+ height: '200px',
+ overflow: 'hidden',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ backgroundColor: '#f8f9fa',
borderRadius: '8px',
- padding: '12px',
- boxShadow: '0 2px 5px rgba(0, 0, 0, 0.1)',
- textAlign: 'center',
- transition: 'transform 0.3s ease', // Added transition for hover effect
- cursor: 'pointer',
+ },
+
+ responsiveImage: {
+ maxWidth: '100%',
+ maxHeight: '100%',
+ width: 'auto',
+ height: 'auto',
+ objectFit: 'contain',
+ transition: 'transform 0.3s ease',
+ '&:hover': {
+ transform: 'scale(1.05)',
+ },
+ },
+ resultItem: {
+ padding: '15px',
+ backgroundColor: '#ffffff',
+ borderRadius: '10px',
+ boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
+ transition: 'transform 0.3s ease',
+ '&:hover': {
+ transform: 'translateY(-5px)',
+ },
},
resultItemHover: {
transform: 'scale(1.05)', // Slightly enlarge the card on hover
@@ -556,10 +642,10 @@ const Search = () => {
{isLoading && (
-
+
)}
{/* Application ID Selection */}
@@ -627,38 +713,43 @@ const Search = () => {
{/* Upload Section */}
- {/* Drag and Drop File Uploader */}
@@ -679,15 +770,14 @@ const Search = () => {
{errorMessage && {errorMessage}}
{/* Submit Button */}
-
+
{/* Results Section */}
- {
- showResult && results.length > 0 && (
+ {showResult && results.length > 0 && (
Results
@@ -698,13 +788,18 @@ const Search = () => {
Similarity: {result.similarity}%
Distance: {result.distance}
-

+
+

+
))}
- )
- }
+ )}
);
diff --git a/src/screens/Biometric/FaceRecognition/Section/Verify.jsx b/src/screens/Biometric/FaceRecognition/Section/Verify.jsx
index af005dd..9189fe3 100644
--- a/src/screens/Biometric/FaceRecognition/Section/Verify.jsx
+++ b/src/screens/Biometric/FaceRecognition/Section/Verify.jsx
@@ -3,12 +3,13 @@ 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", "PNG"];
+ const fileTypes = ["JPG", "JPEG"];
const [file, setFile] = useState(null);
const [errorMessage, setErrorMessage] = useState('');
@@ -18,7 +19,7 @@ const Verify = () => {
const [thresholdError, setThresholdError] = useState('');
const [selectedImageName, setSelectedImageName] = useState('');
const [resultImageLabel, setResultImageLabel] = useState('');
- const fileInputRef = useRef(null);
+ const inputRef = useRef(null);
const [showResult, setShowResult] = useState(false);
const [applicationId, setApplicationId] = useState('');
const [thresholdId, setThresholdId] = useState('');
@@ -33,6 +34,7 @@ const Verify = () => {
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' },
@@ -135,28 +137,68 @@ const Verify = () => {
const handleImageUpload = (file) => {
- if (file && file.name) {
- const fileExtension = file.name.split('.').pop().toUpperCase();
- if (fileTypes.includes(fileExtension)) {
- setSelectedImageName(file.name);
- setFile(file);
- setUploadError('');
- } else {
- alert('Image format is not supported');
- setUploadError('Image format is not supported');
- setFile(null);
- }
- } else {
- console.error('No file selected or invalid file object.');
+ 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 (fileInputRef.current) {
- fileInputRef.current.value = '';
+ if (inputRef.current) {
+ inputRef.current.value = '';
}
};
@@ -308,17 +350,6 @@ const Verify = () => {
}
};
- // Fungsi untuk mengonversi ukuran file dari byte ke KB/MB
- const formatFileSize = (sizeInBytes) => {
- if (sizeInBytes < 1024) {
- return `${sizeInBytes} bytes`; // Jika ukuran lebih kecil dari 1 KB
- } else if (sizeInBytes < 1048576) {
- return `${(sizeInBytes / 1024).toFixed(2)} KB`; // Jika ukuran lebih kecil dari 1 MB
- } else {
- return `${(sizeInBytes / 1048576).toFixed(2)} MB`; // Jika ukuran lebih besar dari 1 MB
- }
- };
-
if (!isServer) {
return (
@@ -734,60 +765,50 @@ const Verify = () => {
{/* Upload Section */}
-
+
-
- Upload Face Photo
-
-
-
-
- {/* File Input */}
-
handleImageUpload(e.target.files[0])}
+ }}
+ children={
+
+
+
Drag and Drop Here
+
Or
+
+ Browse
+
+
Recommended size: 300x300 (Max File Size: 2MB)
+
Supported file types: JPG, JPEG
+
+ }
/>
-
- {/* Error Message */}
- {uploadError &&
{uploadError}}
-
+ {imageError && (
+
+ {imageError}
+
+ )}
@@ -795,11 +816,6 @@ const Verify = () => {
{selectedImageName && (
File: {selectedImageName}
- {file && (
-
- Size: {formatFileSize(file.size)}
-
- )}
@@ -817,33 +833,40 @@ const Verify = () => {
{/* Results Section */}
{showResult && (
-
-
Results
-
-
-
-
- Similarity |
-
- {verified !== null ? (verified ? 'True' : 'False') : 'N/A'}
- |
-
-
-
+
+
Results
+
+
+
+
+ Similarity |
+
+ {verified !== null ? (verified ? 'True' : 'False') : 'N/A'}
+ |
+
+
+
-
-

-
- File Name: {resultImageLabel} {/* Display the resultImageLabel here */}
-
-
+
+

+
+ File Name: {resultImageLabel}
+
+
+
-
)}
+
);
diff --git a/src/screens/Biometric/OcrKtp/Verify.jsx b/src/screens/Biometric/OcrKtp/Verify.jsx
index 90850eb..43431ef 100644
--- a/src/screens/Biometric/OcrKtp/Verify.jsx
+++ b/src/screens/Biometric/OcrKtp/Verify.jsx
@@ -12,7 +12,7 @@ const CustomLabel = ({ overRide, children, ...props }) => {
const Verify = () => {
const BASE_URL = process.env.REACT_APP_BASE_URL;
const API_KEY = process.env.REACT_APP_API_KEY;
- const fileTypes = ["image/jpeg", "image/png"];
+ const fileTypes = ["image/jpeg", "image/jpg"];
const fileInputRef = useRef(null);
const [isMobile, setIsMobile] = useState(false);
@@ -119,19 +119,63 @@ const Verify = () => {
}
};
- const handleImageUpload = (file) => {
+ const checkImageDimensions = (file) => {
+ return new Promise((resolve, reject) => {
+ const img = new Image();
+ img.src = URL.createObjectURL(file);
+
+ img.onload = () => {
+ URL.revokeObjectURL(img.src);
+ if (img.width > 300 || img.height > 300) {
+ reject('Image dimensions must not exceed 300x300 pixels');
+ } else {
+ resolve(true);
+ }
+ };
+
+ img.onerror = () => {
+ URL.revokeObjectURL(img.src);
+ reject('Failed to load image');
+ };
+ });
+ };
+
+ // Update handleImageUpload to include dimension checking
+ const handleImageUpload = async (file) => {
setFile(file);
setSelectedImageName(file.name);
-
- // Validate file type
- if (!fileTypes.includes(file.type)) {
- setImageError('Invalid file type. Only JPG, JPEG, and PNG are allowed.');
- } else if (file.size > 2 * 1024 * 1024) { // Max 2MB
- setImageError('File size exceeds 2MB.');
- } else {
+
+ try {
+ // Check if file is PNG
+ if (file.type === 'image/png') {
+ setImageError('The image format is not suitable. Only JPG and JPEG files are allowed.');
+ setFile(null);
+ setSelectedImageName('');
+ return;
+ }
+
+ // Validate file type
+ if (!fileTypes.includes(file.type)) {
+ setImageError('Invalid file type. Only JPG and JPEG are allowed.');
+ return;
+ }
+
+ // Validate file size
+ if (file.size > 2 * 1024 * 1024) {
+ setImageError('File size exceeds 2MB.');
+ return;
+ }
+
+ // Validate image dimensions
+ await checkImageDimensions(file);
setImageError('');
+
+ } catch (error) {
+ setImageError(error);
+ setFile(null);
+ setSelectedImageName('');
}
- };
+ };
const handleImageCancel = () => {
setFile(null);
@@ -161,6 +205,33 @@ const Verify = () => {
return Object.values(errors).every(error => error === '');
};
+ const handleApiError = (response) => {
+ // Handle 400 Bad Request
+ if (response.status_code === 400) {
+ console.error('❌ Bad Request:', {
+ status: response.status_code,
+ detail: response.detail || 'Mohon Upload KTP'
+ });
+ return response.detail || 'Mohon Upload KTP';
+ }
+
+ // Handle 500 Internal Server Error
+ if (response.status_code >= 500) {
+ console.error('🔥 Server Error:', {
+ status: response.status_code,
+ message: 'Internal Server Error'
+ });
+ return 'Internal Server Error';
+ }
+
+ // Default error message
+ console.error('⚠️ Unknown Error:', {
+ status: response.status_code,
+ response
+ });
+ return 'Terjadi kesalahan. Silakan coba lagi.';
+ };
+
// Submit form and trigger OCR API
const handleCheckClick = async () => {
if (!validateForm()) {
@@ -183,16 +254,18 @@ const Verify = () => {
});
if (!response.ok) {
- throw new Error('OCR processing failed');
+ throw new Error('OCR processing failed, Please check your input, Please check your input');
}
const result = await response.json();
-
+ console.log('📡 API Response:', result);
+
// Log the full result to verify structure
console.log('OCR API Response:', result);
if (result.status_code === 201) {
const responseData = result.details.data?.['data-ktp'] || {};
+ console.log('✅ OCR Success:', result);
const updateQuota = result.details.data.quota
const data = {
@@ -230,10 +303,22 @@ const Verify = () => {
await fetchImage(imageFileName); // Call the fetchImage function to fetch the image
}
} else {
- setErrorMessage('OCR processing failed');
+ const errorMsg = handleApiError(result);
+ setErrorMessage(errorMsg);
+ setShowResult(false);
+ console.error('❌ OCR Failed:', {
+ error: errorMsg,
+ response: result
+ });
}
} catch (error) {
- setErrorMessage(error.message || 'Error during OCR processing');
+ const errorMsg = 'Internal Server Error';
+ setErrorMessage(errorMsg);
+ setShowResult(false);
+ console.error('🔥 Request Failed:', {
+ error: error.message,
+ detail: error
+ });
} finally {
setIsLoading(false);
}
@@ -350,9 +435,10 @@ const Verify = () => {
borderRadius: '4px',
},
errorText: {
- color: '#721c24',
- fontSize: '14px',
- margin: '0',
+ color: '#dc3545', // Bootstrap danger color
+ fontSize: '12px', // Small text
+ marginTop: '5px',
+ fontWeight: '400'
},
loadingOverlay: {
position: 'fixed', // Gunakan fixed untuk overlay penuh layar
@@ -501,8 +587,9 @@ const Verify = () => {
Upload Image (KTP)
+
- {/* Drag and Drop File Input */}
+ {/* Existing drag & drop area */}
- {/* File Input */}
+ {/* File input */}
handleImageUpload(e.target.files[0])}
/>
+ {/* Display selected file info */}
{selectedImageName && (
File: {selectedImageName}
@@ -543,8 +631,12 @@ const Verify = () => {
)}
+
+ {/* Display validation errors */}
{validationErrors.file &&
{validationErrors.file}
}
+ {imageError &&
{imageError}
}
+
diff --git a/src/screens/Biometric/OcrNpwp/Verify.jsx b/src/screens/Biometric/OcrNpwp/Verify.jsx
index 5fbb1a5..c9aff44 100644
--- a/src/screens/Biometric/OcrNpwp/Verify.jsx
+++ b/src/screens/Biometric/OcrNpwp/Verify.jsx
@@ -12,7 +12,7 @@ const CustomLabel = ({ overRide, children, ...props }) => {
const Verify = () => {
const BASE_URL = process.env.REACT_APP_BASE_URL;
const API_KEY = process.env.REACT_APP_API_KEY;
- const fileTypes = ["image/jpeg", "image/png"];
+ const fileTypes = ["image/jpeg", "image/jpg"];
const fileInputRef = useRef(null);
const [isMobile, setIsMobile] = useState(false);
@@ -119,19 +119,63 @@ const Verify = () => {
}
};
- const handleImageUpload = (file) => {
+ const checkImageDimensions = (file) => {
+ return new Promise((resolve, reject) => {
+ const img = new Image();
+ img.src = URL.createObjectURL(file);
+
+ img.onload = () => {
+ URL.revokeObjectURL(img.src);
+ if (img.width > 300 || img.height > 300) {
+ reject('Image dimensions must not exceed 300x300 pixels');
+ } else {
+ resolve(true);
+ }
+ };
+
+ img.onerror = () => {
+ URL.revokeObjectURL(img.src);
+ reject('Failed to load image');
+ };
+ });
+ };
+
+ // Update handleImageUpload function
+ const handleImageUpload = async (file) => {
setFile(file);
setSelectedImageName(file.name);
-
- // Validate file type
- if (!fileTypes.includes(file.type)) {
- setImageError('Invalid file type. Only JPG, JPEG, and PNG are allowed.');
- } else if (file.size > 2 * 1024 * 1024) { // Max 2MB
- setImageError('File size exceeds 2MB.');
- } else {
+
+ try {
+ // Check if file is PNG
+ if (file.type === 'image/png') {
+ setImageError('The image format is not suitable. Only JPG and JPEG files are allowed.');
+ setFile(null);
+ setSelectedImageName('');
+ return;
+ }
+
+ // Validate file type
+ if (!fileTypes.includes(file.type)) {
+ setImageError('Invalid file type. Only JPG and JPEG are allowed.');
+ return;
+ }
+
+ // Validate file size
+ if (file.size > 2 * 1024 * 1024) {
+ setImageError('File size exceeds 2MB.');
+ return;
+ }
+
+ // Validate image dimensions
+ await checkImageDimensions(file);
setImageError('');
+
+ } catch (error) {
+ setImageError(error);
+ setFile(null);
+ setSelectedImageName('');
}
- };
+ };
const handleImageCancel = () => {
setFile(null);
@@ -340,9 +384,10 @@ const Verify = () => {
borderRadius: '4px',
},
errorText: {
- color: '#721c24',
- fontSize: '14px',
- margin: '0',
+ color: '#dc3545',
+ fontSize: '12px',
+ marginTop: '5px',
+ fontWeight: '400'
},loadingOverlay: {
position: 'fixed', // Gunakan fixed untuk overlay penuh layar
top: 0,
@@ -515,7 +560,7 @@ const Verify = () => {
id="imageInput"
className="form-control"
style={{ display: 'none' }}
- accept="image/jpeg, image/png"
+ accept="image/jpeg, image/jpg"
onChange={(e) => handleImageUpload(e.target.files[0])}
/>
@@ -532,7 +577,9 @@ const Verify = () => {
)}
+ {/* Display validation errors */}
{validationErrors.file && {validationErrors.file}
}
+ {imageError && {imageError}
}