add hub get logic and part of client
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
# Discord-like Client Design
|
||||
|
||||
## Context
|
||||
|
||||
The go-socket backend has a full real-time messaging API (REST + WebSocket) but the React client is nearly empty — only `AuthPage` and an empty `MainApp` placeholder exist. This spec covers building the main app UI: a Discord-inspired layout with a connections/DM sidebar and chat panel, wired to the real backend.
|
||||
|
||||
## Layout
|
||||
|
||||
Two-column layout, full viewport height:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ [280px sidebar] │ [flex chat area] │
|
||||
│ │ │
|
||||
│ ○ ○ ○ + ← hub row │ Contact Name │
|
||||
│ ───────────────── │ ──────────────── │
|
||||
│ Search... │ │
|
||||
│ ▸ Contact A [3] │ [message history] │
|
||||
│ ▸ Contact B │ │
|
||||
│ ▸ ... │ ────────────────────── │
|
||||
│ ───────────────── │ [ type a message... ] ➤ │
|
||||
│ [avatar] You ⚙ │ │
|
||||
└──────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Sidebar (280px):**
|
||||
- Hub row: horizontal strip of small icon circles + a `+` stub button (empty for now, layout ready for hubs)
|
||||
- Search input to filter the connections list
|
||||
- Scrollable connections list: colored avatar circle (initial fallback), name, unread badge, last-message preview
|
||||
- Bottom bar: current user avatar + username + settings gear (stub — no action yet)
|
||||
|
||||
**Chat area:**
|
||||
- Header bar: contact name + pronouns
|
||||
- Scrollable message history (newest at bottom)
|
||||
- Message input + send button
|
||||
|
||||
## Components
|
||||
|
||||
```
|
||||
src/
|
||||
context/
|
||||
AppContext.jsx — connections, selectedId, messages, currentUser, ws ref
|
||||
components/
|
||||
MainApp.jsx — root layout, mounts context provider
|
||||
Sidebar.jsx — hub row + search + connection list + user bar
|
||||
HubRow.jsx — stub hub icons + add button
|
||||
ConnectionList.jsx — filtered, sorted list of ConnectionItem
|
||||
ConnectionItem.jsx — single row: avatar, name, unread badge, last message
|
||||
UserBar.jsx — bottom of sidebar: own avatar, name, settings gear stub
|
||||
ChatArea.jsx — header + message list + input bar
|
||||
MessageList.jsx — scrollable history, auto-scrolls to bottom on new message
|
||||
MessageItem.jsx — single message bubble: sender avatar, content, timestamp
|
||||
MessageInput.jsx — textarea + send button, Enter to send
|
||||
api/
|
||||
http.js — thin fetch wrapper; reads token from localStorage; sends token header
|
||||
ws.js — WebSocket singleton: connect, send, onMessage dispatcher
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
**On MainApp mount:**
|
||||
1. Read `token` + `userId` from localStorage (App.jsx already guards this route)
|
||||
2. `GET /connections` → load sidebar list
|
||||
3. `GET /connections/unreadmessages?connections=<ids>` → overlay unread counts
|
||||
4. Open WebSocket `ws://localhost:8080/ws`, on open send `{"token": "..."}`
|
||||
|
||||
**On connection selected:**
|
||||
1. `GET /connection/messages?connectionid=<id>` → render history
|
||||
2. Clear unread badge locally for that connection
|
||||
|
||||
**Sending a message:**
|
||||
1. `POST /connection/message` body: `connectionid`, `msgContent`
|
||||
2. Optimistically append to message list
|
||||
|
||||
**Incoming WebSocket events:**
|
||||
| Type | Action |
|
||||
|------|--------|
|
||||
| 1 — DirectMessage | Append to open chat if matches; else bump unread badge |
|
||||
| 2 — ConnectionCreated | Prepend new connection to sidebar |
|
||||
| 3 — ConnectionDeleted | Remove from sidebar; clear chat if open |
|
||||
| 4/5 — Elevated/DeElevated | Update connection `state` field (Friend/Stranger cosmetic label) |
|
||||
| 6/7/8 — Profile/Avatar/BgChange | Refresh contact display data |
|
||||
|
||||
## API Reference
|
||||
|
||||
All requests send `token` as a plain header (not Bearer). Token and userId stored in localStorage from login.
|
||||
|
||||
| Endpoint | Usage |
|
||||
|----------|-------|
|
||||
| `GET /connections` | Load sidebar list on mount |
|
||||
| `GET /connections/unreadmessages?connections=UUID,UUID` | Unread counts array |
|
||||
| `GET /connection/messages?connectionid=UUID` | Load history for selected DM |
|
||||
| `POST /connection/message` | Send message (body: connectionid, msgContent) |
|
||||
| `WS /ws` → send `{"token":"..."}` | Authenticate WebSocket |
|
||||
|
||||
## Design Aesthetic
|
||||
|
||||
- Dark theme (`bg-gray-900` base, matching existing `index.css`)
|
||||
- Natural, human-designed feel — no generic AI look
|
||||
- User-assigned color (RGBA from server) used as avatar background and accent
|
||||
- Subtle hover/active states, no heavy borders
|
||||
- Tailwind utility classes, no CSS files
|
||||
|
||||
## Out of Scope (this spec)
|
||||
|
||||
- Hub channels and hub management
|
||||
- User profile/customization UI (gear stub present, no action)
|
||||
- File attachments
|
||||
- Friend request flow (elevate/deelevate)
|
||||
- Connection creation UI
|
||||
|
||||
## Verification
|
||||
|
||||
1. `pnpm dev` in `client/` — app loads at localhost:5173
|
||||
2. Log in with existing credentials → redirects to MainApp
|
||||
3. Sidebar shows real connections from the server
|
||||
4. Clicking a connection loads message history
|
||||
5. Sending a message appears in the chat
|
||||
6. Open a second browser tab as another user — send a message → first tab receives it via WebSocket without refresh
|
||||
7. Unread badges update when a message arrives for a non-selected connection
|
||||
Reference in New Issue
Block a user