updata
This commit is contained in:
@@ -16,11 +16,9 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||
const description =
|
||||
post?.caption?.slice(0, 160) ||
|
||||
"مشاهده پست در مادستاگرام — پلتفرم مدلینگ و تبلیغات";
|
||||
const imagePath = post?.files?.[0]?.path?.replace(
|
||||
"/root/modstagram-back/storage",
|
||||
""
|
||||
);
|
||||
const ogImage = imagePath ? `${IMAGE_BASE_URL}${imagePath}` : undefined;
|
||||
const ogImage = post?.files?.[0]?.path
|
||||
? buildStorageUrl(post.files[0].path)
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
title,
|
||||
|
||||
@@ -253,34 +253,52 @@ function TicketChat({ params }: ITicketChatProps) {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
if (fileForUpload) {
|
||||
formData.append("file", fileForUpload);
|
||||
if (fileType) formData.append("fileType", fileType);
|
||||
}
|
||||
if (selfDestructSeconds) {
|
||||
formData.append("selfDestructSeconds", String(selfDestructSeconds));
|
||||
}
|
||||
if (applyViewOnce) {
|
||||
formData.append("viewOnce", "true");
|
||||
}
|
||||
const isFileUpload = fileForUpload && fileType !== "location";
|
||||
|
||||
try {
|
||||
const endpoint =
|
||||
fileToUpload && fileType !== "location" ? "/chat/file" : "/chat";
|
||||
let response: ChatMessage | { data: ChatMessage };
|
||||
|
||||
const response = await request<ChatMessage | { data: ChatMessage }>(
|
||||
"post",
|
||||
endpoint,
|
||||
formData,
|
||||
{ headers: { "Content-Type": "multipart/form-data" } }
|
||||
);
|
||||
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);
|
||||
}
|
||||
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 }>(
|
||||
"post",
|
||||
"/chat/file",
|
||||
formData
|
||||
);
|
||||
} 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
|
||||
);
|
||||
}
|
||||
|
||||
const serverMsg = normalizeMessage(response as ChatMessage);
|
||||
const sentMsg: ChatMessage = {
|
||||
@@ -289,10 +307,10 @@ function TicketChat({ params }: ITicketChatProps) {
|
||||
replyTo: serverMsg.replyTo ?? replyPayload,
|
||||
};
|
||||
|
||||
if (currentUserId && chatPartnerId) {
|
||||
if (currentUserId && targetReceiverId) {
|
||||
linkIds(tempId, sentMsg._id);
|
||||
queryClient.setQueryData(
|
||||
chatThreadQueryKey(currentUserId, chatPartnerId),
|
||||
chatThreadQueryKey(currentUserId, targetReceiverId),
|
||||
(oldData) => appendMessageToThreadCache(oldData, sentMsg)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
"use client";
|
||||
import { useEffect } from "react";
|
||||
import { ICON_VERSION } from "@/components/main/BaseUrl";
|
||||
|
||||
export default function RegisterSW() {
|
||||
useEffect(() => {
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker.register("/service-worker.js").then(() => {
|
||||
console.log("Service Worker Registered!");
|
||||
});
|
||||
navigator.serviceWorker
|
||||
.register(`/service-worker.js?v=${ICON_VERSION}`)
|
||||
.then(() => {
|
||||
console.log("Service Worker Registered!");
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import BoldIcon from "@/components/ui/BoldIcon";
|
||||
import { staticIconUrl } from "@/components/main/BaseUrl";
|
||||
|
||||
export type ChatBoldIconName =
|
||||
| "timer"
|
||||
@@ -20,9 +21,9 @@ export type ChatBoldIconName =
|
||||
|
||||
/** Chat-specific SVG assets (custom uploads) */
|
||||
const CHAT_ICON_SRC: Partial<Record<ChatBoldIconName, string>> = {
|
||||
timer: "/images/icons/chat/timer.svg",
|
||||
search: "/images/icons/chat/search-normal.svg",
|
||||
back: "/images/icons/chat/back.svg",
|
||||
timer: staticIconUrl("/images/icons/chat/timer.svg"),
|
||||
search: staticIconUrl("/images/icons/chat/search-normal.svg"),
|
||||
back: staticIconUrl("/images/icons/chat/back.svg"),
|
||||
};
|
||||
|
||||
const ICON_NAME: Record<ChatBoldIconName, string> = {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useState, useRef, useMemo, useCallback } from "react";
|
||||
import { SOCKET_URL } from "../main/BaseUrl";
|
||||
import { SOCKET_URL, getApiBaseUrl } from "../main/BaseUrl";
|
||||
import { apiClient } from "@/hooks/useAxios";
|
||||
import { chatThreadQueryKey } from "@/lib/chat/queryKeys";
|
||||
import {
|
||||
@@ -97,7 +97,9 @@ const ChatMessageList = ({
|
||||
);
|
||||
|
||||
const senderId = normalizeThreadId(userDetail?._id ?? getStoredUserId());
|
||||
const receiverId = normalizeThreadId(chatPartnerId);
|
||||
const receiverId = normalizeThreadId(
|
||||
userTwoDetail?._id ?? chatPartnerId
|
||||
);
|
||||
const threadReady = Boolean(senderId && receiverId);
|
||||
const queryKey = chatThreadQueryKey(senderId, receiverId);
|
||||
|
||||
@@ -119,7 +121,8 @@ const ChatMessageList = ({
|
||||
|
||||
try {
|
||||
const response = await apiClient.get(
|
||||
`/chat?senderId=${sid}&receiverId=${rid}&page=${pageParam}&limit=50`
|
||||
`/chat?senderId=${sid}&receiverId=${rid}&page=${pageParam}&limit=50`,
|
||||
{ baseURL: getApiBaseUrl() }
|
||||
);
|
||||
const msgs = (response.data.messages || []) as ChatMessage[];
|
||||
return {
|
||||
|
||||
@@ -38,6 +38,18 @@ export const BASE_URL = getApiBaseUrl();
|
||||
/** @deprecated از getStorageBaseUrl() استفاده کنید */
|
||||
export const IMAGE_BASE_URL = getStorageBaseUrl();
|
||||
|
||||
/** نسخه آیکونها — با هر تغییر آیکون این مقدار را افزایش دهید */
|
||||
export const ICON_VERSION =
|
||||
process.env.NEXT_PUBLIC_ICON_VERSION ?? "2";
|
||||
|
||||
/** URL آیکون استاتیک با cache-busting */
|
||||
export function staticIconUrl(path: string): string {
|
||||
if (!path) return "";
|
||||
const normalized = path.startsWith("/") ? path : `/${path}`;
|
||||
const separator = normalized.includes("?") ? "&" : "?";
|
||||
return `${normalized}${separator}v=${ICON_VERSION}`;
|
||||
}
|
||||
|
||||
/** ساخت URL کامل فایل storage — مسیرهای DB را یکسان میکند */
|
||||
export function buildStorageUrl(path: string | null | undefined): string {
|
||||
if (!path) return "";
|
||||
|
||||
@@ -88,10 +88,7 @@ function MainModelCard({
|
||||
const mediaFiles =
|
||||
files?.map((file) => ({
|
||||
...file,
|
||||
src: `${IMAGE_BASE_URL}${file.path.replace(
|
||||
"/root/modstagram-back/storage",
|
||||
""
|
||||
)}`,
|
||||
src: buildStorageUrl(file.path),
|
||||
})) || [];
|
||||
|
||||
// تابع برای ایجاد افکت ripple و تغییر وضعیت صدا
|
||||
|
||||
@@ -71,10 +71,7 @@ function MainModelCard({ postData }: { postData: Post }) {
|
||||
const mediaFiles =
|
||||
files?.map((file) => ({
|
||||
...file,
|
||||
src: `${IMAGE_BASE_URL}${file.path.replace(
|
||||
"/root/modstagram-back/storage",
|
||||
""
|
||||
)}`,
|
||||
src: buildStorageUrl(file.path),
|
||||
})) || [];
|
||||
|
||||
const sliderSettings = {
|
||||
|
||||
@@ -92,7 +92,7 @@ function ModelContentPosts({ filters, token, _id }: InfinitePostsProps) {
|
||||
const mediaFiles =
|
||||
post.files?.map((file) => ({
|
||||
...file,
|
||||
src: `${IMAGE_BASE_URL}${file.path.replace("/root/modstagram-back/storage", "")}`,
|
||||
src: buildStorageUrl(file.path),
|
||||
})) || [];
|
||||
|
||||
const firstMedia = mediaFiles[0]?.src || "/images/placeholder.png";
|
||||
|
||||
@@ -64,10 +64,7 @@ export default function ReelsPostCard({
|
||||
const mediaFiles =
|
||||
files?.map((file) => ({
|
||||
...file,
|
||||
src: `${IMAGE_BASE_URL}${file.path.replace(
|
||||
"/root/modstagram-back/storage",
|
||||
""
|
||||
)}`,
|
||||
src: buildStorageUrl(file.path),
|
||||
})) || [];
|
||||
|
||||
const handleVideoClick = (e: React.MouseEvent<HTMLVideoElement>) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { staticIconUrl } from "@/components/main/BaseUrl";
|
||||
|
||||
const BOLD_BASE = "/images/icons/vuesax/bold";
|
||||
|
||||
@@ -17,7 +18,7 @@ interface BoldIconProps {
|
||||
|
||||
export function boldIconUrl(name: string): string {
|
||||
const file = name.endsWith(".svg") ? name : `${name}.svg`;
|
||||
return `${BOLD_BASE}/${file}`;
|
||||
return staticIconUrl(`${BOLD_BASE}/${file}`);
|
||||
}
|
||||
|
||||
export default function BoldIcon({
|
||||
|
||||
Reference in New Issue
Block a user