bug fixed
This commit is contained in:
parent
142bd4f21f
commit
9d5ca6874f
@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import Table from '@/components/common/Table';
|
import Table from '@/components/common/Table';
|
||||||
import { TextField, SelectField, DateField } from '@/components/common/FormControls';
|
import { TextField, SelectField, DateField } from '@/components/common/FormControls';
|
||||||
import StatusBadge from '@/components/common/StatusBadge';
|
import StatusBadge from '@/components/common/StatusBadge';
|
||||||
import { createQuarterlyWindow, updateQuarterlyWindow, getQuarterlyWindows } from '@/services/configuration/quarterlyWindows';
|
import { createQuarterlyWindow, updateQuarterlyWindow, getQuarterlyWindows, getQuarterlyWindowById } from '@/services/configuration/quarterlyWindows';
|
||||||
|
|
||||||
const downloadIconSrc = '/assets/images/DownloadSimple.svg';
|
const downloadIconSrc = '/assets/images/DownloadSimple.svg';
|
||||||
const addIconSrc = '/assets/images/ic_baseline-plus.svg';
|
const addIconSrc = '/assets/images/ic_baseline-plus.svg';
|
||||||
@ -275,19 +275,56 @@ const QuarterlyWindows = () => {
|
|||||||
setCurrentPage((prev) => Math.min(prev, maxPage));
|
setCurrentPage((prev) => Math.min(prev, maxPage));
|
||||||
}, [filteredRows.length, pageSize]);
|
}, [filteredRows.length, pageSize]);
|
||||||
|
|
||||||
const openEditModal = (index) => {
|
const openEditModal = async (index) => {
|
||||||
const selected = quarterData[index];
|
try {
|
||||||
// Ensure dates are in the correct format for the form inputs
|
setIsLoading(true);
|
||||||
const formData = {
|
|
||||||
...selected,
|
// Calculate the actual index in the filtered data based on pagination
|
||||||
startDate: selected.startDate ? formatDateForInput(selected.startDate) : '',
|
const actualIndex = (currentPage - 1) * pageSize + index;
|
||||||
endDate: selected.endDate ? formatDateForInput(selected.endDate) : ''
|
const selected = filteredRows[actualIndex];
|
||||||
};
|
|
||||||
setEditingRow(index);
|
if (!selected || !selected.id) {
|
||||||
setForm(formData);
|
throw new Error('Invalid quarterly window selected');
|
||||||
setOriginalForm(formData);
|
}
|
||||||
setModalMode('edit');
|
|
||||||
setValidationErrors({});
|
// Fetch the latest data for this quarter
|
||||||
|
const response = await getQuarterlyWindowById(selected.id);
|
||||||
|
|
||||||
|
if (response && response.data) {
|
||||||
|
const quarterData = response.data;
|
||||||
|
const formData = {
|
||||||
|
id: quarterData.id,
|
||||||
|
survey_name: quarterData.survey_name || '',
|
||||||
|
establishment: quarterData.establishment || '-',
|
||||||
|
year: quarterData.year?.toString() || '',
|
||||||
|
quarter: quarterData.quarter || '',
|
||||||
|
startDate: quarterData.start_date ? formatDateForInput(quarterData.start_date) : '',
|
||||||
|
endDate: quarterData.end_date ? formatDateForInput(quarterData.end_date) : '',
|
||||||
|
gracePeriod: quarterData.grace_periods_days ? `${quarterData.grace_periods_days} days` : '0 days',
|
||||||
|
submissionCount: quarterData.submission_count?.toString() || '-',
|
||||||
|
assigned: quarterData.assigned?.toString() || '0',
|
||||||
|
responded: quarterData.responded?.toString() || '0',
|
||||||
|
not_responded: quarterData.not_responded?.toString() || '0',
|
||||||
|
status: quarterData.is_active ? 'Active' : 'Inactive'
|
||||||
|
};
|
||||||
|
|
||||||
|
setEditingRow(actualIndex);
|
||||||
|
setForm(formData);
|
||||||
|
setOriginalForm(formData);
|
||||||
|
setModalMode('edit');
|
||||||
|
setValidationErrors({});
|
||||||
|
} else {
|
||||||
|
throw new Error('No data returned from server');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in openEditModal:', error);
|
||||||
|
setToastData({
|
||||||
|
message: 'Failed to load quarterly window details. Please try again.',
|
||||||
|
type: 'error'
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCloseModal = () => {
|
const handleCloseModal = () => {
|
||||||
|
|||||||
@ -33,10 +33,17 @@ const Banner = () => {
|
|||||||
</a>
|
</a>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
// Scroll to How it works section
|
// Scroll to How it works section with offset for fixed header
|
||||||
const howItWorksSection = document.getElementById('how-it-works');
|
const howItWorksSection = document.getElementById('how-it-works');
|
||||||
if (howItWorksSection) {
|
if (howItWorksSection) {
|
||||||
howItWorksSection.scrollIntoView({ behavior: 'smooth' });
|
const headerOffset = 80; // Same as in Navbar.jsx
|
||||||
|
const elementPosition = howItWorksSection.getBoundingClientRect().top;
|
||||||
|
const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: offsetPosition,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="border-2 border-[#92722A] text-[#92722A] text-md px-5 py-2 rounded-md hover:bg-[#f9f6ec] transition-all shadow-sm"
|
className="border-2 border-[#92722A] text-[#92722A] text-md px-5 py-2 rounded-md hover:bg-[#f9f6ec] transition-all shadow-sm"
|
||||||
|
|||||||
@ -49,13 +49,20 @@ const Navbar = () => {
|
|||||||
: "text-gray-800 hover:text-[#b9933b]"
|
: "text-gray-800 hover:text-[#b9933b]"
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
// Scroll and highlight on click
|
// Scroll and highlight on click with offset for fixed header
|
||||||
const handleClick = (id) => {
|
const handleClick = (id) => {
|
||||||
setActiveSection(id);
|
setActiveSection(id);
|
||||||
closeMenu();
|
closeMenu();
|
||||||
const section = document.getElementById(id);
|
const section = document.getElementById(id);
|
||||||
if (section) {
|
if (section) {
|
||||||
section.scrollIntoView({ behavior: "smooth", block: "start" });
|
const headerOffset = 80; // Height of your fixed header
|
||||||
|
const elementPosition = section.getBoundingClientRect().top;
|
||||||
|
const offsetPosition = elementPosition + window.pageYOffset - headerOffset;
|
||||||
|
|
||||||
|
window.scrollTo({
|
||||||
|
top: offsetPosition,
|
||||||
|
behavior: "smooth"
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -124,8 +131,9 @@ const Navbar = () => {
|
|||||||
)}
|
)}
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* Sections */}
|
{/* Sections with proper spacing */}
|
||||||
<div className="pt-20 scroll-smooth">
|
<div className="scroll-smooth">
|
||||||
|
<div className="pt-24">
|
||||||
<Banner />
|
<Banner />
|
||||||
<section id="about-ipi"><Industrial /></section>
|
<section id="about-ipi"><Industrial /></section>
|
||||||
<section id="how-it-works"><Cards /></section>
|
<section id="how-it-works"><Cards /></section>
|
||||||
@ -138,6 +146,7 @@ const Navbar = () => {
|
|||||||
<section id="faqs"><Faq /></section>
|
<section id="faqs"><Faq /></section>
|
||||||
<Cta/>
|
<Cta/>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -109,19 +109,26 @@ const Login = () => {
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
generateCaptcha();
|
generateCaptcha();
|
||||||
|
|
||||||
const lockUntil = localStorage.getItem('lock_until');
|
// Get the stored attempts and lock status for the current email
|
||||||
const attempts = parseInt(localStorage.getItem('failed_attempts') || '0', 10);
|
const storedAttempts = JSON.parse(localStorage.getItem('login_attempts') || '{}');
|
||||||
|
const emailAttempts = storedAttempts[email] || { attempts: 0, lockUntil: null };
|
||||||
|
|
||||||
|
setFailedAttempts(emailAttempts.attempts);
|
||||||
|
|
||||||
if (lockUntil && Date.now() < parseInt(lockUntil, 10)) {
|
if (emailAttempts.lockUntil && Date.now() < emailAttempts.lockUntil) {
|
||||||
setIsLocked(true);
|
setIsLocked(true);
|
||||||
setLockExpiry(lockUntil);
|
setLockExpiry(emailAttempts.lockUntil);
|
||||||
startCountdown(lockUntil);
|
startCountdown(emailAttempts.lockUntil);
|
||||||
|
} else if (emailAttempts.lockUntil) {
|
||||||
|
// Clear expired lock
|
||||||
|
const updatedAttempts = { ...storedAttempts };
|
||||||
|
delete updatedAttempts[email];
|
||||||
|
localStorage.setItem('login_attempts', JSON.stringify(updatedAttempts));
|
||||||
|
setIsLocked(false);
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem('lock_until');
|
|
||||||
setIsLocked(false);
|
setIsLocked(false);
|
||||||
}
|
}
|
||||||
setFailedAttempts(attempts);
|
}, [generateCaptcha, startCountdown, email]);
|
||||||
}, [generateCaptcha, startCountdown]);
|
|
||||||
|
|
||||||
React.useEffect(
|
React.useEffect(
|
||||||
() => () => {
|
() => () => {
|
||||||
@ -225,8 +232,13 @@ const Login = () => {
|
|||||||
String(role || '').toLowerCase() === 'admin' || payload?.is_admin === true;
|
String(role || '').toLowerCase() === 'admin' || payload?.is_admin === true;
|
||||||
const successMessage = response?.message || 'Login successful.';
|
const successMessage = response?.message || 'Login successful.';
|
||||||
|
|
||||||
localStorage.removeItem('failed_attempts');
|
// Clear login attempts for this email
|
||||||
localStorage.removeItem('lock_until');
|
const storedAttempts = JSON.parse(localStorage.getItem('login_attempts') || '{}');
|
||||||
|
if (storedAttempts[email]) {
|
||||||
|
delete storedAttempts[email];
|
||||||
|
localStorage.setItem('login_attempts', JSON.stringify(storedAttempts));
|
||||||
|
}
|
||||||
|
|
||||||
setFailedAttempts(0);
|
setFailedAttempts(0);
|
||||||
setIsLocked(false);
|
setIsLocked(false);
|
||||||
setRemainingTime(0);
|
setRemainingTime(0);
|
||||||
@ -262,15 +274,27 @@ const Login = () => {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Login failed', err);
|
console.error('Login failed', err);
|
||||||
|
|
||||||
const attempts = failedAttempts + 1;
|
const storedAttempts = JSON.parse(localStorage.getItem('login_attempts') || '{}');
|
||||||
localStorage.setItem('failed_attempts', attempts);
|
const attempts = (storedAttempts[email]?.attempts || 0) + 1;
|
||||||
|
|
||||||
|
// Update attempts for this email
|
||||||
|
const updatedAttempts = {
|
||||||
|
...storedAttempts,
|
||||||
|
[email]: {
|
||||||
|
attempts,
|
||||||
|
lockUntil: attempts >= MAX_FAILED_ATTEMPTS
|
||||||
|
? Date.now() + LOCK_DURATION_MINUTES * 60 * 1000
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
localStorage.setItem('login_attempts', JSON.stringify(updatedAttempts));
|
||||||
setFailedAttempts(attempts);
|
setFailedAttempts(attempts);
|
||||||
|
|
||||||
refreshCaptcha();
|
refreshCaptcha();
|
||||||
|
|
||||||
if (attempts >= MAX_FAILED_ATTEMPTS) {
|
if (attempts >= MAX_FAILED_ATTEMPTS) {
|
||||||
const lockUntil = Date.now() + LOCK_DURATION_MINUTES * 60 * 1000;
|
const lockUntil = Date.now() + LOCK_DURATION_MINUTES * 60 * 1000;
|
||||||
localStorage.setItem('lock_until', lockUntil);
|
|
||||||
setIsLocked(true);
|
setIsLocked(true);
|
||||||
setLockExpiry(lockUntil);
|
setLockExpiry(lockUntil);
|
||||||
startCountdown(lockUntil);
|
startCountdown(lockUntil);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user