Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions docs/database-schema-message.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Message Database Schema Relations

This document outlines the database schema relations for the `messages` table within IntelliCircle, as defined in `packages/shared/src/schema.ts`.

## The `messages` Table
The `messages` table stores the core chat content for the application.

### Columns
- `id`: Serial Primary Key
- `roomId`: Integer (Foreign Key to `chatRooms.id`)
- `userId`: Integer (Foreign Key to `users.id`)
- `content`: Text (Not Null)
- `createdAt`: Timestamp (Defaults to now)

### Relationships
1. **Belongs to a Room:**
Each message is tied to exactly one chat room via `roomId`.
2. **Belongs to a User:**
Each message is authored by exactly one user via `userId`.

### Indexes
- `roomHistoryIdx`: A composite index on `(roomId, createdAt)` exists to optimize the fetching of room message history in chronological order.

### Drizzle ORM Definition
```typescript
export const messages = pgTable("messages", {
id: serial("id").primaryKey(),
roomId: integer("room_id").notNull(),
userId: integer("user_id").notNull(),
content: text("content").notNull(),
createdAt: timestamp("created_at").notNull().defaultNow(),
}, (table) => {
return {
roomHistoryIdx: index("message_room_created_idx").on(table.roomId, table.createdAt),
};
});
```
82 changes: 82 additions & 0 deletions packages/client/src/app/(app)/dashboard/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { Activity, Compass, MessageSquare, Target } from "lucide-react";

export default function DashboardLoading() {
return (
<div className="flex-1 w-full bg-background flex flex-col animate-pulse">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-10 w-full flex-grow">
{/* Header Section Skeleton */}
<div className="mb-10">
<div className="h-10 w-64 bg-white/10 rounded mb-4"></div>
<div className="h-6 w-96 bg-white/5 rounded"></div>
</div>

{/* Main Dashboard Grid Skeleton */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">

{/* Left Column Skeleton */}
<div className="lg:col-span-2 flex flex-col gap-8">
{/* Action Cards Skeleton */}
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="p-6 rounded-2xl bg-[#111827] border border-[#27272a] h-48">
<Compass className="w-8 h-8 text-white/20 mb-4" />
<div className="h-6 w-32 bg-white/10 rounded mb-4"></div>
<div className="h-4 w-full bg-white/5 rounded mb-2"></div>
<div className="h-4 w-3/4 bg-white/5 rounded"></div>
</div>
<div className="p-6 rounded-2xl bg-[#111827] border border-[#27272a] h-48">
<MessageSquare className="w-8 h-8 text-white/20 mb-4" />
<div className="h-6 w-32 bg-white/10 rounded mb-4"></div>
<div className="h-4 w-full bg-white/5 rounded mb-2"></div>
<div className="h-4 w-3/4 bg-white/5 rounded"></div>
</div>
</div>

{/* Recent Activity/Feed Section Skeleton */}
<div className="bg-[#111827] rounded-2xl border border-[#27272a] p-6 flex flex-col flex-grow h-64">
<div className="flex items-center justify-between mb-6">
<div className="flex items-center">
<Activity className="w-5 h-5 mr-2 text-white/20" />
<div className="h-6 w-40 bg-white/10 rounded"></div>
</div>
<div className="h-4 w-16 bg-white/10 rounded"></div>
</div>
<div className="flex-1 border-2 border-dashed border-[#27272a] rounded-xl bg-background/50"></div>
</div>
</div>

{/* Right Column Skeleton */}
<div className="flex flex-col gap-6">
{/* Mini Profile Card Skeleton */}
<div className="bg-[#111827] rounded-2xl border border-[#27272a] p-6 text-center">
<div className="w-20 h-20 rounded-full bg-white/10 mx-auto mb-4"></div>
<div className="h-6 w-24 bg-white/10 rounded mx-auto mb-6"></div>

<div className="grid grid-cols-2 gap-2 border-t border-white/10 pt-4">
<div>
<div className="h-8 w-8 bg-white/10 rounded mx-auto mb-2"></div>
<div className="h-3 w-16 bg-white/5 rounded mx-auto"></div>
</div>
<div className="border-l border-white/10">
<div className="h-8 w-8 bg-white/10 rounded mx-auto mb-2"></div>
<div className="h-3 w-16 bg-white/5 rounded mx-auto"></div>
</div>
</div>
</div>

{/* Suggestions Block Skeleton */}
<div className="bg-[#111827] rounded-2xl border border-[#27272a] p-6 flex-grow">
<div className="flex items-center mb-4">
<Target className="w-5 h-5 mr-2 text-white/20" />
<div className="h-6 w-32 bg-white/10 rounded"></div>
</div>
<div className="space-y-4">
<div className="bg-background/80 p-4 rounded-xl h-24 border border-white/5"></div>
<div className="bg-background/80 p-4 rounded-xl h-24 border border-white/5"></div>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
10 changes: 2 additions & 8 deletions packages/client/src/app/(app)/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useRouter } from "next/navigation";
import { useEffect } from "react";
import Link from "next/link";
import { Compass, MessageSquare, Users, Activity, ChevronRight, Zap, Target } from "lucide-react";
import DashboardLoading from "./loading";

export default function Dashboard() {
const { isAuthenticated, user } = useAuthStore();
Expand All @@ -17,14 +18,7 @@ export default function Dashboard() {
}, [isAuthenticated, router]);

if (!isAuthenticated || !user) {
return (
<div className="flex-1 flex items-center justify-center p-8">
<div className="animate-pulse flex flex-col items-center">
<div className="w-12 h-12 bg-white/10 rounded-full mb-4"></div>
<div className="h-4 w-32 bg-white/10 rounded"></div>
</div>
</div>
);
return <DashboardLoading />;
}

return (
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/components/auth-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export const AuthModal = () => {
{mounted && createPortal(
<AnimatePresence>
{isOpen && (
<div className="fixed inset-0 z-[9999] flex items-center justify-center p-4">
<div className="fixed inset-0 z-[99999] flex items-center justify-center p-4">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
Expand Down
11 changes: 9 additions & 2 deletions packages/shared/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export const participants = pgTable(

// Waitlist Schemas
export const insertWaitlistSchema = z.object({
email: z.string().email(),
email: z.string().email().trim().toLowerCase(),
name: z.string().optional(),
profession: z.string().optional()
});
Expand All @@ -113,7 +113,7 @@ export const anonymousAuthSchema = z.object({
});

export const upgradeAuthSchema = z.object({
email: z.string().email(),
email: z.string().email().trim().toLowerCase(),
password: z.string()
.min(8, "Password must be at least 8 characters long")
.regex(/[A-Z]/, "Password must contain at least one uppercase letter")
Expand Down Expand Up @@ -153,3 +153,10 @@ export const nearbyRoomsQuerySchema = z.object({
interests: z.union([z.string(), z.array(z.string())]).optional()
.transform(val => Array.isArray(val) ? val : (val ? [val] : []))
});

// --- WebSocket Schemas ---
export const userJoinedPayloadSchema = z.object({
userId: z.number(),
roomId: z.number(),
timestamp: z.date().default(() => new Date()),
});