# Frontend Integration Guide — Recent API Changes

This guide covers the features added in the latest backend update:

1. **Comment / reply management** on voice posts (edit, delete, report)
2. **Delete sent chat message** in DMs

**Base URL:** `{HOST}/api/v1` (see `API_PREFIX` in backend `.env`)

**Auth:** All endpoints require:

```
Authorization: Bearer <JWT>
```

**Standard success response:**

```json
{
  "status": 200,
  "success": true,
  "message": "...",
  "data": { }
}
```

**Standard error response:**

```json
{
  "statusCode": 400,
  "success": false,
  "message": "Human-readable error message"
}
```

---

## 1. Comments & Replies (Voice Posts)

Comments and nested replies use the same `Reply` model. The `:id` in all comment endpoints is the **comment/reply `_id`**.

Existing fetch endpoint (unchanged):

```
GET /voice-posts/:postId/comments?page=1&limit=10
```

Deleted comments are **not returned** in this list (`isDeleted: false` filter on the backend).

### 1.1 Permission matrix (UI logic)

| Action | Show control when |
|--------|-------------------|
| **Edit** | `comment.user._id === currentUser.profileId` |
| **Delete** | `comment.user._id === currentUser.profileId` **OR** `post.user._id === currentUser.profileId` |
| **Report** | Any authenticated user (recommend hiding on own comments) |

> Use `profileId` from the JWT payload for comparisons — not `authId`.

---

### 1.2 Delete comment or reply

```
DELETE /voice-posts/comment/:id
```

**Who can call:** Comment author **or** voice post creator.

**Behavior:**
- Soft-deletes the comment and **all nested replies** under it.
- Removes the comment from the post or parent reply `replies` array.
- No socket event — update the UI optimistically or refetch comments after success.

**Success (`200`):**

```json
{
  "status": 200,
  "success": true,
  "message": "Comment deleted successfully",
  "data": {}
}
```

**Errors:**

| Status | Message |
|--------|---------|
| 400 | Authentication required |
| 403 | You are not authorized to delete this comment |
| 404 | Comment not found / Post not found |

**Example (fetch):**

```ts
async function deleteComment(commentId: string, token: string) {
  const res = await fetch(`${API_BASE}/voice-posts/comment/${commentId}`, {
    method: 'DELETE',
    headers: { Authorization: `Bearer ${token}` },
  });
  const body = await res.json();
  if (!body.success) throw new Error(body.message);
  return body;
}
```

**UI recommendation:** After delete, remove the comment node (and its reply subtree) from local state, or refetch `GET /voice-posts/:postId/comments`.

---

### 1.3 Edit comment or reply

```
POST /voice-posts/comment/:id/edit
Content-Type: multipart/form-data
```

**Who can call:** Comment author only.

**Body (multipart):**

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `audio` | file | No* | New voice recording (mp3/wav/webm/ogg, max 50MB) |
| `duration` | number/string | No* | Duration in seconds |

\* At least one of `audio` or `duration` must be sent.

**Success (`200`):**

```json
{
  "status": 200,
  "success": true,
  "message": "Comment edited successfully",
  "data": {
    "comment": {
      "_id": "...",
      "user": "...",
      "audioUrl": "...",
      "duration": 45,
      "post": "...",
      "parentReply": null,
      "isDeleted": false,
      "createdAt": "...",
      "updatedAt": "..."
    }
  }
}
```

**Errors:**

| Status | Message |
|--------|---------|
| 400 | No changes provided / Invalid audio file |
| 403 | You are not authorized to edit this comment |
| 404 | Comment not found |

**Example (FormData):**

