Added working-day-only calculation, Fixed leave logic so balance is deducted only on approval and pending requests are considered to prevent over-application.

Ensured consistent day calculation using stored days field and removed duplicate daysBetween logic.
Implemented working-day-only calculation, excluding weekends (Saturday & Sunday), and blocked invalid date selections.
Corrected handling of Unpaid leave so it does not affect leave balance.
Added routing and integrated Sonner notifications for login, manager actions, and employee leave submission.
This commit is contained in:
sumona-banerjeee committed 2026-04-29 19:14:58 +05:30
1 parent 45444ba8bd
commit 96cc1bb684
9 files changed
+265 -183

No files matched your search

+3 -1
View File
@@ -3,11 +3,12 @@ import "./globals.css";
import { AuthProvider } from "@/context/AuthContext";
import { Geist } from "next/font/google";
import { cn } from "@/lib/utils";
import { Toaster } from "@/components/ui/sonner";
const geist = Geist({subsets:['latin'],variable:'--font-sans'});
export const metadata: Metadata = {
title: "LeaveFlow – Leave Management",
title: "LeaveFlow - Leave Management",
description: "Streamlined leave management for teams",
};
@@ -24,6 +25,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
</head>
<body>
<AuthProvider>{children}</AuthProvider>
<Toaster richColors position="top-right" />
</body>
</html>
);
+6 -3
View File
@@ -15,6 +15,7 @@ import {
LayoutDashboard,
} from "lucide-react";
import { ROUTES } from "@/lib/routes";
import { toast } from "sonner";
type FilterStatus = "All" | "Pending" | "Approved" | "Rejected";
@@ -33,25 +34,27 @@ export default function ManagerPage() {
}, []);
useEffect(() => {
// if (!isLoading && !user) router.replace("/");
// else if (!isLoading && user?.role === "employee") router.replace("/employee");
if (!isLoading && !user) router.replace(ROUTES.home);
else if (!isLoading && user?.role === "employee") router.replace(ROUTES.employee);
else if (!isLoading && user) loadData();
}, [user, isLoading, router, loadData]);
const handleApprove = async (id: number) => {
const leave = leaves.find((l) => l.id === id);
setLoadingId(id);
await updateLeaveStatus(id, "Approved");
await loadData();
setLoadingId(null);
toast.success(`Leave approved for ${leave?.userName ?? "employee"}`);
};
const handleReject = async (id: number) => {
const leave = leaves.find((l) => l.id === id);
setLoadingId(id);
await updateLeaveStatus(id, "Rejected");
await loadData();
setLoadingId(null);
toast.error(`Leave rejected for ${leave?.userName ?? "employee"}`);
};
if (isLoading || !user || !dataLoaded) {
@@ -147,4 +150,4 @@ export default function ManagerPage() {
</main>
</div>
);
}
}
+4 -17
View File
@@ -7,21 +7,19 @@ import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { CalendarDays, AlertCircle, Loader2 } from "lucide-react";
import { CalendarDays, Loader2 } from "lucide-react";
import { ROUTES } from "@/lib/routes";
import { toast } from "sonner";
export default function LoginPage() {
const { login, user, isLoading } = useAuth();
const router = useRouter();
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
useEffect(() => {
if (!isLoading && user) {
// router.replace(user.role === "manager" ? "/manager" : "/employee");
router.replace(user.role === "manager" ? ROUTES.manager : ROUTES.employee);
}
}, [user, isLoading, router]);
@@ -29,17 +27,14 @@ export default function LoginPage() {
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!username || !password) {
setError("Please enter username and password");
toast.error("Please enter username and password");
return;
}
setLoading(true);
setError("");
const result = await login(username, password);
setLoading(false);
if (!result.ok) {
setError(result.error ?? "Login failed");
} else if (result.ok) {
// redirect handled by useEffect
toast.error(result.error ?? "Login failed");
}
};
@@ -77,7 +72,6 @@ export default function LoginPage() {
<h1 className="text-2xl font-bold tracking-tight" style={{ color: "var(--text-primary)" }}>
LeaveFlow
</h1>
</div>
<Card
@@ -123,13 +117,6 @@ export default function LoginPage() {
/>
</div>
{error && (
<Alert style={{ borderColor: "var(--color-danger-border)", background: "var(--color-danger-bg)", borderRadius: "var(--radius-sm)" }}>
<AlertCircle className="h-4 w-4" style={{ color: "var(--color-danger)" }} />
<AlertDescription style={{ color: "var(--color-danger)" }}>{error}</AlertDescription>
</Alert>
)}
<Button
type="submit"
className="w-full font-semibold"