change
This commit is contained in:
parent
eee88e7482
commit
e346485768
|
|
@ -1,11 +1,11 @@
|
|||
# Hijabi Dashboard
|
||||
# DM Dashboard
|
||||
|
||||
## Installation
|
||||
|
||||
1. Clone the repository and navigate into the project directory:
|
||||
|
||||
```bash
|
||||
git clone https://repos.point-dev.net/Karimaldeen/hijabi-dashboard.git
|
||||
cd hijabi-dashboard
|
||||
git clone https://repos.point-dev.net/Karimaldeen/DM-dashboard.git
|
||||
cd DM-dashboard
|
||||
pnpm install
|
||||
pnpm start
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@
|
|||
content="Web site created using create-react-app"
|
||||
/>
|
||||
|
||||
<title>Hijab - App</title>
|
||||
<title>DM - App</title>
|
||||
</head>
|
||||
<script type="module" src="/src/index.tsx"></script>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
|
|
@ -68,8 +68,8 @@
|
|||
"zustand": "^4.4.5"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"start": "vite --port=3000",
|
||||
"build": "vite build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"g:api": "node src/Extensions/FileGenerator/generateApi.js",
|
||||
|
|
@ -99,6 +99,8 @@
|
|||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-toggle": "^4.0.5"
|
||||
"@types/react-toggle": "^4.0.5",
|
||||
"@vitejs/plugin-react": "^4.3.1",
|
||||
"vite": "^5.2.13"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
BIN
public/Logo.png
BIN
public/Logo.png
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 32 KiB |
BIN
public/Logo2.png
Normal file
BIN
public/Logo2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 KiB |
26
src/Hooks/useSocketTracker.ts
Normal file
26
src/Hooks/useSocketTracker.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import React from "react";
|
||||
import { getSocket } from "../lib/SocketProvider";
|
||||
|
||||
function useSocketTracker() {
|
||||
const isLocal = true;
|
||||
|
||||
if (!isLocal) {
|
||||
return;
|
||||
}
|
||||
|
||||
const socket = getSocket();
|
||||
|
||||
socket.on("connect", () => {
|
||||
console.log("CONNECT");
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
console.log("DISCONNECT");
|
||||
});
|
||||
|
||||
socket.onAny((event, ...arg) => {
|
||||
console.log("EVENT ", event, arg);
|
||||
});
|
||||
}
|
||||
|
||||
export default useSocketTracker;
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,26 +1,25 @@
|
|||
import React from 'react';
|
||||
import { Button, Result } from 'antd';
|
||||
import { useTranslation } from 'react-i18next'; // Import useTranslation hook
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useQueryClient } from 'react-query';
|
||||
const ErrorPage: React.FC = () => {
|
||||
const { t } = useTranslation(); // Initialize useTranslation hook
|
||||
const naviagate = useNavigate()
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate()
|
||||
const location = useLocation();
|
||||
const queryClient = useQueryClient(); // Initialize useQueryClient hook
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
|
||||
const handleRefetch = () => {
|
||||
|
||||
const firstPath = location.pathname.split('/')[1]; // Get the first path segment from the URL
|
||||
console.log(firstPath,"firstPath");
|
||||
const firstPath = location.pathname.split('/')[1];
|
||||
|
||||
queryClient.invalidateQueries(firstPath === "/" ? 'home' : firstPath);
|
||||
};
|
||||
|
||||
const handleGoToLogin = () => {
|
||||
naviagate("/")
|
||||
navigate("/")
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ const Sidebar: React.FC<SidebarProps> = () => {
|
|||
<div className={isOpenSide ? 'SideBar SideBar_Open' : 'SideBar noOpen'}>
|
||||
<div className='SideBar_Top'>
|
||||
<div onClick={handleImg}>
|
||||
<img src="../Logo.svg" width={isOpenSide ? 70 : 130} alt="" />
|
||||
<img src="../Logo.png" width={isOpenSide ? 70 : 130} alt="" />
|
||||
{/* <Etaxi/> */}
|
||||
</div>
|
||||
<div className='HamburgerMenu' onClick={handleHamburgerMenu}>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ const OnSuccess = ()=>{
|
|||
|
||||
return (
|
||||
<div className='LoginForm'>
|
||||
<img className='Logo' src="/Logo.svg" alt="Logo" />
|
||||
<img className='Logo' src="/Logo.png" alt="Logo" />
|
||||
|
||||
<nav className='Login_Nav'>
|
||||
<h5> {t("Login")} </h5>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const Auth = () => {
|
|||
<div className='Auth' style={{ background: `url(${LoginBg})` }}>
|
||||
<div className='In_Auth'>
|
||||
<div className="Left_Col">
|
||||
<img className='Logo' src="../Logo.svg" alt="Logo" />
|
||||
<img className='Logo' src="../Logo.png" alt="Logo" />
|
||||
</div>
|
||||
<div className=" Right_Col ">
|
||||
<LoginForm />
|
||||
|
|
|
|||
|
|
@ -44,7 +44,8 @@ const AddProductPage = () => {
|
|||
acc[obj.Description] = obj.key;
|
||||
return acc;
|
||||
}, {});
|
||||
const jsonString = Object.keys(convertedArray).length === 0 ? null : JSON.stringify(convertedArray);
|
||||
const jsonString = convertedArray && Object.keys(convertedArray).length === 0 ? null : JSON.stringify(convertedArray);
|
||||
|
||||
console.log(jsonString, "jsonString");
|
||||
|
||||
const FileimagesArray = values?.variable?.images?.filter((item: any) => typeof item !== 'string') || [];
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ const ViewProduct = () => {
|
|||
return acc;
|
||||
}, {}) : {};
|
||||
|
||||
const jsonString = Object.keys(convertedArray).length === 0 ? null : JSON.stringify(convertedArray);
|
||||
const jsonString = convertedArray && Object.keys(convertedArray).length === 0 ? null : JSON.stringify(convertedArray);
|
||||
|
||||
const FileimagesArray = values?.variable?.images?.filter((item: any) => typeof item !== 'string') || [];
|
||||
console.log(values?.variable?.images,"values?.variable?.images");
|
||||
|
|
@ -96,8 +96,7 @@ const ViewProduct = () => {
|
|||
});
|
||||
console.log(images,"images");
|
||||
|
||||
console.clear()
|
||||
console.log(images,"images");
|
||||
|
||||
|
||||
const Product = {
|
||||
id:values?.product_id,
|
||||
|
|
@ -113,7 +112,7 @@ const ViewProduct = () => {
|
|||
},
|
||||
price: values?.price,
|
||||
info: jsonString,
|
||||
images:images ?? "",
|
||||
images:images,
|
||||
main_photo:main_photo,
|
||||
_method:"PUT"
|
||||
}
|
||||
|
|
|
|||
33
src/Pages/SupportMessages/AttachmentButton.tsx
Normal file
33
src/Pages/SupportMessages/AttachmentButton.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import React, { useState, ChangeEvent } from 'react';
|
||||
import { TiAttachment } from "react-icons/ti";
|
||||
|
||||
const FileUploadButton: React.FC = () => {
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
console.log(file);
|
||||
|
||||
const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.files && event.target.files.length > 0) {
|
||||
setFile(event.target.files[0]);
|
||||
}
|
||||
};
|
||||
const handel_add_file = ()=>{
|
||||
document.getElementById('fileInput')?.click()
|
||||
}
|
||||
return (
|
||||
<div style={{ height:"40px" , width:"40px",display:"flex" , justifyContent:"center" , alignItems:"center"}} >
|
||||
<input
|
||||
type="file"
|
||||
id="fileInput"
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
<TiAttachment size={20} onClick={handel_add_file}/>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FileUploadButton;
|
||||
|
||||
54
src/Pages/SupportMessages/Chat.tsx
Normal file
54
src/Pages/SupportMessages/Chat.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import React, { FormEvent } from 'react';
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { SOCKET } from "../../enums/Socket";
|
||||
import useChatSocket from './useChatSocket';
|
||||
import { Message } from '../../types/socket';
|
||||
import AttachmentButton from './AttachmentButton';
|
||||
|
||||
const Chat = () => {
|
||||
const [t] = useTranslation();
|
||||
const { messages, input, setInput, sendMessage, messagesEndRef } = useChatSocket();
|
||||
|
||||
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
sendMessage(input);
|
||||
setInput("");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="chat">
|
||||
<main>
|
||||
{messages?.length > 0 && (
|
||||
<div className="messages">
|
||||
{messages.map((msg: Message, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={
|
||||
msg.type === SOCKET.INCOMING
|
||||
? SOCKET.INCOMING
|
||||
: SOCKET.OUTGOING
|
||||
}
|
||||
>
|
||||
{msg.text}
|
||||
</div>
|
||||
))}
|
||||
<div className="messagesEndRef" ref={messagesEndRef}></div>
|
||||
</div>
|
||||
)}
|
||||
<form className='socket_form' onSubmit={handleSubmit}>
|
||||
<input
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
className="socket_input"
|
||||
placeholder={t("Enter your model name")}
|
||||
type="text"
|
||||
/>
|
||||
<AttachmentButton/>
|
||||
|
||||
</form>
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Chat;
|
||||
|
|
@ -1,45 +1,44 @@
|
|||
|
||||
import React from 'react'
|
||||
import DashBody from '../../Layout/Dashboard/DashBody'
|
||||
import DashHeader from '../../Layout/Dashboard/DashHeader'
|
||||
import LyTable from '../../Layout/Dashboard/LyTable'
|
||||
import useTableColumns from './useTableColumns'
|
||||
import { QueryStatusEnum } from '../../config/QueryStatus'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import AddButton from '../../Layout/Dashboard/AddButton/AddButton'
|
||||
import { useGetSupportMessages } from '../../api/supportmessages'
|
||||
import SearchField from '../../Layout/Dashboard/SearchField'
|
||||
import React, { useState } from 'react';
|
||||
import { Data } from './fakeData';
|
||||
import Chat from './Chat';
|
||||
import AttachmentButton from './AttachmentButton';
|
||||
|
||||
function Page() {
|
||||
const [selected_user, set_selected_user] = useState(null);
|
||||
|
||||
const column =useTableColumns()
|
||||
const {data ,status } = useGetSupportMessages()
|
||||
const navigate = useNavigate()
|
||||
const totalRows = data?.meta?.total;
|
||||
const handle_select_chat = (item: any) => {
|
||||
set_selected_user(item?.id);
|
||||
};
|
||||
|
||||
return (
|
||||
// Pass Status to Layout
|
||||
<DashBody status={status as QueryStatusEnum} >
|
||||
<DashHeader showAddButton={false} title={'SupportMessages'}>
|
||||
<div className='RightSide d-flex gap-2 align-center '>
|
||||
<SearchField searchBy={"email"} />
|
||||
|
||||
{/* <AddButton onClick={()=>navigate('/support_messages/add')}></AddButton> */}
|
||||
<div className='support_message'>
|
||||
<div className='support_message_left'>
|
||||
<span>
|
||||
<input type="text" placeholder='search' />
|
||||
</span>
|
||||
<div className="user_profiles">
|
||||
{Data?.map((item, index) => {
|
||||
return (
|
||||
<div
|
||||
key={index}
|
||||
onClick={() => handle_select_chat(item)}
|
||||
className={item?.id === selected_user ? 'user_profile user_profile_active' : " user_profile "}
|
||||
>
|
||||
<img src={item?.image} alt="" />
|
||||
<div className=''>
|
||||
<h1>{item?.name}</h1>
|
||||
<p>{item?.lastMessage}</p>
|
||||
</div>
|
||||
</DashHeader>
|
||||
|
||||
<LyTable
|
||||
data={data?.data}
|
||||
isLoading={false}
|
||||
columns={column}
|
||||
total={totalRows }
|
||||
is_pagination={true}
|
||||
/>
|
||||
|
||||
|
||||
</DashBody>
|
||||
)
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
<div className='support_message_right'>
|
||||
{selected_user ? <Chat /> : <div className='select_message'><h1>Select chat to start messaging</h1></div>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Page
|
||||
|
||||
export default Page;
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
|
||||
import React, { useEffect } from 'react'
|
||||
import { Col, Row } from 'reactstrap';
|
||||
import ValidationField from '../../../Components/ValidationField/ValidationField';
|
||||
import { useGetUsers } from '../../../api/users';
|
||||
import { useFormikContext } from 'formik';
|
||||
|
||||
function Form() {
|
||||
const useFormatToSelect = (Data : any) => {
|
||||
const format = (data :any) => {
|
||||
if (!data) return [];
|
||||
return data.map((item :any) => ({
|
||||
value: item?.id,
|
||||
label: item?.name,
|
||||
}));
|
||||
};
|
||||
|
||||
return format(Data);
|
||||
};
|
||||
const { data: user } = useGetUsers()
|
||||
|
||||
const SelectData = useFormatToSelect(user?.data)
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Row xs={1} sm={1} md={1} lg={2} xl={2}>
|
||||
<Col>
|
||||
|
||||
<ValidationField name="id" label='user' placeholder='user' type="Search" option={SelectData} searchBy={"name"} />
|
||||
|
||||
<ValidationField name="whatsApp" />
|
||||
|
||||
</Col>
|
||||
<Col>
|
||||
|
||||
<ValidationField name="subject" />
|
||||
<ValidationField name="message" type='TextArea'/>
|
||||
|
||||
</Col>
|
||||
|
||||
|
||||
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default Form
|
||||
|
||||
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
import { getInitialValues, getValidationSchema, getDataToSend } from '../formUtil'
|
||||
import { Tab, TabList, TabPanel as TabBody, Tabs } from 'react-tabs'
|
||||
import 'react-tabs/style/react-tabs.css';
|
||||
import { MdLanguage } from 'react-icons/md'
|
||||
import ViewPage from '../../../Layout/Dashboard/ViewPage';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useNavigateOnSuccess from '../../../Hooks/useNavigateOnSuccess';
|
||||
import { useAddSupportMessages } from '../../../api/supportmessages';
|
||||
import Form from './AddForm';
|
||||
|
||||
const AddSupportMessagesPage = () => {
|
||||
|
||||
|
||||
const {mutate , isLoading:IsloadingButton , isSuccess} = useAddSupportMessages()
|
||||
const handleSubmit = (values:any)=>{
|
||||
console.log(values,"values");
|
||||
|
||||
mutate(values)
|
||||
|
||||
|
||||
}
|
||||
const {t} = useTranslation();
|
||||
|
||||
useNavigateOnSuccess(isSuccess , '/SupportMessages' )
|
||||
|
||||
|
||||
|
||||
const ViewProps = { getInitialValues, getValidationSchema, getDataToSend, handleSubmit,IsloadingButton };
|
||||
|
||||
|
||||
return (
|
||||
<div className='ViewPage'>
|
||||
|
||||
<ViewPage {...ViewProps}>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab><div className='Tab_Info_Container'><span className='SignleDriverInfoIcon'><MdLanguage size={20} /></span> <h6 className='Tab_Info'>{t("BasicInfo")}</h6></div></Tab>
|
||||
|
||||
|
||||
|
||||
</TabList>
|
||||
<TabBody >
|
||||
<div className=" mt-4"><Form /></div>
|
||||
</TabBody>
|
||||
|
||||
</Tabs>
|
||||
</ViewPage>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
export default AddSupportMessagesPage
|
||||
67
src/Pages/SupportMessages/fakeData.ts
Normal file
67
src/Pages/SupportMessages/fakeData.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
export const Data = [
|
||||
{
|
||||
id: 1,
|
||||
name: "Mohammed",
|
||||
image: "/Logo.png",
|
||||
lastMessage: "Hey, how are you?",
|
||||
timestamp: "2024-06-10 12:34",
|
||||
status: "online"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: "Aisha",
|
||||
image: "/Logo.png",
|
||||
lastMessage: "Let's meet tomorrow. sadasdasd",
|
||||
timestamp: "2024-06-10 11:30",
|
||||
status: "offline"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Ali",
|
||||
image: "/Logo.png",
|
||||
lastMessage: "Got it, thanks!",
|
||||
timestamp: "2024-06-09 18:22",
|
||||
status: "offline"
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Ali",
|
||||
image: "/Logo.png",
|
||||
lastMessage: "Got it, thanks!",
|
||||
timestamp: "2024-06-09 18:22",
|
||||
status: "offline"
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: "Ali",
|
||||
image: "/Logo.png",
|
||||
lastMessage: "Got it, thanks!",
|
||||
timestamp: "2024-06-09 18:22",
|
||||
status: "offline"
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: "Ali",
|
||||
image: "/Logo.png",
|
||||
lastMessage: "Got it, thanks!",
|
||||
timestamp: "2024-06-09 18:22",
|
||||
status: "offline"
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: "Ali",
|
||||
image: "/Logo.png",
|
||||
lastMessage: "Got it, thanks!",
|
||||
timestamp: "2024-06-09 18:22",
|
||||
status: "offline"
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: "Ali",
|
||||
image: "/Logo.png",
|
||||
lastMessage: "Got it, thanks!",
|
||||
timestamp: "2024-06-09 18:22",
|
||||
status: "offline"
|
||||
},
|
||||
|
||||
]
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
|
||||
import * as Yup from "yup";
|
||||
import { buildFormData } from "../../api/helper/buildFormData";
|
||||
|
||||
export const getInitialValues = (objectToEdit: any | null = null): any => {
|
||||
console.log(objectToEdit,"objectToEdit");
|
||||
return {
|
||||
whatsApp: "",
|
||||
subject: "",
|
||||
message: "",
|
||||
id:null,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
export const getValidationSchema = (editMode: boolean = false): Yup.Schema<any> => {
|
||||
// Validate input
|
||||
return Yup.object().shape({
|
||||
whatsApp: Yup.string().required('Required'),
|
||||
subject: Yup.string().required('Required'),
|
||||
message: Yup.string().required('Required'),
|
||||
id: Yup.string().required('Required'),
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const getDataToSend = (values: any): FormData => {
|
||||
const data = { ...values };
|
||||
|
||||
|
||||
const formData = new FormData();
|
||||
buildFormData(formData, data);
|
||||
return formData;
|
||||
};
|
||||
|
||||
export const ChangeDataToPrint = (data:any)=>{
|
||||
|
||||
let new_array = data
|
||||
for(let i =0 ; i<data.length ; i++){
|
||||
new_array[i]['status'] =!data[i]['deleted_at'] ?'available':'unavailable'
|
||||
delete new_array[i]['deleted_at']
|
||||
}
|
||||
return new_array
|
||||
}
|
||||
50
src/Pages/SupportMessages/useChatSocket.ts
Normal file
50
src/Pages/SupportMessages/useChatSocket.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { useEffect, useState, useRef } from 'react';
|
||||
import { disconnectSocket, getSocket } from "../../lib/SocketProvider";
|
||||
import { SOCKET } from "../../enums/Socket";
|
||||
import { Message } from '../../types/socket';
|
||||
|
||||
|
||||
const useChatSocket = () => {
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
const [input, setInput] = useState<string>("");
|
||||
const messagesEndRef = useRef<HTMLDivElement>(null);
|
||||
const Socket = getSocket();
|
||||
|
||||
const scrollToBottom = () => {
|
||||
if (messagesEndRef.current) {
|
||||
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
Socket.on(SOCKET.EVENT_SEND_MESSAGE, (msg: string) => {
|
||||
setMessages((prevMessages) => [
|
||||
...prevMessages,
|
||||
{ type: SOCKET.INCOMING, text: msg },
|
||||
]);
|
||||
});
|
||||
|
||||
return () => {
|
||||
disconnectSocket();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
scrollToBottom();
|
||||
}, [messages]);
|
||||
|
||||
const sendMessage = (msg: string) => {
|
||||
if (msg.trim()) {
|
||||
|
||||
Socket.emit(SOCKET.EVENT_SEND_MESSAGE, msg);
|
||||
setMessages((prevMessages) => [
|
||||
...prevMessages,
|
||||
{ type: SOCKET.OUTGOING, text: msg },
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
return { messages, input, setInput, sendMessage, messagesEndRef };
|
||||
};
|
||||
|
||||
export default useChatSocket;
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
|
||||
import React, { useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Actions from "../../Components/Ui/tables/Actions";
|
||||
import ColumnsImage from "../../Components/Columns/ColumnsImage";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useDeleteSupportMessages } from "../../api/supportmessages";
|
||||
|
||||
|
||||
const useTableColumns :any = () => {
|
||||
const [t] = useTranslation();
|
||||
const deleteMutation = useDeleteSupportMessages()
|
||||
const navigate = useNavigate()
|
||||
|
||||
return useMemo(
|
||||
() => [
|
||||
|
||||
{
|
||||
name: t("email"),
|
||||
center: true,
|
||||
selector: (row: any) => row.email, // Specify selector function for sorting
|
||||
},
|
||||
|
||||
{
|
||||
name: t("whatsApp"),
|
||||
center: true,
|
||||
selector: (row: any) => row.whatsApp, // Specify selector function for sorting
|
||||
},
|
||||
|
||||
{
|
||||
name: t("subject"),
|
||||
center: true,
|
||||
selector: (row: any) => row.subject, // Specify selector function for sorting
|
||||
},
|
||||
{
|
||||
name: t("message"),
|
||||
center: true,
|
||||
selector: (row: any) => row.message, // Specify selector function for sorting
|
||||
},
|
||||
{
|
||||
name: "#",
|
||||
sortable: false,
|
||||
center: true,
|
||||
cell: (row:any) => (
|
||||
<Actions
|
||||
objectToEdit={row}
|
||||
|
||||
onEdit={()=> navigate(`/support_messages/${row.id}`) }
|
||||
showView={false}
|
||||
showEdit={false}
|
||||
onDelete={() => deleteMutation.mutate({ id: row.id })}
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
||||
],
|
||||
[t]
|
||||
);
|
||||
};
|
||||
|
||||
export default useTableColumns;
|
||||
|
||||
|
|
@ -32,7 +32,6 @@ import EditSlider from "./Pages/Slider/View/EditPage";
|
|||
|
||||
|
||||
import SupportMessagesPage from "./Pages/SupportMessages/Page";
|
||||
import AddSupportMessagesPage from "./Pages/SupportMessages/View/AddPage";
|
||||
// import EditSupportMessages from "./Pages/SupportMessages/View/EditPage";
|
||||
|
||||
import UsersPage from "./Pages/Users/Page";
|
||||
|
|
@ -184,21 +183,17 @@ export const RoutesLinks: RoutesLinksType[] = [
|
|||
element: <AddNotificationPage />,
|
||||
hidden:true
|
||||
},
|
||||
{
|
||||
name: "SupportMessages",
|
||||
element: <SupportMessagesPage />,
|
||||
icon: <MessageOutlined />,
|
||||
href: "/support_messages",
|
||||
},
|
||||
// {
|
||||
// name: "SupportMessages",
|
||||
// element: <SupportMessagesPage />,
|
||||
// icon: <MessageOutlined />,
|
||||
// href: "/support_messages",
|
||||
// },
|
||||
// {
|
||||
// href: "/support_messages/:id",
|
||||
// element: <EditSupportMessages />,
|
||||
// hidden:true
|
||||
// },
|
||||
{
|
||||
href: "/support_messages/add",
|
||||
element: <AddSupportMessagesPage />,
|
||||
hidden:true
|
||||
},
|
||||
|
||||
|
||||
]
|
||||
|
|
@ -17,6 +17,6 @@
|
|||
|
||||
@import '../Layout/FillterSection.scss';
|
||||
|
||||
|
||||
@import '../page/SupportMessage.scss'
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -19,3 +19,23 @@
|
|||
background-color: rgba(16 18 27 / 40%);
|
||||
backdrop-filter: blur(24px);
|
||||
}
|
||||
@mixin Scrollbar() {
|
||||
scroll-behavior: smooth;
|
||||
scroll-padding: 10rem;
|
||||
&::-webkit-scrollbar {
|
||||
width: 0.4vw;
|
||||
max-height: 10px;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background-color: var(--secondary);
|
||||
border-radius: 5px; /* Adjust border-radius as needed */
|
||||
}
|
||||
|
||||
/* Track */
|
||||
&::-webkit-scrollbar-track {
|
||||
border-radius: 5px; /* Adjust border-radius as needed */
|
||||
background-color: #d3d5d7; /* Set to desired background color */
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
:root {
|
||||
--primary:red ;
|
||||
--primary:#eb671b ;
|
||||
--secondary : #565656;
|
||||
--text: #565656;
|
||||
--bg: #ffffff;
|
||||
--bg2: #f8f8f8;
|
||||
--shadow: rgba(0, 0, 0, 0.15);
|
||||
--gray : rgb(207, 210, 214);
|
||||
--gray : #e6e5eb54;
|
||||
--linear : linear-gradient(118deg, #2D9CDB, #2D9CDB)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,13 +36,17 @@ overflow-x: hidden;
|
|||
}
|
||||
|
||||
.SideBar_Top {
|
||||
@include Flex;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-block: 20px;
|
||||
width: 100%;
|
||||
color: var(--primary);
|
||||
z-index: 9999999;
|
||||
img{
|
||||
margin-inline: 10px;
|
||||
width: 60px;
|
||||
width: 40px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
.HamburgerMenu{
|
||||
z-index: 999999999999999;
|
||||
|
|
|
|||
156
src/Styles/page/SupportMessage.scss
Normal file
156
src/Styles/page/SupportMessage.scss
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
.support_message{
|
||||
background-color: var(--bg);
|
||||
@include Shadow;
|
||||
display: flex;
|
||||
|
||||
gap: 5%;
|
||||
padding: 2% 2% 8% 2%;
|
||||
border-radius: 2%;
|
||||
.support_message_left{
|
||||
min-width: 250px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
max-height: 60vh;
|
||||
overflow-y: scroll ;
|
||||
@include Scrollbar;
|
||||
>span{
|
||||
>input{
|
||||
all: unset;
|
||||
max-width: 180px;
|
||||
height: 40px;
|
||||
padding-inline: 20px;
|
||||
border-radius: 29px;
|
||||
color: black;
|
||||
background:var(--gray);
|
||||
|
||||
}
|
||||
}
|
||||
.user_profiles{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// padding-inline: 20px;
|
||||
// border-right: 1px solid gray;
|
||||
.user_profile_active{
|
||||
background: var(--gray);
|
||||
|
||||
}
|
||||
.user_profile{
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
padding: 10px 20px;
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
background: var(--gray);
|
||||
}
|
||||
|
||||
>img{
|
||||
border-radius: 50%;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
>div{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 75%;
|
||||
h1{
|
||||
font-size: 20px;
|
||||
margin-bottom: 0;
|
||||
|
||||
|
||||
}
|
||||
p{
|
||||
font-size: 14px;
|
||||
margin-bottom: 0;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.support_message_right{
|
||||
width: 100%;
|
||||
// align-self: flex-end;
|
||||
|
||||
&:has(input){
|
||||
align-self: flex-end;
|
||||
}
|
||||
div{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
}
|
||||
.messages {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
overflow-y: auto;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 20px 20px;
|
||||
max-height: 60vh;
|
||||
|
||||
.incoming {
|
||||
background-color: var(--gray);
|
||||
color: var(--text);
|
||||
padding: 15px;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
border-bottom-right-radius: 10px;
|
||||
font-size: 13px;
|
||||
width: fit-content;
|
||||
}
|
||||
.outgoing {
|
||||
direction: rtl;
|
||||
align-self: flex-end;
|
||||
background-color: var(--gray);
|
||||
color: var(--text);
|
||||
padding: 15px;
|
||||
border-top-left-radius: 10px;
|
||||
border-top-right-radius: 10px;
|
||||
border-bottom-left-radius: 10px;
|
||||
font-size: 13px;
|
||||
width: fit-content;
|
||||
|
||||
}
|
||||
.socket_input {
|
||||
background: var(--gray);
|
||||
outline: none;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 6px 10px;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
|
||||
color: var(--text);
|
||||
&::placeholder {
|
||||
color: #9f9f9f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select_message{
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
>h1{
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.socket_form{
|
||||
display: flex;
|
||||
|
||||
}
|
||||
|
|
@ -5,15 +5,20 @@ export const BaseURL = `https://back-demo.dmmobiles.com/api/`;
|
|||
export const ImageBaseURL = `https://back-demo.dmmobiles.com`;
|
||||
|
||||
|
||||
// export const BaseURL = `http://192.168.1.112:8000/api/`;
|
||||
// export const ImageBaseURL = `http://192.168.1.112:8000`;
|
||||
// export const BaseURL = `http://192.168.1.122:8000/api/`;
|
||||
// export const ImageBaseURL = `http://192.168.1.122:8000`;
|
||||
|
||||
export const BaseURL_IMAGE = BaseURL.slice(0,-1);
|
||||
|
||||
|
||||
const PROJECT_NAME = "Hijab"
|
||||
|
||||
|
||||
|
||||
const PROJECT_NAME = "DM_DAHBOARD"
|
||||
|
||||
export const TOKEN_KEY = PROJECT_NAME + "_TOKEN"
|
||||
export const TOKEN_KEY_SOCKET = PROJECT_NAME + "_SOKCET_TOKEN"
|
||||
|
||||
|
||||
|
||||
export const USER_KEY = PROJECT_NAME + "_USER"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
|
||||
|
||||
|
||||
const PROJECT_NAME = "Hijab_DAHBOARD"
|
||||
|
||||
export const TOKEN_KEY = PROJECT_NAME + "_TOKEN"
|
||||
export const TOKEN_KEY_SOCKET = PROJECT_NAME + "_SOKCET_TOKEN"
|
||||
|
||||
export const USER_KEY = PROJECT_NAME + "_USER"
|
||||
|
||||
|
||||
/// 1825|laravel_sanctum_RpRqXDf1jg1Jgb0VjnJcUzPpSmX46PD7h8jB8ag372d0778a
|
||||
6
src/enums/Socket.ts
Normal file
6
src/enums/Socket.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export enum SOCKET {
|
||||
EVENT_SEND_MESSAGE = "chat_message",
|
||||
INCOMING = "incoming",
|
||||
OUTGOING = "outgoing",
|
||||
}
|
||||
|
||||
|
|
@ -1,37 +1,28 @@
|
|||
const BASE_URL = "ws://localhost:9000";
|
||||
|
||||
import { Socket, io } from 'socket.io-client';
|
||||
import { TOKEN_KEY_SOCKET } from '../config/AppKey';
|
||||
import { io, Socket } from "socket.io-client";
|
||||
import { TOKEN_KEY } from "../api/config";
|
||||
|
||||
var socket: null | Socket = null;
|
||||
export const getSocket = () => {
|
||||
const token = localStorage.getItem(TOKEN_KEY)
|
||||
|
||||
export const BASE_URL_SOCKET = 'http://192.168.1.14:8001/';
|
||||
var socket :Socket | null = null ;
|
||||
|
||||
|
||||
function InitSocket(){
|
||||
|
||||
|
||||
|
||||
if (!socket){
|
||||
socket = io(BASE_URL_SOCKET , {
|
||||
transports:['websocket'],
|
||||
autoConnect:true,
|
||||
query:{
|
||||
token:localStorage.getItem(TOKEN_KEY_SOCKET),
|
||||
if (!socket) {
|
||||
|
||||
socket = io(BASE_URL, {
|
||||
autoConnect: true,
|
||||
transports: ["websocket"],
|
||||
auth:{
|
||||
token: token,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const disconnectSocket = ()=>{
|
||||
|
||||
socket?.disconnect();
|
||||
socket = null;
|
||||
}
|
||||
export const getScoket = ()=>{
|
||||
|
||||
InitSocket();
|
||||
return socket;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export const disconnectSocket = () => {
|
||||
if (socket) {
|
||||
socket.disconnect();
|
||||
socket = null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import {create} from 'zustand';
|
||||
import { TOKEN_KEY, TOKEN_KEY_SOCKET, USER_KEY } from '../../config/AppKey';
|
||||
import { TOKEN_KEY, TOKEN_KEY_SOCKET, USER_KEY } from '../../api/config';
|
||||
|
||||
interface LoginResponse {
|
||||
token:string ,
|
||||
|
|
@ -20,6 +20,8 @@ const useAuthState = create<AuthStore>((set) => {
|
|||
const storedUser :any = localStorage.getItem(USER_KEY) ;
|
||||
|
||||
const storedToken = localStorage.getItem(TOKEN_KEY);
|
||||
console.log(storedToken);
|
||||
|
||||
const initialUser = (storedUser && storedUser !== 'undefined') ? JSON.parse(storedUser) : null;
|
||||
|
||||
return {
|
||||
|
|
|
|||
4
src/types/socket.ts
Normal file
4
src/types/socket.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export interface Message {
|
||||
type: "incoming" | "outgoing";
|
||||
text: string;
|
||||
}
|
||||
11
vite.config.js
Normal file
11
vite.config.js
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
|
||||
export default defineConfig(() => {
|
||||
return {
|
||||
build: {
|
||||
outDir: 'build',
|
||||
},
|
||||
plugins: [react()],
|
||||
};
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user