All checks were successful
Docker Deploy / build-and-push (push) Successful in 3m52s
196 lines
8.9 KiB
Plaintext
196 lines
8.9 KiB
Plaintext
---
|
|
import '../styles/global.css';
|
|
import { Icon } from 'astro-icon/components';
|
|
import { db } from '../db';
|
|
import { members, organizations } from '../db/schema';
|
|
import { eq } from 'drizzle-orm';
|
|
import Avatar from '../components/Avatar.astro';
|
|
import { ClientRouter } from "astro:transitions";
|
|
|
|
interface Props {
|
|
title: string;
|
|
}
|
|
|
|
const { title } = Astro.props;
|
|
const user = Astro.locals.user;
|
|
|
|
if (!user) {
|
|
return Astro.redirect('/login');
|
|
}
|
|
|
|
// Get user's team memberships
|
|
const userMemberships = await db.select({
|
|
membership: members,
|
|
organization: organizations,
|
|
})
|
|
.from(members)
|
|
.innerJoin(organizations, eq(members.organizationId, organizations.id))
|
|
.where(eq(members.userId, user.id))
|
|
.all();
|
|
|
|
// Get current team from cookie or use first membership
|
|
const currentTeamId = Astro.cookies.get('currentTeamId')?.value || userMemberships[0]?.organization.id;
|
|
const currentTeam = userMemberships.find(m => m.organization.id === currentTeamId);
|
|
---
|
|
|
|
<!doctype html>
|
|
<html lang="en" data-theme="dark">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="description" content="Chronus Dashboard" />
|
|
<meta name="viewport" content="width=device-width" />
|
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
|
<meta name="generator" content={Astro.generator} />
|
|
<title>{title}</title>
|
|
<ClientRouter />
|
|
</head>
|
|
<body class="bg-base-100 h-screen flex flex-col overflow-hidden">
|
|
<div class="drawer lg:drawer-open flex-1 overflow-auto">
|
|
<input id="my-drawer-2" type="checkbox" class="drawer-toggle" />
|
|
<div class="drawer-content flex flex-col h-full overflow-auto">
|
|
<!-- Navbar -->
|
|
<div class="navbar bg-base-200/50 backdrop-blur-sm sticky top-0 z-50 lg:hidden border-b border-base-300/50">
|
|
<div class="flex-none lg:hidden">
|
|
<label for="my-drawer-2" aria-label="open sidebar" class="btn btn-square btn-ghost">
|
|
<Icon name="heroicons:bars-3" class="w-6 h-6" />
|
|
</label>
|
|
</div>
|
|
<div class="flex-1 px-2 flex items-center gap-2">
|
|
<img src="/logo.webp" alt="Chronus" class="h-8 w-8" />
|
|
<span class="text-xl font-bold text-primary">Chronus</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Page content here -->
|
|
<main class="p-6 md:p-8">
|
|
<slot />
|
|
</main>
|
|
</div>
|
|
<div class="drawer-side z-50">
|
|
<label for="my-drawer-2" aria-label="close sidebar" class="drawer-overlay"></label>
|
|
<ul class="menu bg-base-200/95 backdrop-blur-sm min-h-full w-80 p-4 border-r border-base-300/30">
|
|
<!-- Sidebar content here -->
|
|
<li class="mb-6">
|
|
<a href="/dashboard" class="flex items-center gap-3 text-2xl font-bold text-primary hover:bg-transparent">
|
|
<img src="/logo.webp" alt="Chronus" class="h-10 w-10" />
|
|
Chronus
|
|
</a>
|
|
</li>
|
|
|
|
{/* Team Switcher */}
|
|
{userMemberships.length > 0 && (
|
|
<li class="mb-4">
|
|
<div class="form-control">
|
|
<select
|
|
class="select select-bordered w-full font-semibold bg-base-300/50 hover:bg-base-300 focus:bg-base-300 border-base-300/50 focus:border-primary focus:outline-none focus:outline-offset-0 transition-all duration-200 hover:border-primary/40 focus:ring-3 focus:ring-primary/15 [&>option]:bg-base-300 [&>option]:text-base-content [&>option]:p-2"
|
|
id="team-switcher"
|
|
onchange="document.cookie = 'currentTeamId=' + this.value + '; path=/'; window.location.reload();"
|
|
>
|
|
{userMemberships.map(({ membership, organization }) => (
|
|
<option
|
|
value={organization.id}
|
|
selected={organization.id === currentTeamId}
|
|
>
|
|
{organization.name}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
</li>
|
|
)}
|
|
|
|
{userMemberships.length === 0 && (
|
|
<li class="mb-4">
|
|
<a href="/dashboard/organizations/new" class="btn btn-primary btn-sm">
|
|
<Icon name="heroicons:plus" class="w-4 h-4" />
|
|
Create Team
|
|
</a>
|
|
</li>
|
|
)}
|
|
|
|
<div class="divider my-2"></div>
|
|
|
|
<li><a href="/dashboard" class:list={[
|
|
"hover:bg-base-300/50 rounded-lg transition-colors active:bg-base-300/50!",
|
|
{ "bg-primary/10 text-primary relative before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:w-0.75 before:h-[70%] before:bg-primary before:rounded-r-full": Astro.url.pathname === "/dashboard" }
|
|
]}>
|
|
<Icon name="heroicons:home" class="w-5 h-5" />
|
|
Dashboard
|
|
</a></li>
|
|
<li><a href="/dashboard/tracker" class:list={[
|
|
"hover:bg-base-300/50 rounded-lg transition-colors active:bg-base-300/50!",
|
|
{ "bg-primary/10 text-primary relative before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:w-0.75 before:h-[70%] before:bg-primary before:rounded-r-full": Astro.url.pathname.startsWith("/dashboard/tracker") }
|
|
]}>
|
|
<Icon name="heroicons:clock" class="w-5 h-5" />
|
|
Time Tracker
|
|
</a></li>
|
|
<li><a href="/dashboard/invoices" class:list={[
|
|
"hover:bg-base-300/50 rounded-lg transition-colors active:bg-base-300/50!",
|
|
{ "bg-primary/10 text-primary relative before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:w-0.75 before:h-[70%] before:bg-primary before:rounded-r-full": Astro.url.pathname.startsWith("/dashboard/invoices") }
|
|
]}>
|
|
<Icon name="heroicons:document-currency-dollar" class="w-5 h-5" />
|
|
Invoices & Quotes
|
|
</a></li>
|
|
<li><a href="/dashboard/reports" class:list={[
|
|
"hover:bg-base-300/50 rounded-lg transition-colors active:bg-base-300/50!",
|
|
{ "bg-primary/10 text-primary relative before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:w-0.75 before:h-[70%] before:bg-primary before:rounded-r-full": Astro.url.pathname.startsWith("/dashboard/reports") }
|
|
]}>
|
|
<Icon name="heroicons:chart-bar" class="w-5 h-5" />
|
|
Reports
|
|
</a></li>
|
|
<li><a href="/dashboard/clients" class:list={[
|
|
"hover:bg-base-300/50 rounded-lg transition-colors active:bg-base-300/50!",
|
|
{ "bg-primary/10 text-primary relative before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:w-0.75 before:h-[70%] before:bg-primary before:rounded-r-full": Astro.url.pathname.startsWith("/dashboard/clients") }
|
|
]}>
|
|
<Icon name="heroicons:building-office" class="w-5 h-5" />
|
|
Clients
|
|
</a></li>
|
|
<li><a href="/dashboard/team" class:list={[
|
|
"hover:bg-base-300/50 rounded-lg transition-colors active:bg-base-300/50!",
|
|
{ "bg-primary/10 text-primary relative before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:w-0.75 before:h-[70%] before:bg-primary before:rounded-r-full": Astro.url.pathname.startsWith("/dashboard/team") }
|
|
]}>
|
|
<Icon name="heroicons:user-group" class="w-5 h-5" />
|
|
Team
|
|
</a></li>
|
|
|
|
{user.isSiteAdmin && (
|
|
<>
|
|
<div class="divider my-2"></div>
|
|
<li><a href="/admin" class:list={[
|
|
"font-semibold hover:bg-base-300/50 rounded-lg transition-colors active:bg-base-300/50!",
|
|
{ "bg-primary/10 text-primary relative before:absolute before:left-0 before:top-1/2 before:-translate-y-1/2 before:w-0.75 before:h-[70%] before:bg-primary before:rounded-r-full": Astro.url.pathname.startsWith("/admin") }
|
|
]}>
|
|
<Icon name="heroicons:cog-6-tooth" class="w-5 h-5" />
|
|
Site Admin
|
|
</a></li>
|
|
</>
|
|
)}
|
|
|
|
<div class="divider my-2"></div>
|
|
|
|
<li>
|
|
<a href="/dashboard/settings" class="flex items-center gap-3 bg-base-300/30 hover:bg-base-300/60 rounded-lg p-3 transition-colors">
|
|
<Avatar name={user.name} />
|
|
<div class="flex-1 min-w-0">
|
|
<div class="font-semibold text-sm truncate">{user.name}</div>
|
|
<div class="text-xs text-base-content/50 truncate">{user.email}</div>
|
|
</div>
|
|
<Icon name="heroicons:chevron-right" class="w-4 h-4 opacity-40" />
|
|
</a>
|
|
</li>
|
|
|
|
<li>
|
|
<form action="/api/auth/logout" method="POST" class="contents">
|
|
<button type="submit" class="flex w-full items-center gap-2 py-2 px-4 text-error hover:bg-error/10 rounded-lg transition-colors active:bg-base-300/50!">
|
|
<Icon name="heroicons:arrow-right-on-rectangle" class="w-5 h-5" />
|
|
Logout
|
|
</button>
|
|
</form>
|
|
</li>
|
|
</ul>
|
|
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|