flowstate/app/(app)/member/[id]/MemberProfileCard.tsx
Chneemann 3db1a18086
All checks were successful
Deploy Flowstate to VPS / deploy (push) Successful in 43s
refactor(member): update member status stat to dynamically display capitalized user role
2026-08-21 04:09:03 +02:00

101 lines
3.6 KiB
TypeScript

/**
* @file MemberProfileCard.tsx
* @description Client component rendering detailed profile information and activity metrics for a specific team member.
*/
"use client";
import {
getFullName,
getInitials,
formatTimeAgo,
capitalize,
} from "@/utils/user";
import { Mail, Clock, ShieldCheck } from "lucide-react";
import { UserListItem } from "@/types/user";
/**
* Properties for the MemberProfileCard component.
*
* @interface MemberProfileCardProps
* @property {UserListItem} member - The user item containing detailed profile data, activity status, and credentials.
*/
interface MemberProfileCardProps {
member: UserListItem;
}
/**
* Renders a detailed profile card for a team member, including user avatar initials, online status indicators,
* contact information, and activity metrics.
*
* @param {MemberProfileCardProps} props - The component props.
* @returns {JSX.Element} The rendered member profile card component.
*/
export default function MemberProfileCard({ member }: MemberProfileCardProps) {
const stats = [
{
label: "Last Activity",
value: formatTimeAgo(member.lastLogin),
icon: Clock,
color: "text-blue-400 bg-blue-500/10 border-blue-500/20",
},
{
label: "Account Status",
value: `Active - ${capitalize(member.role)}`,
icon: ShieldCheck,
color: "text-emerald-400 bg-emerald-500/10 border-emerald-500/20",
},
];
return (
<div className="relative bg-card/40 border border-border/80 rounded-3xl p-4 sm:p-6 shadow-sm overflow-hidden">
{/* Accent Bar */}
<div
className={`absolute left-0 top-0 bottom-0 w-1.5 transition-colors ${member.isOnline ? "bg-emerald-500" : "bg-slate-600"}`}
/>
<div className="flex flex-col md:flex-row md:items-center justify-between gap-6 pl-2">
<div className="flex items-center gap-5">
<div
className={`w-16 h-16 shrink-0 rounded-2xl flex items-center justify-center text-xl font-black tracking-wider text-white shadow-xl border-2 border-card ring-2 ring-border/50 ${member.color}`}
style={{ textShadow: "0 1px 2px rgba(0, 0, 0, 0.8)" }}
>
{getInitials(member.firstName, member.lastName)}
</div>
<div className="space-y-1">
<h1 className="text-2xl font-bold tracking-tight text-foreground">
{getFullName(member.firstName, member.lastName)}
</h1>
<div className="flex items-center gap-2 text-foreground-muted font-mono text-xs sm:text-sm">
<Mail size={14} className="shrink-0 text-foreground-muted/70" />
<span className="truncate">{member.email}</span>
</div>
</div>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mt-4 pt-4 border-t border-border/60 pl-2">
{stats.map((stat) => (
<div
key={stat.label}
className="flex items-center gap-4 p-4 rounded-2xl bg-card/30 border border-border/60 hover:border-primary/40 transition-colors"
>
<div
className={`w-12 h-12 shrink-0 rounded-xl border flex items-center justify-center ${stat.color}`}
>
<stat.icon size={22} />
</div>
<div className="flex flex-col gap-0.5 min-w-0">
<p className="text-[11px] uppercase tracking-wider text-foreground-muted font-mono font-semibold">
{stat.label}
</p>
<p className="text-sm font-semibold text-foreground truncate">
{stat.value}
</p>
</div>
</div>
))}
</div>
</div>
);
}