diff --git a/apps/client/CHANGELOG.md b/apps/client/CHANGELOG.md index 5c95bb4a..31335e63 100644 --- a/apps/client/CHANGELOG.md +++ b/apps/client/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.14.0 + +### Improvements + +- Fixed summary container, updated chat lsit scroll logic + ## 1.13.0 ### Refactor diff --git a/apps/client/package.json b/apps/client/package.json index a398314b..6251c9a2 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,6 +1,6 @@ { "name": "sama", - "version": "1.13.0", + "version": "1.14.0", "homepage": "https://github.com/SAMA-Communications/sama-client#readme", "keywords": [ "react", diff --git a/apps/client/src/hooks/tools/persistedScroll/list.js b/apps/client/src/hooks/tools/persistedScroll/list.js index f903122a..0e5508fc 100644 --- a/apps/client/src/hooks/tools/persistedScroll/list.js +++ b/apps/client/src/hooks/tools/persistedScroll/list.js @@ -13,6 +13,7 @@ const SAVE_DEBOUNCE_MS = 150; const CLAMP_EPS_PX = 2; const EXTRA_FETCH_CAP = 48; const CONTAINER_RAF_TRIES = 40; +const TOP_THRESHOLD_PX = 25; /** * Conversation list scroll persistence. When `active` is false, effects no-op (shared hook entrypoint). @@ -50,7 +51,6 @@ export function useListPersistedScroll(active, p) { const runRestore = useCallback((container, persisted) => { if (!persisted) { - container.scrollTop = 0; pinnedBottomRef.current = false; pendingScrollRef.current = null; anchorRetryRef.current = null; @@ -218,8 +218,12 @@ export function useListPersistedScroll(active, p) { const delta = cont.scrollHeight - prevH; if (prevH > 0 && delta !== 0) { - const maxTop = Math.max(0, cont.scrollHeight - cont.clientHeight); - cont.scrollTop = Math.min(prevTop + delta, maxTop); + if (prevTop <= TOP_THRESHOLD_PX) { + cont.scrollTop = 0; + } else { + const maxTop = Math.max(0, cont.scrollHeight - cont.clientHeight); + cont.scrollTop = Math.min(Math.max(0, prevTop + delta), maxTop); + } } const { pending, pinnedBottom } = buildChatListScrollSavePayload(cont); diff --git a/apps/client/src/services/usersService.js b/apps/client/src/services/usersService.js index 8ce6d35e..0ab86151 100644 --- a/apps/client/src/services/usersService.js +++ b/apps/client/src/services/usersService.js @@ -72,7 +72,7 @@ class UsersService { return await api.userCreate({ login: login.trim().toLowerCase(), - email: login.trim(), + email: email.trim(), password: password.trim(), }); } diff --git a/package-lock.json b/package-lock.json index bd10b868..9b050455 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sama-client", - "version": "1.13.0", + "version": "1.14.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sama-client", - "version": "1.13.0", + "version": "1.14.0", "license": "MIT", "workspaces": [ "apps/client", @@ -19,7 +19,7 @@ }, "apps/client": { "name": "sama", - "version": "1.13.0", + "version": "1.14.0", "license": "Apache-2.0", "dependencies": { "@jitl/quickjs-singlefile-browser-release-sync": "0.31.0", @@ -67,13 +67,6 @@ "lightningcss-linux-x64-gnu": "^1.29.1" } }, - "apps/client/node_modules/@sama-communications/sdk": { - "version": "0.12.1", - "license": "Apache-2.0", - "dependencies": { - "get-browser-fingerprint": "^4.1.0" - } - }, "node_modules/@acemir/cssom": { "version": "0.9.31", "dev": true, @@ -1550,6 +1543,188 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.1.tgz", + "integrity": "sha512-kxz0YeeCrRUHz3zyqvd7n+TVRlNyTifBsmnmNPtk3hQURUyG9eAB+usz6DAwagMusjx/zb3AjvDUvhFGDAexGw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.1.tgz", + "integrity": "sha512-PPkxTOisoNC6TpnDKatjKkjRMsdaWIhyuMkA4UsBXT9WEZY4uHezBTjs6Vl4PbqQQeu6oION1w2voYZv9yquCw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.1.tgz", + "integrity": "sha512-VWXGISWFY18v/0JyNUy4A46KCFCb9NVsH+1100XP31lud+TzlezBbz24CYzbnA4x6w4hx+NYCXDfnvDVO6lcAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.1.tgz", + "integrity": "sha512-BdrLJ2mHTrIYdaS2I99mriyJfGGenSaP+UwGi1kB9BLOCu9SR8ZpbkmmalKIALnRw24kM7qCN0IOm6L0S44iWw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.1.tgz", + "integrity": "sha512-VXeo/puqvCG8JBPNZXZf5Dqq7BzElNJzHRRw3vjBE27WujdzuOPecDPc/+1DcdcTptNBep3861jNq0mYkT8Z6Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.1.tgz", + "integrity": "sha512-ehSKrewwsESPt1TgSE/na9nIhWCosfGSFqv7vwEtjyAqZcvbGIg4JAcV7ZEh2tfj/IlfBeZjgOXm35iOOjadcg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.1.tgz", + "integrity": "sha512-m39iO/aaurh5FVIu/F4/Zsl8xppd76S4qoID8E+dSRQvTyZTOI2gVk3T4oqzfq1PtcvOfAVlwLMK3KRQMaR8lg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.1.tgz", + "integrity": "sha512-Y+GHnGaku4aVLSgrT0uWe2o2Rq8te9hi+MwqGF9r9ORgXhmHK5Q71N757u0F8yU1OIwUIFy6YiJtKjtyktk5hg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.1.tgz", + "integrity": "sha512-jEwjn3jCA+tQGswK3aEWcD09/7M5wGwc6+flhva7dsQNRZZTe30vkalgIzV4tjkopsTS9Jd7Y1Bsj6a4lzz8gQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.1.tgz", + "integrity": "sha512-ySyWikVhNzv+BV/IDCsrraOAZ3UaC8SZB67FZlqVwXwnFhPihOso9rPOxzZbjp81suB1O2Topw+6Ug3JNegejQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.1.tgz", + "integrity": "sha512-BvvA64QxZlh7WZWqDPPdt0GH4bznuL6uOO1pmgPnnv86rpUpc8ZxgZwcEgXvo02GRIZX1hQ0j0pAnhwkhwPqWg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.1.tgz", + "integrity": "sha512-EQSP+8+1VuSulm9RKSMKitTav89fKbHymTf25n5+Yr6gAPZxYWpj3DzAsQqoaHAk9YX2lwEyAf9S4W8F4l3VBQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.1.tgz", + "integrity": "sha512-n/vQ4xRZXKuIpqukkMXZt9RWdl+2zgGNx7Uda8NtmLJ06NL8jiHxUawbwC+hdSq1rrw/9CghCpEONor+l1e2gA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.1.tgz", + "integrity": "sha512-h8d28xzYb98fMQKUz0w2fMc1XuGzLLjdyxVIbhbil4ELfk5/orZlSTpF/xdI9C8K0I8lCkq+1En2RJsawZekkg==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.40.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz", @@ -1563,6 +1738,45 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.1.tgz", + "integrity": "sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.1.tgz", + "integrity": "sha512-b2bcNm9Kbde03H+q+Jjw9tSfhYkzrDUf2d5MAd1bOJuVplXvFhWz7tRtWvD8/ORZi7qSCy0idW6tf2HgxSXQSg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.1.tgz", + "integrity": "sha512-DfcogW8N7Zg7llVEfpqWMZcaErKfsj9VvmfSyRjCyo4BI3wPEfrzTtJkZG6gKP/Z92wFm6rz2aDO7/JfiR/whA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.40.1", "cpu": [ @@ -4833,6 +5047,20 @@ "node": ">=14.14" } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "dev": true, @@ -7549,6 +7777,19 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.40.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.1.tgz", + "integrity": "sha512-nIwkXafAI1/QCS7pxSpv/ZtFW6TXcNUEHAIA9EIyw5OzxJZQ1YDrX+CL6JAIQgZ33CInl1R6mHet9Y/UZTg2Bw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, "node_modules/safe-array-concat": { "version": "1.1.3", "dev": true, @@ -9014,7 +9255,7 @@ }, "packages/sdk": { "name": "@sama-communications/sdk", - "version": "0.17.0", + "version": "0.17.1", "license": "Apache-2.0", "dependencies": { "ws": "8.18.3" diff --git a/package.json b/package.json index e02f87bd..c9c2c451 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sama-client", - "version": "1.13.0", + "version": "1.14.0", "private": true, "description": "SAMA monorepo: web client, SDK, UI kit", "license": "MIT", diff --git a/packages/sdk/CHANGELOG.md b/packages/sdk/CHANGELOG.md index 86dbd80b..bbe025e1 100644 --- a/packages/sdk/CHANGELOG.md +++ b/packages/sdk/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.17.1 + +- Added `Config` interface +- Added `disableAutoReconnect` option in config +- `connect` method can receive 2 arguments (`wsEndpoint`, `httpEndpoint`) + ## 0.17.0 ### Features diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 2d1b66ea..3f230121 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,7 +1,7 @@ { "name": "@sama-communications/sdk", "description": "A SDK client for interacting with the SAMA chat server from Web/Node.js apps", - "version": "0.17.0", + "version": "0.17.1", "keywords": [ "chat", "chat-application", diff --git a/packages/sdk/src/api/api.ts b/packages/sdk/src/api/api.ts index ffb769c9..77eafed8 100644 --- a/packages/sdk/src/api/api.ts +++ b/packages/sdk/src/api/api.ts @@ -1,12 +1,11 @@ import getUniqueId from "../utils/uuid"; import WebSocketImp from "../utils/websocket"; -import { ISocketRequest, UserId, IMessageCreateAck, IMessage, IConversation, IUser, IFile, ISubscription, IResponsePromise } from "../types" +import { Config, ISocketRequest, UserId, IMessageCreateAck, IMessage, IConversation, IUser, IFile, ISubscription, IResponsePromise } from "../types" class SAMAClient { private socket?: WebSocket; - private wsEndpoint: string; - private httpEndpoint: string; - private organizationId: string; + private config: Config; + private currentUserId?: string; private responsesPromises: Record = {}; public deviceId?: string; @@ -29,15 +28,21 @@ class SAMAClient { public onSystemMessageEvent?: ((message: IMessage) => void); public onDisconnectEvent?: (() => void); - constructor({ endpoint: { ws, http }, organization_id }: { endpoint: { ws: string; http: string }, organization_id: string }) { - this.wsEndpoint = ws; - this.httpEndpoint = http; - this.organizationId = organization_id; + constructor(config: Config) { + this.config = config } - async connect(): Promise { + async connect(wsEndpoint?: string, httpEndpoint?: string): Promise { + if (wsEndpoint) { + this.config.endpoint.ws = wsEndpoint + } + + if (httpEndpoint) { + this.config.endpoint.http = httpEndpoint + } + return new Promise((resolve, reject) => { - this.socket = new WebSocketImp(this.wsEndpoint); + this.socket = new WebSocketImp(this.config.endpoint.ws); this.socket.onopen = () => { console.log("[socket.open]"); @@ -104,7 +109,9 @@ class SAMAClient { if (message.message) { if (message.message.error) { - this.responsesPromises[Object.keys(this.responsesPromises).filter(key => key.length == 37).slice(-1)[0]].reject(message.message.error); + const responsesPromisesKey = message.message.id ?? Object.keys(this.responsesPromises).filter(key => key.length == 37).slice(-1)[0] + this.responsesPromises[responsesPromisesKey].reject(message.message.error); + delete this.responsesPromises[responsesPromisesKey]; return; } this.onMessageListener?.(message.message); @@ -159,7 +166,9 @@ class SAMAClient { this.socket.onclose = () => { console.log("[socket.close]"); this.onDisconnectEvent?.(); - this.reconnect(); + if (!this.config.disableAutoReconnect) { + this.reconnect(); + } }; }); } @@ -224,7 +233,7 @@ class SAMAClient { }; if (data) params.body = JSON.stringify(data); - const response = await fetch(`${this.httpEndpoint}/${endpoint}`, params); + const response = await fetch(`${this.config.endpoint.http}/${endpoint}`, params); const text = await response.text(); if (!response.ok) { @@ -243,7 +252,7 @@ class SAMAClient { } async socketLogin(data: { user: { userId: UserId, login: string, password: string, }, deviceId?: string, token?: string }): Promise { - return this.sendRequest("user_login", { organization_id: this.organizationId, ...data.user, device_id: data.deviceId ?? this.deviceId, token: data.token }, "user"); + return this.sendRequest("user_login", { organization_id: this.config.organization_id, ...data.user, device_id: data.deviceId ?? this.deviceId, token: data.token }, ["user", "token"]); } async disconnectSocket(): Promise { @@ -251,7 +260,7 @@ class SAMAClient { } async userCreate(data: { login: string; email: string; password: string }): Promise { - return this.sendRequest("user_create", { organization_id: this.organizationId, login: data.login, email: data.email, password: data.password }, "user"); + return this.sendRequest("user_create", { organization_id: this.config.organization_id, login: data.login, email: data.email, password: data.password }, "user"); } async userEdit(data: { [key: string]: any }): Promise { @@ -265,7 +274,7 @@ class SAMAClient { const tokenExpiredAt = parseInt(localStorage.getItem("sessionExpiredAt") || `${currentTime}`, 10); if (tokenExpiredAt - currentTime <= 0) localStorage.removeItem("sessionId"); - const requestData: { organization_id: string, device_id?: string; login?: string; password?: string } = { organization_id: this.organizationId, device_id: this.deviceId }; + const requestData: { organization_id: string, device_id?: string; login?: string; password?: string } = { organization_id: this.config.organization_id, device_id: this.deviceId }; if (login && password) { requestData.login = login; requestData.password = password; @@ -279,13 +288,13 @@ class SAMAClient { } async userSendOTPToken(data: { email: string }): Promise { - const requestData: { organization_id: string, device_id?: string; email: string; } = { organization_id: this.organizationId, device_id: this.deviceId, email: data.email }; + const requestData: { organization_id: string, device_id?: string; email: string; } = { organization_id: this.config.organization_id, device_id: this.deviceId, email: data.email }; return this.sendRequest("user_send_otp", requestData); } async userResetPassword(data: { email: string, token: number, new_password: string }): Promise { - const requestData: { organization_id: string, device_id?: string; email: string; token: number; new_password: string } = { organization_id: this.organizationId, device_id: this.deviceId, email: data.email, token: data.token, new_password: data.new_password }; + const requestData: { organization_id: string, device_id?: string; email: string; token: number; new_password: string } = { organization_id: this.config.organization_id, device_id: this.deviceId, email: data.email, token: data.token, new_password: data.new_password }; return this.sendRequest("user_reset_password", requestData); } diff --git a/packages/sdk/src/types/index.ts b/packages/sdk/src/types/index.ts index 6d9cd544..aaf3cb65 100644 --- a/packages/sdk/src/types/index.ts +++ b/packages/sdk/src/types/index.ts @@ -1,5 +1,11 @@ export type UserId = string | number +export interface Config { + endpoint: { ws: string; http: string } + organization_id: string + disableAutoReconnect?: boolean +} + export interface ISocketRequest { request: { [key: string]: any; diff --git a/packages/ui-kit/src/components/composites/SummaryContainer/SummaryContainer.tsx b/packages/ui-kit/src/components/composites/SummaryContainer/SummaryContainer.tsx index 6d136990..4c2f2afc 100644 --- a/packages/ui-kit/src/components/composites/SummaryContainer/SummaryContainer.tsx +++ b/packages/ui-kit/src/components/composites/SummaryContainer/SummaryContainer.tsx @@ -1,5 +1,4 @@ import { WandSparkles, X } from "lucide-react"; -import * as m from "motion/react-m"; import { SummaryContainerProps } from "@composites/SummaryContainer/SummaryContainer.types"; @@ -11,13 +10,7 @@ export const SummaryContainer = ({ summaryContent, onClose, getFilterLabel }: Su const { isLoading, text, filter } = summaryContent; return ( - +
Only you can see this summary @@ -38,6 +31,6 @@ export const SummaryContainer = ({ summaryContent, onClose, getFilterLabel }: Su {getFilterLabel && ( {getFilterLabel(filter)} )} - +
); };