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
37 changes: 37 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 @@ -13,6 +13,7 @@
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-checkbox": "^1.3.2",
"@radix-ui/react-collapsible": "^1.1.11",
"@radix-ui/react-dialog": "^1.1.14",
"@radix-ui/react-dropdown-menu": "^2.1.15",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-select": "^2.2.5",
Expand Down
6 changes: 6 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,9 @@ body {
@apply bg-background text-foreground;
}
}

@layer utilities {
.bg-special {
@apply bg-gradient-to-br from-blue-200 via-purple-200 to-pink-200;
}
}
96 changes: 96 additions & 0 deletions src/components/academic-courses-tab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { Button } from "./ui/button";
import { Edit, Plus } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent } from "./ui/card";
import { useCoursesData } from "@/store/hooks/academics/use-courses-data";
import { FormateDate } from "@/lib/utils";

interface CourseData {
coursename: string;
professorname: string;
department: string;
status: string;
startdate: string;
enddate: string;
}

const AcademinCoursesTab = () => {
const { coursesInfo, error, loading } = useCoursesData();

if (loading) return <div>Loading courses data...</div>;
if (error) return <div>Error loading courses data.</div>;

const courseData: CourseData[] = coursesInfo?.courses;
return (
<div className="space-y-4">
<div className="flex justify-between items-center">
<h3 className="text-lg font-medium">Semester Management</h3>
<Button className="gap-2">
<Plus className="w-4 h-4" />
Add new
</Button>
</div>
<div className="space-y-3">
{courseData?.map((course, index) => (
<Card key={index}>
<CardContent>
<div
key={index}
className="flex flex-col md:flex-row flex-wrap gap-2.5 w-full justify-between"
>
<div>
<div className="flex items-center gap-3">
<h4 className="font-medium">{course.coursename}</h4>
<Badge
variant={
course.status === "scheduled"
? "default"
: course.status === "Planning"
? "secondary"
: course.status === "cancled"
? "destructive"
: "outline"
}
>
{course.status}
</Badge>
</div>
<div className="mt-2 flex flex-col md:flex-row gap-6 text-sm text-muted-foreground">
<div>
<span className="font-medium">Professor:</span>{" "}
{course.professorname}
</div>
</div>
<div className="mt-2 flex flex-col md:flex-row gap-6 text-sm text-muted-foreground">
<div>
<span className="font-medium">Start Date:</span>{" "}
{FormateDate(course.startdate)}
</div>
<div>
<span className="font-medium">End Date:</span>{" "}
{FormateDate(course.enddate)}
</div>
</div>
</div>
<div className="flex gap-2 flex-wrap">
<Button variant="outline" size="sm">
<Edit className="w-4 h-4 mr-1" />
Update
</Button>
{course.status === "Planning" && (
<Button size="sm">Activate</Button>
)}
<Button variant="outline" size="sm">
View detail
</Button>
</div>
</div>
</CardContent>
</Card>
))}
</div>
</div>
);
};

export default AcademinCoursesTab;
69 changes: 69 additions & 0 deletions src/components/confirm-dialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
DialogClose,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { useState, type ReactNode } from "react";

interface ConfirmDialogProps {
title: string;
description: string;
trigger: ReactNode;
confirmLabel?: string;
cancelLabel?: string;
destructive?: boolean;
onConfirm: () => Promise<void> | void;
}

export const ConfirmDialog = ({
title,
description,
trigger,
confirmLabel = "Confirm",
cancelLabel = "Cancel",
destructive = true,
onConfirm,
}: ConfirmDialogProps) => {
const [open, setOpen] = useState(false);
const [isProcessing, setIsProcessing] = useState(false);

const handleConfirm = async () => {
setIsProcessing(true);
await onConfirm();
setIsProcessing(false);
setOpen(false);
};

return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>{trigger}</DialogTrigger>

<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
<DialogDescription>{description}</DialogDescription>
</DialogHeader>

<DialogFooter>
<DialogClose asChild>
<Button variant="outline">{cancelLabel}</Button>
</DialogClose>
<Button
variant={destructive ? "destructive" : "default"}
onClick={handleConfirm}
disabled={isProcessing}
>
{isProcessing ? "Processing..." : confirmLabel}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
};
65 changes: 65 additions & 0 deletions src/components/dashboard-welcome.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useAdminData } from "@/store/hooks/useAdminData";
import { AlertCircle, Verified } from "lucide-react";
import { useEffect } from "react";
import { Link, useNavigate } from "react-router-dom";
import { Skeleton } from "./ui/skeleton";

const DashboardWelcome = () => {
const { adminInfo, loading, error } = useAdminData();
const navigate = useNavigate();

const userInfo = adminInfo?.isUserExist;

useEffect(() => {
if (!loading && !userInfo) {
navigate("/auth/user-email");
}
}, [loading, userInfo, navigate]);

if (loading)
return (
<div className="flex items-center gap-3 flex-1 space-y-1">
<Skeleton className="h-9 w-full" />
</div>
);

if (error) return <div>Error loading admin data.</div>;

return (
<div className="bg-special rounded-lg p-4 lg:p-6 flex items-center justify-between w-full">
<div className="flex items-center gap-3 flex-1">
<img
src={userInfo?.profilepic || "./logo.svg"}
className="h-16 w-16 rounded-full dark:text-secondary"
/>

<div>
<span className="text-xl flex lg:text-2xl font-semibold dark:text-secondary ">
Welcome Back,{" "}
<span className="flex items-center gap-1">
{userInfo?.firstname}{" "}
{userInfo?.isVerified && (
<Verified className="text-blue-700" width={16} height={16} />
)}
</span>
</span>
<p className="text-sm dark:text-secondary/70">
Here's what's happening with your university today.
</p>
</div>
</div>
<div className="flex items-center gap-2">
{userInfo?.isVerified === false && (
<>
<AlertCircle className="text-yellow-500" />
<Link to={"/auth/user-email"}>
<span className="text-yellow-500">Verify Account</span>
</Link>
</>
)}
</div>
</div>
);
};

export default DashboardWelcome;
5 changes: 5 additions & 0 deletions src/components/models/course-model.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const CourseModel = () => {
return <div>CourseModel</div>;
};

export default CourseModel;
66 changes: 66 additions & 0 deletions src/components/setting-prefrences.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Card, CardContent } from "@/components/ui/card";
import { Palette } from "lucide-react";
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Button } from "@/components/ui/button";
import { useTheme } from "@/components/theme-provider";

const SettingPrefrences = () => {
const { setTheme, theme } = useTheme();

return (
<Card>
<CardContent className="p-6 space-y-6">
<h3 className="text-lg font-semibold flex items-center gap-2">
<Palette className="h-5 w-5" />
Preferences
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 w-full">
<div className="space-y-2 w-full">
<Label htmlFor="theme">Theme</Label>
<Select
value={theme}
onValueChange={(value: "light" | "dark" | "system") =>
setTheme(value)
}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select theme" />
</SelectTrigger>
<SelectContent>
<SelectItem value="light">Light</SelectItem>
<SelectItem value="dark">Dark</SelectItem>
<SelectItem value="system">System</SelectItem>
</SelectContent>
</Select>
</div>

<div className="space-y-2">
<Label htmlFor="language">Language</Label>
<Select value="english">
<SelectTrigger className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="english">English</SelectItem>
<SelectItem value="greek">Greek</SelectItem>
</SelectContent>
</Select>
</div>
</div>

<Button className="w-full sm:w-auto cursor-pointer">
Save Changes
</Button>
</CardContent>
</Card>
);
};

export default SettingPrefrences;
Loading