```ts
async function editComment(
  commentId: string,
  token: string,
  audioFile?: File,
  duration?: number
) {
  const form = new FormData();
  if (audioFile) form.append('audio', audioFile);
  if (duration != null) form.append('duration', String(duration));

  const res = await fetch(`${API_BASE}/voice-posts/comment/${commentId}/edit`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${token}` },
    body: form,
  });
  const body = await res.json();
  if (!body.success) throw new Error(body.message);
  return body.data.comment;
}
```

**UI recommendation:** Open a re-record flow (same as creating a reply), then PATCH local state with `data.comment` on success.

---

### 1.4 Report comment or reply

```
POST /report/comment/:id/create
Content-Type: application/json
```

**Body:**

```json
{
  "reason": "Harassment"
}
```

`reason` is **required**.

**Success (`200`):**

```json
{
  "status": 200,
  "success": true,
  "message": "Comment reported successfully",
  "data": {
    "report": {
      "_id": "...",
      "reporter": "...",
      "comment": "...",
      "post": "...",
      "reason": "Harassment",
      "type": "comment",
      "status": "unresolved",
      "createdAt": "...",
      "updatedAt": "..."
    }
  }
}
```

**Errors:**

| Status | Message |
|--------|---------|
| 400 | Report reason is required / You have already reported this comment |
| 404 | Comment not found |

**Example:**

```ts
async function reportComment(commentId: string, reason: string, token: string) {
  const res = await fetch(`${API_BASE}/report/comment/${commentId}/create`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ reason }),
  });
  const body = await res.json();
  if (!body.success) throw new Error(body.message);
  return body.data.report;
}
```

**UI recommendation:** Show a reason picker/modal. After success, disable the report button or show “Reported”.

---

### 1.5 Withdraw comment report

```
POST /report/comment/:id/withdraw
```

No body required.

**Success (`200`):**

```json
{
  "status": 200,
  "success": true,
  "message": "Comment report withdrawn successfully",
  "data": {}
}
```

**Errors:**

| Status | Message |
|--------|---------|
| 400 | You have not reported this comment / Report already resolved / Report already dismissed |
| 404 | Comment not found |

**Listing user's comment reports** (existing endpoint):

```
GET /report?type=comment&page=1&limit=10
```

Default `type` is `post` — pass `type=comment` to fetch comment reports only.

---

## 2. Delete Sent Chat Message

```
DELETE /chat/conversations/:conversationId/messages/:messageId
```

**Who can call:** The message **sender** only (`profileId` must match `message.sender`).

**Behavior:**
- Soft-deletes the message (`isDeleted: true`).
- Deleted messages are excluded from `GET /chat/conversations/:conversationId/messages`.
- If the deleted message was the conversation `lastMessage`, the backend rolls back to the previous message (or clears `lastMessage`).
- Emits real-time socket events (see §2.2).

**Success (`200`):**

```json
{
  "status": 200,
  "success": true,
  "message": "Message deleted successfully",
  "data": {}
}
```

**Errors:**

| Status | Message |
|--------|---------|
| 403 | You can only delete your own messages |
| 404 | Conversation not found or access denied / Message not found |
| 500 | Failed to delete message |

**Example:**

```ts
async function deleteChatMessage(
  conversationId: string,
  messageId: string,
  token: string
) {
  const res = await fetch(
    `${API_BASE}/chat/conversations/${conversationId}/messages/${messageId}`,
    {
      method: 'DELETE',
      headers: { Authorization: `Bearer ${token}` },
    }
  );
  const body = await res.json();
  if (!body.success) throw new Error(body.message);
}
```

### 2.1 UI logic

- Show **Delete** only on messages where `message.sender._id === currentUser.profileId`.
- Typical UX: long-press menu or swipe action on own messages.
- On success: remove the message from the local messages list immediately (optimistic) or wait for API + socket confirmation.

### 2.2 Socket events (real-time)

Ensure the client is connected and joined to the conversation room (existing `join_conversation` flow).

**Listen for `message_deleted`** (conversation room `conversation_{conversationId}`):

```json
{
  "conversationId": "664f1a2b3c4d5e6f7a8b9c0d",
  "messageId": "664f1a2b3c4d5e6f7a8b9c0e"
}
```

**Handler:**

```ts
socket.on('message_deleted', ({ conversationId, messageId }) => {
  if (activeConversationId === conversationId) {
    removeMessageFromState(messageId);
  }
});
```

**Listen for `chat_list_updated`** (user room `user_{profileId}`) — fired to the **other** participant when a last-message changes:

```json
{
  "conversationId": "...",
  "unreadCount": 0,
  "lastMessage": {
    "_id": "...",
    "type": "voice",
    "audioUrl": "...",
    "duration": 12,
    "sender": "...",
    "timestamp": "2026-06-22T10:00:00.000Z"
  }
}
```

`lastMessage` may be `null` if all messages in the conversation were deleted.

**Handler:**

```ts
socket.on('chat_list_updated', ({ conversationId, unreadCount, lastMessage }) => {
  updateConversationInList(conversationId, { unreadCount, lastMessage });
});
```

> The deleting user should update their own UI from the DELETE response. `chat_list_updated` is primarily for the recipient's inbox preview.

---

## 3. Quick reference

| Feature | Method | Endpoint |
|---------|--------|----------|
| Delete comment/reply | `DELETE` | `/voice-posts/comment/:id` |
| Edit comment/reply | `POST` | `/voice-posts/comment/:id/edit` |
| Report comment/reply | `POST` | `/report/comment/:id/create` |
| Withdraw comment report | `POST` | `/report/comment/:id/withdraw` |
| Delete chat message | `DELETE` | `/chat/conversations/:conversationId/messages/:messageId` |

---

## 4. Suggested frontend checklist

### Comments on posts
- [ ] Context menu on each comment/reply with Edit / Delete / Report
- [ ] Edit visible only to comment author
- [ ] Delete visible to comment author **and** post creator
- [ ] Report opens reason modal; handle duplicate-report error (`400`)
- [ ] Remove deleted comment subtree from UI or refetch comments
- [ ] Re-record audio flow for edit (multipart upload)

### Chat messages
- [ ] Delete action on own messages only
- [ ] `message_deleted` socket listener in active chat screen
- [ ] `chat_list_updated` socket listener on conversation list screen
- [ ] Handle `lastMessage: null` in conversation list preview

### Shared
- [ ] Send `Authorization: Bearer <token>` on every request
- [ ] Compare user IDs using `profileId` (not `authId`) for comment ownership
- [ ] Surface `message` from error responses to the user
