Task #31: Let people leave, mute, or archive a group chat

Adds per-user mute / archive / leave actions for chats.

Schema:
- `lib/db/src/schema/conversations.ts`: added `is_muted` and
  `is_archived` boolean columns on `conversation_participants`.
- Columns applied directly via SQL (drizzle push wanted to make
  unrelated app_opens decisions; force-applied is_muted/is_archived
  with `ALTER TABLE ... ADD COLUMN IF NOT EXISTS`).

API (`artifacts/api-server/src/routes/conversations.ts`):
- New endpoint `PATCH /conversations/:id/state` — current user
  toggles their own `isMuted` / `isArchived`.
- New endpoint `POST /conversations/:id/leave` — removes the
  caller from a group conversation; rejects DMs.
- `buildConversationDetails` now returns `isMuted` and
  `isArchived` for the requesting user.
- `sendMessage` auto-clears `isArchived` for all participants so
  archived chats reappear when a new message arrives.

OpenAPI (`lib/api-spec/openapi.yaml`):
- Added the two new operations and `UpdateConversationStateBody`.
- Added `isMuted` / `isArchived` to `ConversationWithDetails`.
- Re-ran codegen for `@workspace/api-zod` and
  `@workspace/api-client-react`.

UI (`artifacts/teaboy-os/src/pages/chat.tsx`):
- Header gets a kebab "chat actions" button visible for both DMs
  and groups when a conversation is open.
- Action sheet offers Mute/Unmute, Archive/Unarchive, and
  (groups only) Leave with a confirmation dialog.
- Conversation list now has Active / Archived tabs and a
  bell-off indicator + dimmed unread badge for muted chats.
- Bilingual strings added to en.json and ar.json.

Side fixes (unrelated pre-existing schema drift discovered while
testing): added missing `users.clock_hour12` and
`conversations.avatar_url` columns directly so login and the
conversations list work; the schema files already declared them.

Verified end-to-end with the testing tool: mute, archive,
unarchive, and leave-group flows all pass.
This commit is contained in:
Riyadh
2026-04-21 08:29:01 +00:00
parent 78b51b9112
commit 90a7a807e9
10 changed files with 768 additions and 14 deletions
+58
View File
@@ -729,6 +729,50 @@ paths:
schema:
$ref: "#/components/schemas/ConversationWithDetails"
/conversations/{id}/state:
patch:
operationId: updateConversationState
tags: [conversations]
summary: Update per-user state (mute, archive)
parameters:
- name: id
in: path
required: true
schema:
type: integer
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/UpdateConversationStateBody"
responses:
"200":
description: Updated conversation
content:
application/json:
schema:
$ref: "#/components/schemas/ConversationWithDetails"
/conversations/{id}/leave:
post:
operationId: leaveConversation
tags: [conversations]
summary: Leave a group conversation
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
"200":
description: Left conversation
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessResponse"
/conversations/{id}/messages:
get:
operationId: listMessages
@@ -1458,6 +1502,10 @@ components:
nullable: true
unreadCount:
type: integer
isMuted:
type: boolean
isArchived:
type: boolean
createdAt:
type: string
format: date-time
@@ -1470,6 +1518,8 @@ components:
- createdBy
- participants
- unreadCount
- isMuted
- isArchived
- createdAt
- updatedAt
@@ -1521,6 +1571,14 @@ components:
nameEn:
type: ["string", "null"]
UpdateConversationStateBody:
type: object
properties:
isMuted:
type: boolean
isArchived:
type: boolean
AddParticipantsBody:
type: object
properties: