From 9844553fa6ef85ff327a09830ecf9eed0e1e3b88 Mon Sep 17 00:00:00 2001 From: "ildar.timerbaev" Date: Wed, 10 Apr 2024 21:03:46 +0600 Subject: [PATCH 1/5] Chats: fixed floating date layout --- src/common/features/chats/components/chat-floating-date.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/features/chats/components/chat-floating-date.tsx b/src/common/features/chats/components/chat-floating-date.tsx index 9b77b6c93cb..e6a84d80c25 100644 --- a/src/common/features/chats/components/chat-floating-date.tsx +++ b/src/common/features/chats/components/chat-floating-date.tsx @@ -30,7 +30,7 @@ export function ChatFloatingDate({ "top-[180px] md:top-[57px]": isPage })} > -
+
{currentFormattedDate}
From 54e6c077e46259ca9c560ee0d2844cd175a6687d Mon Sep 17 00:00:00 2001 From: "ildar.timerbaev" Date: Wed, 10 Apr 2024 21:48:11 +0600 Subject: [PATCH 2/5] Chats: Moved pinned contacts on top of list --- .../chat-popup-contacts-and-channels.tsx | 22 +++++++++++++++++-- .../chats/components/chats-sidebar/index.tsx | 18 ++++++++++++--- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/src/common/features/chats/components/chat-popup/chat-popup-contacts-and-channels.tsx b/src/common/features/chats/components/chat-popup/chat-popup-contacts-and-channels.tsx index 3cc0e786453..830f31de66b 100644 --- a/src/common/features/chats/components/chat-popup/chat-popup-contacts-and-channels.tsx +++ b/src/common/features/chats/components/chat-popup/chat-popup-contacts-and-channels.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useMemo } from "react"; import { _t } from "../../../../i18n"; import { ChatsWelcome } from "../chats-welcome"; import { Button } from "@ui/button"; @@ -18,14 +18,32 @@ export function ChatPopupContactsAndChannels({ setShowSearchUser }: Props) { const { privateKey } = useKeysQuery(); + const { data: directContacts } = useDirectContactsQuery(); const { data: channels } = useChannelsQuery(); + const nonPinnedDirectContacts = useMemo( + () => directContacts?.filter((dc) => !dc.pinned), + [directContacts] + ); + const pinnedDirectContacts = useMemo( + () => directContacts?.filter((dc) => !!dc.pinned), + [directContacts] + ); + return ( <> {(directContacts?.length !== 0 || (channels?.length !== 0 && channels?.length !== 0)) && privateKey ? ( <> + {pinnedDirectContacts?.map((contact) => ( + userClicked(contact.name)} + key={contact.pubkey} + /> + ))} {channels?.length !== 0 && ( <>
@@ -48,7 +66,7 @@ export function ChatPopupContactsAndChannels({ )} )} - {directContacts?.map((user) => ( + {nonPinnedDirectContacts?.map((user) => ( directContacts?.filter((dc) => !dc.pinned), + [directContacts] + ); + const pinnedDirectContacts = useMemo( + () => directContacts?.filter((dc) => !!dc.pinned), + [directContacts] + ); + return (
@@ -75,6 +84,9 @@ export default function ChatsSideBar(props: Props) { )) ) : ( <> + {pinnedDirectContacts?.map((contact) => ( + + ))} {channels?.length !== 0 && (
{_t("chat.communities")} @@ -88,12 +100,12 @@ export default function ChatsSideBar(props: Props) { username={username} /> ))} - {directContacts?.length !== 0 && ( + {nonPinnedDirectContacts?.length !== 0 && (
{_t("chat.direct-messages")}
)} - {directContacts?.map((contact) => ( + {nonPinnedDirectContacts?.map((contact) => ( ))} From 9f7f87b1a0031b8b8e9c31fba51758ed5e7f412c Mon Sep 17 00:00:00 2001 From: "ildar.timerbaev" Date: Thu, 11 Apr 2024 22:18:40 +0600 Subject: [PATCH 3/5] Chats: Added local storage to chat provider --- package.json | 2 +- src/common/app.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 8c27d50d273..4c85ffeab24 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { - "@ecency/ns-query": "^1.1.8", + "@ecency/ns-query": "^1.2.3", "@ecency/render-helper": "^2.2.32", "@ecency/render-helper-amp": "^1.1.0", "@emoji-mart/data": "^1.1.2", diff --git a/src/common/app.tsx b/src/common/app.tsx index 54c52d2dc10..a80ed3d1460 100644 --- a/src/common/app.tsx +++ b/src/common/app.tsx @@ -121,6 +121,7 @@ const App = (props: any) => { Date: Thu, 11 Apr 2024 22:52:14 +0600 Subject: [PATCH 4/5] Chats: Added common contacts and channels list --- src/common/app.tsx | 2 +- .../chat-popup-contacts-and-channels.tsx | 68 ++++++----------- .../chats-sidebar/chat-sidebar-channel.tsx | 8 +- .../chat-sidebar-direct-contact.tsx | 4 +- .../chats/components/chats-sidebar/index.tsx | 52 +++++-------- .../composed-contacts-and-channels-query.ts | 73 +++++++++++++++++++ src/common/features/chats/queries/index.ts | 1 + 7 files changed, 122 insertions(+), 86 deletions(-) create mode 100644 src/common/features/chats/queries/composed-contacts-and-channels-query.ts diff --git a/src/common/app.tsx b/src/common/app.tsx index a80ed3d1460..cc3cc475f31 100644 --- a/src/common/app.tsx +++ b/src/common/app.tsx @@ -121,7 +121,7 @@ const App = (props: any) => { void; @@ -21,59 +22,32 @@ export function ChatPopupContactsAndChannels({ const { data: directContacts } = useDirectContactsQuery(); const { data: channels } = useChannelsQuery(); - - const nonPinnedDirectContacts = useMemo( - () => directContacts?.filter((dc) => !dc.pinned), - [directContacts] - ); - const pinnedDirectContacts = useMemo( - () => directContacts?.filter((dc) => !!dc.pinned), - [directContacts] - ); + const composedContactsAndChannels = useComposedContactsAndChannelsQuery(); return ( <> {(directContacts?.length !== 0 || (channels?.length !== 0 && channels?.length !== 0)) && privateKey ? ( <> - {pinnedDirectContacts?.map((contact) => ( - userClicked(contact.name)} - key={contact.pubkey} - /> - ))} - {channels?.length !== 0 && ( - <> -
- {_t("chat.communities")} -
- {channels?.map((channel) => ( - communityClicked(channel.communityName!)} - isLink={false} - /> - ))} - {directContacts?.length !== 0 && ( -
- {_t("chat.dms")} -
- )} - + {composedContactsAndChannels.map((contactOrChannel) => + "id" in contactOrChannel ? ( + communityClicked(contactOrChannel.communityName!)} + isLink={false} + /> + ) : ( + userClicked(contactOrChannel.name)} + key={contactOrChannel.pubkey} + /> + ) )} - {nonPinnedDirectContacts?.map((user) => ( - userClicked(user.name)} - key={user.pubkey} - /> - ))} ) : !privateKey ? ( diff --git a/src/common/features/chats/components/chats-sidebar/chat-sidebar-channel.tsx b/src/common/features/chats/components/chats-sidebar/chat-sidebar-channel.tsx index 972cbd19e86..70f50319385 100644 --- a/src/common/features/chats/components/chats-sidebar/chat-sidebar-channel.tsx +++ b/src/common/features/chats/components/chats-sidebar/chat-sidebar-channel.tsx @@ -13,6 +13,7 @@ import { import { _t } from "../../../../i18n"; import { Badge } from "@ui/badge"; import { useCommunityCache } from "../../../../core"; +import { UilUsersAlt } from "@iconscout/react-unicons"; interface Props { username: string; @@ -42,6 +43,9 @@ export function ChatSidebarChannel({ const content = ( <> +
+ +
{channel.name}
@@ -63,7 +67,7 @@ export function ChatSidebarChannel({ return isLink ? ( setShowContextMenu(v)} @@ -162,7 +163,6 @@ export function ChatSidebarDirectContact({ contact, onClick, isLink = true }: Pr onTouchStart={() => setHoldStarted(true)} onTouchEnd={() => { setHoldStarted(false); - console.log("touch ended"); setTimeout(() => { if (!holdStarted) { @@ -186,7 +186,7 @@ export function ChatSidebarDirectContact({ contact, onClick, isLink = true }: Pr setShowContextMenu(true); }} className={classNameObject({ - "flex items-center text-dark-200 gap-3 p-3 border-b border-[--border-color] last:border-0 hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer": + "flex items-center text-dark-200 gap-3 p-3 last:border-0 hover:bg-gray-100 dark:hover:bg-gray-800 cursor-pointer": true, "bg-gray-100 dark:bg-gray-800": receiverPubKey === contact.pubkey })} diff --git a/src/common/features/chats/components/chats-sidebar/index.tsx b/src/common/features/chats/components/chats-sidebar/index.tsx index 34434ff1fe3..9b0a1bd53da 100644 --- a/src/common/features/chats/components/chats-sidebar/index.tsx +++ b/src/common/features/chats/components/chats-sidebar/index.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useMemo, useState } from "react"; +import React, { useContext, useState } from "react"; import { History } from "history"; import { ChatSidebarHeader } from "./chat-sidebar-header"; import { ChatSidebarSearch } from "./chat-sidebar-search"; @@ -12,7 +12,7 @@ import { useChannelsQuery, useDirectContactsQuery } from "@ecency/ns-query"; -import { useSearchUsersQuery } from "../../queries"; +import { useComposedContactsAndChannelsQuery, useSearchUsersQuery } from "../../queries"; import { useSearchCommunitiesQuery } from "../../queries/search-communities-query"; import { Community } from "../../../../store/communities"; import { Reputations } from "../../../../api/hive"; @@ -32,6 +32,7 @@ export default function ChatsSideBar(props: Props) { const { data: directContacts } = useDirectContactsQuery(); const { data: channels } = useChannelsQuery(); + const composedContactsAndChannels = useComposedContactsAndChannelsQuery(); const chatsSideBarRef = React.createRef(); const [selectedAccount, setSelectedAccount] = useState(""); @@ -45,15 +46,6 @@ export default function ChatsSideBar(props: Props) { useCreateTemporaryContact(selectedAccount); useCreateTemporaryChannel(selectedCommunity); - const nonPinnedDirectContacts = useMemo( - () => directContacts?.filter((dc) => !dc.pinned), - [directContacts] - ); - const pinnedDirectContacts = useMemo( - () => directContacts?.filter((dc) => !!dc.pinned), - [directContacts] - ); - return (
@@ -84,30 +76,22 @@ export default function ChatsSideBar(props: Props) { )) ) : ( <> - {pinnedDirectContacts?.map((contact) => ( - - ))} - {channels?.length !== 0 && ( -
- {_t("chat.communities")} -
- )} - {channels?.map((channel) => ( - - ))} - {nonPinnedDirectContacts?.length !== 0 && ( -
- {_t("chat.direct-messages")} -
+ {composedContactsAndChannels.map((contactOrChannel) => + "id" in contactOrChannel ? ( + + ) : ( + + ) )} - {nonPinnedDirectContacts?.map((contact) => ( - - ))} )}
diff --git a/src/common/features/chats/queries/composed-contacts-and-channels-query.ts b/src/common/features/chats/queries/composed-contacts-and-channels-query.ts new file mode 100644 index 00000000000..ce41cbfeb64 --- /dev/null +++ b/src/common/features/chats/queries/composed-contacts-and-channels-query.ts @@ -0,0 +1,73 @@ +import { + useChannelsQuery, + useDirectContactsQuery, + useKeysQuery, + useNostrGetUserProfileQuery +} from "@ecency/ns-query"; +import { useMemo } from "react"; +import { isAfter } from "date-fns"; + +export function useComposedContactsAndChannelsQuery() { + const { publicKey } = useKeysQuery(); + const { data: contactsData } = useDirectContactsQuery(); + const { data: channelsData } = useChannelsQuery(); + + const { data: activeUserNostrProfiles } = useNostrGetUserProfileQuery(publicKey); + + const channelsLastSeenDate = useMemo( + () => + channelsData.reduce>((acc, channel) => { + if (activeUserNostrProfiles?.[0] && channel) { + const channelsLastSeenTimestamps = + activeUserNostrProfiles?.[0].channelsLastSeenDate ?? {}; + const lastSeenTimestamp = channelsLastSeenTimestamps[channel.id]; + return { + ...acc, + [channel.id]: lastSeenTimestamp + }; + } + return acc; + }, {}), + [channelsData, activeUserNostrProfiles] + ); + + return useMemo( + () => + [...(contactsData ?? []), ...channelsData] + .sort((a, b) => { + let lastSeenDateA: Date | undefined; + if ("lastSeenDate" in a) { + lastSeenDateA = a.lastSeenDate; + } else if ("id" in a) { + lastSeenDateA = channelsLastSeenDate[a.id]; + } + + let lastSeenDateB: Date | undefined; + if ("lastSeenDate" in b) { + lastSeenDateB = b.lastSeenDate; + } else if ("id" in b) { + lastSeenDateB = channelsLastSeenDate[b.id]; + } + + if ( + lastSeenDateA instanceof Date && + lastSeenDateB instanceof Date && + isAfter(lastSeenDateA, lastSeenDateB) + ) { + return -1; + } + return 0; + }) + .sort((a, b) => { + if ("pinned" in a && "pinned" in b) { + return +(b.pinned ?? false) - +(a.pinned ?? false); + } else if ("pinned" in a) { + return -1; + } else if ("pinned" in b) { + return 1; + } + return 0; + }), + [contactsData, channelsData, channelsLastSeenDate] + ); +} diff --git a/src/common/features/chats/queries/index.ts b/src/common/features/chats/queries/index.ts index a25d33f77de..8d31b3adf8a 100644 --- a/src/common/features/chats/queries/index.ts +++ b/src/common/features/chats/queries/index.ts @@ -1 +1,2 @@ export * from "./search-users-query"; +export * from "./composed-contacts-and-channels-query"; From 31e54ae11f0bb897685bb02c3ecb0306c1292c82 Mon Sep 17 00:00:00 2001 From: feruzm Date: Fri, 12 Apr 2024 06:59:29 +0500 Subject: [PATCH 5/5] lockfile update --- yarn.lock | 71 ++++--------------------------------------------------- 1 file changed, 5 insertions(+), 66 deletions(-) diff --git a/yarn.lock b/yarn.lock index 742c84d7524..28195478ce3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1381,18 +1381,16 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@ecency/ns-query@^1.1.8": - version "1.1.8" - resolved "https://registry.yarnpkg.com/@ecency/ns-query/-/ns-query-1.1.8.tgz#5e224c5aa0116f143a0734fc3723916e10ca90f3" - integrity sha512-EEIEsPlKmHr3UyrOSk9/d8TbcrUeCdvqFYb+2TVdIJOQKYJA4YB2z4AWjUfIafbYpX/XAnP6aDH6ZqrPaKRSlA== +"@ecency/ns-query@^1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@ecency/ns-query/-/ns-query-1.2.3.tgz#057ec5d77fc5b379d05743bcd95f44971e19d2b1" + integrity sha512-5WiEmOlDu50ceeBdQkphhhMOggtdU/v2LOb832qTwUG6hrCj0YecU37uxDpGKYW4zIk3u5D4BKBZZR8BxCHTuA== dependencies: "@tanstack/react-query" "^4.29.7" axios "^0.21.2" date-fns "^2.30.0" nostr-tools "^1.17.0" react "^16.8.6" - react-dom "^16.8.6" - react-use "^17.4.1" "@ecency/render-helper-amp@^1.1.0": version "1.1.0" @@ -1893,7 +1891,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== -"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": +"@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -5003,11 +5001,6 @@ csstype@^3.0.6: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.1.tgz#841b532c45c758ee546a11d5bd7b7b473c8c30b9" integrity sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw== -csstype@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" - integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== - currency-symbol-map@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/currency-symbol-map/-/currency-symbol-map-4.0.4.tgz#3cfba625974dd3f86822d327ecbd10248695e95e" @@ -7109,14 +7102,6 @@ inline-style-prefixer@^6.0.0: css-in-js-utils "^3.1.0" fast-loops "^1.1.3" -inline-style-prefixer@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-7.0.0.tgz#991d550735d42069f528ac1bcdacd378d1305442" - integrity sha512-I7GEdScunP1dQ6IM2mQWh6v0mOYdYmH3Bp31UecKdrcUgcURTcctSe1IECdUznSHKSmsHtjrT3CwCPI1pyxfUQ== - dependencies: - css-in-js-utils "^3.1.0" - fast-loops "^1.1.3" - inquirer@7.0.4: version "7.0.4" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703" @@ -8923,20 +8908,6 @@ nano-css@^5.3.1: stacktrace-js "^2.0.2" stylis "^4.0.6" -nano-css@^5.6.1: - version "5.6.1" - resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.6.1.tgz#964120cb1af6cccaa6d0717a473ccd876b34c197" - integrity sha512-T2Mhc//CepkTa3X4pUhKgbEheJHYAxD0VptuqFhDbGMUWVV2m+lkNiW/Ieuj35wrfC8Zm0l7HvssQh7zcEttSw== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - css-tree "^1.1.2" - csstype "^3.1.2" - fastest-stable-stringify "^2.0.2" - inline-style-prefixer "^7.0.0" - rtl-css-js "^1.16.1" - stacktrace-js "^2.0.2" - stylis "^4.3.0" - nanoid@^3.1.22, nanoid@^3.3.6: version "3.3.6" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" @@ -10969,26 +10940,6 @@ react-use@^17.4.0: ts-easing "^0.2.0" tslib "^2.1.0" -react-use@^17.4.1: - version "17.4.2" - resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.4.2.tgz#26d43c774ccb733a17a87be62e12fbcbc5654173" - integrity sha512-1jPtmWLD8OJJNYCdYLJEH/HM+bPDfJuyGwCYeJFgPmWY8ttwpgZnW5QnzgM55CYUByUiTjHxsGOnEpLl6yQaoQ== - dependencies: - "@types/js-cookie" "^2.2.6" - "@xobotyi/scrollbar-width" "^1.9.5" - copy-to-clipboard "^3.3.1" - fast-deep-equal "^3.1.3" - fast-shallow-equal "^1.0.0" - js-cookie "^2.2.1" - nano-css "^5.6.1" - react-universal-interface "^0.6.2" - resize-observer-polyfill "^1.5.1" - screenfull "^5.1.0" - set-harmonic-interval "^1.0.1" - throttle-debounce "^3.0.1" - ts-easing "^0.2.0" - tslib "^2.1.0" - react-virtualized@^9.22.3: version "9.22.3" resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.22.3.tgz#f430f16beb0a42db420dbd4d340403c0de334421" @@ -11483,13 +11434,6 @@ rtl-css-js@^1.14.0: dependencies: "@babel/runtime" "^7.1.2" -rtl-css-js@^1.16.1: - version "1.16.1" - resolved "https://registry.yarnpkg.com/rtl-css-js/-/rtl-css-js-1.16.1.tgz#4b48b4354b0ff917a30488d95100fbf7219a3e80" - integrity sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg== - dependencies: - "@babel/runtime" "^7.1.2" - run-async@^2.2.0, run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -12505,11 +12449,6 @@ stylis@^4.0.6: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.1.3.tgz#fd2fbe79f5fed17c55269e16ed8da14c84d069f7" integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA== -stylis@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.0.tgz#abe305a669fc3d8777e10eefcfc73ad861c5588c" - integrity sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ== - sucrase@^3.32.0: version "3.34.0" resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.34.0.tgz#1e0e2d8fcf07f8b9c3569067d92fbd8690fb576f"