fast notes added and also new form invite users

main
tteld 6 months ago
parent 5eae5d0d74
commit d12ed32c04

Binary file not shown.

@ -1,23 +1,26 @@
import { message } from "antd"; import { message } from "antd";
import { TCall } from "../../types/CallRequests/TCall"; import { TCall } from "../../types/CallRequests/TCall";
import instance from "../api"; import instance from "../api";
import { TPagination } from "../../types/common/TPagination";
export const callController = { export const callController = {
async read(obj: { status: string }) { async read(obj: { status: string; page: number; page_size: number }) {
const params = { ...obj }; const params = { ...obj };
if (!!obj.status) params.status = obj.status; if (!!obj.status) params.status = obj.status;
if (!!obj.page) params.page = obj.page;
if (!!obj.page_size) params.page_size = obj.page_size;
const { data } = await instance.get<TCall[]>(`callback-requests/`, { const { data } = await instance.get<TPagination<TCall[]>>(
params, `callback-requests/`,
}); {
params,
}
);
return data; return data;
}, },
async callPatch( async callPatch(obj: { note?: string; status?: string }, id: number) {
obj: { note?: string; status?: string },
id: number
) {
const params = { ...obj }; const params = { ...obj };
if (!!obj.note) params.note = obj.note; if (!!obj.note) params.note = obj.note;
if (!!obj.status) params.status = obj.status; if (!!obj.status) params.status = obj.status;
@ -26,7 +29,7 @@ export const callController = {
.put<TCall>(`callback-request/${id}/`, params) .put<TCall>(`callback-request/${id}/`, params)
.then((u) => { .then((u) => {
setTimeout(() => { setTimeout(() => {
message.success({ content: "Loaded!", duration: 2 }); message.success({ content: "Success!", duration: 2 });
}, 1000); }, 1000);
return u; return u;
}); });

@ -1,11 +1,13 @@
import { TCompany } from "../../types/Company/TCompany"; import { TCompany } from "../../types/Company/TCompany";
import { TPagination } from "../../types/common/TPagination";
import instance from "../api"; import instance from "../api";
import { message } from "antd"; import { message } from "antd";
export type TCompanyGetParams = { export type TCompanyGetParams = {
name?: string; name?: string;
page?: string | number; page?: number;
is_active?: boolean; is_active?: boolean;
page_size?: number;
}; };
export type TCompanyPutParams = { export type TCompanyPutParams = {
name?: string; name?: string;
@ -29,7 +31,23 @@ export const companyController = {
if (!!filterObject.is_active) params.is_active = filterObject.is_active; if (!!filterObject.is_active) params.is_active = filterObject.is_active;
if (!!filterObject.page) params.page = filterObject.page; if (!!filterObject.page) params.page = filterObject.page;
const { data } = await instance.get<TCompany[]>(`companies/`, { params }); const { data } = await instance.get<TCompany[]>(`companies/`, {
params,
});
return data;
},
async readPaginated(filterObject: TCompanyGetParams) {
const params = { ...filterObject };
if (!!filterObject.name) params.name = filterObject.name;
if (!!filterObject.is_active) params.is_active = filterObject.is_active;
if (!!filterObject.page) params.page = filterObject.page;
if (!!filterObject.page_size) params.page_size = filterObject.page_size;
const { data } = await instance.get<TPagination<TCompany[]>>(`companies/`, {
params,
});
return data; return data;
}, },

@ -1,16 +1,19 @@
import { TCustomer } from "../../types/Customer/TCustomer"; import { TCustomer } from "../../types/Customer/TCustomer";
import { TPagination } from "../../types/common/TPagination";
import instance from "../api"; import instance from "../api";
import { message } from "antd"; import { message } from "antd";
export type TCustomerGetParams = { export type TCustomerGetParams = {
name?: string; name?: string;
pageSize?: string | number; page_size?: string | number;
page?: string | number; page?: string | number;
for_driver_request?: boolean;
is_active?: boolean; is_active?: boolean;
}; };
export type TCustomerByCompanyGetParams = { export type TCustomerByCompanyGetParams = {
name?: string; name?: string;
id?: string; id?: number;
for_driver_request?: boolean;
}; };
export type TCustomerPutParams = { export type TCustomerPutParams = {
name?: string; name?: string;
@ -29,9 +32,14 @@ export const customerController = {
if (!!filterObject.name) params.name = filterObject.name; if (!!filterObject.name) params.name = filterObject.name;
if (!!filterObject.is_active) params.is_active = filterObject.is_active; if (!!filterObject.is_active) params.is_active = filterObject.is_active;
if (!!filterObject.page) params.page = filterObject.page; if (!!filterObject.page) params.page = filterObject.page;
if (!!filterObject.page) params.pageSize = filterObject.pageSize; if (!!filterObject.page_size) params.page_size = filterObject.page_size;
if (!!filterObject.for_driver_request)
params.for_driver_request = filterObject.for_driver_request;
const { data } = await instance.get<TCustomer[]>(`customers/`, { params }); const { data } = await instance.get<TPagination<TCustomer[]>>(
`customers/`,
{ params }
);
return data; return data;
}, },
@ -42,9 +50,14 @@ export const customerController = {
} }
}, },
async customerByCompany(id: string | undefined, name: string | undefined) { async customerByCompany(
const params = { name }; id: number | undefined,
name: string | undefined,
for_driver_request?: boolean
) {
const params = { name, for_driver_request };
if (!!name) params.name = name; if (!!name) params.name = name;
if (!!for_driver_request) params.for_driver_request = for_driver_request;
if (id) { if (id) {
const { data } = await instance.get<TCustomer[]>( const { data } = await instance.get<TCustomer[]>(
`customers-by-company/${id}/`, `customers-by-company/${id}/`,

@ -67,6 +67,11 @@ export const prof = {
`users/my-profile/`, `users/my-profile/`,
{ ...params } { ...params }
); );
message.success({ content: "Changes saved" });
if (params.username) {
localStorage.setItem("username", params.username);
}
window.location.reload()
return data; return data;
} catch (error: any) { } catch (error: any) {
setTimeout(() => { setTimeout(() => {

@ -1,10 +1,14 @@
import { message } from "antd"; import { message } from "antd";
import { TRequests } from "../../types/Requests/TRequests"; import { TRequests } from "../../types/Requests/TRequests";
import instance from "../api"; import instance from "../api";
import { TPagination } from "../../types/common/TPagination";
export type TRequestsGetParams = { export type TRequestsGetParams = {
search?: string; search?: string;
status?: string; status?: string;
for_driver_request?: boolean;
page?: number;
page_size?: number;
}; };
export const requestsController = { export const requestsController = {
@ -13,10 +17,17 @@ export const requestsController = {
if (!!filterObject.search) params.search = filterObject.search; if (!!filterObject.search) params.search = filterObject.search;
if (!!filterObject.status) params.status = filterObject.status; if (!!filterObject.status) params.status = filterObject.status;
if (!!filterObject.page) params.page = filterObject.page;
if (!!filterObject.page_size) params.page_size = filterObject.page_size;
if (!!filterObject.for_driver_request)
params.for_driver_request = filterObject.for_driver_request;
const { data } = await instance.get<TRequests[]>(`driver-requests/`, { const { data } = await instance.get<TPagination<TRequests[]>>(
params, `driver-requests/`,
}); {
params,
}
);
return data; return data;
}, },
@ -36,16 +47,27 @@ export const requestsController = {
}); });
return data; return data;
}, },
async rejectPatch(obj: TRequestsGetParams, id: string | number | undefined) {
const { data } = await instance
.patch<TRequests>(`driver-request/${id}/`, obj)
.then((u) => {
setTimeout(() => {
message.success({ content: "Loaded!", duration: 2 });
}, 1000);
return u;
});
return data;
},
async delete(id: string | number | undefined) { async delete(id: string | number | undefined) {
let res; let res;
let error = ""; let error = "";
try { try {
const { data } = await instance const { data } = await instance
.patch(`driver-request/${id}/`, { status: "Rejected" }) .delete(`driver-request/${id}/`)
.then((u) => { .then((u) => {
setTimeout(() => { setTimeout(() => {
message.success({ content: "Rejected!", key: id, duration: 2 }); message.success({ content: "Deleted!", key: id, duration: 2 });
}, 1000); }, 1000);
return u; return u;
}); });

@ -38,7 +38,10 @@ export const serviceController = {
} catch (error: any) { } catch (error: any) {
setTimeout(() => { setTimeout(() => {
message.error({ message.error({
content: error?.response?.data?.title, content:
error?.response?.data?.title ||
error?.response?.data?.points ||
"Something went wrong!",
key: 2, key: 2,
duration: 2, duration: 2,
}); });

@ -1,12 +1,15 @@
import { message } from "antd";
import { TTask, TTaskHistory } from "../../types/Tasks/TTasks"; import { TTask, TTaskHistory } from "../../types/Tasks/TTasks";
import { TPagination } from "../../types/common/TPagination"; import { TPagination } from "../../types/common/TPagination";
import instance from "../api"; import instance from "../api";
import { isMobile } from "../../App";
export type TTasksGetParams = { export type TTasksGetParams = {
search?: string; search?: string;
status?: string; status?: string;
team?: string; team?: string;
page?: string; page?: number;
page_size: number;
}; };
export type TTasksPutParams = { export type TTasksPutParams = {
@ -45,8 +48,9 @@ export const taskController = {
async read(filterObject: TTasksGetParams) { async read(filterObject: TTasksGetParams) {
const params = { ...filterObject }; const params = { ...filterObject };
if (!!filterObject.page && filterObject.page !== "0") if (!!filterObject.page && filterObject.page !== 0)
params.page = filterObject.page; params.page = filterObject.page;
params.page_size = isMobile ? 10 : 15;
if (!!filterObject.search) params.search = filterObject.search; if (!!filterObject.search) params.search = filterObject.search;
if (Array.isArray(filterObject.status)) { if (Array.isArray(filterObject.status)) {
params.status = filterObject.status.join(","); params.status = filterObject.status.join(",");
@ -66,7 +70,7 @@ export const taskController = {
return data; return data;
}, },
async taskOne(Id: number) { async taskOne(Id: number | undefined) {
const { data } = await instance.get<TTask>(`task/${Id}/`); const { data } = await instance.get<TTask>(`task/${Id}/`);
return data; return data;
}, },
@ -97,7 +101,6 @@ export const taskController = {
for (const file of formData.files) { for (const file of formData.files) {
form.append("files", file); form.append("files", file);
} }
console.log(form);
// if (Array.isArray(formData.files)) { // if (Array.isArray(formData.files)) {
// params.files = formData.files; // params.files = formData.files;
@ -106,13 +109,17 @@ export const taskController = {
// if (!!formData.shift_update_id) // if (!!formData.shift_update_id)
// params.shift_update_id = formData.shift_update_id; // params.shift_update_id = formData.shift_update_id;
if (!!formData.description) params.description = formData.description; if (!!formData.description) params.description = formData.description;
try {
const { data } = await instance.post("attachment/", form, { const { data } = await instance.post("attachment/", form, {
headers: { headers: {
"Content-Type": "multipart/form-data", "Content-Type": "multipart/form-data",
}, },
}); });
return data; message.success({ content: "Success!" });
return data;
} catch (err) {
message.error({ content: `${err}` });
}
}, },
async deleteTaskController(id: number) { async deleteTaskController(id: number) {

@ -44,7 +44,7 @@ export const userController = {
}, },
async userOne(Id: string | number | undefined) { async userOne(Id: string | number | undefined) {
const { data }: { data: any } = await instance(`users/admin/${Id}/`); const { data } = await instance.get<TUser>(`users/admin/${Id}/`);
return data; return data;
}, },

@ -1,11 +1,11 @@
import axios from "axios"; import axios from "axios";
const instance = axios.create({
baseURL: "http://10.10.10.45:8080/api/v1/",
});
// const instance = axios.create({ // const instance = axios.create({
// baseURL: "https://api.tteld.co/api/v1/", // baseURL: "http://10.10.10.12:8080/api/v1/",
// }); // });
const instance = axios.create({
baseURL: "https://api.tteld.co/api/v1/",
});
const token: string | null = localStorage.getItem("access"); const token: string | null = localStorage.getItem("access");
if (token) { if (token) {

@ -13,20 +13,21 @@ export const LoginApi = async ({ username, password }: loginInterface) => {
data: { username, password }, data: { username, password },
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
}); });
console.log(data);
const userObject = { const userObject = {
id: data?.data?.id, id: data?.data?.id,
first_name: data?.data?.first_name, first_name: data?.data?.first_name,
last_name: data?.data?.last_name, last_name: data?.data?.last_name,
username: data?.data?.username, username: data?.data?.username,
timezone: data?.data?.timezone, email: data?.data?.email,
role: data?.data?.role, role: data?.data?.role,
team_id: data?.data?.team_id, team: data?.data?.team,
business: data?.data?.business,
timezone: data?.data?.timezone || data?.data?.business?.timezone,
}; };
const userJSON = JSON.stringify(userObject); const userJSON = JSON.stringify(userObject);
localStorage.setItem("user", userJSON); localStorage.setItem("user", userJSON);
localStorage.setItem("username", data?.data?.username);
localStorage.setItem("access", data?.data.access); localStorage.setItem("access", data?.data.access);
localStorage.setItem("refresh", data?.data.refresh); localStorage.setItem("refresh", data?.data.refresh);
localStorage.setItem("admin_id", data?.data.id); localStorage.setItem("admin_id", data?.data.id);

@ -27,17 +27,17 @@ export const registryVerify = async (value: activateInterface) => {
timezone: data?.data.timezone, timezone: data?.data.timezone,
role: data?.data.role, role: data?.data.role,
}; };
console.log(data);
const userJSON = JSON.stringify(userObject); const userJSON = JSON.stringify(userObject);
localStorage.setItem("user", userJSON); localStorage.setItem("user", userJSON);
localStorage.setItem("access_token", data?.data.access_token); localStorage.setItem("access", data?.data.access);
localStorage.setItem("refresh_token", data?.data.refresh_token); localStorage.setItem("refresh", data?.data.refresh);
document.location.replace("/"); document.location.replace("/");
return status; return status;
} catch (error) { } catch (error) {
console.log(error);
setTimeout(() => { setTimeout(() => {
message.error({ content: "Something went wrong", duration: 2 }); message.error({ content: "Something went wrong", duration: 2 });
}, 1000); }, 1000);

@ -33,7 +33,6 @@ export const RegisterApi = async (value: registerInterface) => {
document.location.replace("/"); document.location.replace("/");
return status; return status;
} catch (error:any) { } catch (error:any) {
console.log(error);
setTimeout(() => { setTimeout(() => {
message.error({ content: ' ', duration: 2 }); message.error({ content: ' ', duration: 2 });
}, 1000); }, 1000);

@ -42,4 +42,4 @@ export const resetPassEmail = async (value: resetPassType) => {
message.error({ content: "Something went wrong", duration: 2 }); message.error({ content: "Something went wrong", duration: 2 });
}, 1000); }, 1000);
} }
}; }

@ -257,6 +257,14 @@
justify-content: end; justify-content: end;
} }
.mobile-filter {
display: flex;
align-items: end;
justify-content: space-between;
flex-direction: column;
}
.search-input-false { .search-input-false {
border: none; border: none;
outline: none; outline: none;
@ -561,7 +569,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin: 20px 24px 24px; margin: 12px 24px 12px;
} }
.TaskModal-header-dark { .TaskModal-header-dark {
display: flex; display: flex;
@ -641,9 +649,9 @@
color: rgb(211, 211, 211); color: rgb(211, 211, 211);
} }
.info-div { /* .info-div {
margin: 16px 24px; margin: 0 !important;
} } */
.info-body { .info-body {
border-radius: 12px; border-radius: 12px;
@ -765,3 +773,21 @@
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.call-requests {
background: rgba(246, 137, 0, 1);
padding: 3px 5px;
border-radius: 20px;
font-size: 10px;
margin-left: 5px;
color: #000000;
}
.call-none {
display: none;
}
.ant-upload-list-text{
overflow: scroll;
height: 50px;
}

@ -1,29 +1,58 @@
import React, { useEffect, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import "./App.css"; import "./App.css";
import { Layout, Menu, ConfigProvider, Dropdown } from "antd"; import { Layout, Menu, ConfigProvider, Dropdown, notification } from "antd";
import { Routes, Route, Navigate, useLocation } from "react-router-dom"; import { Routes, Route, Navigate, useLocation } from "react-router-dom";
import { allMenu, mainItems, superItems } from "./Utils/sidebar"; import { mainItems, superItems } from "./Utils/sidebar";
import Login from "./Auth/Login"; import Login from "./Auth/Login";
import Notfound from "./Utils/Notfound"; import Notfound from "./Utils/Notfound";
import { LogoutApi } from "./API/auth/Logout"; import { LogoutApi } from "./API/auth/Logout";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { MenuProps } from "antd";
// @ts-ignore // @ts-ignore
import themeBtn from "./assets/theme-btn.svg"; import themeBtn from "./assets/theme-btn.svg";
// @ts-ignore // @ts-ignore
import avatar from "./assets/avatar-img.svg"; import avatar from "./assets/avatar-img.svg";
// @ts-ignore
import taskIcon from "./assets/tasknavicon.png";
// @ts-ignore
import companyIcon from "./assets/companynavicon.png";
// @ts-ignore
import serviceIcon from "./assets/servicenavicon.png";
// @ts-ignore
import teamIcon from "./assets/teamnavicon.png";
// @ts-ignore
import statisticIcon from "./assets/statnavicon.png";
// @ts-ignore
import updateIcon from "./assets/updatenavicon.png";
// @ts-ignore
import userIcon from "./assets/usernavicon.png";
// @ts-ignore
import driverIcon from "./assets/customersIcon.png";
// @ts-ignore
import requestIcon from "./assets/requestIcon.png";
// @ts-ignore
import callIcon from "./assets/callIcon.png";
import Register from "./Auth/Register"; import Register from "./Auth/Register";
import Activate from "./Auth/Activate"; import Activate from "./Auth/Activate";
import Invite from "./Auth/Invite"; import Invite from "./Auth/Invite";
import ResetPassword from "./Auth/ResetPassword"; import ResetPassword from "./Auth/ResetPassword";
import ResetByEmail from "./Auth/ResetByEmail"; import ResetByEmail from "./Auth/ResetByEmail";
import { NotificationPlacement } from "antd/es/notification/interface";
import { TCall } from "./types/CallRequests/TCall";
import Task from "./Components/Tasks/Tasks";
import Requests from "./Components/Requests/Requests";
import { callController } from "./API/LayoutApi/callrequests";
import Call from "./Components/CallRequests/Call";
import { dark, light } from "./Utils/styles";
const { Header, Sider, Content } = Layout; const { Header, Sider, Content } = Layout;
const userJSON: any = localStorage.getItem("user"); const userJSON: any = localStorage.getItem("user");
const userObject = JSON.parse(userJSON); const userObject = JSON.parse(userJSON);
export const timeZone = userObject?.timezone; export const timeZone = userObject?.timezone;
export const role = userObject?.role; export const role = userObject?.role;
export const admin_id = localStorage.getItem("admin_id"); export const admin_id = localStorage.getItem("admin_id");
export const team_id = userObject?.team_id; export const team_id = userObject?.team?.id;
export const isMobile = window.innerWidth <= 768;
const username = localStorage.getItem("username");
const App: React.FC = () => { const App: React.FC = () => {
const isAuthenticated = localStorage.getItem("access") as string; const isAuthenticated = localStorage.getItem("access") as string;
@ -34,6 +63,126 @@ const App: React.FC = () => {
const [theme, setTheme] = useState<any>( const [theme, setTheme] = useState<any>(
localStorage.getItem("theme") === "true" ? true : false localStorage.getItem("theme") === "true" ? true : false
); );
const [calls, setCalls] = useState(0);
const [data, setData] = useState<any>();
useEffect(() => {
if (admin_id) {
callController
.read({ status: "Awaiting", page: 1, page_size: 100 })
.then((data: any) => {
setData(data);
});
}
}, [admin_id]);
useEffect(() => {
if (data) {
setCalls(data.data?.length);
}
}, [data]);
type MenuItem = Required<MenuProps>["items"][number];
function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[]
): MenuItem {
return {
key,
icon,
children,
label,
} as MenuItem;
}
const allMenu: MenuItem[] = [
getItem(<Link to="/">Tasks</Link>, "/", <img alt="" src={taskIcon} />),
getItem(
<Link to="companies/">Companies</Link>,
"companies/",
<img alt="" src={companyIcon} />
),
getItem(
<Link to="customers/">Drivers</Link>,
"customers/",
<img alt="" src={driverIcon} />
),
getItem(
<Link to="services/">Services</Link>,
"services/",
<img alt="" src={serviceIcon} />
),
];
if (role === "Tech Support") {
allMenu.push(
getItem(
<Link to="users/">Users</Link>,
"users/",
<img alt="" src={userIcon} />
),
getItem(
<Link to="teams/">Teams</Link>,
"teams/",
<img alt="" src={teamIcon} />
),
getItem(
<Link to="updates/">Updates</Link>,
"updates/",
<img alt="" src={updateIcon} />
),
getItem(
<Link to="requests/">Driver Requests</Link>,
"requests/",
<img alt="" src={requestIcon} />
),
getItem(
<Link to="call/">Call Requests</Link>,
"call/",
<img alt="" src={callIcon} />
)
);
}
if (role === "Owner") {
allMenu.push(
getItem(
<Link to="users/">Users</Link>,
"users/",
<img alt="" src={userIcon} />
),
getItem(
<Link to="teams/">Teams</Link>,
"teams/",
<img alt="" src={teamIcon} />
),
getItem(
<Link to="stats/">Statistics</Link>,
"stats/",
<img alt="" src={statisticIcon} />
),
getItem(
<Link to="updates/">Updates</Link>,
"updates/",
<img alt="" src={updateIcon} />
),
getItem(
<Link to="requests/">Driver Requests</Link>,
"requests/",
<img alt="" src={requestIcon} />
),
getItem(
<Link to="calls/">
Call Requests{" "}
<span className={`${calls !== 0 ? "call-requests" : "call-none"}`}>
{calls}
</span>
</Link>,
"calls/",
<img alt="" src={callIcon} />
)
);
}
useEffect(() => { useEffect(() => {
localStorage.setItem("theme", theme); localStorage.setItem("theme", theme);
@ -46,172 +195,7 @@ const App: React.FC = () => {
const clickLogout = () => { const clickLogout = () => {
LogoutApi(); LogoutApi();
}; };
const dark = {
components: {
Table: {
colorBgContainer: "#202020",
colorText: "#BBBBBB",
headerColor: "#BBBBBB",
borderColor: "#3A3A3A",
headerSplitColor: "#3A3A3A",
rowHoverBg: "#333333",
colorBorder: "#3A3A3A",
},
Layout: {
bodyBg: "#181818",
},
Input: {
colorBgContainer: "#2A2A2A",
colorBgContainerDisabled: "#2A2A2A",
colorText: "#BBBBBB",
colorTextPlaceholder: "#BBBBBB",
colorBorder: "#3A3A3A",
colorFillSecondary: "rgba(0, 0, 0, 0.02)",
activeBorderColor: "#3A3A3A",
activeShadow: "#3A3A3A",
hoverBorderColor: "#3A3A3A",
// colorIcon: "#BBBBBB",
// colorIconHover: "#BBBBBB",
},
Select: {
colorBgContainer: "#2A2A2A",
colorText: "#BBBBBB",
colorTextPlaceholder: "#BBBBBB",
colorBorder: "rgba(150, 150, 150, 0.493)",
colorPrimaryHover: "rgba(249, 158, 44, 1)",
colorIconHover: "#BBB",
optionSelectedBg: "#2A2A2A",
colorBgElevated: "#333",
controlOutline: "none",
optionActiveBg: "#333333",
colorTextQuaternary: "#3A3A3A",
},
Button: {
colorBorderSecondary: "rgba(249, 158, 44, 1)",
colorPrimary: "rgba(249, 158, 44, 1)",
colorPrimaryHover: "#BBBBBB",
colorIcon: "rgba(249, 158, 44, 1)",
colorIconHover: "rgba(249, 158, 44, 1)",
primaryShadow: "none",
dangerShadow: "none",
colorTextDisabled: "#AAAAAA",
borderColorDisabled: "#3A3A3A",
},
// Form: {
// labelColor: "#BBBBBB",
// },
Tabs: {
itemColor: "#BBBBBB",
itemHoverColor: "#FFFFFF",
itemSelectedColor: "rgba(249, 158, 44, 1)",
colorPrimaryActive: "rgba(249, 158, 44, 1)",
inkBarColor: "rgba(249, 158, 44, 1)",
},
// Upload: {
// colorText: "#FFFFFF",
// colorInfoBgHover: "#1E1E1E",
// },
// Pagination: {
// colorText: "#BBBBBB",
// colorPrimary: "#FFFFFF",
// colorBgContainer: "#1A1A1A",
// colorBorderSecondary: "#3A3A3A",
// },
Modal: {
contentBg: "#3A3A3A",
headerBg: "#3A3A3A",
titleColor: "#FFFFFF",
colorText: "#BBBBBB",
colorBgTextActive: "#BBBBBB",
colorBgTextHover: "#BBBBBB",
},
Menu: {
darkItemSelectedBg: "#3A3A3A",
colorBgContainer: "#fff",
},
Switch: {
colorPrimary: "#565656",
colorPrimaryHover: "#737373",
},
Radio: {
colorText: "#737373",
colorBorder: "#3A3A3A",
colorPrimaryActive: "#BBBBBB",
buttonCheckedBg: "rgba(249, 158, 44, 1)",
colorPrimaryHover: "#737373",
colorPrimary: "#565656",
},
Dropdown: {
colorBgContainer: "#3A3A3A",
colorText: "#BBBBBB",
colorPrimaryHover: "#565656",
colorPrimary: "#333333",
},
DatePicker: {
colorBgContainer: "#3A3A3A",
colorBgElevated: "#3A3A3A",
colorText: "#BBBBBB",
colorTextPlaceholder: "#BBBBBB",
colorIcon: "#fff",
colorIconHover: "#fff",
colorPrimary: "rgba(249, 158, 44, 1)",
hoverBorderColor: "#BBBBBB",
},
Empty: {
colorText: "rgba(249, 158, 44, 1)",
colorTextDisabled: "rgba(249, 158, 44, 1)",
},
},
token: {
fontFamily: "Inter, sans-serif",
colorText: "#bbb",
borderRadius: 8,
},
};
const light = {
components: {
Table: {
rowHoverBg: "#bae0ff",
headerBg: "none",
colorText: "rgba(24, 26, 41, 1)",
fontWeightStrong: 500,
colorTextHeading: "rgba(161, 162, 171, 1)",
},
Select: {
colorTextPlaceholder: "rgba(155, 157, 170, 1)",
colorPrimary: "rgba(249, 158, 44, 1)",
colorPrimaryHover: "rgba(249, 158, 44, 1)",
},
Tabs: {
inkBarColor: "rgba(249, 158, 44, 1)",
itemSelectedColor: "rgba(24, 26, 41, 1)",
itemHoverColor: "rgba(24, 26, 41, 1)",
},
Input: {
hoverBorderColor: "rgba(249, 158, 44, 1)",
activeBorderColor: "rgba(249, 158, 44, 1)",
colorTextPlaceholder: "rgba(155, 157, 170, 1)",
},
Upload: {
colorPrimaryHover: "rgba(249, 158, 44, 1)",
},
Button: {
colorPrimary: "rgba(249, 158, 44, 1)",
colorPrimaryHover: "rgba(249, 158, 44, 1)",
},
Textarea: {
colorBorder: "0px 1px 3px 0px rgba(20, 22, 41, 0.1)",
},
Menu: {
darkItemSelectedBg: "rgba(255, 255, 255, 0.08)",
},
},
token: {
fontFamily: "Inter, sans-serif",
color: "#262626",
borderRadius: 8,
},
};
const rep = () => { const rep = () => {
document.location.replace("/"); document.location.replace("/");
}; };
@ -225,6 +209,63 @@ const App: React.FC = () => {
</Menu.Item> </Menu.Item>
</Menu> </Menu>
); );
let taskSocket: WebSocket;
const [isLive, setIslive] = useState(true);
const [socketData, setSocketData] = useState<any>();
const connect = async () => {
try {
if (
(!taskSocket || taskSocket.readyState === WebSocket.CLOSED) &&
admin_id
) {
// taskSocket = new WebSocket(
// `ws://10.10.10.12:8080/global/?user_id=${admin_id}`
// );
taskSocket = new WebSocket(
`wss://api.tteld.co/global/?user_id=${admin_id}`
);
taskSocket.addEventListener("open", (event) => {
setIslive(true);
});
taskSocket.addEventListener("message", (event) => {
const newData: any = JSON.parse(event.data);
setSocketData(newData);
});
taskSocket.addEventListener("error", (errorEvent) => {
console.error("WebSocket error:", errorEvent);
});
taskSocket.addEventListener("close", (event) => {
setIslive(false);
});
}
} catch (err) {}
};
useEffect(() => {
connect();
}, []);
const [api, contextHolder] = notification.useNotification();
const openNotification = useCallback(
(placement: NotificationPlacement, data: TCall) => {
api.info({
message: `Driver ${data?.driver?.name} from ${data?.company?.name} company has made a call request`,
placement,
});
},
[api]
);
useEffect(() => {
if (socketData?.type === "callback_request") {
let status = socketData?.callback_request.status;
if (status === "Awaiting") {
openNotification("bottomRight", socketData?.callback_request);
setCalls((prev: any) => prev + 1);
} else if (status === "Resolved" && calls !== 0) {
setCalls((prev: any) => prev - 1);
}
}
}, [socketData, openNotification]);
return ( return (
<ConfigProvider theme={theme === true ? dark : light}> <ConfigProvider theme={theme === true ? dark : light}>
@ -253,91 +294,134 @@ const App: React.FC = () => {
)} )}
{authorized ? ( {authorized ? (
<Layout> <Layout>
<Sider {contextHolder}
theme={"dark"} {isMobile ? (
collapsible <div className=""></div>
collapsed={collapsed} ) : (
onCollapse={(value) => setCollapsed(value)} <Sider
style={{
height: "100vh",
background: theme === true ? "#202020" : "rgba(20, 22, 41, 1)",
}}
>
<p
onClick={rep}
style={{ cursor: "pointer" }}
className={collapsed ? "logo-collapsed" : "logo"}
>
TT ELD
</p>
<Menu
theme={"dark"} theme={"dark"}
mode="inline" collapsible
defaultSelectedKeys={[location.pathname]} collapsed={collapsed}
items={allMenu} onCollapse={(value) => setCollapsed(value)}
style={{ style={{
height: "100vh",
background: background:
theme === true ? "#202020" : "rgba(20, 22, 41, 1)", theme === true ? "#202020" : "rgba(20, 22, 41, 1)",
color: "rgba(255, 255, 255, 0.6)",
}}
></Menu>
</Sider>
<Layout className="site-layout">
<Header
className="site-layout-background"
style={{
padding: 0,
background:
theme === true ? "#202020" : "rgba(215, 216, 224, 1)",
display: "flex",
justifyContent: "end",
alignItems: "center",
}} }}
> >
<div <p
onClick={rep}
style={{ cursor: "pointer" }}
className={collapsed ? "logo-collapsed" : "logo"}
>
TT ELD
</p>
<Menu
theme={"dark"}
mode="inline"
defaultSelectedKeys={[location.pathname]}
items={allMenu}
style={{ style={{
float: "right", background:
marginRight: "35px", theme === true ? "#202020" : "rgba(20, 22, 41, 1)",
color: "rgba(255, 255, 255, 0.6)",
}}
></Menu>
</Sider>
)}
<Layout className="site-layout">
{isMobile ? (
<Header style={{ padding: 0 }}>
<div className="demo-logo" />
<Menu
theme="dark"
mode="horizontal"
defaultSelectedKeys={["2"]}
items={allMenu}
style={{
background:
theme === true ? "#202020" : "rgba(20, 22, 41, 1)",
color: "rgba(255, 255, 255, 0.6)",
}}
/>
</Header>
) : (
<Header
className="site-layout-background"
style={{
padding: 0,
background:
theme === true ? "#202020" : "rgba(215, 216, 224, 1)",
display: "flex", display: "flex",
justifyContent: "end",
alignItems: "center", alignItems: "center",
alignSelf: "center",
minWidth: 150,
maxWidth: 500,
justifyContent: "space-between",
}} }}
> >
<button <div
className="theme-btn" style={{
onClick={(e) => setTheme(!theme)} float: "right",
marginRight: "35px",
display: "flex",
alignItems: "center",
alignSelf: "center",
minWidth: 150,
maxWidth: 500,
justifyContent: "space-between",
}}
> >
<img src={themeBtn} alt="" /> <button
</button> className="theme-btn"
<Dropdown overlay={menu} trigger={["click"]}> onClick={(e) => setTheme(!theme)}
<div
style={{ cursor: "pointer" }}
onClick={(e) => e.preventDefault()}
> >
<div className="profile-dropdown"> <img src={themeBtn} alt="" />
<div className="profile-dropdown-ava"> </button>
<img src={avatar} alt="" /> <Dropdown overlay={menu} trigger={["click"]}>
</div> <div
<div style={{ cursor: "pointer" }}
className="d-flex profile-dropdown-text" onClick={(e) => e.preventDefault()}
style={{ flexDirection: "column" }} >
> <div className="profile-dropdown">
<p <div className="profile-dropdown-ava">
className={ <img src={avatar} alt="" />
!theme ? "business-name" : "business-name-dark" </div>
} <div className="d-flex profile-dropdown-text">
> <p
{userObject?.username} className={
</p> !theme ? "business-name" : "business-name-dark"
}
>
{username}
{isLive ? (
<div
className="d-flex"
style={{ marginRight: 15 }}
>
<div className="circle"></div>
<p
className={
!theme ? "live-p" : "live-p-dark"
}
>
online
</p>
</div>
) : (
<div
className="d-flex"
style={{ marginRight: 15 }}
>
<div className="circle2"></div>
<p className="live-p">offline</p>
</div>
)}
</p>
</div>
</div> </div>
</div> </div>
</div> </Dropdown>
</Dropdown> </div>
</div> </Header>
</Header> )}
<Content <Content
id="element" id="element"
style={{ style={{
@ -349,6 +433,11 @@ const App: React.FC = () => {
}} }}
> >
<Routes> <Routes>
<Route
key={"task"}
path="/"
element={<Task socketData={socketData} />}
/>
{mainItems && {mainItems &&
mainItems.map((u) => ( mainItems.map((u) => (
<Route key={u.key} path={u.path} element={u.component} /> <Route key={u.key} path={u.path} element={u.component} />
@ -357,6 +446,20 @@ const App: React.FC = () => {
superItems.map((u) => ( superItems.map((u) => (
<Route key={u.key} path={u.path} element={u.component} /> <Route key={u.key} path={u.path} element={u.component} />
))} ))}
{superItems && (
<Route
key={"requests"}
path="/requests/"
element={<Requests socketData={socketData} />}
/>
)}
{superItems && (
<Route
key={"calls"}
path="/calls/"
element={<Call socketData={socketData} />}
/>
)}
<Route path="*" element={<Notfound />} /> <Route path="*" element={<Notfound />} />
</Routes> </Routes>
</Content> </Content>

@ -1,6 +1,6 @@
import { Navigate, useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { registryVerify } from "../API/auth/activate"; import { registryVerify } from "../API/auth/activate";
import { message } from "antd";
const Activate = () => { const Activate = () => {
const location = useLocation(); const location = useLocation();
@ -15,7 +15,7 @@ const Activate = () => {
}) })
} }
return <div></div>; return <div><h1>OOOOOOO Bratim qandoysiz?!</h1></div>;
}; };
export default Activate; export default Activate;

@ -16,8 +16,6 @@ const Invite = () => {
role_id: role_id, role_id: role_id,
business_id: business_id, business_id: business_id,
}).then((status) => { }).then((status) => {
console.log(status);
if (status === 200) { if (status === 200) {
document.location.replace("/"); document.location.replace("/");
} }

@ -3,6 +3,7 @@ import { Button, Card, Input, Space } from "antd";
import { Form, Field } from "react-final-form"; import { Form, Field } from "react-final-form";
import { LockOutlined, UserOutlined } from "@ant-design/icons"; import { LockOutlined, UserOutlined } from "@ant-design/icons";
import { LoginApi } from "../API/auth/Login"; import { LoginApi } from "../API/auth/Login";
import { Link } from "react-router-dom";
const Login: React.FC = () => { const Login: React.FC = () => {
const validate = (val: any) => { const validate = (val: any) => {
@ -106,12 +107,12 @@ const Login: React.FC = () => {
> >
Log In Log In
</Button> </Button>
{/* <h5> <h5>
<Link to='/auth/reset_password'>Forgot password?</Link> <Link to='/auth/reset_password'>Forgot password?</Link>
<br /> <br />
Don't have an account? Don't have an account?
<Link to='/auth/register'> Create one now</Link> <Link to='/auth/register'> Create one now</Link>
</h5> */} </h5>
</Space> </Space>
</form> </form>
</Card> </Card>

@ -71,7 +71,7 @@ const Register: React.FC = () => {
}} }}
> >
<h1>Sign up</h1> <h1>Sign up</h1>
{emailDom && ( {/* { && ( */}
<Card <Card
bodyStyle={{ background: "rgb(250, 250, 250)" }} bodyStyle={{ background: "rgb(250, 250, 250)" }}
title={emailDom} title={emailDom}
@ -120,7 +120,7 @@ const Register: React.FC = () => {
</Col> </Col>
</Row> </Row>
{/* <Form.Item <Form.Item
name="email" name="email"
rules={[ rules={[
{ {
@ -147,7 +147,7 @@ const Register: React.FC = () => {
placeholder="E-mail" placeholder="E-mail"
/> />
)} )}
</Form.Item> */} </Form.Item>
<Form.Item <Form.Item
name="username" name="username"
@ -262,7 +262,7 @@ const Register: React.FC = () => {
</Form.Item> </Form.Item>
</Space> </Space>
</Card> </Card>
)} {/* )} */}
</Space> </Space>
</Form> </Form>
<Success open={open} setOpen={setOpen} email={email} /> <Success open={open} setOpen={setOpen} email={email} />

@ -1,11 +1,74 @@
import React, { useState } from "react"; import { useEffect, useState } from "react";
import CallTable from "./CallTable"; import CallTable from "./CallTable";
import { StepForwardOutlined, StepBackwardOutlined } from "@ant-design/icons";
import { useCallData } from "../../Hooks/CallRequests"; import { useCallData } from "../../Hooks/CallRequests";
import { Radio, RadioChangeEvent } from "antd"; import { Button, Input, Radio, RadioChangeEvent, Space } from "antd";
import { TCall } from "../../types/CallRequests/TCall";
import { TSocket } from "../../types/common/TSocket";
const Call = () => { const Call = ({ socketData }: { socketData: TSocket | undefined }) => {
const [status, setStatus] = useState("Awaiting"); const [status, setStatus] = useState("Awaiting");
const { data, isLoading, refetch } = useCallData({ status: status }); const [page, setPage] = useState(1);
const [tableData, setTableData] = useState<TCall[]>();
const { data, isLoading, refetch } = useCallData({
status: status,
page: page,
page_size: 10,
});
useEffect(() => {
setTableData(data?.data);
}, [data]);
useEffect(() => {
let dataStatus = socketData?.callback_request?.status;
if (socketData?.type === "callback_request") {
if (status === "Awaiting") {
setTableData((prev) => {
if (prev && prev.length >= 15) {
prev.pop();
}
if (dataStatus === "Resolved") {
const data = (prev || []).filter(
(b: TCall) => b?.id !== socketData?.callback_request?.id
);
return data;
}
if (dataStatus === "Awaiting") {
return [socketData?.callback_request, ...(prev || [])] as TCall[];
}
return prev;
});
} else if (status === "Resolved") {
setTableData((prev) => {
if (prev && prev.length >= 15) {
prev.pop();
}
if (dataStatus === "Awaiting") {
const data = (prev || []).filter(
(b: TCall) => b?.id !== socketData?.callback_request?.id
);
return data;
}
if (dataStatus === "Resolved") {
return [socketData?.callback_request, ...(prev || [])] as TCall[];
}
return prev;
});
}
}
}, [socketData]);
const Next = () => {
const a = Number(page) + 1;
setPage(a);
};
const Previos = () => {
Number(page);
if (page > 1) {
const a = Number(page) - 1;
setPage(a);
}
};
return ( return (
<div> <div>
@ -25,7 +88,33 @@ const Call = () => {
</Radio.Group> </Radio.Group>
</div> </div>
</div> </div>
<CallTable data={data} isLoading={isLoading} refetch={refetch} /> <CallTable data={tableData} isLoading={isLoading} refetch={refetch} />
<Space style={{ width: "100%", marginTop: 10 }} direction="vertical">
<Space style={{ width: "100%", justifyContent: "flex-end" }} wrap>
<Button
type="primary"
icon={<StepBackwardOutlined />}
onClick={Previos}
disabled={data?.previous ? false : true}
></Button>
<Input
style={{ width: 50, textAlign: "right" }}
value={page}
onChange={(e) => {
let num = e.target.value;
if (Number(num) && num !== "0") {
setPage(Number(num));
}
}}
/>
<Button
type="primary"
icon={<StepForwardOutlined />}
onClick={Next}
disabled={data?.next ? false : true}
></Button>
</Space>
</Space>
</div> </div>
); );
}; };

@ -11,6 +11,7 @@ import {
RefetchQueryFilters, RefetchQueryFilters,
} from "react-query"; } from "react-query";
import { useState } from "react"; import { useState } from "react";
import { TPagination } from "../../types/common/TPagination";
const CallTable = ({ const CallTable = ({
data, data,
isLoading, isLoading,
@ -20,7 +21,7 @@ const CallTable = ({
isLoading: boolean; isLoading: boolean;
refetch: <TPageData>( refetch: <TPageData>(
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
) => Promise<QueryObserverResult<TCall[], unknown>>; ) => Promise<QueryObserverResult<TPagination<TCall[]>, unknown>>;
}) => { }) => {
const statusClick = (record: TCall | any) => { const statusClick = (record: TCall | any) => {
callController callController

@ -6,6 +6,7 @@ import {
RefetchQueryFilters, RefetchQueryFilters,
} from "react-query"; } from "react-query";
import { TCompany } from "../../types/Company/TCompany"; import { TCompany } from "../../types/Company/TCompany";
import { TPagination } from "../../types/common/TPagination";
const AddCompany = ({ const AddCompany = ({
open, open,
@ -14,7 +15,7 @@ const AddCompany = ({
}: { }: {
refetch: <TPageData>( refetch: <TPageData>(
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
) => Promise<QueryObserverResult<TCompany[], unknown>>; ) => Promise<QueryObserverResult<TPagination<TCompany[]>, unknown>>;
open: boolean; open: boolean;
setOpen(open: boolean): void; setOpen(open: boolean): void;
}) => { }) => {

@ -1,12 +1,15 @@
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import AddCompany from "./AddCompanies"; import AddCompany from "./AddCompanies";
import CompanyTable from "./CompaniesTable"; import CompanyTable from "./CompaniesTable";
import { StepForwardOutlined, StepBackwardOutlined } from "@ant-design/icons";
import { useCompanyPaginated } from "../../Hooks/Companies";
import { Button, Input, Space } from "antd";
// @ts-ignore // @ts-ignore
import IconSearch from "../../assets/searchIcon.png"; import IconSearch from "../../assets/searchIcon.png";
import { useCompanyData } from "../../Hooks/Companies";
//@ts-ignore //@ts-ignore
import addicon from "../../assets/addiconpng.png"; import addicon from "../../assets/addiconpng.png";
import { role } from "../../App";
const theme = localStorage.getItem("theme") === "true" ? true : false; const theme = localStorage.getItem("theme") === "true" ? true : false;
const Company = () => { const Company = () => {
@ -15,10 +18,13 @@ const Company = () => {
setOpen(true); setOpen(true);
}; };
const [search, setSearch] = useState<any>(""); const [search, setSearch] = useState<string>();
const { data, isLoading, refetch } = useCompanyData({ const [page, setPage] = useState<number>(1);
const { data, isLoading, refetch } = useCompanyPaginated({
name: search, name: search,
is_active: undefined, is_active: undefined,
page: page,
page_size: 10,
}); });
const timerRef = useRef<NodeJS.Timeout | null>(null); const timerRef = useRef<NodeJS.Timeout | null>(null);
@ -33,19 +39,33 @@ const Company = () => {
}, 1000); }, 1000);
}; };
const Next = () => {
const a = Number(page) + 1;
setPage(a);
};
const Previos = () => {
Number(page);
if (page > 1) {
const a = Number(page) - 1;
setPage(a);
}
};
return ( return (
<div> <div>
{open && <AddCompany open={open} refetch={refetch} setOpen={setOpen} />} {open && <AddCompany open={open} refetch={refetch} setOpen={setOpen} />}
<div className="header d-flex"> <div className="header d-flex">
<h1 className="title">Companies</h1> <h1 className="title">Companies</h1>
<button {role !== "Checker" && (
style={{ marginRight: 0 }} <button
className="btn-add d-flex" style={{ marginRight: 0 }}
onClick={showModal} className="btn-add d-flex"
> onClick={showModal}
<img src={addicon} style={{ marginRight: 8 }} alt="" /> >
Add Company <img src={addicon} style={{ marginRight: 8 }} alt="" />
</button> Add Company
</button>
)}
</div> </div>
<div className="filter d-flex"> <div className="filter d-flex">
<div className="search-div"> <div className="search-div">
@ -59,7 +79,33 @@ const Company = () => {
</div> </div>
</div> </div>
<CompanyTable data={data} isLoading={isLoading} /> <CompanyTable data={data?.data} isLoading={isLoading} />
<Space style={{ width: "100%", marginTop: 10 }} direction="vertical">
<Space style={{ width: "100%", justifyContent: "flex-end" }} wrap>
<Button
type="primary"
icon={<StepBackwardOutlined />}
onClick={Previos}
disabled={data?.previous ? false : true}
></Button>
<Input
style={{ width: 50, textAlign: "right" }}
value={page}
onChange={(e) => {
let num = e.target.value;
if (Number(num) && num !== "0") {
setPage(Number(num));
}
}}
/>
<Button
type="primary"
icon={<StepForwardOutlined />}
onClick={Next}
disabled={data?.next ? false : true}
></Button>
</Space>
</Space>
</div> </div>
); );
}; };

@ -21,8 +21,9 @@ import { DashboardOutlined } from "@ant-design/icons";
import Notfound from "../../Utils/Notfound"; import Notfound from "../../Utils/Notfound";
import Table from "antd/es/table"; import Table from "antd/es/table";
import AddDriver from "./AddDriver"; import AddDriver from "./AddDriver";
import { role } from "../../App";
import { useTeamData } from "../../Hooks/Teams";
import { useCustomerByComanyData } from "../../Hooks/Customers"; import { useCustomerByComanyData } from "../../Hooks/Customers";
// @ts-ignore // @ts-ignore
import zippy from "../../assets/zippyicon.svg"; import zippy from "../../assets/zippyicon.svg";
// @ts-ignore // @ts-ignore
@ -39,9 +40,6 @@ import tagIcon from "../../assets/tagIcon.png";
import infoIcon from "../../assets/infoIcon.png"; import infoIcon from "../../assets/infoIcon.png";
// @ts-ignore // @ts-ignore
import infoIconActive from "../../assets/infoIconActive.png"; import infoIconActive from "../../assets/infoIconActive.png";
import { role } from "../../App";
import { useTeamData } from "../../Hooks/Teams";
import { validateLocaleAndSetLanguage } from "typescript";
const TabPane = Tabs.TabPane; const TabPane = Tabs.TabPane;
type params = { type params = {
readonly id: any; readonly id: any;
@ -79,7 +77,6 @@ const CompanyEdit = () => {
}; };
const [value, setValue] = useState(1); const [value, setValue] = useState(1);
const onChange = (e: RadioChangeEvent) => { const onChange = (e: RadioChangeEvent) => {
console.log("radio checked", e.target.value);
setValue(e.target.value); setValue(e.target.value);
}; };
const [activeTab, setActiveTab] = useState("1"); const [activeTab, setActiveTab] = useState("1");

@ -117,32 +117,10 @@ function CompanyTable({
responsive: ["lg"], responsive: ["lg"],
}, },
{ {
width: "20%", width: "10%",
title: "Actions", title: "Actions",
dataIndex: "action", dataIndex: "action",
render: ({ id, api }: { id: string; api: string }) => { render: ({ id }: { id: string }) => {
const enterLoading = (index: number, api: string) => {
setLoadings((prevLoadings) => {
const newLoadings = [...prevLoadings];
newLoadings[index] = true;
return newLoadings;
});
if (api && api !== "") {
companyController.SyncCompany(index);
} else {
message.error({
content: "This company doesn't have an api key",
duration: 2,
});
}
setTimeout(() => {
setLoadings((prevLoadings) => {
const newLoadings = [...prevLoadings];
newLoadings[index] = false;
return newLoadings;
});
}, 6000);
};
return ( return (
<Space> <Space>
<Link to={`${id}`}> <Link to={`${id}`}>
@ -151,15 +129,6 @@ function CompanyTable({
<Button type="primary" icon={<EyeOutlined />}></Button> <Button type="primary" icon={<EyeOutlined />}></Button>
)} )}
</Link> </Link>
{role !== "Checker" && (
<Button
type="primary"
icon={<SyncOutlined />}
loading={loadings[Number(id)]}
onClick={() => enterLoading(Number(id), api)}
/>
)}
</Space> </Space>
); );
}, },

@ -1,25 +1,41 @@
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import AddCustomer from "./AddCustomer"; import AddCustomer from "./AddCustomer";
import CustomerTable from "./CustomersTable"; import CustomerTable from "./CustomersTable";
import { StepForwardOutlined, StepBackwardOutlined } from "@ant-design/icons";
import { useCustomerData } from "../../Hooks/Customers"; import { useCustomerData } from "../../Hooks/Customers";
//@ts-ignore //@ts-ignore
import addicon from "../../assets/addiconpng.png"; import addicon from "../../assets/addiconpng.png";
// @ts-ignore // @ts-ignore
import IconSearch from "../../assets/searchIcon.png"; import IconSearch from "../../assets/searchIcon.png";
import { Button, Input, Space } from "antd";
const Customer = () => { const Customer = () => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [page, setPage] = useState(1)
const showModal = () => { const showModal = () => {
setOpen(true); setOpen(true);
}; };
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const { isLoading, data, refetch } = useCustomerData({ const { data, isLoading, refetch } = useCustomerData({
name: search, name: search,
is_active: undefined, is_active: undefined,
page_size: 10,
page: page
}); });
const Next = () => {
const a = Number(page) + 1;
setPage(a);
};
const Previos = () => {
Number(page);
if (page > 1) {
const a = Number(page) - 1;
setPage(a);
}
};
const timerRef = useRef<NodeJS.Timeout | null>(null); const timerRef = useRef<NodeJS.Timeout | null>(null);
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (timerRef.current) { if (timerRef.current) {
@ -53,7 +69,33 @@ const Customer = () => {
/> />
</div> </div>
</div> </div>
<CustomerTable data={data} isLoading={isLoading} /> <CustomerTable data={data?.data} isLoading={isLoading} />
<Space style={{ width: "100%", marginTop: 10 }} direction="vertical">
<Space style={{ width: "100%", justifyContent: "flex-end" }} wrap>
<Button
type="primary"
icon={<StepBackwardOutlined />}
onClick={Previos}
disabled={!data?.previous}
></Button>
<Input
style={{ width: 50, textAlign: "right" }}
value={page}
onChange={(e) => {
let num = e.target.value;
if (Number(num) && num !== "0") {
setPage(Number(num));
}
}}
/>
<Button
type="primary"
icon={<StepForwardOutlined />}
onClick={Next}
disabled={!data?.next}
></Button>
</Space>
</Space>
</div> </div>
); );
}; };

@ -1,5 +1,6 @@
import { useParams } from "react-router-dom"; import { useParams, useNavigate } from "react-router-dom";
import { useCustomerOne } from "../../Hooks/Customers"; import { useCustomerOne } from "../../Hooks/Customers";
import { import {
Form, Form,
Spin, Spin,
@ -13,7 +14,6 @@ import {
} from "antd"; } from "antd";
import { customerController } from "../../API/LayoutApi/customers"; import { customerController } from "../../API/LayoutApi/customers";
import Notfound from "../../Utils/Notfound"; import Notfound from "../../Utils/Notfound";
import { useCompanyOne } from "../../Hooks/Companies";
import { role } from "../../App"; import { role } from "../../App";
import { useState } from "react"; import { useState } from "react";
// @ts-ignore // @ts-ignore
@ -30,22 +30,19 @@ type params = {
const CustomerEdit = () => { const CustomerEdit = () => {
const { id } = useParams<params>(); const { id } = useParams<params>();
const { data, refetch, status } = useCustomerOne(id); const { data, refetch, status } = useCustomerOne(id);
let navigate = useNavigate();
const onSubmit = async (value: any) => { const onSubmit = async (value: any) => {
await customerController.customerPatch(value, id); await customerController.customerPatch(value, id);
refetch(); navigate(-1);
window.location.replace("/#/customers/");
}; };
const companyData = useCompanyOne(data?.id);
const ClickDelete = () => { const ClickDelete = () => {
const shouldDelete = window.confirm( const shouldDelete = window.confirm(
"Are you sure, you want to delete this Driver?" "Are you sure, you want to delete this Driver?"
); );
if (shouldDelete && id !== undefined) { if (shouldDelete && id !== undefined) {
customerController.deleteCustomerController(id).then((data: any) => { customerController.deleteCustomerController(id);
document.location.replace(`/#/customers`); navigate(-1);
});
} }
}; };
const [activeTab, setActiveTab] = useState("1"); const [activeTab, setActiveTab] = useState("1");
@ -94,19 +91,18 @@ const CustomerEdit = () => {
autoComplete="off" autoComplete="off"
> >
<Row gutter={[16, 10]}> <Row gutter={[16, 10]}>
{companyData?.data && ( <Col span={6}>
<Col span={6}> <Form.Item
<Form.Item wrapperCol={{ span: "100%" }}
wrapperCol={{ span: "100%" }} label="Company"
label="Company" >
> <Input
<Input defaultValue={data?.company?.name}
defaultValue={companyData?.data?.name} readOnly
readOnly />
/> </Form.Item>
</Form.Item> </Col>
</Col>
)}
<Col span={6}> <Col span={6}>
<Form.Item <Form.Item
wrapperCol={{ span: "100%" }} wrapperCol={{ span: "100%" }}

@ -1,8 +1,18 @@
import { Table } from "antd"; import { Table, Tooltip } from "antd";
import { useCompanyData } from "../../Hooks/Companies"; import { useCompanyData } from "../../Hooks/Companies";
import { TCustomer } from "../../types/Customer/TCustomer"; import { TCustomer } from "../../types/Customer/TCustomer";
// @ts-ignore // @ts-ignore
import tagIcon from "../../assets/tagIcon.png"; import tagIcon from "../../assets/tagIcon.png";
// @ts-ignore
import zippy from "../../assets/zippyicon.svg";
// @ts-ignore
import evo from "../../assets/evoicon.png";
// @ts-ignore
import zeelog from "../../assets/zeelogicon.svg";
// @ts-ignore
import ontime from "../../assets/ontimeicon.svg";
// @ts-ignore
import tt from "../../assets/tticon.svg";
import { role } from "../../App"; import { role } from "../../App";
function CustomerTable({ function CustomerTable({
@ -12,12 +22,6 @@ function CustomerTable({
data?: TCustomer[] | undefined; data?: TCustomer[] | undefined;
isLoading?: boolean; isLoading?: boolean;
}) { }) {
const CompanyData = useCompanyData({
name: undefined,
page: undefined,
is_active: undefined,
});
type RowProps = { type RowProps = {
id: number; id: number;
}; };
@ -30,6 +34,23 @@ function CustomerTable({
}, },
}; };
}; };
const getImageSource = (source: string) => {
switch (source) {
case "Zippy":
return zippy;
case "EVO":
return evo;
case "Ontime":
return ontime;
case "Zeelog":
return zeelog;
case "TT":
return tt;
default:
return tt;
}
};
return ( return (
<div> <div>
<Table <Table
@ -38,10 +59,7 @@ function CustomerTable({
dataSource={data?.map((u, i) => ({ dataSource={data?.map((u, i) => ({
...u, ...u,
no: i + 1, no: i + 1,
company_id: company: u?.company,
CompanyData?.data?.find(
(company: any) => company.id === u?.company_id
)?.name || "",
}))} }))}
columns={[ columns={[
{ {
@ -55,12 +73,27 @@ function CustomerTable({
}, },
{ {
title: "Company", title: "Company",
dataIndex: "company_id", dataIndex: "company",
render: (text: any, record: any) => (
<Tooltip placement="topLeft" title={text?.name}>
<div style={{ display: "flex", alignItems: "center" }}>
{text?.source && (
<img
src={getImageSource(text?.source)}
alt=""
style={{ width: 20, height: 20, marginRight: 10 }}
/>
)}
{text?.name}
</div>
</Tooltip>
),
}, },
]} ]}
rowClassName={(record, index) => rowClassName={(record, index) =>
index % 2 === 0 ? "odd-row" : "even-row" index % 2 === 0 ? "odd-row" : "even-row"
} }
pagination={false}
/> />
</div> </div>
); );

@ -7,7 +7,6 @@ const ChangePassword = () => {
const submit = () => { const submit = () => {
form.validateFields().then(async (values) => { form.validateFields().then(async (values) => {
form.resetFields(); form.resetFields();
console.log(values);
await prof.changePass(values); await prof.changePass(values);
}); });
}; };

@ -32,7 +32,7 @@ const Profile = () => {
const [range, setRange] = useState<any>(1); const [range, setRange] = useState<any>(1);
const onSubmit = async (value: TProfilePutParams) => { const onSubmit = async (value: TProfilePutParams) => {
await prof.profPatch(value); await prof.profPatch(value)
refetch(); refetch();
}; };

@ -0,0 +1,132 @@
import { Form, Tabs, Row, Col, Input, Modal, Button, Select } from "antd";
import { useState } from "react";
import { useCompanyData } from "../../Hooks/Companies";
// @ts-ignore
import zippy from "../../assets/zippyicon.svg";
// @ts-ignore
import evo from "../../assets/evoicon.png";
// @ts-ignore
import zeelog from "../../assets/zeelogicon.svg";
// @ts-ignore
import ontime from "../../assets/ontimeicon.svg";
// @ts-ignore
import tt from "../../assets/tticon.svg";
import { useCustomerByComanyData } from "../../Hooks/Customers";
const TabPane = Tabs.TabPane;
const AssignedEdit = ({ recordData, editOpen, setEditOpen }: any) => {
const handleCancel = () => {
setEditOpen(!editOpen);
};
const onSubmit = () => {};
const [companyName, setCompanyName] = useState<string>();
const [companyId, setCompanyId] = useState<number>();
const [customerName, setCustomerName] = useState<string>();
const companyData = useCompanyData({ name: companyName });
const customerData = useCustomerByComanyData({
id: companyId,
name: customerName,
});
const getImageSource = (source: string) => {
switch (source) {
case "Zippy":
return zippy;
case "EVO":
return evo;
case "Ontime":
return ontime;
case "Zeelog":
return zeelog;
case "TT":
return tt;
default:
return tt;
}
};
return (
<Modal
onCancel={handleCancel}
footer={null}
open={editOpen}
width={800}
maskClosable={true}
>
<Form
name="basic"
layout="vertical"
wrapperCol={{ span: 16 }}
initialValues={{ ...recordData }}
onFinish={onSubmit}
autoComplete="off"
>
<Row gutter={[16, 10]}>
<Col span={6}>
<Form.Item
wrapperCol={{ span: "100%" }}
label="Company"
name="company"
>
<Select
showSearch
placeholder="Search Company"
onSearch={(value: any) => setCompanyName(value)}
options={companyData?.data?.map((item) => ({
label: (
<div>
{item?.source && (
<img
style={{ width: 15, height: 20, paddingTop: 7 }}
src={getImageSource(item?.source)}
alt=""
/>
)}{" "}
{item?.name}
</div>
),
value: item?.id,
}))}
value={companyName}
filterOption={false}
autoClearSearchValue={false}
allowClear
onChange={(value: any) => setCompanyId(value)}
/>
</Form.Item>
</Col>
<Col span={6}>
<Form.Item
wrapperCol={{ span: "100%" }}
label="Driver"
name="customer"
>
<Select
showSearch
placeholder="Search Driver"
onSearch={(value: any) => setCustomerName(value)}
options={customerData?.data?.map((item) => ({
label: item?.name,
value: item?.id,
}))}
value={customerName}
filterOption={false}
autoClearSearchValue={false}
allowClear
/>
</Form.Item>
</Col>
</Row>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
</Modal>
);
};
export default AssignedEdit;

@ -1,22 +1,28 @@
import { useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { useRequestsData } from "../../Hooks/Requests"; import { useRequestsData } from "../../Hooks/Requests";
import { StepForwardOutlined, StepBackwardOutlined } from "@ant-design/icons";
import { Button, Input, Radio, RadioChangeEvent, Space } from "antd";
import { TRequests } from "../../types/Requests/TRequests";
import { TSocket } from "../../types/common/TSocket";
import RequestsEdit from "./RequestsEdit";
import RequestsTable from "./RequestsTable"; import RequestsTable from "./RequestsTable";
// @ts-ignore // @ts-ignore
import IconSearch from "../../assets/searchIcon.png"; import IconSearch from "../../assets/searchIcon.png";
import { Radio, RadioChangeEvent } from "antd";
import RequestsEdit from "./RequestsEdit";
import { TRequests } from "../../types/Requests/TRequests";
const Requests = () => { const Requests = ({ socketData }: { socketData: TSocket | undefined }) => {
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const [status, setStatus] = useState("Pending");
const [modalOpen, setModalOpen] = useState(false); const [modalOpen, setModalOpen] = useState(false);
const [requestData, setRequestData] = useState<TRequests>(); const [requestData, setRequestData] = useState<TRequests | undefined>();
const [status, setStatus] = useState("Pending");
const [page, setPage] = useState<number>(1);
const { data, refetch, isLoading } = useRequestsData({ const { data, refetch, isLoading } = useRequestsData({
search: search, search: search,
status: status, status: status,
page: page,
page_size: 10,
}); });
const [mainData, setMainData] = useState<TRequests[]>();
const timerRef = useRef<NodeJS.Timeout | null>(null); const timerRef = useRef<NodeJS.Timeout | null>(null);
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@ -31,6 +37,37 @@ const Requests = () => {
}; };
const theme = localStorage.getItem("theme") === "true" ? true : false; const theme = localStorage.getItem("theme") === "true" ? true : false;
useEffect(() => {
if (data) {
setMainData(data.data);
}
}, [data]);
// useEffect(() => {
// if (socketData) {
// setMainData((prev: TRequests[] | undefined) => {
// if (prev && prev?.length >= 15) {
// prev?.pop();
// }
// if (socketData.type === "driver_request") {
// }
// return prev;
// });
// }
// }, [socketData]);
const Next = () => {
const a = Number(page) + 1;
setPage(a);
};
const Previos = () => {
Number(page);
if (page > 1) {
const a = Number(page) - 1;
setPage(a);
}
};
return ( return (
<div> <div>
{modalOpen && ( {modalOpen && (
@ -63,16 +100,41 @@ const Requests = () => {
<Radio.Button value={"Pending"}>Pending</Radio.Button> <Radio.Button value={"Pending"}>Pending</Radio.Button>
<Radio.Button value={"Assigned"}>Assigned</Radio.Button> <Radio.Button value={"Assigned"}>Assigned</Radio.Button>
<Radio.Button value={"Rejected"}>Rejected</Radio.Button> <Radio.Button value={"Rejected"}>Rejected</Radio.Button>
<Radio.Button value={undefined}>All</Radio.Button>
</Radio.Group> </Radio.Group>
</div> </div>
<RequestsTable <RequestsTable
data={data} data={mainData}
isLoading={isLoading} isLoading={isLoading}
refetch={refetch} refetch={refetch}
setOpenModal={setModalOpen} setOpenModal={setModalOpen}
setRequestData={setRequestData} setRequestData={setRequestData}
/> />
<Space style={{ width: "100%", marginTop: 10 }} direction="vertical">
<Space style={{ width: "100%", justifyContent: "flex-end" }} wrap>
<Button
type="primary"
icon={<StepBackwardOutlined />}
onClick={Previos}
disabled={data?.previous ? false : true}
></Button>
<Input
style={{ width: 50, textAlign: "right" }}
value={page}
onChange={(e) => {
let num = e.target.value;
if (Number(num) && num !== "0") {
setPage(Number(num));
}
}}
/>
<Button
type="primary"
icon={<StepForwardOutlined />}
onClick={Next}
disabled={data?.next ? false : true}
></Button>
</Space>
</Space>
</div> </div>
); );
}; };

@ -1,7 +1,10 @@
import { Modal, Select, Button } from "antd"; import { Modal, Select, Button } from "antd";
import { TRequests } from "../../types/Requests/TRequests"; import { TRequests } from "../../types/Requests/TRequests";
import { useState } from "react"; import { useEffect, useState } from "react";
import { useCustomerData } from "../../Hooks/Customers"; import {
useCustomerByComanyData,
useCustomerData,
} from "../../Hooks/Customers";
import { requestsController } from "../../API/LayoutApi/requests"; import { requestsController } from "../../API/LayoutApi/requests";
// @ts-ignore // @ts-ignore
import plus from "../../assets/add-icon.png"; import plus from "../../assets/add-icon.png";
@ -10,6 +13,8 @@ import {
RefetchOptions, RefetchOptions,
RefetchQueryFilters, RefetchQueryFilters,
} from "react-query"; } from "react-query";
import { useCompanyData } from "../../Hooks/Companies";
import { TPagination } from "../../types/common/TPagination";
const RequestsEdit = ({ const RequestsEdit = ({
modalOpen, modalOpen,
setModalOpen, setModalOpen,
@ -18,7 +23,7 @@ const RequestsEdit = ({
}: { }: {
refetch: <TPageData>( refetch: <TPageData>(
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
) => Promise<QueryObserverResult<TRequests[], unknown>>; ) => Promise<QueryObserverResult<TPagination<TRequests[]>, unknown>>;
modalOpen: any; modalOpen: any;
setModalOpen: any; setModalOpen: any;
requestData: TRequests | undefined; requestData: TRequests | undefined;
@ -28,15 +33,49 @@ const RequestsEdit = ({
setModalOpen(!modalOpen); setModalOpen(!modalOpen);
}; };
const [companyName, setCompanyName] = useState<string>();
const [customerName, setCustomerName] = useState<string>(); const [customerName, setCustomerName] = useState<string>();
const [driverId, setDriverId] = useState<number>(); const [driverId, setDriverId] = useState<number>();
const companyData = useCompanyData({ name: companyName });
const [companyId, setCompanyId] = useState<number>();
const [customerOption, setCustomerOption] = useState<any>();
const customerData = useCustomerData({ const customerData = useCustomerData({
name: customerName, name: customerName,
page: 1,
page_size: 5,
for_driver_request: true,
});
const customerDataByCompany = useCustomerByComanyData({
id: companyId,
name: customerName,
for_driver_request: true,
}); });
const optionClick = (value: number) => { useEffect(() => {
setDriverId(value); if (companyId && customerDataByCompany) {
}; const newCustomerOption = customerDataByCompany.data?.map((item) => ({
label: item.name,
value: item.id,
}));
if (
JSON.stringify(newCustomerOption) !== JSON.stringify(customerOption)
) {
setCustomerOption(newCustomerOption);
}
} else if (!companyId && customerData) {
const newCustomerOption = customerData.data?.data.map((item) => ({
label: `${item?.name} - ${item.company?.name}`,
value: item.id,
}));
if (
JSON.stringify(newCustomerOption) !== JSON.stringify(customerOption)
) {
setCustomerOption(newCustomerOption);
}
}
}, [companyId, customerData, customerDataByCompany, customerOption]);
const assignClick = () => { const assignClick = () => {
const value = { const value = {
@ -48,15 +87,15 @@ const RequestsEdit = ({
refetch(); refetch();
setModalOpen(false); setModalOpen(false);
}); });
// console.log(value);
}; };
return ( return (
<div> <div>
<Modal <Modal
onCancel={handleCancel} onCancel={handleCancel}
footer={null} footer={null}
open={modalOpen} open={modalOpen}
width={800} width={1000}
maskClosable={true} maskClosable={true}
> >
<div className="info-div"> <div className="info-div">
@ -100,6 +139,18 @@ const RequestsEdit = ({
{requestData?.company_usdot} {requestData?.company_usdot}
</p> </p>
</tr> </tr>
{requestData?.telegram_user_link && (
<tr>
<p className={!theme ? "sub" : "sub-dark"}>Telegram User</p>
<p className={!theme ? "info" : "info-dark"}>
{requestData?.telegram_user_link ? (
<a href={requestData?.telegram_user_link}>Open Chat</a>
) : (
"This user has no username"
)}
</p>
</tr>
)}
</div> </div>
{requestData?.status === "Assigned" && ( {requestData?.status === "Assigned" && (
@ -138,15 +189,22 @@ const RequestsEdit = ({
</div> </div>
)} )}
{requestData?.status === "Pending" && ( {requestData?.status === "Pending" && (
<div className="search-driver"> <div
<div className="d-flex"> className="search-driver"
style={{
display: "flex",
alignItems: "center",
flexDirection: "column",
}}
>
<div className="d-flex" style={{ width: "100%" }}>
<Select <Select
showSearch showSearch
style={{ width: 325 }} style={{ marginRight: 15, width: "40%" }}
placeholder="Search Driver" placeholder="Search Company"
onSearch={(value) => setCustomerName(value)} onSearch={(value) => setCompanyName(value)}
onChange={(value: number) => optionClick(value)} onChange={(value: number) => setCompanyId(value)}
options={customerData?.data?.map((item) => ({ options={companyData?.data?.map((item) => ({
label: item?.name, label: item?.name,
value: item?.id, value: item?.id,
}))} }))}
@ -154,29 +212,50 @@ const RequestsEdit = ({
autoClearSearchValue={false} autoClearSearchValue={false}
allowClear allowClear
/> />
<Select
style={{ width: "50%" }}
showSearch
placeholder="Search Driver"
onSearch={(value) => setCustomerName(value)}
onChange={(value: number) => setDriverId(value)}
options={customerOption}
filterOption={false}
autoClearSearchValue={false}
allowClear
/>
<Button <Button
type="primary" type="primary"
onClick={assignClick} onClick={assignClick}
disabled={driverId ? false : true} disabled={driverId ? false : true}
style={{ marginLeft: 15 }} style={{ marginLeft: 15, width: "10%" }}
> >
Assign Assign
</Button> </Button>
</div> </div>
<Button <div
onClick={assignClick}
disabled={driverId ? true : false}
style={{ style={{
width: "100%",
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
padding: "6px 15px", justifyContent: "flex-end",
margin: 0,
}} }}
className="btn-add"
> >
<img src={plus} alt="" style={{ marginRight: 8 }} /> <Button
Add new driver onClick={assignClick}
</Button> disabled={driverId ? true : false}
style={{
padding: "6px 15px",
marginTop: 15,
marginRight: 0,
display: "flex",
alignItems: "center",
}}
className="btn-add"
>
<img src={plus} alt="" style={{ marginRight: 8 }} />
New driver
</Button>
</div>
</div> </div>
)} )}
</div> </div>

@ -10,6 +10,7 @@ import moment from "moment";
import { TRequests } from "../../types/Requests/TRequests"; import { TRequests } from "../../types/Requests/TRequests";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { requestsController } from "../../API/LayoutApi/requests"; import { requestsController } from "../../API/LayoutApi/requests";
import { TPagination } from "../../types/common/TPagination";
const RequestsTable = ({ const RequestsTable = ({
data, data,
@ -24,7 +25,7 @@ const RequestsTable = ({
isLoading: boolean; isLoading: boolean;
refetch: <TPageData>( refetch: <TPageData>(
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
) => Promise<QueryObserverResult<TRequests[], unknown>>; ) => Promise<QueryObserverResult<TPagination<TRequests[]>, unknown>>;
}) => { }) => {
const [isTextSelected, setIsTextSelected] = useState(false); const [isTextSelected, setIsTextSelected] = useState(false);
@ -55,11 +56,18 @@ const RequestsTable = ({
}; };
const patchRequest = (record: TRequests) => { const patchRequest = (record: TRequests) => {
requestsController.delete(record?.id).then(() => { requestsController
.rejectPatch({ status: "Rejected" }, record?.id)
.then(() => {
refetch();
});
};
const deleteRequest = (record: any) => {
requestsController.delete(record.id).then(() => {
refetch(); refetch();
}); });
}; };
return ( return (
<div> <div>
<Table <Table
@ -115,7 +123,12 @@ const RequestsTable = ({
dataIndex: "action", dataIndex: "action",
render: (text: string, record: TRequests) => { render: (text: string, record: TRequests) => {
return ( return (
<div> <div
style={{
display: "flex",
alignItems: "center",
}}
>
{record?.status === "Pending" && ( {record?.status === "Pending" && (
<Space> <Space>
<Button <Button
@ -127,6 +140,18 @@ const RequestsTable = ({
</Button> </Button>
</Space> </Space>
)} )}
{(record?.status === "Assigned" ||
record?.status === "Rejected") && (
<Space>
<Button
type="primary"
danger
onClick={(e) => deleteRequest(record)}
>
Delete
</Button>
</Space>
)}
</div> </div>
); );
}, },

@ -1,11 +1,12 @@
import { import {
Input,
Modal, Modal,
Form as FormAnt, Form as FormAnt,
Select, Select,
Upload, Upload,
Switch, Switch,
Button, Button,
Radio,
RadioChangeEvent,
Row, Row,
Col, Col,
} from "antd"; } from "antd";
@ -26,9 +27,12 @@ import zeelog from "../../assets/zeelogicon.svg";
import ontime from "../../assets/ontimeicon.svg"; import ontime from "../../assets/ontimeicon.svg";
// @ts-ignore // @ts-ignore
import tt from "../../assets/tticon.svg"; import tt from "../../assets/tticon.svg";
//@ts-ignore
import addicon from "../../assets/addiconpng.png";
import AddCustomer from "../Customers/AddCustomer"; import AddCustomer from "../Customers/AddCustomer";
import AddDriver from "../Companies/AddDriver"; import AddDriver from "../Companies/AddDriver";
import TextArea from "antd/es/input/TextArea"; import TextArea from "antd/es/input/TextArea";
import { isMobile } from "../../App";
const { Option } = Select; const { Option } = Select;
const AddTask = ({ const AddTask = ({
@ -46,7 +50,7 @@ const AddTask = ({
const [fileIds, setFileIds] = useState([]); const [fileIds, setFileIds] = useState([]);
const [companyName, setCompanyName] = useState<string>(); const [companyName, setCompanyName] = useState<string>();
const [customerName, setCustomerName] = useState<string>(); const [customerName, setCustomerName] = useState<string>();
const [companyId, setCompanyId] = useState<string>(); const [companyId, setCompanyId] = useState<number>();
const ServiceData = useServiceData(); const ServiceData = useServiceData();
const TeamData = useTeamData(""); const TeamData = useTeamData("");
@ -58,20 +62,13 @@ const AddTask = ({
const [driverOpen, setDriverOpen] = useState(false); const [driverOpen, setDriverOpen] = useState(false);
const [previewImage, setPreviewImage] = useState<string | null>(null);
function handlePaste(event: any) { function handlePaste(event: any) {
const clipboardData = event.clipboardData || window.Clipboard; const clipboardData = event.clipboardData || window.Clipboard;
if (clipboardData && clipboardData.items.length > 0) { if (clipboardData && clipboardData.items.length > 0) {
const clipboardItem = clipboardData.items[0]; const clipboardItem = clipboardData.items[0];
if (clipboardItem.kind === "file") { if (clipboardItem.kind === "file") {
const file = clipboardItem.getAsFile(); const file = clipboardItem.getAsFile();
const reader = new FileReader(); const reader = new FileReader();
reader.onload = (e) => {
if (e.target && e.target.result) {
setPreviewImage(e.target.result as string);
}
};
reader.readAsDataURL(file); reader.readAsDataURL(file);
taskController taskController
.addTaskFile({ files: [file] }) .addTaskFile({ files: [file] })
@ -108,6 +105,39 @@ const AddTask = ({
}; };
const [openDrive, setOpenDrive] = useState(false); const [openDrive, setOpenDrive] = useState(false);
const serviceOptions = ServiceData?.data?.map((item) => ({
label: item?.title,
value: item?.id,
}));
const sortByLabel = (a: any, b: any) => {
if (a.label === "Shift") return -1;
if (b.label === "Shift") return 1;
return 0;
};
const noteOptions = [
{ label: "No", value: "" },
{ label: "Empty", value: "Empty" },
{ label: "Bobtail", value: "Bobtail" },
];
const [note, setNote] = useState("");
const onChange = ({ target: { value } }: RadioChangeEvent) => {
setNote(value);
};
const noteOptions2 = [
{ label: "No", value: "" },
{ label: "+1 soat", value: "+1 soat" },
{ label: "+3 soat", value: "+3 soat" },
];
const [note2, setNote2] = useState("");
const onChange2 = ({ target: { value } }: RadioChangeEvent) => {
setNote2(value);
};
const [text, setText] = useState("");
const changeText = (e: any) => {
setText(e.target.value);
};
return ( return (
<div onPaste={(event) => handlePaste(event)}> <div onPaste={(event) => handlePaste(event)}>
{openDrive && ( {openDrive && (
@ -127,8 +157,11 @@ const AddTask = ({
onCancel={handleCancel} onCancel={handleCancel}
onOk={() => { onOk={() => {
form.validateFields().then(async (values) => { form.validateFields().then(async (values) => {
// const updatedValues = { ...values };
values.attachment_ids = fileIds; values.attachment_ids = fileIds;
values.note =
(text ? text + ", " : "") +
(note ? note + ", " : "") +
(note2 ? note2 + ", " : "");
form.resetFields(); form.resetFields();
await taskController.addTaskController(values); await taskController.addTaskController(values);
setOpen(!open); setOpen(!open);
@ -137,184 +170,241 @@ const AddTask = ({
> >
<FormAnt <FormAnt
form={form} form={form}
layout="horizontal" layout={isMobile ? "vertical" : "horizontal"}
name="form_in_modal" name="form_in_modal"
initialValues={{ modifier: "public" }} initialValues={{ modifier: "public" }}
> >
<FormAnt.Item <Row gutter={[16, 16]}>
label="Company" <Col span={24}>
name="company_id" <FormAnt.Item
rules={[{ required: true, message: "Please input company!" }]} label="Company"
> name="company_id"
<Select rules={[{ required: true, message: "Please input company!" }]}
showSearch >
placeholder="Search Company" <Select
onSearch={(value: any) => setCompanyName(value)} showSearch
options={companyData?.data?.map((item) => ({ placeholder="Search Company"
label: ( onSearch={(value: any) => setCompanyName(value)}
<div> options={companyData?.data?.map((item) => ({
{item?.source && ( label: (
<img <div>
style={{ width: 15, height: 20, paddingTop: 7 }} {item?.source && (
src={getImageSource(item?.source)} <img
alt="" style={{ width: 15, height: 20, paddingTop: 7 }}
/> src={getImageSource(item?.source)}
)}{" "} alt=""
{item?.name} />
</div> )}{" "}
), {item?.name}
value: item?.id, </div>
}))} ),
value={companyName} value: item?.id,
filterOption={false} }))}
autoClearSearchValue={false} value={companyName}
allowClear filterOption={false}
onChange={(value: any) => setCompanyId(value)} autoClearSearchValue={false}
/> allowClear
</FormAnt.Item> onChange={(value: any) => setCompanyId(value)}
<div />
style={{ </FormAnt.Item>
display: "flex", </Col>
justifyContent: "space-between",
}} <Col span={24}>
> <div
<FormAnt.Item style={{
label="Driver" display: "flex",
name="customer_id" justifyContent: "space-around",
style={{ width: "85%" }} alignItems: isMobile ? "center" : "none",
rules={[ }}
{ required: true, message: "Please input service points!" }, >
]} <FormAnt.Item
> label="Driver"
<Select name="customer_id"
showSearch style={{ width: "85%" }}
placeholder="Search Driver" rules={[
onSearch={(value: any) => setCustomerName(value)} { required: true, message: "Please input service points!" },
options={customerData?.data?.map((item) => ({ ]}
label: item?.name, >
value: item?.id, <Select
}))} showSearch
value={customerName} placeholder="Search Driver"
filterOption={false} onSearch={(value: any) => setCustomerName(value)}
autoClearSearchValue={false} options={customerData?.data?.map((item) => ({
allowClear label: item?.name,
/> value: item?.id,
</FormAnt.Item> }))}
<Button onClick={(e) => setDriverOpen(true)} type="primary"> value={customerName}
Add filterOption={false}
</Button> autoClearSearchValue={false}
</div> allowClear
/>
</FormAnt.Item>
<Button
onClick={(e) => setDriverOpen(true)}
type="primary"
style={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
marginTop: isMobile ? 5 : 0,
}}
>
{isMobile && <img src={addicon} alt="" />}
{!isMobile && "Add"}
</Button>
</div>
</Col>
<FormAnt.Item <Col span={isMobile ? 12 : 24}>
label="Service" <FormAnt.Item
name="service_id" label="Service"
rules={[{ required: true, message: "Please select service!" }]} name="service_id"
> rules={[{ required: true, message: "Please select service!" }]}
<Select >
options={ServiceData?.data?.map((item) => ({ <Select options={serviceOptions?.sort(sortByLabel)} />
label: item?.title, </FormAnt.Item>
value: item?.id, </Col>
}))}
/>
</FormAnt.Item>
<FormAnt.Item <Col span={isMobile ? 12 : 24}>
label="Assigned to" <FormAnt.Item
name="assigned_to_id" label="Assigned to"
rules={[ name="assigned_to_id"
{ rules={[
required: true, {
message: "Please select one of the teams!", required: true,
}, message: "Please select one of the teams!",
]} },
> ]}
<Select >
options={TeamData?.data?.map((item) => ({ <Select
label: item?.name, options={TeamData?.data?.map((item) => ({
value: item?.id, label: item?.name,
}))} value: item?.id,
/> }))}
</FormAnt.Item> />
</FormAnt.Item>
</Col>
<FormAnt.Item <Col span={isMobile ? 12 : 12}>
label="Status" <FormAnt.Item
name="status" label="Status"
rules={[ name="status"
{ required: false, message: "Please input service points!" }, rules={[
]} { required: false, message: "Please input service points!" },
> ]}
<Select defaultValue="New"> >
<Option value="New">New</Option> <Select defaultValue="New">
<Option value="Checking">Checking</Option> <Option value="New">New</Option>
<Option value="Done">Done</Option> <Option value="Checking">Checking</Option>
</Select> <Option value="Done">Done</Option>
</FormAnt.Item> </Select>
</FormAnt.Item>
</Col>
<FormAnt.Item <Col span={isMobile ? 12 : 12}>
label="PTI" <FormAnt.Item
name="pti" label="PTI"
rules={[ name="pti"
{ required: false, message: "Please input service points!" }, rules={[
]} { required: false, message: "Please input service points!" },
> ]}
<Switch /> >
</FormAnt.Item> <Switch />
</FormAnt.Item>
</Col>
<FormAnt.Item <Col span={24}>
label="Note" <FormAnt.Item
name="note" label="Note"
rules={[ name="note"
{ required: false, message: "Please input service points!" }, rules={[
]} { required: false, message: "Please input service points!" },
> ]}
<TextArea >
style={{ padding: "7px 11px" }} <TextArea
placeholder="note" style={{ padding: "7px 11px" }}
autoSize={{ minRows: 3, maxRows: 3 }} placeholder="note"
/> autoSize={{ minRows: isMobile ? 1 : 2, maxRows: 1 }}
</FormAnt.Item> onChange={changeText}
value={text}
/>
{!isMobile && (
<div
style={{
marginTop: 10,
display: "flex",
alignItems: "center",
}}
>
<Radio.Group
options={noteOptions}
onChange={onChange}
// value={value}
optionType="button"
defaultValue={""}
style={{ marginRight: 15 }}
/>
<Radio.Group
options={noteOptions2}
defaultValue={""}
onChange={onChange2}
// value={value}
optionType="button"
/>
</div>
)}
<br />
</FormAnt.Item>
</Col>
</Row>
</FormAnt> </FormAnt>
<FormAnt> <FormAnt>
<FormAnt.Item name="attachment"> <Row gutter={[16, 16]}>
<div> <Col span={isMobile ? 6 : 24}>
<Upload.Dragger <FormAnt.Item name="attachment">
name="file" <div>
multiple={true} <Upload.Dragger
customRequest={({ file, onSuccess }: any) => { name="file"
const formData = new FormData(); height={isMobile ? 100 : 150}
formData.append("file", file); multiple={true}
taskController customRequest={({ file, onSuccess }: any) => {
.addTaskFile({ task_id: undefined, files: [file] }) const formData = new FormData();
.then((response) => { formData.append("file", file);
console.log(response); taskController
.addTaskFile({ task_id: undefined, files: [file] })
const fileId = response.data.file_ids[0]; .then((response) => {
setFileIds((prevFileIds): any => [ const fileId = response.data.file_ids[0];
...prevFileIds, setFileIds((prevFileIds): any => [
fileId, ...prevFileIds,
]); fileId,
onSuccess(); ]);
// const updatedValues = form.getFieldsValue(); onSuccess();
// updatedValues.attachment_ids = [ });
// ...updatedValues.attachment_ids, }}
// fileId, >
// ]; {!isMobile ? (
// form.setFieldsValue(updatedValues); <p className={`ant-upload-drag-icon`}>
}); <UploadOutlined
}} style={{ color: "rgba(249, 158, 44, 1)" }}
> />
<p className="ant-upload-drag-icon"> </p>
<UploadOutlined style={{ color: "rgba(249, 158, 44, 1)" }} /> ) : (
</p> <UploadOutlined />
<p )}
className="ant-upload-text" {!isMobile && (
style={{ color: "rgba(249, 158, 44, 1)" }} <p
> className="ant-upload-text"
Click or drag a file here to upload style={{ color: "rgba(249, 158, 44, 1)" }}
</p> >
</Upload.Dragger> Click or drag a file here to upload (only .jpeg .jpg
</div> .png .pdf)
</FormAnt.Item> </p>
)}
</Upload.Dragger>
</div>
</FormAnt.Item>
</Col>
</Row>
</FormAnt> </FormAnt>
</Modal> </Modal>
</div> </div>

@ -11,6 +11,13 @@ import {
import TabPane from "antd/es/tabs/TabPane"; import TabPane from "antd/es/tabs/TabPane";
import { timeZone } from "../../App"; import { timeZone } from "../../App";
import { useTaskHistory } from "../../Hooks/Tasks"; import { useTaskHistory } from "../../Hooks/Tasks";
import TextArea from "antd/es/input/TextArea";
import { useEffect, useState } from "react";
import { taskController } from "../../API/LayoutApi/tasks";
import { useTeamData } from "../../Hooks/Teams";
import { TTeam } from "../../types/Team/TTeam";
import { EditOutlined, CaretRightOutlined } from "@ant-design/icons";
import { TSocket } from "../../types/common/TSocket";
// @ts-ignore // @ts-ignore
import closeIcon from "../../assets/closeIcon.png"; import closeIcon from "../../assets/closeIcon.png";
// @ts-ignore // @ts-ignore
@ -45,40 +52,28 @@ import forwardIcon from "../../assets/forward.png";
import driverIcon from "../../assets/drivericon.png"; import driverIcon from "../../assets/drivericon.png";
// @ts-ignore // @ts-ignore
import userIcon from "../../assets/userIcon.png"; import userIcon from "../../assets/userIcon.png";
import TextArea from "antd/es/input/TextArea";
import { useState } from "react";
import { taskController } from "../../API/LayoutApi/tasks";
import {
QueryObserverResult,
RefetchOptions,
RefetchQueryFilters,
} from "react-query";
import { TPagination } from "../../types/common/TPagination";
import { useTeamData } from "../../Hooks/Teams";
import { TTeam } from "../../types/Team/TTeam";
import { EditOutlined } from "@ant-design/icons";
const TaskModal = ({ const TaskModal = ({
modalOpen, modalOpen,
setModalOpen, setModalOpen,
recordTask, recordTask,
setRecordTask,
uploadOpen, uploadOpen,
setUploadOpen, setUploadOpen,
refetch, socketData,
}: { }: {
recordTask: TTask | undefined; recordTask: TTask | undefined;
modalOpen: any; setRecordTask: React.Dispatch<React.SetStateAction<TTask | undefined>>;
modalOpen: boolean;
setModalOpen: any; setModalOpen: any;
uploadOpen: any; uploadOpen: boolean;
setUploadOpen: any; setUploadOpen: any;
refetch: <TPageData>( socketData: TSocket | undefined;
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
) => Promise<QueryObserverResult<TPagination<TTask[]>, unknown>>;
}) => { }) => {
const moment = require("moment-timezone"); const moment = require("moment-timezone");
const theme = localStorage.getItem("theme") === "true" ? true : false;
const [text, setText] = useState<string | undefined>(recordTask?.note); const [text, setText] = useState<string | undefined>(recordTask?.note);
const [pti, setPti] = useState<boolean | undefined>(recordTask?.pti); const [pti, setPti] = useState<boolean | undefined>(recordTask?.pti);
const theme = localStorage.getItem("theme") === "true" ? true : false;
const [status, setStatus] = useState(recordTask?.status); const [status, setStatus] = useState(recordTask?.status);
const [teamName, setTeamName] = useState(recordTask?.assigned_to?.name); const [teamName, setTeamName] = useState(recordTask?.assigned_to?.name);
const { data, isLoading } = useTaskHistory(recordTask?.id); const { data, isLoading } = useTaskHistory(recordTask?.id);
@ -112,9 +107,41 @@ const TaskModal = ({
} }
const teamData = useTeamData(""); const teamData = useTeamData("");
const teams: MenuProps["items"] = teamData?.data?.map((item) => ({ // const teamData = useCustomerData({name: "", page: 1, page_size: 100});
const teams: MenuProps["items"] = teamData?.data?.map((item, index) => ({
key: item?.id, key: item?.id,
label: <p>{item?.name}</p>, label: (
<div
style={{
display: "flex",
alignItems: "center",
}}
>
<div
style={{
width: 10,
height: 10,
background: `rgb(${index * (255 / teamData?.data.length)}, ${
255 - index * (255 / teamData?.data.length)
}, 0)`,
padding: 5,
borderRadius: 5,
marginRight: 10,
}}
></div>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
}}
>
<p>{item?.name}</p>
<p style={{ marginLeft: 30 }}>{item?.task_count_percentage}%</p>
</div>
</div>
),
onClick: () => teampatch(item), onClick: () => teampatch(item),
})); }));
const items: MenuProps["items"] = [ const items: MenuProps["items"] = [
@ -157,7 +184,11 @@ const TaskModal = ({
taskController taskController
.taskPatch({ assigned_to_id: item?.id }, recordTask?.id) .taskPatch({ assigned_to_id: item?.id }, recordTask?.id)
.then(() => { .then(() => {
message.success({ content: "Success", duration: 1 }); message.success({
content: "Task forwarded successfully",
duration: 1,
});
setModalOpen(false);
}); });
}; };
@ -167,8 +198,24 @@ const TaskModal = ({
.then(() => { .then(() => {
message.success({ content: "Saved!" }); message.success({ content: "Saved!" });
}); });
setModalOpen(!modalOpen);
}; };
const nextStatus = (status : string) => {
console.log();
}
useEffect(() => {
if (socketData && socketData.task) {
if (
socketData.type === "task_update" &&
socketData.task.id === recordTask?.id
) {
setRecordTask(socketData.task);
}
}
}, [socketData]);
return ( return (
<Modal <Modal
onCancel={handleCancel} onCancel={handleCancel}
@ -195,6 +242,9 @@ const TaskModal = ({
{status} {status}
<EditOutlined style={{ marginLeft: 4 }} /> <EditOutlined style={{ marginLeft: 4 }} />
</button> </button>
{/* <button onClick={e > nextStatus(status)}>
<CaretRightOutlined />
</button> */}
</Dropdown> </Dropdown>
</div> </div>
<div className="mdoal-actions"> <div className="mdoal-actions">
@ -231,14 +281,13 @@ const TaskModal = ({
</div> </div>
</div> </div>
<div className="TaskModal-content"> <div className="TaskModal-content">
<Tabs> <Tabs style={{ marginLeft: 24 }}>
<TabPane <TabPane
tab={ tab={
<span <span
style={{ style={{
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
marginLeft: 24,
}} }}
> >
<img style={{ marginRight: 10 }} src={infoIcon} alt="" /> <img style={{ marginRight: 10 }} src={infoIcon} alt="" />
@ -365,12 +414,61 @@ const TaskModal = ({
dataSource={recordTask?.attachment_set?.map((u, i) => ({ dataSource={recordTask?.attachment_set?.map((u, i) => ({
no: i + 1, no: i + 1,
...u, ...u,
created: moment(u?.updated_at) created: moment(u?.created_at)
.tz(timeZone) ?.tz(timeZone)
.format("DD.MM.YYYY HH:mm"), ?.format("DD.MM.YYYY HH:mm"),
action: { ...u }, action: { ...u },
by: u,
}))} }))}
columns={[ columns={[
{
title: "User/Driver",
dataIndex: "by",
width: "25%",
key: 1,
ellipsis: {
showTitle: false,
},
render: (text: any) => (
<Tooltip
placement="topLeft"
title={
text?.uploaded_by_which_driver?.username ||
text?.uploaded_by_which_user?.username
}
>
<div style={{ display: "flex", alignItems: "center" }}>
{text?.uploaded_by_which_user ? (
<>
<img
src={getImageSource("user")}
alt=""
style={{ width: 15, height: 15, marginRight: 10 }}
/>
<p>
{text?.uploaded_by_which_user?.username
? text?.uploaded_by_which_user?.username
: ""}
</p>
</>
) : (
<>
<img
src={getImageSource("driver")}
alt=""
style={{ width: 20, height: 15, marginRight: 10 }}
/>
<p>
{text?.uploaded_by_which_driver?.name
? text?.uploaded_by_which_driver?.name
: ""}
</p>
</>
)}
</div>
</Tooltip>
),
},
{ {
title: "Name/Description", title: "Name/Description",
dataIndex: "file_name", dataIndex: "file_name",
@ -466,9 +564,8 @@ const TaskModal = ({
? { user: u?.user?.username } ? { user: u?.user?.username }
: { driver: u?.driver?.name }, : { driver: u?.driver?.name },
created: moment(u?.timestamp) created: moment(u?.timestamp)
.tz(timeZone) ?.tz(timeZone)
.format("DD.MM.YYYY HH:mm"), ?.format("DD.MM.YYYY HH:mm"),
// action: { ...u. },
}))} }))}
columns={[ columns={[
{ {
@ -480,7 +577,10 @@ const TaskModal = ({
showTitle: false, showTitle: false,
}, },
render: (text: any, record: any) => ( render: (text: any, record: any) => (
<Tooltip placement="topLeft" title={text}> <Tooltip
placement="topLeft"
title={text?.user || text?.driver}
>
<div style={{ display: "flex", alignItems: "center" }}> <div style={{ display: "flex", alignItems: "center" }}>
{text?.user ? ( {text?.user ? (
<> <>
@ -490,7 +590,7 @@ const TaskModal = ({
style={{ width: 15, height: 15, marginRight: 10 }} style={{ width: 15, height: 15, marginRight: 10 }}
/> />
<p> <p>
{typeof text.user === "string" ? text.user : ""} {typeof text?.user === "string" ? text?.user : ""}
</p> </p>
</> </>
) : ( ) : (

@ -18,7 +18,7 @@ import tt from "../../assets/tticon.svg";
import tagIcon from "../../assets/tagIcon.png"; import tagIcon from "../../assets/tagIcon.png";
// @ts-ignore // @ts-ignore
import tgIcon from "../../assets/telegram.png"; import tgIcon from "../../assets/telegram.png";
import { role } from "../../App"; import { isMobile, role } from "../../App";
const admin_id = localStorage.getItem("admin_id"); const admin_id = localStorage.getItem("admin_id");
const TaskTable = ({ const TaskTable = ({
@ -59,6 +59,15 @@ const TaskTable = ({
}); });
} }
}; };
const ptiPatch = (record: TTask) => {
Modal.confirm({
title: "Confirmation",
content: `Are you sure you want to change PTI?`,
onOk: () => {
taskController.taskPatch({ pti: !record.pti }, record.id);
},
});
};
const [isTextSelected, setIsTextSelected] = useState(false); const [isTextSelected, setIsTextSelected] = useState(false);
@ -118,7 +127,9 @@ const TaskTable = ({
{ {
title: "", title: "",
dataIndex: "no", dataIndex: "no",
width: "4%", width: isMobile ? "1%" : "5%",
fixed: isMobile ? "left" : false,
key: "1",
render: (text: any, record: TTask) => ( render: (text: any, record: TTask) => (
<div <div
style={{ style={{
@ -148,7 +159,9 @@ const TaskTable = ({
</div> </div>
), ),
dataIndex: "no", dataIndex: "no",
width: "5%", width: isMobile ? "1%" : "5%",
fixed: isMobile ? "left" : false,
key: "2",
render: (text: any, record: TTask) => ( render: (text: any, record: TTask) => (
<div <div
style={{ style={{
@ -165,6 +178,7 @@ const TaskTable = ({
title: "Company", title: "Company",
dataIndex: "company", dataIndex: "company",
width: "13%", width: "13%",
key: "3",
responsive: ["xl"], responsive: ["xl"],
ellipsis: { ellipsis: {
showTitle: true, showTitle: true,
@ -187,7 +201,8 @@ const TaskTable = ({
{ {
title: "Driver", title: "Driver",
dataIndex: "customer", dataIndex: "customer",
width: "13%", width: isMobile ? "5%" : "13%",
key: "4",
ellipsis: { ellipsis: {
showTitle: false, showTitle: false,
}, },
@ -200,7 +215,8 @@ const TaskTable = ({
{ {
title: "Service", title: "Service",
dataIndex: "service", dataIndex: "service",
width: "7%", width: isMobile ? "5%" : "7%",
key: "5",
ellipsis: { ellipsis: {
showTitle: false, showTitle: false,
}, },
@ -213,7 +229,8 @@ const TaskTable = ({
{ {
title: "Status", title: "Status",
dataIndex: "status", dataIndex: "status",
width: "8%", width: isMobile ? "5%" : "8%",
key: "6",
ellipsis: { ellipsis: {
showTitle: false, showTitle: false,
}, },
@ -230,7 +247,8 @@ const TaskTable = ({
{ {
title: "Team", title: "Team",
dataIndex: "assigned_to", dataIndex: "assigned_to",
width: "8%", width: isMobile ? "5%" : "8%",
key: "7",
ellipsis: { ellipsis: {
showTitle: false, showTitle: false,
}, },
@ -243,7 +261,8 @@ const TaskTable = ({
{ {
title: "Assignee", title: "Assignee",
dataIndex: "in_charge", dataIndex: "in_charge",
width: "12%", width: isMobile ? "5%" : "12%",
key: "8",
ellipsis: { ellipsis: {
showTitle: false, showTitle: false,
}, },
@ -257,13 +276,24 @@ const TaskTable = ({
title: "PTI", title: "PTI",
dataIndex: "pti", dataIndex: "pti",
width: "6%", width: "6%",
key: "8",
responsive: ["lg"], responsive: ["lg"],
render: (pti: boolean) => (pti ? "No need" : "Do"), render: (pti: boolean, record: TTask) =>
pti ? (
<p onClick={(e) => ptiPatch(record)} className="status-Assigned">
No need
</p>
) : (
<p onClick={(e) => ptiPatch(record)} className="status-Rejected">
Do
</p>
),
}, },
{ {
title: "Note", title: "Note",
dataIndex: "note", dataIndex: "note",
width: "12%", width: "12%",
key: "9",
responsive: ["lg"], responsive: ["lg"],
ellipsis: { ellipsis: {
showTitle: false, showTitle: false,
@ -278,6 +308,7 @@ const TaskTable = ({
title: "Created at", title: "Created at",
dataIndex: "created", dataIndex: "created",
width: "12%", width: "12%",
key: "10",
responsive: ["xxl"], responsive: ["xxl"],
ellipsis: { ellipsis: {
showTitle: false, showTitle: false,
@ -291,10 +322,12 @@ const TaskTable = ({
{ {
title: "Actions", title: "Actions",
dataIndex: "action", dataIndex: "action",
width: "8%", width: isMobile ? "3%" : "8%",
key: "11",
fixed: isMobile ? "right" : false,
render: (text: string, record: TTask) => { render: (text: string, record: TTask) => {
return ( return (
<div> <div style={{ zIndex: 1000 }}>
{role === "Checker" ? ( {role === "Checker" ? (
<Space> <Space>
{record.status === "New" && ( {record.status === "New" && (
@ -370,6 +403,9 @@ const TaskTable = ({
pagination={false} pagination={false}
loading={isLoading} loading={isLoading}
rowClassName={rowClassName} rowClassName={rowClassName}
scroll={
isMobile ? { x: "calc(800px + 40%)" } : { x: "calc(0px + 100%)" }
}
bordered bordered
/> />
</div> </div>

@ -1,29 +1,19 @@
import { Modal, Upload, Button, Space } from "antd"; import { Modal, Upload, Button, Space } from "antd";
import { taskController } from "../../API/LayoutApi/tasks"; import { taskController } from "../../API/LayoutApi/tasks";
// @ts-ignore
import uploadfile from "../../assets/uploadfile.png";
// @ts-ignore
import createIcon from "../../assets/galkaIcon.png";
import { CloseOutlined } from "@ant-design/icons"; import { CloseOutlined } from "@ant-design/icons";
import { TTask } from "../../types/Tasks/TTasks"; import { TTask } from "../../types/Tasks/TTasks";
import { useState } from "react"; import { useState } from "react";
import TextArea from "antd/es/input/TextArea"; import TextArea from "antd/es/input/TextArea";
import { // @ts-ignore
QueryObserverResult, import uploadfile from "../../assets/uploadfile.png";
RefetchOptions, // @ts-ignore
RefetchQueryFilters, import createIcon from "../../assets/galkaIcon.png";
} from "react-query";
import { TPagination } from "../../types/common/TPagination";
const TaskUploadModal = ({ const TaskUploadModal = ({
uploadOpen, uploadOpen,
recordTask, recordTask,
setUploadOpen, setUploadOpen,
refetch,
}: { }: {
refetch: <TPageData>(
options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
) => Promise<QueryObserverResult<TPagination<TTask[]>, unknown>>;
recordTask: TTask | undefined; recordTask: TTask | undefined;
uploadOpen: boolean; uploadOpen: boolean;
setUploadOpen(open: boolean): void; setUploadOpen(open: boolean): void;
@ -60,7 +50,6 @@ const TaskUploadModal = ({
description: text, description: text,
}) })
.then(() => { .then(() => {
refetch();
setUploadOpen(!uploadOpen); setUploadOpen(!uploadOpen);
}); });
}} }}
@ -109,7 +98,7 @@ const TaskUploadModal = ({
letterSpacing: "-2%", letterSpacing: "-2%",
}} }}
> >
Maximum file size is 10 MB Maximum file size is 10 MB (.jpeg, .jpg, .pdf, .png files only)
</span> </span>
</p> </p>
</Upload.Dragger> </Upload.Dragger>

@ -1,12 +1,12 @@
import { useCallback, useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import AddTask from "./AddTask"; import AddTask from "./AddTask";
import { Button, Input, Select, Space, notification } from "antd"; import { Button, Input, Select, Space } from "antd";
import TaskTable from "./TaskTable"; import TaskTable from "./TaskTable";
import { useTeamData } from "../../Hooks/Teams"; import { useTeamData } from "../../Hooks/Teams";
import { StepForwardOutlined, StepBackwardOutlined } from "@ant-design/icons"; import { StepForwardOutlined, StepBackwardOutlined } from "@ant-design/icons";
import { useTasks } from "../../Hooks/Tasks"; import { useTasks } from "../../Hooks/Tasks";
import { TTask } from "../../types/Tasks/TTasks"; import { TTask } from "../../types/Tasks/TTasks";
import { admin_id, role, team_id } from "../../App"; import { isMobile, role, team_id } from "../../App";
//@ts-ignore //@ts-ignore
import addicon from "../../assets/addiconpng.png"; import addicon from "../../assets/addiconpng.png";
//@ts-ignore //@ts-ignore
@ -15,94 +15,38 @@ import refreshicon from "../../assets/refreshIcon.png";
import IconSearch from "../../assets/searchIcon.png"; import IconSearch from "../../assets/searchIcon.png";
import TaskModal from "./TaskModal"; import TaskModal from "./TaskModal";
import TaskUploadModal from "./TaskUploadModal"; import TaskUploadModal from "./TaskUploadModal";
import { NotificationPlacement } from "antd/es/notification/interface"; import { TSocket } from "../../types/common/TSocket";
import { TCall } from "../../types/CallRequests/TCall";
const { Option } = Select; const { Option } = Select;
const Task = () => { const Task = ({ socketData }: { socketData: TSocket | undefined }) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [modalOpen, setModalOpen] = useState(false); const [modalOpen, setModalOpen] = useState(false);
const [characters, setCharacters] = useState<TTask[] | undefined>(); const [characters, setCharacters] = useState<TTask[] | undefined>();
const [team, setTeam] = useState<any>(); const [team, setTeam] = useState<any>();
const [search, setSearch] = useState<string>(""); const [search, setSearch] = useState<string>("");
const [status, setStatus] = useState<any>(); const [status, setStatus] = useState<any>();
const [page, setPage] = useState<any>(1); const [page, setPage] = useState(1);
const [uploadOpen, setUploadOpen] = useState(false); const [uploadOpen, setUploadOpen] = useState(false);
let taskSocket: WebSocket;
interface newData {
callback_request: TCall;
type: string;
task: TTask;
}
const [isLive, setIslive] = useState(true);
const [socketData, setSocketData] = useState<newData>();
const connect = async () => {
try {
if (!taskSocket || taskSocket.readyState === WebSocket.CLOSED) {
taskSocket = new WebSocket(
`ws://10.10.10.45:8080/tasks/?user_id=${admin_id}`
);
// taskSocket = new WebSocket(
// `wss://api.tteld.co/tasks/?user_id=${admin_id}`
// );
taskSocket.addEventListener("open", (event) => {
console.log("open");
setIslive(true);
});
taskSocket.addEventListener("message", (event) => {
const newData: newData = JSON.parse(event.data);
setSocketData(newData);
});
taskSocket.addEventListener("error", (errorEvent) => {
console.error("WebSocket error:", errorEvent);
});
taskSocket.addEventListener("close", (event) => {
setIslive(false);
console.log("close");
});
}
} catch (err) {}
};
useEffect(() => {
connect();
});
const [api, contextHolder] = notification.useNotification();
const openNotification = useCallback(
(placement: NotificationPlacement, data: TCall) => {
console.log(data);
api.info({
message: `Driver ${data?.driver?.name} from ${data?.company?.name} company has made a call request`,
placement,
});
},
[api]
);
useEffect(() => { useEffect(() => {
if ( if (
socketData && socketData &&
socketData.task &&
((role !== "Checker" && ((role !== "Checker" &&
(!team || team.includes(socketData?.task?.assigned_to?.id))) || (!team || team.includes(socketData?.task?.assigned_to?.id))) ||
role === "Checker") && role === "Checker") &&
(!status || status.includes(socketData.task.status)) (!status || status.includes(socketData?.task?.status))
) { ) {
setCharacters((prev: TTask[] | undefined) => { setCharacters((prev: any) => {
if (prev && prev?.length >= 15) { if (prev && prev?.length >= 15) {
prev?.pop(); prev?.pop();
} }
if (socketData.type === "task_create") { if (socketData.type === "task_create" && socketData.task) {
return [socketData.task, ...(prev || [])]; return [socketData.task, ...(prev || [])];
} else if (socketData.type === "task_update") { } else if (socketData.type === "task_update") {
if (role !== "Checker") { if (role !== "Checker") {
const updatedData = const updatedData =
prev?.filter((b: TTask) => b.id !== socketData.task.id) || []; prev?.filter((b: TTask) => b.id !== socketData?.task?.id) || [];
const data: TTask[] = [socketData.task, ...updatedData]; const data: TTask[] = [socketData.task, ...updatedData];
data.sort((a: TTask, b: TTask) => { data.sort((a: TTask, b: TTask) => {
if (a.status === "New" && b.status === "New") { if (a.status === "New" && b.status === "New") {
@ -119,28 +63,28 @@ const Task = () => {
return data; return data;
} else { } else {
const data = (prev || []).map((b: TTask) => const data = (prev || []).map((b: TTask) =>
b.id === socketData.task.id ? socketData.task : b b.id === socketData.task?.id ? socketData.task : b
); );
return data; return data;
} }
} else if (socketData.type === "task_delete") { } else if (socketData.type === "task_delete") {
const data = (prev || []).filter( const data = (prev || []).filter(
(b: TTask) => b.id !== socketData.task.id (b: TTask) => b.id !== socketData.task?.id
); );
return data; return data;
} else if (socketData.type === "task_forward") { } else if (socketData.type === "task_forward") {
if (role === "Checker") { if (role === "Checker") {
if (socketData.task.assigned_to.id === team_id) { if (socketData.task?.assigned_to.id === team_id) {
return [socketData.task, ...(prev || [])]; return [socketData.task, ...(prev || [])];
} else { } else {
const data = (prev || []).filter( const data = (prev || []).filter(
(b: TTask) => b.id !== socketData.task.id (b: TTask) => b.id !== socketData.task?.id
); );
return data; return data;
} }
} else { } else {
const updatedData = const updatedData =
prev?.filter((b: TTask) => b.id !== socketData.task.id) || []; prev?.filter((b: TTask) => b.id !== socketData.task?.id) || [];
const data: TTask[] = [socketData.task, ...updatedData]; const data: TTask[] = [socketData.task, ...updatedData];
data.sort((a: TTask, b: TTask) => { data.sort((a: TTask, b: TTask) => {
if (a.status === "New" && b.status === "New") { if (a.status === "New" && b.status === "New") {
@ -156,17 +100,11 @@ const Task = () => {
}); });
return data; return data;
} }
} else if (socketData.type === "callback_request") {
if (socketData?.callback_request) {
console.log("run");
openNotification("bottomRight", socketData?.callback_request);
}
} }
return prev; return prev;
}); });
} }
}, [socketData, openNotification]); }, [socketData]);
const teamData = useTeamData(""); const teamData = useTeamData("");
@ -175,12 +113,13 @@ const Task = () => {
label: item?.name, label: item?.name,
value: item?.id, value: item?.id,
})); }));
const page_size = isMobile ? 10 : 15;
const { data, isLoading, refetch } = useTasks({ const { data, isLoading, refetch } = useTasks({
search, search,
status, status,
team, team,
page, page,
page_size,
}); });
useEffect(() => { useEffect(() => {
if (data) { if (data) {
@ -227,11 +166,9 @@ const Task = () => {
const theme = localStorage.getItem("theme") === "true" ? true : false; const theme = localStorage.getItem("theme") === "true" ? true : false;
return ( return (
<div> <div>
{contextHolder}
{open && <AddTask open={open} setOpen={setOpen} />} {open && <AddTask open={open} setOpen={setOpen} />}
{uploadOpen && ( {uploadOpen && (
<TaskUploadModal <TaskUploadModal
refetch={refetch}
recordTask={recordTask} recordTask={recordTask}
uploadOpen={uploadOpen} uploadOpen={uploadOpen}
setUploadOpen={setUploadOpen} setUploadOpen={setUploadOpen}
@ -242,46 +179,44 @@ const Task = () => {
uploadOpen={uploadOpen} uploadOpen={uploadOpen}
setUploadOpen={setUploadOpen} setUploadOpen={setUploadOpen}
recordTask={recordTask} recordTask={recordTask}
setRecordTask={setRecordTask}
modalOpen={modalOpen} modalOpen={modalOpen}
socketData={socketData}
setModalOpen={setModalOpen} setModalOpen={setModalOpen}
refetch={refetch}
/> />
)} )}
<div className="header d-flex"> <div className="header d-flex">
<div className="header-title d-flex"> <div className="header-title d-flex">
<p className="title">Tasks</p> <p className="title">Tasks</p>
{isLive ? (
<div className="d-flex" style={{ marginRight: 15 }}>
<div className="circle"></div>
<p className={!theme ? "live-p" : "live-p-dark"}>online</p>
</div>
) : (
<div className="d-flex" style={{ marginRight: 15 }}>
<div className="circle2"></div>
<p className="live-p">offline</p>
</div>
)}
</div> </div>
<div className="d-flex"> <div className="d-flex">
{role !== "Checker" && ( {role !== "Checker" && (
<button className="btn-add d-flex" onClick={showModal}> <button className="btn-add d-flex" onClick={showModal}>
<img style={{ marginRight: 8 }} src={addicon} alt="" /> <img
Add Task style={{ marginRight: isMobile ? "0px" : "8px" }}
src={addicon}
alt=""
/>
{!isMobile && "Add Task"}
</button> </button>
)} )}
<button <button
className={`btn-refresh-${theme && "dark"} d-flex`} className={`btn-refresh-${theme && "dark"} d-flex`}
onClick={() => { onClick={() => {
refetch(); refetch();
connect(); // connect();
}} }}
> >
<img style={{ marginRight: 8 }} src={refreshicon} alt="" /> <img
Refresh style={{ marginRight: isMobile ? "-8px" : "8px" }}
src={refreshicon}
alt=""
/>
{!isMobile && "Refetch"}
</button> </button>
</div> </div>
</div> </div>
<div className="filter d-flex"> <div className={`filter ${isMobile ? "mobile-filter" : "d-flex"}`}>
<div className="search-div"> <div className="search-div">
<img src={IconSearch} alt="" /> <img src={IconSearch} alt="" />
<input <input
@ -292,7 +227,12 @@ const Task = () => {
/> />
</div> </div>
<Select <Select
style={{ width: 260, marginLeft: 12 }} style={{
width: 260,
marginLeft: 12,
marginTop: isMobile ? 10 : 0,
marginBottom: isMobile ? 10 : 0,
}}
placeholder="status" placeholder="status"
onChange={(value: any) => setStatus(value)} onChange={(value: any) => setStatus(value)}
mode="multiple" mode="multiple"
@ -322,6 +262,7 @@ const Task = () => {
type="primary" type="primary"
icon={<StepBackwardOutlined />} icon={<StepBackwardOutlined />}
onClick={Previos} onClick={Previos}
disabled={data?.previous ? false : true}
></Button> ></Button>
<Input <Input
style={{ width: 50, textAlign: "right" }} style={{ width: 50, textAlign: "right" }}
@ -329,7 +270,7 @@ const Task = () => {
onChange={(e) => { onChange={(e) => {
let num = e.target.value; let num = e.target.value;
if (Number(num) && num !== "0") { if (Number(num) && num !== "0") {
setPage(num); setPage(Number(num));
} }
}} }}
/> />
@ -337,6 +278,7 @@ const Task = () => {
type="primary" type="primary"
icon={<StepForwardOutlined />} icon={<StepForwardOutlined />}
onClick={Next} onClick={Next}
disabled={data?.next ? false : true}
></Button> ></Button>
</Space> </Space>
</Space> </Space>

@ -55,30 +55,7 @@ const TeamTable = ({
title: "Created at", title: "Created at",
dataIndex: "created", dataIndex: "created",
}, },
{
title: "Is Active",
dataIndex: "is_active",
render: (tag: boolean) => (
<Tag color={tag ? "geekblue" : "red"}>{tag ? "True" : "False"}</Tag>
),
filters: [
{
text: "True",
value: true,
},
{
text: "False",
value: false,
},
],
onFilter: (value: string | number | boolean, record: TTeam) => {
return record.is_active === value;
},
},
]} ]}
rowClassName={(record, index) =>
index % 2 === 0 ? "odd-row" : "even-row"
}
/> />
); );
}; };

@ -2,7 +2,6 @@ import { Input, Modal, Form as FormAnt, Select, Upload } from "antd";
import { updateController } from "../../API/LayoutApi/update"; import { updateController } from "../../API/LayoutApi/update";
import { useState } from "react"; import { useState } from "react";
import { UploadOutlined } from "@ant-design/icons"; import { UploadOutlined } from "@ant-design/icons";
import { taskController } from "../../API/LayoutApi/tasks";
import { useCompanyData } from "../../Hooks/Companies"; import { useCompanyData } from "../../Hooks/Companies";
import { useCustomerByComanyData } from "../../Hooks/Customers"; import { useCustomerByComanyData } from "../../Hooks/Customers";
import { import {
@ -29,10 +28,9 @@ const AddUpdate = ({
refetch(); refetch();
setOpen(!open); setOpen(!open);
}; };
const [fileIds, setFileIds] = useState([]);
const [companyName, setCompanyName] = useState<string>(""); const [companyName, setCompanyName] = useState<string>("");
const [customerName, setCustomerName] = useState<string>(""); const [customerName, setCustomerName] = useState<string>("");
const [companyId, setCompanyId] = useState<string>(); const [companyId, setCompanyId] = useState<number>();
const companyData = useCompanyData({ name: companyName }); const companyData = useCompanyData({ name: companyName });
const customerData = useCustomerByComanyData({ const customerData = useCustomerByComanyData({
@ -40,7 +38,6 @@ const AddUpdate = ({
name: customerName, name: customerName,
}); });
const [imgname, setImgname] = useState<any>([]);
function handlePaste(event: any) { function handlePaste(event: any) {
const clipboardData = event.clipboardData || window.Clipboard; const clipboardData = event.clipboardData || window.Clipboard;
if (clipboardData && clipboardData.items.length > 0) { if (clipboardData && clipboardData.items.length > 0) {
@ -76,7 +73,6 @@ const AddUpdate = ({
onOk={() => { onOk={() => {
form.validateFields().then(async (values) => { form.validateFields().then(async (values) => {
const updatedValues = { ...values }; const updatedValues = { ...values };
updatedValues.attachment_ids = fileIds;
form.resetFields(); form.resetFields();
await updateController.addUpdateController(updatedValues); await updateController.addUpdateController(updatedValues);
setOpen(!open); setOpen(!open);
@ -187,7 +183,6 @@ const AddUpdate = ({
Click or drag file to this area to upload Click or drag file to this area to upload
</p> </p>
</Upload.Dragger> </Upload.Dragger>
<p>{imgname.join(",\n")}</p>
</FormAnt.Item> </FormAnt.Item>
</FormAnt> </FormAnt>
</Modal> </Modal>

@ -1,6 +1,6 @@
import { useState } from "react"; import { useState } from "react";
import AddUpdate from "./AddUpdate"; import AddUpdate from "./AddUpdate";
import { Button, Select } from "antd"; import { Select } from "antd";
import UpdateTable from "./UpdateTable"; import UpdateTable from "./UpdateTable";
import { useUpdateData } from "../../Hooks/Update"; import { useUpdateData } from "../../Hooks/Update";
//@ts-ignore //@ts-ignore

@ -94,7 +94,7 @@ const UpdateTable = ({
company_name: CompanyData?.data?.find( company_name: CompanyData?.data?.find(
(company: any) => company.id === u.company_id (company: any) => company.id === u.company_id
)?.name, )?.name,
customer_name: CustomerData?.data?.find( customer_name: CustomerData?.data?.data?.find(
(customer: any) => customer.id === u.customer_id (customer: any) => customer.id === u.customer_id
)?.name, )?.name,
in_charge_name: AdminData?.data?.find( in_charge_name: AdminData?.data?.find(
@ -191,8 +191,8 @@ const UpdateTable = ({
<p className="status-in-progress">Checking</p> <p className="status-in-progress">Checking</p>
)} )}
{status === "New" && <p className="status-new">New</p>} {status === "New" && <p className="status-new">New</p>}
{status === "Setup" && <p className="status-setup">Setup</p>} {status === "Setup" && <p className="status-new">Setup</p>}
{status === "Paper" && <p className="status-paper">Paper</p>} {status === "Paper" && <p className="status-new">Paper</p>}
</span> </span>
), ),
}, },

@ -26,13 +26,11 @@ const TabPane = Tabs.TabPane;
type params = { type params = {
readonly id: string; readonly id: string;
}; };
type MyObjectType = {
[key: string | number]: any;
};
const UserEdit = () => { const UserEdit = () => {
const { id } = useParams<params>(); const { id } = useParams<params>();
const { data, refetch, status }: MyObjectType = useUserOne(id); const { data, refetch, status } = useUserOne(id);
const onSubmit = async (value: any) => { const onSubmit = async (value: any) => {
id && (await userController.userPatch(value, id)); id && (await userController.userPatch(value, id));
@ -69,80 +67,83 @@ const UserEdit = () => {
{status === "loading" ? ( {status === "loading" ? (
<Spin size="large" spinning={!data} /> <Spin size="large" spinning={!data} />
) : data ? ( ) : data ? (
<Spin size="large" spinning={!data}> <Space
<Space direction="vertical"
direction="vertical" size="middle"
size="middle" style={{ display: "flex" }}
style={{ display: "flex" }} >
<Tabs
defaultActiveKey="1"
activeKey={activeTab}
onChange={(key) => setActiveTab(key)}
> >
<Tabs <TabPane
defaultActiveKey="1" tab={
activeKey={activeTab} <span style={{ display: "flex", alignItems: "center" }}>
onChange={(key) => setActiveTab(key)} <img
style={{ marginRight: 10 }}
src={activeTab === "1" ? infoIconActive : infoIcon}
alt=""
/>
Information
</span>
}
key="1"
> >
<TabPane <Space
tab={ direction="vertical"
<span style={{ display: "flex", alignItems: "center" }}> size="middle"
<img style={{ display: "flex" }}
style={{ marginRight: 10 }}
src={activeTab === "1" ? infoIconActive : infoIcon}
alt=""
/>
Information
</span>
}
key="1"
> >
<Space <Form
direction="vertical" name="basic"
size="middle" layout="vertical"
style={{ display: "flex" }} wrapperCol={{ span: 16 }}
initialValues={{ ...data }}
onFinish={onSubmit}
autoComplete="off"
> >
<Form <Row gutter={[16, 10]}>
name="basic" <Col span={6}>
layout="vertical" <Form.Item
wrapperCol={{ span: 16 }} wrapperCol={{ span: "100%" }}
initialValues={{ ...data }} label="First name"
onFinish={onSubmit} name="first_name"
autoComplete="off" >
> <Input readOnly />
<Row gutter={[16, 10]}> </Form.Item>
<Col span={6}> </Col>
<Form.Item <Col span={6}>
wrapperCol={{ span: "100%" }} <Form.Item
label="First name" wrapperCol={{ span: "100%" }}
name="first_name" label="Last name"
> name="last_name"
<Input readOnly /> >
</Form.Item> <Input readOnly />
</Col> </Form.Item>
<Col span={6}> </Col>
<Form.Item <Col span={6}>
wrapperCol={{ span: "100%" }} <Form.Item
label="Last name" wrapperCol={{ span: "100%" }}
name="last_name" label="Username"
> name="username"
<Input readOnly /> >
</Form.Item> <Input readOnly />
</Col> </Form.Item>
<Col span={6}> </Col>
<Form.Item <Col span={4}>
wrapperCol={{ span: "100%" }} <Form.Item
label="Username" wrapperCol={{ span: "100%" }}
name="username" label="Team"
> name="team_id"
<Input readOnly /> >
</Form.Item> <Select
</Col> options={TeamOption}
<Col span={4}> defaultValue={data?.team?.name}
<Form.Item />
wrapperCol={{ span: "100%" }} </Form.Item>
label="Team" </Col>
name="team_id" {role === "Owner" && (
>
<Select options={TeamOption} />
</Form.Item>
</Col>
<Col span={4}> <Col span={4}>
<Form.Item <Form.Item
wrapperCol={{ span: "100%" }} wrapperCol={{ span: "100%" }}
@ -154,31 +155,32 @@ const UserEdit = () => {
label: item?.name, label: item?.name,
value: item?.id, value: item?.id,
}))} }))}
defaultValue={data?.role?.name}
/> />
</Form.Item> </Form.Item>
</Col> </Col>
</Row> )}
<Form.Item> </Row>
{role !== "Checker" && ( <Form.Item>
<Button {role !== "Checker" && (
onClick={() => ClickDelete()} <Button
type="primary" onClick={() => ClickDelete()}
style={{ marginRight: 10 }} type="primary"
danger style={{ marginRight: 10 }}
> danger
Delete >
</Button> Delete
)}
<Button type="primary" htmlType="submit">
Submit
</Button> </Button>
</Form.Item> )}
</Form> <Button type="primary" htmlType="submit">
</Space> Submit
</TabPane> </Button>
</Tabs> </Form.Item>
</Space> </Form>
</Spin> </Space>
</TabPane>
</Tabs>
</Space>
) : ( ) : (
<Notfound /> <Notfound />
)} )}

@ -21,8 +21,6 @@ const UserTable = ({
) => Promise<QueryObserverResult<TUser[], unknown>>; ) => Promise<QueryObserverResult<TUser[], unknown>>;
}) => { }) => {
const navigate = useNavigate(); const navigate = useNavigate();
const TeamData = useTeamData("");
const Row = (record: TUser) => { const Row = (record: TUser) => {
let isTextSelected = false; let isTextSelected = false;
document.addEventListener("selectionchange", () => { document.addEventListener("selectionchange", () => {
@ -49,13 +47,8 @@ const UserTable = ({
onRow={(record) => Row(record)} onRow={(record) => Row(record)}
dataSource={data?.map((u, i) => ({ dataSource={data?.map((u, i) => ({
no: i + 1, no: i + 1,
team: TeamData?.data?.map((team: any) => { team_name: u?.team?.name,
if (team.id === u?.team_id) { role_name: u?.role?.name,
return team?.name;
} else {
return null;
}
}),
action: { id: u.id }, action: { id: u.id },
...u, ...u,
}))} }))}
@ -72,7 +65,11 @@ const UserTable = ({
}, },
{ {
title: "Team", title: "Team",
dataIndex: "team", dataIndex: "team_name",
},
{
title: "Role",
dataIndex: "role_name",
}, },
{ {
title: "Is Active", title: "Is Active",

@ -1,10 +1,18 @@
import { useQuery } from "react-query"; import { useQuery } from "react-query";
import { callController } from "../../API/LayoutApi/callrequests"; import { callController } from "../../API/LayoutApi/callrequests";
export const useCallData = ({ status }: { status: string }) => { export const useCallData = ({
status,
page,
page_size,
}: {
status: string;
page: number;
page_size: number;
}) => {
return useQuery( return useQuery(
[`callback-requests/`, { status }], [`callback-requests/`, { status, page, page_size }],
() => callController.read({ status }), () => callController.read({ status, page, page_size }),
{ {
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
} }

@ -11,8 +11,19 @@ export const useCompanyData = ({
}: TCompanyGetParams) => { }: TCompanyGetParams) => {
return useQuery( return useQuery(
[`companies/`, name, page, is_active], [`companies/`, name, page, is_active],
() => () => companyController.read({ name, page, is_active }),
companyController.read({ name: name, page: page, is_active: is_active }), { refetchOnWindowFocus: false }
);
};
export const useCompanyPaginated = ({
name,
page,
is_active,
page_size,
}: TCompanyGetParams) => {
return useQuery(
[`companies/`, name, page, is_active, page_size],
() => companyController.readPaginated({ name, page, is_active, page_size }),
{ refetchOnWindowFocus: false } { refetchOnWindowFocus: false }
); );
}; };

@ -9,16 +9,18 @@ export const useCustomerData = ({
name, name,
page, page,
is_active, is_active,
pageSize, page_size,
for_driver_request,
}: TCustomerGetParams) => { }: TCustomerGetParams) => {
return useQuery( return useQuery(
[`customers/`, name, page, is_active, pageSize], [`customers/`, name, page, is_active, page_size, for_driver_request],
() => () =>
customerController.read({ customerController.read({
name: name, name,
page: page, page,
is_active: is_active, is_active,
pageSize: pageSize, page_size,
for_driver_request,
}), }),
{ refetchOnWindowFocus: false } { refetchOnWindowFocus: false }
); );
@ -27,10 +29,11 @@ export const useCustomerData = ({
export const useCustomerByComanyData = ({ export const useCustomerByComanyData = ({
name, name,
id, id,
for_driver_request,
}: TCustomerByCompanyGetParams) => { }: TCustomerByCompanyGetParams) => {
return useQuery( return useQuery(
[`customers-by-company/${id}`, name], [`customers-by-company/${id}`, name, for_driver_request],
() => customerController.customerByCompany(id, name), () => customerController.customerByCompany(id, name, for_driver_request),
{ refetchOnWindowFocus: false } { refetchOnWindowFocus: false }
); );
}; };

@ -4,10 +4,26 @@ import {
TRequestsGetParams, TRequestsGetParams,
} from "../../API/LayoutApi/requests"; } from "../../API/LayoutApi/requests";
export const useRequestsData = ({ search, status }: TRequestsGetParams) => { export const useRequestsData = ({
search,
status,
page,
page_size,
for_driver_request,
}: TRequestsGetParams) => {
return useQuery( return useQuery(
[`driver-requests/`, { search, status }], [
() => requestsController.read({ search, status }), `driver-requests/`,
{ search, status, page, page_size, for_driver_request },
],
() =>
requestsController.read({
search,
status,
page,
page_size,
for_driver_request,
}),
{ refetchOnWindowFocus: false } { refetchOnWindowFocus: false }
); );
}; };

@ -1,15 +1,21 @@
import { useQuery } from "react-query"; import { useQuery } from "react-query";
import { TTasksGetParams, taskController } from "../../API/LayoutApi/tasks"; import { TTasksGetParams, taskController } from "../../API/LayoutApi/tasks";
export const useTasks = ({ search, status, team, page }: TTasksGetParams) => { export const useTasks = ({
search,
status,
team,
page,
page_size,
}: TTasksGetParams) => {
return useQuery( return useQuery(
[`tasks/`, search, status, team, page], [`tasks/`, search, status, team, page, page_size],
() => taskController.read({ search, status, team, page }), () => taskController.read({ search, status, team, page, page_size }),
{ refetchOnWindowFocus: false } { refetchOnWindowFocus: false }
); );
}; };
export const useTaskOne = (taskId: number) => { export const useTaskOne = (taskId: number | undefined) => {
return useQuery( return useQuery(
[`task/${taskId}/`, taskId], [`task/${taskId}/`, taskId],
() => taskController.taskOne(taskId), () => taskController.taskOne(taskId),

@ -2,16 +2,12 @@ import { useQuery } from "react-query";
import { teamController } from "../../API/LayoutApi/teams"; import { teamController } from "../../API/LayoutApi/teams";
export const useTeamData = (name: string) => { export const useTeamData = (name: string) => {
return useQuery( return useQuery([`teams/?name=${name}/`], () => teamController.read(name), {
[`teams/?name=${name}/`, name], refetchOnWindowFocus: false,
() => teamController.read(name), });
{ refetchOnWindowFocus: false }
);
}; };
export const useTeamOne = ( export const useTeamOne = (teamId: number | string | undefined): any => {
teamId: number | string | undefined
): any => {
return useQuery( return useQuery(
[`team/${teamId || "all"}`, teamId], [`team/${teamId || "all"}`, teamId],
() => teamController.teamOne(teamId), () => teamController.teamOne(teamId),

@ -1,17 +1,15 @@
import { useQuery } from "react-query"; import { useQuery } from "react-query";
import { TUsersGetParams, userController } from "../../API/LayoutApi/users"; import { TUsersGetParams, userController } from "../../API/LayoutApi/users";
export const useUserData = ({name, team, role}: TUsersGetParams) => { export const useUserData = ({ name, team, role }: TUsersGetParams) => {
return useQuery( return useQuery(
[`users/admins/`, {name, team, role}], [`users/admins/`, { name, team, role }],
() => userController.read({name, team, role}), () => userController.read({ name, team, role }),
{ refetchOnWindowFocus: false } { refetchOnWindowFocus: false }
); );
}; };
export const useUserOne = ( export const useUserOne = (userId?: number | string) => {
userId: number | string | undefined
): any => {
return useQuery( return useQuery(
[`user/${userId || "all"}`, userId], [`user/${userId || "all"}`, userId],
() => userController.userOne(userId), () => userController.userOne(userId),
@ -19,9 +17,7 @@ export const useUserOne = (
); );
}; };
export const useCheckUser = ( export const useCheckUser = (username: string): any => {
username: string
): any => {
return useQuery( return useQuery(
[`user/${username}/`], [`user/${username}/`],
() => userController.CheckUsername(username), () => userController.CheckUsername(username),

@ -1,140 +1,17 @@
import { MenuProps } from "antd";
import { Link } from "react-router-dom";
import Company from "../Components/Companies/Companies"; import Company from "../Components/Companies/Companies";
import CompanyEdit from "../Components/Companies/CompaniesEdit"; import CompanyEdit from "../Components/Companies/CompaniesEdit";
import Customer from "../Components/Customers/Customers"; import Customer from "../Components/Customers/Customers";
import CustomerEdit from "../Components/Customers/CustomersEdit"; import CustomerEdit from "../Components/Customers/CustomersEdit";
import Service from "../Components/Services/Services"; import Service from "../Components/Services/Services";
import ServiceEdit from "../Components/Services/ServiceEdit"; import ServiceEdit from "../Components/Services/ServiceEdit";
import Task from "../Components/Tasks/Tasks";
import TeamEdit from "../Components/Teams/TeamEdit"; import TeamEdit from "../Components/Teams/TeamEdit";
import Team from "../Components/Teams/Teams"; import Team from "../Components/Teams/Teams";
import User from "../Components/Users/Users"; import User from "../Components/Users/Users";
import UserEdit from "../Components/Users/UserEdit"; import UserEdit from "../Components/Users/UserEdit";
import MenuItem from "antd/es/menu/MenuItem";
import Stat from "../Components/Statistics/Statistic"; import Stat from "../Components/Statistics/Statistic";
import Profile from "../Components/Profile/Profile"; import Profile from "../Components/Profile/Profile";
import Update from "../Components/Updates/Update"; import Update from "../Components/Updates/Update";
import UpdateEdit from "../Components/Updates/UpdateEdit"; import UpdateEdit from "../Components/Updates/UpdateEdit";
// @ts-ignore
import taskIcon from "../assets/tasknavicon.png";
// @ts-ignore
import companyIcon from "../assets/companynavicon.png";
// @ts-ignore
import serviceIcon from "../assets/servicenavicon.png";
// @ts-ignore
import teamIcon from "../assets/teamnavicon.png";
// @ts-ignore
import statisticIcon from "../assets/statnavicon.png";
// @ts-ignore
import updateIcon from "../assets/updatenavicon.png";
// @ts-ignore
import userIcon from "../assets/usernavicon.png";
// @ts-ignore
import driverIcon from "../assets/customersIcon.png";
// @ts-ignore
import requestIcon from "../assets/requestIcon.png";
// @ts-ignore
import callIcon from "../assets/callIcon.png";
import Requests from "../Components/Requests/Requests";
import Call from "../Components/CallRequests/Call";
const loc: any = localStorage.getItem("user");
const role = JSON.parse(loc)?.role;
type MenuItem = Required<MenuProps>["items"][number];
function getItem(
label: React.ReactNode,
key: React.Key,
icon?: React.ReactNode,
children?: MenuItem[]
): MenuItem {
return {
key,
icon,
children,
label,
} as MenuItem;
}
export const allMenu: MenuItem[] = [
getItem(<Link to="/">Tasks</Link>, "/", <img alt="" src={taskIcon} />),
getItem(
<Link to="companies/">Companies</Link>,
"companies/",
<img alt="" src={companyIcon} />
),
getItem(
<Link to="customers/">Drivers</Link>,
"customers/",
<img alt="" src={driverIcon} />
),
getItem(
<Link to="services/">Services</Link>,
"services/",
<img alt="" src={serviceIcon} />
),
];
if (role === "Tech Support") {
allMenu.push(
getItem(
<Link to="teams/">Teams</Link>,
"teams/",
<img alt="" src={teamIcon} />
),
getItem(
<Link to="updates/">Updates</Link>,
"updates/",
<img alt="" src={updateIcon} />
),
getItem(
<Link to="requests/">Driver Requests</Link>,
"requests/",
<img alt="" src={requestIcon} />
),
getItem(
<Link to="call/">Call Requests</Link>,
"call/",
<img alt="" src={callIcon} />
)
);
}
if (role === "Owner") {
allMenu.push(
getItem(
<Link to="users/">Users</Link>,
"users/",
<img alt="" src={userIcon} />
),
getItem(
<Link to="teams/">Teams</Link>,
"teams/",
<img alt="" src={teamIcon} />
),
getItem(
<Link to="stats/">Statistics</Link>,
"stats/",
<img alt="" src={statisticIcon} />
),
getItem(
<Link to="updates/">Updates</Link>,
"updates/",
<img alt="" src={updateIcon} />
),
getItem(
<Link to="requests/">Driver Requests</Link>,
"requests/",
<img alt="" src={requestIcon} />
),
getItem(
<Link to="call/">Call Requests</Link>,
"call/",
<img alt="" src={callIcon} />
)
);
}
type TItems = { type TItems = {
path: string; path: string;
@ -173,11 +50,6 @@ export const mainItems: TItems[] = [
component: <ServiceEdit />, component: <ServiceEdit />,
key: "/service/:id/", key: "/service/:id/",
}, },
{
path: "/",
component: <Task />,
key: "tasks",
},
]; ];
export const superItems: TItems[] = [ export const superItems: TItems[] = [
@ -221,14 +93,4 @@ export const superItems: TItems[] = [
component: <UpdateEdit />, component: <UpdateEdit />,
key: "/update/:id/", key: "/update/:id/",
}, },
{
path: "/requests/",
component: <Requests />,
key: "/requests/",
},
{
path: "/call/",
component: <Call />,
key: "/call/",
},
]; ];

@ -0,0 +1,147 @@
export const dark = {
components: {
Table: {
colorBgContainer: "#202020",
colorText: "#BBBBBB",
headerColor: "#BBBBBB",
borderColor: "#3A3A3A",
headerSplitColor: "#3A3A3A",
rowHoverBg: "#333333",
colorBorder: "#3A3A3A",
},
Layout: {
bodyBg: "#181818",
},
Input: {
colorBgContainer: "#2A2A2A",
colorBgContainerDisabled: "#2A2A2A",
colorText: "#BBBBBB",
colorTextPlaceholder: "#BBBBBB",
colorBorder: "#3A3A3A",
colorFillSecondary: "rgba(0, 0, 0, 0.02)",
activeBorderColor: "#3A3A3A",
activeShadow: "#3A3A3A",
hoverBorderColor: "#3A3A3A",
},
Select: {
colorBgContainer: "#2A2A2A",
colorText: "#BBBBBB",
colorTextPlaceholder: "#BBBBBB",
colorBorder: "rgba(150, 150, 150, 0.493)",
colorPrimaryHover: "rgba(249, 158, 44, 1)",
colorIconHover: "#BBB",
optionSelectedBg: "#2A2A2A",
colorBgElevated: "#333",
controlOutline: "none",
optionActiveBg: "#333333",
colorTextQuaternary: "#3A3A3A",
},
Button: {
colorBorderSecondary: "rgba(249, 158, 44, 1)",
colorPrimary: "rgba(249, 158, 44, 1)",
colorPrimaryHover: "#BBBBBB",
colorIcon: "rgba(249, 158, 44, 1)",
colorIconHover: "rgba(249, 158, 44, 1)",
primaryShadow: "none",
dangerShadow: "none",
colorTextDisabled: "#AAAAAA",
borderColorDisabled: "#3A3A3A",
},
// Form: {
// labelColor: "#BBBBBB",
// },
Tabs: {
itemColor: "#BBBBBB",
itemHoverColor: "#FFFFFF",
itemSelectedColor: "rgba(249, 158, 44, 1)",
colorPrimaryActive: "rgba(249, 158, 44, 1)",
inkBarColor: "rgba(249, 158, 44, 1)",
},
Modal: {
contentBg: "#3A3A3A",
headerBg: "#3A3A3A",
titleColor: "#FFFFFF",
colorText: "#BBBBBB",
colorBgTextActive: "#BBBBBB",
colorBgTextHover: "#BBBBBB",
},
Menu: {
darkItemSelectedBg: "#3A3A3A",
colorBgContainer: "#fff",
},
Switch: {
colorPrimary: "#565656",
colorPrimaryHover: "#737373",
},
Radio: {
colorText: "#737373",
colorBorder: "#3A3A3A",
colorPrimaryActive: "#BBBBBB",
buttonCheckedBg: "rgba(249, 158, 44, 1)",
colorPrimaryHover: "#737373",
colorPrimary: "#565656",
},
Dropdown: {
colorBgContainer: "#3A3A3A",
colorText: "#BBBBBB",
colorPrimaryHover: "#565656",
colorPrimary: "#333333",
},
DatePicker: {
colorBgContainer: "#3A3A3A",
colorBgElevated: "#3A3A3A",
colorText: "#BBBBBB",
colorTextPlaceholder: "#BBBBBB",
colorIcon: "#fff",
colorIconHover: "#fff",
colorPrimary: "rgba(249, 158, 44, 1)",
hoverBorderColor: "#BBBBBB",
},
Empty: {
colorText: "rgba(249, 158, 44, 1)",
colorTextDisabled: "rgba(249, 158, 44, 1)",
},
},
token: {
fontFamily: "Inter, sans-serif",
colorText: "#bbb",
borderRadius: 8,
},
};
export const light = {
components: {
Select: {
colorTextPlaceholder: "rgba(155, 157, 170, 1)",
colorPrimary: "rgba(249, 158, 44, 1)",
colorPrimaryHover: "rgba(249, 158, 44, 1)",
},
Tabs: {
inkBarColor: "rgba(249, 158, 44, 1)",
itemSelectedColor: "rgba(24, 26, 41, 1)",
itemHoverColor: "rgba(24, 26, 41, 1)",
},
Input: {
hoverBorderColor: "rgba(249, 158, 44, 1)",
activeBorderColor: "rgba(249, 158, 44, 1)",
colorTextPlaceholder: "rgba(155, 157, 170, 1)",
},
Upload: {
colorPrimaryHover: "rgba(249, 158, 44, 1)",
},
Button: {
colorPrimary: "rgba(249, 158, 44, 1)",
colorPrimaryHover: "rgba(249, 158, 44, 1)",
},
Textarea: {
colorBorder: "0px 1px 3px 0px rgba(20, 22, 41, 0.1)",
},
Menu: {
darkItemSelectedBg: "rgba(255, 255, 255, 0.08)",
},
},
token: {
fontFamily: "Inter, sans-serif",
color: "#262626",
borderRadius: 8,
},
};

@ -11,4 +11,5 @@ export type TRequests = {
is_active: boolean; is_active: boolean;
created_at: string; created_at: string;
updated_at: string; updated_at: string;
telegram_user_link: string;
}; };

@ -1,3 +1,5 @@
import { TUser } from "../User/TUser";
type data = { type data = {
id: number; id: number;
name?: string; name?: string;
@ -21,7 +23,19 @@ export type TTask = {
assigned_to: AssignedTo; assigned_to: AssignedTo;
in_charge: InCharge; in_charge: InCharge;
forwarded_from: { id: number; name: string }; forwarded_from: { id: number; name: string };
attachment_set: any[]; attachment_set?: TAttachment[];
};
export type TAttachment = {
created_at: string;
id: number;
description: string;
file_name: string;
path: string;
updated_at: string;
uploaded_by: number;
uploaded_by_which_driver?: { id: number; name: string } | null;
uploaded_by_which_user?: TUser | null;
}; };
export interface AssignedTo { export interface AssignedTo {

@ -1,6 +1,8 @@
export type TTeam = { export type TTeam = {
id: number; id: number;
name: string; name: string;
is_active: boolean; is_active: boolean;
created_at: Date; created_at: Date;
} task_count_percentage: number;
task_count?: number;
};

@ -1,8 +1,8 @@
export type TUser = { export type TUser = {
id: number; id: number;
username: string; username: string;
team_id: number | null; team: {id: number, name: string}
role_id: number[]; role: {id: number, name: string}
first_name: string | ''; first_name: string | '';
last_name: string | ''; last_name: string | '';
is_active: boolean; is_active: boolean;

@ -1,6 +1,6 @@
export type TPagination<T> = { export type TPagination<T> = {
data: T; data: T;
page_size: number; page_size: number;
next: string | null;
}; previous: string | null;
};

@ -0,0 +1,11 @@
import { TCall } from "../CallRequests/TCall";
import { TRequests } from "../Requests/TRequests";
import { TTask } from "../Tasks/TTasks";
export type TSocket = {
type: string;
task?: TTask;
callback_request?: TCall;
driver_request?: TRequests;
};

@ -5350,6 +5350,11 @@ fs.realpath@^1.0.0:
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
fsevents@^2.3.2, fsevents@~2.3.2:
version "2.3.3"
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
function-bind@^1.1.1: function-bind@^1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"

Loading…
Cancel
Save