change
This commit is contained in:
parent
eee88e7482
commit
e346485768
|
|
@ -1,11 +1,11 @@
|
||||||
# Hijabi Dashboard
|
# DM Dashboard
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Clone the repository and navigate into the project directory:
|
1. Clone the repository and navigate into the project directory:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://repos.point-dev.net/Karimaldeen/hijabi-dashboard.git
|
git clone https://repos.point-dev.net/Karimaldeen/DM-dashboard.git
|
||||||
cd hijabi-dashboard
|
cd DM-dashboard
|
||||||
pnpm install
|
pnpm install
|
||||||
pnpm start
|
pnpm start
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,10 @@
|
||||||
content="Web site created using create-react-app"
|
content="Web site created using create-react-app"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<title>Hijab - App</title>
|
<title>DM - App</title>
|
||||||
</head>
|
</head>
|
||||||
|
<script type="module" src="/src/index.tsx"></script>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|
||||||
|
|
@ -68,8 +68,8 @@
|
||||||
"zustand": "^4.4.5"
|
"zustand": "^4.4.5"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "vite --port=3000",
|
||||||
"build": "react-scripts build",
|
"build": "vite build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject",
|
"eject": "react-scripts eject",
|
||||||
"g:api": "node src/Extensions/FileGenerator/generateApi.js",
|
"g:api": "node src/Extensions/FileGenerator/generateApi.js",
|
||||||
|
|
@ -99,6 +99,8 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"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 React from 'react';
|
||||||
import { Button, Result } from 'antd';
|
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 { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { useQueryClient } from 'react-query';
|
import { useQueryClient } from 'react-query';
|
||||||
const ErrorPage: React.FC = () => {
|
const ErrorPage: React.FC = () => {
|
||||||
const { t } = useTranslation(); // Initialize useTranslation hook
|
const { t } = useTranslation();
|
||||||
const naviagate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const queryClient = useQueryClient(); // Initialize useQueryClient hook
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
|
||||||
const handleRefetch = () => {
|
const handleRefetch = () => {
|
||||||
|
|
||||||
const firstPath = location.pathname.split('/')[1]; // Get the first path segment from the URL
|
const firstPath = location.pathname.split('/')[1];
|
||||||
console.log(firstPath,"firstPath");
|
|
||||||
|
|
||||||
queryClient.invalidateQueries(firstPath === "/" ? 'home' : firstPath);
|
queryClient.invalidateQueries(firstPath === "/" ? 'home' : firstPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGoToLogin = () => {
|
const handleGoToLogin = () => {
|
||||||
naviagate("/")
|
navigate("/")
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ const Sidebar: React.FC<SidebarProps> = () => {
|
||||||
<div className={isOpenSide ? 'SideBar SideBar_Open' : 'SideBar noOpen'}>
|
<div className={isOpenSide ? 'SideBar SideBar_Open' : 'SideBar noOpen'}>
|
||||||
<div className='SideBar_Top'>
|
<div className='SideBar_Top'>
|
||||||
<div onClick={handleImg}>
|
<div onClick={handleImg}>
|
||||||
<img src="../Logo.svg" width={isOpenSide ? 70 : 130} alt="" />
|
<img src="../Logo.png" width={isOpenSide ? 70 : 130} alt="" />
|
||||||
{/* <Etaxi/> */}
|
{/* <Etaxi/> */}
|
||||||
</div>
|
</div>
|
||||||
<div className='HamburgerMenu' onClick={handleHamburgerMenu}>
|
<div className='HamburgerMenu' onClick={handleHamburgerMenu}>
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ const OnSuccess = ()=>{
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='LoginForm'>
|
<div className='LoginForm'>
|
||||||
<img className='Logo' src="/Logo.svg" alt="Logo" />
|
<img className='Logo' src="/Logo.png" alt="Logo" />
|
||||||
|
|
||||||
<nav className='Login_Nav'>
|
<nav className='Login_Nav'>
|
||||||
<h5> {t("Login")} </h5>
|
<h5> {t("Login")} </h5>
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ const Auth = () => {
|
||||||
<div className='Auth' style={{ background: `url(${LoginBg})` }}>
|
<div className='Auth' style={{ background: `url(${LoginBg})` }}>
|
||||||
<div className='In_Auth'>
|
<div className='In_Auth'>
|
||||||
<div className="Left_Col">
|
<div className="Left_Col">
|
||||||
<img className='Logo' src="../Logo.svg" alt="Logo" />
|
<img className='Logo' src="../Logo.png" alt="Logo" />
|
||||||
</div>
|
</div>
|
||||||
<div className=" Right_Col ">
|
<div className=" Right_Col ">
|
||||||
<LoginForm />
|
<LoginForm />
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,8 @@ const AddProductPage = () => {
|
||||||
acc[obj.Description] = obj.key;
|
acc[obj.Description] = obj.key;
|
||||||
return acc;
|
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");
|
console.log(jsonString, "jsonString");
|
||||||
|
|
||||||
const FileimagesArray = values?.variable?.images?.filter((item: any) => typeof item !== 'string') || [];
|
const FileimagesArray = values?.variable?.images?.filter((item: any) => typeof item !== 'string') || [];
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ const ViewProduct = () => {
|
||||||
return acc;
|
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') || [];
|
const FileimagesArray = values?.variable?.images?.filter((item: any) => typeof item !== 'string') || [];
|
||||||
console.log(values?.variable?.images,"values?.variable?.images");
|
console.log(values?.variable?.images,"values?.variable?.images");
|
||||||
|
|
@ -96,9 +96,8 @@ const ViewProduct = () => {
|
||||||
});
|
});
|
||||||
console.log(images,"images");
|
console.log(images,"images");
|
||||||
|
|
||||||
console.clear()
|
|
||||||
console.log(images,"images");
|
|
||||||
|
|
||||||
const Product = {
|
const Product = {
|
||||||
id:values?.product_id,
|
id:values?.product_id,
|
||||||
name: {
|
name: {
|
||||||
|
|
@ -113,7 +112,7 @@ const ViewProduct = () => {
|
||||||
},
|
},
|
||||||
price: values?.price,
|
price: values?.price,
|
||||||
info: jsonString,
|
info: jsonString,
|
||||||
images:images ?? "",
|
images:images,
|
||||||
main_photo:main_photo,
|
main_photo:main_photo,
|
||||||
_method:"PUT"
|
_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, { useState } from 'react';
|
||||||
import React from 'react'
|
import { Data } from './fakeData';
|
||||||
import DashBody from '../../Layout/Dashboard/DashBody'
|
import Chat from './Chat';
|
||||||
import DashHeader from '../../Layout/Dashboard/DashHeader'
|
import AttachmentButton from './AttachmentButton';
|
||||||
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'
|
|
||||||
|
|
||||||
function Page() {
|
function Page() {
|
||||||
|
const [selected_user, set_selected_user] = useState(null);
|
||||||
|
|
||||||
const column =useTableColumns()
|
const handle_select_chat = (item: any) => {
|
||||||
const {data ,status } = useGetSupportMessages()
|
set_selected_user(item?.id);
|
||||||
const navigate = useNavigate()
|
};
|
||||||
const totalRows = data?.meta?.total;
|
|
||||||
|
|
||||||
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> */}
|
return (
|
||||||
</div>
|
<div className='support_message'>
|
||||||
</DashHeader>
|
<div className='support_message_left'>
|
||||||
|
<span>
|
||||||
<LyTable
|
<input type="text" placeholder='search' />
|
||||||
data={data?.data}
|
</span>
|
||||||
isLoading={false}
|
<div className="user_profiles">
|
||||||
columns={column}
|
{Data?.map((item, index) => {
|
||||||
total={totalRows }
|
return (
|
||||||
is_pagination={true}
|
<div
|
||||||
/>
|
key={index}
|
||||||
|
onClick={() => handle_select_chat(item)}
|
||||||
|
className={item?.id === selected_user ? 'user_profile user_profile_active' : " user_profile "}
|
||||||
</DashBody>
|
>
|
||||||
)
|
<img src={item?.image} alt="" />
|
||||||
|
<div className=''>
|
||||||
|
<h1>{item?.name}</h1>
|
||||||
|
<p>{item?.lastMessage}</p>
|
||||||
|
</div>
|
||||||
|
</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 SupportMessagesPage from "./Pages/SupportMessages/Page";
|
||||||
import AddSupportMessagesPage from "./Pages/SupportMessages/View/AddPage";
|
|
||||||
// import EditSupportMessages from "./Pages/SupportMessages/View/EditPage";
|
// import EditSupportMessages from "./Pages/SupportMessages/View/EditPage";
|
||||||
|
|
||||||
import UsersPage from "./Pages/Users/Page";
|
import UsersPage from "./Pages/Users/Page";
|
||||||
|
|
@ -184,21 +183,17 @@ export const RoutesLinks: RoutesLinksType[] = [
|
||||||
element: <AddNotificationPage />,
|
element: <AddNotificationPage />,
|
||||||
hidden:true
|
hidden:true
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
name: "SupportMessages",
|
// name: "SupportMessages",
|
||||||
element: <SupportMessagesPage />,
|
// element: <SupportMessagesPage />,
|
||||||
icon: <MessageOutlined />,
|
// icon: <MessageOutlined />,
|
||||||
href: "/support_messages",
|
// href: "/support_messages",
|
||||||
},
|
// },
|
||||||
// {
|
// {
|
||||||
// href: "/support_messages/:id",
|
// href: "/support_messages/:id",
|
||||||
// element: <EditSupportMessages />,
|
// element: <EditSupportMessages />,
|
||||||
// hidden:true
|
// hidden:true
|
||||||
// },
|
// },
|
||||||
{
|
|
||||||
href: "/support_messages/add",
|
|
||||||
element: <AddSupportMessagesPage />,
|
|
||||||
hidden:true
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
@ -17,6 +17,6 @@
|
||||||
|
|
||||||
@import '../Layout/FillterSection.scss';
|
@import '../Layout/FillterSection.scss';
|
||||||
|
|
||||||
|
@import '../page/SupportMessage.scss'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,24 @@
|
||||||
@mixin GlassModeCover{
|
@mixin GlassModeCover{
|
||||||
background-color: rgba(16 18 27 / 40%);
|
background-color: rgba(16 18 27 / 40%);
|
||||||
backdrop-filter: blur(24px);
|
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 {
|
:root {
|
||||||
--primary:red ;
|
--primary:#eb671b ;
|
||||||
--secondary : #565656;
|
--secondary : #565656;
|
||||||
--text: #565656;
|
--text: #565656;
|
||||||
--bg: #ffffff;
|
--bg: #ffffff;
|
||||||
--bg2: #f8f8f8;
|
--bg2: #f8f8f8;
|
||||||
--shadow: rgba(0, 0, 0, 0.15);
|
--shadow: rgba(0, 0, 0, 0.15);
|
||||||
--gray : rgb(207, 210, 214);
|
--gray : #e6e5eb54;
|
||||||
--linear : linear-gradient(118deg, #2D9CDB, #2D9CDB)
|
--linear : linear-gradient(118deg, #2D9CDB, #2D9CDB)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,17 @@ overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.SideBar_Top {
|
.SideBar_Top {
|
||||||
@include Flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
margin-block: 20px;
|
margin-block: 20px;
|
||||||
|
width: 100%;
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
z-index: 9999999;
|
z-index: 9999999;
|
||||||
img{
|
img{
|
||||||
margin-inline: 10px;
|
margin-inline: 10px;
|
||||||
width: 60px;
|
width: 40px;
|
||||||
|
border-radius: 20px;
|
||||||
}
|
}
|
||||||
.HamburgerMenu{
|
.HamburgerMenu{
|
||||||
z-index: 999999999999999;
|
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 ImageBaseURL = `https://back-demo.dmmobiles.com`;
|
||||||
|
|
||||||
|
|
||||||
// export const BaseURL = `http://192.168.1.112:8000/api/`;
|
// export const BaseURL = `http://192.168.1.122:8000/api/`;
|
||||||
// export const ImageBaseURL = `http://192.168.1.112:8000`;
|
// export const ImageBaseURL = `http://192.168.1.122:8000`;
|
||||||
|
|
||||||
export const BaseURL_IMAGE = BaseURL.slice(0,-1);
|
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 = PROJECT_NAME + "_TOKEN"
|
||||||
|
export const TOKEN_KEY_SOCKET = PROJECT_NAME + "_SOKCET_TOKEN"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const USER_KEY = PROJECT_NAME + "_USER"
|
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 { io, Socket } from "socket.io-client";
|
||||||
import { TOKEN_KEY_SOCKET } from '../config/AppKey';
|
import { TOKEN_KEY } from "../api/config";
|
||||||
|
|
||||||
|
|
||||||
export const BASE_URL_SOCKET = 'http://192.168.1.14:8001/';
|
|
||||||
var socket :Socket | null = null ;
|
|
||||||
|
|
||||||
|
|
||||||
function InitSocket(){
|
|
||||||
|
|
||||||
|
var socket: null | Socket = null;
|
||||||
|
export const getSocket = () => {
|
||||||
|
const token = localStorage.getItem(TOKEN_KEY)
|
||||||
|
|
||||||
|
if (!socket) {
|
||||||
|
|
||||||
|
socket = io(BASE_URL, {
|
||||||
|
autoConnect: true,
|
||||||
|
transports: ["websocket"],
|
||||||
|
auth:{
|
||||||
|
token: token,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return socket;
|
||||||
|
};
|
||||||
|
|
||||||
if (!socket){
|
export const disconnectSocket = () => {
|
||||||
socket = io(BASE_URL_SOCKET , {
|
if (socket) {
|
||||||
transports:['websocket'],
|
socket.disconnect();
|
||||||
autoConnect:true,
|
|
||||||
query:{
|
|
||||||
token:localStorage.getItem(TOKEN_KEY_SOCKET),
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const disconnectSocket = ()=>{
|
|
||||||
|
|
||||||
socket?.disconnect();
|
|
||||||
socket = null;
|
socket = null;
|
||||||
}
|
}
|
||||||
export const getScoket = ()=>{
|
};
|
||||||
|
|
||||||
InitSocket();
|
|
||||||
return socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import {create} from 'zustand';
|
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 {
|
interface LoginResponse {
|
||||||
token:string ,
|
token:string ,
|
||||||
|
|
@ -20,6 +20,8 @@ const useAuthState = create<AuthStore>((set) => {
|
||||||
const storedUser :any = localStorage.getItem(USER_KEY) ;
|
const storedUser :any = localStorage.getItem(USER_KEY) ;
|
||||||
|
|
||||||
const storedToken = localStorage.getItem(TOKEN_KEY);
|
const storedToken = localStorage.getItem(TOKEN_KEY);
|
||||||
|
console.log(storedToken);
|
||||||
|
|
||||||
const initialUser = (storedUser && storedUser !== 'undefined') ? JSON.parse(storedUser) : null;
|
const initialUser = (storedUser && storedUser !== 'undefined') ? JSON.parse(storedUser) : null;
|
||||||
|
|
||||||
return {
|
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