Browse Source

feat: update development server port, adjust chat component styles, and add new SVG icons

master
sina_sajjadi 2 weeks ago
parent
commit
1bfb7fe9aa
  1. 2
      next.config.js
  2. 2
      package.json
  3. 2055
      public/image/Frame-48098164.svg
  4. 3
      public/image/face-smile.svg
  5. 3
      public/image/icon-park-outline_link.svg
  6. 4
      public/image/link-simple.svg
  7. 3
      public/image/microphone-01.svg
  8. 3
      public/image/send-01.svg
  9. 10
      src/components/chat/chat-input.tsx
  10. 80
      src/components/chat/file-input.tsx
  11. 6
      src/components/chat/file-message.tsx
  12. 99
      src/components/chat/message.tsx
  13. 2
      src/components/chat/messages-list.tsx
  14. 2
      src/components/product/form-utils.ts
  15. 18
      src/contexts/WebSocket.context.tsx
  16. 2
      src/data/client/user.ts
  17. 2
      src/data/shop.ts
  18. 4
      src/pages/chat/chat-box.tsx
  19. 2
      src/pages/chat/converstions.tsx
  20. 27
      src/pages/shop/index.tsx

2
next.config.js

@ -12,7 +12,7 @@ const { i18n } = require('./next-i18next.config');
const nextConfig = { const nextConfig = {
basePath: '/dashboard', basePath: '/dashboard',
// assetPrefix: '/dashboard/', // assetPrefix: '/dashboard/',
reactStrictMode: true,
reactStrictMode: false,
i18n, i18n,
publicRuntimeConfig: { publicRuntimeConfig: {

2
package.json

@ -3,7 +3,7 @@
"version": "6.6.0", "version": "6.6.0",
"private": true, "private": true,
"scripts": { "scripts": {
"dev": "next dev -p 3000",
"dev": "next dev -p 3001",
"build": "next build", "build": "next build",
"start": "next start -p 3000", "start": "next start -p 3000",
"lint": "next lint" "lint": "next lint"

2055
public/image/Frame-48098164.svg
File diff suppressed because it is too large
View File

3
public/image/face-smile.svg

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.667 18.667C10.667 18.667 12.667 21.3337 16.0003 21.3337C19.3337 21.3337 21.3337 18.667 21.3337 18.667M20.0003 12.0003H20.0137M12.0003 12.0003H12.0137M29.3337 16.0003C29.3337 23.3641 23.3641 29.3337 16.0003 29.3337C8.63653 29.3337 2.66699 23.3641 2.66699 16.0003C2.66699 8.63653 8.63653 2.66699 16.0003 2.66699C23.3641 2.66699 29.3337 8.63653 29.3337 16.0003ZM20.667 12.0003C20.667 12.3685 20.3685 12.667 20.0003 12.667C19.6321 12.667 19.3337 12.3685 19.3337 12.0003C19.3337 11.6321 19.6321 11.3337 20.0003 11.3337C20.3685 11.3337 20.667 11.6321 20.667 12.0003ZM12.667 12.0003C12.667 12.3685 12.3685 12.667 12.0003 12.667C11.6321 12.667 11.3337 12.3685 11.3337 12.0003C11.3337 11.6321 11.6321 11.3337 12.0003 11.3337C12.3685 11.3337 12.667 11.6321 12.667 12.0003Z" stroke="#363636" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

3
public/image/icon-park-outline_link.svg

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.4718 6.37661L6.57248 16.2766C5.44745 17.4018 4.81543 18.9278 4.81543 20.5189C4.81543 22.1101 5.44745 23.6361 6.57248 24.7613C7.12963 25.3184 7.79107 25.7604 8.51903 26.0619C9.24699 26.3635 10.0272 26.5187 10.8151 26.5187C11.6031 26.5187 12.3833 26.3635 13.1113 26.0619C13.8392 25.7604 14.5007 25.3184 15.0578 24.7613L26.8431 12.9766C27.2147 12.6052 27.5094 12.1642 27.7104 11.6788C27.9115 11.1935 28.015 10.6733 28.015 10.1479C28.015 9.6226 27.9115 9.1024 27.7104 8.61705C27.5094 8.1317 27.2147 7.69072 26.8431 7.31927C26.4717 6.94777 26.0307 6.65307 25.5454 6.45201C25.06 6.25095 24.5398 6.14746 24.0145 6.14746C23.4891 6.14746 22.9689 6.25095 22.4836 6.45201C21.9982 6.65307 21.5573 6.94777 21.1858 7.31927L9.40115 19.1046C9.2154 19.2903 9.06805 19.5108 8.96752 19.7535C8.86699 19.9962 8.81524 20.2563 8.81524 20.5189C8.81524 20.7816 8.86699 21.0417 8.96752 21.2844C9.06805 21.5271 9.2154 21.7476 9.40115 21.9333C9.7762 22.3082 10.2848 22.5188 10.8151 22.5188C11.3455 22.5188 11.8541 22.3082 12.2291 21.9333L22.1291 12.0333" stroke="#212121" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

4
public/image/link-simple.svg

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.17177 14.8286L14.8286 9.17177M6.34334 10.586L4.57557 12.3537C2.62295 14.3064 2.62295 17.4722 4.57557 19.4248V19.4248C6.52819 21.3774 9.69402 21.3774 11.6466 19.4248L13.4144 17.657M10.586 6.34334L12.3537 4.57557C14.3064 2.62295 17.4722 2.62295 19.4248 4.57557V4.57557C21.3774 6.5282 21.3774 9.69402 19.4248 11.6466L17.657 13.4144" stroke="#222222" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.17177 14.8286L14.8286 9.17177M6.34334 10.586L4.57557 12.3537C2.62295 14.3064 2.62295 17.4722 4.57557 19.4248V19.4248C6.52819 21.3774 9.69402 21.3774 11.6466 19.4248L13.4144 17.657M10.586 6.34334L12.3537 4.57557C14.3064 2.62295 17.4722 2.62295 19.4248 4.57557V4.57557C21.3774 6.5282 21.3774 9.69402 19.4248 11.6466L17.657 13.4144" stroke="#222222" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

3
public/image/microphone-01.svg

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M25.3337 13.3337V16.0003C25.3337 21.155 21.155 25.3337 16.0003 25.3337M6.66699 13.3337V16.0003C6.66699 21.155 10.8457 25.3337 16.0003 25.3337M16.0003 25.3337V29.3337M10.667 29.3337H21.3337M16.0003 20.0003C13.7912 20.0003 12.0003 18.2095 12.0003 16.0003V6.66699C12.0003 4.45785 13.7912 2.66699 16.0003 2.66699C18.2095 2.66699 20.0003 4.45785 20.0003 6.66699V16.0003C20.0003 18.2095 18.2095 20.0003 16.0003 20.0003Z" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

3
public/image/send-01.svg

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 12L4.83771 17.7661C4.52632 18.5965 5.36976 19.3912 6.18018 19.031L19.9439 12.9138C20.7357 12.5619 20.7357 11.4381 19.9439 11.0862L6.18018 4.96897C5.36976 4.60878 4.52632 5.40351 4.83771 6.2339L7 12ZM7 12H13" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

10
src/components/chat/chat-input.tsx

@ -1,13 +1,13 @@
import { PiTrash } from "react-icons/pi"; import { PiTrash } from "react-icons/pi";
import Image from "next/image"; import Image from "next/image";
import SendIcon from "public/assets/images/send-01.svg";
import MicIcon from "public/assets/images/microphone-01.svg";
import LinkIcon from "public/assets/images/link-simple.svg";
import SmileIcon from "public/assets/images/face-smile.svg";
import SendIcon from "public/image/send-01.svg";
import MicIcon from "public/image/microphone-01.svg";
import LinkIcon from "public/image/link-simple.svg";
import SmileIcon from "public/image/face-smile.svg";
import { MdClose } from "react-icons/md"; import { MdClose } from "react-icons/md";
import { useEffect, useState, useRef } from "react"; import { useEffect, useState, useRef } from "react";
import { useWebSocket } from "@/contexts/WebSocket.context"; import { useWebSocket } from "@/contexts/WebSocket.context";
import FileInput from "../ui/file-input";
import FileInput from "./file-input";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import EmojiPicker from "emoji-picker-react"; import EmojiPicker from "emoji-picker-react";
import { BsFillReplyFill } from "react-icons/bs"; import { BsFillReplyFill } from "react-icons/bs";

80
src/components/chat/file-input.tsx

@ -0,0 +1,80 @@
import { useWebSocket } from "@/contexts/WebSocket.context";
import Image from "next/image";
import FaPlus from "public/image/icon-park-outline_link.svg";
import { useEffect, useState } from "react";
import { toast } from "react-toastify"; // Import toast from react-toastify
import "react-toastify/dist/ReactToastify.css"; // Import CSS for toast
// Define the allowed image, video, and audio extensions
const IMAGE_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "bmp", "tiff", "webp", "svg"];
const VIDEO_EXTENSIONS = ["mp4", "mkv", "webm", "avi", "mov", "flv", "wmv"];
const AUDIO_EXTENSIONS = ["mp3", "wav", "ogg", "flac", "aac", "m4a"];
const getFileType = (extension : string) => {
const ext = extension.toLowerCase();
// Check if it's an image
if (IMAGE_EXTENSIONS.includes(ext)) {
return "image";
}
// Check if it's a video
if (VIDEO_EXTENSIONS.includes(ext)) {
return "video";
}
// Check if it's an audio file
if (AUDIO_EXTENSIONS.includes(ext)) {
return "audio";
}
// Everything else is a generic file
return "file";
};
const FileInput = () => {
const {setLoadingMessage} = useWebSocket()
const { sendFile } = useWebSocket();
const [file, setFile] = useState(null); // To store the selected file
const MAX_FILE_SIZE = 300 * 1024 * 1024; // 300 MB in bytes
const handleFileChange = async (event : any) => {
const selectedFile = event.target.files[0];
if (selectedFile) {
// Check file size
if (selectedFile.size > MAX_FILE_SIZE) {
toast.error("File is too large. Please select a file smaller than 300 MB.");
return; // Prevent further processing if the file is too large
}
selectedFile.status = "loading"
setLoadingMessage((prev) => [...prev, selectedFile]);
}
};
// Send the file when it's available
return (
<div>
{/* Hidden file input */}
<input
id="file-input"
type="file"
className="hidden"
onChange={handleFileChange} // Handle file change
/>
{/* Label triggers the file input */}
<label
htmlFor="file-input" // This associates the label with the file input
className="text-white px-3 py-2 rounded-md transition flex content-center hover:bg-slate-100"
>
<Image width={25} height={25} src={FaPlus} />
</label>
</div>
);
};
export default FileInput;

6
src/components/chat/file-message.tsx

@ -19,6 +19,8 @@ const fileTypes = {
}; };
const FileMessage = ({ file }) => { const FileMessage = ({ file }) => {
console.log( "file Message",file);
const { sendFile } = useWebSocket(); const { sendFile } = useWebSocket();
const [percentage, setPercentage] = useState(1); const [percentage, setPercentage] = useState(1);
const isLoading = file.status === "loading"; const isLoading = file.status === "loading";
@ -95,7 +97,9 @@ const FileMessage = ({ file }) => {
}) })
.then((res) => { .then((res) => {
const fileType = getFileType(fileExtension); const fileType = getFileType(fileExtension);
sendFile({ ...res.data, type: fileType });
console.log("file sent");
sendFile({ ...res, type: fileType });
}) })
.catch((err) => console.error(err)); .catch((err) => console.error(err));
} }

99
src/components/chat/message.tsx

@ -1,26 +1,26 @@
import { useState, useEffect, useCallback, useRef } from "react";
import { useRouter } from "next/router";
import ContextMenu from "./contex-menu"; // Import the ContextMenu component
import Image from "next/image";
import Seen from "public/image/quill_checkmark-double.svg";
import UnSeen from "public/image/State=Send.svg";
import Pending from "public/image/clock-fast-forward.png";
import { useWebSocket } from "@/contexts/WebSocket.context";
import Button from "../ui/button";
import { Routes as ROUTES } from "@/config/routes";
import { useState, useEffect, useCallback, useRef } from 'react';
import { useRouter } from 'next/router';
import ContextMenu from './contex-menu'; // Import the ContextMenu component
import Image from 'next/image';
import Seen from 'public/image/quill_checkmark-double.svg';
import UnSeen from 'public/image/State=Send.svg';
import Pending from 'public/image/clock-fast-forward.png';
import { useWebSocket } from '@/contexts/WebSocket.context';
import Button from '../ui/button';
import { Routes as ROUTES } from '@/config/routes';
import { HttpClient as http } from "@/data/client/http-client";
import FileMessage from "./file-message";
import ImageMessage from "./image-message";
import AudioMessage from "./audio-message";
import { HttpClient as http } from '@/data/client/http-client';
import FileMessage from './file-message';
import ImageMessage from './image-message';
import AudioMessage from './audio-message';
const Message = ({ msg }) => { const Message = ({ msg }) => {
const isFileMessage = msg.status || msg?.mime_type === "file" ? true : false;
const isFileMessage = msg.status || msg?.mime_type === 'file' ? true : false;
const isLoadingMessage = msg.status ? true : false; const isLoadingMessage = msg.status ? true : false;
const isAudioMessage = msg?.mime_type === "audio" ? true : false;
const isAudioMessage = msg?.mime_type === 'audio' ? true : false;
const isImageMessage = const isImageMessage =
msg?.mime_type === "image" || msg?.mime_type === "video" ? true : false;
const isTextMessage = msg.mime_type === "text" ? true : false;
msg?.mime_type === 'image' || msg?.mime_type === 'video' ? true : false;
const isTextMessage = msg.mime_type === 'text' ? true : false;
if (isLoadingMessage) { if (isLoadingMessage) {
return <FileMessage file={msg} />; return <FileMessage file={msg} />;
} }
@ -46,7 +46,7 @@ const Message = ({ msg }) => {
const date = new Date(timestamp); const date = new Date(timestamp);
let hours = date.getHours(); let hours = date.getHours();
const minutes = date.getMinutes(); const minutes = date.getMinutes();
const ampm = hours >= 12 ? "PM" : "AM";
const ampm = hours >= 12 ? 'PM' : 'AM';
hours %= 12; hours %= 12;
hours = hours || 12; // Convert '0' to '12' hours = hours || 12; // Convert '0' to '12'
@ -55,16 +55,15 @@ const Message = ({ msg }) => {
return `${hours}:${formattedMinutes} ${ampm}`; return `${hours}:${formattedMinutes} ${ampm}`;
}, []); }, []);
// Handlers for context menu actions // Handlers for context menu actions
const handleCopy = useCallback(() => { const handleCopy = useCallback(() => {
navigator.clipboard navigator.clipboard
.writeText(typeof msg === "string" ? msg : msg.content)
.writeText(typeof msg === 'string' ? msg : msg.content)
.then(() => { .then(() => {
console.log("Copied to clipboard");
console.log('Copied to clipboard');
}) })
.catch((err) => { .catch((err) => {
console.error("Failed to copy: ", err);
console.error('Failed to copy: ', err);
}); });
setShowMenu(false); setShowMenu(false);
}, [msg]); }, [msg]);
@ -85,7 +84,7 @@ const Message = ({ msg }) => {
e.preventDefault(); e.preventDefault();
setShowMenu((prev) => !prev); setShowMenu((prev) => !prev);
}, },
[setShowMenu]
[setShowMenu],
); );
// Close menu if clicked outside // Close menu if clicked outside
@ -100,43 +99,43 @@ const Message = ({ msg }) => {
setShowMenu(false); setShowMenu(false);
} }
}, },
[menuRef, messageRef]
[menuRef, messageRef],
); );
// Handle escape key to close menu // Handle escape key to close menu
const handleKeyDown = useCallback( const handleKeyDown = useCallback(
(e) => { (e) => {
if (e.key === "Escape") {
if (e.key === 'Escape') {
setShowMenu(false); setShowMenu(false);
} }
}, },
[setShowMenu]
[setShowMenu],
); );
useEffect(() => { useEffect(() => {
if (showMenu) { if (showMenu) {
document.addEventListener("mousedown", handleClickOutside);
document.addEventListener("keydown", handleKeyDown);
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener('keydown', handleKeyDown);
} else { } else {
document.removeEventListener("mousedown", handleClickOutside);
document.removeEventListener("keydown", handleKeyDown);
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('keydown', handleKeyDown);
} }
// Cleanup on unmount // Cleanup on unmount
return () => { return () => {
document.removeEventListener("mousedown", handleClickOutside);
document.removeEventListener("keydown", handleKeyDown);
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('keydown', handleKeyDown);
}; };
}, [showMenu, handleClickOutside, handleKeyDown]); }, [showMenu, handleClickOutside, handleKeyDown]);
const isStringMessage = typeof msg === "string";
const isStringMessage = typeof msg === 'string';
const messageContent = isStringMessage ? msg : msg.content; const messageContent = isStringMessage ? msg : msg.content;
const messageKey = isStringMessage ? msg : msg.id; const messageKey = isStringMessage ? msg : msg.id;
const messageTime = isStringMessage const messageTime = isStringMessage
? formatTime() ? formatTime()
: formatTime(msg.created_at); : formatTime(msg.created_at);
const isUser = !isStringMessage && msg?.by_user?.account_type === "user";
const isUser = !isStringMessage && msg?.by_user?.account_type === 'merchant';
const isSeen = !isStringMessage && msg?.is_read; const isSeen = !isStringMessage && msg?.is_read;
const product = const product =
!isStringMessage && Object.keys(msg?.product_reply).length !isStringMessage && Object.keys(msg?.product_reply).length
@ -161,14 +160,14 @@ const Message = ({ msg }) => {
key={messageKey} key={messageKey}
className={`rounded-lg border p-2 mb-2 max-w-[525px] flex flex-col whitespace-pre-line break-words relative ${ className={`rounded-lg border p-2 mb-2 max-w-[525px] flex flex-col whitespace-pre-line break-words relative ${
isUser isUser
? "self-end bg-[#323232] text-white"
? 'self-end bg-[#323232] text-white'
: isStringMessage : isStringMessage
? "self-end bg-[#323232] text-white"
: "self-start bg-white text-gray-800"
? 'self-end bg-[#323232] text-white'
: 'self-start bg-white text-gray-800'
}`} }`}
tabIndex={0} tabIndex={0}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.key === "ContextMenu" || (e.shiftKey && e.key === "F10")) {
if (e.key === 'ContextMenu' || (e.shiftKey && e.key === 'F10')) {
e.preventDefault(); e.preventDefault();
setShowMenu(true); setShowMenu(true);
} }
@ -184,28 +183,30 @@ const Message = ({ msg }) => {
onDelete={handleDelete} onDelete={handleDelete}
menuRef={menuRef} menuRef={menuRef}
isUser={isUser} isUser={isUser}
className={isUser ? "-right-2" : ""}
className={isUser ? '-right-2' : ''}
/> />
{/* Render file message */} {/* Render file message */}
{product && ( {product && (
<div <div
className={`w-[510px] border rounded-lg mb-4 ${
className={`w-full border rounded-lg mb-4 ${
isUser isUser
? "border-[#626262] bg-[#3F3F3F] text-[#F2F2F2]"
: "border-[#D8D8D8] bg-[#F2F2F2] text-black "
? 'border-[#626262] bg-[#3F3F3F] text-[#F2F2F2]'
: 'border-[#D8D8D8] bg-[#F2F2F2] text-black '
} p-3`} } p-3`}
> >
<div className="flex mb-4"> <div className="flex mb-4">
<div>
{product?.get_first_image && (
<Image <Image
className="rounded-lg" className="rounded-lg"
width={130} width={130}
height={130} height={130}
src={product?.get_first_image} src={product?.get_first_image}
alt='product'
/> />
</div>
)}
<div></div>
<div className="flex flex-col justify-between"> <div className="flex flex-col justify-between">
<p <p
className={`font-bold text-2xl w-96 mb-0 px-3 overflow-hidden text-ellipsis whitespace-nowrap`} className={`font-bold text-2xl w-96 mb-0 px-3 overflow-hidden text-ellipsis whitespace-nowrap`}
@ -223,17 +224,17 @@ const Message = ({ msg }) => {
<div className="flex gap-4 justify-between"> <div className="flex gap-4 justify-between">
<Button <Button
onClick={() => { onClick={() => {
router.push(`${ROUTES.PRODUCT}/${product.slug}`, undefined, {
router.push(`https://mesbahi.nwhco.ir/products/${product.slug}`, undefined, {
locale: router.locale, locale: router.locale,
}); });
}} }}
className="w-full bg-[#C5C5C5]"
className="w-[calc(50%-12px)] bg-[#C5C5C5]"
> >
Product details Product details
</Button> </Button>
<Button <Button
className={`w-full ${
isUser && "bg-white"
className={`w-[calc(50%-12px)] ${
isUser && 'bg-white'
} !text-black hover:!text-white`} } !text-black hover:!text-white`}
> >
Add to cart Add to cart

2
src/components/chat/messages-list.tsx

@ -51,7 +51,7 @@ const MessageList = ({ messages }) => {
role="log" // Optional: Improves accessibility role="log" // Optional: Improves accessibility
aria-live="polite" // Optional: Announces new messages to screen readers aria-live="polite" // Optional: Announces new messages to screen readers
style={{ style={{
backgroundImage: "url('/assets/images/Frame 48098164.svg')", // Replace with your image path
backgroundImage: "url('/dashboard/image/Frame-48098164.svg')", // Replace with your image path
backgroundSize: "conrain", backgroundSize: "conrain",
backgroundPosition: "center", backgroundPosition: "center",
}} }}

2
src/components/product/form-utils.ts

@ -262,7 +262,7 @@ export function getProductInputValues(
tags: tags.map((tag) => tag?.id), tags: tags.map((tag) => tag?.id),
images: omitTypename<any>(images), images: omitTypename<any>(images),
is_active : values.is_active === "publish" ? true : false , is_active : values.is_active === "publish" ? true : false ,
discount : `${values.discount}` ,
discount : values.discount ,
...(product_type?.value === ProductType?.Simple && { ...(product_type?.value === ProductType?.Simple && {
quantity, quantity,
...(is_digital && { ...(is_digital && {

18
src/contexts/WebSocket.context.tsx

@ -8,7 +8,8 @@ import React, {
} from "react"; } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useMeQuery } from "@/data/user"; import { useMeQuery } from "@/data/user";
import { AUTH_CRED } from "@/utils/constants";
import Cookies from "js-cookie";
interface WebSocketData { interface WebSocketData {
event: string; event: string;
token?: string; token?: string;
@ -53,7 +54,7 @@ interface WebSocketProviderProps {
export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({ export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({
children, children,
}) => { }) => {
const { user } = useMeQuery()
// const { data : user } = useMeQuery()
const [chatRooms, setChatRooms] = useState<ChatRoom[]>([]); const [chatRooms, setChatRooms] = useState<ChatRoom[]>([]);
const [roomInfo, setRoomInfo] = useState<ChatRoom[]>([]); const [roomInfo, setRoomInfo] = useState<ChatRoom[]>([]);
const [messages, setMessages] = useState<[]>([]); const [messages, setMessages] = useState<[]>([]);
@ -69,24 +70,26 @@ export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({
const { const {
query: { slug }, query: { slug },
} = router; } = router;
const token = Cookies.get(AUTH_CRED)
const getRooms = () => { const getRooms = () => {
socketRef.current?.send( socketRef.current?.send(
JSON.stringify({ JSON.stringify({
event: "get_rooms", event: "get_rooms",
account_type: "user",
account_type: "merchant",
page: "1", page: "1",
per_page: "16", per_page: "16",
} as WebSocketData) } as WebSocketData)
); );
}; };
console.log(user);
console.log(token);
useEffect(() => { useEffect(() => {
socketRef.current = new WebSocket("wss://mesbahi.nwhco.ir/chat/ws"); socketRef.current = new WebSocket("wss://mesbahi.nwhco.ir/chat/ws");
setMessages([]); setMessages([]);
if (user?.token) {
if (token) {
socketRef.current.onopen = () => { socketRef.current.onopen = () => {
console.log("WebSocket Connected"); console.log("WebSocket Connected");
@ -94,7 +97,7 @@ export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({
socketRef.current?.send( socketRef.current?.send(
JSON.stringify({ JSON.stringify({
event: "connect", event: "connect",
token: user?.token, // Pass user token
token: JSON.parse(token),
}) })
); );
if (socketRef.current?.readyState === WebSocket.OPEN) { if (socketRef.current?.readyState === WebSocket.OPEN) {
@ -179,7 +182,7 @@ export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({
socketRef.current.close(); socketRef.current.close();
} }
}; };
}, [user, userID]);
}, [token , userID]);
const getNextPage = () => { const getNextPage = () => {
setNextPage((prevPage) => { setNextPage((prevPage) => {
@ -244,6 +247,7 @@ export const WebSocketProvider: React.FC<WebSocketProviderProps> = ({
}, },
id?: number id?: number
) => { ) => {
if (socketRef.current && connected) { if (socketRef.current && connected) {
if (!file) return; // Avoid sending empty messages if (!file) return; // Avoid sending empty messages

2
src/data/client/user.ts

@ -28,6 +28,8 @@ export const userClient = {
return HttpClient.get<User>(API_ENDPOINTS.ME); return HttpClient.get<User>(API_ENDPOINTS.ME);
}, },
login: (variables: {password : string ,phone_number : string , user_type: 'merchant'}) => { login: (variables: {password : string ,phone_number : string , user_type: 'merchant'}) => {
console.log("LOGING IN");
return HttpClient.post<AuthResponse>(API_ENDPOINTS.TOKEN, variables); return HttpClient.post<AuthResponse>(API_ENDPOINTS.TOKEN, variables);
}, },
logout: () => { logout: () => {

2
src/data/shop.ts

@ -96,6 +96,8 @@ export const useShopQuery = (options?: any) => {
return useQuery<Shop, Error>( return useQuery<Shop, Error>(
API_ENDPOINTS.GET_SHOPS, API_ENDPOINTS.GET_SHOPS,
() => shopClient.get().then((data) => { () => shopClient.get().then((data) => {
console.log(data);
return data; return data;
}), }),
{ {

4
src/pages/chat/chat-box.tsx

@ -1,6 +1,6 @@
import ContactInfo from "@/components/chat/contact-info"; import ContactInfo from "@/components/chat/contact-info";
import MessageList from "@/components/chat/messages-list"; import MessageList from "@/components/chat/messages-list";
import Input from "@/components/ui/input";
import Input from "@/components/chat/chat-input";
import { useWebSocket } from "@/contexts/WebSocket.context"; import { useWebSocket } from "@/contexts/WebSocket.context";
import noMessages from "public/image/Frame 1000005529.svg"; import noMessages from "public/image/Frame 1000005529.svg";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@ -25,7 +25,7 @@ export default function ChatBox({ product , searchValue }) {
} }
return ( return (
<div className="relative flex flex-col w-full h-[calc(100%+65px)] bg-white shadow-md border border-[#D9D9D9]">
<div className="relative flex flex-col w-full h-[calc(100%+62px)] bg-white shadow-md border border-[#D9D9D9]">
<ContactInfo /> <ContactInfo />
<div className="relative flex h-full"> <div className="relative flex h-full">

2
src/pages/chat/converstions.tsx

@ -54,7 +54,7 @@ export default function Conversations() {
}; };
return ( return (
<div className="border border-[#D9D9D9] h-[calc(100%+65px)]">
<div className="border border-[#D9D9D9] h-[calc(100%+62px)]">
<div className="bg-white shadow rounded-md h-full w-[450px] mx-auto"> <div className="bg-white shadow rounded-md h-full w-[450px] mx-auto">
{/* Header Section */} {/* Header Section */}
<div className="border-b border-[#D9D9D9] justify-end flex flex-row-reverse h-24 items-center p-4"> <div className="border-b border-[#D9D9D9] justify-end flex flex-row-reverse h-24 items-center p-4">

27
src/pages/shop/index.tsx

@ -40,6 +40,7 @@ import { useFormatPhoneNumber } from '@/utils/format-phone-number';
import { useSettingsQuery } from '@/data/settings'; import { useSettingsQuery } from '@/data/settings';
import { IosArrowDown } from '@/components/icons/ios-arrow-down'; import { IosArrowDown } from '@/components/icons/ios-arrow-down';
import { OWNERSHIP_TRANSFER_STATUS } from '@/utils/constants'; import { OWNERSHIP_TRANSFER_STATUS } from '@/utils/constants';
import { useGetActiveSubscription } from '@/data/subscription';
export default function ShopPage() { export default function ShopPage() {
const router = useRouter(); const router = useRouter();
@ -53,12 +54,8 @@ export default function ShopPage() {
const { settings } = useSettingsQuery({ const { settings } = useSettingsQuery({
language: locale!, language: locale!,
}); });
const {
data,
isLoading: loading,
error,
} = useShopQuery();
console.log(data);
const { data, isLoading: loading, error } = useShopQuery();
const {data : subscription} = useGetActiveSubscription()
const { price: totalEarnings } = usePrice( const { price: totalEarnings } = usePrice(
data && { data && {
@ -79,7 +76,6 @@ export default function ShopPage() {
if (error) return <ErrorMessage message={error.message} />; if (error) return <ErrorMessage message={error.message} />;
const { const {
name, name,
is_active,
logo, logo,
cover_image, cover_image,
description, description,
@ -93,13 +89,11 @@ export default function ShopPage() {
id: shop_id, id: shop_id,
ownership_history, ownership_history,
} = data ?? {}; } = data ?? {};
const has_shop = data?.detail !== 'No merchant associated with this merchant account.';
if (
!hasAccess(adminOnly, permissions) &&
!me?.shops?.map((shop) => shop.id).includes(shop_id) &&
me?.managed_shop?.id != shop_id
) {
router.replace(Routes.dashboard);
const is_active = subscription?.status !== "no_subscription"
if (!has_shop) {
router.replace(Routes.shop.create);
} }
return ( return (
@ -203,10 +197,12 @@ export default function ShopPage() {
<div className="self-end pt-4 xl:pt-0 space-x-4"> <div className="self-end pt-4 xl:pt-0 space-x-4">
<Link <Link
className="inline-flex items-center gap-1 rounded-full bg-accent px-[0.625rem] py-[0.5625rem] text-xs font-medium text-white hover:bg-accent-hover" className="inline-flex items-center gap-1 rounded-full bg-accent px-[0.625rem] py-[0.5625rem] text-xs font-medium text-white hover:bg-accent-hover"
href={`/shop/edit`}
href={has_shop ? `/shop/edit` : `/shop/create`}
> >
<EditFillIcon /> <EditFillIcon />
{t('common:text-edit-shop')}
{!has_shop
? t('common:text-edit-shop')
: t('common:text-create-shop')}
</Link> </Link>
{!OWNERSHIP_TRANSFER_STATUS?.includes( {!OWNERSHIP_TRANSFER_STATUS?.includes(
@ -308,4 +304,3 @@ export const getStaticProps = async ({ locale }: any) => ({
...(await serverSideTranslations(locale, ['form', 'common', 'table'])), ...(await serverSideTranslations(locale, ['form', 'common', 'table'])),
}, },
}); });
Loading…
Cancel
Save