Files
chronus/src/pages/dashboard/team/settings.astro
Atridad Lahiji 82e1b8a626
Some checks failed
Docker Deploy / build-and-push (push) Has been cancelled
Style updates
2026-01-18 01:40:22 -07:00

274 lines
9.0 KiB
Plaintext

---
import DashboardLayout from '../../../layouts/DashboardLayout.astro';
import { Icon } from 'astro-icon/components';
import { db } from '../../../db';
import { categories, members, organizations } from '../../../db/schema';
import { eq } from 'drizzle-orm';
const user = Astro.locals.user;
if (!user) return Astro.redirect('/login');
// Get current team from cookie
const currentTeamId = Astro.cookies.get('currentTeamId')?.value;
const userMemberships = await db.select()
.from(members)
.where(eq(members.userId, user.id))
.all();
if (userMemberships.length === 0) return Astro.redirect('/dashboard');
// Use current team or fallback to first membership
const userMembership = currentTeamId
? userMemberships.find(m => m.organizationId === currentTeamId) || userMemberships[0]
: userMemberships[0];
const isAdmin = userMembership.role === 'owner' || userMembership.role === 'admin';
if (!isAdmin) return Astro.redirect('/dashboard/team');
const orgId = userMembership.organizationId;
const organization = await db.select()
.from(organizations)
.where(eq(organizations.id, orgId))
.get();
if (!organization) return Astro.redirect('/dashboard');
const allCategories = await db.select()
.from(categories)
.where(eq(categories.organizationId, orgId))
.all();
const url = new URL(Astro.request.url);
const successType = url.searchParams.get('success');
---
<DashboardLayout title="Team Settings - Chronus">
<div class="flex items-center gap-3 mb-6">
<a href="/dashboard/team" class="btn btn-ghost btn-sm">
<Icon name="heroicons:arrow-left" class="w-5 h-5" />
</a>
<h1 class="text-3xl font-bold">Team Settings</h1>
</div>
<!-- Team Settings -->
<div class="card bg-base-100 shadow-xl border border-base-200 mb-6">
<div class="card-body">
<h2 class="card-title mb-4">
<Icon name="heroicons:building-office-2" class="w-6 h-6" />
Team Settings
</h2>
{successType === 'org-name' && (
<div class="alert alert-success mb-4">
<Icon name="heroicons:check-circle" class="w-6 h-6" />
<span>Team information updated successfully!</span>
</div>
)}
<form
action="/api/organizations/update-name"
method="POST"
class="space-y-4"
enctype="multipart/form-data"
>
<input type="hidden" name="organizationId" value={organization.id} />
<div class="form-control">
<div class="label">
<span class="label-text font-medium">Team Logo</span>
</div>
<div class="flex items-center gap-6">
<div class="avatar placeholder">
<div class="bg-base-200 text-neutral-content rounded-xl w-24 border border-base-300 flex items-center justify-center overflow-hidden">
{organization.logoUrl ? (
<img
src={organization.logoUrl}
alt={organization.name}
class="w-full h-full object-cover"
/>
) : (
<Icon
name="heroicons:photo"
class="w-8 h-8 opacity-40 text-base-content"
/>
)}
</div>
</div>
<div>
<input
type="file"
name="logo"
accept="image/png, image/jpeg"
class="file-input file-input-bordered w-full max-w-xs"
/>
<div class="text-xs text-base-content/60 mt-2">
Upload a company logo (PNG, JPG).
<br />
Will be displayed on invoices and quotes.
</div>
</div>
</div>
</div>
<label class="form-control">
<div class="label">
<span class="label-text font-medium">Team Name</span>
</div>
<input
type="text"
name="name"
value={organization.name}
placeholder="Organization name"
class="input input-bordered w-full"
required
/>
<div class="label">
<span class="label-text-alt text-base-content/60">This name is visible to all team members</span>
</div>
</label>
<div class="divider">Address Information</div>
<label class="form-control">
<div class="label">
<span class="label-text font-medium">Street Address</span>
</div>
<input
type="text"
name="street"
value={organization.street || ''}
placeholder="123 Main Street"
class="input input-bordered w-full"
/>
</label>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<label class="form-control">
<div class="label">
<span class="label-text font-medium">City</span>
</div>
<input
type="text"
name="city"
value={organization.city || ''}
placeholder="City"
class="input input-bordered w-full"
/>
</label>
<label class="form-control">
<div class="label">
<span class="label-text font-medium">State/Province</span>
</div>
<input
type="text"
name="state"
value={organization.state || ''}
placeholder="State/Province"
class="input input-bordered w-full"
/>
</label>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<label class="form-control">
<div class="label">
<span class="label-text font-medium">Postal Code</span>
</div>
<input
type="text"
name="zip"
value={organization.zip || ''}
placeholder="12345"
class="input input-bordered w-full"
/>
</label>
<label class="form-control">
<div class="label">
<span class="label-text font-medium">Country</span>
</div>
<input
type="text"
name="country"
value={organization.country || ''}
placeholder="Country"
class="input input-bordered w-full"
/>
</label>
</div>
<div class="flex flex-col sm:flex-row justify-between items-center gap-4 mt-6">
<span class="text-xs text-base-content/60 text-center sm:text-left">
Address information appears on invoices and quotes
</span>
<button type="submit" class="btn btn-primary w-full sm:w-auto">
<Icon name="heroicons:check" class="w-5 h-5" />
Save Changes
</button>
</div>
</form>
</div>
</div>
<!-- Categories Section -->
<div class="card bg-base-100 shadow-xl border border-base-200 mb-6">
<div class="card-body">
<div class="flex justify-between items-center mb-4">
<h2 class="card-title">
<Icon name="heroicons:tag" class="w-6 h-6" />
Work Categories
</h2>
<a href="/dashboard/team/settings/categories/new" class="btn btn-primary btn-sm">
<Icon name="heroicons:plus" class="w-5 h-5" />
Add Category
</a>
</div>
<p class="text-base-content/70 mb-4">
Categories help organize time tracking by type of work. All team members use the same categories.
</p>
{allCategories.length === 0 ? (
<div class="alert alert-info">
<Icon name="heroicons:information-circle" class="w-6 h-6" />
<div>
<div class="font-bold">No categories yet</div>
<div class="text-sm">Create your first category to start organizing time entries.</div>
</div>
</div>
) : (
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{allCategories.map(category => (
<div class="card bg-base-200 border border-base-300">
<div class="card-body p-4">
<div class="flex items-center gap-3">
{category.color && (
<span class="w-4 h-4 rounded-full shrink-0" style={`background-color: ${category.color}`}></span>
)}
<div class="grow min-w-0">
<h3 class="font-semibold truncate">{category.name}</h3>
<p class="text-xs text-base-content/60">
Created {category.createdAt?.toLocaleDateString() ?? 'N/A'}
</p>
</div>
<a
href={`/dashboard/team/settings/categories/${category.id}/edit`}
class="btn btn-ghost btn-xs"
>
<Icon name="heroicons:pencil" class="w-4 h-4" />
</a>
</div>
</div>
</div>
))}
</div>
)}
</div>
</div>
</DashboardLayout>