+>(({ className, ...props }, ref) => (
+ [role=checkbox]]:translate-y-[2px]",
+ className
+ )}
+ {...props}
+ />
+))
+TableCell.displayName = "TableCell"
+
+const TableCaption = React.forwardRef<
+ HTMLTableCaptionElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+TableCaption.displayName = "TableCaption"
+
+export {
+ Table,
+ TableHeader,
+ TableBody,
+ TableFooter,
+ TableHead,
+ TableRow,
+ TableCell,
+ TableCaption,
+}
diff --git a/src/index.css b/src/index.css
index 08a3ac9..3ee82ad 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1,68 +1,123 @@
-:root {
- font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
+/* Keep this minimal; shadcn init will add theme tokens + base styles. */
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
-}
-a:hover {
- color: #535bf2;
-}
-body {
- margin: 0;
- display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
-}
-
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
-}
-
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-@media (prefers-color-scheme: light) {
+@layer base {
:root {
- color: #213547;
- background-color: #ffffff;
+
+ --background: 0 0% 100%;
+
+ --foreground: 240 10% 3.9%;
+
+ --card: 0 0% 100%;
+
+ --card-foreground: 240 10% 3.9%;
+
+ --popover: 0 0% 100%;
+
+ --popover-foreground: 240 10% 3.9%;
+
+ --primary: 240 5.9% 10%;
+
+ --primary-foreground: 0 0% 98%;
+
+ --secondary: 240 4.8% 95.9%;
+
+ --secondary-foreground: 240 5.9% 10%;
+
+ --muted: 240 4.8% 95.9%;
+
+ --muted-foreground: 240 3.8% 46.1%;
+
+ --accent: 240 4.8% 95.9%;
+
+ --accent-foreground: 240 5.9% 10%;
+
+ --destructive: 0 84.2% 60.2%;
+
+ --destructive-foreground: 0 0% 98%;
+
+ --border: 240 5.9% 90%;
+
+ --input: 240 5.9% 90%;
+
+ --ring: 240 10% 3.9%;
+
+ --chart-1: 12 76% 61%;
+
+ --chart-2: 173 58% 39%;
+
+ --chart-3: 197 37% 24%;
+
+ --chart-4: 43 74% 66%;
+
+ --chart-5: 27 87% 67%;
+
+ --radius: 0.5rem
}
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
+ .dark {
+
+ --background: 240 10% 3.9%;
+
+ --foreground: 0 0% 98%;
+
+ --card: 240 10% 3.9%;
+
+ --card-foreground: 0 0% 98%;
+
+ --popover: 240 10% 3.9%;
+
+ --popover-foreground: 0 0% 98%;
+
+ --primary: 0 0% 98%;
+
+ --primary-foreground: 240 5.9% 10%;
+
+ --secondary: 240 3.7% 15.9%;
+
+ --secondary-foreground: 0 0% 98%;
+
+ --muted: 240 3.7% 15.9%;
+
+ --muted-foreground: 240 5% 64.9%;
+
+ --accent: 240 3.7% 15.9%;
+
+ --accent-foreground: 0 0% 98%;
+
+ --destructive: 0 62.8% 30.6%;
+
+ --destructive-foreground: 0 0% 98%;
+
+ --border: 240 3.7% 15.9%;
+
+ --input: 240 3.7% 15.9%;
+
+ --ring: 240 4.9% 83.9%;
+
+ --chart-1: 220 70% 50%;
+
+ --chart-2: 160 60% 45%;
+
+ --chart-3: 30 80% 55%;
+
+ --chart-4: 280 65% 60%;
+
+ --chart-5: 340 75% 55%
+ }
+}
+
+
+
+@layer base {
+ * {
+ @apply border-border;
+ }
+ body {
+ @apply bg-background text-foreground font-sans;
}
}
diff --git a/src/layouts/app-shell.tsx b/src/layouts/app-shell.tsx
new file mode 100644
index 0000000..958e8a9
--- /dev/null
+++ b/src/layouts/app-shell.tsx
@@ -0,0 +1,186 @@
+import { Outlet, Link, useLocation } from "react-router-dom"
+import {
+ LayoutDashboard,
+ FolderKanban,
+ Calendar,
+ Leaf,
+ Settings,
+ Bell,
+ HelpCircle,
+ DollarSign,
+ FileText,
+ Users,
+ Briefcase,
+ Mail,
+ Copy,
+ UserPlus,
+ Megaphone,
+ Search,
+} from "lucide-react"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Avatar, AvatarFallback } from "@/components/ui/avatar"
+import { Separator } from "@/components/ui/separator"
+import { Card, CardContent } from "@/components/ui/card"
+import { cn } from "@/lib/utils"
+
+const navigationItems = [
+ { icon: LayoutDashboard, label: "Dashboard", path: "/" },
+ { icon: FolderKanban, label: "Projects", path: "/projects" },
+ { icon: Calendar, label: "Calendar", path: "/calendar" },
+ { icon: Leaf, label: "Leave Management", path: "/leave" },
+ { icon: Settings, label: "Settings", path: "/settings" },
+ { icon: Bell, label: "Notification", path: "/notifications" },
+ { icon: HelpCircle, label: "Help & Center", path: "/help" },
+]
+
+const adminNavigationItems = [
+ { icon: Users, label: "Subscriptions", path: "/subscriptions" },
+ { icon: DollarSign, label: "Transactions", path: "/transactions" },
+ { icon: Briefcase, label: "Clients", path: "/clients" },
+ { icon: Users, label: "Members", path: "/members" },
+ { icon: Bell, label: "Notifications", path: "/notifications" },
+ { icon: FileText, label: "Activity Log", path: "/activity-log" },
+]
+
+export function AppShell() {
+ const location = useLocation()
+
+ const isActive = (path: string) => {
+ if (path === "/") {
+ return location.pathname === "/"
+ }
+ return location.pathname.startsWith(path)
+ }
+
+ return (
+
+ {/* Sidebar */}
+
+ {/* Logo */}
+
+
+ {/* Navigation */}
+
+ {navigationItems.map((item) => {
+ const Icon = item.icon
+ return (
+
+
+ {item.label}
+
+ )
+ })}
+
+
+
+
+ Admin
+
+
+ {adminNavigationItems.map((item) => {
+ const Icon = item.icon
+ return (
+
+
+ {item.label}
+
+ )
+ })}
+
+
+ {/* Announcements Card */}
+
+
+
+
+
+ Announcements
+
+
+ Stay updated with TurHR
+
+
+ Create Now
+
+
+ Read by:
+
+
+
+
+
+
+
+ {/* Main Content */}
+
+ {/* Top Header */}
+
+ Dashboard
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +10
+
+
+
+
+ Invite
+
+
+ U
+
+
+
+
+ {/* Page Content */}
+
+
+
+
+
+ )
+}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
new file mode 100644
index 0000000..bd0c391
--- /dev/null
+++ b/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx"
+import { twMerge } from "tailwind-merge"
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/src/main.tsx b/src/main.tsx
index bef5202..f726fb0 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -2,9 +2,16 @@ import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
+import { BrowserRouter } from "react-router-dom"
+import { QueryClientProvider } from "@tanstack/react-query"
+import { queryClient } from "@/app/query-client"
createRoot(document.getElementById('root')!).render(
-
+
+
+
+
+
,
)
diff --git a/src/pages/activity-log/index.tsx b/src/pages/activity-log/index.tsx
new file mode 100644
index 0000000..981b464
--- /dev/null
+++ b/src/pages/activity-log/index.tsx
@@ -0,0 +1,143 @@
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Badge } from "@/components/ui/badge"
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table"
+import { Search, Download, Eye, MoreVertical } from "lucide-react"
+
+export default function ActivityLogPage() {
+ return (
+
+
+
Activity Log
+
+
+ Export Log
+
+
+
+
+
+
+
All Activities
+
+
+
+
+
+
+ All Actions
+ Create
+ Update
+ Delete
+ Login
+ Logout
+
+
+ All Users
+ Admin
+ Manager
+ User
+
+
+
+ Export
+
+
+
+
+
+
+
+
+ Log ID
+ User
+ Action
+ Entity
+ Description
+ IP Address
+ Timestamp
+ Action
+
+
+
+
+ LOG001
+ john.smith@example.com
+
+ Create
+
+ Client
+ Created new client record
+ 192.168.1.1
+ 2024-01-15 10:30:45
+
+
+
+
+
+
+
+
+
+
+
+
+ LOG002
+ jane.doe@example.com
+
+ Update
+
+ Subscription
+ Updated subscription status
+ 192.168.1.2
+ 2024-01-15 09:15:22
+
+
+
+
+
+
+
+
+
+
+
+
+ LOG003
+ admin@example.com
+
+ Login
+
+ System
+ User logged in successfully
+ 192.168.1.3
+ 2024-01-15 08:00:00
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/pages/clients/index.tsx b/src/pages/clients/index.tsx
new file mode 100644
index 0000000..8b856f9
--- /dev/null
+++ b/src/pages/clients/index.tsx
@@ -0,0 +1,128 @@
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Badge } from "@/components/ui/badge"
+import { Avatar, AvatarFallback } from "@/components/ui/avatar"
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table"
+import { Search, Download, Eye, MoreVertical, UserPlus } from "lucide-react"
+
+export default function ClientsPage() {
+ return (
+
+
+
Clients
+
+
+ Add Client
+
+
+
+
+
+
+
All Clients
+
+
+
+
+
+
+ All Status
+ Active
+ Inactive
+
+
+
+ Export
+
+
+
+
+
+
+
+
+ Client ID
+ Client Name
+ Email
+ Company
+ Status
+ Subscription
+ Joined Date
+ Action
+
+
+
+
+ CLT001
+
+
+
+ client@example.com
+ Company Name
+
+ Active
+
+ Premium Plan
+ 2024-01-01
+
+
+
+
+
+
+
+
+
+
+
+
+ CLT002
+
+
+
+ AC
+
+
Another Client
+
+
+ another@example.com
+ Another Company
+
+ Pending
+
+ Basic Plan
+ 2024-02-01
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/pages/dashboard/index.tsx b/src/pages/dashboard/index.tsx
new file mode 100644
index 0000000..e307905
--- /dev/null
+++ b/src/pages/dashboard/index.tsx
@@ -0,0 +1,35 @@
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Download } from "lucide-react"
+
+export default function DashboardPage() {
+ return (
+
+
+
Good Morning, Admin
+
+
+ 01 Sep - 15 Sep 2024
+
+
+
+ Export Data
+
+
+
+
+
+
+
+ Welcome to Dashboard
+
+
+
+ This is your main dashboard page.
+
+
+
+
+
+ )
+}
diff --git a/src/pages/members/index.tsx b/src/pages/members/index.tsx
new file mode 100644
index 0000000..1209aa1
--- /dev/null
+++ b/src/pages/members/index.tsx
@@ -0,0 +1,135 @@
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Badge } from "@/components/ui/badge"
+import { Avatar, AvatarFallback } from "@/components/ui/avatar"
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table"
+import { Search, Download, Eye, MoreVertical, UserPlus } from "lucide-react"
+
+export default function MembersPage() {
+ return (
+
+
+
Members (System Users)
+
+
+ Add Member
+
+
+
+
+
+
+
All Members
+
+
+
+
+
+
+ All Status
+ Active
+ Inactive
+ Suspended
+
+
+ All Roles
+ Admin
+ Manager
+ User
+
+
+
+ Export
+
+
+
+
+
+
+
+
+ Member ID
+ Name
+ Email
+ Role
+ Department
+ Status
+ Last Login
+ Action
+
+
+
+
+ MEM001
+
+
+
+ john.smith@example.com
+ Admin
+ IT Department
+
+ Active
+
+ 2024-01-15 10:30
+
+
+
+
+
+
+
+
+
+
+
+
+ MEM002
+
+
+
+ jane.doe@example.com
+ Manager
+ Operations
+
+ Pending
+
+ 2024-01-14 15:45
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/pages/notifications/index.tsx b/src/pages/notifications/index.tsx
new file mode 100644
index 0000000..533dc43
--- /dev/null
+++ b/src/pages/notifications/index.tsx
@@ -0,0 +1,123 @@
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Badge } from "@/components/ui/badge"
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table"
+import { Search, Download, Eye, MoreVertical, Bell } from "lucide-react"
+
+export default function NotificationsPage() {
+ return (
+
+
+
Notifications
+
+
+ Create Notification
+
+
+
+
+
+
+
All Notifications
+
+
+
+
+
+
+ All Types
+ System
+ User
+ Alert
+
+
+ All Status
+ Read
+ Unread
+
+
+
+ Export
+
+
+
+
+
+
+
+
+ Notification ID
+ Title
+ Type
+ Recipient
+ Status
+ Created Date
+ Sent Date
+ Action
+
+
+
+
+ NOT001
+ System Update Available
+
+ System
+
+ All Users
+
+ Sent
+
+ 2024-01-15
+ 2024-01-15 10:00
+
+
+
+
+
+
+
+
+
+
+
+
+ NOT002
+ Payment Received
+
+ User
+
+ john@example.com
+
+ Delivered
+
+ 2024-01-14
+ 2024-01-14 14:30
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/pages/subscriptions/index.tsx b/src/pages/subscriptions/index.tsx
new file mode 100644
index 0000000..c8112a5
--- /dev/null
+++ b/src/pages/subscriptions/index.tsx
@@ -0,0 +1,114 @@
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Badge } from "@/components/ui/badge"
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table"
+import { Search, Download, Eye, MoreVertical } from "lucide-react"
+
+export default function SubscriptionsPage() {
+ return (
+
+
+
Subscriptions
+
+
+ Export Data
+
+
+
+
+
+
+
All Subscriptions
+
+
+
+
+
+
+ All Status
+ Active
+ Inactive
+ Cancelled
+
+
+
+ Export
+
+
+
+
+
+
+
+
+ Subscription ID
+ Plan Name
+ Client
+ Amount
+ Status
+ Start Date
+ End Date
+ Action
+
+
+
+
+ SUB001
+ Premium Plan
+ Client Name
+ $99.00
+
+ Active
+
+ 2024-01-01
+ 2024-12-31
+
+
+
+
+
+
+
+
+
+
+
+
+ SUB002
+ Basic Plan
+ Another Client
+ $49.00
+
+ Pending
+
+ 2024-02-01
+ 2024-11-30
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/src/pages/transactions/index.tsx b/src/pages/transactions/index.tsx
new file mode 100644
index 0000000..754db5f
--- /dev/null
+++ b/src/pages/transactions/index.tsx
@@ -0,0 +1,120 @@
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
+import { Button } from "@/components/ui/button"
+import { Input } from "@/components/ui/input"
+import { Badge } from "@/components/ui/badge"
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table"
+import { Search, Download, Eye, MoreVertical } from "lucide-react"
+
+export default function TransactionsPage() {
+ return (
+
+
+
Transactions
+
+
+ Export Data
+
+
+
+
+
+
+
All Transactions
+
+
+
+
+
+
+ All Status
+ Completed
+ Pending
+ Failed
+
+
+ All Types
+ Payment
+ Refund
+ Subscription
+
+
+
+ Export
+
+
+
+
+
+
+
+
+ Transaction ID
+ Client
+ Type
+ Amount
+ Status
+ Date
+ Payment Method
+ Action
+
+
+
+
+ TXN001
+ Client Name
+ Payment
+ $99.00
+
+ Completed
+
+ 2024-01-15
+ Credit Card
+
+
+
+
+
+
+
+
+
+
+
+
+ TXN002
+ Another Client
+ Refund
+ -$49.00
+
+ Pending
+
+ 2024-01-14
+ Bank Transfer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..cc35775
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,75 @@
+import tailwindAnimate from "tailwindcss-animate"
+
+/** @type {import('tailwindcss').Config} */
+export default {
+ darkMode: ["class"],
+ content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx}"],
+ theme: {
+ extend: {
+ fontFamily: {
+ sans: [
+ '"Plus Jakarta Sans"',
+ "ui-sans-serif",
+ "system-ui",
+ "-apple-system",
+ "Segoe UI",
+ "Roboto",
+ "Helvetica",
+ "Arial",
+ "Apple Color Emoji",
+ "Segoe UI Emoji",
+ ],
+ },
+ borderRadius: {
+ lg: 'var(--radius)',
+ md: 'calc(var(--radius) - 2px)',
+ sm: 'calc(var(--radius) - 4px)'
+ },
+ colors: {
+ background: 'hsl(var(--background))',
+ foreground: 'hsl(var(--foreground))',
+ card: {
+ DEFAULT: 'hsl(var(--card))',
+ foreground: 'hsl(var(--card-foreground))'
+ },
+ popover: {
+ DEFAULT: 'hsl(var(--popover))',
+ foreground: 'hsl(var(--popover-foreground))'
+ },
+ primary: {
+ DEFAULT: 'hsl(var(--primary))',
+ foreground: 'hsl(var(--primary-foreground))'
+ },
+ secondary: {
+ DEFAULT: 'hsl(var(--secondary))',
+ foreground: 'hsl(var(--secondary-foreground))'
+ },
+ muted: {
+ DEFAULT: 'hsl(var(--muted))',
+ foreground: 'hsl(var(--muted-foreground))'
+ },
+ accent: {
+ DEFAULT: 'hsl(var(--accent))',
+ foreground: 'hsl(var(--accent-foreground))'
+ },
+ destructive: {
+ DEFAULT: 'hsl(var(--destructive))',
+ foreground: 'hsl(var(--destructive-foreground))'
+ },
+ border: 'hsl(var(--border))',
+ input: 'hsl(var(--input))',
+ ring: 'hsl(var(--ring))',
+ chart: {
+ '1': 'hsl(var(--chart-1))',
+ '2': 'hsl(var(--chart-2))',
+ '3': 'hsl(var(--chart-3))',
+ '4': 'hsl(var(--chart-4))',
+ '5': 'hsl(var(--chart-5))'
+ }
+ }
+ }
+ },
+ plugins: [tailwindAnimate],
+}
+
+
diff --git a/tsconfig.app.json b/tsconfig.app.json
index a9b5a59..cf8de40 100644
--- a/tsconfig.app.json
+++ b/tsconfig.app.json
@@ -7,6 +7,10 @@
"module": "ESNext",
"types": ["vite/client"],
"skipLibCheck": true,
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ },
/* Bundler mode */
"moduleResolution": "bundler",
diff --git a/tsconfig.json b/tsconfig.json
index 1ffef60..aa3c04f 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,4 +1,10 @@
{
+ "compilerOptions": {
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
diff --git a/vite.config.ts b/vite.config.ts
index 8b0f57b..c30c4d6 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,7 +1,13 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
+import { defineConfig } from "vite"
+import react from "@vitejs/plugin-react"
+import path from "node:path"
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
+ resolve: {
+ alias: {
+ "@": path.resolve(__dirname, "./src"),
+ },
+ },
})