add hub menagment functions
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
---
|
||||
|
||||
## ▶ Continuation State (last updated 2026-04-28)
|
||||
## ▶ Continuation State (last updated 2026-04-29)
|
||||
|
||||
Pick up here if resuming on a new device or session.
|
||||
|
||||
@@ -18,8 +18,8 @@ Pick up here if resuming on a new device or session.
|
||||
| 4 | MainApp two-column layout | ✅ Done | |
|
||||
| 5 | HubRow + UserBar | ✅ Done | `colorToCss` extracted to `src/utils/color.js` (shared), stub buttons `disabled` |
|
||||
| 6 | ConnectionItem + ConnectionList + Sidebar | ✅ Done | `h-full` on Sidebar, search fallback for unresolved users, `min-w-0` truncate fix |
|
||||
| 7 | MessageItem + MessageList + MessageInput + ChatArea | 🔄 Created, review **interrupted** — needs spec + quality review before proceeding |
|
||||
| 8 | End-to-end verification | ⬜ Pending | Run `pnpm dev` in `client/`, manual browser smoke test (see task for steps) |
|
||||
| 7 | MessageItem + MessageList + MessageInput + ChatArea | ✅ Done | Spec + code-quality review passed 2026-04-29; rollback consistent with `sendMessage` rethrow |
|
||||
| 8 | End-to-end verification | ⏳ Manual only | Static import/dep check passed 2026-04-29. `pnpm dev` browser smoke test (auth, sidebar, DM round-trip, WS) is owner-driven. |
|
||||
|
||||
### Extra file created (not in original plan)
|
||||
|
||||
@@ -120,7 +120,7 @@ Pick up here if resuming on a new device or session.
|
||||
- Create: `client/src/api/http.js`
|
||||
- Create: `client/src/api/ws.js`
|
||||
|
||||
- [ ] **Step 1: Create `client/src/api/http.js`**
|
||||
- [x] **Step 1: Create `client/src/api/http.js`**
|
||||
|
||||
```js
|
||||
const BASE = 'http://localhost:8080'
|
||||
@@ -138,7 +138,7 @@ export async function apiFetch(method, path, { body, query } = {}) {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Create `client/src/api/ws.js`**
|
||||
- [x] **Step 2: Create `client/src/api/ws.js`**
|
||||
|
||||
```js
|
||||
let socket = null
|
||||
@@ -177,7 +177,7 @@ export function wsDisconnect() {
|
||||
|
||||
The login response is `{ token, userId }`. Both must be saved to localStorage — `userId` is needed to identify "my" messages and to fetch own profile.
|
||||
|
||||
- [ ] **Step 1: Replace `client/src/components/AuthPage.jsx` with wired version**
|
||||
- [x] **Step 1: Replace `client/src/components/AuthPage.jsx` with wired version**
|
||||
|
||||
```jsx
|
||||
import { useState } from 'react'
|
||||
@@ -277,7 +277,7 @@ export default function AuthPage() {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify in browser**
|
||||
- [x] **Step 2: Verify in browser** (owner-confirmed, prior session)
|
||||
|
||||
Run `pnpm dev` in `client/`. Navigate to `http://localhost:5173/auth`.
|
||||
- Enter valid credentials → should redirect to `/` (currently shows "Main App")
|
||||
@@ -293,7 +293,7 @@ Run `pnpm dev` in `client/`. Navigate to `http://localhost:5173/auth`.
|
||||
|
||||
`userMap` is a `{ [userId]: userDetails }` dict populated by fetching `GET /user` for each connection's "other" participant. The `selectedIdRef` keeps the WS handler in sync with the current selection without stale closures.
|
||||
|
||||
- [ ] **Step 1: Create `client/src/context/AppContext.jsx`**
|
||||
- [x] **Step 1: Create `client/src/context/AppContext.jsx`**
|
||||
|
||||
```jsx
|
||||
import { createContext, useContext, useReducer, useEffect, useRef, useCallback } from 'react'
|
||||
@@ -487,7 +487,7 @@ export function useApp() {
|
||||
**Files:**
|
||||
- Modify: `client/src/components/MainApp.jsx`
|
||||
|
||||
- [ ] **Step 1: Replace `client/src/components/MainApp.jsx`**
|
||||
- [x] **Step 1: Replace `client/src/components/MainApp.jsx`**
|
||||
|
||||
```jsx
|
||||
import { AppProvider } from '../context/AppContext'
|
||||
@@ -514,7 +514,7 @@ export default function MainApp() {
|
||||
- Create: `client/src/components/HubRow.jsx`
|
||||
- Create: `client/src/components/UserBar.jsx`
|
||||
|
||||
- [ ] **Step 1: Create `client/src/components/HubRow.jsx`**
|
||||
- [x] **Step 1: Create `client/src/components/HubRow.jsx`**
|
||||
|
||||
```jsx
|
||||
export default function HubRow() {
|
||||
@@ -531,7 +531,7 @@ export default function HubRow() {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Create `client/src/components/UserBar.jsx`**
|
||||
- [x] **Step 2: Create `client/src/components/UserBar.jsx`**
|
||||
|
||||
```jsx
|
||||
import { useApp } from '../context/AppContext'
|
||||
@@ -576,7 +576,7 @@ export default function UserBar() {
|
||||
- Create: `client/src/components/ConnectionList.jsx`
|
||||
- Create: `client/src/components/Sidebar.jsx`
|
||||
|
||||
- [ ] **Step 1: Create `client/src/components/ConnectionItem.jsx`**
|
||||
- [x] **Step 1: Create `client/src/components/ConnectionItem.jsx`**
|
||||
|
||||
The "other user" is whichever of `requestorId`/`recipientId` isn't our `userId`.
|
||||
|
||||
@@ -633,7 +633,7 @@ export default function ConnectionItem({ conn }) {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Create `client/src/components/ConnectionList.jsx`**
|
||||
- [x] **Step 2: Create `client/src/components/ConnectionList.jsx`**
|
||||
|
||||
```jsx
|
||||
import { useState } from 'react'
|
||||
@@ -675,7 +675,7 @@ export default function ConnectionList() {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Create `client/src/components/Sidebar.jsx`**
|
||||
- [x] **Step 3: Create `client/src/components/Sidebar.jsx`**
|
||||
|
||||
```jsx
|
||||
import HubRow from './HubRow'
|
||||
@@ -703,7 +703,7 @@ export default function Sidebar() {
|
||||
- Create: `client/src/components/MessageInput.jsx`
|
||||
- Create: `client/src/components/ChatArea.jsx`
|
||||
|
||||
- [ ] **Step 1: Create `client/src/components/MessageItem.jsx`**
|
||||
- [x] **Step 1: Create `client/src/components/MessageItem.jsx`**
|
||||
|
||||
Messages are displayed in Discord style: avatar + sender name on first message of a group, compact rows for consecutive same-sender messages.
|
||||
|
||||
@@ -761,7 +761,7 @@ export default function MessageItem({ msg, showHeader }) {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Create `client/src/components/MessageList.jsx`**
|
||||
- [x] **Step 2: Create `client/src/components/MessageList.jsx`**
|
||||
|
||||
Groups consecutive messages from the same sender so that only the first shows the header (avatar + name).
|
||||
|
||||
@@ -791,7 +791,7 @@ export default function MessageList() {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Create `client/src/components/MessageInput.jsx`**
|
||||
- [x] **Step 3: Create `client/src/components/MessageInput.jsx`**
|
||||
|
||||
```jsx
|
||||
import { useState, useRef } from 'react'
|
||||
@@ -845,7 +845,7 @@ export default function MessageInput() {
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Create `client/src/components/ChatArea.jsx`**
|
||||
- [x] **Step 4: Create `client/src/components/ChatArea.jsx`**
|
||||
|
||||
```jsx
|
||||
import { useApp } from '../context/AppContext'
|
||||
@@ -908,6 +908,8 @@ export default function ChatArea() {
|
||||
|
||||
## Task 8: End-to-End Verification
|
||||
|
||||
> Steps 1–6 require a running browser + backend and are owner-driven. Static verification done 2026-04-29: every Task 7 import resolves to an existing file, no missing dependencies in `package.json`.
|
||||
|
||||
- [ ] **Step 1: Start the dev server**
|
||||
|
||||
In `client/`:
|
||||
|
||||
Reference in New Issue
Block a user