All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Fixes all 542 ESLint problems in the web package to achieve 0 errors and 0 warnings. Changes: - Fixed 144 issues: nullish coalescing, return types, unused variables - Fixed 118 issues: unnecessary conditions, type safety, template literals - Fixed 79 issues: non-null assertions, unsafe assignments, empty functions - Fixed 67 issues: explicit return types, promise handling, enum comparisons - Fixed 45 final warnings: missing return types, optional chains - Fixed 25 typecheck-related issues: async/await, type assertions, formatting - Fixed JSX.Element namespace errors across 90+ files All Quality Rails violations resolved. Lint and typecheck both pass with 0 problems. Files modified: 118 components, tests, hooks, and utilities Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
62 lines
2.2 KiB
TypeScript
62 lines
2.2 KiB
TypeScript
import type { Workspace } from "@mosaic/shared";
|
|
import { WorkspaceMemberRole } from "@mosaic/shared";
|
|
import Link from "next/link";
|
|
|
|
interface WorkspaceCardProps {
|
|
workspace: Workspace;
|
|
userRole: WorkspaceMemberRole;
|
|
memberCount: number;
|
|
}
|
|
|
|
const roleColors: Record<WorkspaceMemberRole, string> = {
|
|
[WorkspaceMemberRole.OWNER]: "bg-purple-100 text-purple-700",
|
|
[WorkspaceMemberRole.ADMIN]: "bg-blue-100 text-blue-700",
|
|
[WorkspaceMemberRole.MEMBER]: "bg-green-100 text-green-700",
|
|
[WorkspaceMemberRole.GUEST]: "bg-gray-100 text-gray-700",
|
|
};
|
|
|
|
const roleLabels: Record<WorkspaceMemberRole, string> = {
|
|
[WorkspaceMemberRole.OWNER]: "Owner",
|
|
[WorkspaceMemberRole.ADMIN]: "Admin",
|
|
[WorkspaceMemberRole.MEMBER]: "Member",
|
|
[WorkspaceMemberRole.GUEST]: "Guest",
|
|
};
|
|
|
|
export function WorkspaceCard({
|
|
workspace,
|
|
userRole,
|
|
memberCount,
|
|
}: WorkspaceCardProps): React.JSX.Element {
|
|
return (
|
|
<Link
|
|
href={`/settings/workspaces/${workspace.id}`}
|
|
className="block bg-white rounded-lg shadow-sm border border-gray-200 p-6 hover:shadow-md transition-shadow"
|
|
>
|
|
<div className="flex items-start justify-between">
|
|
<div className="flex-1">
|
|
<h3 className="text-lg font-semibold text-gray-900 mb-2">{workspace.name}</h3>
|
|
<div className="flex items-center gap-3 text-sm text-gray-600">
|
|
<span className="flex items-center gap-1">
|
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path
|
|
strokeLinecap="round"
|
|
strokeLinejoin="round"
|
|
strokeWidth={2}
|
|
d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z"
|
|
/>
|
|
</svg>
|
|
{memberCount} {memberCount === 1 ? "member" : "members"}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<span className={`px-3 py-1 rounded-full text-xs font-medium ${roleColors[userRole]}`}>
|
|
{roleLabels[userRole]}
|
|
</span>
|
|
</div>
|
|
<div className="mt-4 text-sm text-gray-500">
|
|
Created {new Date(workspace.createdAt).toLocaleDateString()}
|
|
</div>
|
|
</Link>
|
|
);
|
|
}
|