Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"file-saver": "^2.0.5",
"jspdf": "^3.0.3",
"jspdf-autotable": "^5.0.2",
"lucide-react": "^0.545.0",
"react": "^19.1.0",
"react-chartjs-2": "^5.3.0",
"react-dom": "^19.1.0",
Expand Down
Binary file added src/assets/img/TaskSphereLogo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
233 changes: 112 additions & 121 deletions src/components/Signin.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// src/components/Signin.jsx
import React, { useState, useEffect } from "react";
import { useNavigate, useLocation, useOutletContext } from "react-router-dom";
import Swal from "sweetalert2";
import "../components/Style/Style.css";
import Logo1 from "../assets/img/Dct-Logo.png";
import Logo2 from "../assets/img/Costum.png";
import Logo1 from "../assets/img/TaskSphereLogo.png";
import Logo2 from "../assets/img/Dct-Logo.png";
import { supabase } from "../supabaseClient";
import { UserAuth } from "../Contex/AuthContext";
import SigninHead from "./heade-foot/SigninHead";
Expand All @@ -20,13 +18,21 @@ const Signin = () => {
const { setIsLoggedIn } = useOutletContext();
const { login } = UserAuth();

// =====================================================
// 🚫 Route Guard (Trap user inside /Signin)
// =====================================================
// Hard lock page scroll (belt-and-suspenders)
useEffect(() => {
const storedUser = localStorage.getItem("customUser");
const prevDoc = document.documentElement.style.overflow;
const prevBody = document.body.style.overflow;
document.documentElement.style.overflow = "hidden";
document.body.style.overflow = "hidden";
return () => {
document.documentElement.style.overflow = prevDoc;
document.body.style.overflow = prevBody;
};
}, []);

// 🔹 If user is logged in, redirect to their dashboard
// Route guard
useEffect(() => {
const storedUser = localStorage.getItem("customUser");
if (storedUser) {
const user = JSON.parse(storedUser);
const roleRoutes = {
Expand All @@ -37,27 +43,16 @@ const Signin = () => {
};
navigate(roleRoutes[user.user_roles] || "/Signin", { replace: true });
} else {
// 🔹 If user is not logged in, trap them inside /Signin
const allowedPaths = ["/", "/Signin", "/signin"];
if (!allowedPaths.includes(location.pathname)) {
navigate("/Signin", { replace: true });
}

// Disable back/forward navigation
const allowed = ["/", "/Signin", "/signin"];
if (!allowed.includes(location.pathname)) navigate("/Signin", { replace: true });
window.history.pushState(null, "", window.location.href);
window.onpopstate = () => {
window.history.pushState(null, "", window.location.href);
};
window.onpopstate = () => window.history.pushState(null, "", window.location.href);
}
}, [location, navigate]);

// =====================================================
// 🔹 Handle Sign In
// =====================================================
const handleSignIn = async (e) => {
e.preventDefault();
setLoading(true);

try {
const { data: user, error } = await supabase
.from("user_credentials")
Expand All @@ -67,27 +62,15 @@ const Signin = () => {
.single();

if (error || !user) {
Swal.fire({
icon: "error",
title: "Login failed",
text: "Invalid credentials. Please try again.",
});
Swal.fire({ icon: "error", title: "Login failed", text: "Invalid credentials. Please try again." });
return;
}

// ✅ Save to context + localStorage
login(user);
localStorage.setItem("customUser", JSON.stringify(user));
localStorage.setItem("user_id", user.user_id);
setIsLoggedIn(true);

console.log("✅ User signed in:", {
user_id: user.user_id,
uuid: user.id,
role: user.user_roles,
});

// 🔹 Role-based navigation
const roleRoutes = {
1: { path: "/Manager", label: "Manager" },
2: { path: "/Member", label: "Member" },
Expand All @@ -106,107 +89,115 @@ const Signin = () => {
});
navigate(target.path);
} else {
Swal.fire({
icon: "warning",
title: "Unknown role",
text: "Please contact the administrator.",
});
Swal.fire({ icon: "warning", title: "Unknown role", text: "Please contact the administrator." });
}
} catch (err) {
Swal.fire({
icon: "error",
title: "Server Error",
text: "Something went wrong. Please try again later.",
});
Swal.fire({ icon: "error", title: "Server Error", text: "Something went wrong. Please try again later." });
console.error("❌ SignIn Error:", err.message);
} finally {
setLoading(false);
}
};

useEffect(() => {
const storedUser = localStorage.getItem("customUser");
if (storedUser) {
const user = JSON.parse(storedUser);
const roleRoutes = {
1: "/Manager/Dashboard",
2: "/Member/Dashboard",
3: "/Adviser/Dashboard",
4: "/Instructor/Dashboard",
};
navigate(roleRoutes[user.user_roles] || "/Signin", { replace: true });
}
}, []);
const storedUser = localStorage.getItem("customUser");
if (storedUser) {
const user = JSON.parse(storedUser);
const roleRoutes = {
1: "/Manager/Dashboard",
2: "/Member/Dashboard",
3: "/Adviser/Dashboard",
4: "/Instructor/Dashboard",
};
navigate(roleRoutes[user.user_roles] || "/Signin", { replace: true });
}
}, [navigate]);

