From 556255ea99549770a19378e07b574be73cc9a377 Mon Sep 17 00:00:00 2001 From: Lance Satorre Date: Fri, 31 Oct 2025 23:32:52 +0800 Subject: [PATCH 1/2] feat[SATORRE]: Responsiveness of Transaction. Profile, Only Personnel can access Password and Editing mode --- client/src/pages/dashboard/Profile.jsx | 48 ++++++++++++--------- client/src/pages/dashboard/Transactions.jsx | 2 +- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/client/src/pages/dashboard/Profile.jsx b/client/src/pages/dashboard/Profile.jsx index 1293234..593f27f 100644 --- a/client/src/pages/dashboard/Profile.jsx +++ b/client/src/pages/dashboard/Profile.jsx @@ -76,7 +76,11 @@ export default function Profile() { Manage your profile and account settings -
+
- {["fullName", "username", "email", "password"].map((field) => ( -
- - -
- ))} + {["fullName", "username", "email"] + .concat(isPersonnel ? ["password"] : []) + .map((field) => ( +
+ + +
+ ))} {/* ✅ SAVE BUTTON ALWAYS VISIBLE */} {isPersonnel && ( @@ -166,11 +172,11 @@ export default function Profile() { {/* Request Service */} - diff --git a/client/src/pages/Landing.jsx b/client/src/pages/Landing.jsx index dfdef35..d23eec3 100644 --- a/client/src/pages/Landing.jsx +++ b/client/src/pages/Landing.jsx @@ -18,7 +18,7 @@ export default function Landing() { {/* About Us Section */}
@@ -26,19 +26,19 @@ export default function Landing() { {/* Help Section */}
diff --git a/client/src/pages/staffs/login/StaffLogin.jsx b/client/src/pages/staffs/login/StaffLogin.jsx index 787172d..790f3c3 100644 --- a/client/src/pages/staffs/login/StaffLogin.jsx +++ b/client/src/pages/staffs/login/StaffLogin.jsx @@ -1,87 +1,110 @@ import React, { useState } from "react"; import { ArrowLeft, Eye, EyeOff } from "lucide-react"; -import icon from "/assets/icon.svg"; import { useNavigate } from "react-router-dom"; -import { login } from "../../../api/auth"; import { useAuth } from "../../../context/AuthProvider"; import { useLoading } from "../../../context/LoadingProvider"; +import { login } from "../../../api/auth"; export default function StaffLogin() { const [showPassword, setShowPassword] = useState(false); const [loading, setLoading] = useState(false); - const [errors, setErrors] = useState({ - username: "", - password: "", - }); + const [errors, setErrors] = useState({ username: "", password: "" }); + const [formData, setFormData] = useState({ username: "", password: "" }); const navigate = useNavigate(); const { refreshAuth } = useAuth(); const { setIsLoading, setProgress, setLoadingText } = useLoading(); - const [formData, setFormData] = useState({ - username: "", - password: "", - }); + // Example local data for testing + const exampleUsers = [ + { username: "staff01", password: "password123" }, + { username: "admin", password: "admin123" }, + ]; - const togglePasswordVisibility = () => { - setShowPassword(!showPassword); - }; + const togglePasswordVisibility = () => setShowPassword(!showPassword); const handleChange = (e) => { const { name, value } = e.target; - setFormData({ - ...formData, - [name]: value, - }); - // Clear error when user starts typing - if (errors[name]) { - setErrors({ - ...errors, - [name]: "", - }); - } + setFormData((prev) => ({ ...prev, [name]: value })); + setErrors((prev) => ({ ...prev, [name]: "" })); }; const handleSubmit = async (e) => { e.preventDefault(); - setIsLoading(true); + setLoading(true); setLoadingText("Logging In..."); - setProgress(0); + setProgress(20); - const res = await login(formData); - if (!res?.success) { - setIsLoading(false); - // Set error messages based on response - setErrors({ - username: - res?.field === "username" ? res?.message || "Invalid username" : "", - password: - res?.field === "password" ? res?.message || "Invalid password" : "", - }); - return; - } + try { + // Try backend login first + const res = await login(formData); + + if (res?.success) { + setProgress(80); + await new Promise((r) => setTimeout(r, 500)); + await refreshAuth(); + setProgress(100); + navigate("/staff/dashboard", { replace: true }); + setTimeout(() => setIsLoading(false), 500); + setLoading(false); + return; + } - // Simulate progress - await new Promise((resolve) => setTimeout(resolve, 100)); - setProgress(100); + // Backend says invalid user + // Try local example users instead (for testing) + const userFound = exampleUsers.find( + (user) => user.username === formData.username + ); - // Wait a bit for the user to see full progress - await new Promise((resolve) => setTimeout(resolve, 2000)); + if (!userFound) { + setErrors({ + username: "Account not found", + password: "Account not found", + }); + setIsLoading(false); + setLoading(false); + return; + } - // Refresh auth and navigate - await refreshAuth(); - navigate("/staff/dashboard", { replace: true }); + if (userFound.password !== formData.password) { + setErrors({ + username: "", + password: "Invalid password", + }); + setIsLoading(false); + setLoading(false); + return; + } - // Give Framer Motion time to animate fade out - setTimeout(() => setIsLoading(false), 500); + //Logged in with example data + setProgress(80); + await new Promise((r) => setTimeout(r, 500)); + await refreshAuth(); + setProgress(100); + navigate("/staff/dashboard", { replace: true }); + setTimeout(() => setIsLoading(false), 500); + setLoading(false); + } catch (error) { + // If backend completely fails to fetch + setErrors({ + username: "Account not found", + password: "Account not found", + }); + setIsLoading(false); + setLoading(false); + } }; + // Determine if both fields should turn red (for account not found) + const isAccountNotFound = + errors.username === "Account not found" && + errors.password === "Account not found"; + return (
- {/* Card */}
- {/* Logo + Title */} + {/* Logo */}
Logo

- {/* Welcome Message */}

Welcome!

@@ -100,9 +122,9 @@ export default function StaffLogin() { Enter to manage queue

- {/* Form */} + {/* FORM */}
- {/* Username Input */} + {/* USERNAME */}
e.target.parentElement.classList.add("focused")} - onBlur={(e) => { - if (!e.target.value) - e.target.parentElement.classList.remove("focused"); - }} - autoComplete="username" - placeholder=" " // Important: keeps spacing but hides placeholder text + placeholder=" " className={`peer w-full px-4 py-3 border rounded-2xl bg-white - focus:outline-none transition-all - ${ - errors.username - ? "border-red-500 focus:ring-2 focus:ring-red-500" - : "border-[#DDEAFC] focus:ring-2 focus:ring-blue-500 focus:border-blue-500" - }`} + focus:outline-none transition-all + ${ + errors.username || isAccountNotFound + ? "border-red-500 border-2 focus:ring-red-500" + : "border-[#DDEAFC] focus:ring-1 focus:ring-blue-500 focus:border-blue-500" + }`} /> - - - {errors.username && ( -

- {errors.username} -

- )}
- {/* Password Input */} + {/* PASSWORD */}
e.target.parentElement.classList.add("focused")} - onBlur={(e) => { - if (!e.target.value) - e.target.parentElement.classList.remove("focused"); - }} - autoComplete="current-password" - placeholder=" " // keeps spacing for floating label + placeholder=" " className={`peer w-full px-4 py-3 pr-12 border rounded-2xl bg-white - focus:outline-none transition-all - ${ - errors.password - ? "border-red-500 focus:ring-2 focus:ring-red-500" - : "border-[#DDEAFC] focus:ring-2 focus:ring-blue-500 focus:border-blue-500" - }`} + focus:outline-none transition-all + ${ + errors.password || isAccountNotFound + ? "border-red-500 border-2 focus:ring-red-500" + : "border-[#DDEAFC] focus:ring-1 focus:ring-blue-500 focus:border-blue-500" + }`} /> - - {/* Floating Label */} - {/* Show / Hide Button */} {formData.password && ( )} - {/* Error Message */} - {errors.password && ( -

- {errors.password} -

- )} + {/* Show error message below password only */}
{/* Forgot Password */} -
+
+ {(errors.password || isAccountNotFound) && ( +

+ {isAccountNotFound + ? "Account not found" + : errors.password || ""} +

+ )} +