vue-parley 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +276 -0
- package/dist/chat.css +3223 -0
- package/dist/chunks/Call-CTIujxDi.cjs +818 -0
- package/dist/chunks/Call-CTIujxDi.cjs.map +1 -0
- package/dist/chunks/Call-Dwuyd-Ut.mjs +818 -0
- package/dist/chunks/Call-Dwuyd-Ut.mjs.map +1 -0
- package/dist/chunks/index-D50Yn7q4.cjs +7031 -0
- package/dist/chunks/index-D50Yn7q4.cjs.map +1 -0
- package/dist/chunks/index-JU_JZkSC.mjs +7010 -0
- package/dist/chunks/index-JU_JZkSC.mjs.map +1 -0
- package/dist/chunks/session-B3KIrj3_.mjs +711 -0
- package/dist/chunks/session-B3KIrj3_.mjs.map +1 -0
- package/dist/chunks/session-BOfkV8PJ.cjs +711 -0
- package/dist/chunks/session-BOfkV8PJ.cjs.map +1 -0
- package/dist/fakes.cjs +335 -0
- package/dist/fakes.cjs.map +1 -0
- package/dist/fakes.mjs +335 -0
- package/dist/fakes.mjs.map +1 -0
- package/dist/index.cjs +24 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +24 -0
- package/dist/index.mjs.map +1 -0
- package/dist/types/app/components/ChatPage.vue.d.ts +60 -0
- package/dist/types/app/components/ChatPage.vue.d.ts.map +1 -0
- package/dist/types/app/components/call/Call.vue.d.ts +8 -0
- package/dist/types/app/components/call/Call.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/ChatBubble.vue.d.ts +64 -0
- package/dist/types/app/components/chat/ChatBubble.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/ChatInput.vue.d.ts +60 -0
- package/dist/types/app/components/chat/ChatInput.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/ChatMessages.vue.d.ts +45 -0
- package/dist/types/app/components/chat/ChatMessages.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/ChatPageBar.vue.d.ts +50 -0
- package/dist/types/app/components/chat/ChatPageBar.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/ChatProfileOverview.vue.d.ts +11 -0
- package/dist/types/app/components/chat/ChatProfileOverview.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/ChatView.vue.d.ts +244 -0
- package/dist/types/app/components/chat/ChatView.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleDivider.vue.d.ts +7 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleDivider.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleImages.vue.d.ts +13 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleImages.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleMeta.vue.d.ts +11 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleMeta.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleOptions.vue.d.ts +16 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleOptions.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleRequest.vue.d.ts +8 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleRequest.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleSelectionMark.vue.d.ts +7 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleSelectionMark.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleStatus.vue.d.ts +7 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleStatus.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleVideo.vue.d.ts +25 -0
- package/dist/types/app/components/chat/chat-bubbles/BubbleVideo.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/FileDisplay.vue.d.ts +13 -0
- package/dist/types/app/components/chat/chat-bubbles/FileDisplay.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/ImageGroupDisplay.vue.d.ts +14 -0
- package/dist/types/app/components/chat/chat-bubbles/ImageGroupDisplay.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/ReplyPreview.vue.d.ts +10 -0
- package/dist/types/app/components/chat/chat-bubbles/ReplyPreview.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/UploadProgressOverlay.vue.d.ts +10 -0
- package/dist/types/app/components/chat/chat-bubbles/UploadProgressOverlay.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-bubbles/VoiceDisplay.vue.d.ts +12 -0
- package/dist/types/app/components/chat/chat-bubbles/VoiceDisplay.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-input/AttachementFileDisplay.vue.d.ts +12 -0
- package/dist/types/app/components/chat/chat-input/AttachementFileDisplay.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-input/InputActionBar.vue.d.ts +13 -0
- package/dist/types/app/components/chat/chat-input/InputActionBar.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-input/InputAttachement.vue.d.ts +18 -0
- package/dist/types/app/components/chat/chat-input/InputAttachement.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-input/PermissionPopup.vue.d.ts +8 -0
- package/dist/types/app/components/chat/chat-input/PermissionPopup.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-input/RecordButton.vue.d.ts +27 -0
- package/dist/types/app/components/chat/chat-input/RecordButton.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-input/RecordingStatus.vue.d.ts +12 -0
- package/dist/types/app/components/chat/chat-input/RecordingStatus.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/chat-input/VideoRecordDisplay.vue.d.ts +26 -0
- package/dist/types/app/components/chat/chat-input/VideoRecordDisplay.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/contact/ChatContactDisplay.vue.d.ts +8 -0
- package/dist/types/app/components/chat/contact/ChatContactDisplay.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/contact/ChatList.vue.d.ts +5 -0
- package/dist/types/app/components/chat/contact/ChatList.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/contact/ChatListSearch.vue.d.ts +16 -0
- package/dist/types/app/components/chat/contact/ChatListSearch.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/contact/ContactAvatar.vue.d.ts +10 -0
- package/dist/types/app/components/chat/contact/ContactAvatar.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/contact/ContactSkeleton.vue.d.ts +3 -0
- package/dist/types/app/components/chat/contact/ContactSkeleton.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/messages/FloatingDateHeader.vue.d.ts +9 -0
- package/dist/types/app/components/chat/messages/FloatingDateHeader.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/messages/MessagesSkeleton.vue.d.ts +8 -0
- package/dist/types/app/components/chat/messages/MessagesSkeleton.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/messages/ScrollToBottomButton.vue.d.ts +11 -0
- package/dist/types/app/components/chat/messages/ScrollToBottomButton.vue.d.ts.map +1 -0
- package/dist/types/app/components/chat/profile/FileDisplay.vue.d.ts +9 -0
- package/dist/types/app/components/chat/profile/FileDisplay.vue.d.ts.map +1 -0
- package/dist/types/app/components/general/ConfirmModal.vue.d.ts +21 -0
- package/dist/types/app/components/general/ConfirmModal.vue.d.ts.map +1 -0
- package/dist/types/app/components/general/FileFormatDisplay.vue.d.ts +16 -0
- package/dist/types/app/components/general/FileFormatDisplay.vue.d.ts.map +1 -0
- package/dist/types/app/components/general/IconButton.vue.d.ts +13 -0
- package/dist/types/app/components/general/IconButton.vue.d.ts.map +1 -0
- package/dist/types/app/components/general/LoadingStatus.vue.d.ts +16 -0
- package/dist/types/app/components/general/LoadingStatus.vue.d.ts.map +1 -0
- package/dist/types/app/components/general/MediaImage.vue.d.ts +30 -0
- package/dist/types/app/components/general/MediaImage.vue.d.ts.map +1 -0
- package/dist/types/app/components/general/NoDataDisplay.vue.d.ts +7 -0
- package/dist/types/app/components/general/NoDataDisplay.vue.d.ts.map +1 -0
- package/dist/types/app/components/general/ResponsiveDialog.vue.d.ts +28 -0
- package/dist/types/app/components/general/ResponsiveDialog.vue.d.ts.map +1 -0
- package/dist/types/app/components/general/SafeEmojiText.vue.d.ts +10 -0
- package/dist/types/app/components/general/SafeEmojiText.vue.d.ts.map +1 -0
- package/dist/types/app/components/global/BEmojiPicker.vue.d.ts +8 -0
- package/dist/types/app/components/global/BEmojiPicker.vue.d.ts.map +1 -0
- package/dist/types/app/components/global/BIcon.vue.d.ts +11 -0
- package/dist/types/app/components/global/BIcon.vue.d.ts.map +1 -0
- package/dist/types/app/components/global/BVirtualVerticalList.vue.d.ts +30 -0
- package/dist/types/app/components/global/BVirtualVerticalList.vue.d.ts.map +1 -0
- package/dist/types/app/composables/call/media.d.ts +204 -0
- package/dist/types/app/composables/call/media.d.ts.map +1 -0
- package/dist/types/app/composables/call/peer.d.ts +39 -0
- package/dist/types/app/composables/call/peer.d.ts.map +1 -0
- package/dist/types/app/composables/call/peers.d.ts +54 -0
- package/dist/types/app/composables/call/peers.d.ts.map +1 -0
- package/dist/types/app/composables/call/session.d.ts +284 -0
- package/dist/types/app/composables/call/session.d.ts.map +1 -0
- package/dist/types/app/composables/call/signaling.d.ts +36 -0
- package/dist/types/app/composables/call/signaling.d.ts.map +1 -0
- package/dist/types/app/composables/call/useCallUi.d.ts +27 -0
- package/dist/types/app/composables/call/useCallUi.d.ts.map +1 -0
- package/dist/types/app/composables/chat/useChatRecording.d.ts +75 -0
- package/dist/types/app/composables/chat/useChatRecording.d.ts.map +1 -0
- package/dist/types/app/composables/chat/useInputDraft.d.ts +14 -0
- package/dist/types/app/composables/chat/useInputDraft.d.ts.map +1 -0
- package/dist/types/app/composables/useAppPermissions.d.ts +25 -0
- package/dist/types/app/composables/useAppPermissions.d.ts.map +1 -0
- package/dist/types/app/composables/useAppToast.d.ts +13 -0
- package/dist/types/app/composables/useAppToast.d.ts.map +1 -0
- package/dist/types/app/composables/useAttachmentPicker.d.ts +18 -0
- package/dist/types/app/composables/useAttachmentPicker.d.ts.map +1 -0
- package/dist/types/app/composables/useCall.d.ts +91 -0
- package/dist/types/app/composables/useCall.d.ts.map +1 -0
- package/dist/types/app/composables/useChatMessageList.d.ts +18 -0
- package/dist/types/app/composables/useChatMessageList.d.ts.map +1 -0
- package/dist/types/app/composables/useDate.d.ts +7 -0
- package/dist/types/app/composables/useDate.d.ts.map +1 -0
- package/dist/types/app/composables/useDevice.d.ts +32 -0
- package/dist/types/app/composables/useDevice.d.ts.map +1 -0
- package/dist/types/app/composables/useFlippedVirtualScroll.d.ts +22 -0
- package/dist/types/app/composables/useFlippedVirtualScroll.d.ts.map +1 -0
- package/dist/types/app/composables/useHostI18n.d.ts +15 -0
- package/dist/types/app/composables/useHostI18n.d.ts.map +1 -0
- package/dist/types/app/composables/useLocalI18n.d.ts +5 -0
- package/dist/types/app/composables/useLocalI18n.d.ts.map +1 -0
- package/dist/types/app/composables/useLongPress.d.ts +6 -0
- package/dist/types/app/composables/useLongPress.d.ts.map +1 -0
- package/dist/types/app/composables/useRichTextEditor.d.ts +12 -0
- package/dist/types/app/composables/useRichTextEditor.d.ts.map +1 -0
- package/dist/types/app/directives/loading.d.ts +6 -0
- package/dist/types/app/directives/loading.d.ts.map +1 -0
- package/dist/types/app/index.d.ts +31 -0
- package/dist/types/app/index.d.ts.map +1 -0
- package/dist/types/app/plugin.d.ts +28 -0
- package/dist/types/app/plugin.d.ts.map +1 -0
- package/dist/types/app/provider/callProvider.d.ts +7 -0
- package/dist/types/app/provider/callProvider.d.ts.map +1 -0
- package/dist/types/app/stores/callStore.d.ts +1626 -0
- package/dist/types/app/stores/callStore.d.ts.map +1 -0
- package/dist/types/app/stores/chatStore.d.ts +126 -0
- package/dist/types/app/stores/chatStore.d.ts.map +1 -0
- package/dist/types/app/stores/mediaStore.d.ts +18 -0
- package/dist/types/app/stores/mediaStore.d.ts.map +1 -0
- package/dist/types/app/stores/messageStores.d.ts +2460 -0
- package/dist/types/app/stores/messageStores.d.ts.map +1 -0
- package/dist/types/app/stores/profileStore.d.ts +102 -0
- package/dist/types/app/stores/profileStore.d.ts.map +1 -0
- package/dist/types/app/types/components/chat-input.d.ts +4 -0
- package/dist/types/app/types/components/chat-input.d.ts.map +1 -0
- package/dist/types/app/types/components/menu-options.d.ts +7 -0
- package/dist/types/app/types/components/menu-options.d.ts.map +1 -0
- package/dist/types/app/types/components/modal.d.ts +17 -0
- package/dist/types/app/types/components/modal.d.ts.map +1 -0
- package/dist/types/app/types/index.d.ts +257 -0
- package/dist/types/app/types/index.d.ts.map +1 -0
- package/dist/types/app/utils/emojiParser.d.ts +5 -0
- package/dist/types/app/utils/emojiParser.d.ts.map +1 -0
- package/dist/types/app/utils/format.d.ts +4 -0
- package/dist/types/app/utils/format.d.ts.map +1 -0
- package/dist/types/fakes/backend.d.ts +25 -0
- package/dist/types/fakes/backend.d.ts.map +1 -0
- package/dist/types/fakes/call.d.ts +7 -0
- package/dist/types/fakes/call.d.ts.map +1 -0
- package/dist/types/fakes/data.d.ts +13 -0
- package/dist/types/fakes/data.d.ts.map +1 -0
- package/dist/types/fakes/index.d.ts +7 -0
- package/dist/types/fakes/index.d.ts.map +1 -0
- package/dist/types/fakes.d.ts +2 -0
- package/dist/types/i18n/locales/index.d.ts +3557 -0
- package/dist/types/i18n/locales/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/package.json +98 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-JU_JZkSC.mjs","sources":["../../app/composables/useAppToast.ts","../../app/composables/useHostI18n.ts","../../app/stores/profileStore.ts","../../i18n/locales/index.ts","../../app/stores/callStore.ts","../../app/stores/chatStore.ts","../../app/composables/useDate.ts","../../app/stores/messageStores.ts","../../app/stores/mediaStore.ts","../../app/assets/lib-images/chat/empty-state.webp","../../app/components/general/MediaImage.vue","../../app/components/general/NoDataDisplay.vue","../../app/composables/useLocalI18n.ts","../../app/components/global/BVirtualVerticalList.vue","../../app/components/global/BIcon.vue","../../app/directives/loading.ts","../../app/utils/emojiParser.ts","../../app/components/general/SafeEmojiText.vue","../../app/components/chat/contact/ContactAvatar.vue","../../app/components/chat/contact/ChatContactDisplay.vue","../../app/components/chat/contact/ContactSkeleton.vue","../../app/components/general/IconButton.vue","../../app/components/chat/contact/ChatListSearch.vue","../../app/components/chat/contact/ChatList.vue","../../app/composables/useAppPermissions.ts","../../app/components/general/ResponsiveDialog.vue","../../app/components/chat/chat-input/PermissionPopup.vue","../../app/assets/lib-images/chat/profile-background.webp","../../app/utils/format.ts","../../app/components/chat/profile/FileDisplay.vue","../../app/components/chat/ChatProfileOverview.vue","../../app/components/general/ConfirmModal.vue","../../app/components/chat/chat-bubbles/ImageGroupDisplay.vue","../../app/components/chat/chat-bubbles/BubbleOptions.vue","../../app/components/general/LoadingStatus.vue","../../app/components/chat/chat-bubbles/VoiceDisplay.vue","../../app/components/chat/chat-bubbles/BubbleVideo.vue","../../app/components/general/FileFormatDisplay.vue","../../app/components/chat/chat-bubbles/FileDisplay.vue","../../app/components/chat/chat-bubbles/BubbleDivider.vue","../../app/components/chat/chat-bubbles/UploadProgressOverlay.vue","../../app/components/chat/chat-bubbles/BubbleImages.vue","../../app/components/chat/chat-bubbles/BubbleSelectionMark.vue","../../app/components/chat/chat-bubbles/BubbleRequest.vue","../../app/components/chat/chat-bubbles/BubbleStatus.vue","../../app/components/chat/chat-bubbles/BubbleMeta.vue","../../app/components/chat/chat-bubbles/ReplyPreview.vue","../../app/composables/useLongPress.ts","../../app/components/chat/ChatBubble.vue","../../app/components/chat/messages/MessagesSkeleton.vue","../../app/components/chat/messages/FloatingDateHeader.vue","../../app/components/chat/messages/ScrollToBottomButton.vue","../../app/composables/useChatMessageList.ts","../../app/composables/useFlippedVirtualScroll.ts","../../app/components/chat/ChatMessages.vue","../../app/components/chat/ChatPageBar.vue","../../app/components/global/BEmojiPicker.vue","../../app/components/chat/chat-input/AttachementFileDisplay.vue","../../app/composables/useAttachmentPicker.ts","../../app/components/chat/chat-input/InputAttachement.vue","../../app/composables/chat/useChatRecording.ts","../../app/components/chat/chat-input/VideoRecordDisplay.vue","../../app/composables/useRichTextEditor.ts","../../app/components/chat/chat-input/InputActionBar.vue","../../app/components/chat/chat-input/RecordingStatus.vue","../../app/components/chat/chat-input/RecordButton.vue","../../app/composables/chat/useInputDraft.ts","../../app/components/chat/ChatInput.vue","../../app/components/chat/ChatView.vue","../../app/components/ChatPage.vue","../../app/types/index.ts","../../app/provider/callProvider.ts","../../app/plugin.ts","../../app/index.ts"],"sourcesContent":["import { useToast } from \"primevue/usetoast\";\n\n/** Rendered by `<Toast group=\"vue-parley\" />` in ChatView, so the host's own toasts stay apart. */\nexport const TOAST_GROUP = \"vue-parley\";\n\nconst SEVERITY = {\n success: \"success\",\n error: \"error\",\n warning: \"warn\",\n info: \"info\",\n} as const;\n\nexport const useAppToast = () => {\n const toast = useToast();\n\n const openToast = (\n message: string,\n type: keyof typeof SEVERITY = \"success\",\n ) => {\n toast.add({\n group: TOAST_GROUP,\n severity: SEVERITY[type],\n summary: message,\n life: 4000,\n });\n };\n\n return { openToast };\n};\n","import {\n computed,\n getCurrentInstance,\n inject,\n isRef,\n watch,\n type App,\n type ComputedRef,\n type InjectionKey,\n type Ref,\n} from \"vue\";\nimport { createI18n, type I18n } from \"vue-i18n\";\n\n// vue-i18n provides itself under a per-instance symbol, reachable only through the app. createChat()\n// re-provides it under this key so stores, which have no component, can find it too.\nconst hostI18nKey: InjectionKey<I18n> = Symbol(\"vue-chat:i18n\");\n\ntype I18nApp = App & { __VUE_I18N_SYMBOL__?: InjectionKey<I18n> };\n\nfunction injectFromApp(app: I18nApp): I18n | undefined {\n const symbol = app.__VUE_I18N_SYMBOL__;\n return symbol ? app.runWithContext(() => inject(symbol, undefined)) : undefined;\n}\n\nexport function provideHostI18n(app: App) {\n const i18n = injectFromApp(app);\n if (i18n) app.provide(hostI18nKey, i18n);\n}\n\nfunction injectHostI18n(): I18n {\n const instance = getCurrentInstance();\n const i18n =\n inject(hostI18nKey, undefined) ??\n // Stores configured through setHandlers() instead of createChat(), used from a component.\n (instance ? injectFromApp(instance.appContext.app) : undefined);\n if (!i18n) {\n throw new Error(\n \"[vue-chat] vue-i18n not found: install it, then createChat(), before using the chat\",\n );\n }\n return i18n;\n}\n\nfunction read(value: string | Ref<string> | undefined): string | undefined {\n return isRef(value) ? value.value : value;\n}\n\n/**\n * The host's current locale. Unlike useI18n(), works in a store as well as a component, so a\n * store can be created anywhere (a Nuxt plugin, a route guard), not only in a component's setup.\n */\nexport function useHostLocale(): ComputedRef<string> {\n const global = injectHostI18n().global as unknown as { locale: string | Ref<string> };\n return computed(() => read(global.locale) ?? \"en\");\n}\n\n/**\n * Translations for a store: `messages` on their own, following the host's locale. A component\n * uses useLocalI18n() instead, which scopes them to the component.\n */\nexport function useStoreI18n(messages: Record<string, any>): { t: (key: string) => string } {\n const host = injectHostI18n().global as unknown as {\n locale: string | Ref<string>;\n fallbackLocale: string | Ref<string>;\n };\n const locale = useHostLocale();\n const { global } = createI18n({\n legacy: false,\n locale: locale.value,\n fallbackLocale: read(host.fallbackLocale) ?? \"en\",\n messages,\n });\n watch(locale, (value) => (global.locale.value = value));\n return { t: (key) => global.t(key) };\n}\n","import { ProfileAttachmentsPage, ProfileHandlers } from \"~/types\";\nimport { defineStore } from \"pinia\";\n\nconst DEFAULT_PAGE_SIZE = 20;\n\nexport const useProfileStore = defineStore(\"profile-store\", () => {\n let handlers: ProfileHandlers;\n\n function setHandlers(val: ProfileHandlers) {\n handlers = val;\n }\n\n const userId = ref<string>(\"\");\n const userName = ref<string>(\"\");\n const userAvatar = ref<Blob | undefined>(undefined);\n const mediaMap = ref<Record<string, string[]>>({});\n const filesMap = ref<Record<string, string[]>>({});\n const mediaPage = ref<Record<string, number>>({});\n const filesPage = ref<Record<string, number>>({});\n const mediaHasNextPage = ref<Record<string, boolean>>({});\n const filesHasNextPage = ref<Record<string, boolean>>({});\n const pageSize = ref(DEFAULT_PAGE_SIZE);\n const mediaLoading = ref(false);\n const filesLoading = ref(false);\n\n const fetchMedia = async (\n conversationId: string,\n page: number = 1,\n size: number = pageSize.value,\n ) => {\n if (mediaLoading.value) return;\n if (page > 1 && !mediaHasNextPage.value[conversationId]) return;\n mediaLoading.value = true;\n try {\n const batch: ProfileAttachmentsPage = await handlers.fetchMedia({\n conversationId,\n page,\n pageSize: size,\n });\n const existing = mediaMap.value[conversationId] ?? [];\n mediaMap.value[conversationId] =\n page === 1 ? batch.data : [...existing, ...batch.data];\n mediaPage.value[conversationId] = page;\n mediaHasNextPage.value[conversationId] = batch.hasNextPage;\n } finally {\n mediaLoading.value = false;\n }\n };\n\n const fetchFiles = async (\n conversationId: string,\n page: number = 1,\n size: number = pageSize.value,\n ) => {\n if (filesLoading.value) return;\n if (page > 1 && !filesHasNextPage.value[conversationId]) return;\n filesLoading.value = true;\n try {\n const batch: ProfileAttachmentsPage = await handlers.fetchFiles({\n conversationId,\n page,\n pageSize: size,\n });\n const existing = filesMap.value[conversationId] ?? [];\n filesMap.value[conversationId] =\n page === 1 ? batch.data : [...existing, ...batch.data];\n filesPage.value[conversationId] = page;\n filesHasNextPage.value[conversationId] = batch.hasNextPage;\n } finally {\n filesLoading.value = false;\n }\n };\n\n const clear = (conversationId: string) => {\n delete mediaMap.value[conversationId];\n delete filesMap.value[conversationId];\n delete mediaPage.value[conversationId];\n delete filesPage.value[conversationId];\n delete mediaHasNextPage.value[conversationId];\n delete filesHasNextPage.value[conversationId];\n };\n\n return {\n setHandlers,\n fetchMedia,\n fetchFiles,\n clear,\n mediaMap,\n filesMap,\n mediaPage,\n filesPage,\n mediaHasNextPage,\n userId,\n userName,\n userAvatar,\n filesHasNextPage,\n mediaLoading,\n filesLoading,\n pageSize,\n };\n});\n","import generalEn from \"./en/general.json\";\nimport chatEn from \"./en/chat.json\";\nimport profileEn from \"./en/profile.json\";\nimport calendarEn from \"./en/calendar.json\";\nimport validationEn from \"./en/validation.json\";\n\nimport generalFa from \"./fa/general.json\";\nimport chatFa from \"./fa/chat.json\";\nimport profileFa from \"./fa/profile.json\";\nimport calendarFa from \"./fa/calendar.json\";\nimport validationFa from \"./fa/validation.json\";\nimport authFa from \"./fa/auth.json\";\n\nimport componentsGeneralEn from \"./en/components/general.json\";\nimport componentsGeneralFa from \"./fa/components/general.json\";\n\nimport bModalEn from \"./en/components/BModal.json\";\nimport boardColorPickerEn from \"./en/components/BoardColorPicker.json\";\nimport bubbleOptionsEn from \"./en/components/BubbleOptions.json\";\nimport callPageOverlayEn from \"./en/components/CallPageOverlay.json\";\nimport callPaintBoardEn from \"./en/components/CallPaintBoard.json\";\nimport chatBubbleEn from \"./en/components/ChatBubble.json\";\nimport chatContactDisplayEn from \"./en/components/ChatContactDisplay.json\";\nimport chatInputEn from \"./en/components/ChatInput.json\";\nimport chatListEn from \"./en/components/ChatList.json\";\nimport chatListSearchEn from \"./en/components/ChatListSearch.json\";\nimport chatMessagesEn from \"./en/components/ChatMessages.json\";\nimport chatPageEn from \"./en/components/ChatPage.json\";\nimport chatPageBarEn from \"./en/components/ChatPageBar.json\";\nimport chatProfileOverviewEn from \"./en/components/ChatProfileOverview.json\";\nimport chatViewEn from \"./en/components/ChatView.json\";\nimport inputAttachementEn from \"./en/components/InputAttachement.json\";\nimport permissionPopupEn from \"./en/components/PermissionPopup.json\";\nimport chatBubblesFileDisplayEn from \"./en/components/chat-bubbles_FileDisplay.json\";\nimport profileFileDisplayEn from \"./en/components/profile_FileDisplay.json\";\n\nimport bModalFa from \"./fa/components/BModal.json\";\nimport boardColorPickerFa from \"./fa/components/BoardColorPicker.json\";\nimport bubbleOptionsFa from \"./fa/components/BubbleOptions.json\";\nimport callPageOverlayFa from \"./fa/components/CallPageOverlay.json\";\nimport callPaintBoardFa from \"./fa/components/CallPaintBoard.json\";\nimport chatBubbleFa from \"./fa/components/ChatBubble.json\";\nimport chatContactDisplayFa from \"./fa/components/ChatContactDisplay.json\";\nimport chatInputFa from \"./fa/components/ChatInput.json\";\nimport chatListFa from \"./fa/components/ChatList.json\";\nimport chatListSearchFa from \"./fa/components/ChatListSearch.json\";\nimport chatMessagesFa from \"./fa/components/ChatMessages.json\";\nimport chatPageFa from \"./fa/components/ChatPage.json\";\nimport chatPageBarFa from \"./fa/components/ChatPageBar.json\";\nimport chatProfileOverviewFa from \"./fa/components/ChatProfileOverview.json\";\nimport chatViewFa from \"./fa/components/ChatView.json\";\nimport inputAttachementFa from \"./fa/components/InputAttachement.json\";\nimport permissionPopupFa from \"./fa/components/PermissionPopup.json\";\nimport chatBubblesFileDisplayFa from \"./fa/components/chat-bubbles_FileDisplay.json\";\nimport profileFileDisplayFa from \"./fa/components/profile_FileDisplay.json\";\n\nexport const general = {\n en: generalEn,\n fa: generalFa,\n};\n\nexport const chat = {\n en: { ...general.en, ...chatEn },\n fa: { ...general.fa, ...chatFa },\n};\n\nexport const profile = {\n en: { ...general.en, ...profileEn },\n fa: { ...general.fa, ...profileFa },\n};\n\nexport const calendar = {\n en: { ...general.en, ...calendarEn },\n fa: { ...general.fa, ...calendarFa },\n};\n\nexport const validation = {\n en: { ...general.en, ...validationEn },\n fa: { ...general.fa, ...validationFa },\n};\n\nexport const auth = {\n en: { ...general.en },\n fa: { ...general.fa, ...authFa },\n};\n\nexport const componentsGeneral = {\n en: componentsGeneralEn,\n fa: componentsGeneralFa,\n};\n\nexport const bModal = {\n en: { ...componentsGeneral.en, ...bModalEn },\n fa: { ...componentsGeneral.fa, ...bModalFa },\n};\n\nexport const boardColorPicker = {\n en: { ...componentsGeneral.en, ...boardColorPickerEn },\n fa: { ...componentsGeneral.fa, ...boardColorPickerFa },\n};\n\nexport const bubbleOptions = {\n en: { ...componentsGeneral.en, ...bubbleOptionsEn },\n fa: { ...componentsGeneral.fa, ...bubbleOptionsFa },\n};\n\nexport const callPageOverlay = {\n en: { ...componentsGeneral.en, ...callPageOverlayEn },\n fa: { ...componentsGeneral.fa, ...callPageOverlayFa },\n};\n\nexport const callPaintBoard = {\n en: { ...componentsGeneral.en, ...callPaintBoardEn },\n fa: { ...componentsGeneral.fa, ...callPaintBoardFa },\n};\n\nexport const chatBubble = {\n en: { ...componentsGeneral.en, ...chatBubbleEn },\n fa: { ...componentsGeneral.fa, ...chatBubbleFa },\n};\n\nexport const chatContactDisplay = {\n en: { ...componentsGeneral.en, ...chatContactDisplayEn },\n fa: { ...componentsGeneral.fa, ...chatContactDisplayFa },\n};\n\nexport const chatInput = {\n en: { ...componentsGeneral.en, ...chatInputEn },\n fa: { ...componentsGeneral.fa, ...chatInputFa },\n};\n\nexport const chatList = {\n en: { ...componentsGeneral.en, ...chatListEn },\n fa: { ...componentsGeneral.fa, ...chatListFa },\n};\n\nexport const chatListSearch = {\n en: { ...componentsGeneral.en, ...chatListSearchEn },\n fa: { ...componentsGeneral.fa, ...chatListSearchFa },\n};\n\nexport const chatMessages = {\n en: { ...componentsGeneral.en, ...chatMessagesEn },\n fa: { ...componentsGeneral.fa, ...chatMessagesFa },\n};\n\nexport const chatPage = {\n en: { ...componentsGeneral.en, ...chatPageEn },\n fa: { ...componentsGeneral.fa, ...chatPageFa },\n};\n\nexport const chatPageBar = {\n en: { ...componentsGeneral.en, ...chatPageBarEn },\n fa: { ...componentsGeneral.fa, ...chatPageBarFa },\n};\n\nexport const chatProfileOverview = {\n en: { ...componentsGeneral.en, ...chatProfileOverviewEn },\n fa: { ...componentsGeneral.fa, ...chatProfileOverviewFa },\n};\n\nexport const chatView = {\n en: { ...componentsGeneral.en, ...chatViewEn },\n fa: { ...componentsGeneral.fa, ...chatViewFa },\n};\n\nexport const inputAttachement = {\n en: { ...componentsGeneral.en, ...inputAttachementEn },\n fa: { ...componentsGeneral.fa, ...inputAttachementFa },\n};\n\nexport const permissionPopup = {\n en: { ...componentsGeneral.en, ...permissionPopupEn },\n fa: { ...componentsGeneral.fa, ...permissionPopupFa },\n};\n\nexport const chatBubblesFileDisplay = {\n en: { ...componentsGeneral.en, ...chatBubblesFileDisplayEn },\n fa: { ...componentsGeneral.fa, ...chatBubblesFileDisplayFa },\n};\n\nexport const profileFileDisplay = {\n en: { ...componentsGeneral.en, ...profileFileDisplayEn },\n fa: { ...componentsGeneral.fa, ...profileFileDisplayFa },\n};\n","import { defineStore, acceptHMRUpdate } from \"pinia\";\nimport { markRaw, ref, shallowRef } from \"vue\";\nimport type { CallHandlers } from \"~/types\";\nimport type { CallSession } from \"~/composables/call/session\";\nimport { useAppToast } from \"~/composables/useAppToast\";\nimport { useStoreI18n } from \"~/composables/useHostI18n\";\nimport { useProfileStore } from \"./profileStore\";\nimport { chat } from \"@i18n/locales\";\n\nexport const useCallStore = defineStore(\"call-modal\", () => {\n const { t } = useStoreI18n(chat);\n const { openToast } = useAppToast();\n const profileStore = useProfileStore();\n\n let handlers: CallHandlers | null = null;\n function setHandlers(val: CallHandlers) {\n handlers = val;\n }\n\n /**\n * The running call. Lives here, not in a component, so it survives the call view unmounting.\n * Null until its code has loaded: calling is fetched on first use.\n */\n const session = shallowRef<CallSession | null>(null);\n /** Bumped on every start/end, so a slow load can tell it was overtaken. */\n let attempt = 0;\n\n const timerInterval = ref<ReturnType<typeof setInterval> | null>(null);\n const channelId = ref<string | null>(null);\n const startTime = ref<number | null>(null);\n const isMinimized = ref(false);\n const isActive = ref(false);\n const elapsedTime = ref(0);\n\n const stopTimer = () => {\n if (timerInterval.value) clearInterval(timerInterval.value);\n timerInterval.value = null;\n startTime.value = null;\n };\n\n const startTimer = () => {\n stopTimer();\n startTime.value = Date.now();\n timerInterval.value = setInterval(() => {\n elapsedTime.value = Math.floor(\n (Date.now() - (startTime.value || 0)) / 1000,\n );\n }, 1000);\n };\n\n const startCall = (id: string) => {\n // One call at a time; asking again just brings the running one back into view.\n if (isActive.value) {\n isMinimized.value = false;\n return;\n }\n if (!handlers) {\n throw new Error(\n \"[vue-chat] No call handlers: pass `call` to createChat() or use provideCallHandlers()\",\n );\n }\n\n const callHandlers = handlers;\n const current = ++attempt;\n startTimer();\n channelId.value = id;\n isActive.value = true;\n isMinimized.value = false;\n\n void import(\"~/composables/call/session\").then(({ createCallSession }) => {\n if (current !== attempt) return; // ended or restarted while loading\n const call = createCallSession({\n handlers: callHandlers,\n channel: id,\n self: {\n id: profileStore.userId,\n name: () => profileStore.userName ?? \"\",\n avatar: () => profileStore.userAvatar,\n },\n notify: (key) => openToast(t(key), \"error\"),\n });\n // Streams and connections inside must not be made deeply reactive.\n session.value = markRaw(call);\n void call.start();\n });\n };\n\n const endCall = () => {\n attempt++;\n session.value?.end();\n session.value = null;\n stopTimer();\n isActive.value = false;\n isMinimized.value = false;\n elapsedTime.value = 0;\n channelId.value = null;\n };\n\n const minimize = () => {\n isMinimized.value = true;\n };\n\n const maximize = () => {\n isMinimized.value = false;\n };\n\n return {\n session,\n isActive,\n isMinimized,\n elapsedTime,\n channelId,\n setHandlers,\n startCall,\n endCall,\n minimize,\n maximize,\n };\n});\n\nif (import.meta.hot) {\n import.meta.hot.accept(acceptHMRUpdate(useCallStore, import.meta.hot));\n}\n","import { ChatHandlers, Contact, StateKeys, UserRoleKey } from \"~/types\";\nimport { defineStore } from \"pinia\";\nimport { shallowReadonly } from \"vue\";\n\nconst FILTERS: StateKeys[] = [\"\", \"online\", \"ended\", \"active\"];\n\ninterface ListState {\n /** Contact ids in the order the server returned them. */\n ids: string[];\n loading: boolean;\n /** A page-1 load (first load, search, filter), as opposed to loading more. */\n refreshing: boolean;\n page: number;\n hasNextPage: boolean;\n}\n\n/** One conversation list as `conversationStates` exposes it. */\nexport interface ConversationListView {\n /** Read-only: add contacts with `addContact`, change them with `updateContact`. */\n data: readonly Contact[];\n loading: boolean;\n refreshing?: boolean;\n page: number;\n hasNextPage: boolean;\n}\n\nconst byLastMessage = (a: Contact, b: Contact) =>\n (b.lastMessage ? new Date(b.lastMessage.date).getTime() : 0) -\n (a.lastMessage ? new Date(a.lastMessage.date).getTime() : 0);\n\nexport const useChatStore = defineStore(\"chat\", () => {\n const { height: windowHeight } = useWindowSize();\n let handlers: ChatHandlers;\n const calls = ref<\n { channel: string; name: string; avatar?: string; from: string }[]\n >([]);\n\n // `handlers` is not reactive, so the UI reads this flag instead.\n const canEndConversation = ref(false);\n\n function setHandlers(val: ChatHandlers) {\n handlers = val;\n canEndConversation.value = !!val.endConversation;\n }\n\n const chatsPerPage = computed(() => {\n const h = windowHeight.value || 800;\n return Math.floor((h - 138) / 76) + 1;\n });\n\n /** @deprecated Host-specific; kept for compatibility. */\n const chosenRole = ref<UserRoleKey>(\"user\");\n /** @deprecated Host-specific; kept for compatibility. */\n const currentUserBirthDate = ref<Date | null>(null);\n const activeConversationId = ref<string | null>(null);\n const profileViewOpen = ref(false);\n const typingByConversation = ref<Record<string, string | null>>({});\n\n // --- Normalised conversations: each contact stored once, lists hold ids ---\n const contactsById = ref<Record<string, Contact>>({});\n const emptyList = (): ListState => ({\n ids: [],\n loading: false,\n refreshing: false,\n page: 0,\n hasNextPage: true,\n });\n const lists = ref<Record<StateKeys, ListState>>({\n \"\": emptyList(),\n online: emptyList(),\n ended: emptyList(),\n active: emptyList(),\n });\n\n const contactsOf = (list: ListState) =>\n list.ids.map((id) => contactsById.value[id]).filter((c): c is Contact => !!c);\n\n /**\n * Each list with its contacts resolved; the shape hosts already read. The lists are read-only\n * (writing to them warns in development), since they are rebuilt from `contactsById`.\n */\n const conversationStates = computed(\n () =>\n Object.fromEntries(\n FILTERS.map((key) => {\n const list = lists.value[key];\n return [\n key,\n {\n data: shallowReadonly(contactsOf(list)),\n loading: list.loading,\n refreshing: list.refreshing,\n page: list.page,\n hasNextPage: list.hasNextPage,\n },\n ];\n }),\n ) as Record<StateKeys, ConversationListView>,\n );\n\n /** Each list sorted newest-first, recomputed only when its contacts change. */\n const displayedContacts = computed(\n () =>\n Object.fromEntries(\n FILTERS.map((key) => [key, [...conversationStates.value[key].data].sort(byLastMessage)]),\n ) as Record<StateKeys, Contact[]>,\n );\n\n const getDisplayedContacts = (filter: StateKeys): Contact[] =>\n displayedContacts.value[filter];\n\n const getContactById = (id: string): Contact | null =>\n contactsById.value[id] ?? null;\n\n /**\n * Adds a contact the lists haven't fetched (e.g. a conversation opened from a link) to the top\n * of a list, or refreshes it if it is already known.\n */\n const addContact = (contact: Contact, filter: StateKeys = \"\") => {\n contactsById.value[contact.id] = contact;\n const list = lists.value[filter];\n if (!list.ids.includes(contact.id)) list.ids.unshift(contact.id);\n };\n\n /** Changes a contact everywhere it is listed. */\n const updateContact = (id: string, updates: Partial<Contact>) => {\n const contact = contactsById.value[id];\n if (contact) Object.assign(contact, updates);\n };\n\n const setSelectedChat = (id: string | null) => {\n activeConversationId.value = id;\n profileViewOpen.value = false;\n };\n\n const openProfile = () => {\n profileViewOpen.value = true;\n };\n\n const closeProfile = () => {\n profileViewOpen.value = false;\n };\n\n const queued: Partial<Record<StateKeys, string>> = {};\n\n const fetchConversations = async (\n filterState: StateKeys = \"\",\n page = 1,\n search = \"\",\n ) => {\n const list = lists.value[filterState];\n\n if (list.loading) {\n // A new search or filter must not be dropped because a load is in flight; run the\n // latest one when it finishes. Loading more while busy is safely ignored.\n if (page === 1) queued[filterState] = search;\n return;\n }\n list.loading = true;\n list.refreshing = page === 1;\n try {\n const result = await handlers.fetchConversations({\n pageSize: chatsPerPage.value,\n state: filterState,\n search,\n page,\n });\n\n // The newest copy of a contact wins, whichever list it came in with.\n for (const contact of result.data) contactsById.value[contact.id] = contact;\n const ids = result.data.map((c) => c.id);\n list.ids = page === 1 ? ids : [...list.ids, ...ids.filter((id) => !list.ids.includes(id))];\n list.page = page;\n list.hasNextPage = result.hasNextPage;\n } finally {\n list.loading = false;\n list.refreshing = false;\n const next = queued[filterState];\n if (next !== undefined) {\n delete queued[filterState];\n void fetchConversations(filterState, 1, next);\n }\n }\n };\n\n const loadNextPage = async (filter: StateKeys) => {\n const list = lists.value[filter];\n if (list.hasNextPage && !list.loading) {\n await fetchConversations(filter, list.page + 1);\n }\n };\n\n const endConversation = async (id: string) => {\n if (!handlers.endConversation) return;\n await handlers.endConversation(id);\n updateContact(id, { isActive: false });\n };\n\n const deleteConversation = async (id: string) => {\n const contact = contactsById.value[id];\n // Where it was listed, to put it back if the server refuses.\n const positions = FILTERS.map((key) => [key, lists.value[key].ids.indexOf(id)] as const)\n .filter(([, index]) => index !== -1);\n\n for (const [key] of positions)\n lists.value[key].ids = lists.value[key].ids.filter((x) => x !== id);\n delete contactsById.value[id];\n\n const wasActive = activeConversationId.value === id;\n if (wasActive) {\n activeConversationId.value = null;\n profileViewOpen.value = false;\n }\n delete typingByConversation.value[id];\n\n try {\n await handlers.deleteConversation(id);\n } catch (error) {\n if (contact) contactsById.value[id] = contact;\n for (const [key, index] of positions) lists.value[key].ids.splice(index, 0, id);\n if (wasActive) activeConversationId.value = id;\n throw error;\n }\n };\n\n const unreadCount = computed(\n () =>\n Object.values(contactsById.value).filter(\n (c) => c.lastMessage && c.lastMessage.isRead === false,\n ).length,\n );\n\n return {\n chosenRole,\n currentUserBirthDate,\n conversationStates,\n activeConversationId,\n profileViewOpen,\n typingByConversation,\n chatsPerPage,\n unreadCount,\n setHandlers,\n setSelectedChat,\n openProfile,\n closeProfile,\n deleteConversation,\n canEndConversation,\n endConversation,\n fetchConversations,\n loadNextPage,\n getContactById,\n getDisplayedContacts,\n updateContact,\n addContact,\n calls,\n };\n});\n","import { useHostLocale } from \"./useHostI18n\";\n\nexport const useDate = () => {\n const locale = useHostLocale();\n\n const getLang = (): string => {\n const current = locale.value;\n if (current.includes(\"fa\")) return \"fa\";\n if (current.includes(\"ar\")) return \"ar\";\n return \"en\";\n };\n\n const parseDate = (dateInput: string | Date): Date => {\n return typeof dateInput === \"string\" ? new Date(dateInput) : dateInput;\n };\n\n const formatTime = (dateInput: string | Date): string => {\n const date = parseDate(dateInput);\n const lang = getLang();\n return new Intl.DateTimeFormat(lang, {\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false,\n }).format(date);\n };\n\n const formatRelativeDate = (dateInput: string | Date): string => {\n const date = parseDate(dateInput);\n const lang = getLang();\n const now = new Date();\n\n const rtf = new Intl.RelativeTimeFormat(lang, { numeric: \"auto\" });\n\n const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);\n\n if (diffInSeconds < 3600) {\n const mins = Math.max(Math.floor(diffInSeconds / 60), 1);\n return rtf.format(-mins, \"minute\");\n }\n\n if (diffInSeconds < 86400) {\n const hrs = Math.floor(diffInSeconds / 3600);\n return rtf.format(-hrs, \"hour\");\n }\n\n const startOfToday = new Date(\n now.getFullYear(),\n now.getMonth(),\n now.getDate(),\n );\n const startOfDate = new Date(\n date.getFullYear(),\n date.getMonth(),\n date.getDate(),\n );\n const diffInDays = Math.floor(\n (startOfToday.getTime() - startOfDate.getTime()) / 86400000,\n );\n\n if (diffInDays === 1) {\n return rtf.format(-1, \"day\");\n }\n\n const calendarLang = lang === \"fa\" ? \"fa-IR-u-ca-persian\" : lang;\n\n const isCurrentYear =\n lang === \"fa\"\n ? new Intl.DateTimeFormat(\"en-US-u-ca-persian\", {\n year: \"numeric\",\n }).format(now) ===\n new Intl.DateTimeFormat(\"en-US-u-ca-persian\", {\n year: \"numeric\",\n }).format(date)\n : now.getFullYear() === date.getFullYear();\n\n if (isCurrentYear) {\n return new Intl.DateTimeFormat(calendarLang, {\n day: \"numeric\",\n month: \"long\",\n }).format(date);\n } else {\n return new Intl.DateTimeFormat(calendarLang, {\n day: \"numeric\",\n month: \"long\",\n year: \"numeric\",\n }).format(date);\n }\n };\n\n const formatDateShort = (dateInput: string | Date): string => {\n const date = parseDate(dateInput);\n const lang = getLang();\n const now = new Date();\n\n const calendarLang = lang === \"fa\" ? \"fa-IR-u-ca-persian\" : lang;\n\n const isCurrentYear =\n lang === \"fa\"\n ? new Intl.DateTimeFormat(\"en-US-u-ca-persian\", {\n year: \"numeric\",\n }).format(now) ===\n new Intl.DateTimeFormat(\"en-US-u-ca-persian\", {\n year: \"numeric\",\n }).format(date)\n : now.getFullYear() === date.getFullYear();\n\n return new Intl.DateTimeFormat(calendarLang, {\n day: \"numeric\",\n month: \"long\",\n year: isCurrentYear ? undefined : \"numeric\",\n }).format(date);\n };\n\n const getYearsPassed = (date: Date): number => {\n const today = new Date();\n let years = today.getFullYear() - date.getFullYear();\n const monthDiff = today.getMonth() - date.getMonth();\n\n if (\n monthDiff < 0 ||\n (monthDiff === 0 && today.getDate() < date.getDate())\n ) {\n years--;\n }\n return years;\n };\n\n return {\n formatRelativeDate,\n getYearsPassed,\n formatDateShort,\n formatTime,\n };\n};\n","import {\n ExtendedMessage,\n Message,\n MessagesHandlers,\n UploadProgressEvent,\n} from \"~/types\";\nimport { useAppToast } from \"~/composables/useAppToast\";\nimport { useStoreI18n } from \"~/composables/useHostI18n\";\nimport { useProfileStore } from \"./profileStore\";\nimport { useDate } from \"~/composables/useDate\";\nimport { useChatStore } from \"./chatStore\";\nimport { chat } from \"@i18n/locales\";\nimport { defineStore } from \"pinia\";\n\nexport const useMessagesStore = defineStore(\"messages-store\", () => {\n const { t } = useStoreI18n(chat);\n const { openToast } = useAppToast();\n const { formatDateShort, formatTime } = useDate();\n const chatStore = useChatStore();\n const profileStore = useProfileStore();\n const currentUserId = computed(() => profileStore.userId);\n\n let handlers: MessagesHandlers;\n\n function setHandlers(val: MessagesHandlers) {\n handlers = val;\n }\n\n const isOptionMenuOpen = ref(false);\n const isSelectMode = ref(false);\n const selectedMessages = ref<Map<string, ExtendedMessage>>(new Map());\n const uploadProgress = ref<Map<string, UploadProgressEvent>>(new Map());\n const replyingTo = ref<ExtendedMessage | null>(null);\n\n // Unsent text per conversation, so switching chats never loses what was being typed.\n const drafts = ref<Record<string, string>>({});\n const setDraft = (conversationId: string, text: string) => {\n if (text.trim()) drafts.value[conversationId] = text;\n else delete drafts.value[conversationId];\n };\n\n const messagesMap = ref<Record<string, Message[]>>({});\n // Per conversation, so a fetch still running for one chat never swallows another's.\n const messagesLoadingMap = ref<Record<string, boolean>>({});\n const messagesLoading = computed(() =>\n Object.values(messagesLoadingMap.value).some(Boolean),\n );\n const messagesPageSize = ref(20);\n const messagesPage = ref<Record<string, number>>({});\n const messagesHasNextPage = ref<Record<string, boolean>>({});\n\n const selectedArray = computed(() =>\n Array.from(selectedMessages.value.values()),\n );\n\n const editWindowHours = ref(6);\n\n const canEdit = computed(() => {\n if (selectedMessages.value.size !== 1) return false;\n const msg = selectedArray.value[0];\n if (!msg) return false;\n const isMine = msg.senderId === currentUserId.value;\n const hoursPassed =\n (Date.now() - new Date(msg.date).getTime()) / (1000 * 60 * 60);\n return isMine && hoursPassed < editWindowHours.value;\n });\n\n const canDelete = computed(() => {\n if (selectedMessages.value.size === 0) return false;\n return selectedArray.value.every((msg) => {\n const isMine = msg.senderId === currentUserId.value;\n const hoursPassed =\n (Date.now() - new Date(msg.date).getTime()) / (1000 * 60 * 60);\n return isMine && hoursPassed < editWindowHours.value;\n });\n });\n\n const clearSelection = () => {\n isSelectMode.value = false;\n selectedMessages.value.clear();\n };\n\n const startSelectMode = (message: ExtendedMessage) => {\n isSelectMode.value = true;\n const newMap = new Map();\n newMap.set(message.id, message);\n selectedMessages.value = newMap;\n };\n\n const toggleSelection = (message: ExtendedMessage) => {\n const newMap = new Map(selectedMessages.value);\n if (newMap.has(message.id)) {\n newMap.delete(message.id);\n if (newMap.size === 0) isSelectMode.value = false;\n } else {\n newMap.set(message.id, message);\n }\n selectedMessages.value = newMap;\n };\n\n const triggerEdit = (message: ExtendedMessage) => {\n editingMessage.value = message;\n editBus.emit(message);\n };\n\n const copyMessageText = () => {\n const textToCopy = selectedArray.value\n .map((msg) => {\n const isMine = msg.senderId === currentUserId.value;\n const senderName = isMine ? t(\"chat.you\") : msg.contact?.name || \"User\";\n const dateTime = `${formatDateShort(msg.date)}, ${formatTime(msg.date)}`;\n const content =\n msg.text ||\n (msg.imageUrl ? \"[Image]\" : msg.voiceUrl ? \"[Voice]\" : \"[File]\");\n return `${senderName} [${dateTime}]:\\n${content}`;\n })\n .join(\"\\n\\n\");\n\n navigator.clipboard.writeText(textToCopy).then(() => {\n openToast(t(\"chat.copiedMessage\"), \"success\");\n });\n clearActions();\n };\n\n const triggerDelete = async (specificIds?: string[]) => {\n const targets = specificIds?.length\n ? specificIds\n : selectedArray.value.map((m) => m.id);\n if (targets.length === 0) return;\n\n // Only asks for confirmation; `confirmDelete` runs once the user accepts.\n deleteBus.emit(targets);\n clearActions();\n };\n\n const confirmDelete = async (targets: string[]) => {\n if (targets.length === 0) return;\n targets.forEach((id) => processingActions.value.set(id, \"cancel-request\"));\n\n try {\n await handlers.deleteMessages(targets);\n } finally {\n targets.forEach((id) => processingActions.value.delete(id));\n }\n };\n\n const processingActions = ref(new Map<string, string>());\n\n const isActionBusy = (messageId: string, actionKey: string) =>\n processingActions.value.get(messageId) === actionKey;\n\n const editingMessage = ref<ExtendedMessage | null>(null);\n\n const deleteBus = useEventBus<string[]>(\"chat-delete\");\n const sendBus = useEventBus<Message[]>(\"chat-send\");\n const editBus = useEventBus<ExtendedMessage>(\"edit-message\");\n const updateBus = useEventBus<{ id: string; updates: Partial<Message> }>(\n \"chat-update\",\n );\n\n const canReply = computed(() => selectedMessages.value.size <= 1);\n\n const clearActions = () => {\n clearSelection();\n replyingTo.value = null;\n editingMessage.value = null;\n };\n\n const handleRemoteAction = async (\n messageId: string,\n actionKey: string,\n apiCall: () => Promise<void>,\n ) => {\n processingActions.value.set(messageId, actionKey);\n try {\n await apiCall();\n } finally {\n processingActions.value.delete(messageId);\n }\n };\n\n /**\n * Patches one message in its own conversation. Keyed by the message's conversation rather\n * than the open one, so a send that settles after the user switched chats still lands.\n * When `updates.id` swaps a temp id for one the thread already holds (the realtime event\n * beat the send response), the temp copy is dropped instead of leaving a duplicate.\n */\n const patchMessage = (\n conversationId: string,\n id: string,\n updates: Partial<Message>,\n ) => {\n const list = messagesMap.value[conversationId];\n if (!list) return;\n const index = list.findIndex((m) => m.id === id);\n if (index === -1) return;\n\n if (updates.id && updates.id !== id && list.some((m) => m.id === updates.id)) {\n messagesMap.value[conversationId] = list.filter((_, i) => i !== index);\n return;\n }\n\n messagesMap.value[conversationId] = [\n ...list.slice(0, index),\n { ...list[index]!, ...updates },\n ...list.slice(index + 1),\n ];\n };\n\n /** Puts messages back after a failed delete, in date order. */\n const restoreMessages = (conversationId: string, restored: Message[]) => {\n const list = messagesMap.value[conversationId];\n if (!list || restored.length === 0) return;\n const present = new Set(list.map((m) => m.id));\n const merged = [...list, ...restored.filter((m) => !present.has(m.id))].sort(\n (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime(),\n );\n messagesMap.value[conversationId] = merged;\n const last = merged[merged.length - 1];\n if (last) updateLastMessage(conversationId, last);\n };\n\n const markAsRead = (conversationId: string) => {\n const last = chatStore.getContactById(conversationId)?.lastMessage;\n chatStore.updateContact(conversationId, {\n unreadCount: 0,\n ...(last && { lastMessage: { ...last, isRead: true } }),\n });\n handlers.markRead?.(conversationId).catch((error) =>\n console.error(\"[chat] failed to mark conversation as read\", error),\n );\n };\n\n const updateLastMessage = (conversationId: string, message: Message) => {\n chatStore.updateContact(conversationId, { lastMessage: { ...message } });\n };\n\n const patchLastMessage = (\n conversationId: string,\n messageId: string,\n updates: Partial<Message>,\n ) => {\n const last = chatStore.getContactById(conversationId)?.lastMessage;\n if (last?.id === messageId)\n chatStore.updateContact(conversationId, { lastMessage: { ...last, ...updates } });\n };\n\n const sendMessage = async (messages: Message[]) => {\n const tempMessages = messages.map((m) => ({\n ...m,\n id: `tmp-${crypto.randomUUID()}`,\n isSent: false,\n }));\n\n sendBus.emit(tempMessages);\n\n if (tempMessages.length > 0) {\n const latest = tempMessages[tempMessages.length - 1]!;\n updateLastMessage(latest.conversationId, latest);\n }\n\n await Promise.all(tempMessages.map(deliver));\n };\n\n const applyUpdate = (\n conversationId: string,\n id: string,\n updates: Partial<Message>,\n ) => {\n patchMessage(conversationId, id, updates);\n patchLastMessage(conversationId, id, updates);\n updateBus.emit({ id, updates });\n };\n\n const deliver = async (tempMsg: Message) => {\n const { conversationId } = tempMsg;\n const tracksProgress = tempMsg.type !== \"text\";\n try {\n const canonical = await handlers.sendMessage(tempMsg, {\n onProgress: tracksProgress\n ? (e) => {\n if (e.progress >= 100) {\n uploadProgress.value.delete(tempMsg.id);\n } else {\n uploadProgress.value.set(tempMsg.id, {\n progress: e.progress,\n uploaded: e.uploaded,\n total: e.total,\n });\n }\n }\n : undefined,\n });\n\n uploadProgress.value.delete(tempMsg.id);\n applyUpdate(conversationId, tempMsg.id, {\n id: canonical.id,\n isSent: true,\n isFailed: false,\n });\n } catch {\n uploadProgress.value.delete(tempMsg.id);\n applyUpdate(conversationId, tempMsg.id, { isSent: false, isFailed: true });\n }\n };\n\n /** Re-sends a message whose last attempt failed, keeping its place in the thread. */\n const retryMessage = async (message: Message) => {\n // The bubble hands over its enriched copy; send the stored one.\n const stored = messagesMap.value[message.conversationId]?.find(\n (m) => m.id === message.id,\n );\n if (!stored?.isFailed || !stored.id.startsWith(\"tmp-\")) return;\n applyUpdate(stored.conversationId, stored.id, { isFailed: false });\n await deliver({ ...stored, isFailed: false });\n };\n\n const saveEditMessage = async (id: string, text: string) => {\n const original = editingMessage.value;\n const conversationId = original?.conversationId;\n clearActions();\n if (!conversationId) return;\n\n applyUpdate(conversationId, id, { text, isSent: false });\n\n try {\n await handlers.editMessage(id, text);\n applyUpdate(conversationId, id, { isSent: true, isEdited: true });\n } catch {\n // Put the old text back: the edit never reached the server, and an unsent edit has no retry.\n applyUpdate(conversationId, id, { text: original.text, isSent: true });\n openToast(t(\"chat.editFailed\"), \"error\");\n }\n };\n\n const fetchMessages = async (\n conversationId: string,\n page: number = 1,\n pageSize: number = messagesPageSize.value,\n ) => {\n if (messagesLoadingMap.value[conversationId]) return;\n messagesLoadingMap.value[conversationId] = true;\n try {\n const batch = await handlers.fetchMessages({\n conversationId,\n page,\n pageSize,\n });\n\n const existing = messagesMap.value[conversationId] ?? [];\n // Pages count back from the newest message, so each one sent or received shifts them: an\n // older page can repeat messages already shown.\n const known = new Set(existing.map((m) => m.id));\n messagesMap.value[conversationId] =\n page === 1 ? batch : [...batch.filter((m) => !known.has(m.id)), ...existing];\n messagesPage.value[conversationId] = page;\n messagesHasNextPage.value[conversationId] = batch.length === pageSize;\n } finally {\n delete messagesLoadingMap.value[conversationId];\n }\n };\n\n return {\n isOptionMenuOpen,\n isSelectMode,\n selectedMessages,\n replyingTo,\n selectedArray,\n editWindowHours,\n canEdit,\n canDelete,\n clearSelection,\n startSelectMode,\n setHandlers,\n toggleSelection,\n triggerEdit,\n copyMessageText,\n triggerDelete,\n confirmDelete,\n editingMessage,\n canReply,\n deleteBus,\n sendBus,\n updateBus,\n drafts,\n setDraft,\n sendMessage,\n retryMessage,\n patchMessage,\n restoreMessages,\n saveEditMessage,\n fetchMessages,\n markAsRead,\n updateLastMessage,\n patchLastMessage,\n messagesMap,\n messagesLoading,\n messagesLoadingMap,\n messagesPage,\n messagesPageSize,\n messagesHasNextPage,\n clearActions,\n editBus,\n processingActions,\n isActionBusy,\n handleRemoteAction,\n uploadProgress,\n };\n});\n","import { MediaDownloadOptions, MediaHandlers } from \"~/types\";\nimport { defineStore } from \"pinia\";\n\nconst DB_NAME = \"ChatFileCache\";\n// v2 stores { blob, size, usedAt } so the cache can be kept under a size limit.\nconst DB_VERSION = 2;\nconst STORE_NAME = \"files\";\n/** Least recently used files are dropped beyond this. */\nconst MAX_CACHE_BYTES = 200 * 1024 * 1024;\n\ninterface CacheEntry {\n blob: Blob;\n size: number;\n usedAt: number;\n}\n\nconst request = <T>(req: IDBRequest<T>) =>\n new Promise<T>((resolve, reject) => {\n req.onsuccess = () => resolve(req.result);\n req.onerror = () => reject(req.error);\n });\n\n// One connection for the page, opened on first use.\nlet dbPromise: Promise<IDBDatabase> | null = null;\nconst getDB = () =>\n (dbPromise ??= new Promise<IDBDatabase>((resolve, reject) => {\n const open = indexedDB.open(DB_NAME, DB_VERSION);\n open.onupgradeneeded = () => {\n const db = open.result;\n // v1 stored bare blobs with no sizes; start over rather than guess.\n if (db.objectStoreNames.contains(STORE_NAME)) db.deleteObjectStore(STORE_NAME);\n db.createObjectStore(STORE_NAME);\n };\n open.onsuccess = () => resolve(open.result);\n open.onerror = () => {\n dbPromise = null;\n reject(open.error);\n };\n }));\n\n/** Deletes least recently used entries until the cache fits in MAX_CACHE_BYTES. */\nasync function evict(db: IDBDatabase) {\n const store = db.transaction(STORE_NAME, \"readwrite\").objectStore(STORE_NAME);\n const [keys, entries] = await Promise.all([\n request(store.getAllKeys()),\n request(store.getAll() as IDBRequest<CacheEntry[]>),\n ]);\n let total = entries.reduce((sum, e) => sum + (e?.size ?? 0), 0);\n if (total <= MAX_CACHE_BYTES) return;\n\n const byAge = keys\n .map((key, i) => ({ key, entry: entries[i]! }))\n .sort((a, b) => a.entry.usedAt - b.entry.usedAt);\n for (const { key, entry } of byAge) {\n if (total <= MAX_CACHE_BYTES) break;\n store.delete(key);\n total -= entry.size;\n }\n}\n\nexport const useMediaStore = defineStore(\"media\", () => {\n let handlers: MediaHandlers;\n\n function setHandlers(val: MediaHandlers) {\n handlers = val;\n }\n\n const getCachedBlob = async (url: string): Promise<Blob | null> => {\n try {\n const db = await getDB();\n const store = db.transaction(STORE_NAME, \"readwrite\").objectStore(STORE_NAME);\n const entry = (await request(store.get(url))) as CacheEntry | undefined;\n if (!entry) return null;\n // Mark as recently used, so eviction keeps it.\n store.put({ ...entry, usedAt: Date.now() }, url);\n return entry.blob;\n } catch {\n return null;\n }\n };\n\n const putCachedBlob = async (url: string, blob: Blob): Promise<void> => {\n try {\n const db = await getDB();\n const entry: CacheEntry = { blob, size: blob.size, usedAt: Date.now() };\n await request(\n db.transaction(STORE_NAME, \"readwrite\").objectStore(STORE_NAME).put(entry, url),\n );\n await evict(db);\n } catch {\n // cache is best-effort; ignore write failures\n }\n };\n\n const fetchFileSize = (url: string): Promise<number | null> =>\n handlers.getFileSize(url);\n\n const download = async (\n url: string,\n opts?: MediaDownloadOptions,\n ): Promise<Blob> => {\n const cached = await getCachedBlob(url);\n if (cached) {\n opts?.onProgress?.(100);\n return cached;\n }\n const blob = await handlers.download(url, opts);\n await putCachedBlob(url, blob);\n return blob;\n };\n\n return {\n setHandlers,\n fetchFileSize,\n getCachedBlob,\n download,\n };\n});\n","export default \"data:image/webp;base64,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\"","<script setup lang=\"ts\">\n/** An image that shows a PrimeVue Skeleton until it loads, then fades in. Sized by its class. */\nimport { ref, watch } from \"vue\";\nimport Skeleton from \"primevue/skeleton\";\n\nconst props = withDefaults(\n defineProps<{\n src?: string;\n alt?: string;\n fit?: \"cover\" | \"contain\";\n /** Skip the skeleton, e.g. for decorative images that load from the bundle. */\n noLoading?: boolean;\n }>(),\n { src: \"\", alt: \"\", fit: \"cover\", noLoading: false },\n);\n\nconst loaded = ref(false);\nwatch(\n () => props.src,\n () => (loaded.value = false),\n);\n</script>\n\n<template>\n <div class=\"relative overflow-hidden\">\n <div v-if=\"!loaded && !noLoading\" class=\"absolute inset-0\">\n <Skeleton width=\"100%\" height=\"100%\" border-radius=\"0\" />\n </div>\n <img\n v-if=\"src\"\n :key=\"src\"\n :src=\"src\"\n :alt=\"alt\"\n draggable=\"false\"\n class=\"block size-full select-none transition-opacity duration-300\"\n :class=\"[\n fit === 'cover' ? 'object-cover' : 'object-contain',\n loaded || noLoading ? 'opacity-100' : 'opacity-0',\n ]\"\n @load=\"loaded = true\"\n @error=\"loaded = true\"\n />\n <div v-if=\"$slots.default\" class=\"absolute inset-0\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport MediaImage from \"./MediaImage.vue\";\n\ndefineProps<{\n imagePath?: string;\n title?: string;\n}>();\n</script>\n<template>\n <div class=\"w-full h-full flex flex-col items-center justify-center gap-y-5\">\n <div class=\"h-50 w-50\">\n <MediaImage :src=\"imagePath\" fit=\"contain\" no-loading class=\"size-full\" />\n </div>\n <div class=\"select-none text-label-sm text-center text-chat-muted\">\n {{ title }}\n </div>\n </div>\n</template>\n","import { useI18n } from \"vue-i18n\";\nimport { computed } from \"vue\";\n\nfunction mergeLocaleObjects(objects: Record<string, any>[]) {\n return objects.reduce<Record<string, any>>((result, obj) => {\n for (const [key, value] of Object.entries(obj)) {\n result[key] = {\n ...(result[key] || {}),\n ...value,\n };\n }\n\n return result;\n }, {});\n}\n\nexport default function useLocalI18n(...messages: Record<string, any>[]) {\n return useI18n({\n useScope: \"local\",\n inheritLocale: true,\n messages: mergeLocaleObjects(messages),\n });\n}\n\nexport function useDirection() {\n const { locale } = useI18n();\n\n const dir = computed<\"rtl\" | \"ltr\">(() => {\n const currentLocale = locale.value;\n\n if (currentLocale.startsWith(\"fa\") || currentLocale.startsWith(\"ar\")) {\n return \"rtl\";\n }\n\n return \"ltr\";\n });\n\n return {\n dir,\n };\n}\n","<template>\n <div\n ref=\"parentRef\"\n class=\"h-full w-full overflow-y-auto\"\n :class=\"[scrollbar ? 'chat-scrollbar' : 'hide-scrollbar']\"\n >\n <div\n :style=\"{\n height: `${virtualizer.getTotalSize()}px`,\n width: '100%',\n position: 'relative',\n }\"\n >\n <div\n v-for=\"virtualRow in virtualizer.getVirtualItems()\"\n :key=\"virtualRow.index\"\n :data-index=\"virtualRow.index\"\n :ref=\"(el) => virtualizer.measureElement(el as HTMLElement)\"\n :style=\"{\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n transform: `translateY(${virtualRow.start}px)`,\n }\"\n >\n <slot\n name=\"item\"\n :item=\"items[virtualRow.index]\"\n :index=\"virtualRow.index\"\n />\n </div>\n </div>\n\n <div\n v-show=\"pagination && hasNextPage\"\n ref=\"sentinelRef\"\n class=\"flex min-h-13 w-full flex-col justify-center\"\n >\n <slot v-if=\"hasNextPage\" name=\"loader\">\n <Skeleton height=\"2.75rem\" border-radius=\"0.75rem\" />\n </slot>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\" generic=\"T extends Record<string, any>\">\nimport { ref, onMounted, onUnmounted } from \"vue\";\nimport { useVirtualizer } from \"@tanstack/vue-virtual\";\nimport Skeleton from \"primevue/skeleton\";\n\nconst props = withDefaults(\n defineProps<{\n items: T[];\n loading: boolean;\n hasNextPage: boolean;\n scrollbar?: boolean;\n pagination?: boolean;\n }>(),\n {\n scrollbar: false,\n pagination: true,\n },\n);\n\nconst emit = defineEmits<{\n \"load-more\": [];\n}>();\n\nconst parentRef = ref<HTMLElement | null>(null);\nconst sentinelRef = ref<HTMLElement | null>(null);\nlet observer: IntersectionObserver | null = null;\n\nconst virtualizer = useVirtualizer({\n get count() {\n return props.items.length;\n },\n getScrollElement: () => parentRef.value,\n // Internal default guess. TanStack will correct this instantly upon rendering.\n estimateSize: () => 45,\n overscan: 10,\n});\n\ndefineExpose<{\n resetScroll: () => void;\n}>({\n resetScroll: () => {\n if (parentRef.value) {\n parentRef.value.scrollTop = 0;\n }\n },\n});\n\n// Auto-trigger load-more when reaching the bottom\nonMounted(() => {\n if (!sentinelRef.value) return;\n\n observer = new IntersectionObserver(\n ([entry]) => {\n if (\n entry.isIntersecting &&\n props.hasNextPage &&\n !props.loading &&\n props.pagination\n ) {\n emit(\"load-more\");\n }\n },\n { threshold: 0.1 },\n );\n\n observer.observe(sentinelRef.value);\n});\n\nonUnmounted(() => {\n observer?.disconnect();\n});\n</script>\n","<script setup lang=\"ts\">\nimport { computed, useAttrs, type Component } from \"vue\";\nimport {\n PhArrowBendUpLeft,\n PhArrowDown,\n PhArrowLeft,\n PhArrowsClockwise,\n PhArrowUUpLeft,\n PhArrowUUpRight,\n PhBuildings,\n PhCamera,\n PhCaretDown,\n PhCaretLeft,\n PhCaretUp,\n PhCheck,\n PhCheckCircle,\n PhChecks,\n PhCircleNotch,\n PhClock,\n PhCopy,\n PhCornersIn,\n PhDotsThreeVertical,\n PhDownloadSimple,\n PhEraser,\n PhFile,\n PhFiles,\n PhFlag,\n PhFrameCorners,\n PhHamburger,\n PhImage,\n PhInfo,\n PhLightbulb,\n PhLightning,\n PhLightningSlash,\n PhLockKey,\n PhMagnifyingGlass,\n PhMicrophone,\n PhMicrophoneSlash,\n PhMonitor,\n PhMonitorArrowUp,\n PhMoon,\n PhMusicNotes,\n PhPalette,\n PhPaperclip,\n PhPaperPlaneTilt,\n PhPause,\n PhPauseCircle,\n PhPawPrint,\n PhPencilLine,\n PhPencilSimpleLine,\n PhPhone,\n PhPhoneCall,\n PhPhoneX,\n PhPlay,\n PhPlayCircle,\n PhPlus,\n PhResize,\n PhSmiley,\n PhSoccerBall,\n PhSpeakerHigh,\n PhSpeakerSlash,\n PhSubtitles,\n PhSunDim,\n PhTrash,\n PhTrayArrowDown,\n PhUploadSimple,\n PhUsers,\n PhVideo,\n PhVideoCamera,\n PhVideoCameraSlash,\n PhWarning,\n PhWarningCircle,\n PhWarningOctagon,\n PhWaveform,\n PhX,\n PhXCircle,\n PhXSquare,\n} from \"@phosphor-icons/vue\";\n\nconst props = withDefaults(\n defineProps<{\n icon: string;\n weight?: \"thin\" | \"light\" | \"regular\" | \"bold\" | \"fill\" | \"duotone\";\n size?: string | number;\n }>(),\n {\n weight: \"regular\",\n size: \"1em\",\n },\n);\n\nconst attrs = useAttrs();\n\n// Filter out 'class' to handle it separately and avoid duplication\nconst filteredAttrs = computed(() => {\n const { class: _, ...rest } = attrs;\n return rest;\n});\n\ntype PhosphorComponent = Component & { name?: string };\n\nconst icons: Record<string, PhosphorComponent> = {\n PhArrowBendUpLeft,\n PhArrowDown,\n PhArrowLeft,\n PhArrowsClockwise,\n PhArrowUUpLeft,\n PhArrowUUpRight,\n PhBuildings,\n PhCamera,\n PhCaretDown,\n PhCaretLeft,\n PhCaretUp,\n PhCheck,\n PhCheckCircle,\n PhChecks,\n PhCircleNotch,\n PhClock,\n PhCopy,\n PhCornersIn,\n PhDotsThreeVertical,\n PhDownloadSimple,\n PhEraser,\n PhFile,\n PhFiles,\n PhFlag,\n PhFrameCorners,\n PhHamburger,\n PhImage,\n PhInfo,\n PhLightbulb,\n PhLightning,\n PhLightningSlash,\n PhLockKey,\n PhMagnifyingGlass,\n PhMicrophone,\n PhMicrophoneSlash,\n PhMonitor,\n PhMonitorArrowUp,\n PhMoon,\n PhMusicNotes,\n PhPalette,\n PhPaperclip,\n PhPaperPlaneTilt,\n PhPause,\n PhPauseCircle,\n PhPawPrint,\n PhPencilLine,\n PhPencilSimpleLine,\n PhPhone,\n PhPhoneCall,\n PhPhoneX,\n PhPlay,\n PhPlayCircle,\n PhPlus,\n PhResize,\n PhSmiley,\n PhSoccerBall,\n PhSpeakerHigh,\n PhSpeakerSlash,\n PhSubtitles,\n PhSunDim,\n PhTrash,\n PhTrayArrowDown,\n PhUploadSimple,\n PhUsers,\n PhVideo,\n PhVideoCamera,\n PhVideoCameraSlash,\n PhWarning,\n PhWarningCircle,\n PhWarningOctagon,\n PhWaveform,\n PhX,\n PhXCircle,\n PhXSquare,\n};\n\nconst iconComponent = computed<PhosphorComponent | string>(() => {\n if (!props.icon) return \"span\";\n\n const name = normalizeIconName(props.icon);\n return icons[name] ?? \"span\";\n});\n\nfunction normalizeIconName(icon: string): string {\n // Strip a \"Ph\"/\"ph\" prefix (case-insensitive), then re-add a normalized \"Ph\".\n const withoutPrefix = /^ph/i.test(icon) ? icon.slice(2) : icon;\n return \"Ph\" + withoutPrefix.charAt(0).toUpperCase() + withoutPrefix.slice(1);\n}\n</script>\n<template>\n <component\n :is=\"iconComponent\"\n :weight=\"weight\"\n :size=\"size\"\n v-bind=\"filteredAttrs\"\n :class=\"['inline-block fill-current transition-all duration-200']\"\n />\n</template>","import type { Directive, DirectiveBinding } from \"vue\";\n\n// 1. The visual skeleton properties (No transitions here)\nconst coreClasses = [\n \"!text-transparent\",\n \"!bg-surface-variant-2\",\n \"dark:!bg-surface-variant-2\",\n \"!animate-pulse\",\n \"!rounded\",\n \"!pointer-events-none\",\n \"!select-none\",\n \"[&>*]:!opacity-0\",\n \"will-change-[opacity,background-color]\",\n];\n\n// 2. The transition properties (Applied AFTER initial load)\nconst transitionClasses = [\"!transition-all\", \"!duration-300\", \"!ease-in-out\"];\n\nconst loadingDirective: Directive & {\n getSSRProps?: (binding: DirectiveBinding) => Record<string, string>;\n} = {\n getSSRProps(binding: DirectiveBinding): Record<string, string> {\n if (binding.value) {\n return {\n class: coreClasses.join(\" \"),\n \"aria-busy\": \"true\",\n \"aria-hidden\": \"true\",\n };\n }\n return {};\n },\n // Runs BEFORE the element is added to the DOM\n beforeMount(el: HTMLElement, binding: DirectiveBinding) {\n if (binding.value) {\n // Instantly apply the skeleton visual without any delay/fade\n el.classList.add(...coreClasses);\n el.setAttribute(\"aria-busy\", \"true\");\n el.setAttribute(\"aria-hidden\", \"true\");\n }\n },\n\n // Runs AFTER the element is fully drawn on the screen\n mounted(el: HTMLElement) {\n void el.offsetHeight;\n // Wait for the browser to finish the initial paint,\n // then silently add the transition classes so future changes fade smoothly.\n requestAnimationFrame(() => {\n el.classList.add(...transitionClasses);\n });\n },\n\n // Runs when your `isLoading` boolean changes\n updated(el: HTMLElement, binding: DirectiveBinding) {\n if (binding.value !== binding.oldValue) {\n if (binding.value) {\n requestAnimationFrame(() => {\n el.classList.add(...coreClasses);\n el.setAttribute(\"aria-busy\", \"true\");\n el.setAttribute(\"aria-hidden\", \"true\");\n });\n } else {\n requestAnimationFrame(() => {\n el.classList.remove(...coreClasses);\n el.removeAttribute(\"aria-busy\");\n el.removeAttribute(\"aria-hidden\");\n });\n }\n }\n },\n};\n\nexport default loadingDirective;\n","export function parseEmojiArray(text: string | undefined) {\n if (!text) return [];\n\n // Safely split text by visual characters\n const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });\n const graphemes = Array.from(segmenter.segment(text)).map(s => s.segment);\n\n const emojiRegex = /\\p{Extended_Pictographic}|\\p{Regional_Indicator}/u;\n const result: Array<{ type: 'text' | 'emoji'; content: string }> = [];\n let currentText = '';\n\n for (const grapheme of graphemes) {\n if (emojiRegex.test(grapheme)) {\n if (currentText) {\n result.push({ type: 'text', content: currentText });\n currentText = '';\n }\n result.push({ type: 'emoji', content: grapheme });\n } else {\n currentText += grapheme;\n }\n }\n\n if (currentText) {\n result.push({ type: 'text', content: currentText });\n }\n\n return result;\n}","<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport { parseEmojiArray } from \"~/utils/emojiParser\";\n\nconst props = withDefaults(\n defineProps<{\n text?: string;\n truncate?: boolean;\n }>(),\n {\n text: \"\",\n truncate: false,\n },\n);\n\nconst parsedText = computed(() => parseEmojiArray(props.text));\n</script>\n\n<template>\n <component\n :is=\"truncate ? 'div' : 'span'\"\n :class=\"[\n truncate\n ? 'line-clamp-1 overflow-hidden text-ellipsis break-all w-full'\n : 'inline whitespace-pre-wrap break-words',\n ]\"\n >\n <template v-for=\"(chunk, index) in parsedText\" :key=\"index\">\n <span\n v-if=\"chunk.type === 'emoji'\"\n class=\"emoji-glyph inline-block h-5 w-5 leading-5 text-xl align-middle select-text\"\n >{{ chunk.content }}</span>\n <span v-else>{{ chunk.content }}</span>\n </template>\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport Avatar from \"primevue/avatar\";\nimport type { Contact } from \"~/types\";\n\nconst props = withDefaults(\n defineProps<{\n contact: Contact;\n showOnline?: boolean;\n }>(),\n { showOnline: true },\n);\n\nconst image = computed(() => props.contact.imageUrl?.trim() || undefined);\n\nconst initials = computed(() => {\n const first = props.contact?.name?.trim() || \"\";\n const last = props.contact?.lastName?.trim() || \"\";\n\n if (!first && !last) return \"\";\n\n const firstInitial = first.charAt(0);\n const lastInitial = last.charAt(0);\n\n const isRTL = /[-ۿ]/.test(firstInitial);\n\n if (isRTL) {\n return lastInitial ? `${firstInitial} ${lastInitial}` : firstInitial;\n } else {\n return (firstInitial + lastInitial).toUpperCase();\n }\n});\n</script>\n<template>\n <div class=\"relative z-10 size-full\">\n <Avatar\n :image=\"image\"\n :label=\"image ? undefined : initials\"\n shape=\"circle\"\n class=\"size-full! bg-chat-primary/10! text-sm! font-semibold text-chat-primary! select-none\"\n :pt=\"{ image: { draggable: false } }\"\n />\n <div\n v-if=\"contact.isOnline && showOnline\"\n class=\"absolute right-0 bottom-0 size-2.5 rounded-full border-2 border-chat-background bg-chat-primary\"\n ></div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport Badge from \"primevue/badge\";\nimport vLoading from \"~/directives/loading\";\nimport SafeEmojiText from \"~/components/general/SafeEmojiText.vue\";\nimport { useProfileStore } from \"~/stores/profileStore.js\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { useChatStore } from \"~/stores/chatStore.js\";\nimport { useMessagesStore } from \"~/stores/messageStores.js\";\nimport { chatContactDisplay } from \"@i18n/locales\";\nimport ContactAvatar from \"./ContactAvatar.vue\";\nimport { useDate } from \"~/composables/useDate\";\nimport type { Contact } from \"~/types\";\nimport { computed } from \"vue\";\n\nconst props = defineProps<{\n contact: Contact;\n loading?: boolean;\n}>();\n\nconst { t } = useLocalI18n(chatContactDisplay);\nconst chatStore = useChatStore();\nconst messagesStore = useMessagesStore();\nconst profileStore = useProfileStore();\nconst currentUserId = computed(() => profileStore.userId);\n\nconst isActive = computed(\n () => chatStore.activeConversationId === props.contact.id,\n);\n\nconst isLoading = computed(() => props.loading);\nconst unreadCount = computed(() => props.contact.unreadCount ?? 0);\n\nconst openChat = () => {\n chatStore.setSelectedChat(props.contact.id);\n};\n\n// The open chat shows its draft in the input already.\nconst draft = computed(() =>\n isActive.value ? \"\" : (messagesStore.drafts[props.contact.id] ?? \"\"),\n);\n\nconst isFromMe = computed(\n () => props.contact.lastMessage?.senderId === currentUserId.value,\n);\n\nconst lastMessageIcon = computed(() => {\n const msg = props.contact.lastMessage;\n if (!msg || !isFromMe.value) return { color: \"\", icon: \"\" };\n\n if (msg.isFailed) return { color: \"fill-error\", icon: \"PhWarningCircle\" };\n if (!msg.isSent)\n return { color: \"fill-chat-on-background/30\", icon: \"PhClock\" };\n if (!msg.isRead)\n return { color: \"fill-chat-muted\", icon: \"PhCheck\" };\n return { color: \"fill-chat-primary\", icon: \"PhChecks\" };\n});\n\nconst attachmentIcon = computed(() => {\n const msg = props.contact.lastMessage;\n if (!msg) return null;\n\n if (msg.request) return \"PhSubtitles\";\n\n const icons: Record<string, string> = {\n image: \"PhImage\",\n file: \"PhFile\",\n voice: \"PhMicrophone\",\n video: \"PhVideo\",\n };\n\n if (msg.type !== \"text\") {\n return icons[msg.type] || null;\n }\n\n return null;\n});\n\nconst { formatTime, formatDateShort } = useDate();\n\n/** Today's messages show their time; older ones their date. */\nconst lastMessageTime = computed(() => {\n const date = props.contact.lastMessage?.date;\n if (!date) return \"\";\n return new Date(date).toDateString() === new Date().toDateString()\n ? formatTime(date)\n : formatDateShort(date);\n});\n\nconst lastMessageText = computed(() => {\n const msg = props.contact.lastMessage;\n if (!msg) return \"\";\n\n // Handle content (Text or Attachment Title)\n let content = msg.text;\n if (!content && msg.request) {\n content = t(\"attachementTypes.request\");\n }\n if (!content && msg.type !== \"text\") {\n content = t(`attachementTypes.${msg.type}`);\n }\n\n // Handle Name Prefix\n if (!isFromMe.value) {\n return `${props.contact.name}: ${content}`;\n }\n\n return content;\n});\n\nconst lastMessageColor = computed(() => {\n const msg = props.contact.lastMessage;\n if (!msg) return \"text-chat-muted\";\n\n if ((!msg.text && msg.type !== \"text\") || msg.request)\n return \"text-chat-primary font-medium\";\n\n if (unreadCount.value > 0)\n return \"text-chat-on-background font-medium\";\n\n return \"text-chat-muted\";\n});\n</script>\n<template>\n <div\n data-testid=\"chat-contact\"\n :data-contact-id=\"contact.id\"\n @click=\"openChat\"\n :class=\"[isActive ? 'bg-chat-surface' : 'bg-chat-surface/0']\"\n class=\"rounded-xl w-full transition-all duration-200 ease-in-out cursor-pointer p-2.5 flex justify-between gap-x-3 items-center h-19\"\n >\n <div v-loading=\"isLoading\" class=\"relative shrink-0 h-11 w-11\">\n <ContactAvatar :contact=\"contact\" />\n </div>\n\n <div class=\"select-none flex-1 overflow-hidden\">\n <div class=\"w-full flex items-center justify-between\">\n <div\n class=\"text-label-md text-chat-on-background min-w-20 truncate\"\n v-loading=\"isLoading\"\n >\n {{ contact.name }} {{ contact.lastName }}\n </div>\n <div\n v-if=\"contact.lastMessage\"\n class=\"flex gap-x-1.5 items-center shrink-0\"\n >\n <div\n v-loading=\"isLoading\"\n class=\"text-chat-muted text-[11px]\"\n >\n {{ lastMessageTime }}\n </div>\n <BIcon\n v-if=\"lastMessageIcon.icon !== ''\"\n :icon=\"lastMessageIcon.icon\"\n :class=\"lastMessageIcon.color\"\n class=\"w-4 h-4\"\n />\n </div>\n </div>\n\n <div class=\"w-full flex items-center justify-between mt-0.5\">\n <div class=\"flex items-center gap-x-1.5 flex-1 overflow-hidden\">\n <div\n v-if=\"draft\"\n class=\"max-w-full truncate text-body-sm flex items-center gap-x-1\"\n >\n <span class=\"text-error shrink-0\">{{ t(\"draft\") }}:</span>\n <SafeEmojiText\n truncate\n :text=\"draft\"\n class=\"text-chat-muted\"\n />\n </div>\n\n <BIcon\n v-if=\"!draft && attachmentIcon && contact.lastMessage\"\n weight=\"bold\"\n :icon=\"attachmentIcon\"\n class=\"w-4 h-4 fill-chat-primary shrink-0\"\n />\n\n <div\n v-loading=\"isLoading\"\n v-if=\"!draft && contact.lastMessage\"\n :class=\"[\n 'max-w-full truncate text-body-sm transition-colors',\n lastMessageColor,\n ]\"\n >\n <SafeEmojiText truncate :text=\"lastMessageText\" />\n </div>\n </div>\n\n <div class=\"h-full flex items-center shrink-0 ms-2\">\n <Badge\n v-if=\"unreadCount > 0 && !isLoading\"\n dir=\"ltr\"\n severity=\"danger\"\n :value=\"unreadCount > 99 ? '+99' : unreadCount\"\n />\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** A placeholder conversation row, the size and shape of ChatContactDisplay, for loading more. */\nimport Skeleton from \"primevue/skeleton\";\n</script>\n\n<template>\n <div\n class=\"vue-chat flex h-19 w-full items-center gap-x-3 p-2.5\"\n aria-hidden=\"true\"\n >\n <Skeleton shape=\"circle\" size=\"2.75rem\" class=\"shrink-0\" />\n <div class=\"flex flex-1 flex-col gap-y-2.5 overflow-hidden\">\n <div class=\"flex items-center justify-between\">\n <Skeleton width=\"7rem\" height=\"0.875rem\" />\n <Skeleton width=\"2rem\" height=\"0.625rem\" />\n </div>\n <Skeleton width=\"60%\" height=\"0.75rem\" />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * An icon-only PrimeVue Button showing a Phosphor icon. Defaults to a round, text, secondary\n * button; any Button prop (severity, variant, size, loading, disabled...) and listener passes\n * through and overrides those defaults.\n */\nimport Button from \"primevue/button\";\nimport BIcon from \"~/components/global/BIcon.vue\";\n\ndefineOptions({ inheritAttrs: false });\n\nwithDefaults(\n defineProps<{\n icon: string;\n /** Accessible name; the button has no visible text. */\n label: string;\n weight?: \"thin\" | \"light\" | \"regular\" | \"bold\" | \"fill\" | \"duotone\";\n iconClass?: string;\n }>(),\n { weight: \"regular\", iconClass: \"size-5\" },\n);\n</script>\n\n<template>\n <Button rounded text severity=\"secondary\" v-bind=\"$attrs\" :aria-label=\"label\">\n <template #icon>\n <BIcon :icon=\"icon\" :weight=\"weight\" :class=\"iconClass\" />\n </template>\n </Button>\n</template>\n","<script setup lang=\"ts\">\nimport { nextTick, ref, type ComponentPublicInstance } from \"vue\";\nimport InputText from \"primevue/inputtext\";\nimport IconButton from \"~/components/general/IconButton.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { chatListSearch } from \"@i18n/locales\";\nconst model = defineModel<string>({ default: \"\" });\n\nconst { t } = useLocalI18n(chatListSearch);\nconst isOpen = ref(false);\nconst inputRef = ref<ComponentPublicInstance | null>(null);\n\nconst toggleSearch = async () => {\n isOpen.value = !isOpen.value;\n if (!isOpen.value) {\n model.value = \"\";\n return;\n }\n await nextTick();\n (inputRef.value?.$el as HTMLInputElement | undefined)?.focus();\n};\n</script>\n<template>\n <div class=\"w-full\">\n <div\n class=\"flex h-16 w-full shrink-0 items-center justify-between gap-x-2 border-b border-b-chat-outline-variant px-5 md:h-20\"\n >\n <div\n v-if=\"!isOpen\"\n class=\"truncate text-label-lg text-chat-on-background select-none\"\n >\n {{ t(\"title\") }}\n </div>\n <InputText\n v-else\n ref=\"inputRef\"\n v-model=\"model\"\n data-testid=\"chat-search\"\n :placeholder=\"t('search')\"\n size=\"small\"\n class=\"min-w-0 flex-1\"\n />\n\n <IconButton\n :icon=\"isOpen ? 'PhX' : 'PhMagnifyingGlass'\"\n :label=\"t('search')\"\n data-testid=\"chat-search-toggle\"\n class=\"shrink-0\"\n @click=\"toggleSearch\"\n />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { ref, computed, watch, onMounted, onBeforeUnmount } from \"vue\";\nimport SelectButton from \"primevue/selectbutton\";\nimport NoData from \"~/assets/lib-images/chat/empty-state.webp\";\nimport NoDataDisplay from \"~/components/general/NoDataDisplay.vue\";\nimport type { ChatFilter, StateKeys } from \"~/types\";\nimport ChatContactDisplay from \"./ChatContactDisplay.vue\";\nimport ContactSkeleton from \"./ContactSkeleton.vue\";\nimport { useChatStore } from \"~/stores/chatStore.js\";\nimport ChatListSearch from \"./ChatListSearch.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { chatList } from \"@i18n/locales\";\nconst { t } = useLocalI18n(chatList);\nconst chatStore = useChatStore();\n\nconst activeFilter = ref<StateKeys>(\"\");\nconst searchText = ref(\"\");\nconst listRef = ref<HTMLElement | null>(null);\n\nlet searchTimeout: ReturnType<typeof setTimeout> | null = null;\n\nconst currentState = computed(\n () => chatStore.conversationStates[activeFilter.value],\n);\n\nconst chats = computed(() =>\n chatStore.getDisplayedContacts(activeFilter.value),\n);\n\nconst filters = computed<ChatFilter[]>(() => [\n { key: \"active\", label: t(\"filters.active\") },\n { key: \"ended\", label: t(\"filters.ended\") },\n]);\n\nconst setFilter = (type: StateKeys) => {\n if (activeFilter.value === type) return;\n activeFilter.value = type;\n};\n\n// Handle Filter Changes\nwatch(activeFilter, (newFilter) => {\n // 1. Scroll to top\n const scrollEl = listRef.value;\n if (scrollEl) scrollEl.scrollTop = 0;\n\n // 2. Fetch if category is empty\n if (chatStore.conversationStates[newFilter].data.length === 0) {\n chatStore.fetchConversations(newFilter, 1);\n }\n});\n\n// Handle Search with Debounce\nwatch(searchText, (newQuery) => {\n if (searchTimeout) clearTimeout(searchTimeout);\n\n searchTimeout = setTimeout(() => {\n chatStore.fetchConversations(activeFilter.value, 1, newQuery);\n\n const scrollEl = listRef.value;\n if (scrollEl) scrollEl.scrollTop = 0;\n }, 500);\n});\n\nonMounted(() => {\n if (chatStore.conversationStates[activeFilter.value].data.length === 0) {\n chatStore.fetchConversations(activeFilter.value, 1);\n }\n});\n\n// Cleanup timeout to prevent memory leaks or state updates on unmounted components\nonBeforeUnmount(() => {\n if (searchTimeout) clearTimeout(searchTimeout);\n});\n</script>\n\n<template>\n <div\n class=\"vue-chat flex h-full w-full flex-col overflow-hidden border border-chat-outline-variant bg-chat-background\"\n >\n <ChatListSearch v-model=\"searchText\" class=\"shrink-0\" />\n\n <div class=\"flex w-full flex-1 flex-col overflow-hidden\">\n <div class=\"flex w-full shrink-0 items-center gap-x-2 px-5 py-2\">\n <SelectButton\n :model-value=\"activeFilter || null\"\n :options=\"filters\"\n option-label=\"label\"\n option-value=\"key\"\n size=\"small\"\n @update:model-value=\"(key) => setFilter(key ?? '')\"\n />\n </div>\n\n <div\n v-if=\"currentState.loading || chats.length > 0\"\n class=\"relative w-full flex-1 overflow-hidden px-2.5 pt-2.5\"\n >\n <BVirtualVerticalList\n ref=\"listRef\"\n :items=\"chats\"\n :loading=\"currentState.loading\"\n :has-next-page=\"currentState.hasNextPage\"\n scrollbar\n class=\"h-full w-full\"\n @load-more=\"chatStore.loadNextPage(activeFilter)\"\n >\n <template #loader>\n <ContactSkeleton v-for=\"n in 2\" :key=\"n\" />\n </template>\n <template #item=\"{ item }\">\n <ChatContactDisplay\n :contact=\"item\"\n :loading=\"currentState.loading && (currentState.page === 0 || !!currentState.refreshing)\"\n />\n </template>\n </BVirtualVerticalList>\n </div>\n\n <div v-else class=\"flex w-full flex-1 items-center justify-center\">\n <NoDataDisplay :image-path=\"NoData\" :title=\"t('noMessages')\" />\n </div>\n </div>\n </div>\n</template>\n","// composables/useAppPermissions.ts\nimport { ref } from \"vue\";\nimport { useEventBus } from \"@vueuse/core\";\nexport type PopupState =\n | \"permission\"\n | \"mic-error\"\n | \"cam-error\"\n | \"mic-permission\"\n | \"cam-permission\"\n | \"screen-share-error\"\n | \"screen-share-permission\";\n\ninterface PermissionRequest {\n state: PopupState;\n resolve: (value: boolean) => void;\n}\n\nconst permissionBus = useEventBus<PermissionRequest>(\"global-permission-popup\");\nexport function useAppPermissions() {\n const checkMediaStatus = async () => {\n try {\n const mic = await navigator.permissions.query({\n name: \"microphone\" as PermissionName,\n });\n const cam = await navigator.permissions.query({\n name: \"camera\" as PermissionName,\n });\n return { mic: mic.state, cam: cam.state };\n } catch (err) {\n return { mic: \"unknown\", cam: \"unknown\" };\n }\n };\n\n // Requests BOTH at once as requested, with a fallback if hardware is missing\n const requestMediaAccess = async (need: \"audio\" | \"video\" | \"both\") => {\n try {\n // 1. Try the primary request\n const constraints: MediaStreamConstraints = {\n audio: need === \"audio\" || need === \"both\",\n video: need === \"video\" || need === \"both\",\n };\n\n const stream = await navigator.mediaDevices.getUserMedia(constraints);\n stream.getTracks().forEach((track) => track.stop());\n return { success: true };\n } catch (error: any) {\n // 2. DETECT MISSING HARDWARE (Mac Mini case)\n if (\n error.name === \"NotFoundError\" ||\n error.name === \"DevicesNotFoundError\"\n ) {\n console.warn(\"Hardware not found. Checking for partial success...\");\n\n // If they needed 'both' but only have one (or none), try a partial fallback\n if (need === \"both\") {\n try {\n // Try ONLY video if audio failed\n const vStream = await navigator.mediaDevices.getUserMedia({\n video: true,\n });\n vStream.getTracks().forEach((t) => t.stop());\n return { success: true, hardwareWarning: \"no-mic\" };\n } catch {\n return { success: false, error: \"no-hardware\" };\n }\n }\n return { success: false, error: \"no-hardware\" };\n }\n\n // 3. Handle explicit denials (NotAllowedError)\n return { success: false, error: error.name };\n }\n };\n\n const requestLocation = async (): Promise<GeolocationPosition> => {\n return new Promise((resolve, reject) => {\n if (!navigator.geolocation) return reject(\"Unsupported\");\n navigator.geolocation.getCurrentPosition(resolve, reject);\n });\n };\n\n const requestScreenShare = async (): Promise<boolean> => {\n return await requestWithPopup(\"screen-share-permission\");\n };\n\n const requestWithPopup = (state: PopupState) => {\n return new Promise<boolean>((resolve) => {\n permissionBus.emit({ state, resolve });\n });\n };\n\n const getNativeScreenShare = async (): Promise<MediaStream> => {\n return await navigator.mediaDevices.getDisplayMedia({\n video: true,\n audio: false,\n });\n };\n\n return {\n checkMediaStatus,\n requestMediaAccess,\n requestLocation,\n requestScreenShare,\n requestWithPopup,\n getNativeScreenShare,\n };\n}\n","<script setup lang=\"ts\">\n/**\n * A modal PrimeVue Dialog that is centred on wide screens and becomes a full-width bottom sheet\n * on phones. Dialog props, listeners and slots pass through.\n */\nimport Dialog from \"primevue/dialog\";\nimport { useSlots } from \"vue\";\nimport { useMediaQuery } from \"@vueuse/core\";\n\ndefineOptions({ inheritAttrs: false });\n\nwithDefaults(defineProps<{ width?: string }>(), { width: \"30rem\" });\n\nconst visible = defineModel<boolean>(\"visible\", { default: false });\nconst slotNames: string[] = Object.keys(useSlots());\n\n// Tailwind's `md` breakpoint.\nconst isSheet = useMediaQuery(\"(max-width: 767.98px)\");\n</script>\n\n<template>\n <Dialog\n v-model:visible=\"visible\"\n modal\n :position=\"isSheet ? 'bottom' : 'center'\"\n :draggable=\"false\"\n :style=\"{ width }\"\n :breakpoints=\"{ '767.98px': '100vw' }\"\n v-bind=\"$attrs\"\n :class=\"['vue-chat', isSheet && 'm-0! rounded-b-none!']\"\n >\n <template v-for=\"name in slotNames\" #[name]=\"scope\">\n <slot :name=\"name\" v-bind=\"scope ?? {}\" />\n </template>\n </Dialog>\n</template>\n","<template>\n <ResponsiveDialog\n v-model:visible=\"visible\"\n :show-header=\"false\"\n width=\"30rem\"\n @hide=\"onHide\"\n >\n <div class=\"flex w-full items-center gap-x-2 pt-5 pb-3\">\n <BIcon\n :icon=\"popupIcon.icon\"\n weight=\"fill\"\n :class=\"[popupIcon.color]\"\n class=\"size-7\"\n />\n <div class=\"text-label-lg text-chat-on-background select-none\">\n {{ popupContent.title }}\n </div>\n </div>\n <p class=\"text-body-md text-chat-muted select-none\">\n {{ popupContent.description }}\n </p>\n <div class=\"flex w-full items-center gap-x-3 pt-5\">\n <Button\n :label=\"actionButtonText\"\n :loading=\"isLoading\"\n @click=\"handleAction\"\n />\n <Button\n severity=\"secondary\"\n outlined\n :label=\"t('permissions.notNow')\"\n @click=\"closePopup\"\n />\n </div>\n </ResponsiveDialog>\n</template>\n\n<script setup lang=\"ts\">\nimport {\n useAppPermissions,\n type PopupState,\n} from \"~/composables/useAppPermissions\";\nimport { ref, computed, onUnmounted } from \"vue\";\nimport Button from \"primevue/button\";\nimport ResponsiveDialog from \"~/components/general/ResponsiveDialog.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { permissionPopup } from \"@i18n/locales\";\nimport { useEventBus } from \"@vueuse/core\";\n\nconst { t } = useLocalI18n(permissionPopup);\nconst { requestMediaAccess, getNativeScreenShare } = useAppPermissions();\n\nconst visible = ref(false);\nconst popupMode = ref<PopupState>(\"mic-permission\");\nconst isLoading = ref(false);\nconst currentResolver = ref<((v: boolean) => void) | null>(null);\n\n// --- Event Bus ---\nconst bus = useEventBus<{ resolve: (v: boolean) => void; state: PopupState }>(\n \"global-permission-popup\",\n);\n\n// `bus.on(handler)` returns the cleanup function directly — not an object with an `off` property.\nconst offBus = bus.on((payload) => {\n currentResolver.value = payload.resolve;\n switchMode(payload.state);\n});\n\nonUnmounted(() => {\n offBus();\n});\n\n// --- Computed ---\nconst popupIcon = computed(() => ({\n icon: popupMode.value.endsWith(\"permission\")\n ? \"PhWarningCircle\"\n : \"PhWarningOctagon\",\n color: popupMode.value.endsWith(\"permission\")\n ? \"text-chat-primary\"\n : \"text-chat-error\",\n}));\n\nconst actionButtonText = computed(() =>\n popupMode.value.endsWith(\"permission\")\n ? t(\"permissions.allow\")\n : t(\"permissions.retry\"),\n);\n\nconst popupContent = computed(() => {\n switch (popupMode.value) {\n case \"permission\":\n return {\n title: t(\"permissions.permissionTitle\"),\n description: t(\"permissions.description\"),\n };\n case \"cam-error\":\n return {\n title: t(\"permissions.camError.title\"),\n description: t(\"permissions.camError.description\"),\n };\n case \"mic-error\":\n return {\n title: t(\"permissions.micError.title\"),\n description: t(\"permissions.micError.description\"),\n };\n case \"cam-permission\":\n return {\n title: t(\"permissions.cam.title\"),\n description: t(\"permissions.cam.description\"),\n };\n case \"mic-permission\":\n return {\n title: t(\"permissions.mic.title\"),\n description: t(\"permissions.mic.description\"),\n };\n case \"screen-share-error\":\n return {\n title: t(\"permissions.screenError.title\"),\n description: t(\"permissions.screenError.description\"),\n };\n case \"screen-share-permission\":\n return {\n title: t(\"permissions.screen.title\"),\n description: t(\"permissions.screen.description\"),\n };\n }\n});\n\n// --- Methods ---\nconst settle = (granted: boolean) => {\n currentResolver.value?.(granted);\n currentResolver.value = null;\n};\n\nlet switching = false;\n\n// Dismissing the dialog (Escape) refuses, like \"Not now\"; switching to another state does not.\nconst onHide = () => {\n if (!switching) settle(false);\n};\n\nconst switchMode = async (newMode: PopupState) => {\n switching = true;\n visible.value = false;\n\n // Let the closing dialog finish animating before it reopens with new content.\n await new Promise((resolve) => setTimeout(resolve, 300));\n\n popupMode.value = newMode;\n isLoading.value = false;\n visible.value = true;\n switching = false;\n};\n\nconst closePopup = () => {\n settle(false);\n visible.value = false;\n};\n\nconst handleAction = async () => {\n isLoading.value = true;\n let success = false;\n\n // --- 1. SCREEN SHARE FLOW (Standalone) ---\n if (popupMode.value === \"screen-share-permission\") {\n try {\n const stream = await getNativeScreenShare();\n if (stream) success = true;\n } catch (err: unknown) {\n console.error(\"Screen Share Error:\", (err as Error).name);\n success = false;\n }\n\n isLoading.value = false;\n if (success) {\n settle(true);\n visible.value = false;\n } else {\n // macOS often throws NotAllowedError if System Settings are off\n await switchMode(\"screen-share-error\");\n }\n return; // EXIT HERE so it doesn't run the Mic/Cam logic below\n }\n\n // --- 2. MIC / CAM FLOW ---\n let need: \"audio\" | \"video\" | \"both\" = \"audio\";\n if (popupMode.value.startsWith(\"cam\")) need = \"video\";\n if (popupMode.value === \"permission\") need = \"both\";\n\n const result = await requestMediaAccess(need);\n\n isLoading.value = false;\n if (result.success) {\n settle(true);\n visible.value = false;\n } else {\n // If hardware is missing (Mac Mini), show a specific error\n const errorMode =\n need === \"video\" || need === \"both\" ? \"cam-error\" : \"mic-error\";\n await switchMode(errorMode);\n }\n};\n\ndefineExpose<{\n open: (state: PopupState) => void;\n close: () => void;\n setLoading: (state: boolean) => void;\n}>({\n open: (state: PopupState) => {\n popupMode.value = state;\n isLoading.value = false;\n visible.value = true;\n },\n close: closePopup,\n setLoading: (state: boolean) => {\n isLoading.value = state;\n },\n});\n</script>\n","export default \"data:image/webp;base64,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\"","export const replaceDigitsByLocale = (\n value: string | number,\n locale: string = \"fa\",\n): string => {\n if (value === null || value === undefined) return \"\";\n const str = String(value);\n if (locale !== \"fa\") return str;\n const persianDigits = [\"۰\", \"۱\", \"۲\", \"۳\", \"۴\", \"۵\", \"۶\", \"۷\", \"۸\", \"۹\"];\n return str.replace(/\\d/g, (digit) => {\n return persianDigits[parseInt(digit)];\n });\n};\n\nexport const formatBytes = (bytes: number) => {\n if (bytes === 0) return \"0 KB\";\n const k = 1024;\n const sizes = [\"Bytes\", \"KB\", \"MB\", \"GB\"];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + \" \" + sizes[i];\n};\n\nexport const formatDuration = (totalSeconds: number): string => {\n const hours = Math.floor(totalSeconds / 3600);\n const minutes = Math.floor((totalSeconds % 3600) / 60);\n const seconds = totalSeconds % 60;\n\n const padded = (val: number) => val.toString().padStart(2, \"0\");\n\n if (hours > 0) {\n return `${padded(hours)}:${padded(minutes)}:${padded(seconds)}`;\n }\n\n return `${padded(minutes)}:${padded(seconds)}`;\n};\n","<script setup lang=\"ts\">\nimport vLoading from \"~/directives/loading\";\nimport { ref, computed, onMounted } from \"vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { profileFileDisplay } from \"@i18n/locales\";\nimport { formatBytes } from \"~/utils/format\";\nimport { useMediaStore } from \"~/stores/mediaStore\";\n\nconst props = withDefaults(\n defineProps<{\n url: string;\n loading?: boolean;\n }>(),\n {\n loading: true,\n },\n);\n\nconst { t } = useLocalI18n(profileFileDisplay);\nconst mediaStore = useMediaStore();\nconst fetchedSize = ref<number | null>(null);\nconst isLoading = computed(() => props.loading);\n\nconst fileName = computed(() => {\n try {\n const urlObj = new URL(props.url);\n const path = urlObj.pathname;\n return decodeURIComponent(path.split(\"/\").pop() || \"Unknown_File\");\n } catch {\n return \"File\";\n }\n});\n\nconst fileExt = computed(() => {\n const name = fileName.value;\n const lastDot = name.lastIndexOf(\".\");\n if (lastDot !== -1) {\n return name\n .substring(lastDot + 1)\n .toUpperCase()\n .substring(0, 4);\n }\n return \"FILE\";\n});\n\nconst formattedSize = computed(() => {\n // FIX: Check `!== null` instead of truthy. If the file size is exactly 0 bytes,\n // a truthy check would incorrectly show \"Calculating...\" forever.\n return fetchedSize.value !== null\n ? formatBytes(fetchedSize.value)\n : t(\"file.calculating\");\n});\n\nconst getFileSize = async () => {\n try {\n const size = await mediaStore.fetchFileSize(props.url);\n fetchedSize.value = size ?? 0;\n } catch (e) {\n console.warn(\"Could not fetch file size upfront:\", e);\n fetchedSize.value = 0; // Fallback\n }\n};\n\nonMounted(() => {\n getFileSize();\n});\n</script>\n\n<template>\n <div class=\"flex w-full select-none items-center gap-x-2\">\n <div class=\"flex min-w-0 flex-1 flex-col gap-y-0.5 text-left\">\n <div v-loading=\"isLoading\" class=\"truncate text-label-md text-chat-on-background\">\n {{ fileName }}\n </div>\n <div\n v-loading=\"isLoading\"\n dir=\"ltr\"\n class=\"text-body-sm text-chat-on-background/70\"\n >\n {{ formattedSize }}\n </div>\n </div>\n\n <div\n v-loading=\"isLoading\"\n class=\"relative shrink-0 cursor-pointer transition-transform active:scale-95\"\n >\n <BIcon\n icon=\"PhFile\"\n weight=\"fill\"\n class=\"h-10 w-10 fill-chat-surface-3\"\n />\n <div\n class=\"absolute bottom-2 right-0 flex items-center justify-center rounded-sm bg-chat-error px-1 py-0.5\"\n >\n <div\n class=\"text-center text-[7px] font-bold uppercase leading-none tracking-wide text-white\"\n >\n {{ fileExt }}\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport Button from \"primevue/button\";\nimport Tab from \"primevue/tab\";\nimport TabList from \"primevue/tablist\";\nimport Tabs from \"primevue/tabs\";\nimport Tag from \"primevue/tag\";\nimport vLoading from \"~/directives/loading\";\nimport IconButton from \"~/components/general/IconButton.vue\";\nimport MediaImage from \"~/components/general/MediaImage.vue\";\nimport profileBackground from \"~/assets/lib-images/chat/profile-background.webp\";\nimport { useProfileStore } from \"~/stores/profileStore.js\";\nimport ContactAvatar from \"./contact/ContactAvatar.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { useChatStore } from \"~/stores/chatStore.js\";\nimport { useCallStore } from \"~/stores/callStore.js\";\nimport { chatProfileOverview } from \"@i18n/locales\";\nimport FileDisplay from \"./profile/FileDisplay.vue\";\nimport { useDate } from \"~/composables/useDate.js\";\nimport { ref, computed, watch } from \"vue\";\nimport type { Contact } from \"~/types\";\n\ninterface Action {\n title: string;\n icon: string;\n key: \"end\" | \"voice-call\" | \"video-call\";\n active: boolean | null;\n color?: string;\n}\n\nconst props = withDefaults(\n defineProps<{\n profile?: Contact | null;\n }>(),\n {\n profile: null,\n },\n);\n\nconst { getYearsPassed } = useDate();\nconst callStore = useCallStore();\nconst chatStore = useChatStore();\nconst profileStore = useProfileStore();\nconst { t } = useLocalI18n(chatProfileOverview);\n// FIX: Renamed from `imageList` to `imagesSection` to actually match the template ref=\"imagesSection\"\nconst imagesSection = ref<HTMLElement | null>(null);\n\nconst conversationId = computed(() => chatStore.activeConversationId ?? \"\");\nconst isOpen = ref(false);\nconst localProfile = ref<Contact>();\nconst currentTab = ref(0);\n\nconst mediaAttachements = computed<string[]>(\n () =>\n (conversationId.value && profileStore.mediaMap[conversationId.value]) || [],\n);\nconst fileAttachements = computed<string[]>(\n () =>\n (conversationId.value && profileStore.filesMap[conversationId.value]) || [],\n);\nconst isLoadingMedia = computed(() => profileStore.mediaLoading);\nconst isLoadingAttachements = computed(() => profileStore.filesLoading);\nconst hasMediaNextPage = computed(\n () =>\n (conversationId.value &&\n profileStore.mediaHasNextPage[conversationId.value]) ??\n false,\n);\nconst hasFileNextPage = computed(\n () =>\n (conversationId.value &&\n profileStore.filesHasNextPage[conversationId.value]) ??\n false,\n);\n\nconst role = computed(() => chatStore.chosenRole);\nconst isInCall = computed(() => callStore.isActive);\n\nconst listHeight = computed(() => {\n if (!imagesSection.value) return 12;\n return imagesSection.value.clientHeight;\n});\n\nconst maxImageCounts = computed(() =>\n Math.max(Math.floor(listHeight.value / 62) * 4, 12),\n);\nconst imagesPerPage = computed(() => maxImageCounts.value * 4);\nconst filesPerPage = computed(() => maxImageCounts.value);\nconst maxFileCounts = ref(2);\n\nconst tabs = computed(() => [t(\"info.media\"), t(\"info.files\")]);\n\nconst shouldShowTabs = computed(\n () =>\n fileAttachements.value.length > maxFileCounts.value ||\n mediaAttachements.value.length > maxImageCounts.value,\n);\n\nconst isLoading = computed(() => props.profile === null);\nconst showPersonalInfo = computed(() => role.value !== \"user\");\n\nconst actionButtons = computed<Action[]>(() => [\n {\n title: t(\"options.end\"),\n icon: \"PhX\",\n active: localProfile.value ? localProfile.value.isActive : false,\n key: \"end\",\n color: \"error\",\n },\n {\n title: t(\"options.voiceCall\"),\n icon: \"PhPhoneCall\",\n active: localProfile.value\n ? localProfile.value.isActive &&\n localProfile.value.serviceType !== \"chat\" &&\n !isInCall.value\n : false,\n key: \"voice-call\",\n },\n {\n title: t(\"options.videoCall\"),\n icon: \"PhVideoCamera\",\n active: localProfile.value\n ? localProfile.value.isActive &&\n localProfile.value.serviceType === \"video-call\" &&\n !isInCall.value\n : false,\n key: \"video-call\",\n },\n]);\n\nconst chunkedMedia = computed(() => {\n const rows = [];\n for (let i = 0; i < mediaAttachements.value.length; i += 4) {\n rows.push(mediaAttachements.value.slice(i, i + 4));\n }\n return rows;\n});\n\nconst displayedInfo = computed(() => {\n const items = [\n {\n title: t(\"info.nationalCode\"),\n value: localProfile.value?.nationalCode,\n canDisplay: showPersonalInfo.value,\n },\n {\n title: t(\"info.phoneNumber\"),\n value: localProfile.value?.phoneNumber,\n canDisplay: showPersonalInfo.value,\n },\n {\n title: t(\"info.age\"),\n value: getYearsPassed(localProfile.value?.birthDate || new Date()),\n canDisplay: true,\n },\n ];\n return items.filter((item) => item.canDisplay);\n});\n\n// --- Watchers ---\nwatch(\n () => chatStore.profileViewOpen,\n (isProfileOpen) => {\n if (isProfileOpen) {\n if (props.profile) {\n localProfile.value = props.profile;\n }\n isOpen.value = true;\n const id = conversationId.value;\n if (id) {\n profileStore.fetchMedia(id, 1, imagesPerPage.value);\n profileStore.fetchFiles(id, 1, filesPerPage.value);\n }\n } else {\n isOpen.value = false;\n }\n },\n { immediate: true },\n);\n\nwatch(\n () => props.profile,\n (newVal) => {\n if (newVal) {\n localProfile.value = newVal;\n }\n },\n);\n\nwatch(\n () => conversationId.value,\n (newId, oldId) => {\n if (!newId || newId === oldId || !isOpen.value) return;\n profileStore.fetchMedia(newId, 1, imagesPerPage.value);\n profileStore.fetchFiles(newId, 1, filesPerPage.value);\n },\n);\n\n// --- Methods ---\nconst closeSidebar = () => {\n chatStore.closeProfile();\n};\n\nconst handleAction = (action: Action) => {\n if (!action.active) return;\n switch (action.key) {\n case \"end\":\n break;\n case \"voice-call\":\n case \"video-call\":\n if (chatStore.activeConversationId && props.profile) {\n callStore.startCall(chatStore.activeConversationId);\n }\n break;\n }\n};\n\nconst fetchMoreMedia = async () => {\n const id = conversationId.value;\n if (!id) return;\n const nextPage = (profileStore.mediaPage[id] ?? 0) + 1;\n await profileStore.fetchMedia(id, nextPage, imagesPerPage.value);\n};\n\nconst fetchMoreFiles = async () => {\n const id = conversationId.value;\n if (!id) return;\n const nextPage = (profileStore.filesPage[id] ?? 0) + 1;\n await profileStore.fetchFiles(id, nextPage, filesPerPage.value);\n};\n</script>\n\n<template>\n <div\n class=\"h-full shrink-0 overflow-hidden bg-chat-background transition-none md:transition-all md:duration-300 md:ease-in-out ltr:border-r-chat-surface rtl:border-l-chat-surface ltr:border-r rtl:border-l\"\n :class=\"[isOpen ? 'w-dvw md:w-80' : 'w-0 border-none!']\"\n :aria-hidden=\"!isOpen\"\n :inert=\"!isOpen\"\n >\n <div class=\"flex h-full w-full flex-col\">\n <div class=\"flex h-full w-full flex-col md:px-2 md:pt-16.5\">\n <div class=\"relative w-full shrink-0\">\n <div class=\"h-29 w-full\">\n <MediaImage\n :src=\"profileBackground\"\n no-loading\n class=\"size-full md:rounded-xl\"\n >\n <div class=\"p-1\">\n <IconButton\n icon=\"PhX\"\n :label=\"t('actions.close')\"\n class=\"text-white!\"\n @click=\"closeSidebar\"\n />\n </div>\n </MediaImage>\n </div>\n <div\n class=\"flex w-full -translate-y-1/2 items-center justify-center absolute z-20\"\n >\n <div class=\"h-25 w-25 overflow-hidden rounded-full\">\n <ContactAvatar v-if=\"profile\" :contact=\"profile\" />\n </div>\n </div>\n <div class=\"h-12.5 w-full\" />\n </div>\n\n <div\n class=\"flex w-full shrink-0 flex-col items-center justify-center gap-y-2 select-none mt-2\"\n >\n <div\n v-loading=\"isLoading\"\n class=\"text-title-md text-chat-on-background\"\n >\n {{ localProfile?.name }}\n </div>\n <Tag\n v-if=\"localProfile?.isOnline && !isLoading\"\n rounded\n :value=\"t('online')\"\n />\n </div>\n\n <div class=\"w-full shrink-0 px-6\">\n <div class=\"flex w-full items-center justify-center gap-x-2 py-4\">\n <Button\n v-for=\"action in actionButtons\"\n :key=\"action.key\"\n v-loading=\"isLoading\"\n :label=\"action.title\"\n icon-pos=\"top\"\n severity=\"secondary\"\n :disabled=\"!action.active\"\n class=\"aspect-square w-15.5 gap-y-0.5! p-1! text-[10px]!\"\n @click=\"handleAction(action)\"\n >\n <template #icon>\n <BIcon\n :icon=\"action.icon\"\n weight=\"fill\"\n class=\"size-6\"\n :class=\"action.color === 'error' ? 'text-chat-error' : 'text-chat-primary'\"\n />\n </template>\n </Button>\n </div>\n\n <div class=\"w-full\">\n <div class=\"h-0.5 w-full rounded-full bg-chat-surface\" />\n </div>\n\n <div class=\"flex w-full flex-col gap-y-4 py-4\">\n <div\n v-for=\"(info, index) in displayedInfo\"\n :key=\"index\"\n class=\"flex w-full flex-col select-none gap-y-1\"\n >\n <div\n v-loading=\"isLoading\"\n class=\"text-body-sm text-chat-muted\"\n >\n {{ info.title }}\n </div>\n <div\n v-loading=\"isLoading\"\n class=\"text-body-md text-chat-on-background\"\n >\n {{ info.value }}\n </div>\n </div>\n </div>\n </div>\n\n <div class=\"flex min-h-0 w-full flex-1 flex-col select-none\">\n <div\n v-if=\"!shouldShowTabs\"\n class=\"flex h-full w-full min-h-0 flex-col gap-y-1\"\n >\n <div\n v-if=\"fileAttachements.length > 0\"\n class=\"flex w-full shrink-0 flex-col gap-y-1\"\n >\n <div class=\"text-body-sm text-chat-muted\">\n {{ t(\"info.files\") }}\n </div>\n <FileDisplay\n v-for=\"(file, index) in fileAttachements\"\n :key=\"index\"\n :url=\"file\"\n :loading=\"isLoadingAttachements\"\n />\n </div>\n <div\n v-if=\"mediaAttachements.length > 0\"\n class=\"flex flex-1 flex-col gap-y-1\"\n >\n <div class=\"shrink-0 text-body-sm text-chat-muted\">\n {{ t(\"info.media\") }}\n </div>\n <div ref=\"imagesSection\" class=\"w-full flex-1\">\n <div class=\"grid w-full grid-cols-4 gap-x-4 gap-y-3\">\n <div\n v-for=\"(media, index) in mediaAttachements\"\n :key=\"index\"\n class=\"aspect-square md:h-14 md:w-14 overflow-hidden rounded-xl\"\n >\n <MediaImage :src=\"media\" class=\"size-full\" />\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div v-else class=\"flex h-full w-full min-h-0 flex-col gap-y-2\">\n <Tabs v-model:value=\"currentTab\" class=\"shrink-0\">\n <TabList>\n <Tab v-for=\"(tab, index) in tabs\" :key=\"index\" :value=\"index\">\n {{ tab }}\n </Tab>\n </TabList>\n </Tabs>\n <div class=\"w-full flex-1 min-h-0 overflow-hidden\">\n <div\n class=\"flex h-full w-[200%] min-h-0 transition-all duration-200 ease-in-out\"\n :class=\"[\n currentTab === 0\n ? 'translate-x-0'\n : 'ltr:-translate-x-1/2 rtl:translate-x-1/2',\n ]\"\n >\n <div class=\"h-full w-1/2 min-h-0 px-1\">\n <BVirtualVerticalList\n :items=\"chunkedMedia\"\n :loading=\"isLoadingMedia\"\n :has-next-page=\"hasMediaNextPage\"\n @load-more=\"fetchMoreMedia\"\n >\n <template #item=\"{ item: row }\">\n <div class=\"grid w-full grid-cols-4 gap-4 pb-3\">\n <div\n v-for=\"(media, idx) in row\"\n :key=\"idx\"\n class=\"aspect-square md:h-14 md:w-14 overflow-hidden rounded-xl\"\n >\n <MediaImage :src=\"media\" class=\"size-full\" />\n </div>\n </div>\n </template>\n </BVirtualVerticalList>\n </div>\n\n <div class=\"h-full w-1/2 min-h-0 px-1\">\n <BVirtualVerticalList\n :items=\"fileAttachements\"\n :loading=\"isLoadingAttachements\"\n :has-next-page=\"hasFileNextPage\"\n @load-more=\"fetchMoreFiles\"\n >\n <template #item=\"{ item: file }\">\n <div class=\"pb-2\">\n <FileDisplay\n :url=\"file\"\n :loading=\"\n isLoadingAttachements &&\n fileAttachements.length === 0\n \"\n />\n </div>\n </template>\n </BVirtualVerticalList>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n</template>\n","<template>\n <ResponsiveDialog\n v-model:visible=\"visible\"\n :show-header=\"false\"\n :closable=\"!loading\"\n :close-on-escape=\"!loading\"\n :dismissable-mask=\"!loading\"\n width=\"30rem\"\n @after-hide=\"emit('closed')\"\n >\n <div class=\"flex flex-col items-center pt-6 text-center\">\n <div\n class=\"flex size-16 items-center justify-center rounded-full\"\n :class=\"stateStyle.bg\"\n >\n <BIcon\n :icon=\"stateStyle.icon\"\n weight=\"fill\"\n class=\"size-8\"\n :class=\"stateStyle.text\"\n />\n </div>\n <div class=\"mt-4 flex w-full flex-col items-center gap-y-3 select-none\">\n <div v-if=\"title.trim()\" class=\"text-label-lg text-chat-on-background\">\n {{ title }}\n </div>\n <div v-if=\"text.trim()\" class=\"text-body-md text-chat-muted\">\n {{ text }}\n </div>\n </div>\n <div class=\"mt-8 flex w-full items-center gap-x-3\">\n <Button\n class=\"flex-1\"\n :label=\"hasAction ? actionText : t('confirm')\"\n :severity=\"hasAction ? stateStyle.severity : undefined\"\n :loading=\"loading\"\n @click=\"handleAction\"\n />\n <Button\n v-if=\"hasAction\"\n class=\"flex-1\"\n :label=\"t('cancel')\"\n severity=\"secondary\"\n outlined\n :disabled=\"loading\"\n @click=\"closeModal\"\n />\n </div>\n </div>\n </ResponsiveDialog>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed } from \"vue\";\nimport Button from \"primevue/button\";\nimport ResponsiveDialog from \"./ResponsiveDialog.vue\";\nimport type { ModalState } from \"~/types/components/modal\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { bModal } from \"@i18n/locales\";\n\nwithDefaults(\n defineProps<{\n /** Keeps the modal open, with the action button spinning, until cleared. */\n loading?: boolean;\n }>(),\n { loading: false },\n);\n\nconst emit = defineEmits<{\n cancel: [];\n action: [];\n closed: [];\n}>();\n\nconst { t } = useLocalI18n(bModal);\nconst visible = ref(false);\nconst state = ref<ModalState>(\"success\");\nconst text = ref(\"\");\nconst title = ref(\"\");\nconst hasAction = ref(false);\nconst actionText = ref(\"\");\n\nconst STATE_STYLES = {\n error: {\n icon: \"PhWarningOctagon\",\n severity: \"danger\",\n bg: \"bg-chat-error/10\",\n text: \"text-chat-error\",\n },\n warning: {\n icon: \"PhWarning\",\n severity: \"warn\",\n bg: \"bg-chat-warning/10\",\n text: \"text-chat-warning\",\n },\n success: {\n icon: \"PhCheckCircle\",\n severity: undefined,\n bg: \"bg-chat-success/10\",\n text: \"text-chat-success\",\n },\n} as const;\n\nconst stateStyle = computed(() => STATE_STYLES[state.value]);\n\nconst closeModal = () => {\n visible.value = false;\n};\n\nconst openModal = (\n modalTitle: string,\n description: string,\n color: ModalState,\n action: boolean = false,\n modalActionText?: string,\n) => {\n text.value = description;\n title.value = modalTitle;\n state.value = color;\n hasAction.value = action;\n actionText.value = modalActionText || t(\"confirm\");\n visible.value = true;\n};\n\nconst handleAction = () => {\n if (hasAction.value) {\n emit(\"action\");\n } else {\n closeModal();\n emit(\"cancel\");\n }\n};\n\ndefineExpose({ openModal, closeModal });\n</script>\n","<script setup lang=\"ts\">\n/** Full-screen viewer for a message's images: swipe or arrow between them, thumbnails below. */\nimport { computed, onUnmounted, ref, useTemplateRef, watch } from \"vue\";\nimport Galleria from \"primevue/galleria\";\nimport { useSwipe } from \"@vueuse/core\";\nimport IconButton from \"~/components/general/IconButton.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { useDirection } from \"~/composables/useLocalI18n\";\nimport { useMediaStore } from \"~/stores/mediaStore\";\nimport { chatBubble } from \"@i18n/locales\";\n\nconst props = withDefaults(\n defineProps<{\n images?: string[];\n }>(),\n {\n images: () => [],\n },\n);\n\nconst mediaStore = useMediaStore();\nconst { t } = useLocalI18n(chatBubble);\nconst { dir } = useDirection();\n\nconst isOpen = ref(false);\nconst activeIndex = ref(0);\nconst hasMany = computed(() => props.images.length > 1);\n\nwatch(\n () => props.images,\n (newImages) => {\n if (activeIndex.value >= newImages.length) activeIndex.value = 0;\n },\n);\n\n// Swiping the photo moves to the neighbouring one, in reading direction.\nconst stageRef = useTemplateRef<HTMLElement>(\"stage\");\nuseSwipe(stageRef, {\n onSwipeEnd: (_, direction) => {\n if (direction !== \"left\" && direction !== \"right\") return;\n const forward = (direction === \"left\") === (dir.value !== \"rtl\");\n const next = activeIndex.value + (forward ? 1 : -1);\n if (next >= 0 && next < props.images.length) activeIndex.value = next;\n },\n});\n\nconst downloadImage = async () => {\n const url = props.images[activeIndex.value];\n if (!url) return;\n\n try {\n const blob = await mediaStore.download(url);\n const blobUrl = window.URL.createObjectURL(blob);\n\n const link = document.createElement(\"a\");\n link.href = blobUrl;\n link.download = url.split(\"/\").pop() || \"image.jpg\";\n document.body.appendChild(link);\n link.click();\n\n document.body.removeChild(link);\n window.URL.revokeObjectURL(blobUrl);\n } catch (error) {\n console.error(\"Failed to download image:\", error);\n }\n};\n\n// The browser's Back button closes the viewer instead of leaving the page.\nconst handlePopState = () => {\n isOpen.value = false;\n};\n\nwatch(isOpen, (open) => {\n if (open) {\n window.history.pushState({ viewerOpen: true }, \"\");\n window.addEventListener(\"popstate\", handlePopState);\n return;\n }\n window.removeEventListener(\"popstate\", handlePopState);\n if (window.history.state?.viewerOpen) window.history.back();\n});\n\nonUnmounted(() => {\n window.removeEventListener(\"popstate\", handlePopState);\n if (isOpen.value && window.history.state?.viewerOpen) window.history.back();\n});\n\ndefineExpose({\n open: (index: number) => {\n activeIndex.value = index;\n isOpen.value = true;\n },\n close: () => {\n isOpen.value = false;\n },\n download: downloadImage,\n});\n</script>\n\n<template>\n <Galleria\n v-model:visible=\"isOpen\"\n v-model:active-index=\"activeIndex\"\n :value=\"images\"\n full-screen\n :show-thumbnails=\"hasMany\"\n :show-item-navigators=\"hasMany\"\n :num-visible=\"5\"\n :pt=\"{\n mask: {\n class: 'vue-chat',\n 'data-testid': 'image-viewer',\n 'data-open': String(isOpen),\n },\n root: { class: 'w-dvw max-w-dvw md:w-[70vw]' },\n }\"\n >\n <template #item=\"{ item }\">\n <div\n ref=\"stage\"\n class=\"flex h-[60dvh] w-full items-center justify-center md:h-[75vh]\"\n >\n <img\n :src=\"item\"\n alt=\"\"\n draggable=\"false\"\n class=\"block max-h-full max-w-full object-contain select-none md:rounded-xl\"\n />\n </div>\n </template>\n <template #thumbnail=\"{ item }\">\n <img\n :src=\"item\"\n alt=\"\"\n draggable=\"false\"\n class=\"block size-16 rounded-lg object-cover select-none\"\n />\n </template>\n <template #footer>\n <div class=\"flex w-full justify-center py-2\">\n <IconButton\n icon=\"PhDownloadSimple\"\n :label=\"t('actions.download')\"\n class=\"text-white!\"\n @click=\"downloadImage\"\n />\n </div>\n </template>\n </Galleria>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref } from \"vue\";\nimport ContextMenu from \"primevue/contextmenu\";\nimport type { MenuItem } from \"primevue/menuitem\";\nimport { useMessagesStore } from \"~/stores/messageStores\";\nimport type { ExtendedMessage } from \"~/types\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { bubbleOptions } from \"@i18n/locales\";\nconst props = defineProps<{\n message: ExtendedMessage;\n}>();\n\nconst { t } = useLocalI18n(bubbleOptions);\nconst messagesStore = useMessagesStore();\n\nconst menu = ref<InstanceType<typeof ContextMenu> | null>(null);\n\n/** Opens at the pointer: a right click, or where a long press began. */\nconst openMenu = (event: MouseEvent | PointerEvent) => {\n messagesStore.isOptionMenuOpen = true;\n menu.value?.show(event);\n};\n\nconst closeMenu = () => {\n menu.value?.hide();\n};\n\nconst onMenuClosed = () => {\n messagesStore.isOptionMenuOpen = false;\n};\n\ndefineExpose({ openMenu, closeMenu });\n\nconst showAsDeselect = computed(() => {\n return (\n messagesStore.isSelectMode &&\n messagesStore.selectedMessages.has(props.message.id)\n );\n});\n\nconst targetIds = () =>\n messagesStore.isSelectMode &&\n messagesStore.selectedMessages.has(props.message.id)\n ? messagesStore.selectedArray.map((m) => m.id)\n : [props.message.id];\n\nconst items = computed<MenuItem[]>(() => [\n {\n phIcon: \"PhArrowBendUpLeft\",\n label: t(\"messageOptions.reply\"),\n visible: props.message.isSent,\n command: () => {\n messagesStore.replyingTo = props.message;\n },\n },\n {\n phIcon: \"PhPencilSimpleLine\",\n label: t(\"messageOptions.edit\"),\n visible: messagesStore.canEdit,\n command: () => messagesStore.triggerEdit(props.message),\n },\n {\n phIcon: \"PhCopy\",\n label: t(\"messageOptions.copy\"),\n command: () => messagesStore.copyMessageText(),\n },\n {\n phIcon: showAsDeselect.value ? \"PhXCircle\" : \"PhCheckCircle\",\n label: showAsDeselect.value\n ? t(\"messageOptions.deselect\")\n : t(\"messageOptions.select\"),\n command: () => {\n if (!messagesStore.isSelectMode) {\n messagesStore.startSelectMode(props.message);\n } else {\n messagesStore.toggleSelection(props.message);\n }\n },\n },\n {\n phIcon: \"PhTrash\",\n label: t(\"messageOptions.delete\"),\n visible: messagesStore.canDelete,\n danger: true,\n command: () => messagesStore.triggerDelete(targetIds()),\n },\n]);\n</script>\n<template>\n <ContextMenu ref=\"menu\" :model=\"items\" class=\"vue-chat\" @hide=\"onMenuClosed\">\n <template #item=\"{ item, props: itemProps }\">\n <a\n v-bind=\"itemProps.action\"\n :class=\"item.danger && 'text-chat-error!'\"\n >\n <BIcon\n :icon=\"item.phIcon\"\n class=\"size-5\"\n :class=\"item.danger ? 'text-chat-error' : 'text-chat-muted'\"\n />\n <span v-bind=\"itemProps.label\">{{ item.label }}</span>\n </a>\n </template>\n </ContextMenu>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from \"vue\";\n\nconst props = withDefaults(\n defineProps<{\n progress?: number;\n size?: number;\n strokeWidth?: number;\n isUploading?: boolean;\n isDownloading?: boolean;\n }>(),\n {\n progress: 0,\n size: 40,\n strokeWidth: 2,\n isUploading: false,\n isDownloading: false,\n },\n);\n\n// SVG Geometry Calculations\nconst center = computed(() => props.size / 2);\n\n// Ensure the circle stays within the SVG box by subtracting half the stroke\nconst radius = computed(() => props.size / 2 - props.strokeWidth / 2);\n\n// Math for the progress ring\nconst circumference = computed(() => 2 * Math.PI * radius.value);\n\nconst dashOffset = computed(() => {\n return circumference.value - props.progress * circumference.value;\n});\n\n// Dynamic Icon Sizing (40% of container size)\nconst iconSize = computed(() => props.size * 0.4);\n</script>\n\n<template>\n <div\n class=\"relative shrink-0 group flex items-center justify-center\"\n :style=\"{ width: `${size}px`, height: `${size}px` }\"\n >\n <svg\n class=\"absolute inset-0 w-full h-full -rotate-90 pointer-events-none\"\n :viewBox=\"`0 0 ${size} ${size}`\"\n >\n <circle\n :cx=\"center\"\n :cy=\"center\"\n :r=\"radius\"\n class=\"stroke-chat-on-background/45\"\n :stroke-width=\"strokeWidth\"\n fill=\"none\"\n />\n <circle\n :cx=\"center\"\n :cy=\"center\"\n :r=\"radius\"\n class=\"stroke-chat-on-background transition-all duration-200 ease-linear\"\n :stroke-width=\"strokeWidth\"\n fill=\"none\"\n stroke-linecap=\"round\"\n :stroke-dasharray=\"circumference\"\n :stroke-dashoffset=\"dashOffset\"\n />\n </svg>\n\n <div class=\"flex items-center justify-center transition-colors\">\n <BIcon\n v-if=\"isUploading\"\n icon=\"PhUploadSimple\"\n :style=\"{ width: `${iconSize}px`, height: `${iconSize}px` }\"\n class=\"fill-chat-on-background\"\n />\n <BIcon\n v-else-if=\"isDownloading\"\n icon=\"PhX\"\n :style=\"{ width: `${iconSize}px`, height: `${iconSize}px` }\"\n class=\"fill-chat-on-background\"\n />\n <BIcon\n v-else\n icon=\"PhDownloadSimple\"\n :style=\"{ width: `${iconSize}px`, height: `${iconSize}px` }\"\n class=\"fill-chat-on-background\"\n />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n// @ts-nocheck — grandfathered legacy chat-tree type errors; lift incrementally\nimport { computed, onBeforeUnmount, onMounted, ref } from \"vue\";\nimport Button from \"primevue/button\";\nimport IconButton from \"~/components/general/IconButton.vue\";\nimport LoadingStatus from \"~/components/general/LoadingStatus.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { chatBubblesFileDisplay } from \"@i18n/locales\";\nimport { useMessagesStore } from \"~/stores/messageStores\";\nimport { useMediaStore } from \"~/stores/mediaStore\";\n\nconst props = withDefaults(\n defineProps<{\n url: string;\n messageId?: string;\n isSent?: boolean;\n }>(),\n {\n isSent: true,\n },\n);\n\nconst { t } = useLocalI18n(chatBubblesFileDisplay);\nconst messagesStore = useMessagesStore();\nconst mediaStore = useMediaStore();\nconst status = ref<\"idle\" | \"downloading\" | \"downloaded\">(\"idle\");\nconst downloadProgress = ref(0);\nconst playProgress = ref(0);\nconst isPlaying = ref(false);\nconst audioSrc = ref<string>(\"\");\n\nconst audioRef = ref<HTMLAudioElement | null>(null);\nlet abortController: AbortController | null = null;\n\nconst uploadData = computed(() =>\n props.messageId ? messagesStore.uploadProgress.get(props.messageId) : null,\n);\nconst isUploading = computed(() => !props.isSent && uploadData.value);\n\nconst displayProgress = computed(() => {\n if (isUploading.value && uploadData.value) {\n return uploadData.value.progress / 100;\n }\n if (status.value === \"downloading\") {\n return downloadProgress.value / 100;\n }\n return 0;\n});\n\nconst staticWaveform = [\n 20, 50, 90, 60, 30, 40, 80, 50, 30, 50, 80, 80, 90, 30, 60, 40, 70, 90, 40,\n 70, 40, 60, 20,\n];\n\nconst checkLocalExistence = async () => {\n try {\n const cached = await mediaStore.getCachedBlob(props.url);\n if (cached) {\n audioSrc.value = URL.createObjectURL(cached);\n status.value = \"downloaded\";\n }\n } catch (e) {\n console.warn(\"IDB check failed\", e);\n }\n};\n\nconst handleAction = async () => {\n if (isUploading.value) return;\n\n if (status.value === \"downloaded\" && audioRef.value) {\n if (isPlaying.value) {\n audioRef.value.pause();\n isPlaying.value = false;\n } else {\n audioRef.value\n .play()\n .then(() => {\n isPlaying.value = true;\n })\n .catch((err) => {\n console.warn(\n \"Cached blob invalid (likely mock data). Falling back to URL.\",\n err,\n );\n if (audioRef.value) {\n audioRef.value.src = props.url;\n audioRef.value.play().then(() => {\n isPlaying.value = true;\n });\n }\n });\n }\n return;\n }\n\n if (status.value === \"downloading\") {\n abortController?.abort();\n status.value = \"idle\";\n downloadProgress.value = 0;\n return;\n }\n\n status.value = \"downloading\";\n downloadProgress.value = 0;\n abortController = new AbortController();\n\n try {\n const blob = await mediaStore.download(props.url, {\n signal: abortController.signal,\n onProgress: (p) => {\n downloadProgress.value = p;\n },\n });\n audioSrc.value = URL.createObjectURL(blob);\n status.value = \"downloaded\";\n } catch (error: any) {\n if (error.name !== \"AbortError\")\n console.error(\"Voice download error:\", error);\n status.value = \"idle\";\n downloadProgress.value = 0;\n }\n};\n\nconst onTimeUpdate = () => {\n if (!audioRef.value) return;\n const current = audioRef.value.currentTime;\n const total = audioRef.value.duration;\n if (total) playProgress.value = (current / total) * 100;\n};\n\nconst onEnded = () => {\n isPlaying.value = false;\n playProgress.value = 0;\n};\n\nconst seekAudio = (e: MouseEvent) => {\n if (status.value !== \"downloaded\" || !audioRef.value || isUploading.value)\n return;\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n const clickPosition = Math.max(\n 0,\n Math.min(1, (e.clientX - rect.left) / rect.width),\n );\n const newTime = clickPosition * audioRef.value.duration;\n if (isFinite(newTime)) {\n audioRef.value.currentTime = newTime;\n playProgress.value = clickPosition * 100;\n }\n};\n\nonMounted(() => checkLocalExistence());\nonBeforeUnmount(() => {\n if (audioSrc.value) URL.revokeObjectURL(audioSrc.value);\n abortController?.abort();\n});\n</script>\n<template>\n <div class=\"w-55 p-2 flex items-center gap-x-2.5 select-none text-chat-on-background\">\n <div\n class=\"flex-1 h-7 relative flex items-center cursor-pointer overflow-hidden\"\n @click=\"seekAudio\"\n >\n <audio\n ref=\"audioRef\"\n :src=\"audioSrc\"\n @timeupdate=\"onTimeUpdate\"\n @ended=\"onEnded\"\n ></audio>\n\n <div\n class=\"absolute inset-0 flex items-center justify-between opacity-30\"\n >\n <div\n v-for=\"(h, idx) in staticWaveform\"\n :key=\"'base-' + idx\"\n :style=\"{ height: h + '%' }\"\n class=\"w-0.5 rounded-full bg-chat-on-background\"\n ></div>\n </div>\n\n <div\n class=\"absolute inset-0 flex items-center justify-between transition-all ease-linear\"\n :class=\"[isPlaying ? 'duration-100' : 'duration-75']\"\n :style=\"{ clipPath: `inset(0 ${100 - playProgress}% 0 0)` }\"\n >\n <div\n v-for=\"(h, idx) in staticWaveform\"\n :key=\"'active-' + idx\"\n :style=\"{ height: h + '%' }\"\n class=\"w-0.5 rounded-full bg-chat-on-background\"\n ></div>\n </div>\n </div>\n\n <IconButton\n v-if=\"status === 'downloaded' && !isUploading\"\n :icon=\"isPlaying ? 'PhPause' : 'PhPlay'\"\n :label=\"isPlaying ? t('actions.pause') : t('actions.play')\"\n weight=\"fill\"\n :text=\"false\"\n severity=\"contrast\"\n size=\"large\"\n class=\"shrink-0\"\n @click=\"handleAction\"\n />\n <Button\n v-else\n text\n rounded\n class=\"size-11! shrink-0 p-0!\"\n :aria-label=\"status === 'downloading' ? t('actions.cancelDownload') : t('actions.download')\"\n :disabled=\"isUploading\"\n @click=\"handleAction\"\n >\n <LoadingStatus\n :size=\"44\"\n :stroke-width=\"2.5\"\n :progress=\"displayProgress\"\n :is-uploading=\"isUploading\"\n :is-downloading=\"status === 'downloading'\"\n />\n </Button>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, watch } from \"vue\";\nimport { useMessagesStore } from \"~/stores/messageStores\";\n\nconst props = withDefaults(\n defineProps<{\n videoUrl?: string;\n thumbnail?: string;\n mode?: \"playback\" | \"recording\";\n stream?: MediaStream | null;\n messageId?: string;\n isSent?: boolean;\n isPaused?: boolean;\n recordingTime?: number;\n maxDuration?: number;\n }>(),\n {\n videoUrl: \"\",\n thumbnail: \"\",\n mode: \"playback\",\n stream: null,\n isSent: true,\n isPaused: false,\n recordingTime: 0,\n maxDuration: 60,\n },\n);\n\nconst messagesStore = useMessagesStore();\nconst videoRef = ref<HTMLVideoElement | null>(null);\nconst isPlaying = ref(false);\nconst isLoaded = ref(false);\nconst progress = ref(0);\n\nconst uploadData = computed(() =>\n props.messageId ? messagesStore.uploadProgress.get(props.messageId) : null,\n);\nconst isUploading = computed(() => !props.isSent && uploadData.value);\n\nconst circumference = 2 * Math.PI * 113;\nconst dashOffset = computed(() => {\n if (isUploading.value && uploadData.value) {\n return circumference - (uploadData.value.progress / 100) * circumference;\n }\n\n if (props.mode === \"recording\") {\n const progressPercent = Math.min(\n (props.recordingTime / props.maxDuration) * 100,\n 100,\n );\n return circumference - (progressPercent / 100) * circumference;\n }\n\n return circumference - (progress.value / 100) * circumference;\n});\n\nconst togglePlay = () => {\n if (props.mode === \"recording\" || !videoRef.value || isUploading.value)\n return;\n\n if (isPlaying.value) {\n videoRef.value.pause();\n } else {\n videoRef.value.play();\n }\n};\n\nconst handleTimeUpdate = () => {\n if (!videoRef.value || props.mode === \"recording\" || isUploading.value)\n return;\n const current = videoRef.value.currentTime;\n const total = videoRef.value.duration;\n if (total) {\n progress.value = (current / total) * 100;\n }\n};\n\nconst handleEnded = () => {\n isPlaying.value = false;\n progress.value = 0;\n if (videoRef.value) videoRef.value.currentTime = 0;\n};\n\nconst handlePlay = () => {\n isPlaying.value = true;\n};\nconst handlePause = () => {\n isPlaying.value = false;\n};\n\nwatch(\n () => props.stream,\n (newStream) => {\n if (props.mode === \"recording\" && videoRef.value) {\n if (newStream) {\n videoRef.value.srcObject = newStream;\n videoRef.value.play();\n } else {\n videoRef.value.srcObject = null;\n }\n }\n },\n { immediate: true },\n);\n\nwatch(\n () => props.isPaused,\n (paused) => {\n if (\n props.mode === \"recording\" &&\n videoRef.value &&\n videoRef.value.srcObject\n ) {\n if (paused) {\n videoRef.value.pause();\n } else {\n videoRef.value.play();\n }\n }\n },\n);\n\nonBeforeUnmount(() => {\n if (videoRef.value) {\n videoRef.value.srcObject = null;\n }\n});\n</script>\n\n<template>\n <div\n class=\"relative w-60.5 h-60.5 p-2 shrink-0 group select-none flex items-center justify-center\"\n >\n <svg\n class=\"absolute w-57.5 h-57.5 -rotate-90 pointer-events-none z-20\"\n viewBox=\"0 0 230 230\"\n >\n <circle\n cx=\"115\"\n cy=\"115\"\n r=\"113\"\n :class=\"[\n isUploading ? 'stroke-white/30' : 'stroke-white dark:stroke-chat-background',\n ]\"\n stroke-width=\"4\"\n fill=\"none\"\n />\n\n <circle\n cx=\"115\"\n cy=\"115\"\n r=\"113\"\n class=\"stroke-chat-primary transition-all ease-linear\"\n :class=\"[isPlaying || isUploading ? 'duration-200' : 'duration-75']\"\n stroke-width=\"4\"\n fill=\"none\"\n stroke-linecap=\"round\"\n :stroke-dasharray=\"circumference\"\n :stroke-dashoffset=\"dashOffset\"\n />\n </svg>\n\n <div\n class=\"relative w-54.5 h-54.5 shrink-0 rounded-full overflow-hidden bg-[#1C1E22] z-10\"\n :class=\"[isUploading ? 'cursor-default' : 'cursor-pointer']\"\n @click=\"togglePlay\"\n >\n <video\n ref=\"videoRef\"\n :src=\"mode === 'playback' ? videoUrl : undefined\"\n :poster=\"thumbnail\"\n playsinline\n loop\n muted\n class=\"w-full h-full object-cover transition-opacity duration-300\"\n :class=\"[\n isLoaded || mode === 'recording' ? 'opacity-100' : 'opacity-0',\n ]\"\n @timeupdate=\"handleTimeUpdate\"\n @ended=\"handleEnded\"\n @play=\"handlePlay\"\n @pause=\"handlePause\"\n @loadeddata=\"isLoaded = true\"\n ></video>\n\n <div\n v-if=\"!isLoaded && mode === 'playback'\"\n class=\"absolute inset-0 flex items-center justify-center bg-chat-background\"\n ></div>\n\n <div\n v-if=\"mode === 'playback' && !isUploading\"\n class=\"absolute inset-0 flex items-center justify-center transition-all duration-300\"\n :class=\"[\n isPlaying ? 'bg-transparent opacity-0' : ' bg-black/30 opacity-100',\n ]\"\n >\n <BIcon\n :icon=\"isPlaying ? 'PhPause' : 'PhPlay'\"\n weight=\"light\"\n class=\"w-5 h-5 text-white transition-transform duration-300\"\n :class=\"[isPlaying ? 'scale-75' : 'scale-100 ml-1']\"\n />\n </div>\n\n <div\n v-if=\"isUploading\"\n class=\"absolute inset-0 flex items-center justify-center bg-black/40 z-20\"\n >\n <BIcon icon=\"PhUploadSimple\" class=\"w-6 h-6 text-white\" />\n </div>\n\n <div\n v-if=\"mode === 'recording'\"\n class=\"absolute top-4 left-1/2 -translate-x-1/2 flex items-center justify-center gap-x-1\"\n >\n <div class=\"w-2 h-2 rounded-full bg-chat-error animate-pulse\"></div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from \"vue\";\n\nconst props = withDefaults(\n defineProps<{\n width?: number | string;\n height?: number | string;\n label?: string;\n mainColor?: string;\n accentColor?: string;\n }>(),\n {\n width: 40,\n height: 40,\n label: \"\",\n mainColor: \"#FFFFFF\",\n accentColor: \"#F24E1E\",\n },\n);\n\nconst ASPECT_RATIO = 65 / 72;\n\nconst finalWidth = computed(() => {\n return Number(props.height) * ASPECT_RATIO;\n});\n\nconst finalHeight = computed(() => {\n return Number(props.width) / ASPECT_RATIO;\n});\n</script>\n<template>\n <div dir=\"ltr\" class=\"relative cursor-pointer\">\n <svg\n :width=\"finalWidth\"\n :height=\"finalHeight\"\n viewBox=\"0 0 65 72\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n fill-rule=\"evenodd\"\n clip-rule=\"evenodd\"\n d=\"M47.564 4.21766C44.8552 1.51714 41.1812 0 37.3502 0H14.4444C6.467 0 0 6.4471 0 14.4V57.6C0 65.5529 6.467 72 14.4444 72H50.5556C58.533 72 65 65.5529 65 57.6V27.5647C65 23.7456 63.4782 20.0829 60.7693 17.3823L47.564 4.21766Z\"\n :fill=\"mainColor\"\n />\n\n <path\n fill-rule=\"evenodd\"\n clip-rule=\"evenodd\"\n d=\"M44 1C45.5315 1.7318 46.9413 2.75075 48.154 4.02411L61.1199 17.6383C61.1203 17.6387 61.1207 17.6392 61.1211 17.6396C62.3333 18.9127 63.3033 20.3924 64 22H52.8641C47.9686 22 44 17.833 44 12.6927V1Z\"\n :fill=\"accentColor\"\n />\n </svg>\n <div\n class=\"absolute right-0 top-1/2 rounded-sm px-1 py-0.5 flex items-center justify-center\"\n :style=\"{ backgroundColor: accentColor }\"\n >\n <div\n class=\"text-center text-white text-[7px] font-bold leading-none uppercase tracking-wide\"\n >\n {{ label }}\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport Button from \"primevue/button\";\nimport FileFormatDisplay from \"~/components/general/FileFormatDisplay.vue\";\nimport LoadingStatus from \"~/components/general/LoadingStatus.vue\";\nimport { useMessagesStore } from \"~/stores/messageStores\";\nimport { chatBubblesFileDisplay } from \"@i18n/locales\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { useMediaStore } from \"~/stores/mediaStore\";\nimport { computed, onMounted, ref } from \"vue\";\nimport { formatBytes } from \"~/utils/format\";\n\nconst props = withDefaults(\n defineProps<{\n messageId?: string;\n isMine?: boolean;\n isSent?: boolean;\n url: string;\n fileName?: string;\n }>(),\n {\n isMine: true,\n isSent: true,\n },\n);\n\nconst { t } = useLocalI18n(chatBubblesFileDisplay);\nconst messagesStore = useMessagesStore();\nconst mediaStore = useMediaStore();\n\nconst status = ref<\"idle\" | \"downloading\" | \"downloaded\">(\"idle\");\nconst progress = ref(0);\nconst fetchedSize = ref<number | null>(null);\nlet abortController: AbortController | null = null;\n\nconst uploadData = computed(() =>\n props.messageId ? messagesStore.uploadProgress.get(props.messageId) : null,\n);\nconst isUploading = computed(() => !props.isSent && !!uploadData.value);\n\nconst displayProgress = computed(() => {\n if (isUploading.value && uploadData.value) {\n return uploadData.value.progress / 100;\n }\n if (status.value === \"downloading\") {\n return progress.value / 100;\n }\n return 0;\n});\n\nconst checkLocalExistence = async () => {\n const cached = await mediaStore.getCachedBlob(props.url);\n if (cached) status.value = \"downloaded\";\n};\n\nconst fileName = computed(() => {\n if (props.fileName) return props.fileName;\n try {\n const urlObj = new URL(props.url);\n return decodeURIComponent(\n urlObj.pathname.split(\"/\").pop() || \"Unknown_File\",\n );\n } catch {\n return \"File\";\n }\n});\n\nconst actionLabel = computed(() => {\n if (status.value === \"downloading\") return t(\"actions.cancelDownload\");\n return t(\"actions.download\");\n});\n\nconst fileExt = computed(() => {\n const name = fileName.value;\n const lastDot = name.lastIndexOf(\".\");\n return lastDot !== -1\n ? name\n .substring(lastDot + 1)\n .toUpperCase()\n .substring(0, 4)\n : \"FILE\";\n});\n\nconst formattedSize = computed(() => {\n if (isUploading.value && uploadData.value) {\n const realTotal = fetchedSize.value || uploadData.value.total;\n const currentUploaded = (uploadData.value.progress / 100) * realTotal;\n return `${formatBytes(currentUploaded)} / ${formatBytes(realTotal)}`;\n }\n if (status.value === \"downloading\" && fetchedSize.value) {\n const downloaded = (progress.value / 100) * fetchedSize.value;\n return `${formatBytes(downloaded)} / ${formatBytes(fetchedSize.value)}`;\n }\n return fetchedSize.value\n ? formatBytes(fetchedSize.value)\n : t(\"file.calculating\");\n});\n\nconst getFileSize = async () => {\n if (props.url.startsWith(\"blob:\")) {\n try {\n const res = await fetch(props.url);\n const blob = await res.blob();\n fetchedSize.value = blob.size;\n } catch {\n fetchedSize.value = 0;\n }\n return;\n }\n try {\n const size = await mediaStore.fetchFileSize(props.url);\n fetchedSize.value = size ?? 0;\n } catch {\n fetchedSize.value = 0;\n }\n};\n\nconst toggleDownload = async () => {\n if (isUploading.value) return;\n\n if (status.value === \"downloaded\") {\n const fileBlob = await mediaStore.getCachedBlob(props.url);\n\n if (fileBlob) {\n const blobUrl = URL.createObjectURL(fileBlob);\n const a = document.createElement(\"a\");\n a.href = blobUrl;\n a.download = fileName.value;\n document.body.appendChild(a);\n a.click();\n document.body.removeChild(a);\n setTimeout(() => URL.revokeObjectURL(blobUrl), 1000);\n } else {\n status.value = \"idle\";\n toggleDownload();\n }\n return;\n }\n\n if (status.value === \"downloading\") {\n abortController?.abort();\n status.value = \"idle\";\n progress.value = 0;\n return;\n }\n\n status.value = \"downloading\";\n progress.value = 0;\n abortController = new AbortController();\n\n try {\n await mediaStore.download(props.url, {\n signal: abortController.signal,\n onProgress: (p) => {\n progress.value = p;\n },\n });\n status.value = \"downloaded\";\n } catch {\n status.value = \"idle\";\n progress.value = 0;\n }\n};\n\nonMounted(() => {\n getFileSize();\n checkLocalExistence();\n});\n</script>\n<template>\n <div class=\"px-3 flex gap-x-2 select-none items-center\">\n <div dir=\"ltr\" class=\"flex text-left flex-col gap-y-0.5 flex-1 min-w-0\">\n <div class=\"text-chat-on-background text-label-md truncate\">{{ fileName }}</div>\n <div class=\"w-20\">\n <div\n class=\"text-body-sm text-left text-chat-on-background/70 w-full line-clamp-1 text-ellipsis overflow-hidden\"\n >\n {{ formattedSize }}\n </div>\n </div>\n </div>\n <Button\n text\n rounded\n class=\"size-11! shrink-0 p-0!\"\n :aria-label=\"actionLabel\"\n :disabled=\"isUploading\"\n @click=\"toggleDownload\"\n >\n <FileFormatDisplay\n v-if=\"status === 'downloaded' && !isUploading\"\n :width=\"30\"\n :height=\"33\"\n :label=\"fileExt\"\n />\n <LoadingStatus\n v-else\n :progress=\"displayProgress\"\n :is-uploading=\"isUploading\"\n :is-downloading=\"status === 'downloading'\"\n />\n </Button>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** The pill above a message that starts a new day, or the first unread one. */\ndefineProps<{ label: string }>();\n</script>\n\n<template>\n <div class=\"py-5 w-full flex items-center justify-center\">\n <div\n class=\"rounded-full bg-on-surface/10 flex items-center justify-center px-4 py-0.5\"\n >\n <div class=\"text-on-surface select-none text-body-sm\">\n {{ label }}\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Dims an image that is still uploading and shows how far along it is. */\nimport LoadingStatus from \"~/components/general/LoadingStatus.vue\";\n\nconst props = withDefaults(\n defineProps<{\n /** 0–100, as UploadProgressEvent reports it. */\n progress: number;\n size?: \"sm\" | \"lg\";\n }>(),\n { size: \"lg\" },\n);\n</script>\n\n<template>\n <div\n data-testid=\"upload-progress\"\n class=\"absolute inset-0 flex items-center justify-center bg-black/40\"\n >\n <div class=\"rounded-full bg-chat-background/85 p-0.5\">\n <LoadingStatus\n :progress=\"props.progress / 100\"\n :size=\"props.size === 'lg' ? 44 : 28\"\n is-uploading\n />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Image content of a message: one large tile, or a row of thumbnails with a \"+N\" tile when\n * there are more than fit. Emits the index to open in the viewer.\n */\nimport { computed } from \"vue\";\nimport type { UploadProgressEvent } from \"~/types\";\nimport UploadProgressOverlay from \"./UploadProgressOverlay.vue\";\nimport MediaImage from \"~/components/general/MediaImage.vue\";\n\nconst MAX_VISIBLE_IMAGES = 3;\n\nconst props = defineProps<{\n images: string[];\n isSent: boolean;\n upload?: UploadProgressEvent;\n}>();\n\nconst emit = defineEmits<{ preview: [index: number] }>();\n\nconst displayedImages = computed(() => props.images.slice(0, MAX_VISIBLE_IMAGES));\nconst showUpload = computed(() => !props.isSent && !!props.upload);\n</script>\n\n<template>\n <div\n v-if=\"images.length === 1\"\n data-testid=\"bubble-image\"\n @click.stop=\"emit('preview', 0)\"\n class=\"relative cursor-pointer overflow-hidden rounded-xl max-w-full md:max-w-85 w-85 h-40.5\"\n >\n <MediaImage :src=\"images[0]\" class=\"size-full rounded-xl\" />\n <UploadProgressOverlay\n v-if=\"showUpload\"\n :progress=\"upload!.progress\"\n size=\"lg\"\n />\n </div>\n\n <div v-else class=\"max-w-75 flex items-center gap-x-3 h-16\">\n <div\n v-if=\"images.length > MAX_VISIBLE_IMAGES\"\n @click=\"emit('preview', MAX_VISIBLE_IMAGES)\"\n class=\"h-full rounded-xl cursor-pointer overflow-hidden aspect-square flex items-center justify-center bg-surface-variant-2\"\n >\n <div class=\"text-on-surface select-none text-label-md\">\n +{{ images.length - MAX_VISIBLE_IMAGES }}\n </div>\n </div>\n\n <div\n v-for=\"(image, index) in displayedImages\"\n :key=\"index\"\n @click.stop=\"emit('preview', index)\"\n class=\"relative h-full rounded-xl cursor-pointer overflow-hidden aspect-square\"\n >\n <MediaImage :src=\"image\" class=\"size-full\" />\n <UploadProgressOverlay\n v-if=\"showUpload\"\n :progress=\"upload!.progress\"\n size=\"sm\"\n />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** The round mark beside a message while it is selected in select mode. */\ndefineProps<{ selected: boolean }>();\n</script>\n\n<template>\n <div\n class=\"shrink-0 transition-all duration-200 overflow-hidden ease-in-out whitespace-nowrap\"\n :class=\"{ 'w-auto': selected, 'w-0': !selected }\"\n >\n <div\n class=\"transition-all duration-200 ease-in-out w-5 h-5 rounded-full bg-gradient-primary-secondary flex items-center justify-center\"\n :class=\"{\n 'opacity-100 scale-100': selected,\n 'opacity-0 scale-0': !selected,\n }\"\n >\n <div class=\"w-2.5 h-2.5 rounded-full bg-surface\"></div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { Contact, ExtendedMessage } from \"~/types\";\n\n// A request message is drawn by the host's own globally registered `RequestCard`. It is looked up\n// here rather than in ChatBubble because a template resolves its components on every render, so\n// every ordinary bubble would warn about a `RequestCard` that hosts without requests never register.\ndefineProps<{ message: ExtendedMessage; contact?: Contact | null }>();\n</script>\n\n<template>\n <RequestCard :message=\"message\" :contact=\"contact\" />\n</template>\n","<script setup lang=\"ts\">\n/**\n * The retry prompt under a message that failed to send. The time and send state of every other\n * message sit inside the bubble, in BubbleMeta.\n */\nimport Button from \"primevue/button\";\nimport type { Message } from \"~/types\";\nimport { useMessagesStore } from \"~/stores/messageStores.js\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { chatBubble } from \"@i18n/locales\";\n\ndefineProps<{ message: Message }>();\n\nconst { t } = useLocalI18n(chatBubble);\nconst messagesStore = useMessagesStore();\n</script>\n\n<template>\n <div class=\"flex w-full justify-start pt-1\">\n <Button\n text\n size=\"small\"\n severity=\"danger\"\n :label=\"t('sendFailed')\"\n @click.stop=\"messagesStore.retryMessage(message)\"\n >\n <template #icon>\n <BIcon icon=\"PhWarningCircle\" class=\"size-4\" />\n </template>\n </Button>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * A message's time and, on your own messages, its send state, drawn inside the bubble's end corner.\n * `overlay` is the pill form laid over a photo or video, where plain text would not be readable.\n */\nimport { computed } from \"vue\";\nimport type { Message } from \"~/types\";\nimport { useDate } from \"~/composables/useDate.js\";\n\nconst props = withDefaults(\n defineProps<{ message: Message; isMine: boolean; overlay?: boolean }>(),\n { overlay: false },\n);\n\nconst { formatTime } = useDate();\n\nconst checkIcon = computed(() => {\n if (props.message.isFailed) return \"PhWarningCircle\";\n if (props.message.isSent)\n return props.message.isRead ? \"PhChecks\" : \"PhCheck\";\n return \"PhClock\";\n});\n\nconst iconColor = computed(() => {\n if (props.message.isFailed) return \"fill-chat-error\";\n if (props.overlay) return \"fill-white\";\n return props.message.isRead && props.message.isSent\n ? \"fill-chat-primary\"\n : \"fill-chat-muted\";\n});\n</script>\n\n<template>\n <div\n class=\"pointer-events-none flex select-none items-center gap-x-1 text-[11px] leading-none\"\n :class=\"\n overlay\n ? 'rounded-full bg-black/45 px-2 py-1 text-white'\n : 'text-chat-muted'\n \"\n >\n <BIcon v-if=\"isMine\" :icon=\"checkIcon\" class=\"size-3.5\" :class=\"iconColor\" />\n <span>{{ formatTime(message.date) }}</span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** The quoted message shown at the top of a bubble that replies to another message. */\nimport { computed } from \"vue\";\nimport type { Contact, ExtendedMessage } from \"~/types\";\nimport SafeEmojiText from \"~/components/general/SafeEmojiText.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { chatBubble } from \"@i18n/locales\";\n\nconst props = defineProps<{\n message: ExtendedMessage;\n contact?: Contact | null;\n isMine: boolean;\n currentUserId: string;\n}>();\n\nconst { t } = useLocalI18n(chatBubble);\n\nconst replied = computed(() => props.message.repliedTo!);\n\nconst senderName = computed(() =>\n replied.value.senderId === props.currentUserId\n ? t(\"you\")\n : `${props.contact?.name ?? \"\"} ${props.contact?.lastName ?? \"\"}`.trim(),\n);\n\nconst preview = computed(() => {\n const m = replied.value;\n if (m.text?.trim()) return m.text;\n if (m.imageUrl?.length) return t(\"attachementTypes.image\");\n if (m.voiceUrl) return t(\"attachementTypes.voice\");\n if (m.videoUrl) return t(\"attachementTypes.video\");\n if (m.fileUrl) return m.fileName || t(\"attachementTypes.file\");\n return \"\";\n});\n</script>\n\n<template>\n <div\n data-testid=\"reply-preview\"\n class=\"mx-2 mt-2 flex flex-col gap-y-0.5 overflow-hidden rounded-lg border-s-2 border-s-chat-primary px-3 py-1.5 text-body-sm\"\n :class=\"isMine ? 'bg-on-surface/5' : 'bg-surface-variant-2'\"\n >\n <div class=\"truncate text-label-sm text-chat-primary\">{{ senderName }}</div>\n <div class=\"line-clamp-1 text-on-surface/70\">\n <SafeEmojiText :text=\"preview\" />\n </div>\n </div>\n</template>\n","import { ref, onBeforeUnmount } from \"vue\";\n\nexport function useLongPress(callback: (event: PointerEvent) => void) {\n const longPressTimer = ref<ReturnType<typeof setTimeout> | null>(null);\n const touchStartPos = ref({ x: 0, y: 0 });\n\n const onPointerDown = (event: PointerEvent) => {\n if (event.button !== 0 && event.pointerType === \"mouse\") return;\n touchStartPos.value = { x: event.clientX, y: event.clientY };\n longPressTimer.value = setTimeout(() => {\n if (\"vibrate\" in navigator) navigator.vibrate(50);\n callback(event);\n longPressTimer.value = null;\n }, 1000);\n };\n\n const onPointerMove = (event: PointerEvent) => {\n if (!longPressTimer.value) return;\n const deltaX = Math.abs(event.clientX - touchStartPos.value.x);\n const deltaY = Math.abs(event.clientY - touchStartPos.value.y);\n if (deltaX > 10 || deltaY > 10) {\n clearTimeout(longPressTimer.value);\n longPressTimer.value = null;\n }\n };\n\n const onPointerUp = () => {\n if (longPressTimer.value) {\n clearTimeout(longPressTimer.value);\n longPressTimer.value = null;\n }\n };\n\n onBeforeUnmount(() => {\n if (longPressTimer.value) clearTimeout(longPressTimer.value);\n });\n\n return { onPointerDown, onPointerMove, onPointerUp };\n}\n","<script setup lang=\"ts\">\nimport { computed, nextTick, ref, useTemplateRef } from \"vue\";\nimport type { Contact, ExtendedMessage, Message } from \"~/types\";\nimport ImageGroupDisplay from \"./chat-bubbles/ImageGroupDisplay.vue\";\nimport BubbleOptions from \"./chat-bubbles/BubbleOptions.vue\";\nimport VoiceDisplay from \"./chat-bubbles/VoiceDisplay.vue\";\nimport BubbleVideo from \"./chat-bubbles/BubbleVideo.vue\";\nimport FileDisplay from \"./chat-bubbles/FileDisplay.vue\";\nimport SafeEmojiText from \"../general/SafeEmojiText.vue\";\nimport ContactAvatar from \"./contact/ContactAvatar.vue\";\nimport BubbleDivider from \"./chat-bubbles/BubbleDivider.vue\";\nimport BubbleImages from \"./chat-bubbles/BubbleImages.vue\";\nimport BubbleSelectionMark from \"./chat-bubbles/BubbleSelectionMark.vue\";\nimport BubbleRequest from \"./chat-bubbles/BubbleRequest.vue\";\nimport BubbleStatus from \"./chat-bubbles/BubbleStatus.vue\";\nimport BubbleMeta from \"./chat-bubbles/BubbleMeta.vue\";\nimport ReplyPreview from \"./chat-bubbles/ReplyPreview.vue\";\n\nimport { useMessagesStore } from \"~/stores/messageStores.js\";\nimport { useLongPress } from \"~/composables/useLongPress\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { useDate } from \"~/composables/useDate.js\";\nimport { chatBubble } from \"@i18n/locales\";\nimport { useProfileStore } from \"~/stores/profileStore.js\";\n\nconst props = withDefaults(\n defineProps<{\n message: ExtendedMessage;\n contact: Contact;\n isFirstUnread?: boolean;\n isDeleting?: boolean;\n }>(),\n {\n isFirstUnread: false,\n isDeleting: false,\n },\n);\n\nconst { t } = useLocalI18n(chatBubble);\nconst messagesStore = useMessagesStore();\nconst { formatDateShort } = useDate();\n\ntype ImageDisplayInstance = InstanceType<typeof ImageGroupDisplay>;\ntype BubbleOptionsInstance = InstanceType<typeof BubbleOptions>;\n\nconst imageDisplayRef = useTemplateRef<ImageDisplayInstance>(\"imageDisplay\");\nconst bubbleOptionsRef =\n useTemplateRef<BubbleOptionsInstance>(\"bubbleOptions\");\n\nconst profileStore = useProfileStore();\nconst currentUserId = computed(() => profileStore.userId);\n\nconst isMine = computed(() => props.message.senderId === currentUserId.value);\nconst isSelected = computed(() =>\n messagesStore.selectedMessages.has(props.message.id),\n);\nconst isSelectMode = computed(() => messagesStore.isSelectMode);\n\nconst messageType = computed(() => {\n if (props.message.voiceUrl?.trim()) return \"voice\";\n if (props.message.imageUrl && props.message.imageUrl.length > 1)\n return \"multiImage\";\n if (props.message.imageUrl?.length === 1 && props.message.imageUrl[0]?.trim())\n return \"image\";\n if (props.message.videoUrl?.trim()) return \"video\";\n if (props.message.fileUrl?.trim()) return \"file\";\n return \"text\";\n});\n\nconst isTextBased = computed(() =>\n [\"text\", \"file\", \"voice\"].includes(messageType.value),\n);\n\n// Consecutive messages from one sender on one day form a group: they sit close together, share\n// one avatar (on the last) and round off into each other on the sender's side.\nconst sameGroup = (a?: Message | null, b?: Message | null) =>\n !!a &&\n !!b &&\n !a.request &&\n !b.request &&\n a.senderId === b.senderId &&\n new Date(a.date).toDateString() === new Date(b.date).toDateString();\n\n// The unread divider splits a group, like the date divider does.\nconst groupedWithPrev = computed(\n () =>\n !props.isFirstUnread && sameGroup(props.message.prevMessage, props.message),\n);\nconst groupedWithNext = computed(() =>\n sameGroup(props.message, props.message.nextMessage),\n);\n\n// Logical corners, so the sender's side is right whichever way the host lays the chat out: your\n// messages sit at the start, theirs at the end. The last bubble of a group keeps a tail.\nconst roundingClasses = computed(() => {\n const prev = groupedWithPrev.value;\n const next = groupedWithNext.value;\n if (isMine.value)\n return [prev && \"rounded-ss-md\", next ? \"rounded-es-md\" : \"rounded-es-xs\"];\n return [prev && \"rounded-se-md\", next ? \"rounded-ee-md\" : \"rounded-ee-xs\"];\n});\n\nconst uploadData = computed(() =>\n messagesStore.uploadProgress.get(props.message.id),\n);\n\n// --- Actions ---\nconst viewerMounted = ref(false);\nconst previewImage = async (index: number) => {\n if (!viewerMounted.value) {\n viewerMounted.value = true;\n await nextTick();\n }\n imageDisplayRef.value?.open(index);\n};\n\nconst optionsMounted = ref(false);\n\nconst handleRightClick = async (event: MouseEvent | PointerEvent) => {\n if (props.message.request || !props.message.isSent) return;\n if (!messagesStore.isSelectMode) {\n messagesStore.selectedMessages.clear();\n messagesStore.toggleSelection(props.message);\n }\n if (!optionsMounted.value) {\n optionsMounted.value = true;\n await nextTick();\n }\n bubbleOptionsRef.value?.openMenu(event);\n};\n\nconst handleLeftClick = () => {\n if (messagesStore.isSelectMode) messagesStore.toggleSelection(props.message);\n};\n\n// Replaces 40 lines of pointer event logic\nconst longPress = useLongPress(handleRightClick);\n</script>\n\n<template>\n <div\n data-testid=\"chat-bubble\"\n :data-message-id=\"message.id\"\n @contextmenu.prevent=\"handleRightClick\"\n class=\"vue-chat w-full transition-all duration-300 ease-in-out\"\n :class=\"{\n 'max-h-0 opacity-0 overflow-hidden': isDeleting,\n 'max-h-250 opacity-100': !isDeleting,\n }\"\n >\n <BubbleDivider\n v-if=\"message.isFirstInDate || isFirstUnread\"\n :label=\"\n isFirstUnread ? t('unreadMessages') : formatDateShort(message.date)\n \"\n />\n\n <!-- Message Row -->\n <div\n class=\"w-full px-5 transition-all duration-200 flex items-center ease-in-out\"\n :class=\"{\n 'pt-0.5': groupedWithPrev,\n 'pt-3': !groupedWithPrev,\n 'bg-on-surface/5 gap-x-3': isSelectMode && isSelected,\n 'bg-on-surface/0 gap-x-0': !(isSelectMode && isSelected),\n 'cursor-pointer select-none': isSelectMode,\n }\"\n >\n <BubbleSelectionMark\n v-if=\"!message.request\"\n :selected=\"isSelectMode && isSelected\"\n />\n\n <!-- Request Card Fallback -->\n <div v-if=\"message.request\" class=\"py-3 w-full flex justify-center\">\n <BubbleRequest :message=\"message\" :contact=\"contact\" />\n </div>\n\n <!-- Standard Message Bubble -->\n <div\n v-else\n class=\"flex items-center flex-1 min-w-0 relative\"\n :class=\"{ 'justify-start': isMine, 'justify-end': !isMine }\"\n @click=\"handleLeftClick\"\n v-on=\"longPress\"\n >\n <div class=\"select-none md:select-auto w-full\">\n <div\n class=\"w-full flex items-center\"\n :class=\"{ 'justify-start': isMine, 'justify-end': !isMine }\"\n >\n <div class=\"flex max-w-4/5 items-end gap-x-2\">\n <div class=\"flex-1 min-w-0\">\n <!-- Text / File / Voice Bubble Wrapper -->\n <div\n v-if=\"isTextBased\"\n class=\"relative rounded-2xl p-1 shadow-xs\"\n :class=\"[\n roundingClasses,\n isMine ? 'bg-chat-bubble-mine' : 'bg-chat-bubble',\n { 'text-chat-base text-chat-on-background': messageType === 'text' },\n ]\"\n >\n <ReplyPreview\n v-if=\"messageType === 'text' && message.repliedTo\"\n :message=\"message\"\n :contact=\"contact\"\n :is-mine=\"isMine\"\n :current-user-id=\"currentUserId\"\n />\n <p\n v-if=\"messageType === 'text'\"\n class=\"max-w-full wrap-break-word px-2.5 py-1.5\"\n >\n <SafeEmojiText :text=\"message.text\" />\n <!-- Holds the last line clear of the time, which sits over the bubble's end corner. -->\n <span\n aria-hidden=\"true\"\n class=\"inline-block h-3\"\n :class=\"isMine ? 'w-14' : 'w-10'\"\n />\n </p>\n <BubbleMeta\n v-if=\"messageType === 'text'\"\n :message=\"message\"\n :is-mine=\"isMine\"\n class=\"absolute end-3 bottom-2\"\n />\n <FileDisplay\n v-else-if=\"messageType === 'file'\"\n :is-mine=\"isMine\"\n :url=\"message.fileUrl ?? ''\"\n :file-name=\"message.fileName\"\n :message-id=\"message.id\"\n :is-sent=\"message.isSent\"\n />\n <VoiceDisplay\n v-else-if=\"messageType === 'voice'\"\n :url=\"message.voiceUrl ?? ''\"\n :message-id=\"message.id\"\n :is-sent=\"message.isSent\"\n />\n <div v-if=\"messageType !== 'text'\" class=\"flex justify-end px-2 pb-1\">\n <BubbleMeta :message=\"message\" :is-mine=\"isMine\" />\n </div>\n </div>\n\n <!-- Photos and video carry the time as a pill over their end corner. -->\n <div v-else class=\"relative\">\n <BubbleImages\n v-if=\"messageType === 'image' || messageType === 'multiImage'\"\n :images=\"message.imageUrl!\"\n :is-sent=\"message.isSent\"\n :upload=\"uploadData\"\n @preview=\"previewImage\"\n />\n <BubbleVideo\n v-else-if=\"messageType === 'video'\"\n :video-url=\"message.videoUrl\"\n mode=\"playback\"\n />\n <BubbleMeta\n :message=\"message\"\n :is-mine=\"isMine\"\n overlay\n class=\"absolute end-2 bottom-2 z-20\"\n />\n </div>\n\n <BubbleStatus v-if=\"isMine && message.isFailed\" :message=\"message\" />\n </div>\n\n <!-- Avatar, once per group, level with its last bubble. -->\n <div v-if=\"!isMine\" class=\"size-8 shrink-0\">\n <ContactAvatar\n v-if=\"!groupedWithNext\"\n :contact=\"contact\"\n :show-online=\"false\"\n />\n </div>\n </div>\n </div>\n </div>\n\n <!-- Overlays, each mounted on first open: otherwise every bubble keeps idle copies. -->\n <ImageGroupDisplay\n v-if=\"viewerMounted && message.imageUrl && message.imageUrl.length > 0\"\n ref=\"imageDisplay\"\n :images=\"message.imageUrl\"\n />\n <BubbleOptions\n v-if=\"optionsMounted\"\n :message=\"message\"\n ref=\"bubbleOptions\"\n />\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Placeholder bubbles while a conversation's messages load, laid out like ChatBubble: the other\n * side's at the end with an avatar on the last of each group, yours at the start.\n */\nimport { computed } from \"vue\";\nimport Skeleton from \"primevue/skeleton\";\n\nconst props = withDefaults(defineProps<{ count?: number }>(), { count: 6 });\n\n// A fixed, varied pattern, so the placeholder reads as a conversation rather than a stripe.\nconst PATTERN = [\n { mine: false, width: \"55%\", height: \"2.75rem\" },\n { mine: false, width: \"38%\", height: \"2.75rem\" },\n { mine: true, width: \"62%\", height: \"4rem\" },\n { mine: false, width: \"46%\", height: \"2.75rem\" },\n { mine: true, width: \"34%\", height: \"2.75rem\" },\n { mine: true, width: \"50%\", height: \"2.75rem\" },\n];\n\nconst rows = computed(() =>\n Array.from({ length: props.count }, (_, i) => {\n const row = PATTERN[i % PATTERN.length]!;\n const next = PATTERN[(i + 1) % PATTERN.length]!;\n return { ...row, avatar: !row.mine && (i === props.count - 1 || next.mine) };\n }),\n);\n</script>\n\n<template>\n <div class=\"vue-chat flex w-full flex-col gap-y-2 px-5 py-3\" aria-hidden=\"true\">\n <div\n v-for=\"(row, i) in rows\"\n :key=\"i\"\n class=\"flex w-full items-end gap-x-2\"\n :class=\"row.mine ? 'justify-start' : 'justify-end'\"\n >\n <Skeleton\n :width=\"row.width\"\n :height=\"row.height\"\n border-radius=\"1rem\"\n class=\"max-w-4/5\"\n />\n <div v-if=\"!row.mine\" class=\"size-8 shrink-0\">\n <Skeleton v-if=\"row.avatar\" shape=\"circle\" size=\"2rem\" />\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** The date pill that floats over the list while scrolling and fades out when it stops. */\ndefineProps<{ label: string | null; opacity: number; offset: boolean }>();\n</script>\n\n<template>\n <div\n :class=\"[offset ? 'top-12' : 'top-4']\"\n class=\"absolute left-0 right-0 z-20 flex justify-center pointer-events-none transition-opacity duration-200\"\n :style=\"{ opacity }\"\n >\n <div\n v-if=\"label\"\n class=\"rounded-full bg-chat-on-background/10 flex items-center justify-center px-4 py-0.5\"\n >\n <div class=\"text-chat-on-background select-none text-label-sm\">\n {{ label }}\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Jumps back to the newest message; shows how many arrived while the user was scrolled up. */\nimport Badge from \"primevue/badge\";\nimport IconButton from \"~/components/general/IconButton.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { chatMessages } from \"@i18n/locales\";\n\ndefineProps<{ visible: boolean; unseen: number }>();\nconst emit = defineEmits<{ click: [] }>();\n\nconst { t } = useLocalI18n(chatMessages);\n</script>\n\n<template>\n <div class=\"relative w-14 pr-3 pb-1\">\n <div\n :class=\"[\n visible\n ? 'pointer-events-auto scale-100 opacity-100'\n : 'pointer-events-none scale-0 opacity-0',\n ]\"\n class=\"origin-bottom transition-all duration-200 ease-in-out\"\n >\n <IconButton\n icon=\"PhArrowDown\"\n icon-class=\"size-6\"\n :label=\"t('actions.scrollToLatest')\"\n :text=\"false\"\n raised\n size=\"large\"\n :tabindex=\"visible ? undefined : -1\"\n @click=\"emit('click')\"\n />\n </div>\n <Badge\n v-if=\"visible && unseen > 0\"\n dir=\"ltr\"\n :value=\"unseen > 99 ? '99+' : unseen\"\n class=\"pointer-events-none absolute! -top-2 right-3\"\n />\n </div>\n</template>\n","import { ref, computed, onScopeDispose, type ComputedRef } from \"vue\";\nimport type { Message, ExtendedMessage } from \"~/types\";\nimport { useMessagesStore } from \"~/stores/messageStores\";\nimport { useChatStore } from \"~/stores/chatStore\";\nimport { useProfileStore } from \"~/stores/profileStore\";\n\nexport function useChatMessageList(chatId: ComputedRef<string | null>) {\n const messagesStore = useMessagesStore();\n const chatStore = useChatStore();\n\n const profileStore = useProfileStore();\n const currentUserId = computed(() => profileStore.userId);\n\n const messages = computed<Message[]>(\n () => messagesStore.messagesMap[chatId.value ?? \"\"] ?? [],\n );\n const isLoading = computed(\n () => !!messagesStore.messagesLoadingMap[chatId.value ?? \"\"],\n );\n\n // --- Enrichment ---\n // Any change to a thread (a new message, an id swap, a read flag) re-runs this computed. Handing\n // back the previous enriched object whenever its inputs are unchanged keeps every other bubble's\n // `message` prop identical, so only the bubbles that actually changed re-render.\n const enrichedCache = new WeakMap<Message, ExtendedMessage>();\n\n const reversedMessages = computed<ExtendedMessage[]>(() => {\n const raw = messages.value;\n // Contacts are keyed by conversation, and in a 1:1 chat that contact is the counterpart.\n const contact = chatStore.getContactById(chatId.value ?? \"\");\n const enriched = new Array<ExtendedMessage>(raw.length);\n\n for (let idx = 0; idx < raw.length; idx++) {\n const msg = raw[idx]!;\n const prev = raw[idx - 1];\n const next = raw[idx + 1];\n\n const cached = enrichedCache.get(msg);\n if (\n cached &&\n cached.prevMessage === prev &&\n cached.nextMessage === next &&\n cached.contact === contact\n ) {\n enriched[raw.length - 1 - idx] = cached;\n continue;\n }\n\n const isFirstInDate =\n !prev ||\n new Date(msg.date).toDateString() !==\n new Date(prev.date).toDateString();\n\n const value: ExtendedMessage = {\n ...msg,\n prevMessage: prev,\n nextMessage: next,\n isFirstInDate,\n contact: contact ?? undefined,\n };\n enrichedCache.set(msg, value);\n enriched[raw.length - 1 - idx] = value;\n }\n return enriched;\n });\n\n const firstUnreadId = computed(() => {\n const unreadMsg = messages.value.find(\n (m) => !m.isRead && m.senderId !== currentUserId.value,\n );\n return unreadMsg ? unreadMsg.id : null;\n });\n\n // --- Fetching ---\n const fetchMessages = async (page: number) => {\n const id = chatId.value;\n if (!id || messagesStore.messagesLoadingMap[id]) return;\n if (page > 1 && !messagesStore.messagesHasNextPage[id]) return;\n await messagesStore.fetchMessages(id, page);\n };\n\n const loadNextPage = () => {\n const id = chatId.value;\n if (!id) return;\n const nextPage = (messagesStore.messagesPage[id] ?? 0) + 1;\n fetchMessages(nextPage);\n };\n\n // --- Animations & Mutations ---\n const animatingIds = ref<Set<string>>(new Set());\n const deletingIds = ref<Set<string>>(new Set());\n\n const addMessages = (newMsgs: Message[]) => {\n if (!newMsgs || newMsgs.length === 0) return;\n const hasMyMessage = newMsgs.some(\n (msg) => msg.senderId === currentUserId.value,\n );\n\n newMsgs.forEach((msg) => animatingIds.value.add(msg.id));\n setTimeout(() => {\n newMsgs.forEach((msg) => animatingIds.value.delete(msg.id));\n }, 400);\n\n // Each message goes to its own conversation, not whichever one is open.\n for (const msg of newMsgs) {\n const id = msg.conversationId;\n messagesStore.messagesMap[id] = [\n ...(messagesStore.messagesMap[id] ?? []),\n msg,\n ];\n }\n\n return hasMyMessage; // Return boolean so component knows whether to scroll down\n };\n\n const executeDelete = (idsToDelete: string[], onDone: () => void) => {\n // Captured now: the user may switch conversation during the animation.\n const id = chatId.value;\n setTimeout(() => {\n idsToDelete.forEach((id) => deletingIds.value.add(id));\n\n setTimeout(() => {\n idsToDelete.forEach((id) => deletingIds.value.delete(id));\n if (id) {\n const remainingMessages = (\n messagesStore.messagesMap[id] ?? []\n ).filter((m) => !idsToDelete.includes(m.id));\n messagesStore.messagesMap[id] = remainingMessages;\n\n const newLastMessage =\n remainingMessages.length > 0\n ? remainingMessages[remainingMessages.length - 1]\n : null;\n\n if (newLastMessage) {\n messagesStore.updateLastMessage(id, newLastMessage);\n } else {\n messagesStore.patchLastMessage(id, \"-1\", {\n text: \"\",\n date: new Date().toISOString(),\n } as unknown as Message);\n }\n }\n messagesStore.clearActions();\n onDone();\n }, 300);\n }, 300);\n };\n\n // --- Event Bus Subscriptions ---\n let unsubSend: () => void;\n let unsubDelete: () => void;\n\n const subscribeToBus = (callbacks: {\n onSend: (hasMyMessage: boolean) => void;\n onDelete: (ids: string[]) => void;\n }) => {\n unsubSend = messagesStore.sendBus.on((newMsgs) => {\n const hasMyMessage = addMessages(newMsgs);\n if (hasMyMessage) callbacks.onSend(true);\n });\n\n unsubDelete = messagesStore.deleteBus.on((ids) => callbacks.onDelete(ids));\n // Updates are applied by the store itself (`patchMessage`), keyed by conversation.\n };\n\n // Auto-unsubscribe when the component scope is destroyed\n onScopeDispose(() => {\n if (unsubSend) unsubSend();\n if (unsubDelete) unsubDelete();\n });\n\n return {\n messages,\n reversedMessages,\n firstUnreadId,\n isLoading,\n animatingIds,\n deletingIds,\n fetchMessages,\n loadNextPage,\n subscribeToBus,\n executeDelete,\n };\n}\n","import { ref, computed, type Ref } from \"vue\";\nimport { useVirtualizer } from \"@tanstack/vue-virtual\";\n\ninterface ScrollOptions {\n scrollContainer: Ref<HTMLElement | null>;\n hasCall: Ref<boolean>;\n isLoading: Ref<boolean>;\n isLocked: Ref<boolean>;\n onLoadMore: () => void;\n}\n\nexport function useFlippedVirtualScroll(options: ScrollOptions) {\n const {\n scrollContainer,\n hasCall,\n isLoading,\n isLocked,\n onLoadMore,\n } = options;\n\n // --- Virtualizer Setup ---\n // Note: The actual `reversedMessages` and `count` will be injected via a setter\n // to avoid circular dependency issues in the main component.\n const itemCount = ref(0);\n const getItemKey = ref<(index: number) => string | number>(\n (index: number) => index,\n );\n\n const virtualizer = useVirtualizer(\n computed(() => ({\n count: itemCount.value,\n getScrollElement: () => scrollContainer.value,\n estimateSize: () => 80,\n overscan: 15,\n getItemKey: getItemKey.value,\n })),\n );\n\n // --- Scroll State ---\n const headerOpacity = ref(0);\n const scrollOffset = ref(0);\n const topVisibleMessageIndex = ref(0);\n const targetScroll = ref(0);\n let scrollTimer: ReturnType<typeof setTimeout> | null = null;\n let animationFrame: number | null = null;\n\n // The list is flipped: the newest message is at scrollTop 0 (drawn at the bottom of the screen),\n // so \"away from newest\" is scrollTop itself.\n const canScroll = computed(() => scrollOffset.value > 100);\n\n // --- Scroll Handlers ---\n const handleScroll = () => {\n if (isLocked.value) return;\n const el = scrollContainer.value;\n if (!el) return;\n\n scrollOffset.value = el.scrollTop;\n\n // Floating Header Logic\n headerOpacity.value = 1;\n if (scrollTimer) clearTimeout(scrollTimer);\n scrollTimer = setTimeout(() => {\n headerOpacity.value = 0;\n }, 3000);\n\n // Infinite Scroll Trigger (In flipped list, high scrollTop = older messages = top of screen)\n const distanceToTop = el.scrollHeight - el.scrollTop - el.clientHeight;\n if (distanceToTop < 100 && !isLoading.value && itemCount.value > 0) {\n onLoadMore();\n }\n\n // Track Top Visible Message for Floating Header\n const items = virtualizer.value.getVirtualItems();\n if (items.length > 0) {\n const targetOffset = hasCall.value ? 88 : 44;\n const physicalTopOfViewport =\n el.scrollHeight - el.clientHeight - el.scrollTop;\n const targetPhysicalTop = physicalTopOfViewport + targetOffset;\n\n let closestIndex = items[0].index;\n let minDiff = Infinity;\n\n for (const item of items) {\n const diff = Math.abs(item.start - targetPhysicalTop);\n if (diff < minDiff) {\n minDiff = diff;\n closestIndex = item.index;\n }\n }\n topVisibleMessageIndex.value = closestIndex;\n }\n };\n\n const handleWheel = (e: WheelEvent) => {\n if (isLocked.value || !scrollContainer.value || itemCount.value === 0)\n return;\n\n // Start from where the list actually is, not a target left over from an earlier wheel or a\n // touch/keyboard scroll the loop never saw.\n if (!animationFrame) targetScroll.value = scrollContainer.value.scrollTop;\n\n // In a flipped list, positive deltaY raises scrollTop, towards older messages.\n targetScroll.value += e.deltaY;\n\n const maxScroll =\n scrollContainer.value.scrollHeight - scrollContainer.value.clientHeight;\n targetScroll.value = Math.max(0, Math.min(targetScroll.value, maxScroll));\n\n if (!animationFrame) smoothScrollLoop();\n };\n\n const smoothScrollLoop = () => {\n if (!scrollContainer.value) return;\n const current = scrollContainer.value.scrollTop;\n const target = targetScroll.value;\n const distance = (target - current) * 0.22;\n\n if (Math.abs(distance) > 0.5) {\n scrollContainer.value.scrollTop += distance;\n animationFrame = requestAnimationFrame(smoothScrollLoop);\n } else {\n scrollContainer.value.scrollTop = target;\n animationFrame = null;\n }\n };\n\n const resetScroll = () => {\n const el = scrollContainer.value;\n if (!el) return;\n // Let the virtualizer drive the jump. A plain el.scrollTo is cancelled the moment a newly\n // measured row makes the virtualizer shift scrollTop to hold the viewport, stalling short of\n // the newest message; during its own smooth scroll it skips those shifts and keeps going.\n if (animationFrame) cancelAnimationFrame(animationFrame);\n animationFrame = null;\n targetScroll.value = 0;\n virtualizer.value.scrollToOffset(0, { behavior: \"smooth\" });\n };\n\n const cleanup = () => {\n if (animationFrame) cancelAnimationFrame(animationFrame);\n if (scrollTimer) clearTimeout(scrollTimer);\n };\n\n return {\n virtualizer,\n headerOpacity,\n canScroll,\n topVisibleMessageIndex,\n handleScroll,\n handleWheel,\n resetScroll,\n cleanup,\n // Exposed to allow component to pass dynamic data without circular refs\n setItemCount: (count: number) => {\n itemCount.value = count;\n },\n setGetItemKey: (fn: (index: number) => string | number) => {\n getItemKey.value = fn;\n },\n };\n}\n","<template>\n <div v-if=\"contact\" class=\"vue-chat relative w-full h-full overflow-hidden\">\n <FloatingDateHeader\n :label=\"floatingHeader\"\n :opacity=\"scroll.headerOpacity.value\"\n :offset=\"hasCall\"\n />\n\n <!-- Flipped Scroll Container -->\n <div\n dir=\"rtl\"\n id=\"list\"\n ref=\"scrollContainer\"\n class=\"h-full w-full max-w-dvw overflow-x-hidden overflow-y-auto pt-4 pb-4 chat-scrollbar flip-vertical bg-chat-surface/30\"\n :class=\"{ 'overflow-hidden': lockScroll }\"\n @scroll=\"scroll.handleScroll\"\n @wheel.prevent=\"scroll.handleWheel\"\n >\n <div\n class=\"w-full max-w-dvw overflow-x-hidden\"\n v-show=\"msgList.messages.value.length\"\n >\n <div\n :style=\"{\n height: scroll.virtualizer.value.getTotalSize() + 'px',\n width: '100%',\n position: 'relative',\n }\"\n >\n <div\n v-for=\"{ row, message } in virtualRows\"\n :key=\"message.id\"\n :data-index=\"row.index\"\n :ref=\"\n (el) => el && scroll.virtualizer.value.measureElement(el as any)\n \"\n :style=\"{\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n transform: `translateY(${row.start}px)`,\n }\"\n >\n <div\n class=\"flip-vertical pt-0\"\n :class=\"[row.index === 0 ? 'pb-2' : '', enterAnimation(message)]\"\n >\n <ChatBubble\n :is-deleting=\"msgList.deletingIds.value.has(message.id)\"\n :is-first-unread=\"message.id === msgList.firstUnreadId.value\"\n :message=\"message\"\n :contact=\"contact\"\n />\n </div>\n </div>\n </div>\n\n <!-- Older messages on their way in, above the ones already shown. -->\n <div v-show=\"msgList.isLoading.value\" class=\"w-full shrink-0 flip-vertical\">\n <MessagesSkeleton :count=\"2\" />\n </div>\n </div>\n\n <!-- Empty States -->\n <div\n v-show=\"msgList.messages.value.length === 0 && !msgList.isLoading.value\"\n class=\"h-full flex items-center justify-center text-chat-muted text-body-md flip-vertical\"\n >\n <NoDataDisplay :title=\"t('noMessages')\" :image-path=\"NoMessages\" />\n </div>\n\n <div\n v-show=\"msgList.messages.value.length === 0 && msgList.isLoading.value\"\n class=\"w-full flex h-full flip-vertical items-end\"\n >\n <MessagesSkeleton />\n </div>\n\n <div\n class=\"transition-all duration-200 ease-in-out pointer-events-none\"\n :class=\"[scroll.canScroll.value ? 'h-16' : 'h-0']\"\n ></div>\n </div>\n\n <div\n class=\"absolute pointer-events-none bottom-0 right-0 w-full transition-all duration-300 ease-in-out\"\n @click.self.stop\n >\n <ScrollToBottomButton\n :visible=\"scroll.canScroll.value\"\n :unseen=\"newWhileScrolledUp\"\n @click=\"scroll.resetScroll()\"\n />\n </div>\n </div>\n\n <ConfirmModal ref=\"modal\" @action=\"handleModalConfirm\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick, onBeforeUnmount } from \"vue\";\nimport ConfirmModal from \"~/components/general/ConfirmModal.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { chat, chatMessages } from \"@i18n/locales\";\nimport { useAppToast } from \"~/composables/useAppToast\";\nimport ChatBubble from \"./ChatBubble.vue\";\nimport MessagesSkeleton from \"./messages/MessagesSkeleton.vue\";\nimport FloatingDateHeader from \"./messages/FloatingDateHeader.vue\";\nimport ScrollToBottomButton from \"./messages/ScrollToBottomButton.vue\";\nimport type { Contact, ExtendedMessage } from \"~/types\";\nimport NoDataDisplay from \"../general/NoDataDisplay.vue\";\nimport NoMessages from \"~/assets/lib-images/chat/empty-state.webp\";\nimport type { Modal } from \"~/types/components/modal\";\nimport { useMessagesStore } from \"~/stores/messageStores\";\nimport { useChatStore } from \"~/stores/chatStore\";\nimport { useCallStore } from \"~/stores/callStore\";\nimport { useDate } from \"~/composables/useDate\";\nimport { useChatMessageList } from \"~/composables/useChatMessageList.js\";\nimport { useFlippedVirtualScroll } from \"~/composables/useFlippedVirtualScroll.js\";\nimport { useProfileStore } from \"~/stores/profileStore.js\";\n\nwithDefaults(defineProps<{ contact: Contact | null }>(), { contact: null });\n\nconst modal = ref<Modal | null>(null);\nconst chatStore = useChatStore();\nconst callStore = useCallStore();\nconst messagesStore = useMessagesStore();\n// One call: a component gets a single local scope, so a second useLocalI18n() would return the\n// first one's messages.\nconst { t } = useLocalI18n(chatMessages, chat);\nconst { openToast } = useAppToast();\nconst { formatDateShort } = useDate();\nconst profileStore = useProfileStore();\nconst currentUserId = computed(() => profileStore.userId);\n\nconst chatId = computed(() => chatStore.activeConversationId);\nconst hasCall = computed(() => callStore.isActive);\nconst lockScroll = computed(() => messagesStore.isOptionMenuOpen);\nconst scrollContainer = ref<HTMLElement | null>(null);\nconst selectedToDelete = ref<string[]>([]);\n\n// --- Initialize Composables ---\n\n// 1. Message List State\nconst msgList = useChatMessageList(chatId);\n\n// 2. Scroll Mechanics (Depends on msgList for loadMore and count updates)\nconst scroll = useFlippedVirtualScroll({\n scrollContainer,\n hasCall,\n isLoading: msgList.isLoading,\n isLocked: lockScroll,\n onLoadMore: msgList.loadNextPage,\n});\n\n// Each rendered row paired with its message, so the template looks it up once.\nconst virtualRows = computed(() =>\n scroll.virtualizer.value\n .getVirtualItems()\n .map((row) => ({ row, message: msgList.reversedMessages.value[row.index]! }))\n .filter(({ message }) => !!message),\n);\n\nconst enterAnimation = (message: ExtendedMessage) => {\n if (!msgList.animatingIds.value.has(message.id)) return \"\";\n if (message.request) return \"animate-request-in\";\n return message.senderId === currentUserId.value\n ? \"animate-slide-right\"\n : \"animate-slide-left\";\n};\n\n// Keep Virtualizer count in sync with messages\nwatch(\n () => msgList.reversedMessages.value.length,\n (len) => {\n scroll.setItemCount(len);\n scroll.setGetItemKey(\n (index: number) => msgList.reversedMessages.value[index]?.id ?? index,\n );\n },\n { immediate: true },\n);\n\n// Messages from the other side that arrived while the user was reading history, shown on the\n// scroll-to-bottom button. Keyed off the newest message so older pages loading in don't count.\nconst newWhileScrolledUp = ref(0);\nwatch(\n () => msgList.messages.value.at(-1),\n (last, prev) => {\n if (!last || !prev || last.id === prev.id) return;\n if (last.conversationId !== prev.conversationId) return;\n if (scroll.canScroll.value && last.senderId !== currentUserId.value)\n newWhileScrolledUp.value++;\n },\n);\nwatch(scroll.canScroll, (away) => {\n if (!away) newWhileScrolledUp.value = 0;\n});\nwatch(chatId, () => (newWhileScrolledUp.value = 0));\n\n// --- Event Bus Wiring ---\nmsgList.subscribeToBus({\n onSend: (hasMyMessage) => {\n if (hasMyMessage) nextTick(() => scroll.resetScroll());\n },\n onDelete: (ids) => handleDeleteMessages(ids),\n});\n\n// --- Modal / Delete Actions (UI specific logic stays in component) ---\nconst handleDeleteMessages = (idsToDelete: string[]) => {\n selectedToDelete.value = idsToDelete;\n const isRequestDeletion =\n idsToDelete.length === 1 &&\n msgList.messages.value.find((m) => m.id === idsToDelete[0])?.request;\n\n modal.value?.openModal(\n isRequestDeletion ? t(\"delete.requestTitle\") : t(\"delete.title\"),\n isRequestDeletion\n ? t(\"delete.request\")\n : idsToDelete.length === 1\n ? t(\"delete.singleMessage\")\n : t(\"delete.multipleMessages\", { count: idsToDelete.length }),\n \"error\",\n true,\n t(\"delete.confirm\"),\n );\n};\n\nconst handleModalConfirm = () => {\n if (selectedToDelete.value.length > 0) {\n modal.value?.closeModal();\n const ids = [...selectedToDelete.value];\n const conversationId = chatId.value;\n const snapshot = msgList.messages.value.filter((m) => ids.includes(m.id));\n\n // Removal is optimistic; if the server refuses, wait for the animation to finish removing\n // them and then put them back, so the thread never shows messages that still exist as gone.\n const removed = new Promise<void>((resolve) =>\n msgList.executeDelete(ids, () => {\n selectedToDelete.value = [];\n resolve();\n }),\n );\n messagesStore.confirmDelete(ids).catch(async () => {\n await removed;\n if (conversationId) messagesStore.restoreMessages(conversationId, snapshot);\n openToast(t(\"chat.deleteFailed\"), \"error\");\n });\n }\n};\n\n// --- Floating Header Text ---\nconst floatingHeader = computed(() => {\n const msg =\n msgList.reversedMessages.value[scroll.topVisibleMessageIndex.value];\n if (!msg) return null;\n if (msg.id === msgList.firstUnreadId.value) return t(\"unreadMessages\");\n return formatDateShort(msg.date);\n});\n\n// --- Lifecycle ---\nonMounted(() => {\n if (chatId.value) {\n messagesStore.markAsRead(chatId.value);\n msgList.fetchMessages(1);\n }\n});\n\nonBeforeUnmount(() => {\n scroll.cleanup();\n});\n\nwatch(\n () => chatId.value,\n (newId, oldId) => {\n if (newId && newId !== oldId) {\n messagesStore.markAsRead(newId);\n if (scrollContainer.value) scrollContainer.value.scrollTop = 0;\n msgList.fetchMessages(1);\n }\n },\n);\n</script>\n\n<style scoped>\n/* Styles remain exactly the same */\n.flip-vertical {\n transform: scaleY(-1);\n will-change: transform;\n}\n[data-index] {\n will-change: transform;\n backface-visibility: hidden;\n}\n\n@keyframes slide-in-right {\n 0% {\n opacity: 0;\n transform: scaleY(-1) translateX(30px);\n }\n 100% {\n opacity: 1;\n transform: scaleY(-1) translateX(0);\n }\n}\n@keyframes slide-in-left {\n 0% {\n opacity: 0;\n transform: scaleY(-1) translateX(-30px);\n }\n 100% {\n opacity: 1;\n transform: scaleY(-1) translateX(0);\n }\n}\n.animate-slide-right {\n animation: slide-in-right 300ms ease-out forwards;\n will-change: transform, opacity;\n}\n.animate-slide-left {\n animation: slide-in-left 300ms ease-out forwards;\n will-change: transform, opacity;\n}\n#list {\n will-change: padding-top;\n}\n\n.animate-request-in {\n animation: request-in 0.4s ease-out forwards;\n overflow: hidden;\n transform: scaleY(-1);\n}\n@keyframes request-in {\n 0% {\n opacity: 0;\n max-height: 0;\n transform: scaleY(-1) translateY(10px);\n }\n 100% {\n opacity: 1;\n max-height: 1000px;\n transform: scaleY(-1) translateY(0);\n }\n}\n</style>\n","<template>\n <div class=\"vue-chat relative z-20 w-full\">\n <div\n v-if=\"selectedChat\"\n class=\"relative z-50 flex h-16 w-full items-center justify-between gap-x-4 border-b border-b-chat-outline-variant bg-chat-background py-4 px-5 md:h-20\"\n >\n <div\n class=\"relative flex w-full items-center justify-between gap-x-4\"\n >\n <Button\n text\n severity=\"secondary\"\n class=\"gap-x-3! p-1! text-start\"\n @click=\"openProfile\"\n >\n <div class=\"relative h-10 w-10 shrink-0\">\n <ContactAvatar v-if=\"contact\" :contact=\"contact\" />\n </div>\n <div class=\"select-none\">\n <div class=\"text-label-md text-chat-on-background\">\n {{ selectedChat.name }} {{ selectedChat.lastName }}\n </div>\n <div\n v-if=\"selectedChat.lastSeen\"\n class=\"text-body-sm text-chat-muted\"\n >\n {{\n t(\"lastSeen\", {\n time: formatRelativeDate(selectedChat.lastSeen),\n })\n }}\n </div>\n </div>\n </Button>\n\n <div class=\"relative z-[1001] h-10\">\n <div\n class=\"relative transition-all duration-200 ease-in-out\"\n :class=\"[isSelectMode ? '-translate-y-10' : 'translate-y-0']\"\n >\n <div\n class=\"relative flex items-center gap-x-4 transition-all duration-200 ease-in-out\"\n >\n <!-- Host actions for the open conversation, beside the call button. -->\n <slot name=\"actions\" :contact=\"selectedChat\" />\n <IconButton\n v-if=\"selectedChat.serviceType !== 'chat'\"\n icon=\"PhPhone\"\n icon-class=\"size-6\"\n :label=\"t('actions.call')\"\n data-testid=\"chat-start-call\"\n class=\"hidden! md:inline-flex!\"\n @click=\"initCall\"\n />\n <IconButton\n v-if=\"options.length\"\n icon=\"PhDotsThreeVertical\"\n icon-class=\"size-6\"\n :label=\"t('actions.moreOptions')\"\n aria-haspopup=\"true\"\n data-testid=\"chat-more-options\"\n @click=\"optionsMenuRef?.toggle($event)\"\n />\n <Menu ref=\"optionsMenu\" :model=\"menuItems\" popup class=\"vue-chat\">\n <template #itemicon=\"{ item }\">\n <BIcon\n :icon=\"item.phIcon\"\n class=\"size-5\"\n :class=\"item.danger ? 'text-chat-error' : 'text-chat-muted'\"\n />\n </template>\n </Menu>\n </div>\n <!-- <div\n class=\"hidden items-center gap-x-4 md:flex\"\n \n >\n <BIcon\n icon=\"PhTrash\"\n class=\"h-6 w-6\"\n :class=\"[\n canDelete\n ? 'cursor-pointer fill-chat-error'\n : 'cursor-not-allowed fill-chat-muted',\n ]\"\n @click=\"deleteMessages\"\n />\n <BIcon\n icon=\"PhCopy\"\n class=\"h-6 w-6 cursor-pointer fill-chat-on-background\"\n @click=\"copy\"\n />\n </div> -->\n </div>\n </div>\n </div>\n <IconButton\n icon=\"PhArrowLeft\"\n icon-class=\"size-6\"\n :label=\"t('actions.back')\"\n class=\"md:hidden!\"\n @click=\"goBack\"\n />\n </div>\n\n <!-- A conversation is open but its contact is still being fetched (e.g. a deep link). -->\n <div\n v-else-if=\"currentConversationId\"\n class=\"relative z-50 flex h-16 w-full items-center gap-x-3 border-b border-b-chat-outline-variant bg-chat-background py-4 px-5 md:h-20\"\n >\n <div class=\"h-10 w-10 shrink-0 overflow-hidden rounded-full\">\n <div v-loading=\"true\" class=\"h-full w-full\" />\n </div>\n <div class=\"flex flex-col gap-y-1.5\">\n <div v-loading=\"true\" class=\"h-4 w-32\" />\n <div v-loading=\"true\" class=\"h-3 w-20\" />\n </div>\n </div>\n\n <div class=\"absolute bottom-0 z-20 h-0 w-full overflow-visible\">\n <div\n class=\"flex w-full items-center overflow-hidden whitespace-nowrap bg-diamond-primary-secondary text-wrap px-2 transition-all duration-200 ease-in-out\"\n :class=\"[callData.show ? 'h-11' : 'h-0']\"\n >\n <div\n class=\"flex w-full items-center gap-x-3 transition-all duration-200 ease-in-out\"\n :class=\"[callData.show ? 'opacity-100' : 'opacity-0']\"\n >\n <BIcon icon=\"PhPhoneCall\" class=\"h-5 w-5 shrink-0 fill-white\" />\n <div class=\"flex-1 select-none text-label-md text-white\">\n {{ callData.duration }}\n </div>\n <IconButton\n icon=\"PhFrameCorners\"\n :label=\"t('actions.returnToCall')\"\n size=\"small\"\n class=\"shrink-0 text-white!\"\n @click=\"backToCall\"\n />\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport vLoading from \"~/directives/loading\";\nimport Button from \"primevue/button\";\nimport Menu from \"primevue/menu\";\nimport type { MenuItem } from \"primevue/menuitem\";\nimport type { MenuOption } from \"~/types/components/menu-options\";\nimport IconButton from \"~/components/general/IconButton.vue\";\nimport { useMessagesStore } from \"~/stores/messageStores.js\";\nimport ContactAvatar from \"./contact/ContactAvatar.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { useCallStore } from \"~/stores/callStore.js\";\nimport { useChatStore } from \"~/stores/chatStore.js\";\nimport { useDate } from \"~/composables/useDate.js\";\nimport { formatDuration } from \"~/utils/format\";\nimport { chatPageBar } from \"@i18n/locales\";\nimport type { Contact } from \"~/types\";\nimport { computed, useTemplateRef } from \"vue\";\n\nconst props = withDefaults(\n defineProps<{\n contact: Contact | null;\n /** Actions for the open conversation, listed in the header's \"more options\" menu. */\n options: MenuOption[];\n }>(),\n {\n contact: null,\n options: () => [],\n },\n);\n\nconst emit = defineEmits<{\n call: [];\n \"open-profile\": [];\n select: [key: string];\n}>();\n\nconst optionsMenuRef = useTemplateRef<InstanceType<typeof Menu>>(\"optionsMenu\");\nconst menuItems = computed<MenuItem[]>(() =>\n props.options.map((option) => ({\n label: option.label,\n phIcon: option.icon,\n danger: option.color === \"error\",\n command: () => emit(\"select\", option.key),\n })),\n);\n\nconst messagesStore = useMessagesStore();\nconst { formatRelativeDate } = useDate();\nconst { t } = useLocalI18n(chatPageBar);\nconst callStore = useCallStore();\nconst chatStore = useChatStore();\n\nconst currentConversationId = computed(() => chatStore.activeConversationId);\nconst isSelectMode = computed(() => messagesStore.isSelectMode);\nconst selectedChat = computed(() => props.contact);\nconst callData = computed(() => ({\n show: callStore.isActive,\n duration: formatDuration(callStore.elapsedTime),\n}));\n\nconst openProfile = () => {\n emit(\"open-profile\");\n};\n\nconst goBack = () => {\n chatStore.setSelectedChat(null);\n};\n\nconst initCall = () => {\n if (currentConversationId.value) {\n callStore.startCall(currentConversationId.value);\n }\n};\n\nconst backToCall = () => {\n callStore.maximize();\n};\n</script>\n","<script setup lang=\"ts\">\nimport { defineAsyncComponent } from \"vue\";\nimport type { EmojiExt } from \"vue3-emoji-picker\";\n\n// Loaded when a picker first renders, not with the chat.\nconst EmojiPicker = defineAsyncComponent(async () => {\n const [picker] = await Promise.all([\n import(\"vue3-emoji-picker\"),\n import(\"vue3-emoji-picker/css\"),\n ]);\n return picker.default;\n});\n\nconst emit = defineEmits<{ select: [emoji: EmojiExt] }>();\n</script>\n\n<template>\n <EmojiPicker :native=\"true\" @select=\"(emoji: EmojiExt) => emit('select', emoji)\" />\n</template>\n\n<style>\n.v3-emoji-picker {\n height: 407px;\n width: 332px;\n}\n\n.v3-emoji-picker .v3-footer {\n display: none !important;\n}\n</style>\n","<template>\n <div class=\"flex w-full select-none items-center gap-x-2\">\n <div class=\"flex min-w-0 flex-1 flex-col gap-y-0.5 text-left\">\n <div class=\"truncate text-label-md text-chat-on-background\">{{ fileName }}</div>\n <div dir=\"ltr\" class=\"text-body-sm text-chat-on-background/70\">\n {{ formattedSize }}\n </div>\n </div>\n\n <div\n class=\"relative shrink-0 cursor-pointer transition-transform active:scale-95\"\n >\n <BIcon icon=\"PhFile\" class=\"h-10 w-10 fill-white\" />\n <div\n class=\"absolute bottom-2 right-0 flex items-center justify-center rounded-sm bg-chat-error px-1 py-0.5\"\n >\n <div\n class=\"text-center text-[7px] font-bold uppercase leading-none tracking-wide text-white\"\n >\n {{ fileExt }}\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport { formatBytes } from \"~/utils/format\";\n\ninterface AttachmentFile {\n name: string;\n size: number;\n format: string;\n path: string;\n}\n\nconst props = defineProps<{\n file: AttachmentFile;\n}>();\n\nconst fileExt = computed(() => {\n if (!props.file?.name) return \"FILE\";\n const parts = props.file.name.split(\".\");\n return parts.length > 1 ? parts.pop()?.substring(0, 4) || \"FILE\" : \"FILE\";\n});\n\nconst fileName = computed(() => props.file?.name || \"Unknown File\");\n\nconst formattedSize = computed(() => formatBytes(props.file?.size || 0));\n</script>\n","import { useFileDialog } from \"@vueuse/core\";\n\nexport interface PickedImage {\n file: File;\n path: string;\n}\n\nexport interface PickedFile extends PickedImage {\n name: string;\n format: string;\n size: number;\n}\n\nconst UNSAFE_EXTENSIONS = [\".exe\", \".bat\", \".sh\", \".js\"];\n\n/** Opens the browser's file chooser for images or files and hands back object URLs. */\nexport function useAttachmentPicker(handlers: {\n onImages: (images: PickedImage[]) => void;\n onFiles: (files: PickedFile[]) => void;\n}) {\n const images = useFileDialog({\n multiple: true,\n accept: \"image/jpeg, image/png, image/webp, image/gif\",\n reset: true,\n });\n images.onChange((list) => {\n const picked = Array.from(list ?? [])\n .filter((file) => file.type !== \"image/svg+xml\")\n .map((file) => ({ file, path: URL.createObjectURL(file) }));\n if (picked.length) handlers.onImages(picked);\n });\n\n const files = useFileDialog({ multiple: true, reset: true });\n files.onChange((list) => {\n const picked = Array.from(list ?? [])\n .filter(\n (file) =>\n !UNSAFE_EXTENSIONS.some((ext) => file.name.toLowerCase().endsWith(ext)),\n )\n .map((file) => ({\n file,\n name: file.name,\n path: URL.createObjectURL(file),\n format: file.type || file.name.split(\".\").pop() || \"\",\n size: file.size,\n }));\n if (picked.length) handlers.onFiles(picked);\n });\n\n // Must run inside the click handler: browsers only open a chooser on a user gesture.\n return { pickImages: () => images.open(), pickFiles: () => files.open() };\n}\n","<template>\n <div>\n <IconButton\n icon=\"PhPaperclip\"\n :label=\"t('actions.attach')\"\n icon-class=\"size-6\"\n data-testid=\"chat-attach\"\n aria-haspopup=\"true\"\n @click=\"menu?.toggle($event)\"\n />\n <Menu ref=\"menu\" :model=\"menuItems\" popup class=\"vue-chat\">\n <template #itemicon=\"{ item }\">\n <BIcon :icon=\"item.phIcon\" class=\"size-5 text-chat-muted\" />\n </template>\n </Menu>\n\n <ResponsiveDialog\n v-model:visible=\"dialogOpen\"\n :header=\"dialogTitle\"\n width=\"28.5rem\"\n @after-hide=\"resetSelections\"\n >\n <div class=\"flex w-full flex-col items-center gap-y-3\">\n <MediaImage\n v-if=\"dialogMode === 'single-image'\"\n :src=\"selectedMedia[0]?.path\"\n fit=\"contain\"\n class=\"max-h-109 w-full rounded-xl\"\n />\n\n <div\n v-else-if=\"dialogMode === 'multi-image'\"\n class=\"grid max-h-109 w-full grid-cols-4 gap-3 overflow-y-auto\"\n >\n <MediaImage\n v-for=\"(image, index) in selectedMedia\"\n :key=\"index\"\n :src=\"image.path\"\n class=\"h-25 w-full rounded-xl\"\n />\n </div>\n\n <div\n v-else\n class=\"flex max-h-109 w-full flex-col gap-y-3 overflow-y-auto\"\n >\n <AttachementFileDisplay\n v-for=\"(file, index) in selectedFiles\"\n :key=\"index\"\n :file=\"file\"\n />\n </div>\n\n <Textarea\n v-model=\"caption\"\n :placeholder=\"t('caption')\"\n rows=\"3\"\n auto-resize\n class=\"max-h-40 w-full\"\n />\n </div>\n\n <template #footer>\n <div class=\"flex w-full items-center gap-x-3\">\n <Button class=\"flex-1\" :label=\"t('send')\" @click=\"sendMessages\" />\n <Button\n class=\"flex-1\"\n severity=\"secondary\"\n :label=\"t('file.cancel')\"\n @click=\"dialogOpen = false\"\n />\n </div>\n </template>\n </ResponsiveDialog>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch } from \"vue\";\nimport Button from \"primevue/button\";\nimport Menu from \"primevue/menu\";\nimport Textarea from \"primevue/textarea\";\nimport type { MenuItem } from \"primevue/menuitem\";\nimport IconButton from \"~/components/general/IconButton.vue\";\nimport MediaImage from \"~/components/general/MediaImage.vue\";\nimport ResponsiveDialog from \"~/components/general/ResponsiveDialog.vue\";\nimport AttachementFileDisplay from \"./AttachementFileDisplay.vue\";\nimport {\n useAttachmentPicker,\n type PickedFile,\n type PickedImage,\n} from \"~/composables/useAttachmentPicker\";\nimport { useAppToast } from \"~/composables/useAppToast\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { inputAttachement } from \"@i18n/locales\";\n\ntype DialogMode = \"single-image\" | \"multi-image\" | \"file\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AttachmentData = any;\n\nconst MAX_IMAGES = 10;\n\nconst props = withDefaults(\n defineProps<{\n initialCaption?: string;\n }>(),\n {\n initialCaption: \"\",\n },\n);\n\nconst emit = defineEmits<{\n \"send-attachments\": [messages: AttachmentData[]];\n}>();\n\nconst { t } = useLocalI18n(inputAttachement);\nconst { openToast } = useAppToast();\n\nconst menu = ref<InstanceType<typeof Menu> | null>(null);\nconst dialogOpen = ref(false);\nconst dialogMode = ref<DialogMode>(\"file\");\nconst caption = ref(\"\");\nconst selectedMedia = ref<PickedImage[]>([]);\nconst selectedFiles = ref<PickedFile[]>([]);\n\nwatch(\n () => props.initialCaption,\n (newVal) => {\n caption.value = newVal;\n },\n { immediate: true },\n);\n\nconst handleMediaSelected = (incoming: PickedImage[]) => {\n const remaining = MAX_IMAGES - selectedMedia.value.length;\n\n if (remaining <= 0) {\n openToast(t(\"errors.maxFilesReached\"), \"error\");\n return;\n }\n\n selectedMedia.value = [\n ...selectedMedia.value,\n ...incoming.slice(0, remaining),\n ];\n dialogMode.value =\n selectedMedia.value.length === 1 ? \"single-image\" : \"multi-image\";\n dialogOpen.value = true;\n};\n\nconst handleFilesSelected = (files: PickedFile[]) => {\n selectedFiles.value = [...selectedFiles.value, ...files];\n dialogMode.value = \"file\";\n dialogOpen.value = true;\n};\n\nconst { pickImages, pickFiles } = useAttachmentPicker({\n onImages: handleMediaSelected,\n onFiles: handleFilesSelected,\n});\n\nconst resetSelections = () => {\n selectedMedia.value = [];\n selectedFiles.value = [];\n};\n\nconst menuItems = computed<MenuItem[]>(() => [\n {\n label: t(\"file.attachMedia\"),\n phIcon: \"PhImage\",\n command: () => {\n resetSelections();\n pickImages();\n },\n },\n {\n label: t(\"file.attachFile\"),\n phIcon: \"PhFile\",\n command: () => {\n resetSelections();\n pickFiles();\n },\n },\n]);\n\nconst dialogTitle = computed(() => {\n switch (dialogMode.value) {\n case \"file\":\n return t(\"file.sendFile\");\n case \"multi-image\":\n return t(\"file.sendImages\");\n case \"single-image\":\n return t(\"file.sendImage\");\n }\n});\n\nconst sendMessages = () => {\n const messagesToEmit: AttachmentData[] = [];\n\n if (caption.value.trim()) {\n messagesToEmit.push({\n type: \"text\",\n text: caption.value,\n });\n }\n\n if (selectedMedia.value.length > 0) {\n messagesToEmit.push({\n type: \"image\",\n imageUrl: selectedMedia.value.map((m) => m.path),\n files: selectedMedia.value.map((m) => m.file),\n });\n }\n\n selectedFiles.value.forEach((fileData) => {\n messagesToEmit.push({\n type: \"file\",\n fileUrl: fileData.path,\n file: fileData.file,\n fileName: fileData.name,\n });\n });\n\n emit(\"send-attachments\", messagesToEmit);\n dialogOpen.value = false;\n};\n</script>\n","// @ts-nocheck — grandfathered legacy chat-tree type errors; lift incrementally\n// composables/useChatRecording.ts\nimport { ref, computed, onBeforeUnmount, type Ref } from \"vue\";\n\nexport function useChatRecording(\n inputWidth: Ref<number | undefined>,\n callbacks: {\n onStart: () => void;\n onCancel: () => void;\n onSend?: (mediaUrl?: string) => void;\n requestPermission: () => Promise<boolean>;\n getMode?: () => \"video\" | \"voice\";\n },\n) {\n const isRecording = ref(false);\n const isLocked = ref(false);\n const isPaused = ref(false);\n const recordingTime = ref(0);\n let timerInterval: ReturnType<typeof setInterval> | null = null;\n\n const mediaStream = ref<MediaStream | null>(null);\n let mediaRecorder: MediaRecorder | null = null;\n const recordedChunks: Blob[] = [];\n const currentFacingMode = ref<\"user\" | \"environment\">(\"user\");\n\n const pickRecorderMime = (isVideo: boolean) => {\n const candidates = isVideo\n ? [\n \"video/webm;codecs=vp9,opus\",\n \"video/webm;codecs=vp8,opus\",\n \"video/webm\",\n \"video/mp4\",\n ]\n : [\"audio/webm;codecs=opus\", \"audio/webm\", \"audio/mp4\"];\n for (const c of candidates) {\n if (\n typeof MediaRecorder !== \"undefined\" &&\n MediaRecorder.isTypeSupported(c)\n )\n return c;\n }\n return isVideo ? \"video/webm\" : \"audio/webm\";\n };\n\n const startRecorder = () => {\n const stream = mediaStream.value;\n if (!stream || typeof MediaRecorder === \"undefined\") return;\n recordedChunks.length = 0;\n const isVideo = stream.getVideoTracks().length > 0;\n let recorder: MediaRecorder;\n try {\n recorder = new MediaRecorder(stream, {\n mimeType: pickRecorderMime(isVideo),\n });\n } catch {\n try {\n recorder = new MediaRecorder(stream);\n } catch (err) {\n console.error(\"Failed to create MediaRecorder:\", err);\n return;\n }\n }\n recorder.ondataavailable = (event) => {\n if (event.data && event.data.size > 0) recordedChunks.push(event.data);\n };\n recorder.start(250);\n mediaRecorder = recorder;\n };\n\n const stopStream = () => {\n if (mediaStream.value) {\n mediaStream.value.getTracks().forEach((t) => t.stop());\n mediaStream.value = null;\n }\n };\n\n const finalizeAndSend = () => {\n const chunks = recordedChunks.slice();\n const mimeType =\n (mediaRecorder && mediaRecorder.mimeType) ||\n (chunks.length ? chunks[0].type : \"video/webm\");\n mediaRecorder = null;\n recordedChunks.length = 0;\n stopStream();\n if (chunks.length === 0) {\n callbacks.onCancel();\n return;\n }\n const blob = new Blob(chunks, { type: mimeType });\n if (blob.size === 0) {\n callbacks.onCancel();\n return;\n }\n callbacks.onSend?.(URL.createObjectURL(blob));\n };\n\n const toggleCamera = async () => {\n if (!mediaStream.value || !isRecording.value) return;\n currentFacingMode.value =\n currentFacingMode.value === \"user\" ? \"environment\" : \"user\";\n\n const oldTrack = mediaStream.value.getVideoTracks()[0];\n if (oldTrack) oldTrack.stop();\n\n try {\n const newStream = await navigator.mediaDevices.getUserMedia({\n video: { facingMode: currentFacingMode.value },\n });\n if (mediaStream.value && newStream.getVideoTracks()[0]) {\n mediaStream.value.removeTrack(oldTrack);\n mediaStream.value.addTrack(newStream.getVideoTracks()[0]);\n }\n } catch (err) {\n console.error(\"Failed to flip camera:\", err);\n }\n };\n\n // Drag State\n const isDragging = ref(false);\n const startX = ref(0);\n const startY = ref(0);\n const dragOffset = ref({ x: 0, y: 0 });\n const dragAxis = ref<\"x\" | \"y\" | null>(null);\n\n const pressTimer = ref<ReturnType<typeof setTimeout> | null>(null);\n const isPointerDown = ref(false);\n const isLongPress = ref(false);\n\n const formattedTime = computed(() => {\n const m = Math.floor(recordingTime.value / 60)\n .toString()\n .padStart(2, \"0\");\n const s = (recordingTime.value % 60).toString().padStart(2, \"0\");\n return `${m}:${s}`;\n });\n\n const lockOpacity = computed(() => (dragAxis.value === \"x\" ? 0 : 1));\n const cancelOpacity = computed(() =>\n dragAxis.value === \"y\"\n ? 1\n : 1 - Math.min(Math.abs(dragOffset.value.x) / 80, 1),\n );\n\n const resetDrag = () => {\n isDragging.value = false;\n dragOffset.value = { x: 0, y: 0 };\n dragAxis.value = null;\n };\n\n const togglePause = () => {\n isPaused.value = !isPaused.value;\n if (mediaRecorder && mediaRecorder.state !== \"inactive\") {\n try {\n if (isPaused.value) mediaRecorder.pause();\n else mediaRecorder.resume();\n } catch {\n // ignore — recorder pause/resume best-effort\n }\n }\n if (!isPaused.value) {\n timerInterval = setInterval(() => recordingTime.value++, 1000);\n } else if (timerInterval) {\n clearInterval(timerInterval);\n }\n };\n\n const stopRecording = (triggerSend = false) => {\n if (timerInterval) clearInterval(timerInterval);\n isRecording.value = false;\n isLocked.value = false;\n isPaused.value = false;\n recordingTime.value = 0;\n resetDrag();\n\n const recorder = mediaRecorder;\n if (triggerSend && recorder && recorder.state !== \"inactive\") {\n recorder.onstop = finalizeAndSend;\n try {\n recorder.stop();\n } catch {\n finalizeAndSend();\n }\n return;\n }\n if (recorder && recorder.state !== \"inactive\") {\n try {\n recorder.stop();\n } catch {\n // ignore\n }\n }\n mediaRecorder = null;\n recordedChunks.length = 0;\n stopStream();\n callbacks.onCancel();\n };\n\n const onPointerDown = (event: PointerEvent) => {\n isPointerDown.value = true;\n isLongPress.value = false;\n startX.value = event.clientX;\n startY.value = event.clientY;\n resetDrag();\n\n window.addEventListener(\"pointermove\", onPointerMove);\n window.addEventListener(\"pointerup\", onPointerUp);\n window.addEventListener(\"pointercancel\", onPointerUp);\n\n if (pressTimer.value) clearTimeout(pressTimer.value);\n\n pressTimer.value = setTimeout(async () => {\n isLongPress.value = true;\n // Await the permission UI\n const hasPermission = await callbacks.requestPermission();\n\n if (hasPermission && isPointerDown.value) {\n isDragging.value = true;\n isRecording.value = true;\n isPaused.value = false;\n recordingTime.value = 0;\n callbacks.onStart();\n timerInterval = setInterval(() => recordingTime.value++, 1000);\n\n try {\n const isVideo = !callbacks.getMode || callbacks.getMode() === \"video\";\n mediaStream.value = await navigator.mediaDevices.getUserMedia({\n video: isVideo ? { facingMode: currentFacingMode.value } : false,\n audio: true,\n });\n startRecorder();\n } catch (err) {\n console.error(\"Stream failed\", err);\n }\n }\n }, 400);\n };\n\n const onPointerMove = (event: PointerEvent) => {\n if (!isRecording.value || isLocked.value || !isDragging.value) return;\n\n const deltaX = event.clientX - startX.value;\n const deltaY = event.clientY - startY.value;\n\n if (!dragAxis.value) {\n if (deltaY < -10) dragAxis.value = \"y\";\n else if (deltaX < -10) dragAxis.value = \"x\";\n }\n\n if (dragAxis.value === \"y\") {\n dragOffset.value.y = Math.max(-100, Math.min(0, deltaY));\n if (dragOffset.value.y <= -60) {\n isLocked.value = true;\n resetDrag();\n }\n } else if (dragAxis.value === \"x\") {\n const cancelThreshold = inputWidth.value ? inputWidth.value / 3 : 150;\n dragOffset.value.x = Math.max(-cancelThreshold, Math.min(0, deltaX));\n if (deltaX <= -cancelThreshold) stopRecording(false);\n }\n };\n\n const onPointerUp = () => {\n isPointerDown.value = false;\n window.removeEventListener(\"pointermove\", onPointerMove);\n window.removeEventListener(\"pointerup\", onPointerUp);\n window.removeEventListener(\"pointercancel\", onPointerUp);\n\n if (pressTimer.value) {\n clearTimeout(pressTimer.value);\n pressTimer.value = null;\n }\n\n if (isRecording.value && !isLocked.value) {\n if (dragAxis.value === \"x\") stopRecording(false);\n else stopRecording(true);\n }\n resetDrag();\n };\n\n // Release the MediaStream and stop the timer if the host component\n // unmounts mid-recording (e.g. route change while recording).\n onBeforeUnmount(() => {\n if (pressTimer.value) {\n clearTimeout(pressTimer.value);\n pressTimer.value = null;\n }\n window.removeEventListener(\"pointermove\", onPointerMove);\n window.removeEventListener(\"pointerup\", onPointerUp);\n window.removeEventListener(\"pointercancel\", onPointerUp);\n if (isRecording.value) stopRecording(false);\n });\n\n return {\n isRecording,\n isLocked,\n isPaused,\n formattedTime,\n dragOffset,\n isDragging,\n lockOpacity,\n cancelOpacity,\n isLongPress,\n onPointerDown,\n mediaStream,\n toggleCamera,\n togglePause,\n stopRecording,\n };\n}\n","<template>\n <div\n class=\"pointer-events-none fixed left-0 top-0 z-20 h-dvh w-dvw overflow-visible md:absolute md:h-0 md:w-full md:backdrop-blur-none\"\n :class=\"[\n isOpen\n ? 'bg-chat-on-background/10 backdrop-blur-lg md:bg-transparent'\n : 'backdrop-blur-none',\n ]\"\n >\n <div\n class=\"pointer-events-none flex h-full flex-col items-center justify-between py-26 md:h-auto md:-translate-y-full md:items-end md:pr-4 md:py-4\"\n >\n <!-- Spacer for mobile layout to push video up -->\n <div class=\"md:hidden\" />\n\n <!-- Video Bubble -->\n <div\n class=\"transition-all duration-200 ease-in-out\"\n :class=\"[\n isOpen\n ? 'pointer-events-auto translate-y-0 scale-100 opacity-100'\n : 'pointer-events-none translate-y-1/4 scale-0 opacity-0',\n ]\"\n >\n <BubbleVideo\n mode=\"recording\"\n :stream=\"stream\"\n :is-paused=\"isPaused\"\n :recording-time=\"recordingTime\"\n :max-duration=\"60\"\n />\n </div>\n\n <!-- Mobile Bottom Toolbar -->\n <div\n class=\"origin-bottom flex items-center gap-x-2 rounded-full bg-chat-background px-4 py-3 shadow-floating md:hidden\"\n :class=\"[\n isOpen\n ? 'pointer-events-auto translate-y-0 scale-100 opacity-100'\n : 'pointer-events-none translate-y-1/4 scale-0 opacity-0',\n ]\"\n >\n <IconButton\n v-for=\"option in mobileOptions\"\n :key=\"option.key\"\n :icon=\"option.icon\"\n :label=\"option.label\"\n icon-class=\"size-6\"\n :disabled=\"option.disabled\"\n @click=\"handleOption(option.key)\"\n />\n </div>\n </div>\n </div>\n</template>\n\n<!-- Normal script block used to export the interface for parent components to import -->\n<script lang=\"ts\">\nexport interface VideoRecordDisplayExposed {\n open: () => void;\n close: () => void;\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted, watch } from \"vue\";\nimport BubbleVideo from \"../chat-bubbles/BubbleVideo.vue\";\nimport IconButton from \"~/components/general/IconButton.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { chatInput } from \"@i18n/locales\";\n\nconst props = withDefaults(\n defineProps<{\n stream?: MediaStream | null;\n isPaused?: boolean;\n recordingTime?: number;\n }>(),\n {\n stream: null,\n isPaused: false,\n recordingTime: 0,\n },\n);\n\nconst emit = defineEmits<{\n \"flip-camera\": [];\n}>();\n\nconst { t } = useLocalI18n(chatInput);\nconst isOpen = ref(false);\nconst isFlashOn = ref(false);\nconst hasMultipleCameras = ref(false);\nconst supportsTorch = ref(false);\n\nconst flashIcon = computed(() =>\n isFlashOn.value ? \"PhLightningSlash\" : \"PhLightning\",\n);\n\nonMounted(async () => {\n try {\n const devices = await navigator.mediaDevices.enumerateDevices();\n const videoInputs = devices.filter((d) => d.kind === \"videoinput\");\n hasMultipleCameras.value = videoInputs.length > 1;\n } catch (err) {\n console.error(\"Failed to enumerate devices for camera count\", err);\n }\n});\n\nwatch(\n () => props.stream,\n (newStream) => {\n if (newStream) {\n const track = newStream.getVideoTracks()[0];\n if (track && track.getCapabilities) {\n const caps = track.getCapabilities();\n supportsTorch.value = \"torch\" in caps;\n } else {\n supportsTorch.value = false;\n }\n } else {\n supportsTorch.value = false;\n isFlashOn.value = false;\n }\n },\n { immediate: true },\n);\n\nconst mobileOptions = computed(() => [\n {\n icon: \"PhArrowsClockwise\",\n label: t(\"actions.flipCamera\"),\n key: \"flip-camera\" as const,\n disabled: !hasMultipleCameras.value,\n },\n {\n icon: flashIcon.value,\n label: t(\"actions.flashlight\"),\n key: \"toggle-flash\" as const,\n disabled: !supportsTorch.value,\n },\n]);\n\nconst handleOption = async (key: string) => {\n const option = mobileOptions.value.find((o) => o.key === key);\n if (option?.disabled) return;\n\n switch (key) {\n case \"toggle-flash\": {\n const track = props.stream?.getVideoTracks()[0];\n if (track) {\n try {\n isFlashOn.value = !isFlashOn.value;\n // Apply the native torch constraint to the existing track.\n // `torch` is a non-standard Chromium-only MediaTrackConstraint, so TS doesn't know it;\n // cast through `unknown` to satisfy the type checker without silencing it broadly.\n await track.applyConstraints({\n advanced: [{ torch: isFlashOn.value }],\n } as unknown as MediaTrackConstraints);\n } catch (err) {\n console.error(\"Failed to toggle flash:\", err);\n isFlashOn.value = !isFlashOn.value; // Revert UI if hardware rejects it\n }\n }\n break;\n }\n case \"flip-camera\":\n emit(\"flip-camera\");\n break;\n }\n};\n\nconst open = () => {\n isOpen.value = true;\n};\n\nconst close = () => {\n isOpen.value = false;\n};\n\ndefineExpose<VideoRecordDisplayExposed>({\n open,\n close,\n});\n</script>\n","import { ref, nextTick, type Ref } from \"vue\";\nimport { parseEmojiArray } from \"~/utils/emojiParser\";\n\nexport function useRichTextEditor(inputRef: Ref<HTMLDivElement | null>) {\n const messageText = ref(\"\");\n const savedRange = ref<Range | null>(null);\n const isSelectingEmoji = ref(false);\n\n const adjustHeight = () => {\n const el = inputRef.value;\n if (!el) return;\n\n // 1. Temporarily shrink to get the accurate scroll height of the content\n el.style.height = \"0px\";\n\n // 2. Cap at 144 to match the CSS max-height. This prevents JS from assigning\n // a height larger than 144px, which would break the parent flex layout.\n const maxHeight = 144;\n el.style.height = `${Math.min(el.scrollHeight, maxHeight)}px`;\n };\n const saveCursorPosition = () => {\n const selection = window.getSelection();\n if (selection && selection.rangeCount > 0 && inputRef.value) {\n if (inputRef.value.contains(selection.anchorNode)) {\n savedRange.value = selection.getRangeAt(0).cloneRange();\n }\n }\n };\n\n const handleContentInput = () => {\n if (!inputRef.value) return;\n messageText.value = inputRef.value.innerText;\n adjustHeight();\n };\n\n const handleEmojiSelect = (emoji: string, shouldBlurAfter = false) => {\n isSelectingEmoji.value = true;\n if (!inputRef.value) return;\n\n inputRef.value.focus();\n const selection = window.getSelection();\n let range: Range;\n\n if (savedRange.value) {\n range = savedRange.value;\n selection?.removeAllRanges();\n selection?.addRange(range);\n } else {\n range = document.createRange();\n range.selectNodeContents(inputRef.value);\n range.collapse(false);\n selection?.removeAllRanges();\n selection?.addRange(range);\n }\n\n range.deleteContents();\n\n const parsed = parseEmojiArray(emoji);\n if (parsed.length > 0 && parsed[0].type === \"emoji\") {\n const chunk = parsed[0];\n const span = document.createElement(\"span\");\n span.textContent = chunk.content;\n span.className =\n \"emoji-glyph inline-block h-5 w-5 mx-0.5 leading-5 text-xl align-middle select-text pointer-events-none\";\n span.setAttribute(\"contenteditable\", \"false\");\n\n range.insertNode(span);\n range.setStartAfter(span);\n range.collapse(true);\n selection?.removeAllRanges();\n selection?.addRange(range);\n savedRange.value = range.cloneRange();\n }\n\n handleContentInput();\n\n nextTick(() => {\n if (shouldBlurAfter) inputRef.value?.blur();\n adjustHeight();\n });\n\n isSelectingEmoji.value = false;\n };\n\n /** Replaces the content with plain text, e.g. a restored draft or a message being edited. */\n const setText = (text: string) => {\n messageText.value = text;\n savedRange.value = null;\n if (inputRef.value) inputRef.value.innerText = text;\n nextTick(() => adjustHeight());\n };\n\n const clearInput = () => {\n messageText.value = \"\";\n if (inputRef.value) inputRef.value.innerHTML = \"\";\n nextTick(() => adjustHeight());\n };\n\n return {\n messageText,\n isSelectingEmoji,\n saveCursorPosition,\n handleContentInput,\n handleEmojiSelect,\n clearInput,\n setText,\n adjustHeight,\n };\n}\n","<script setup lang=\"ts\">\n/** The strip above the input while replying to or editing a message. */\nimport SafeEmojiText from \"~/components/general/SafeEmojiText.vue\";\nimport IconButton from \"~/components/general/IconButton.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { chatInput } from \"@i18n/locales\";\n\ndefineProps<{\n mode: \"normal\" | \"edit\" | \"reply\";\n /** Who wrote the message being replied to. */\n name: string;\n text: string;\n}>();\nconst emit = defineEmits<{ cancel: [] }>();\n\nconst { t } = useLocalI18n(chatInput);\n</script>\n\n<template>\n <div\n :class=\"[mode !== 'normal' ? ' h-10' : 'h-0']\"\n class=\"gap-x-3 px-3 w-full whitespace-nowrap overflow-hidden border-t select-none text-body-sm border-t-outline-variant flex relative z-30 justify-between items-center transition-all duration-200 ease-in-out bg-surface\"\n >\n <BIcon\n :icon=\"mode === 'edit' ? 'PhPencilSimpleLine' : 'PhArrowBendUpLeft'\"\n class=\"w-5 h-5 fill-on-surface shrink-0\"\n />\n <div class=\"flex-1 flex items-center gap-x-2\">\n <div v-if=\"mode === 'reply'\" class=\"shrink-0 text-chat-muted\">\n {{ name }} :\n </div>\n <div class=\"flex-1\">\n <div\n class=\"text-on-surface w-full overflow-hidden text-ellipsis line-clamp-1\"\n >\n <SafeEmojiText :text=\"text\" />\n </div>\n </div>\n </div>\n <IconButton\n icon=\"PhX\"\n :label=\"t('cancel')\"\n size=\"small\"\n class=\"shrink-0\"\n @click=\"emit('cancel')\"\n />\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Replaces the text field while recording: swipe-to-cancel hint (or Cancel once locked) and the timer. */\nimport Button from \"primevue/button\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { chat, chatInput } from \"@i18n/locales\";\n\ndefineProps<{ locked: boolean; cancelOpacity: number; time: string }>();\nconst emit = defineEmits<{ cancel: [] }>();\n\nconst { t } = useLocalI18n(chatInput, chat);\n</script>\n\n<template>\n <div class=\"flex-1 justify-between -translate-y-2 flex items-center\">\n <div></div>\n <div\n class=\"flex justify-center items-center text-body-md text-on-surface/70 transition-opacity\"\n :style=\"{ opacity: cancelOpacity }\"\n >\n <span v-if=\"!locked\">{{ t(\"chat.swipeToCancel\") }}</span>\n <Button\n v-else\n text\n size=\"small\"\n class=\"z-20\"\n :label=\"t('chat.cancel')\"\n @click=\"emit('cancel')\"\n />\n </div>\n\n <div class=\"left-6 flex items-center gap-x-2 shrink-0 z-10\">\n <div class=\"w-2.5 h-2.5 relative\">\n <div class=\"w-2.5 h-2.5 rounded-full bg-error\"></div>\n <div\n class=\"w-2.5 h-2.5 rounded-full bg-error animate-ping absolute top-0 left-0 inset-0\"\n ></div>\n </div>\n <span\n class=\"text-body-md min-w-12 text-center text-on-surface tabular-nums mt-0.5\"\n dir=\"ltr\"\n >{{ time }}</span\n >\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * The primary action beside the input: the microphone/camera button (hold to record, tap to\n * switch between voice and video), or the send button once there is text or a locked recording.\n * While recording it floats the lock pill above itself, which becomes pause/resume once locked.\n */\nimport { computed } from \"vue\";\nimport Button from \"primevue/button\";\nimport IconButton from \"~/components/general/IconButton.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { chatInput } from \"@i18n/locales\";\n\nconst props = defineProps<{\n isRecording: boolean;\n isLocked: boolean;\n isPaused: boolean;\n hasText: boolean;\n icon: string;\n disabled?: boolean;\n lockOpacity: number;\n dragOffset: { x: number; y: number };\n isDragging: boolean;\n}>();\n\nconst emit = defineEmits<{\n pointerdown: [event: PointerEvent];\n toggleType: [];\n togglePause: [];\n send: [];\n}>();\n\nconst { t } = useLocalI18n(chatInput);\n\nconst showSend = computed(() => props.isLocked || props.hasText);\n</script>\n\n<template>\n <div\n class=\"relative z-30 mb-0.5 flex shrink-0 items-center justify-center\"\n :style=\"{\n transform: `translate(${dragOffset.x}px, ${dragOffset.y}px)`,\n transition: isDragging\n ? 'none'\n : 'transform 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n }\"\n >\n <div\n v-if=\"isRecording\"\n class=\"absolute -top-20 flex w-10 flex-col items-center justify-center rounded-full bg-chat-background shadow-floating transition-opacity\"\n :class=\"[\n isLocked ? 'pointer-events-auto py-1' : 'pointer-events-none gap-y-3 py-3',\n ]\"\n :style=\"{ opacity: lockOpacity }\"\n >\n <BIcon v-if=\"!isLocked\" icon=\"PhLockKey\" class=\"size-5\" />\n <IconButton\n v-else\n :icon=\"isPaused ? 'PhPlayCircle' : 'PhPauseCircle'\"\n :label=\"isPaused ? t('actions.resume') : t('actions.pause')\"\n icon-class=\"size-6\"\n @click=\"emit('togglePause')\"\n />\n <BIcon icon=\"PhCaretUp\" class=\"size-4 animate-bounce opacity-60\" />\n </div>\n\n <Button\n v-if=\"showSend\"\n rounded\n :aria-label=\"t('actions.sendMessage')\"\n :disabled=\"disabled\"\n @click=\"emit('send')\"\n >\n <template #icon>\n <BIcon icon=\"PhPaperPlaneTilt\" class=\"size-6 rtl:-scale-x-100\" />\n </template>\n </Button>\n <!-- Hold to record; a tap switches between voice and video. -->\n <Button\n v-else\n rounded\n :text=\"!isRecording\"\n :severity=\"isRecording ? undefined : 'secondary'\"\n :aria-label=\"icon === 'PhCamera' ? t('actions.recordVideo') : t('actions.recordVoice')\"\n :disabled=\"disabled\"\n class=\"touch-none\"\n @pointerdown=\"emit('pointerdown', $event)\"\n @click=\"emit('toggleType')\"\n >\n <template #icon>\n <BIcon\n :icon=\"icon\"\n :weight=\"isRecording ? 'fill' : 'regular'\"\n class=\"size-6\"\n />\n </template>\n </Button>\n </div>\n</template>\n","import { onMounted, watch, type Ref } from \"vue\";\nimport { useChatStore } from \"~/stores/chatStore\";\nimport { useMessagesStore } from \"~/stores/messageStores\";\n\ninterface DraftEditor {\n messageText: Ref<string>;\n setText: (text: string) => void;\n}\n\n/**\n * Keeps the input's unsent text per conversation: saved as it is typed, swapped when the open\n * conversation changes, and restored on mount. Text typed while editing a message is not a draft.\n */\nexport function useInputDraft(editor: DraftEditor, isEditing: () => boolean) {\n const chatStore = useChatStore();\n const messagesStore = useMessagesStore();\n\n /** Puts the open conversation's draft (or nothing) back into the input. */\n const restoreDraft = () => {\n const id = chatStore.activeConversationId;\n editor.setText((id && messagesStore.drafts[id]) || \"\");\n };\n\n watch(editor.messageText, (text) => {\n const id = chatStore.activeConversationId;\n if (id && !isEditing()) messagesStore.setDraft(id, text);\n });\n\n watch(\n () => chatStore.activeConversationId,\n () => {\n // An edit belongs to the conversation it started in.\n if (isEditing()) messagesStore.clearActions();\n restoreDraft();\n },\n );\n\n onMounted(() => {\n const id = chatStore.activeConversationId;\n if (id && messagesStore.drafts[id]) restoreDraft();\n });\n\n return { restoreDraft };\n}\n","<template>\n <div dir=\"rtl\" class=\"vue-chat w-full relative\">\n <VideoRecordDisplay\n ref=\"videoDisplay\"\n :stream=\"mediaStream\"\n :is-paused=\"isPaused\"\n :recording-time=\"currentRecordingSeconds\"\n @flip-camera=\"handleFlipCamera\"\n />\n <InputActionBar\n :mode=\"textMode\"\n :name=\"displayActionName\"\n :text=\"displayedActionText ?? ''\"\n @cancel=\"cancelAction\"\n />\n <div\n @contextmenu.prevent\n ref=\"rootElements\"\n class=\"px-4 transition-all duration-200 ease-in-out min-h-19 py-4 w-full bg-surface flex items-end border-t border-t-outline-variant gap-x-5 relative z-40 overflow-visible select-none\"\n >\n <RecordButton\n :is-recording=\"isRecording\"\n :is-locked=\"isLocked\"\n :is-paused=\"isPaused\"\n :has-text=\"editor.messageText.value.trim().length > 0\"\n :icon=\"secondaryMessageIcon\"\n :disabled=\"inputDisabled\"\n :lock-opacity=\"lockOpacity\"\n :drag-offset=\"dragOffset\"\n :is-dragging=\"isDragging\"\n @pointerdown=\"handlePointerDown\"\n @toggle-type=\"toggleSecondaryMessageType\"\n @toggle-pause=\"togglePause\"\n @send=\"handleSend\"\n />\n\n <div v-show=\"!isRecording\" class=\"flex-1 flex items-end gap-x-5\">\n <div class=\"min-h-11 flex items-center w-full\">\n <div\n ref=\"input\"\n data-testid=\"chat-input\"\n contenteditable=\"true\"\n @keydown.enter.exact.prevent=\"handleEnterKey\"\n @input=\"editor.handleContentInput\"\n @focus=\"onInputFocus\"\n @blur=\"editor.saveCursorPosition\"\n @keyup=\"editor.saveCursorPosition\"\n @mouseup=\"editor.saveCursorPosition\"\n :data-placeholder=\"inputPlaceholder\"\n class=\"text-body-md text-on-surface outline-none flex-1 bg-transparent z-10 max-h-[144px] overflow-y-auto hide-scrollbar leading-6 py-1 cursor-text whitespace-pre-wrap break-words empty:before:content-[attr(data-placeholder)] empty:before:text-chat-muted pointer-events-auto\"\n ></div>\n </div>\n <div class=\"z-10 flex h-11 shrink-0 items-center gap-x-2\">\n <!-- A popover on wide screens; on phones the picker opens under the input instead. -->\n <IconButton\n icon=\"PhSmiley\"\n icon-class=\"size-6\"\n :label=\"t('actions.emoji')\"\n :disabled=\"inputDisabled\"\n data-testid=\"chat-emoji\"\n class=\"hidden! md:inline-flex!\"\n @mousedown.prevent\n @click=\"openEmojiPopover\"\n />\n <Popover ref=\"emojiPopover\" class=\"vue-chat\">\n <BEmojiPicker v-if=\"emojiUsed\" @select=\"handleEmojiSelect\" />\n </Popover>\n <IconButton\n icon=\"PhSmiley\"\n icon-class=\"size-6\"\n :label=\"t('actions.emoji')\"\n :disabled=\"inputDisabled\"\n class=\"md:hidden!\"\n @mousedown.prevent\n @click=\"toggleMobileEmoji\"\n />\n <InputAttachement\n :initial-caption=\"editor.messageText.value\"\n @send-attachments=\"handleAttachments\"\n />\n </div>\n </div>\n\n <RecordingStatus\n v-show=\"isRecording\"\n :locked=\"isLocked\"\n :cancel-opacity=\"cancelOpacity\"\n :time=\"formattedTime\"\n @cancel=\"cancelRecording\"\n />\n </div>\n <div\n class=\"md:hidden w-full transition-all relative z-30 duration-300 ease-[cubic-bezier(0.33,1,0.68,1)] overflow-hidden\"\n :class=\"\n showMobileEmojiPicker ? 'max-h-60 opacity-100' : 'max-h-0 opacity-0'\n \"\n >\n <BEmojiPicker v-if=\"emojiUsed\" @select=\"handleEmojiSelect\" />\n </div>\n </div>\n</template>\n<script setup lang=\"ts\">\nimport {\n ref,\n computed,\n nextTick,\n watch,\n onMounted,\n onUnmounted,\n useTemplateRef,\n} from \"vue\";\nimport Popover from \"primevue/popover\";\nimport IconButton from \"~/components/general/IconButton.vue\";\nimport type { ExtendedMessage, Message } from \"~/types\";\nimport InputAttachement from \"./chat-input/InputAttachement.vue\";\nimport {\n useAppPermissions,\n type PopupState,\n} from \"~/composables/useAppPermissions\";\nimport { useChatRecording } from \"~/composables/chat/useChatRecording\";\nimport VideoRecordDisplay from \"./chat-input/VideoRecordDisplay.vue\";\nimport { useRichTextEditor } from \"~/composables/useRichTextEditor\";\nimport { useMessagesStore } from \"~/stores/messageStores.js\";\nimport { useProfileStore } from \"~/stores/profileStore.js\";\nimport InputActionBar from \"./chat-input/InputActionBar.vue\";\nimport RecordingStatus from \"./chat-input/RecordingStatus.vue\";\nimport RecordButton from \"./chat-input/RecordButton.vue\";\nimport { useInputDraft } from \"~/composables/chat/useInputDraft\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { useChatStore } from \"~/stores/chatStore.js\";\nimport { useCallStore } from \"~/stores/callStore.js\";\nimport { type EmojiExt } from \"vue3-emoji-picker\";\nimport { chat, chatInput } from \"@i18n/locales\";\n\nconst props = withDefaults(\n defineProps<{\n isActive?: boolean;\n }>(),\n { isActive: false },\n);\n\nconst emit = defineEmits<{\n send: [];\n edit: [];\n}>();\n\nconst { t } = useLocalI18n(chatInput, chat);\nconst { requestWithPopup, checkMediaStatus } = useAppPermissions();\nconst messagesStore = useMessagesStore();\nconst chatStore = useChatStore();\nconst callStore = useCallStore();\n\nconst profileStore = useProfileStore();\nconst currentUserId = computed(() => profileStore.userId);\n\n// Template Refs (Properly typed, no 'any')\nconst rootElementsRef = useTemplateRef<HTMLElement>(\"rootElements\");\nconst inputRef = useTemplateRef<HTMLDivElement>(\"input\");\nconst emojiPopoverRef = useTemplateRef<InstanceType<typeof Popover>>(\"emojiPopover\");\nconst videoDisplayRef =\n useTemplateRef<InstanceType<typeof VideoRecordDisplay>>(\"videoDisplay\");\n\n// Local State\nconst showMobileEmojiPicker = ref(false);\n/** The pickers mount on first use: they are heavy, and most messages have no emoji. */\nconst emojiUsed = ref(false);\nconst textMode = ref<\"normal\" | \"edit\" | \"reply\">(\"normal\");\nconst editingMessageData = ref<ExtendedMessage | null>(null);\nconst replyingToMessageData = ref<ExtendedMessage | null>(null);\nconst secondaryMessageType = ref<\"video\" | \"voice\">(\"voice\");\n\n// Composables\nconst editor = useRichTextEditor(inputRef);\nconst { restoreDraft } = useInputDraft(editor, () => textMode.value === \"edit\");\nconst inputWidth = computed(() => rootElementsRef.value?.clientWidth || 0);\n\n// --- Computed UI States ---\nconst inputDisabled = computed(() => !props.isActive);\nconst inputPlaceholder = computed(() =>\n props.isActive ? t(\"placeholder\") : t(\"chatLocked\"),\n);\n\nconst secondaryMessageIcon = computed(() =>\n secondaryMessageType.value === \"voice\" ? \"PhMicrophone\" : \"PhCamera\",\n);\n\n// Replaces messy inline template logic\nconst showSecondaryAction = computed(\n () =>\n !isRecording.value &&\n !isLocked.value &&\n editor.messageText.value.trim().length === 0,\n);\nconst showSendButton = computed(() => !showSecondaryAction.value);\n\nconst displayedActionText = computed(() => {\n const message =\n textMode.value === \"edit\"\n ? editingMessageData.value\n : replyingToMessageData.value;\n if (!message) return \"\";\n // Fixed typos: attachementTypes -> attachmentTypes\n if (message.voiceUrl?.trim()) return t(\"attachmentTypes.voice\");\n if (message.videoUrl?.trim()) return t(\"attachmentTypes.video\");\n if (message.imageUrl?.length) return t(\"attachmentTypes.image\");\n if (message.fileUrl?.trim()) return t(\"attachmentTypes.file\");\n return message.text;\n});\n\nconst displayActionName = computed(() => {\n if (textMode.value === \"edit\") return t(\"you\");\n if (replyingToMessageData.value?.senderId === currentUserId.value)\n return t(\"you\");\n return replyingToMessageData.value?.contact?.name || \"\";\n});\n\n// --- Recording Composable ---\nconst recording = useChatRecording(inputWidth, {\n onStart: () => {\n if (secondaryMessageType.value === \"video\") videoDisplayRef.value?.open();\n },\n onCancel: () => {\n if (secondaryMessageType.value === \"video\") videoDisplayRef.value?.close();\n },\n onSend: (mediaUrl?: string) => {\n const finalUrl = mediaUrl || \"placeholder\";\n const msg = createBaseMessage();\n console.log(msg);\n msg.type = secondaryMessageType.value as Message[\"type\"];\n if (msg.type === \"voice\") msg.voiceUrl = finalUrl;\n if (msg.type === \"video\") msg.videoUrl = finalUrl;\n\n messagesStore.sendMessage([msg]);\n messagesStore.clearActions();\n if (secondaryMessageType.value === \"video\") videoDisplayRef.value?.close();\n },\n requestPermission: async () => await ensurePermissions(),\n getMode: () => secondaryMessageType.value,\n});\n\nconst {\n isRecording,\n isLocked,\n isPaused,\n dragOffset,\n isDragging,\n formattedTime,\n isLongPress,\n onPointerDown: onRecordPointerDown,\n stopRecording,\n mediaStream,\n lockOpacity,\n cancelOpacity,\n togglePause,\n} = recording;\n\nconst currentRecordingSeconds = computed(() => {\n if (!formattedTime.value) return 0;\n const [minutes, seconds] = formattedTime.value.split(\":\").map(Number);\n return (minutes || 0) * 60 + (seconds || 0);\n});\n\nwatch(currentRecordingSeconds, (sec) => {\n if (sec >= 60 && isRecording.value) stopRecording(true);\n});\n\n// --- Permissions ---\nconst ensurePermissions = async () => {\n const isVideo = secondaryMessageType.value === \"video\";\n const currentStatus = await checkMediaStatus();\n const status = isVideo ? currentStatus.cam : currentStatus.mic;\n\n if (status === \"granted\") return true;\n\n const state: PopupState = isVideo\n ? status === \"denied\"\n ? \"cam-error\"\n : \"cam-permission\"\n : status === \"denied\"\n ? \"mic-error\"\n : \"mic-permission\";\n\n return await requestWithPopup(state);\n};\n\n// --- Message Handling ---\nconst createBaseMessage = (): Message =>\n ({\n id: String(Date.now() + Math.floor(Math.random() * 1000)),\n conversationId: chatStore.activeConversationId ?? \"\",\n date: new Date(),\n type: \"text\",\n isEdited: false,\n senderId: currentUserId.value,\n isSent: false,\n isRead: false,\n repliedTo: messagesStore.replyingTo || undefined,\n }) as Message;\n\nconst handleAttachments = (payloads: Message[]) => {\n const newMessages = payloads.map((payload) => {\n const msg = createBaseMessage();\n msg.type = payload.type;\n if (payload.type === \"text\") msg.text = payload.text;\n if (payload.type === \"image\") msg.imageUrl = payload.imageUrl;\n if (payload.type === \"file\") {\n msg.fileUrl = payload.fileUrl;\n msg.fileName = payload.fileName;\n }\n if (payload.type === \"voice\") msg.voiceUrl = payload.voiceUrl;\n if (payload.type === \"video\") msg.videoUrl = payload.videoUrl;\n return msg;\n });\n\n messagesStore.sendMessage(newMessages);\n editor.clearInput();\n messagesStore.clearActions();\n};\n\nconst sendMessage = () => {\n if (editor.messageText.value.trim().length === 0) return;\n\n if (textMode.value === \"edit\" && editingMessageData.value) {\n // Clears `editingMessage`; its watcher leaves edit mode and restores the draft.\n messagesStore.saveEditMessage(\n editingMessageData.value.id,\n editor.messageText.value,\n );\n return;\n } else {\n const msg = createBaseMessage();\n msg.type = \"text\";\n msg.text = editor.messageText.value;\n messagesStore.sendMessage([msg]);\n }\n\n editor.clearInput();\n textMode.value = \"normal\";\n messagesStore.clearActions();\n};\n\nconst cancelAction = () => messagesStore.clearActions();\n\nconst handleEditMessage = (msg: ExtendedMessage) => {\n textMode.value = \"edit\";\n editingMessageData.value = msg;\n editor.setText(msg.text || \"\");\n nextTick(() => inputRef.value?.focus());\n};\n\n// --- Watchers ---\n// The store sets `editingMessage` from the bubble menu; enter edit mode from it, and leave it\n// (restoring the draft the edit displaced) when the edit is saved or cancelled.\nwatch(\n () => messagesStore.editingMessage,\n (msg) => {\n if (msg) {\n handleEditMessage(msg);\n } else if (textMode.value === \"edit\") {\n textMode.value = \"normal\";\n editingMessageData.value = null;\n restoreDraft();\n }\n },\n);\n\nwatch(\n () => messagesStore.replyingTo,\n (msg) => {\n if (msg) {\n textMode.value = \"reply\";\n replyingToMessageData.value = msg;\n nextTick(() => inputRef.value?.focus());\n } else if (textMode.value === \"reply\") {\n textMode.value = \"normal\";\n replyingToMessageData.value = null;\n }\n },\n);\n\n// --- Input Interactions ---\nconst onInputFocus = () => {\n if (editor.isSelectingEmoji.value) return;\n showMobileEmojiPicker.value = false;\n};\n\nconst handlePointerDown = (event: PointerEvent) => {\n if (editor.messageText.value.trim().length > 0) {\n sendMessage();\n return;\n }\n emojiPopoverRef.value?.hide();\n recording.onPointerDown(event);\n\n // NOTE: The 300ms setTimeout has been completely removed from here.\n // The @click event now handles the toggle safely!\n};\n\nconst handleEnterKey = (e: KeyboardEvent) => {\n if (e.shiftKey) return;\n e.preventDefault();\n sendMessage();\n};\n\nconst openEmojiPopover = (event: MouseEvent) => {\n emojiUsed.value = true;\n emojiPopoverRef.value?.toggle(event);\n};\n\nconst toggleMobileEmoji = () => {\n emojiUsed.value = true;\n showMobileEmojiPicker.value = !showMobileEmojiPicker.value;\n if (showMobileEmojiPicker.value) {\n editor.saveCursorPosition();\n inputRef.value?.blur();\n }\n};\n\nconst handleEmojiSelect = (emoji: EmojiExt) => {\n editor.handleEmojiSelect(emoji.i, showMobileEmojiPicker.value);\n};\n\n// Cleaned up pointer/click handlers\nconst handleActionPointerDown = (e: PointerEvent) => {\n if (showSecondaryAction.value) onRecordPointerDown(e);\n};\n\nconst handleActionClick = () => {\n if (showSecondaryAction.value) toggleSecondaryMessageType();\n};\n\nconst toggleSecondaryMessageType = () => {\n if (!isLongPress.value && !isRecording.value) {\n secondaryMessageType.value =\n secondaryMessageType.value === \"voice\" ? \"video\" : \"voice\";\n }\n};\n\nconst handleFlipCamera = () => {\n if (typeof recording.toggleCamera === \"function\") recording.toggleCamera();\n};\n\n// The send button sends the typed text, or a recording once it has been locked.\nconst handleSend = () => (isLocked.value ? stopRecording(true) : sendMessage());\nconst cancelRecording = () => stopRecording(false);\n\n// --- Global Keys ---\n// PrimeVue closes its own overlays on Escape, in listeners that run before this one on `window`\n// while the overlay is still in the DOM. When one is open, Escape is for it alone: it must not\n// also cancel a reply or close the conversation behind it.\nconst OVERLAYS =\n \".p-menu-overlay, .p-contextmenu, .p-popover, .p-dialog-mask, .p-drawer-mask, .p-galleria-mask\";\n\nconst handleGlobalKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n if (event.defaultPrevented || document.querySelector(OVERLAYS)) return;\n if (textMode.value !== \"normal\" || messagesStore.selectedArray.length > 0) {\n cancelAction();\n } else {\n const isCallMode = callStore.isActive;\n const isProfileView = chatStore.profileViewOpen;\n\n if (isCallMode) callStore.minimize();\n else if (isProfileView) chatStore.closeProfile();\n else chatStore.setSelectedChat(null);\n }\n }\n};\n\nonMounted(() => window.addEventListener(\"keydown\", handleGlobalKeyDown));\nonUnmounted(() => window.removeEventListener(\"keydown\", handleGlobalKeyDown));\n\ndefineExpose({ focus: () => inputRef.value?.focus() });\n</script>\n","<template>\n <div class=\"vue-chat h-full w-full bg-chat-surface\">\n <div class=\"flex h-full w-full\">\n <ChatProfileOverview :profile=\"selectedChat\" />\n\n <!-- On phones the open profile takes the whole screen. -->\n <div\n v-show=\"chatId\"\n class=\"h-full flex-1 flex-col items-center justify-between\"\n :class=\"isProfile ? 'hidden md:flex' : 'flex'\"\n >\n <div class=\"h-16 w-full bg-chat-background md:h-20\">\n <ChatPageBar\n :contact=\"selectedChat\"\n :options=\"medicOptions\"\n @open-profile=\"openProfile\"\n @select=\"handleOption\"\n >\n <template v-if=\"$slots['header-actions']\" #actions=\"{ contact }\">\n <slot name=\"header-actions\" :contact=\"contact\" />\n </template>\n </ChatPageBar>\n </div>\n <!-- Host content between the header and the messages, e.g. a toolbar for this chat. -->\n <div v-if=\"$slots['conversation-top']\" class=\"w-full\">\n <slot\n name=\"conversation-top\"\n :conversation-id=\"chatId\"\n :contact=\"selectedChat\"\n />\n </div>\n <div class=\"min-h-0 w-full flex-1 overflow-hidden\">\n <!-- Renders nothing without a contact, so no v-show: it can't apply to an empty root. -->\n <ChatMessages :contact=\"selectedChat\" />\n <!-- The open conversation's contact is still being fetched (e.g. a deep link). -->\n <div v-if=\"isResolving\" class=\"flex h-full w-full items-end\">\n <MessagesSkeleton />\n </div>\n </div>\n <slot\n v-if=\"selectedChat?.isActive\"\n name=\"above-input\"\n :conversation-id=\"chatId\"\n :contact=\"selectedChat\"\n />\n <ChatInput\n v-if=\"selectedChat?.isActive\"\n ref=\"chatInput\"\n :is-active=\"true\"\n />\n <!-- In place of the input, so the thread keeps its full height. -->\n <div\n v-else-if=\"selectedChat\"\n class=\"flex w-full items-center justify-center gap-x-2 border-t border-t-chat-outline-variant bg-chat-background px-5 py-4 text-body-md text-chat-on-background/60\"\n >\n <BIcon icon=\"PhLockKey\" class=\"size-5 shrink-0\" />\n <span>{{ t(\"chatEnded\") }}</span>\n </div>\n </div>\n\n <div\n v-show=\"!chatId\"\n class=\"flex h-full w-full items-center justify-center\"\n />\n </div>\n\n <PermissionPopup />\n <ConfirmModal ref=\"modal\" :loading=\"ending\" @action=\"endConversation\" />\n <Toast :group=\"TOAST_GROUP\" position=\"bottom-center\" class=\"vue-chat\" />\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, nextTick, watch } from \"vue\";\nimport Toast from \"primevue/toast\";\nimport PermissionPopup from \"~/components/chat/chat-input/PermissionPopup.vue\";\nimport ChatProfileOverview from \"~/components/chat/ChatProfileOverview.vue\";\nimport type { ChatTextField } from \"~/types/components/chat-input\";\nimport type { MenuOption } from \"~/types/components/menu-options\";\nimport ChatMessages from \"~/components/chat/ChatMessages.vue\";\nimport MessagesSkeleton from \"~/components/chat/messages/MessagesSkeleton.vue\";\nimport ChatPageBar from \"~/components/chat/ChatPageBar.vue\";\nimport ChatInput from \"~/components/chat/ChatInput.vue\";\nimport ConfirmModal from \"~/components/general/ConfirmModal.vue\";\nimport type { Modal } from \"~/types/components/modal\";\nimport { TOAST_GROUP } from \"~/composables/useAppToast\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { useChatStore } from \"~/stores/chatStore\";\nimport { chatView } from \"@i18n/locales\";\n\nconst chatStore = useChatStore();\nconst { t } = useLocalI18n(chatView);\n// Template Refs\nconst chatInput = ref<ChatTextField | null>(null);\n\nconst chatId = computed(() => chatStore.activeConversationId);\nconst isProfile = computed(() => chatStore.profileViewOpen);\n\nconst selectedChat = computed(() => {\n if (!chatId.value) return null;\n return chatStore.getContactById(chatId.value);\n});\n\n// Until the contact arrives the pane would otherwise read as an ended chat.\nconst isResolving = computed(() => !!chatId.value && !selectedChat.value);\n\nconst medicOptions = computed<MenuOption[]>(() =>\n chatStore.canEndConversation && selectedChat.value?.isActive\n ? [\n {\n label: t(\"barOptions.endChat\"),\n icon: \"PhXSquare\",\n key: \"end-chat\",\n color: \"error\",\n },\n ]\n : [],\n);\n\nconst modal = ref<Modal | null>(null);\nconst ending = ref(false);\n\nconst handleOption = (key: string) => {\n if (key !== \"end-chat\" || !chatId.value) return;\n modal.value?.openModal(\n t(\"endChat.title\"),\n t(\"endChat.message\"),\n \"error\",\n true,\n t(\"endChat.confirm\"),\n );\n};\n\nconst endConversation = () => {\n // Stay open with the button spinning until the server answers; the host reports failures.\n if (ending.value || !chatId.value) return;\n ending.value = true;\n chatStore\n .endConversation(chatId.value)\n .catch(() => {})\n .finally(() => {\n ending.value = false;\n modal.value?.closeModal();\n });\n};\n\nconst openProfile = () => {\n chatStore.openProfile();\n};\n\nwatch(\n () => chatStore.activeConversationId,\n () => {\n if (chatId.value && selectedChat.value?.isActive) {\n nextTick(() => {\n chatInput.value?.focus();\n });\n }\n },\n);\n</script>\n","<script setup lang=\"ts\">\nimport NoChatSelected from \"../assets/lib-images/chat/empty-state.webp\";\nimport NoDataDisplay from \"./general/NoDataDisplay.vue\";\nimport useLocalI18n from \"~/composables/useLocalI18n\";\nimport { useChatStore } from \"../stores/chatStore\";\nimport ChatList from \"./chat/contact/ChatList.vue\";\nimport { useCallStore } from \"~/stores/callStore\";\nimport ChatView from \"./chat/ChatView.vue\";\nimport { chatPage } from \"@i18n/locales\";\nimport { computed, defineAsyncComponent, useSlots } from \"vue\";\n\n// Loaded with the first call, not with the chat.\nconst Call = defineAsyncComponent(() => import(\"./call/Call.vue\"));\nimport type { Contact } from \"~/types\";\n\nconst props = withDefaults(\n defineProps<{\n /**\n * Render the call view here. Set to false and mount `<Call />` once near the app root to\n * keep the call on screen while the user navigates away from the chat.\n */\n renderCall?: boolean;\n }>(),\n { renderCall: true },\n);\n\ndefineSlots<{\n /** Replaces the \"no conversation selected\" placeholder. */\n empty?: () => unknown;\n /** Extra actions in the conversation header, beside the call button. */\n \"header-actions\"?: (props: { contact: Contact | null }) => unknown;\n /** Between the header and the messages. */\n \"conversation-top\"?: (props: {\n conversationId: string | null;\n contact: Contact | null;\n }) => unknown;\n /** Above the input, only while the conversation is active. */\n \"above-input\"?: (props: {\n conversationId: string | null;\n contact: Contact | null;\n }) => unknown;\n}>();\n\nconst slots = useSlots();\n\nconst chatStore = useChatStore();\nconst callStore = useCallStore();\nconst { t } = useLocalI18n(chatPage);\n\nconst isInChat = computed(() => chatStore.activeConversationId !== null);\n</script>\n<template>\n <div\n class=\"vue-chat flex w-full h-full max-h-full overflow-hidden font-chat-family text-chat-base text-chat-on-background bg-chat-background\"\n >\n <!-- On phones only one pane shows: the list, or the open conversation. -->\n <div\n class=\"relative h-full flex-1\"\n :class=\"isInChat ? 'block' : 'hidden md:block'\"\n >\n <!-- Each is forwarded only when filled, so ChatView's `$slots[...]` checks stay accurate. -->\n <ChatView v-if=\"isInChat\">\n <template v-if=\"slots['header-actions']\" #header-actions=\"scope\">\n <slot name=\"header-actions\" v-bind=\"scope\" />\n </template>\n <template v-if=\"slots['conversation-top']\" #conversation-top=\"scope\">\n <slot name=\"conversation-top\" v-bind=\"scope\" />\n </template>\n <template v-if=\"slots['above-input']\" #above-input=\"scope\">\n <slot name=\"above-input\" v-bind=\"scope\" />\n </template>\n </ChatView>\n <div v-else class=\"w-full h-full flex items-center justify-center\">\n <slot name=\"empty\">\n <NoDataDisplay\n :image-path=\"NoChatSelected\"\n :title=\"t('noConversationSelected')\"\n />\n </slot>\n </div>\n </div>\n\n <div\n class=\"h-full w-full shrink-0 border-l border-chat-outline-variant md:w-80\"\n :class=\"isInChat ? 'hidden md:block' : 'block'\"\n >\n <ChatList />\n </div>\n </div>\n <Call v-if=\"props.renderCall && callStore.session\" />\n</template>\n","/**\n * A WebRTC signalling payload: an SDP offer/answer, an ICE candidate, or a request for the\n * initiator to renegotiate. The same shape simple-peer uses, so clients on the previous,\n * simple-peer based build still interoperate.\n */\nexport interface SignalData {\n type?: \"transceiverRequest\" | \"renegotiate\" | \"candidate\" | RTCSdpType;\n sdp?: string;\n candidate?: RTCIceCandidateInit;\n renegotiate?: boolean;\n transceiverRequest?: { kind: string; init?: RTCRtpTransceiverInit };\n}\n\nexport type ThemeMode = \"light\" | \"dark\";\n\nexport interface CallMember extends Contact {\n stream: MediaStream | null;\n isScreenSharing: boolean;\n isCameraOn: boolean;\n isSpeaking: boolean;\n isMuted: boolean;\n}\n\nexport type status = \"pending\" | \"approved\" | \"rejected\" | \"expired\";\nexport type ServicePresence = \"online\" | \"on-site\";\nexport type UserRoleKey = \"user\" | \"employee\" | \"business\" | \"support\";\nexport type StateKeys = \"\" | \"online\" | \"ended\" | \"active\";\nexport type MessageType = \"text\" | \"image\" | \"file\" | \"voice\" | \"video\";\nexport interface Message {\n id: string;\n conversationId: string;\n date: Date;\n type: MessageType;\n text?: string;\n imageUrl?: string[];\n fileUrl?: string;\n fileName?: string;\n voiceUrl?: string;\n videoUrl?: string;\n isEdited: boolean;\n senderId: string;\n isSent: boolean;\n /** Set when the last send attempt failed, so the bubble can offer a retry. */\n isFailed?: boolean;\n isRead: boolean;\n repliedTo?: Message;\n request?: string;\n}\n\nexport interface Contact {\n id: string;\n name: string;\n lastName: string;\n isOnline: boolean;\n /** Omit when unknown; the header then hides the \"last seen\" line. */\n lastSeen?: Date;\n imageUrl: string;\n nationalCode?: string;\n phoneNumber?: string;\n isActive: boolean;\n birthDate: Date;\n lastMessage?: Message;\n unreadCount?: number;\n serviceType?: \"video-call\" | \"voice-call\" | \"chat\";\n userType: UserRoleKey[];\n}\n\nexport interface ChatFilter {\n key: StateKeys;\n label: string;\n}\n\nexport interface ExtendedMessage extends Message {\n prevMessage?: Message;\n nextMessage?: Message;\n isFirstInDate: boolean;\n contact?: Contact;\n}\n\nexport interface ChatProvider {\n fetchContacts: () => Promise<Contact[]>;\n}\n\nexport type CallKind = \"voice-call\" | \"video-call\";\n\nexport type CallMessage =\n | {\n type: \"signal\";\n payload: {\n signal: SignalData & { sdp: string };\n from: string;\n to: string;\n name: string;\n };\n }\n | { type: \"join\"; payload: { from: string; name: string } }\n | {\n type: \"track_type\";\n payload: { from: string; types: { id: string; type: TrackType }[] };\n }\n | {\n type: \"call\";\n payload: {\n from: string;\n name: string;\n channel: string;\n avatar?: string;\n };\n }\n | {\n type: \"hangup\";\n payload: { from: string; channel: string; name?: string };\n };\n\nexport interface TurnConfig {\n urls: string[];\n username?: string;\n credential?: string;\n iceTransportPolicy?: \"relay\" | \"all\";\n}\n\nexport interface CallPublishOptions {\n retain?: boolean;\n}\n\nexport type Credential = {\n ttl: number;\n user: string;\n pass: string;\n urls: string[];\n};\n\nexport interface CallHandlers {\n credential: Credential;\n handleGenerateCred: () => Promise<void>;\n publisher: (json: string) => Promise<void>;\n subscriber: (\n callback: (message: CallMessageSchema) => Promise<void>,\n ) => Promise<number>;\n unSubscriber: (id: number) => Promise<void>;\n /**\n * \"relay\" (the default) sends media only through the TURN servers in `credential`. \"all\" also\n * allows direct connections, and works without TURN servers (e.g. on a LAN or in tests).\n */\n iceTransportPolicy?: RTCIceTransportPolicy;\n /** Logs signalling and peer events to the console. */\n debug?: boolean;\n}\n\nexport interface FetchContactsParams {\n page: number;\n pageSize: number;\n state: StateKeys;\n search?: string;\n}\n\nexport interface ContactsPage {\n data: Contact[];\n hasNextPage: boolean;\n}\n\nexport interface ChatHandlers {\n fetchConversations(params: FetchContactsParams): Promise<ContactsPage>;\n deleteConversation(id: string): Promise<void>;\n /** Optional; the \"end conversation\" action is only offered when provided. */\n endConversation?(id: string): Promise<void>;\n}\n\nexport interface MediaDownloadOptions {\n signal?: AbortSignal;\n onProgress?: (percent: number) => void;\n}\n\nexport interface MediaHandlers {\n download(url: string, opts?: MediaDownloadOptions): Promise<Blob>;\n getFileSize(url: string): Promise<number | null>;\n}\n\nexport interface UploadProgressEvent {\n uploaded: number;\n total: number;\n progress: number;\n}\n\nexport interface SendMessageOptions {\n onProgress?: (e: UploadProgressEvent) => void;\n}\n\nexport interface FetchMessagesParams {\n conversationId: string;\n page: number;\n pageSize: number;\n}\n\nexport interface MessagesHandlers {\n sendMessage(msg: Message, opts?: SendMessageOptions): Promise<Message>;\n editMessage(id: string, text: string): Promise<Message>;\n deleteMessages(ids: string[]): Promise<void>;\n fetchMessages(params: FetchMessagesParams): Promise<Message[]>;\n /** Persists that the viewer has read a conversation. Optional; without it read state stays local. */\n markRead?(conversationId: string): Promise<void>;\n}\n\nexport interface FetchProfileAttachmentsParams {\n conversationId: string;\n page: number;\n pageSize: number;\n}\n\nexport interface ProfileAttachmentsPage {\n data: string[];\n hasNextPage: boolean;\n}\n\nexport interface ProfileHandlers {\n fetchMedia(\n params: FetchProfileAttachmentsParams,\n ): Promise<ProfileAttachmentsPage>;\n fetchFiles(\n params: FetchProfileAttachmentsParams,\n ): Promise<ProfileAttachmentsPage>;\n}\n\n// A plain object rather than a `const enum`, which consumers compiling with isolatedModules or\n// erasableSyntaxOnly can't use from a .d.ts.\nexport const CallMessageType = {\n Signal: \"signal\",\n Join: \"join\",\n TrackType: \"track_type\",\n Call: \"call\",\n Hangup: \"hangup\",\n} as const;\nexport type CallMessageType = (typeof CallMessageType)[keyof typeof CallMessageType];\n\nexport type TrackType = \"webcam\" | \"screen\" | \"audio\" | \"webcam_audio\";\n\nexport type CallMessageSchema =\n | {\n type: typeof CallMessageType.Signal;\n payload: {\n signal: SignalData & { sdp: string };\n from: string;\n to: string;\n name: string;\n };\n }\n | {\n type: typeof CallMessageType.Join;\n payload: {\n from: string;\n name: string;\n };\n }\n | {\n type: typeof CallMessageType.TrackType;\n payload: {\n from: string;\n types: { id: string; type: TrackType }[];\n };\n }\n | {\n type: typeof CallMessageType.Call;\n payload: {\n from: string;\n name: string;\n channel: string;\n avatar: string;\n };\n }\n | {\n type: typeof CallMessageType.Hangup;\n payload: {\n from: string;\n channel: string;\n };\n };\n","import type { CallHandlers } from \"../types\";\nimport { useCallStore } from \"../stores/callStore\";\n\n/**\n * Gives the chat its call handlers from inside a component's setup. `createChat({ call })` does\n * the same app-wide; use this when the handlers only exist further down the tree.\n */\nexport function provideCallHandlers(handlers: CallHandlers) {\n useCallStore().setHandlers(handlers);\n}\n","import type { App, Plugin } from \"vue\";\nimport type { Pinia } from \"pinia\";\nimport ToastService from \"primevue/toastservice\";\nimport type {\n CallHandlers,\n ChatHandlers,\n MediaHandlers,\n MessagesHandlers,\n ProfileHandlers,\n} from \"./types\";\nimport { useCallStore } from \"./stores/callStore\";\nimport { useChatStore } from \"./stores/chatStore\";\nimport { useMessagesStore } from \"./stores/messageStores\";\nimport { useMediaStore } from \"./stores/mediaStore\";\nimport { useProfileStore } from \"./stores/profileStore\";\nimport { provideHostI18n } from \"./composables/useHostI18n\";\n\nexport interface ChatUser {\n id: string;\n name: string;\n avatar?: Blob;\n}\n\nexport interface ChatOptions {\n chat: ChatHandlers;\n messages: MessagesHandlers;\n media: MediaHandlers;\n /** Needed for the profile panel's media and files tabs. */\n profile?: ProfileHandlers;\n /** Omit to leave calling out; `provideCallHandlers()` can still supply them later. */\n call?: CallHandlers;\n /** The signed-in user. Can also be set later through `useProfileStore()`. */\n user?: ChatUser;\n}\n\n/**\n * Wires the chat into an app in one call:\n *\n * app.use(createPinia()).use(i18n).use(PrimeVue, { theme }).use(createChat({ chat, messages, media, user }))\n *\n * Pinia, vue-i18n and PrimeVue must be installed first; the stores, translations and UI depend\n * on them.\n */\nexport function createChat(options: ChatOptions): Plugin {\n return {\n install(app: App) {\n const pinia = app.config.globalProperties.$pinia as Pinia | undefined;\n if (!pinia) {\n throw new Error(\n \"[vue-chat] Install Pinia before createChat(): app.use(createPinia()).use(createChat(...))\",\n );\n }\n if (!app.config.globalProperties.$i18n) {\n throw new Error(\n \"[vue-chat] Install vue-i18n (legacy: false) before createChat()\",\n );\n }\n // The UI is built from PrimeVue components, themed by the host's own preset.\n if (!app.config.globalProperties.$primevue) {\n throw new Error(\n \"[vue-chat] Install PrimeVue before createChat(): app.use(PrimeVue, { theme }).use(createChat(...))\",\n );\n }\n // The chat's toasts go through PrimeVue's toast service; hosts that use it already keep theirs.\n if (!app.config.globalProperties.$toast) app.use(ToastService);\n\n // Lets stores translate without a component, so they can be created anywhere.\n provideHostI18n(app);\n\n // Configure each store when it first comes to life, whoever creates it.\n pinia.use(({ store }) => {\n switch (store.$id) {\n case useChatStore.$id:\n store.setHandlers(options.chat);\n break;\n case useMessagesStore.$id:\n store.setHandlers(options.messages);\n break;\n case useMediaStore.$id:\n store.setHandlers(options.media);\n break;\n case useCallStore.$id:\n if (options.call) store.setHandlers(options.call);\n break;\n case useProfileStore.$id:\n if (options.profile) store.setHandlers(options.profile);\n if (options.user) {\n store.userId = options.user.id;\n store.userName = options.user.name;\n store.userAvatar = options.user.avatar;\n }\n break;\n }\n });\n\n },\n };\n}\n","import \"./assets/css/main.css\";\nimport { defineAsyncComponent } from \"vue\";\nimport { useCallStore } from \"./stores/callStore\";\nimport { useChatStore } from \"./stores/chatStore\";\nimport { useMessagesStore } from \"./stores/messageStores\";\nimport { useMediaStore } from \"./stores/mediaStore\";\nimport { useProfileStore } from \"./stores/profileStore\";\n\nexport { default as ChatPage } from \"./components/ChatPage.vue\";\n// Async, so hosts that never call don't download it. Render it while `callStore.session` is set.\nexport const Call = defineAsyncComponent(() => import(\"./components/call/Call.vue\"));\n\n// Building blocks, for hosts that compose their own layout instead of <ChatPage />. They read\n// the same stores, so they work together as long as the handlers are registered.\nexport { default as ChatList } from \"./components/chat/contact/ChatList.vue\";\nexport { default as ChatConversation } from \"./components/chat/ChatView.vue\";\nexport { default as ChatHeader } from \"./components/chat/ChatPageBar.vue\";\nexport { default as ChatMessages } from \"./components/chat/ChatMessages.vue\";\nexport { default as ChatInput } from \"./components/chat/ChatInput.vue\";\nexport { default as ChatBubble } from \"./components/chat/ChatBubble.vue\";\n\nexport { default as BVirtualVerticalList } from \"./components/global/BVirtualVerticalList.vue\";\nexport { default as BEmojiPicker } from \"./components/global/BEmojiPicker.vue\";\nexport { default as BIcon } from \"./components/global/BIcon.vue\";\n\nexport * from \"./types\";\nexport * from \"./stores/messageStores\";\nexport * from \"./stores/chatStore\";\nexport * from \"./stores/mediaStore\";\nexport * from \"./stores/profileStore\";\n\nexport { provideCallHandlers } from \"./provider/callProvider\";\nexport { createChat } from \"./plugin\";\nexport type { ChatOptions, ChatUser } from \"./plugin\";\n\nexport {\n useChatStore,\n useCallStore,\n useMessagesStore,\n useMediaStore,\n useProfileStore,\n};\n"],"names":["search","result","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createVNode","_unref","$slots","_hoisted_4","_renderSlot","_createElementVNode","MediaImage","_hoisted_3","_toDisplayString","_normalizeClass","_normalizeStyle","_Fragment","_renderList","_vShow","_createBlock","_resolveDynamicComponent","_mergeProps","draft","_withDirectives","ContactAvatar","_hoisted_5","_createTextVNode","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","SafeEmojiText","_hoisted_12","$attrs","BIcon","_useModel","IconButton","filters","ChatListSearch","ContactSkeleton","_withCtx","ChatContactDisplay","NoDataDisplay","NoData","_normalizeProps","_guardReactiveProps","ResponsiveDialog","_hoisted_13","info","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","file","FileDisplay","title","LoadingStatus","FileFormatDisplay","UploadProgressOverlay","_withModifiers","BubbleDivider","BubbleSelectionMark","BubbleRequest","_toHandlers","ReplyPreview","BubbleMeta","VoiceDisplay","BubbleImages","BubbleVideo","BubbleStatus","ImageGroupDisplay","BubbleOptions","id","options","FloatingDateHeader","ChatBubble","MessagesSkeleton","NoMessages","ScrollToBottomButton","ConfirmModal","caption","AttachementFileDisplay","VideoRecordDisplay","InputActionBar","RecordButton","InputAttachement","RecordingStatus","chatInput","_a","ChatProfileOverview","ChatPageBar","ChatInput","PermissionPopup","Call","ChatView","_createSlots","ChatList"],"mappings":"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"}
|