// =====================================================
// 🔹 UI
// =====================================================
return (
<div className="w-full min-h-screen bg-gray-100 flex flex-col">
// Lock the page height; no scroll
<div className="h-screen w-full bg-neutral-100 flex flex-col overflow-hidden">
<SigninHead />

<div className="flex flex-col md:flex-row w-full max-w-6xl mx-auto h-full border rounded-lg py-5 px-3 main-bg-color flex-grow">
<div className="w-full md:w-1/2 p-6 flex items-center justify-center b-rd bg-white">
<form onSubmit={handleSignIn} className="w-full max-w-md text-center">
<h2 className="text-2xl font-bold mb-4">Welcome to TaskSphere IT</h2>
<img src={Logo1} alt="Logo" className="mx-auto mb-6 w-24 h-24" />
<div className="mb-4 text-left">
<label htmlFor="userID" className="block font-medium mb-1">
ID Number
</label>
<input
onChange={(e) => setUserID(e.target.value)}
value={userID}
className="w-full p-3 border rounded"
type="text"
id="userID"
placeholder="Enter your ID number"
required
/>
</div>

<div className="mb-2 text-left">
<label htmlFor="password" className="block font-medium mb-1">
Password
</label>
<input
onChange={(e) => setPassword(e.target.value)}
value={password}
className="w-full p-3 border rounded"
type="password"
id="password"
placeholder="Enter your password"
required
/>
<div className="text-right mt-1">
<button
type="button"
onClick={() => navigate("/ForgotPassword")}
className="text-sm text-blue-600 hover:text-blue-800 font-medium"
>
Forgot Password?
</button>
{/* Main fills remaining height; internal overflow hidden */}
<main className="flex-1 bg-white flex flex-col overflow-hidden">
<div className="flex-1 overflow-hidden">
<div className="mx-auto h-full w-full max-w-[1200px] px-6 md:px-8 grid grid-cols-1 md:grid-cols-2 gap-10 items-center">
{/* Left: taller login card */}
<div className="flex justify-start">
<div className="w-full max-w-[440px] rounded-xl border border-neutral-200 bg-white p-8 shadow-sm min-h-[640px]">
<h2 className="text-center text-[32px] md:text-[34px] font-extrabold leading-8 text-[#611A11]">
Welcome to
<br />
<span className="text-[32px] md:text-[34px] font-extrabold">TaskSphere IT</span>
</h2>

<img
src={Logo1}
alt="TaskSphere icon"
className="mx-auto mt-5 h-[150px] w-[150px] object-contain"
/>

<form onSubmit={handleSignIn} className="mt-8 space-y-6">
<div>
<label htmlFor="userID" className="mb-1 block text-sm font-semibold text-neutral-700">
Username
</label>
<input
id="userID"
type="text"
value={userID}
onChange={(e) => setUserID(e.target.value)}
className="w-full rounded-md border border-neutral-300 bg-white px-3 py-2 text-sm text-black outline-none focus:border-[#611A11] focus:ring-1 focus:ring-[#611A11]"
required
/>
</div>

<div>
<label htmlFor="password" className="mb-1 block text-sm font-semibold text-neutral-700">
Password
</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full rounded-md border border-neutral-300 bg-white px-3 py-2 text-sm text-black outline-none focus:border-[#611A11] focus:ring-1 focus:ring-[#611A11]"
required
/>
<div className="mt-1 text-right">
<button
type="button"
onClick={() => navigate("/ForgotPassword")}
className="text-[11px] font-medium text-black hover:underline focus:outline-none bg-transparent p-0 m-0"
>
Forgot Password
</button>
</div>
</div>

<button
type="submit"
disabled={loading}
className="mt-2 w-full rounded-full bg-[#611A11] py-2 text-sm font-semibold text-white shadow hover:opacity-95 active:opacity-90 disabled:opacity-60"
>
{loading ? "Signing in..." : "Sign In"}
</button>
</form>
</div>
</div>

<button
type="submit"
disabled={loading}
className="w-full bg-blue-600 text-white py-2 rounded main-bg-color"
>
{loading ? "Signing in..." : "Sign In"}
</button>
</form>
</div>

<div className="w-full md:w-1/2 flex flex-col items-center justify-center main-bg-color text-white rounded-lg p-8 space-y-6">
<h1 className="text-3xl font-semibold text-center">
Empowering Collaboration,
<br />
Streamlining IT Capstone Success.
</h1>
<img src={Logo2} alt="Team" className="w-80 h-auto rounded-lg shadow-md" />
{/* Right: seal + headline */}
<div className="flex flex-col items-center justify-center text-center">
<img src={Logo2} alt="CCS Seal" className="h-32 w-32 md:h-36 md:w-36 object-contain" />
<p className="mt-6 text-[30px] md:text-[34px] font-semibold leading-tight text-neutral-800">
A Task Management System for
<br />
Capstone Project Development
</p>
</div>
</div>
</div>
</div>
</main>

<SigninFoot />
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/components/Style/Style.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@
}
.b-rd {
border-radius: 8px;
}
}

Loading