diff --git a/app/(app)/member/MemberHeader.tsx b/app/(app)/member/MemberHeader.tsx index 91d4d6f..b7a2da2 100644 --- a/app/(app)/member/MemberHeader.tsx +++ b/app/(app)/member/MemberHeader.tsx @@ -5,7 +5,9 @@ "use client"; +import { GoBackButton } from "@/app/components/ui/buttons/GoBackButton"; import { UsersRound } from "lucide-react"; +import { usePathname } from "next/navigation"; /** * Renders the members page header featuring title details, workspace subtitle, and an indicator icon. @@ -13,18 +15,27 @@ import { UsersRound } from "lucide-react"; * @returns {JSX.Element} The rendered members header component. */ export default function MemberHeader() { + const pathname = usePathname(); + const isRootPage = pathname === "/member"; + return ( -
-
-
- - Team + <> +
+
+
+ + Team +
+

Member

+

+ Manage your team members and collaborate efficiently. +

-

Member

-

- Manage your team members and collaborate efficiently. -

-
+ + {!isRootPage && ( + + )} + ); } diff --git a/app/(app)/member/[id]/MemberProfileCard.tsx b/app/(app)/member/[id]/MemberProfileCard.tsx new file mode 100644 index 0000000..24ba2d4 --- /dev/null +++ b/app/(app)/member/[id]/MemberProfileCard.tsx @@ -0,0 +1,96 @@ +/** + * @file MemberProfileCard.tsx + * @description Client component rendering detailed profile information and activity metrics for a specific team member. + */ + +"use client"; + +import { getFullName, getInitials, formatTimeAgo } 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 - Member", + icon: ShieldCheck, + color: "text-emerald-400 bg-emerald-500/10 border-emerald-500/20", + }, + ]; + + return ( +
+ {/* Accent Bar */} +
+ +
+
+
+ {getInitials(member.firstName, member.lastName)} +
+
+

+ {getFullName(member.firstName, member.lastName)} +

+
+ + {member.email} +
+
+
+
+ +
+ {stats.map((stat) => ( +
+
+ +
+
+

+ {stat.label} +

+

+ {stat.value} +

+
+
+ ))} +
+
+ ); +} diff --git a/app/(app)/member/[id]/page.tsx b/app/(app)/member/[id]/page.tsx new file mode 100644 index 0000000..8746a58 --- /dev/null +++ b/app/(app)/member/[id]/page.tsx @@ -0,0 +1,43 @@ +/** + * @file member/[id]/page.tsx + * @description Server component rendering the detailed profile page for a specific member by fetching their user profile data. + */ + +import { UserService } from "@/services/user.service"; +import { notFound } from "next/navigation"; +import MemberHeader from "../MemberHeader"; +import MemberProfileCard from "./MemberProfileCard"; + +/** + * Properties for the MemberDetailPage component. + * + * @interface MemberDetailPageProps + * @property {Promise<{ id: string }>} params - Promise containing route context parameters with the target member ID. + */ +interface MemberDetailPageProps { + params: Promise<{ id: string }>; +} + +/** + * Renders the member detail page by resolving the route parameter, fetching the user profile by ID, + * and displaying their header and profile card or triggering a 404 page if the member is not found. + * + * @async + * @param {MemberDetailPageProps} props - The component props. + * @returns {Promise} The rendered member detail page component. + */ +export default async function MemberDetailPage({ + params, +}: MemberDetailPageProps) { + const { id } = await params; + const user = await UserService.findProfileById(id); + + if (!user) notFound(); + + return ( +
+ + +
+ ); +} diff --git a/app/(app)/member/list/MemberItem.tsx b/app/(app)/member/list/MemberItem.tsx index d4680c8..c7903ca 100644 --- a/app/(app)/member/list/MemberItem.tsx +++ b/app/(app)/member/list/MemberItem.tsx @@ -13,6 +13,7 @@ import { } from "@/utils/user"; import { Mail } from "lucide-react"; import { UserListItem } from "@/types/user"; +import Link from "next/link"; /** * Properties for the MemberItem component. @@ -32,7 +33,10 @@ interface MemberItemProps { */ export default function MemberItem({ member }: MemberItemProps) { return ( -
+ {/* Dynamic colored accent stripe */}
-
+ ); } diff --git a/services/user.service.ts b/services/user.service.ts index 3bc0f29..427badc 100644 --- a/services/user.service.ts +++ b/services/user.service.ts @@ -5,24 +5,26 @@ import { db } from "@/db"; import { usersTable } from "@/db/schema"; -import { eq, desc, sql } from "drizzle-orm"; +import { eq, sql } from "drizzle-orm"; /** * Service class for handling user operations and database interactions. */ export class UserService { /** - * Retrieves specific profile information (firstName, lastName, color, online status, last login) for a user by ID. + * Retrieves specific profile information for a user by ID. * * @async * @param {string} userId - The unique identifier of the user. - * @returns {Promise<{ firstName: string; lastName: string; color: string; isOnline: boolean; lastLogin: Date } | null>} The user profile data or null if not found. + * @returns {Promise<{ id: string; firstName: string; lastName: string; email: string; color: string; isOnline: boolean; lastLogin: Date } | null>} The user profile data or null if not found. */ static async findProfileById(userId: string) { const [user] = await db .select({ + id: usersTable.id, firstName: usersTable.firstName, lastName: usersTable.lastName, + email: usersTable.email, color: usersTable.color, isOnline: usersTable.isOnline, lastLogin: usersTable.lastLogin, @@ -34,7 +36,7 @@ export class UserService { } /** - * Retrieves a list of all users sorted by their last login date in descending order, putting null values last. + * Retrieves a list of all users sorted by their last login date in descending order, placing null values last. * * @async * @returns {Promise>} An array of user list items.