From 39b12a098654aafa7119b008bc2a7326002792a5 Mon Sep 17 00:00:00 2001 From: payacom <59262811+payacom@users.noreply.github.com> Date: Sun, 12 Jul 2026 19:01:04 +0330 Subject: [PATCH] chat --- .../settings/chats/[username]/[id]/page.tsx | 105 ++++++++++-------- src/components/explore/ExploreAuthor.tsx | 4 +- src/components/explore/ExploreGrid.tsx | 16 ++- 3 files changed, 69 insertions(+), 56 deletions(-) diff --git a/src/app/settings/chats/[username]/[id]/page.tsx b/src/app/settings/chats/[username]/[id]/page.tsx index 2377f29..0004570 100644 --- a/src/app/settings/chats/[username]/[id]/page.tsx +++ b/src/app/settings/chats/[username]/[id]/page.tsx @@ -269,76 +269,83 @@ function TicketChat({ params }: ITicketChatProps) { const isFileUpload = fileForUpload && fileType !== "location"; try { - let response: ChatMessage | { data: ChatMessage }; + if (!socketRef.current) { + throw new Error("Socket not connected"); + } + + let messagePayload: Record = { + content: textContent, + receiverId: targetReceiverId, + senderId: currentUserId, + tempId: tempId, + }; + + if (replySource?._id && !replySource._id.startsWith("temp")) { + messagePayload.replyToId = replySource._id; + } + if (selfDestructSeconds) { + messagePayload.selfDestructSeconds = selfDestructSeconds; + } + if (fileType) { + messagePayload.fileType = fileType; + } + if (applyViewOnce) { + messagePayload.viewOnce = true; + } if (isFileUpload) { const formData = new FormData(); - formData.append("content", textContent); - formData.append("receiverId", targetReceiverId); - formData.append("senderId", currentUserId); - if (replySource?._id && !replySource._id.startsWith("temp")) { - formData.append("replyToId", replySource._id); + for (const key in messagePayload) { + formData.append(key, String(messagePayload[key])); } formData.append("file", fileForUpload); - if (fileType) formData.append("fileType", fileType); - if (selfDestructSeconds) { - formData.append("selfDestructSeconds", String(selfDestructSeconds)); - } - if (applyViewOnce) { - formData.append("viewOnce", "true"); - } - response = await request( + // ارسال فایل از طریق HTTP (معمولاً فایل‌ها از طریق HTTP ارسال می‌شوند و اطلاعات از طریق Socket.IO) + const response = await request( "post", "/chat/file", formData ); + const serverMsg = normalizeMessage(response as ChatMessage); + socketRef.current.emit("sendMessage", { ...serverMsg, tempId }); } else { - const payload: Record = { - content: textContent, - receiverId: targetReceiverId, - senderId: currentUserId, - }; - if (replySource?._id && !replySource._id.startsWith("temp")) { - payload.replyToId = replySource._id; - } - if (selfDestructSeconds) { - payload.selfDestructSeconds = selfDestructSeconds; - } - - response = await request( - "post", - "/chat", - payload - ); + socketRef.current.emit("sendMessage", messagePayload); } - const serverMsg = normalizeMessage(response as ChatMessage); - const sentMsg: ChatMessage = { - ...serverMsg, - status: "sent", - replyTo: serverMsg.replyTo ?? replyPayload, - }; + // اپتیمیستیک آپدیت (این بخش باید توسط رویداد Socket.IO سرور تایید شود) + // const serverMsg = normalizeMessage(response as ChatMessage); + // const sentMsg: ChatMessage = { + // ...serverMsg, + // status: "sent", + // replyTo: serverMsg.replyTo ?? replyPayload, + // }; - if (currentUserId && targetReceiverId) { - linkIds(tempId, sentMsg._id); - queryClient.setQueryData( - chatThreadQueryKey(currentUserId, targetReceiverId), - (oldData) => appendMessageToThreadCache(oldData, sentMsg) - ); - } + // if (currentUserId && targetReceiverId) { + // linkIds(tempId, sentMsg._id); + // queryClient.setQueryData( + // chatThreadQueryKey(currentUserId, targetReceiverId), + // (oldData) => appendMessageToThreadCache(oldData, sentMsg) + // ); + // } - setPendingMessages((prev) => prev.filter((m) => m._id !== tempId)); + // setPendingMessages((prev) => prev.filter((m) => m._id !== tempId)); - setReplyingTo(null); - activeReplyRef.current = null; - setSelfDestructSeconds(null); - if (applyViewOnce) setViewOnceMedia(false); + // این موارد پس از دریافت تاییدیه از Socket.IO باید انجام شوند + // setReplyingTo(null); + // activeReplyRef.current = null; + // setSelfDestructSeconds(null); + // if (applyViewOnce) setViewOnceMedia(false); } catch (error) { console.error("Error sending message:", error); setPendingMessages((prev) => prev.filter((m) => m._id !== tempId)); toast.error("ارسال پیام ناموفق بود."); } + + // پاک کردن وضعیت پیام پس از ارسال + setReplyingTo(null); + activeReplyRef.current = null; + setSelfDestructSeconds(null); + if (applyViewOnce) setViewOnceMedia(false); }; const handleExpirePending = useCallback((ids: string[]) => { diff --git a/src/components/explore/ExploreAuthor.tsx b/src/components/explore/ExploreAuthor.tsx index 4c55567..51d3d10 100644 --- a/src/components/explore/ExploreAuthor.tsx +++ b/src/components/explore/ExploreAuthor.tsx @@ -38,10 +38,10 @@ export default function ExploreAuthor({ - + {userName ? `@${userName}` : displayName} diff --git a/src/components/explore/ExploreGrid.tsx b/src/components/explore/ExploreGrid.tsx index dfdcbe7..e4141dd 100644 --- a/src/components/explore/ExploreGrid.tsx +++ b/src/components/explore/ExploreGrid.tsx @@ -220,17 +220,23 @@ export default function ExploreGrid({ ? fetchAcademyExplore(page, 15, token) : Promise.resolve({ items: [], hasNextPage: false }); - const [postsResult, academyResult] = await Promise.all([ + const [postsResult, academyResult] = await Promise.allSettled([ postsPromise, academyPromise, ]); + const resolvedPosts = postsResult.status === "fulfilled" ? postsResult.value.posts ?? [] : []; + const resolvedPostsHasMore = postsResult.status === "fulfilled" ? (postsResult.value.posts?.length ?? 0) > 0 : false; + + const resolvedAcademyItems = academyResult.status === "fulfilled" ? academyResult.value.items : []; + const resolvedAcademyHasMore = academyResult.status === "fulfilled" ? academyResult.value.hasNextPage : false; + return { page, - posts: postsResult.posts ?? [], - postsHasMore: (postsResult.posts?.length ?? 0) > 0, - academyItems: academyResult.items, - academyHasMore: academyResult.hasNextPage, + posts: resolvedPosts, + postsHasMore: resolvedPostsHasMore, + academyItems: resolvedAcademyItems, + academyHasMore: resolvedAcademyHasMore, }; }, getNextPageParam: (lastPage, allPages) => {