+ );
+}
diff --git a/components/sidebar/MemberSidebar.tsx b/components/sidebar/MemberSidebar.tsx
deleted file mode 100644
index 27ce6c4..0000000
--- a/components/sidebar/MemberSidebar.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-/**
- * @file components/sidebar/MemberSidebar.tsx
- * @description Sidebar component displaying lists of online and offline channel members with avatar and status indicators.
- */
-
-/**
- * Renders the member sidebar showing categorized online and offline user statuses.
- *
- * @returns {JSX.Element} The rendered member sidebar interface.
- */
-export function MemberSidebar() {
- return (
-
- {/* Online Section */}
-
-
- Online — 1
-
-
-
-
-
- U
-
-
-
-
- User 1
-
-
-
-
-
- {/* Offline Section */}
-
-
- Offline — 2
-
-
-
-
-
- U
-
-
-
-
- User 2
-
-
-
-
-
-
- U
-
-
-
-
- User 3
-
-
-
-
-
- );
-}
diff --git a/db/schema.ts b/db/schema.ts
index 5477538..ef61380 100644
--- a/db/schema.ts
+++ b/db/schema.ts
@@ -22,6 +22,16 @@ import {
*/
export const roleEnum = pgEnum("role", ["OWNER", "ADMIN", "MEMBER"]);
+/**
+ * Enum representing online status of a user.
+ */
+export const userStatusEnum = pgEnum("user_status", [
+ "ONLINE",
+ "OFFLINE",
+ "IDLE",
+ "DND",
+]);
+
// ==========================================
// Tables
// ==========================================
@@ -35,6 +45,8 @@ export const users = pgTable("users", {
email: varchar("email", { length: 255 }).notNull().unique(),
password: text("password").notNull(),
color: varchar("color", { length: 50 }).default("bg-indigo-500").notNull(),
+ status: userStatusEnum("status").default("OFFLINE").notNull(),
+ lastSeenAt: timestamp("last_seen_at").defaultNow().notNull(),
createdAt: timestamp("created_at").defaultNow().notNull(),
});
@@ -160,3 +172,4 @@ export type Server = typeof servers.$inferSelect;
export type Member = typeof members.$inferSelect;
export type Channel = typeof channels.$inferSelect;
export type Message = typeof messages.$inferSelect;
+export type UserStatus = (typeof userStatusEnum.enumValues)[number];
diff --git a/lib/constants/member.styles.ts b/lib/constants/member.styles.ts
new file mode 100644
index 0000000..bd8307c
--- /dev/null
+++ b/lib/constants/member.styles.ts
@@ -0,0 +1,35 @@
+/**
+ * @file lib/constants/member.styles.ts
+ */
+
+import type { UserStatus } from "@/db/schema";
+
+/**
+ * Shared Tailwind CSS class constants mapping available member background color keys to their respective CSS utility classes.
+ */
+export const MEMBER_COLOR_CLASSES: Record = {
+ "bg-indigo-500": "bg-indigo-500",
+ "bg-emerald-500": "bg-emerald-500",
+ "bg-rose-500": "bg-rose-500",
+ "bg-amber-500": "bg-amber-500",
+ "bg-sky-500": "bg-sky-500",
+ "bg-violet-500": "bg-violet-500",
+ "bg-fuchsia-500": "bg-fuchsia-500",
+ "bg-cyan-500": "bg-cyan-500",
+};
+
+/**
+ * List of available color option class names for member icon selection.
+ * Dynamically generated from MEMBER_COLOR_OPTIONS to avoid duplicate maintenance.
+ */
+export const MEMBER_COLOR_OPTIONS = Object.keys(MEMBER_COLOR_CLASSES);
+
+/**
+ * Mapping of user status keys to their respective Tailwind CSS indicator background colors.
+ */
+export const MEMBER_STATUS_COLOR_CLASSES: Record = {
+ ONLINE: "bg-emerald-500",
+ IDLE: "bg-amber-500",
+ DND: "bg-rose-500",
+ OFFLINE: "bg-slate-500",
+};
diff --git a/lib/context/ServerContext.tsx b/lib/context/ServerContext.tsx
index 5e8badb..06fd1a9 100644
--- a/lib/context/ServerContext.tsx
+++ b/lib/context/ServerContext.tsx
@@ -1,6 +1,6 @@
/**
* @file lib/context/ServerContext.tsx
- * @description Context for managing active server state across sidebars and mobile drawers.
+ * @description Context for managing active server state and members across sidebars and mobile drawers.
*/
"use client";
@@ -14,49 +14,69 @@ import type { Server, Channel } from "@/db/schema";
export type ServerWithChannels = Server & { channels: Channel[] };
/**
- * Interface defining the shape of the ServerContext state and update functions.
+ * Represents a member within a server.
+ *
+ * @interface ServerMember
+ * @property {string} id - The unique identifier of the server member.
+ * @property {string} name - The display name of the server member.
+ * @property {boolean} [isOnline] - Optional flag indicating whether the member is currently online.
+ */
+export interface ServerMember {
+ id: string;
+ name: string;
+ isOnline?: boolean;
+}
+
+/**
+ * Interface defining the shape of the ServerContext state and update handlers.
*
* @interface ServerContextType
- * @property {ServerWithChannels | null} activeServer - The currently selected active server, or null if no server is active.
- * @property {(server: ServerWithChannels | null) => void} setActiveServer - Callback function to update the active server state.
+ * @property {ServerWithChannels | null} activeServer - The currently active server instance with its associated channels.
+ * @property {(server: ServerWithChannels | null) => void} setActiveServer - State setter function for updating the active server.
+ * @property {ServerMember[]} members - The list of members belonging to the active server.
+ * @property {(members: ServerMember[]) => void} setMembers - State setter function for updating the server members list.
*/
interface ServerContextType {
activeServer: ServerWithChannels | null;
setActiveServer: (server: ServerWithChannels | null) => void;
+ members: ServerMember[];
+ setMembers: (members: ServerMember[]) => void;
}
-/**
- * React Context instance for providing and consuming active server state.
- */
const ServerContext = createContext({
activeServer: null,
setActiveServer: () => {},
+ members: [],
+ setMembers: () => {},
});
/**
- * Context provider component that wraps the tree to manage and broadcast active server state.
+ * Provider component that wraps the application layout to provide global access to active server state and member listings.
*
- * @param {Object} props - The component props.
- * @param {React.ReactNode} props.children - The child components to be rendered within the context provider context.
- * @returns {JSX.Element} The rendered context provider wrapper.
+ * @param {Object} props - React component properties.
+ * @param {React.ReactNode} props.children - The child components wrapped by the provider.
+ * @returns {JSX.Element} The rendered React provider wrapping the child elements.
*/
export function ServerProvider({ children }: { children: React.ReactNode }) {
const [activeServer, setActiveServer] = useState(
null,
);
+ const [members, setMembers] = useState([]);
return (
-
+
{children}
);
}
/**
- * Custom hook to consume the ServerContext values.
+ * Custom hook to access the current ServerContext state.
*
- * @returns {ServerContextType} The active server context state and setter method.
- * @throws {Error} Throws an error if used outside of a ServerProvider wrapper.
+ * @throws {Error} Throws an error if used outside of a `ServerProvider`.
+ * @returns {ServerContextType} The server context value containing active server state and member management functions.
*/
export function useActiveServer() {
const context = useContext(ServerContext);
diff --git a/lib/services/member.service.ts b/lib/services/member.service.ts
new file mode 100644
index 0000000..7850471
--- /dev/null
+++ b/lib/services/member.service.ts
@@ -0,0 +1,36 @@
+/**
+ * @file lib/services/member.service.ts
+ * @description Service module providing data access functions for server members using Drizzle ORM.
+ */
+
+import { db } from "@/db";
+import { members, users } from "@/db/schema";
+import { eq } from "drizzle-orm";
+
+/**
+ * Retrieves all members belonging to a specific server, including user profile details.
+ *
+ * @async
+ * @function getServerMembers
+ * @param {string} serverId - The unique identifier of the server to fetch members for.
+ * @returns {Promise>} Array of member user profiles, or an empty array if an error occurs.
+ */
+export async function getServerMembers(serverId: string) {
+ try {
+ const result = await db
+ .select({
+ id: users.id,
+ username: users.username,
+ color: users.color,
+ status: users.status,
+ })
+ .from(members)
+ .innerJoin(users, eq(members.userId, users.id))
+ .where(eq(members.serverId, serverId));
+
+ return result;
+ } catch (error) {
+ console.error("Error fetching server members:", error);
+ return [];
+ }
+}