client side bug fixed
This commit is contained in:
parent
9b015fe922
commit
2aa572ad1f
@ -59,7 +59,12 @@ const ChangePassword = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
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 [otp, setOtp] = React.useState("");
|
||||||
const [newPassword, setNewPassword] = React.useState("");
|
const [newPassword, setNewPassword] = React.useState("");
|
||||||
@ -132,6 +137,7 @@ if (newPassword !== confirmPassword) {
|
|||||||
otp: otp.trim(),
|
otp: otp.trim(),
|
||||||
password: newPassword,
|
password: newPassword,
|
||||||
confirm_password: confirmPassword,
|
confirm_password: confirmPassword,
|
||||||
|
user_type: userType // Use the user_type from location state
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await apiClient.post("/forgot-password/verify-otp", payload);
|
const response = await apiClient.post("/forgot-password/verify-otp", payload);
|
||||||
@ -197,6 +203,21 @@ if (newPassword !== confirmPassword) {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</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
|
<ToggleableInput
|
||||||
label="Verification Code"
|
label="Verification Code"
|
||||||
required
|
required
|
||||||
|
|||||||
@ -1,50 +1,76 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useRef, useEffect } from "react";
|
||||||
import { ChevronDown, ChevronUp } from "lucide-react"; // ✅ Up/Down icons
|
import { ChevronDown, ChevronUp } from "lucide-react";
|
||||||
|
|
||||||
const Faq = () => {
|
const Faq = () => {
|
||||||
const [openIndex, setOpenIndex] = useState(null);
|
const [openIndexLeft, setOpenIndexLeft] = useState(null);
|
||||||
|
const [openIndexRight, setOpenIndexRight] = useState(null);
|
||||||
|
|
||||||
const faqs = [
|
// FULL FAQ DATA
|
||||||
|
const leftFaqs = [
|
||||||
{
|
{
|
||||||
question: "Do I need an account to respond?",
|
question: "Do I need an account to respond?",
|
||||||
answer:
|
answer:
|
||||||
"Yes. FCSC provisions accounts to selected establishments. Use Login to access the survey.",
|
"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?",
|
question: "Is my data public?",
|
||||||
answer: "No. Results are published only in aggregate form.",
|
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?",
|
question: "Can I update after submission?",
|
||||||
answer:
|
answer:
|
||||||
"Yes, if a revision window is open or if FCSC requests a correction.",
|
"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?",
|
question: "How long does it take?",
|
||||||
answer:
|
answer:
|
||||||
"Most respondents complete within minutes each quarter, depending on product lines.",
|
"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?",
|
question: "Who can I contact?",
|
||||||
answer: "See Need help below.",
|
answer: "See Need help below.",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const toggleFaq = (index) => {
|
// Auto height expand component
|
||||||
setOpenIndex(openIndex === index ? null : index);
|
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 (
|
return (
|
||||||
@ -53,42 +79,91 @@ const Faq = () => {
|
|||||||
Frequently asked questions
|
Frequently asked questions
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div className="grid md:grid-cols-2 gap-6">
|
{/* TWO FULLY INDEPENDENT COLUMNS */}
|
||||||
{faqs.map((faq, index) => {
|
<div className="grid md:grid-cols-2 gap-10">
|
||||||
const isOpen = openIndex === index;
|
|
||||||
return (
|
{/* LEFT COLUMN */}
|
||||||
<div
|
<div className="flex flex-col gap-6">
|
||||||
key={index}
|
{leftFaqs.map((faq, index) => {
|
||||||
className={`border rounded-xl p-5 shadow-sm transition-all duration-300 bg-white ${
|
const isOpen = openIndexLeft === index;
|
||||||
isOpen ? "border-gray-200" : "border-gray-200"
|
|
||||||
}`}
|
return (
|
||||||
>
|
<div
|
||||||
<button
|
key={index}
|
||||||
onClick={() => toggleFaq(index)}
|
className="bg-white rounded-xl p-5 shadow-sm transition-all duration-300"
|
||||||
className="w-full flex justify-between items-center text-left"
|
>
|
||||||
>
|
<button
|
||||||
<span
|
onClick={() =>
|
||||||
className={`font-medium ${
|
setOpenIndexLeft(isOpen ? null : index)
|
||||||
isOpen ? "text-yellow-800" : "text-gray-900"
|
}
|
||||||
}`}
|
className="w-full flex justify-between items-center text-left"
|
||||||
>
|
>
|
||||||
{faq.question}
|
<span
|
||||||
</span>
|
className={`font-medium ${
|
||||||
{isOpen ? (
|
isOpen ? "text-yellow-800" : "text-gray-900"
|
||||||
<ChevronUp size={22} className="text-yellow-700" /> // ⬆️ when open
|
}`}
|
||||||
) : (
|
>
|
||||||
<ChevronDown size={22} className="text-gray-600" /> // ⬇️ when closed
|
{faq.question}
|
||||||
)}
|
</span>
|
||||||
</button>
|
|
||||||
|
{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>
|
||||||
|
|
||||||
{isOpen && (
|
|
||||||
<p className="mt-3 text-gray-700 text-sm leading-relaxed">
|
|
||||||
{faq.answer}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -8,6 +8,7 @@ const PublicContactForm = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
|
userType: "establishment_user",
|
||||||
establishmentName: "",
|
establishmentName: "",
|
||||||
establishmentId: "",
|
establishmentId: "",
|
||||||
email: "",
|
email: "",
|
||||||
@ -74,7 +75,13 @@ const PublicContactForm = () => {
|
|||||||
const validate = (data = formData) => {
|
const validate = (data = formData) => {
|
||||||
const newErrors = {};
|
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.";
|
if (!data.email.trim()) newErrors.email = "Required.";
|
||||||
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email))
|
else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email))
|
||||||
newErrors.email = "Enter a valid email address.";
|
newErrors.email = "Enter a valid email address.";
|
||||||
@ -113,6 +120,7 @@ const PublicContactForm = () => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const payload = {
|
const payload = {
|
||||||
|
user_type: formData.userType,
|
||||||
establishment_name: formData.establishmentName.trim(),
|
establishment_name: formData.establishmentName.trim(),
|
||||||
establishment_code: formData.establishmentId.trim(),
|
establishment_code: formData.establishmentId.trim(),
|
||||||
registered_email: formData.email.trim(),
|
registered_email: formData.email.trim(),
|
||||||
@ -124,7 +132,10 @@ const PublicContactForm = () => {
|
|||||||
showToast('success', 'Verification Code sent to your registered email successfully!');
|
showToast('success', 'Verification Code sent to your registered email successfully!');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
navigate("/change-password", {
|
navigate("/change-password", {
|
||||||
state: { email: formData.email.trim() },
|
state: {
|
||||||
|
email: formData.email.trim(),
|
||||||
|
user_type: formData.userType
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}, 1500);
|
}, 1500);
|
||||||
} else {
|
} else {
|
||||||
@ -156,13 +167,19 @@ const PublicContactForm = () => {
|
|||||||
const payload = {
|
const payload = {
|
||||||
registered_email: formData.email.trim(),
|
registered_email: formData.email.trim(),
|
||||||
otp: otp.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);
|
const response = await apiClient.post("/forgot-password/verify-otp", payload);
|
||||||
|
|
||||||
if (response?.data?.status === "success") {
|
if (response?.data?.status === "success") {
|
||||||
setSuccess("Verification Code verified successfully. Redirecting to change password...");
|
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 {
|
} else {
|
||||||
const serverMsg = response?.data?.message?.toLowerCase() || "";
|
const serverMsg = response?.data?.message?.toLowerCase() || "";
|
||||||
|
|
||||||
@ -240,27 +257,74 @@ const PublicContactForm = () => {
|
|||||||
{errorMsg}
|
{errorMsg}
|
||||||
</div>
|
</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 && (
|
{success && (
|
||||||
<div className="text-sm text-green-700 bg-green-50 border border-green-200 rounded px-3 py-2">
|
<div className="text-sm text-green-700 bg-green-50 border border-green-200 rounded px-3 py-2">
|
||||||
{success}
|
{success}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<InputField
|
{formData.userType === 'establishment_user' && (
|
||||||
label="Establishment Name"
|
<div className="space-y-4">
|
||||||
name="establishmentName"
|
<div>
|
||||||
required
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
value={formData.establishmentName}
|
Establishment Name <span className="text-red-500">*</span>
|
||||||
onChange={handleChange}
|
</label>
|
||||||
error={errors.establishmentName}
|
<input
|
||||||
/>
|
type="text"
|
||||||
<InputField
|
name="establishmentName"
|
||||||
label="Establishment ID"
|
value={formData.establishmentName}
|
||||||
name="establishmentId"
|
onChange={handleChange}
|
||||||
required
|
className={`block w-full h-10 rounded-md border-2 ${
|
||||||
value={formData.establishmentId}
|
errors.establishmentName ? "border-red-500" : "border-[#92722A]"
|
||||||
onChange={handleChange}
|
} 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
|
<InputField
|
||||||
label="Registered Email"
|
label="Registered Email"
|
||||||
name="email"
|
name="email"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user