This commit is contained in:
karimalden 2024-06-15 13:10:57 +03:00
parent eee88e7482
commit e346485768
36 changed files with 543 additions and 343 deletions

View File

@ -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

View File

@ -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>

View File

@ -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"
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 32 KiB

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

View 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

View File

@ -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 (

View File

@ -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}>

View File

@ -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>

View File

@ -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 />

View File

@ -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') || [];

View File

@ -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,8 +96,7 @@ 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,
@ -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"
} }

View 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;

View 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;

View File

@ -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 ( return (
// Pass Status to Layout <div className='support_message'>
<DashBody status={status as QueryStatusEnum} > <div className='support_message_left'>
<DashHeader showAddButton={false} title={'SupportMessages'}> <span>
<div className='RightSide d-flex gap-2 align-center '> <input type="text" placeholder='search' />
<SearchField searchBy={"email"} /> </span>
<div className="user_profiles">
{/* <AddButton onClick={()=>navigate('/support_messages/add')}></AddButton> */} {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> </div>
</DashHeader> </div>
);
<LyTable })}
data={data?.data} </div>
isLoading={false} </div>
columns={column} <div className='support_message_right'>
total={totalRows } {selected_user ? <Chat /> : <div className='select_message'><h1>Select chat to start messaging</h1></div>}
is_pagination={true} </div>
/> </div>
);
</DashBody>
)
} }
export default Page export default Page;

View File

@ -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

View File

@ -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

View 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"
},
]

View File

@ -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
}

View 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;

View File

@ -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;

View File

@ -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
},
] ]

View File

@ -17,6 +17,6 @@
@import '../Layout/FillterSection.scss'; @import '../Layout/FillterSection.scss';
@import '../page/SupportMessage.scss'

View File

@ -19,3 +19,23 @@
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 */
}
}

View File

@ -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)
} }

View File

@ -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;

View 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;
}

View File

@ -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"

View File

@ -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
View File

@ -0,0 +1,6 @@
export enum SOCKET {
EVENT_SEND_MESSAGE = "chat_message",
INCOMING = "incoming",
OUTGOING = "outgoing",
}

View File

@ -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) { if (!socket) {
socket = io(BASE_URL_SOCKET , {
transports:['websocket'],
autoConnect:true,
query:{
token:localStorage.getItem(TOKEN_KEY_SOCKET),
socket = io(BASE_URL, {
autoConnect: true,
transports: ["websocket"],
auth:{
token: token,
} }
}); });
} }
} return socket;
};
export const disconnectSocket = () => { export const disconnectSocket = () => {
if (socket) {
socket?.disconnect(); socket.disconnect();
socket = null; socket = null;
} }
export const getScoket = ()=>{ };
InitSocket();
return socket;
}

View File

@ -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
View File

@ -0,0 +1,4 @@
export interface Message {
type: "incoming" | "outgoing";
text: string;
}

11
vite.config.js Normal file
View File

@ -0,0 +1,11 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig(() => {
return {
build: {
outDir: 'build',
},
plugins: [react()],
};
});