This commit is contained in:
payacom
2026-07-12 19:01:04 +03:30
parent 20c780f104
commit 39b12a0986
3 changed files with 69 additions and 56 deletions

View File

@@ -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<string, unknown> = {
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<ChatMessage | { data: ChatMessage }>(
// ارسال فایل از طریق HTTP (معمولاً فایل‌ها از طریق HTTP ارسال می‌شوند و اطلاعات از طریق Socket.IO)
const response = await request<ChatMessage | { data: ChatMessage }>(
"post",
"/chat/file",
formData
);
const serverMsg = normalizeMessage(response as ChatMessage);
socketRef.current.emit("sendMessage", { ...serverMsg, tempId });
} else {
const payload: Record<string, unknown> = {
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<ChatMessage | { data: ChatMessage }>(
"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[]) => {

View File

@@ -38,10 +38,10 @@ export default function ExploreAuthor({
<ProfileAvatar
src={avatarSrc}
alt={userName || displayName}
size="xxs"
size="xs"
rounded="full"
/>
<span className="truncate text-[10px] font-medium text-neutral-600 dark:text-neutral-300">
<span className="truncate text-xs font-medium text-neutral-600 dark:text-neutral-300">
{userName ? `@${userName}` : displayName}
</span>
</>

View File

@@ -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) => {