|
1 | 1 | <script lang="ts"> |
2 | 2 | import { page } from "$app/state"; |
3 | 3 | import { trackedFetch } from "$lib/utils/trackedFetch"; |
4 | | - import type { OBPChatRoomParticipant } from "$lib/obp/types"; |
| 4 | + import type { OBPChatRoom, OBPChatRoomParticipant } from "$lib/obp/types"; |
5 | 5 |
|
6 | 6 | const chatRoomId = $derived(page.params.chat_room_id); |
7 | 7 | const level = $derived(page.url.searchParams.get("level") || "system"); |
8 | 8 | const bankId = $derived(page.url.searchParams.get("bank_id") || ""); |
9 | 9 |
|
| 10 | + let room = $state<OBPChatRoom | null>(null); |
10 | 11 | let participants = $state<OBPChatRoomParticipant[]>([]); |
11 | 12 | let loading = $state(false); |
12 | 13 | let error = $state<string | null>(null); |
|
16 | 17 | let addUserId = $state(""); |
17 | 18 | let addPermissions = $state("can_send_message"); |
18 | 19 |
|
| 20 | + async function fetchRoom() { |
| 21 | + if (!chatRoomId) return; |
| 22 | + try { |
| 23 | + const bankParam = bankId ? `?bank_id=${encodeURIComponent(bankId)}` : ""; |
| 24 | + const res = await trackedFetch( |
| 25 | + `/proxy/obp/v6.0.0/chat-rooms/${encodeURIComponent(chatRoomId)}${bankParam}`, |
| 26 | + ); |
| 27 | + if (!res.ok) { |
| 28 | + const data = await res.json().catch(() => ({})); |
| 29 | + throw new Error(data.error || "Failed to fetch chat room"); |
| 30 | + } |
| 31 | + room = await res.json(); |
| 32 | + } catch (err) { |
| 33 | + error = err instanceof Error ? err.message : "Failed to fetch chat room"; |
| 34 | + room = null; |
| 35 | + } |
| 36 | + } |
| 37 | +
|
19 | 38 | async function fetchParticipants() { |
20 | 39 | if (!chatRoomId) return; |
21 | 40 | loading = true; |
|
69 | 88 | } |
70 | 89 | } |
71 | 90 |
|
| 91 | + async function refreshJoiningKey() { |
| 92 | + if (!chatRoomId) return; |
| 93 | + error = null; |
| 94 | + successMessage = null; |
| 95 | + try { |
| 96 | + const endpoint = |
| 97 | + level === "bank" && bankId |
| 98 | + ? `/proxy/obp/v6.0.0/banks/${encodeURIComponent(bankId)}/chat-rooms/${encodeURIComponent(chatRoomId)}/joining-key` |
| 99 | + : `/proxy/obp/v6.0.0/chat-rooms/${encodeURIComponent(chatRoomId)}/joining-key`; |
| 100 | + const res = await trackedFetch(endpoint, { method: "PUT" }); |
| 101 | + if (!res.ok) { |
| 102 | + const data = await res.json().catch(() => ({})); |
| 103 | + throw new Error(data.error || "Failed to refresh joining key"); |
| 104 | + } |
| 105 | + successMessage = "Joining key refreshed."; |
| 106 | + fetchRoom(); |
| 107 | + } catch (err) { |
| 108 | + error = err instanceof Error ? err.message : "Failed to refresh joining key"; |
| 109 | + } |
| 110 | + } |
| 111 | +
|
| 112 | + async function copyJoiningKey() { |
| 113 | + if (!room?.joining_key) return; |
| 114 | + try { |
| 115 | + await navigator.clipboard.writeText(room.joining_key); |
| 116 | + successMessage = "Joining key copied."; |
| 117 | + } catch { |
| 118 | + error = "Could not copy to clipboard."; |
| 119 | + } |
| 120 | + } |
| 121 | +
|
72 | 122 | async function removeParticipant(userId: string) { |
73 | 123 | if (!chatRoomId) return; |
74 | 124 | error = null; |
|
105 | 155 | } |
106 | 156 |
|
107 | 157 | $effect(() => { |
| 158 | + fetchRoom(); |
108 | 159 | fetchParticipants(); |
109 | 160 | }); |
110 | 161 | </script> |
|
135 | 186 | Participants: {participants.length} |
136 | 187 | </span> |
137 | 188 | {/if} |
138 | | - <button |
139 | | - onclick={() => (showAddForm = !showAddForm)} |
140 | | - class="inline-flex items-center rounded-lg bg-blue-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600" |
141 | | - data-testid="add-participant-btn" |
142 | | - > |
143 | | - {showAddForm ? "Cancel" : "Add Participant"} |
144 | | - </button> |
| 189 | + {#if !room?.is_open_room} |
| 190 | + <button |
| 191 | + onclick={() => (showAddForm = !showAddForm)} |
| 192 | + class="inline-flex items-center rounded-lg bg-blue-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600" |
| 193 | + data-testid="add-participant-btn" |
| 194 | + > |
| 195 | + {showAddForm ? "Cancel" : "Add Participant"} |
| 196 | + </button> |
| 197 | + {/if} |
145 | 198 | </div> |
146 | 199 | </div> |
147 | 200 |
|
| 201 | +{#if room && !room.is_open_room && room.joining_key} |
| 202 | + <div class="mb-4 rounded-lg border border-gray-200 bg-white p-3 dark:border-gray-700 dark:bg-gray-800" data-testid="joining-key-panel"> |
| 203 | + <div class="flex flex-wrap items-center gap-3"> |
| 204 | + <span class="text-sm font-medium text-gray-700 dark:text-gray-300">Joining Key:</span> |
| 205 | + <code class="flex-1 min-w-0 truncate rounded bg-gray-100 px-2 py-1 font-mono text-sm text-gray-900 dark:bg-gray-900 dark:text-gray-100" data-testid="joining-key-value">{room.joining_key}</code> |
| 206 | + <button |
| 207 | + onclick={copyJoiningKey} |
| 208 | + class="inline-flex items-center rounded border border-gray-300 bg-white px-2 py-1 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600" |
| 209 | + data-testid="copy-joining-key-btn" |
| 210 | + > |
| 211 | + Copy |
| 212 | + </button> |
| 213 | + <button |
| 214 | + onclick={refreshJoiningKey} |
| 215 | + class="inline-flex items-center rounded border border-gray-300 bg-white px-2 py-1 text-xs font-medium text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:bg-gray-700 dark:text-gray-200 dark:hover:bg-gray-600" |
| 216 | + data-testid="refresh-joining-key-btn" |
| 217 | + > |
| 218 | + Refresh |
| 219 | + </button> |
| 220 | + </div> |
| 221 | + </div> |
| 222 | +{/if} |
| 223 | + |
148 | 224 | {#if successMessage} |
149 | 225 | <div class="mb-4 rounded-lg border border-green-200 bg-green-50 p-3 text-sm text-green-800 dark:border-green-800 dark:bg-green-900/20 dark:text-green-200" data-testid="success-message"> |
150 | 226 | {successMessage} |
|
258 | 334 | </table> |
259 | 335 | </div> |
260 | 336 | {:else if !error} |
261 | | - <div class="rounded-lg bg-gray-100 p-8 text-center dark:bg-gray-800"> |
262 | | - <p class="text-lg font-medium text-gray-700 dark:text-gray-300"> |
263 | | - No participants found |
264 | | - </p> |
265 | | - <p class="mt-1 text-gray-600 dark:text-gray-400"> |
266 | | - Add a participant to this chat room. |
267 | | - </p> |
| 337 | + <div class="rounded-lg bg-gray-100 p-8 text-center dark:bg-gray-800" data-testid="empty-participants"> |
| 338 | + {#if room?.is_open_room} |
| 339 | + <p class="text-lg font-medium text-gray-700 dark:text-gray-300" data-testid="everyone-label"> |
| 340 | + This room is Open. Everyone can join. |
| 341 | + </p> |
| 342 | + {:else} |
| 343 | + <p class="text-lg font-medium text-gray-700 dark:text-gray-300"> |
| 344 | + No participants found |
| 345 | + </p> |
| 346 | + <p class="mt-1 text-gray-600 dark:text-gray-400"> |
| 347 | + Add a participant to this chat room. |
| 348 | + </p> |
| 349 | + {/if} |
268 | 350 | </div> |
269 | 351 | {/if} |
0 commit comments