client side bug fixed
This commit is contained in:
parent
9b015fe922
commit
2aa572ad1f
@ -59,7 +59,12 @@ const ChangePassword = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
const registeredEmail = location.state?.email || "";
|
||||
const { email: registeredEmail, user_type: userType } = location.state || {};
|
||||
|
||||
// Ensure user_type is set in the form data
|
||||
const [formData, setFormData] = React.useState({
|
||||
user_type: userType
|
||||
});
|
||||
|
||||
const [otp, setOtp] = React.useState("");
|
||||
const [newPassword, setNewPassword] = React.useState("");
|
||||
@ -132,6 +137,7 @@ if (newPassword !== confirmPassword) {
|
||||
otp: otp.trim(),
|
||||
password: newPassword,
|
||||
confirm_password: confirmPassword,
|
||||
user_type: userType // Use the user_type from location state
|
||||
};
|
||||
|
||||
const response = await apiClient.post("/forgot-password/verify-otp", payload);
|
||||
@ -197,6 +203,21 @@ if (newPassword !== confirmPassword) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
User Type
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
type="text"
|
||||
disabled
|
||||
value={userType === 'admin_user' ? 'Admin' : 'Establishment'}
|
||||
className="block w-full h-10 rounded-md border-2 border-gray-300 px-4 text-sm bg-gray-50 cursor-not-allowed"
|
||||
/>
|
||||
<input type="hidden" name="user_type" value={userType} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ToggleableInput
|
||||
label="Verification Code"
|
||||
required
|
||||
|
||||
@ -1,97 +1,172 @@
|
||||
import React, { useState } from "react";
|
||||
import { ChevronDown, ChevronUp } from "lucide-react"; // ✅ Up/Down icons
|
||||
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import { ChevronDown, ChevronUp } from "lucide-react";
|
||||
|
||||
const Faq = () => {
|
||||
const [openIndex, setOpenIndex] = useState(null);
|
||||
|
||||
const faqs = [
|
||||
const [openIndexLeft, setOpenIndexLeft] = useState(null);
|
||||
const [openIndexRight, setOpenIndexRight] = useState(null);
|
||||
|
||||
// FULL FAQ DATA
|
||||
const leftFaqs = [
|
||||
{
|
||||
question: "Do I need an account to respond?",
|
||||
answer:
|
||||
"Yes. FCSC provisions accounts to selected establishments. Use Login to access the survey.",
|
||||
},
|
||||
{
|
||||
question: "Can I register myself?",
|
||||
answer:
|
||||
"No. There is no self-registration. If you were contacted but can’t access your account, use Forgot password or Contact support.",
|
||||
},
|
||||
{
|
||||
question: "Is my data public?",
|
||||
answer: "No. Results are published only in aggregate form.",
|
||||
},
|
||||
{
|
||||
question: "What if production was zero in a month?",
|
||||
answer: "Enter 0 for the month and provide a reason when prompted.",
|
||||
},
|
||||
{
|
||||
question: "Can I update after submission?",
|
||||
answer:
|
||||
"Yes, if a revision window is open or if FCSC requests a correction.",
|
||||
},
|
||||
{
|
||||
question: "Which browser is supported?",
|
||||
answer: "Latest Chrome, Edge, Safari.",
|
||||
},
|
||||
{
|
||||
question: "How long does it take?",
|
||||
answer:
|
||||
"Most respondents complete within minutes each quarter, depending on product lines.",
|
||||
},
|
||||
];
|
||||
|
||||
const rightFaqs = [
|
||||
{
|
||||
question: "Can I register myself?",
|
||||
answer:
|
||||
"No. There is no self-registration. If you were contacted but can’t access your account, use Forgot password or Contact support.",
|
||||
},
|
||||
{
|
||||
question: "What if production was zero in a month?",
|
||||
answer: "Enter 0 for the month and provide a reason when prompted.",
|
||||
},
|
||||
{
|
||||
question: "Which browser is supported?",
|
||||
answer: "Latest Chrome, Edge, Safari.",
|
||||
},
|
||||
{
|
||||
question: "Who can I contact?",
|
||||
answer: "See Need help below.",
|
||||
},
|
||||
];
|
||||
|
||||
const toggleFaq = (index) => {
|
||||
setOpenIndex(openIndex === index ? null : index);
|
||||
|
||||
// Auto height expand component
|
||||
const Expandable = ({ isOpen, children }) => {
|
||||
const ref = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
ref.current.style.maxHeight = ref.current.scrollHeight + "px";
|
||||
} else {
|
||||
ref.current.style.maxHeight = "0px";
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={`overflow-hidden transition-[max-height] duration-300 ${
|
||||
isOpen ? "mt-3" : ""
|
||||
}`}
|
||||
style={{ maxHeight: "0px" }}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<section className="bg-[#fafafa] py-12 px-6 md:px-16 lg:px-24">
|
||||
<h2 className="text-2xl font-semibold text-gray-900 mb-8">
|
||||
Frequently asked questions
|
||||
</h2>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{faqs.map((faq, index) => {
|
||||
const isOpen = openIndex === index;
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className={`border rounded-xl p-5 shadow-sm transition-all duration-300 bg-white ${
|
||||
isOpen ? "border-gray-200" : "border-gray-200"
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
onClick={() => toggleFaq(index)}
|
||||
className="w-full flex justify-between items-center text-left"
|
||||
|
||||
{/* TWO FULLY INDEPENDENT COLUMNS */}
|
||||
<div className="grid md:grid-cols-2 gap-10">
|
||||
|
||||
{/* LEFT COLUMN */}
|
||||
<div className="flex flex-col gap-6">
|
||||
{leftFaqs.map((faq, index) => {
|
||||
const isOpen = openIndexLeft === index;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-white rounded-xl p-5 shadow-sm transition-all duration-300"
|
||||
>
|
||||
<span
|
||||
className={`font-medium ${
|
||||
isOpen ? "text-yellow-800" : "text-gray-900"
|
||||
}`}
|
||||
<button
|
||||
onClick={() =>
|
||||
setOpenIndexLeft(isOpen ? null : index)
|
||||
}
|
||||
className="w-full flex justify-between items-center text-left"
|
||||
>
|
||||
{faq.question}
|
||||
</span>
|
||||
{isOpen ? (
|
||||
<ChevronUp size={22} className="text-yellow-700" /> // ⬆️ when open
|
||||
) : (
|
||||
<ChevronDown size={22} className="text-gray-600" /> // ⬇️ when closed
|
||||
)}
|
||||
</button>
|
||||
|
||||
{isOpen && (
|
||||
<p className="mt-3 text-gray-700 text-sm leading-relaxed">
|
||||
{faq.answer}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
<span
|
||||
className={`font-medium ${
|
||||
isOpen ? "text-yellow-800" : "text-gray-900"
|
||||
}`}
|
||||
>
|
||||
{faq.question}
|
||||
</span>
|
||||
|
||||
{isOpen ? (
|
||||
<ChevronUp size={22} className="text-yellow-700" />
|
||||
) : (
|
||||
<ChevronDown size={22} className="text-gray-600" />
|
||||
)}
|
||||
</button>
|
||||
|
||||
<Expandable isOpen={isOpen}>
|
||||
<p className="text-gray-700 text-sm leading-relaxed">
|
||||
{faq.answer}
|
||||
</p>
|
||||
</Expandable>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* RIGHT COLUMN */}
|
||||
<div className="flex flex-col gap-6">
|
||||
{rightFaqs.map((faq, index) => {
|
||||
const isOpen = openIndexRight === index;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-white rounded-xl p-5 shadow-sm transition-all duration-300"
|
||||
>
|
||||
<button
|
||||
onClick={() =>
|
||||
setOpenIndexRight(isOpen ? null : index)
|
||||
}
|
||||
className="w-full flex justify-between items-center text-left"
|
||||
>
|
||||
<span
|
||||
className={`font-medium ${
|
||||
isOpen ? "text-yellow-800" : "text-gray-900"
|
||||
}`}
|
||||
>
|
||||
{faq.question}
|
||||
</span>
|
||||
|
||||
{isOpen ? (
|
||||
<ChevronUp size={22} className="text-yellow-700" />
|
||||
) : (
|
||||
<ChevronDown size={22} className="text-gray-600" />
|
||||
)}
|
||||
</button>
|
||||
|
||||
<Expandable isOpen={isOpen}>
|
||||
<p className="text-gray-700 text-sm leading-relaxed">
|
||||
{faq.answer}
|
||||
</p>
|
||||
</Expandable>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Faq;
|
||||
|
||||
export default Faq;
|
||||
@ -8,6 +8,7 @@ const PublicContactForm = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
userType: "establishment_user",
|
||||
establishmentName: "",
|
||||
establishmentId: "",
|
||||
email: "",
|
||||
@ -74,7 +75,13 @@ const PublicContactForm = () => {
|
||||
const validate = (data = formData) => {
|
||||
const newErrors = {};
|
||||
|
||||
if (!data.establishmentName.trim()) newErrors.establishmentName = "Required.";
|
||||
if (!data.userType) {
|
||||
newErrors.userType = "Please select user type";
|
||||
} else if (data.userType === 'establishment_user') {
|
||||
if (!data.establishmentName.trim()) newErrors.establishmentName = "Required.";
|
||||
if (!data.establishmentId.trim()) newErrors.establishmentId = "Required.";
|
||||
}
|
||||
|
||||
if (!data.email.trim()) newErrors.email = "Required.";
|
||||
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email))
|
||||
newErrors.email = "Enter a valid email address.";
|
||||
@ -113,6 +120,7 @@ const PublicContactForm = () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const payload = {
|
||||
user_type: formData.userType,
|
||||
establishment_name: formData.establishmentName.trim(),
|
||||
establishment_code: formData.establishmentId.trim(),
|
||||
registered_email: formData.email.trim(),
|
||||
@ -124,7 +132,10 @@ const PublicContactForm = () => {
|
||||
showToast('success', 'Verification Code sent to your registered email successfully!');
|
||||
setTimeout(() => {
|
||||
navigate("/change-password", {
|
||||
state: { email: formData.email.trim() },
|
||||
state: {
|
||||
email: formData.email.trim(),
|
||||
user_type: formData.userType
|
||||
},
|
||||
});
|
||||
}, 1500);
|
||||
} else {
|
||||
@ -156,13 +167,19 @@ const PublicContactForm = () => {
|
||||
const payload = {
|
||||
registered_email: formData.email.trim(),
|
||||
otp: otp.trim(),
|
||||
user_type: formData.userType // Add user_type to the verification request
|
||||
};
|
||||
|
||||
const response = await apiClient.post("/forgot-password/verify-otp", payload);
|
||||
|
||||
if (response?.data?.status === "success") {
|
||||
setSuccess("Verification Code verified successfully. Redirecting to change password...");
|
||||
setTimeout(() => navigate("/change-password"), 1500);
|
||||
setTimeout(() => navigate("/change-password", {
|
||||
state: {
|
||||
email: formData.email.trim(),
|
||||
user_type: formData.userType // Ensure user_type is passed
|
||||
}
|
||||
}), 1500);
|
||||
} else {
|
||||
const serverMsg = response?.data?.message?.toLowerCase() || "";
|
||||
|
||||
@ -240,27 +257,74 @@ const PublicContactForm = () => {
|
||||
{errorMsg}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
User Type <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<select
|
||||
name="userType"
|
||||
value={formData.userType}
|
||||
onChange={handleChange}
|
||||
className={`w-full px-3 py-2 border ${
|
||||
errors.userType ? 'border-red-300' : 'border-gray-300'
|
||||
} rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-[#92722A] focus:border-[#92722A]`}
|
||||
>
|
||||
<option value="establishment_user">Establishment</option>
|
||||
<option value="admin_user">Admin</option>
|
||||
</select>
|
||||
{errors.userType && (
|
||||
<p className="mt-1 text-sm text-red-600">{errors.userType}</p>
|
||||
)}
|
||||
</div>
|
||||
{success && (
|
||||
<div className="text-sm text-green-700 bg-green-50 border border-green-200 rounded px-3 py-2">
|
||||
{success}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<InputField
|
||||
label="Establishment Name"
|
||||
name="establishmentName"
|
||||
required
|
||||
value={formData.establishmentName}
|
||||
onChange={handleChange}
|
||||
error={errors.establishmentName}
|
||||
/>
|
||||
<InputField
|
||||
label="Establishment ID"
|
||||
name="establishmentId"
|
||||
required
|
||||
value={formData.establishmentId}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
{formData.userType === 'establishment_user' && (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Establishment Name <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="establishmentName"
|
||||
value={formData.establishmentName}
|
||||
onChange={handleChange}
|
||||
className={`block w-full h-10 rounded-md border-2 ${
|
||||
errors.establishmentName ? "border-red-500" : "border-[#92722A]"
|
||||
} focus:border-[#92722A] focus:ring-0 px-4 text-sm`}
|
||||
placeholder="Enter establishment name"
|
||||
/>
|
||||
{errors.establishmentName && (
|
||||
<p className="text-xs text-red-600 mt-1">{errors.establishmentName}</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Establishment ID <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="establishmentId"
|
||||
value={formData.establishmentId}
|
||||
onChange={handleChange}
|
||||
className={`block w-full h-10 rounded-md border-2 ${
|
||||
errors.establishmentId ? "border-red-500" : "border-[#92722A]"
|
||||
} focus:border-[#92722A] focus:ring-0 px-4 text-sm`}
|
||||
placeholder="Enter establishment ID"
|
||||
/>
|
||||
{errors.establishmentId && (
|
||||
<p className="text-xs text-red-600 mt-1">{errors.establishmentId}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<InputField
|
||||
label="Registered Email"
|
||||
name="email"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user