All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Wrap 7 list-item/card components with React.memo to prevent unnecessary re-renders when parent components update but props remain unchanged: - TaskItem (task lists) - EventCard (calendar views) - EntryCard (knowledge base) - WorkspaceCard (workspace list) - TeamCard (team list) - DomainItem (domain list) - ConnectionCard (federation connections) All are pure components rendered inside .map() loops that depend solely on their props for rendering output. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
63 lines
2.2 KiB
TypeScript
63 lines
2.2 KiB
TypeScript
import React from "react";
|
|
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 const WorkspaceCard = React.memo(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>
|
|
);
|
|
});
|