feat(web): add workspace management UI (M2 #12)

- Create workspace listing page at /settings/workspaces
  - List all user workspaces with role badges
  - Create new workspace functionality
  - Display member count per workspace

- Create workspace detail page at /settings/workspaces/[id]
  - Workspace settings (name, ID, created date)
  - Member management with role editing
  - Invite member functionality
  - Delete workspace (owner only)

- Add workspace components:
  - WorkspaceCard: Display workspace info with role badge
  - WorkspaceSettings: Edit workspace settings and delete
  - MemberList: Display and manage workspace members
  - InviteMember: Send invitations with role selection

- Add WorkspaceMemberWithUser type to shared package
- Follow existing app patterns for styling and structure
- Use mock data (ready for API integration)
This commit is contained in:
Jason Woltje
2026-01-29 16:59:26 -06:00
parent 287a0e2556
commit 5291fece26
43 changed files with 4152 additions and 99 deletions

View File

@@ -0,0 +1,2 @@
export * from "./update-preferences.dto";
export * from "./preferences-response.dto";

View File

@@ -0,0 +1,12 @@
/**
* Response DTO for user preferences
*/
export interface PreferencesResponseDto {
id: string;
userId: string;
theme: string;
locale: string;
timezone: string | null;
settings: Record<string, unknown>;
updatedAt: Date;
}

View File

@@ -0,0 +1,25 @@
import { IsString, IsOptional, IsObject, IsIn } from "class-validator";
/**
* DTO for updating user preferences
*/
export class UpdatePreferencesDto {
@IsOptional()
@IsString({ message: "theme must be a string" })
@IsIn(["light", "dark", "system"], {
message: "theme must be one of: light, dark, system",
})
theme?: string;
@IsOptional()
@IsString({ message: "locale must be a string" })
locale?: string;
@IsOptional()
@IsString({ message: "timezone must be a string" })
timezone?: string;
@IsOptional()
@IsObject({ message: "settings must be an object" })
settings?: Record<string, unknown>;
}