commit
						1f82cbd187
					
				@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# dependencies
 | 
				
			||||||
 | 
					/node_modules
 | 
				
			||||||
 | 
					/.pnp
 | 
				
			||||||
 | 
					.pnp.js
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# testing
 | 
				
			||||||
 | 
					/coverage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# production
 | 
				
			||||||
 | 
					/build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# misc
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					.env.local
 | 
				
			||||||
 | 
					.env.development.local
 | 
				
			||||||
 | 
					.env.test.local
 | 
				
			||||||
 | 
					.env.production.local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					npm-debug.log*
 | 
				
			||||||
 | 
					yarn-debug.log*
 | 
				
			||||||
 | 
					yarn-error.log*
 | 
				
			||||||
@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    "cSpell.words": [
 | 
				
			||||||
 | 
					        "antd",
 | 
				
			||||||
 | 
					        "Previos",
 | 
				
			||||||
 | 
					        "Sider",
 | 
				
			||||||
 | 
					        "tteld",
 | 
				
			||||||
 | 
					        "USDOT"
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
											
												
													File diff suppressed because it is too large
													Load Diff
												
											
										
									
								@ -0,0 +1,68 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "newdashboard",
 | 
				
			||||||
 | 
					  "version": "0.1.0",
 | 
				
			||||||
 | 
					  "private": true,
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "@reduxjs/toolkit": "^1.9.7",
 | 
				
			||||||
 | 
					    "@stripe/react-stripe-js": "^2.3.2",
 | 
				
			||||||
 | 
					    "@stripe/stripe-js": "^2.1.11",
 | 
				
			||||||
 | 
					    "@testing-library/jest-dom": "^5.17.0",
 | 
				
			||||||
 | 
					    "@testing-library/react": "^13.4.0",
 | 
				
			||||||
 | 
					    "@testing-library/user-event": "^13.5.0",
 | 
				
			||||||
 | 
					    "@types/antd": "^1.0.0",
 | 
				
			||||||
 | 
					    "@types/axios": "^0.14.0",
 | 
				
			||||||
 | 
					    "@types/jest": "^27.5.2",
 | 
				
			||||||
 | 
					    "@types/moment": "^2.13.0",
 | 
				
			||||||
 | 
					    "@types/node": "^16.18.50",
 | 
				
			||||||
 | 
					    "@types/react": "^18.2.21",
 | 
				
			||||||
 | 
					    "@types/react-dom": "^18.2.7",
 | 
				
			||||||
 | 
					    "@types/react-query": "^1.2.9",
 | 
				
			||||||
 | 
					    "@types/react-router-dom": "^5.3.3",
 | 
				
			||||||
 | 
					    "antd": "^5.9.0",
 | 
				
			||||||
 | 
					    "bootstrap-vue": "^2.23.1",
 | 
				
			||||||
 | 
					    "dayjs": "^1.11.10",
 | 
				
			||||||
 | 
					    "file-saver": "^2.0.5",
 | 
				
			||||||
 | 
					    "final-form": "^4.20.10",
 | 
				
			||||||
 | 
					    "moment-timezone": "^0.5.43",
 | 
				
			||||||
 | 
					    "react": "^18.2.0",
 | 
				
			||||||
 | 
					    "react-dom": "^18.2.0",
 | 
				
			||||||
 | 
					    "react-final-form": "^6.5.9",
 | 
				
			||||||
 | 
					    "react-icons": "^4.11.0",
 | 
				
			||||||
 | 
					    "react-redux": "^8.1.3",
 | 
				
			||||||
 | 
					    "react-router-dom": "^6.15.0",
 | 
				
			||||||
 | 
					    "react-scripts": "5.0.1",
 | 
				
			||||||
 | 
					    "recharts": "^2.10.4",
 | 
				
			||||||
 | 
					    "redux": "^4.2.1",
 | 
				
			||||||
 | 
					    "redux-thunk": "^2.4.2",
 | 
				
			||||||
 | 
					    "typescript": "^4.9.5",
 | 
				
			||||||
 | 
					    "web-vitals": "^2.1.4",
 | 
				
			||||||
 | 
					    "yarn": "^1.22.19"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "start": "react-scripts start",
 | 
				
			||||||
 | 
					    "build": "react-scripts build",
 | 
				
			||||||
 | 
					    "test": "react-scripts test",
 | 
				
			||||||
 | 
					    "eject": "react-scripts eject"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "eslintConfig": {
 | 
				
			||||||
 | 
					    "extends": [
 | 
				
			||||||
 | 
					      "react-app",
 | 
				
			||||||
 | 
					      "react-app/jest"
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "browserslist": {
 | 
				
			||||||
 | 
					    "production": [
 | 
				
			||||||
 | 
					      ">0.2%",
 | 
				
			||||||
 | 
					      "not dead",
 | 
				
			||||||
 | 
					      "not op_mini all"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "development": [
 | 
				
			||||||
 | 
					      "last 1 chrome version",
 | 
				
			||||||
 | 
					      "last 1 firefox version",
 | 
				
			||||||
 | 
					      "last 1 safari version"
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "@babel/plugin-proposal-private-property-in-object": "^7.21.11"
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html lang="en">
 | 
				
			||||||
 | 
					  <head>
 | 
				
			||||||
 | 
					    <script
 | 
				
			||||||
 | 
					      async
 | 
				
			||||||
 | 
					      src="https://www.googletagmanager.com/gtag/js?id=G-TS04B6F9E3"
 | 
				
			||||||
 | 
					    ></script>
 | 
				
			||||||
 | 
					    <script>
 | 
				
			||||||
 | 
					      window.dataLayer = window.dataLayer || [];
 | 
				
			||||||
 | 
					      function gtag() {
 | 
				
			||||||
 | 
					        dataLayer.push(arguments);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      gtag("js", new Date());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      gtag("config", "G-TS04B6F9E3");
 | 
				
			||||||
 | 
					    </script>
 | 
				
			||||||
 | 
					    <meta charset="utf-8" />
 | 
				
			||||||
 | 
					    <meta name="viewport" content="width=device-width, initial-scale=1" />
 | 
				
			||||||
 | 
					    <meta name="theme-color" content="#000000" />
 | 
				
			||||||
 | 
					    <meta
 | 
				
			||||||
 | 
					      name="description"
 | 
				
			||||||
 | 
					      content="Admin Panel for Support Specialists in TT ELD - A comprehensive management tool for efficient operations and monitoring of TT ELD services."
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					    <title>TT ELD</title>
 | 
				
			||||||
 | 
					    <link rel="preconnect" href="https://fonts.googleapis.com" />
 | 
				
			||||||
 | 
					    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
 | 
				
			||||||
 | 
					    <link
 | 
				
			||||||
 | 
					      href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap"
 | 
				
			||||||
 | 
					      rel="stylesheet"
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  </head>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  <body>
 | 
				
			||||||
 | 
					    <noscript>You need to enable JavaScript to run this app.</noscript>
 | 
				
			||||||
 | 
					    <div id="root"></div>
 | 
				
			||||||
 | 
					  </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					import { TCall } from "../../types/CallRequests/TCall";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const callController = {
 | 
				
			||||||
 | 
					  async read(obj: { status: string }) {
 | 
				
			||||||
 | 
					    const params = { ...obj };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!!obj.status) params.status = obj.status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TCall[]>(`callback-requests/`, {
 | 
				
			||||||
 | 
					      params,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async callPatch(
 | 
				
			||||||
 | 
					    obj: { note?: string; status?: string },
 | 
				
			||||||
 | 
					    id: number
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    const params = { ...obj };
 | 
				
			||||||
 | 
					    if (!!obj.note) params.note = obj.note;
 | 
				
			||||||
 | 
					    if (!!obj.status) params.status = obj.status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data }: { data: any } = await instance
 | 
				
			||||||
 | 
					      .put<TCall>(`callback-request/${id}/`, params)
 | 
				
			||||||
 | 
					      .then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({ content: "Loaded!", duration: 2 });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					import { TCompany } from "../../types/Company/TCompany";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TCompanyGetParams = {
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
 | 
					  page?: string | number;
 | 
				
			||||||
 | 
					  is_active?: boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export type TCompanyPutParams = {
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
 | 
					  owner?: string;
 | 
				
			||||||
 | 
					  is_active?: boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export type TCompanyPostParams = {
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
 | 
					  team_id?: number;
 | 
				
			||||||
 | 
					  owner?: string;
 | 
				
			||||||
 | 
					  is_active?: boolean;
 | 
				
			||||||
 | 
					  usdot?: string;
 | 
				
			||||||
 | 
					  api_key?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const companyController = {
 | 
				
			||||||
 | 
					  async read(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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TCompany[]>(`companies/`, { params });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async companyOne(Id: number | undefined) {
 | 
				
			||||||
 | 
					    if (Id) {
 | 
				
			||||||
 | 
					      const { data } = await instance.get<TCompany>(`company/${Id}/`);
 | 
				
			||||||
 | 
					      return data;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async companyPatch(obj: TCompanyPutParams, id: string) {
 | 
				
			||||||
 | 
					    const { data }: { data: any } = await instance
 | 
				
			||||||
 | 
					      .put<TCompany>(`company/${id}/`, obj)
 | 
				
			||||||
 | 
					      .then((u) => {
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async addCompanyController(obj: TCompanyPostParams) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.post<TCompany>("company/", obj);
 | 
				
			||||||
 | 
					      return data;
 | 
				
			||||||
 | 
					    } catch (error: any) {
 | 
				
			||||||
 | 
					      setTimeout(() => {
 | 
				
			||||||
 | 
					        message.error({
 | 
				
			||||||
 | 
					          content: error.response.data.name,
 | 
				
			||||||
 | 
					          key: 2,
 | 
				
			||||||
 | 
					          duration: 2,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }, 1000);
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async SyncCompany(id: number) {
 | 
				
			||||||
 | 
					    let res;
 | 
				
			||||||
 | 
					    let error = "";
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.post(`company-sync/${id}/`).then((u) => {
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      res = data;
 | 
				
			||||||
 | 
					    } catch (err: any) {}
 | 
				
			||||||
 | 
					    return { data: res, error };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async deleteCompanyController(id: string) {
 | 
				
			||||||
 | 
					    message.loading({ content: "Loading..." });
 | 
				
			||||||
 | 
					    let res;
 | 
				
			||||||
 | 
					    let error;
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.delete(`company/${id}/`).then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({
 | 
				
			||||||
 | 
					            content: "Deleted!",
 | 
				
			||||||
 | 
					            key: id,
 | 
				
			||||||
 | 
					            duration: 2,
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      res = data;
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      error = "Oops something went wrong!";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { data: res, error };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					import { TCustomer } from "../../types/Customer/TCustomer";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TCustomerGetParams = {
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
 | 
					  pageSize?: string | number;
 | 
				
			||||||
 | 
					  page?: string | number;
 | 
				
			||||||
 | 
					  is_active?: boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export type TCustomerByCompanyGetParams = {
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
 | 
					  id?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export type TCustomerPutParams = {
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
 | 
					  company_id?: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export type TCustomerPostParams = {
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
 | 
					  company_id?: number;
 | 
				
			||||||
 | 
					  is_active?: boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const customerController = {
 | 
				
			||||||
 | 
					  async read(filterObject: TCustomerGetParams) {
 | 
				
			||||||
 | 
					    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) params.pageSize = filterObject.pageSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TCustomer[]>(`customers/`, { params });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async customerOne(Id: number | undefined) {
 | 
				
			||||||
 | 
					    if (Id) {
 | 
				
			||||||
 | 
					      const { data } = await instance.get<TCustomer>(`customer/${Id}/`);
 | 
				
			||||||
 | 
					      return data;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async customerByCompany(id: string | undefined, name: string | undefined) {
 | 
				
			||||||
 | 
					    const params = { name };
 | 
				
			||||||
 | 
					    if (!!name) params.name = name;
 | 
				
			||||||
 | 
					    if (id) {
 | 
				
			||||||
 | 
					      const { data } = await instance.get<TCustomer[]>(
 | 
				
			||||||
 | 
					        `customers-by-company/${id}/`,
 | 
				
			||||||
 | 
					        { params }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      return data;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async customerPatch(obj: TCustomerPutParams, id: string) {
 | 
				
			||||||
 | 
					    const { data }: { data: any } = await instance
 | 
				
			||||||
 | 
					      .put<TCustomer>(`customer/${id}/`, obj)
 | 
				
			||||||
 | 
					      .then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({ content: "Loaded!", duration: 2 });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async addCustomerController(obj: TCustomerPostParams) {
 | 
				
			||||||
 | 
					    message.loading({ content: "Loading..." });
 | 
				
			||||||
 | 
					    const { data } = await instance
 | 
				
			||||||
 | 
					      .post<TCustomer>("customer/", obj)
 | 
				
			||||||
 | 
					      .then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({ content: "Loaded!", duration: 2 });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async deleteCustomerController(id: string) {
 | 
				
			||||||
 | 
					    message.loading({ content: "Loading..." });
 | 
				
			||||||
 | 
					    let res;
 | 
				
			||||||
 | 
					    let error = "";
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.delete(`customer/${id}/`).then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({ content: "Deleted!", duration: 2 });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      res = data;
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      error = "Oops something went wrong!";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { data: res, error };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  TMyTaskHistory,
 | 
				
			||||||
 | 
					  TMystats,
 | 
				
			||||||
 | 
					  TProfile,
 | 
				
			||||||
 | 
					} from "../../types/Profile/TProfile";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TProfilePutParams = {
 | 
				
			||||||
 | 
					  first_name?: string;
 | 
				
			||||||
 | 
					  last_name?: string;
 | 
				
			||||||
 | 
					  username?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export type TMyTaskHistoryGetParams = {
 | 
				
			||||||
 | 
					  start_date?: string;
 | 
				
			||||||
 | 
					  end_date?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export type TChangePostParams = {
 | 
				
			||||||
 | 
					  old_password?: string;
 | 
				
			||||||
 | 
					  new_password?: string;
 | 
				
			||||||
 | 
					  password_confirm?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const prof = {
 | 
				
			||||||
 | 
					  async read(filterObject: TMyTaskHistoryGetParams) {
 | 
				
			||||||
 | 
					    const params = { ...filterObject };
 | 
				
			||||||
 | 
					    if (!!filterObject.start_date) params.start_date = filterObject.start_date;
 | 
				
			||||||
 | 
					    if (!!filterObject.end_date) params.end_date = filterObject.end_date;
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TMystats>(`stats/my-stats/`, {
 | 
				
			||||||
 | 
					      params,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  // async read(filterObject: TMyTaskHistoryGetParams) {
 | 
				
			||||||
 | 
					  //   const params = { ...filterObject };
 | 
				
			||||||
 | 
					  //   if (!!filterObject.start_date) params.start_date = filterObject.start_date;
 | 
				
			||||||
 | 
					  //   if (!!filterObject.end_date) params.end_date = filterObject.end_date;
 | 
				
			||||||
 | 
					  //   const { data } = await instance.get<TMystats>(`stats/my-stats/`, {
 | 
				
			||||||
 | 
					  //     params,
 | 
				
			||||||
 | 
					  //   });
 | 
				
			||||||
 | 
					  //   return data;
 | 
				
			||||||
 | 
					  // },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async self() {
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TProfile>(`users/my-profile/`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async myTaskHistory(filterObject: TMyTaskHistoryGetParams) {
 | 
				
			||||||
 | 
					    const params = { ...filterObject };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!!filterObject.start_date) params.start_date = filterObject.start_date;
 | 
				
			||||||
 | 
					    if (!!filterObject.end_date) params.end_date = filterObject.end_date;
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TMyTaskHistory[]>(`my-task-history/`, {
 | 
				
			||||||
 | 
					      params,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async profPatch(filterObject: TProfilePutParams) {
 | 
				
			||||||
 | 
					    const params = { ...filterObject };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    params.first_name = filterObject.first_name || params.first_name;
 | 
				
			||||||
 | 
					    params.last_name = filterObject.last_name || params.last_name;
 | 
				
			||||||
 | 
					    params.username = filterObject.username || params.username;
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.put<TProfilePutParams>(
 | 
				
			||||||
 | 
					        `users/my-profile/`,
 | 
				
			||||||
 | 
					        { ...params }
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      return data;
 | 
				
			||||||
 | 
					    } catch (error: any) {
 | 
				
			||||||
 | 
					      setTimeout(() => {
 | 
				
			||||||
 | 
					        message.error({
 | 
				
			||||||
 | 
					          content: error.response.data.username,
 | 
				
			||||||
 | 
					          key: 2,
 | 
				
			||||||
 | 
					          duration: 2,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }, 1000);
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  async changePass(obj: TChangePostParams) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.post<any>(
 | 
				
			||||||
 | 
					        "users/my-profile/change-password/",
 | 
				
			||||||
 | 
					        obj
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      message.success(data.message);
 | 
				
			||||||
 | 
					      return data;
 | 
				
			||||||
 | 
					    } catch (error: any) {
 | 
				
			||||||
 | 
					      if (error.response && error.response.status === 400) {
 | 
				
			||||||
 | 
					        const errorMessage =
 | 
				
			||||||
 | 
					          error?.response?.data?.old_password ||
 | 
				
			||||||
 | 
					          error?.response?.data?.new_password[0] ||
 | 
				
			||||||
 | 
					          "Bad Request";
 | 
				
			||||||
 | 
					        message.error(errorMessage);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        message.error("An error occurred");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      throw error;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					import { TRequests } from "../../types/Requests/TRequests";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TRequestsGetParams = {
 | 
				
			||||||
 | 
					  search?: string;
 | 
				
			||||||
 | 
					  status?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const requestsController = {
 | 
				
			||||||
 | 
					  async read(filterObject: TRequestsGetParams) {
 | 
				
			||||||
 | 
					    const params = { ...filterObject };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!!filterObject.search) params.search = filterObject.search;
 | 
				
			||||||
 | 
					    if (!!filterObject.status) params.status = filterObject.status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TRequests[]>(`driver-requests/`, {
 | 
				
			||||||
 | 
					      params,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async requestsOne(Id: string | number | undefined) {
 | 
				
			||||||
 | 
					    const { data }: { data: any } = await instance(`driver-request/${Id}/`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async requestPatch(obj: TRequestsGetParams, id: string | number | undefined) {
 | 
				
			||||||
 | 
					    const { data } = await instance
 | 
				
			||||||
 | 
					      .put<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) {
 | 
				
			||||||
 | 
					    let res;
 | 
				
			||||||
 | 
					    let error = "";
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance
 | 
				
			||||||
 | 
					        .patch(`driver-request/${id}/`, { status: "Rejected" })
 | 
				
			||||||
 | 
					        .then((u) => {
 | 
				
			||||||
 | 
					          setTimeout(() => {
 | 
				
			||||||
 | 
					            message.success({ content: "Rejected!", key: id, duration: 2 });
 | 
				
			||||||
 | 
					          }, 1000);
 | 
				
			||||||
 | 
					          return u;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      res = data;
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      error = "Oops something went wrong!";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { data: res, error };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					import { TRole } from "../../types/Role/TRole";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const roleController = {
 | 
				
			||||||
 | 
					  async read() {
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TRole[]>(`users/roles/`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async roleOne(id: string) {
 | 
				
			||||||
 | 
					    const { data }: { data: any } = await instance.get<TRole>(
 | 
				
			||||||
 | 
					      `users/role/${id}/`
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					import { TService } from "../../types/Service/TService";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TServicePutParams = {
 | 
				
			||||||
 | 
					  title?: string;
 | 
				
			||||||
 | 
					  points?: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export type TServicePostParams = {
 | 
				
			||||||
 | 
					  title?: string;
 | 
				
			||||||
 | 
					  points?: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const serviceController = {
 | 
				
			||||||
 | 
					  async read() {
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TService[]>(`services/`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async serviceOne(Id: number | undefined) {
 | 
				
			||||||
 | 
					    if (Id) {
 | 
				
			||||||
 | 
					      const { data } = await instance.get<TService>(`service/${Id}/`);
 | 
				
			||||||
 | 
					      return data;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async servicePatch(obj: TServicePutParams, id: string) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance
 | 
				
			||||||
 | 
					        .put<TService>(`service/${id}/`, obj)
 | 
				
			||||||
 | 
					        .then((u) => {
 | 
				
			||||||
 | 
					          setTimeout(() => {
 | 
				
			||||||
 | 
					            message.success({ content: "Loaded!", duration: 2 });
 | 
				
			||||||
 | 
					          }, 1000);
 | 
				
			||||||
 | 
					          return u;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      return data;
 | 
				
			||||||
 | 
					    } catch (error: any) {
 | 
				
			||||||
 | 
					      setTimeout(() => {
 | 
				
			||||||
 | 
					        message.error({
 | 
				
			||||||
 | 
					          content: error?.response?.data?.title,
 | 
				
			||||||
 | 
					          key: 2,
 | 
				
			||||||
 | 
					          duration: 2,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }, 1000);
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async addServiceController(obj: TServicePostParams) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance
 | 
				
			||||||
 | 
					        .post<TService>("service/", obj)
 | 
				
			||||||
 | 
					        .then((u) => {
 | 
				
			||||||
 | 
					          setTimeout(() => {
 | 
				
			||||||
 | 
					            message.success({ content: "Loaded!", duration: 2 });
 | 
				
			||||||
 | 
					          }, 1000);
 | 
				
			||||||
 | 
					          return u;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      return data;
 | 
				
			||||||
 | 
					    } catch (error: any) {
 | 
				
			||||||
 | 
					      setTimeout(() => {
 | 
				
			||||||
 | 
					        message.error({
 | 
				
			||||||
 | 
					          content: error?.response?.data?.title,
 | 
				
			||||||
 | 
					          key: 2,
 | 
				
			||||||
 | 
					          duration: 2,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }, 1000);
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async deleteServiceController(id: string) {
 | 
				
			||||||
 | 
					    let res;
 | 
				
			||||||
 | 
					    let error = "";
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.delete(`service/${id}/`).then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({ content: "Deleted!", duration: 2 });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      res = data;
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      error = "Oops something went wrong!";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { data: res, error };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,132 @@
 | 
				
			|||||||
 | 
					import { TCard, TStat, TStatTeam } from "../../types/Statistic/TStat";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TStatGetParams = {
 | 
				
			||||||
 | 
					  search?: string;
 | 
				
			||||||
 | 
					  team?: string;
 | 
				
			||||||
 | 
					  start_date?: string;
 | 
				
			||||||
 | 
					  end_date?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TStatTeamGetParams = {
 | 
				
			||||||
 | 
					  search?: string;
 | 
				
			||||||
 | 
					  start_date?: string;
 | 
				
			||||||
 | 
					  end_date?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TStatCreatorsGetParams = {
 | 
				
			||||||
 | 
					  start_date?: string;
 | 
				
			||||||
 | 
					  end_date?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const statController = {
 | 
				
			||||||
 | 
					  async read(filterObject: TStatGetParams) {
 | 
				
			||||||
 | 
					    const params = { ...filterObject };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!!filterObject.search) params.search = filterObject.search;
 | 
				
			||||||
 | 
					    if (!!filterObject.team) params.team = filterObject.team;
 | 
				
			||||||
 | 
					    if (!!filterObject.start_date) params.start_date = filterObject.start_date;
 | 
				
			||||||
 | 
					    if (!!filterObject.end_date) params.end_date = filterObject.end_date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TStat[]>(`stats/all-users/`, {
 | 
				
			||||||
 | 
					      params,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async team(filterObject: TStatTeamGetParams) {
 | 
				
			||||||
 | 
					    const params = { ...filterObject };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!!filterObject.search) params.search = filterObject.search;
 | 
				
			||||||
 | 
					    if (!!filterObject.start_date) params.start_date = filterObject.start_date;
 | 
				
			||||||
 | 
					    if (!!filterObject.end_date) params.end_date = filterObject.end_date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TStatTeam[]>(`stats/all-teams/`, {
 | 
				
			||||||
 | 
					      params,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async creators(filterObject: TStatCreatorsGetParams) {
 | 
				
			||||||
 | 
					    const params = { ...filterObject };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!!filterObject.start_date) params.start_date = filterObject.start_date;
 | 
				
			||||||
 | 
					    if (!!filterObject.end_date) params.end_date = filterObject.end_date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TStatTeam[]>(`stats/task-creators/`, {
 | 
				
			||||||
 | 
					      params,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  async cards(filterObject: TStatCreatorsGetParams) {
 | 
				
			||||||
 | 
					    const params = { ...filterObject };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!!filterObject.start_date) params.start_date = filterObject.start_date;
 | 
				
			||||||
 | 
					    if (!!filterObject.end_date) params.end_date = filterObject.end_date;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TCard>(`stats/tasks-comparison/`, {
 | 
				
			||||||
 | 
					      params,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async saveUsersStats(
 | 
				
			||||||
 | 
					    fileName: string,
 | 
				
			||||||
 | 
					    startDate: string,
 | 
				
			||||||
 | 
					    endDate: string,
 | 
				
			||||||
 | 
					    team: string
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					    const response = await instance.post(
 | 
				
			||||||
 | 
					      `stats/all-users/?start_date=${startDate}&end_date=${endDate}&team=${team}`,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        headers: {
 | 
				
			||||||
 | 
					          "Content-Type": "multipart/form-data",
 | 
				
			||||||
 | 
					          "Content-Disposition": `attachment;`,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        responseType: "arraybuffer",
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const blob = new Blob([response.data], {
 | 
				
			||||||
 | 
					      type: "application/octet-stream",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const downloadUrl = URL.createObjectURL(blob);
 | 
				
			||||||
 | 
					    const a = document.createElement("a");
 | 
				
			||||||
 | 
					    a.style.display = "none";
 | 
				
			||||||
 | 
					    a.href = downloadUrl;
 | 
				
			||||||
 | 
					    a.download = `stats_${fileName}.csv`;
 | 
				
			||||||
 | 
					    document.body.appendChild(a);
 | 
				
			||||||
 | 
					    a.click();
 | 
				
			||||||
 | 
					    window.URL.revokeObjectURL(downloadUrl);
 | 
				
			||||||
 | 
					    return response.data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async saveTeamStats(fileName: string, startDate: string, endDate: string) {
 | 
				
			||||||
 | 
					    const response = await instance.post(
 | 
				
			||||||
 | 
					      `stats/all-teams/?start_date=${startDate}&end_date=${endDate}`,
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        headers: {
 | 
				
			||||||
 | 
					          "Content-Type": "multipart/form-data",
 | 
				
			||||||
 | 
					          "Content-Disposition": `attachment;`,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        responseType: "arraybuffer",
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const blob = new Blob([response.data], {
 | 
				
			||||||
 | 
					      type: "application/octet-stream",
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const downloadUrl = URL.createObjectURL(blob);
 | 
				
			||||||
 | 
					    const a = document.createElement("a");
 | 
				
			||||||
 | 
					    a.style.display = "none";
 | 
				
			||||||
 | 
					    a.href = downloadUrl;
 | 
				
			||||||
 | 
					    a.download = `stats_${fileName}.csv`;
 | 
				
			||||||
 | 
					    document.body.appendChild(a);
 | 
				
			||||||
 | 
					    a.click();
 | 
				
			||||||
 | 
					    window.URL.revokeObjectURL(downloadUrl);
 | 
				
			||||||
 | 
					    return response.data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async statOne(Id: string | number | undefined) {
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TStat>(`stats/${Id}`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,118 @@
 | 
				
			|||||||
 | 
					import { TTask, TTaskHistory } from "../../types/Tasks/TTasks";
 | 
				
			||||||
 | 
					import { TPagination } from "../../types/common/TPagination";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TTasksGetParams = {
 | 
				
			||||||
 | 
					  search?: string;
 | 
				
			||||||
 | 
					  status?: string;
 | 
				
			||||||
 | 
					  team?: string;
 | 
				
			||||||
 | 
					  page?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TTasksPutParams = {
 | 
				
			||||||
 | 
					  company_id?: number;
 | 
				
			||||||
 | 
					  customer_id?: number;
 | 
				
			||||||
 | 
					  service_id?: number;
 | 
				
			||||||
 | 
					  assigned_to_id?: number;
 | 
				
			||||||
 | 
					  note?: string;
 | 
				
			||||||
 | 
					  status?: string;
 | 
				
			||||||
 | 
					  message?: string;
 | 
				
			||||||
 | 
					  pti?: boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TTasksPostParams = {
 | 
				
			||||||
 | 
					  company_id?: number;
 | 
				
			||||||
 | 
					  customer_id?: number;
 | 
				
			||||||
 | 
					  service_id?: number;
 | 
				
			||||||
 | 
					  provider_id?: number;
 | 
				
			||||||
 | 
					  assigned_to_id?: number;
 | 
				
			||||||
 | 
					  in_charge_id?: number;
 | 
				
			||||||
 | 
					  note?: string;
 | 
				
			||||||
 | 
					  status?: string;
 | 
				
			||||||
 | 
					  is_active?: boolean;
 | 
				
			||||||
 | 
					  pti?: boolean;
 | 
				
			||||||
 | 
					  attachment_ids?: number[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const taskController = {
 | 
				
			||||||
 | 
					  async read(filterObject: TTasksGetParams) {
 | 
				
			||||||
 | 
					    const params = { ...filterObject };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!!filterObject.page && filterObject.page !== "0")
 | 
				
			||||||
 | 
					      params.page = filterObject.page;
 | 
				
			||||||
 | 
					    if (!!filterObject.search) params.search = filterObject.search;
 | 
				
			||||||
 | 
					    if (Array.isArray(filterObject.status)) {
 | 
				
			||||||
 | 
					      params.status = filterObject.status.join(",");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (Array.isArray(filterObject.team)) {
 | 
				
			||||||
 | 
					      params.team = filterObject.team.join(", ");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TPagination<TTask[]>>(`tasks/`, {
 | 
				
			||||||
 | 
					      params,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async getHistory(id: number | undefined) {
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TTaskHistory[]>(`task-history/${id}/`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async taskOne(Id: number) {
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TTask>(`task/${Id}/`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async taskPatch(obj: TTasksPutParams, task_id: number | undefined) {
 | 
				
			||||||
 | 
					    const { data } = await instance
 | 
				
			||||||
 | 
					      .put<TTask>(`task/${task_id}/`, obj)
 | 
				
			||||||
 | 
					      .then((u) => {
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async addTaskController(obj: TTasksPostParams) {
 | 
				
			||||||
 | 
					    const { data } = await instance.post<TTask>("task/", obj).then((u) => {
 | 
				
			||||||
 | 
					      return u;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async addTaskFile(formData: any) {
 | 
				
			||||||
 | 
					    const { data } = await instance.post("attachment/", formData, {
 | 
				
			||||||
 | 
					      headers: {
 | 
				
			||||||
 | 
					        "Content-Type": "multipart/form-data", // Установите правильный Content-Type
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async deleteTaskController(id: number) {
 | 
				
			||||||
 | 
					    let res;
 | 
				
			||||||
 | 
					    let error = "";
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.delete(`task/${id}/`).then((u) => {
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      res = data;
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      error = "Oops something went wrong!";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { data: res, error };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  async deleteAttachmentController(id: number) {
 | 
				
			||||||
 | 
					    let res;
 | 
				
			||||||
 | 
					    let error = "";
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.delete(`attachment/${id}/`).then((u) => {
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      res = data;
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      error = "Oops something went wrong!";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { data: res, error };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,73 @@
 | 
				
			|||||||
 | 
					import { TTeam } from "../../types/Team/TTeam";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TTeamPutParams = {
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
 | 
					  is_active?: boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TTeamPostParams = {
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
 | 
					  is_active?: boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const teamController = {
 | 
				
			||||||
 | 
					  async read(name: string) {
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TTeam[]>(`teams/?name=${name}`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async teamOne(Id: string | number | undefined) {
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TTeam>(`team/${Id}`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async teamPatch(obj: TTeamPutParams, id: string) {
 | 
				
			||||||
 | 
					    const { data } = await instance.put<TTeam>(`team/${id}/`, obj).then((u) => {
 | 
				
			||||||
 | 
					      setTimeout(() => {
 | 
				
			||||||
 | 
					        message.success({ content: "Loaded!", duration: 2 });
 | 
				
			||||||
 | 
					      }, 1000);
 | 
				
			||||||
 | 
					      return u;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async addTeamController(obj: TTeamPostParams) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.post<TTeam>("team/", obj).then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({ content: "Loaded!", duration: 2 });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return data;
 | 
				
			||||||
 | 
					    } catch (error: any) {
 | 
				
			||||||
 | 
					      setTimeout(() => {
 | 
				
			||||||
 | 
					        message.error({
 | 
				
			||||||
 | 
					          content: error?.response?.data?.name,
 | 
				
			||||||
 | 
					          key: 2,
 | 
				
			||||||
 | 
					          duration: 2,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }, 1000);
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async deleteTeamController(id: string) {
 | 
				
			||||||
 | 
					    let res;
 | 
				
			||||||
 | 
					    let error = "";
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.delete(`team/${id}`).then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({ content: "Deleted!", duration: 2 });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      res = data;
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      error = "Oops something went wrong!";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { data: res, error };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,94 @@
 | 
				
			|||||||
 | 
					import { TUpdate } from "../../types/Update/TUpdate";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TUpdatePutParams = {
 | 
				
			||||||
 | 
					  company_id?: number;
 | 
				
			||||||
 | 
					  customer_id?: number;
 | 
				
			||||||
 | 
					  status?: string;
 | 
				
			||||||
 | 
					  note?: string;
 | 
				
			||||||
 | 
					  is_pinned?: boolean;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TUpdatePostParams = {
 | 
				
			||||||
 | 
					  company_id?: number;
 | 
				
			||||||
 | 
					  customer_id?: number;
 | 
				
			||||||
 | 
					  provider_id?: number;
 | 
				
			||||||
 | 
					  executor_id?: number;
 | 
				
			||||||
 | 
					  status?: string;
 | 
				
			||||||
 | 
					  note?: string;
 | 
				
			||||||
 | 
					  solution?: string;
 | 
				
			||||||
 | 
					  is_active?: boolean;
 | 
				
			||||||
 | 
					  is_pinned?: boolean;
 | 
				
			||||||
 | 
					  attachment_ids?: number[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const updateController = {
 | 
				
			||||||
 | 
					  async read(status: string) {
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TUpdate[]>(
 | 
				
			||||||
 | 
					      `shift-updates/?status=${status}`
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async updateOne(Id: string | number | undefined) {
 | 
				
			||||||
 | 
					    const { data }: { data: any } = await instance(`shift-update/${Id}`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  async addTaskFile(formData: FormData) {
 | 
				
			||||||
 | 
					    const { data } = await instance.post("attachment/", formData, {
 | 
				
			||||||
 | 
					      headers: {
 | 
				
			||||||
 | 
					        "Content-Type": "multipart/form-data",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async updatePut(updateData: TUpdate, update_id: string) {
 | 
				
			||||||
 | 
					    const { data } = await instance(`shift-update/${update_id}/`, {
 | 
				
			||||||
 | 
					      method: "PUT",
 | 
				
			||||||
 | 
					      data: updateData,
 | 
				
			||||||
 | 
					    }).then((u) => {
 | 
				
			||||||
 | 
					      return u;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  async updatePatch(obj: TUpdatePutParams, id: string | number) {
 | 
				
			||||||
 | 
					    const { data } = await instance(`shift-update/${id}/`, {
 | 
				
			||||||
 | 
					      method: "PUT",
 | 
				
			||||||
 | 
					      data: obj,
 | 
				
			||||||
 | 
					    }).then((u) => {
 | 
				
			||||||
 | 
					      return u;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async addUpdateController(obj: TUpdatePostParams) {
 | 
				
			||||||
 | 
					    const { data } = await instance
 | 
				
			||||||
 | 
					      .post<TUpdate>("shift-update/", obj)
 | 
				
			||||||
 | 
					      .then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({ content: "Loaded!", duration: 2 });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async deleteUpdateController(id: string) {
 | 
				
			||||||
 | 
					    let res;
 | 
				
			||||||
 | 
					    let error = "";
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.delete(`shift-update/${id}`).then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({ content: "Deleted!", duration: 2 });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      res = data;
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      error = "Oops something went wrong!";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { data: res, error };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,92 @@
 | 
				
			|||||||
 | 
					import { TUser } from "../../types/User/TUser";
 | 
				
			||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TUsersGetParams = {
 | 
				
			||||||
 | 
					  name?: string;
 | 
				
			||||||
 | 
					  team?: string;
 | 
				
			||||||
 | 
					  role?: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TUsersPutParams = {
 | 
				
			||||||
 | 
					  first_name?: string;
 | 
				
			||||||
 | 
					  last_name?: string;
 | 
				
			||||||
 | 
					  username?: string;
 | 
				
			||||||
 | 
					  team_id?: number;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type TUsersPostParams = {
 | 
				
			||||||
 | 
					  username?: string;
 | 
				
			||||||
 | 
					  password?: string;
 | 
				
			||||||
 | 
					  team_id?: number;
 | 
				
			||||||
 | 
					  groups?: number[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const userController = {
 | 
				
			||||||
 | 
					  async read(filterObject: TUsersGetParams) {
 | 
				
			||||||
 | 
					    const params = { ...filterObject };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!!filterObject.name) params.name = filterObject.name;
 | 
				
			||||||
 | 
					    if (Array.isArray(filterObject.team)) {
 | 
				
			||||||
 | 
					      params.team = filterObject.team.join(", ");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (Array.isArray(filterObject.role)) {
 | 
				
			||||||
 | 
					      params.role = filterObject.role.join(", ");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TUser[]>(`users/`, { params });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async CheckUsername(username: string) {
 | 
				
			||||||
 | 
					    const { data } = await instance.get<TUser[]>(`users/check/${username}`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async userOne(Id: string | number | undefined) {
 | 
				
			||||||
 | 
					    const { data }: { data: any } = await instance(`users/admin/${Id}/`);
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async userPatch(obj: TUsersPutParams, id: string) {
 | 
				
			||||||
 | 
					    const { data } = await instance
 | 
				
			||||||
 | 
					      .put<TUser>(`users/admin/${id}/`, obj)
 | 
				
			||||||
 | 
					      .then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({ content: "Loaded!", duration: 2 });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async addUserController(obj: TUsersPostParams) {
 | 
				
			||||||
 | 
					    message.loading({ content: "Loading..." });
 | 
				
			||||||
 | 
					    let responseData = null;
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const response = await instance.post<TUser>("users/admin/", obj);
 | 
				
			||||||
 | 
					      responseData = response;
 | 
				
			||||||
 | 
					      message.success({ content: "Loaded!", duration: 2 });
 | 
				
			||||||
 | 
					    } catch (err: any) {
 | 
				
			||||||
 | 
					      responseData = err?.response?.data;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { data: responseData };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async deleteUserController(id: string) {
 | 
				
			||||||
 | 
					    let res;
 | 
				
			||||||
 | 
					    let error = "";
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const { data } = await instance.delete(`users/admin/${id}/`).then((u) => {
 | 
				
			||||||
 | 
					        setTimeout(() => {
 | 
				
			||||||
 | 
					          message.success({ content: "Deleted!", key: id, duration: 2 });
 | 
				
			||||||
 | 
					        }, 1000);
 | 
				
			||||||
 | 
					        return u;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      res = data;
 | 
				
			||||||
 | 
					    } catch (err) {
 | 
				
			||||||
 | 
					      error = "Oops something went wrong!";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return { data: res, error };
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import axios from "axios";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const instance = axios.create({
 | 
				
			||||||
 | 
					  baseURL: "http://10.10.10.45:8080/api/v1/",
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					// const instance = axios.create({
 | 
				
			||||||
 | 
					//   baseURL: "https://api.tteld.co/api/v1/",
 | 
				
			||||||
 | 
					// });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const token: string | null = localStorage.getItem("access");
 | 
				
			||||||
 | 
					if (token) {
 | 
				
			||||||
 | 
					  instance.defaults.headers.common["Authorization"] = `Bearer ${token}`;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					instance.interceptors.response.use(
 | 
				
			||||||
 | 
					  (response) => response,
 | 
				
			||||||
 | 
					  (error) => {
 | 
				
			||||||
 | 
					    if (error.response && error.response.status === 401) {
 | 
				
			||||||
 | 
					      localStorage.clear();
 | 
				
			||||||
 | 
					      window.location.reload();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return Promise.reject(error);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default instance;
 | 
				
			||||||
@ -0,0 +1,42 @@
 | 
				
			|||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface loginInterface {
 | 
				
			||||||
 | 
					  username: string;
 | 
				
			||||||
 | 
					  password: string | number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const LoginApi = async ({ username, password }: loginInterface) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const { data } = await instance("auth/login/", {
 | 
				
			||||||
 | 
					      method: "POST",
 | 
				
			||||||
 | 
					      data: { username, password },
 | 
				
			||||||
 | 
					      headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    console.log(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const userObject = {
 | 
				
			||||||
 | 
					      id: data?.data?.id,
 | 
				
			||||||
 | 
					      first_name: data?.data?.first_name,
 | 
				
			||||||
 | 
					      last_name: data?.data?.last_name,
 | 
				
			||||||
 | 
					      username: data?.data?.username,
 | 
				
			||||||
 | 
					      timezone: data?.data?.timezone,
 | 
				
			||||||
 | 
					      role: data?.data?.role,
 | 
				
			||||||
 | 
					      team_id: data?.data?.team_id,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const userJSON = JSON.stringify(userObject);
 | 
				
			||||||
 | 
					    localStorage.setItem("user", userJSON);
 | 
				
			||||||
 | 
					    localStorage.setItem("access", data?.data.access);
 | 
				
			||||||
 | 
					    localStorage.setItem("refresh", data?.data.refresh);
 | 
				
			||||||
 | 
					    localStorage.setItem("admin_id", data?.data.id);
 | 
				
			||||||
 | 
					    document.location.replace("/");
 | 
				
			||||||
 | 
					  } catch (err) {
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      message.error({
 | 
				
			||||||
 | 
					        content: "Username or password incorrect!",
 | 
				
			||||||
 | 
					        duration: 2,
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const LogoutApi = async () => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    await instance("auth/logout/", {
 | 
				
			||||||
 | 
					      method: "POST",
 | 
				
			||||||
 | 
					      headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					      data: { refresh_token: localStorage.getItem("refresh") },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    localStorage.removeItem("access");
 | 
				
			||||||
 | 
					    localStorage.removeItem("refresh");
 | 
				
			||||||
 | 
					    localStorage.removeItem("user");
 | 
				
			||||||
 | 
					    localStorage.removeItem("admin_id");
 | 
				
			||||||
 | 
					    document.location.replace("/");
 | 
				
			||||||
 | 
					  } catch (err) {
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      message.error({ content: "Something went wrong! ", duration: 2 });
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					    throw new Error("Something went wrong");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface activateInterface {
 | 
				
			||||||
 | 
					  user_id: string;
 | 
				
			||||||
 | 
					  confirmation_token: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export interface inviteInterface {
 | 
				
			||||||
 | 
					  user_id: string;
 | 
				
			||||||
 | 
					  confirmation_token: string;
 | 
				
			||||||
 | 
					  role_id: string | null;
 | 
				
			||||||
 | 
					  business_id: string | null;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const registryVerify = async (value: activateInterface) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const { data, status } = await instance("users/verify-registration/", {
 | 
				
			||||||
 | 
					      method: "POST",
 | 
				
			||||||
 | 
					      data: value,
 | 
				
			||||||
 | 
					      headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const userObject = {
 | 
				
			||||||
 | 
					      first_name: data?.data.first_name,
 | 
				
			||||||
 | 
					      last_name: data?.data.last_name,
 | 
				
			||||||
 | 
					      username: data?.data.username,
 | 
				
			||||||
 | 
					      id: data?.data.id,
 | 
				
			||||||
 | 
					      timezone: data?.data.timezone,
 | 
				
			||||||
 | 
					      role: data?.data.role,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const userJSON = JSON.stringify(userObject);
 | 
				
			||||||
 | 
					    localStorage.setItem("user", userJSON);
 | 
				
			||||||
 | 
					    localStorage.setItem("access_token", data?.data.access_token);
 | 
				
			||||||
 | 
					    localStorage.setItem("refresh_token", data?.data.refresh_token);
 | 
				
			||||||
 | 
					    document.location.replace("/");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return status;
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    console.log(error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      message.error({ content: "Something went wrong", duration: 2 });
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const inviteVerify = async (value: inviteInterface) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const { data, status } = await instance("users/invite-verify/", {
 | 
				
			||||||
 | 
					      method: "POST",
 | 
				
			||||||
 | 
					      data: value,
 | 
				
			||||||
 | 
					      headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const userObject = {
 | 
				
			||||||
 | 
					      first_name: data?.data.first_name,
 | 
				
			||||||
 | 
					      last_name: data?.data.last_name,
 | 
				
			||||||
 | 
					      username: data?.data.username,
 | 
				
			||||||
 | 
					      id: data?.data.id,
 | 
				
			||||||
 | 
					      timezone: data?.data.timezone,
 | 
				
			||||||
 | 
					      role: data?.data.role,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const userJSON = JSON.stringify(userObject);
 | 
				
			||||||
 | 
					    localStorage.setItem("user", userJSON);
 | 
				
			||||||
 | 
					    localStorage.setItem("access", data?.data.access);
 | 
				
			||||||
 | 
					    localStorage.setItem("refresh", data?.data.refresh);
 | 
				
			||||||
 | 
					    localStorage.setItem("admin_id", data?.data.id);
 | 
				
			||||||
 | 
					    instance.defaults.headers.common[
 | 
				
			||||||
 | 
					      "Authorization"
 | 
				
			||||||
 | 
					    ] = `Bearer ${data?.data.access}`;
 | 
				
			||||||
 | 
					    return status;
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      message.error({ content: "Something went wrong", duration: 2 });
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface inviteType {
 | 
				
			||||||
 | 
					  role_id: number;
 | 
				
			||||||
 | 
					  email: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const inviteVerify = async (value: inviteType) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const {data} = await instance("users/invite/", {
 | 
				
			||||||
 | 
					      method: "POST",
 | 
				
			||||||
 | 
					      data: value,
 | 
				
			||||||
 | 
					      headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const succesMessage = data?.message;
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					        message.success({ content: succesMessage, duration: 2 });
 | 
				
			||||||
 | 
					      }, 1000);
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      message.error({ content: "Something went wrong", duration: 2 });
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,46 @@
 | 
				
			|||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface registerInterface {
 | 
				
			||||||
 | 
					  first_name: string;
 | 
				
			||||||
 | 
					  last_name: string;
 | 
				
			||||||
 | 
					  username: string;
 | 
				
			||||||
 | 
					  email: string;
 | 
				
			||||||
 | 
					  password: string;
 | 
				
			||||||
 | 
					  password_confirm: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const RegisterApi = async (value: registerInterface) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const { status, data } = await instance("users/register/", {
 | 
				
			||||||
 | 
					      method: "POST",
 | 
				
			||||||
 | 
					      data: value,
 | 
				
			||||||
 | 
					      headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const userObject = {
 | 
				
			||||||
 | 
					      first_name: data?.data.first_name,
 | 
				
			||||||
 | 
					      last_name: data?.data.last_name,
 | 
				
			||||||
 | 
					      username: data?.data.username,
 | 
				
			||||||
 | 
					      id: data?.data.id,
 | 
				
			||||||
 | 
					      timezone: data?.data.timezone, 
 | 
				
			||||||
 | 
					      role: data?.data.role,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const userJSON = JSON.stringify(userObject);
 | 
				
			||||||
 | 
					    localStorage.setItem("user", userJSON);
 | 
				
			||||||
 | 
					    localStorage.setItem("access_token", data?.data.access_token);
 | 
				
			||||||
 | 
					    localStorage.setItem("refresh_token", data?.data.refresh_token);
 | 
				
			||||||
 | 
					    document.location.replace("/");
 | 
				
			||||||
 | 
					    return status;
 | 
				
			||||||
 | 
					  } catch (error:any) {
 | 
				
			||||||
 | 
					    console.log(error);
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      message.error({ content: ' ', duration: 2 });
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  } 
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const validateUsername = async (value: any) => {
 | 
				
			||||||
 | 
					  const {status} = await instance.get(`users/check/${value}/`);
 | 
				
			||||||
 | 
					  return status
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					import instance from "../api";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface resetType {
 | 
				
			||||||
 | 
					  login: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					export interface resetPassType {
 | 
				
			||||||
 | 
					  user_id: string;
 | 
				
			||||||
 | 
					  confirmation_token: string;
 | 
				
			||||||
 | 
					  new_password: string;
 | 
				
			||||||
 | 
					  password_confirm: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const resetPass = async (value: resetType) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const { data } = await instance("users/send-reset-password-link/", {
 | 
				
			||||||
 | 
					      method: "POST",
 | 
				
			||||||
 | 
					      data: value,
 | 
				
			||||||
 | 
					      headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return data;
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      message.error({ content: "Something went wrong", duration: 2 });
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const resetPassEmail = async (value: resetPassType) => {
 | 
				
			||||||
 | 
					  try {
 | 
				
			||||||
 | 
					    const { data } = await instance("users/reset-password/", {
 | 
				
			||||||
 | 
					      method: "POST",
 | 
				
			||||||
 | 
					      data: value,
 | 
				
			||||||
 | 
					      headers: { "Content-Type": "application/json" },
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    const succesMessage = data?.message;
 | 
				
			||||||
 | 
					    message.success({ content: succesMessage, duration: 2 });
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      document.location.replace('/auth/login')
 | 
				
			||||||
 | 
					    }, 2000);
 | 
				
			||||||
 | 
					  } catch (error) {
 | 
				
			||||||
 | 
					    setTimeout(() => {
 | 
				
			||||||
 | 
					      message.error({ content: "Something went wrong", duration: 2 });
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,767 @@
 | 
				
			|||||||
 | 
					* {
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					  box-sizing: border-box;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#components-layout-demo-custom-trigger .trigger {
 | 
				
			||||||
 | 
					  line-height: 64px;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  transition: color 0.3s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#components-layout-demo-custom-trigger .trigger:hover {
 | 
				
			||||||
 | 
					  color: #1890ff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:where(.css-dev-only-do-not-override-1vtf12y).ant-menu .ant-menu-item {
 | 
				
			||||||
 | 
					  white-space: initial !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					:where(.css-1vtf12y).ant-menu .ant-menu-item {
 | 
				
			||||||
 | 
					  white-space: unset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.site-layout .site-layout-background {
 | 
				
			||||||
 | 
					  background: #fff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.ant-pagination-options-size-changer.ant-select {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.logo {
 | 
				
			||||||
 | 
					  font-size: 28px;
 | 
				
			||||||
 | 
					  /* font-family: Arial, Helvetica, sans-serif;  */
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  padding: 14px 0;
 | 
				
			||||||
 | 
					  color: #fff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.logo-collapsed {
 | 
				
			||||||
 | 
					  font-size: 18px;
 | 
				
			||||||
 | 
					  /* font-family: Arial, Helvetica, sans-serif;  */
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  padding: 20px 0;
 | 
				
			||||||
 | 
					  color: #fff;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.isnot {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ant-table-row {
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#element::-webkit-scrollbar {
 | 
				
			||||||
 | 
					  width: 10px;
 | 
				
			||||||
 | 
					  background-color: #f9f9fd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#element::-webkit-scrollbar-thumb {
 | 
				
			||||||
 | 
					  border-radius: 10px;
 | 
				
			||||||
 | 
					  background-color: #595959;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#element::-webkit-scrollbar-track {
 | 
				
			||||||
 | 
					  -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.2);
 | 
				
			||||||
 | 
					  border-radius: 10px;
 | 
				
			||||||
 | 
					  background-color: #f9f9fd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ant-layout-sider-trigger {
 | 
				
			||||||
 | 
					  background: none !important;
 | 
				
			||||||
 | 
					  border-top: 1px solid #cecece;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.new-status-row {
 | 
				
			||||||
 | 
					  background-color: rgba(170, 170, 170, 0.44);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.theme-btn {
 | 
				
			||||||
 | 
					  background: rgb(241, 241, 241);
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(233, 233, 233, 0.11);
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  padding: 11px 13px;
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.062);
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.profile-dropdown {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  width: max-content;
 | 
				
			||||||
 | 
					  margin-left: 12px;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.profile-dropdown:hover {
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  background: #7c7c7c;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.profile-dropdown-ava {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.profile-dropdown-text {
 | 
				
			||||||
 | 
					  text-align-last: left;
 | 
				
			||||||
 | 
					  align-items: end;
 | 
				
			||||||
 | 
					  margin-left: 12px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.profile-dropdown .business-name {
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  font-weight: 700;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: right;
 | 
				
			||||||
 | 
					  padding: 0 20px 0 0;
 | 
				
			||||||
 | 
					  color: #363636;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.business-name-dark {
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  font-weight: 700;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: right;
 | 
				
			||||||
 | 
					  padding: 0 20px 0 0;
 | 
				
			||||||
 | 
					  color: #bbb;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.profile-dropdown .username {
 | 
				
			||||||
 | 
					  font-size: 13px;
 | 
				
			||||||
 | 
					  font-weight: 400;
 | 
				
			||||||
 | 
					  line-height: 16px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: right;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.dot-true {
 | 
				
			||||||
 | 
					  width: 10px;
 | 
				
			||||||
 | 
					  height: 10px;
 | 
				
			||||||
 | 
					  background: #05e776;
 | 
				
			||||||
 | 
					  border-radius: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.dot-false {
 | 
				
			||||||
 | 
					  width: 10px;
 | 
				
			||||||
 | 
					  height: 10px;
 | 
				
			||||||
 | 
					  background: #c71d1d;
 | 
				
			||||||
 | 
					  border-radius: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.live-p {
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  margin-left: 7px;
 | 
				
			||||||
 | 
					  width: max-content;
 | 
				
			||||||
 | 
					  color: #424242;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.live-p-dark {
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					  font-size: 12px;
 | 
				
			||||||
 | 
					  margin-left: 7px;
 | 
				
			||||||
 | 
					  width: max-content;
 | 
				
			||||||
 | 
					  color: #a8a8a8;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.d-flex {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.header {
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-add {
 | 
				
			||||||
 | 
					  padding: 10px 15px 10px 12px;
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  background: rgba(249, 158, 44, 1);
 | 
				
			||||||
 | 
					  color: rgba(255, 255, 255, 1);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  font-family: Inter;
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.1);
 | 
				
			||||||
 | 
					  margin-right: 12px;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-add:hover {
 | 
				
			||||||
 | 
					  background: rgb(247, 176, 89);
 | 
				
			||||||
 | 
					  transition: 0.5s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-refresh-false {
 | 
				
			||||||
 | 
					  padding: 10px 21px 10px 12px;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  font-family: Inter;
 | 
				
			||||||
 | 
					  border: 1px solid rgba(215, 216, 224, 1);
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.1);
 | 
				
			||||||
 | 
					  background: rgba(255, 255, 255, 1);
 | 
				
			||||||
 | 
					  color: rgba(15, 17, 28, 1);
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.btn-refresh-dark {
 | 
				
			||||||
 | 
					  padding: 10px 21px 10px 12px;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  font-family: Inter;
 | 
				
			||||||
 | 
					  border: 1px solid #777;
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.1);
 | 
				
			||||||
 | 
					  background: #333;
 | 
				
			||||||
 | 
					  color: #bbb;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-refresh-false:hover {
 | 
				
			||||||
 | 
					  border: 1px solid rgba(249, 158, 44, 1);
 | 
				
			||||||
 | 
					  transition: 0.5s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.btn-refresh-dark:hover {
 | 
				
			||||||
 | 
					  border: 1px solid rgba(249, 158, 44, 1);
 | 
				
			||||||
 | 
					  transition: 0.5s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.title {
 | 
				
			||||||
 | 
					  font-family: Inter;
 | 
				
			||||||
 | 
					  font-size: 24px;
 | 
				
			||||||
 | 
					  font-weight: 700;
 | 
				
			||||||
 | 
					  line-height: 28px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.04em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  margin-right: 12px;
 | 
				
			||||||
 | 
					  color: #bbb;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.filter {
 | 
				
			||||||
 | 
					  margin: 16px 0;
 | 
				
			||||||
 | 
					  justify-content: end;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-input-false {
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  font-size: 13px;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  color: rgba(15, 17, 28, 1);
 | 
				
			||||||
 | 
					  caret-color: rgba(249, 158, 44, 1);
 | 
				
			||||||
 | 
					  margin-left: 8px;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  background: #00000000;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-input-false::placeholder {
 | 
				
			||||||
 | 
					  color: rgba(155, 157, 170, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.search-input-true {
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  font-size: 13px;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  color: #bbb;
 | 
				
			||||||
 | 
					  caret-color: rgba(249, 158, 44, 1);
 | 
				
			||||||
 | 
					  margin-left: 8px;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  background: #00000000;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-input-true::placeholder {
 | 
				
			||||||
 | 
					  color: rgba(155, 157, 170, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-div {
 | 
				
			||||||
 | 
					  border: 1px solid rgba(150, 150, 150, 0.493);
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.1);
 | 
				
			||||||
 | 
					  padding: 5px 12px;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  width: 260px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-div:hover,
 | 
				
			||||||
 | 
					.search-div:focus {
 | 
				
			||||||
 | 
					  border: 1px solid rgba(249, 158, 44, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-div:active {
 | 
				
			||||||
 | 
					  border: 1px solid rgba(249, 158, 44, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.status-new {
 | 
				
			||||||
 | 
					  background: rgba(45, 155, 219, 0.1);
 | 
				
			||||||
 | 
					  padding: 6px 0;
 | 
				
			||||||
 | 
					  color: rgb(32, 155, 226);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(45, 156, 219, 0.3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.status-Pending {
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(246, 137, 0, 0.3);
 | 
				
			||||||
 | 
					  padding: 3px;
 | 
				
			||||||
 | 
					  background: rgba(246, 137, 0, 0.1);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  color: rgba(246, 137, 0, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.status-checking {
 | 
				
			||||||
 | 
					  background: rgba(45, 156, 219, 0.1);
 | 
				
			||||||
 | 
					  padding: 6px 0;
 | 
				
			||||||
 | 
					  color: rgba(45, 156, 219, 1);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(45, 156, 219, 0.3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.status-in-progress {
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(246, 137, 0, 0.3);
 | 
				
			||||||
 | 
					  padding: 6px 0;
 | 
				
			||||||
 | 
					  background: rgba(246, 137, 0, 0.1);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  color: rgba(246, 137, 0, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.status-Rejected {
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(246, 0, 0, 0.3);
 | 
				
			||||||
 | 
					  padding: 3px;
 | 
				
			||||||
 | 
					  background: rgba(246, 0, 0, 0.1);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  color: #ff4d4f;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.status-done {
 | 
				
			||||||
 | 
					  padding: 6px 0;
 | 
				
			||||||
 | 
					  color: rgba(10, 160, 106, 1);
 | 
				
			||||||
 | 
					  background: rgba(10, 160, 106, 0.1);
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(10, 160, 106, 0.3);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.status-Assigned {
 | 
				
			||||||
 | 
					  padding: 3px;
 | 
				
			||||||
 | 
					  color: rgba(10, 160, 106, 1);
 | 
				
			||||||
 | 
					  background: rgba(10, 160, 106, 0.1);
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(10, 160, 106, 0.3);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.status-paper {
 | 
				
			||||||
 | 
					  background: rgba(45, 156, 219, 0.1);
 | 
				
			||||||
 | 
					  padding: 6px 0;
 | 
				
			||||||
 | 
					  color: rgba(45, 156, 219, 1);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(45, 156, 219, 0.3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.status-setup {
 | 
				
			||||||
 | 
					  background: rgba(45, 156, 219, 0.1);
 | 
				
			||||||
 | 
					  padding: 6px 0;
 | 
				
			||||||
 | 
					  color: rgba(45, 156, 219, 1);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(45, 156, 219, 0.3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.circle {
 | 
				
			||||||
 | 
					  width: 10px;
 | 
				
			||||||
 | 
					  height: 10px;
 | 
				
			||||||
 | 
					  background-color: #05e776;
 | 
				
			||||||
 | 
					  border-radius: 50%;
 | 
				
			||||||
 | 
					  animation: pulse 2s infinite alternate; /* Анимация будет повторяться бесконечно */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes pulse {
 | 
				
			||||||
 | 
					  0% {
 | 
				
			||||||
 | 
					    transform: scale(1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  50% {
 | 
				
			||||||
 | 
					    transform: scale(1.2);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  100% {
 | 
				
			||||||
 | 
					    transform: scale(1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.circle2 {
 | 
				
			||||||
 | 
					  width: 10px;
 | 
				
			||||||
 | 
					  height: 10px;
 | 
				
			||||||
 | 
					  background-color: #c71d1d;
 | 
				
			||||||
 | 
					  border-radius: 50%;
 | 
				
			||||||
 | 
					  animation: pulse 2s infinite alternate; /* Анимация будет повторяться бесконечно */
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes pulse {
 | 
				
			||||||
 | 
					  0% {
 | 
				
			||||||
 | 
					    transform: scale(1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  50% {
 | 
				
			||||||
 | 
					    transform: scale(1.2);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  100% {
 | 
				
			||||||
 | 
					    transform: scale(1);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-pin {
 | 
				
			||||||
 | 
					  background: rgba(255, 255, 255, 1);
 | 
				
			||||||
 | 
					  border: 1px solid rgba(215, 216, 224, 1);
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.1);
 | 
				
			||||||
 | 
					  padding: 7px 10px;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  padding-top: 7px !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-unpin {
 | 
				
			||||||
 | 
					  padding: 7px 10px;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  background: rgba(246, 71, 71, 1);
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.1);
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.TaskModal {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  width: 800px;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  right: 0;
 | 
				
			||||||
 | 
					  z-index: 2;
 | 
				
			||||||
 | 
					  background: rgba(255, 255, 255, 1);
 | 
				
			||||||
 | 
					  border-left: 1px solid rgba(215, 216, 224, 1);
 | 
				
			||||||
 | 
					  box-shadow: -40px 0px 100px 10000px rgba(0, 0, 0, 0.5);
 | 
				
			||||||
 | 
					  transition: 3s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.TaskModal-dark {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  width: 800px;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  right: 0;
 | 
				
			||||||
 | 
					  z-index: 2;
 | 
				
			||||||
 | 
					  background: rgb(37, 37, 37);
 | 
				
			||||||
 | 
					  border-left: 1px solid rgba(215, 216, 224, 1);
 | 
				
			||||||
 | 
					  box-shadow: -40px 0px 100px 1000px rgba(0, 0, 0, 0.5);
 | 
				
			||||||
 | 
					  transition: 3s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-modal-action-false {
 | 
				
			||||||
 | 
					  padding: 8px 10px;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  border: 1px solid rgba(215, 216, 224, 1);
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.1);
 | 
				
			||||||
 | 
					  background: rgba(255, 255, 255, 1);
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.btn-modal-action-dark {
 | 
				
			||||||
 | 
					  padding: 8px 10px;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  border: 1px solid #777777;
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.1);
 | 
				
			||||||
 | 
					  background: #333;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  color: #bbb;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.btn-modal-action-false:hover {
 | 
				
			||||||
 | 
					  background: #e6e6e6;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.btn-modal-action-dark:hover {
 | 
				
			||||||
 | 
					  background: #e6e6e6;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.btn-modal-action-false img,
 | 
				
			||||||
 | 
					.btn-modal-action-dark img {
 | 
				
			||||||
 | 
					  margin-right: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.mdoal-actions {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  justify-content: end;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.TaskModal-header {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  margin: 20px 24px 24px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.TaskModal-header-dark {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					  margin: 20px 24px 24px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.TaskModal-title {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.TaskModal-title-dark {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.status-New {
 | 
				
			||||||
 | 
					  background: rgba(45, 156, 219, 0.1);
 | 
				
			||||||
 | 
					  padding: 4px 10px;
 | 
				
			||||||
 | 
					  color: rgba(45, 156, 219, 1);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 16px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(45, 156, 219, 0.3);
 | 
				
			||||||
 | 
					  font-size: 13px;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.status-Done {
 | 
				
			||||||
 | 
					  padding: 4px 10px;
 | 
				
			||||||
 | 
					  color: rgba(10, 160, 106, 1);
 | 
				
			||||||
 | 
					  background: rgba(10, 160, 106, 0.1);
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(10, 160, 106, 0.3);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 16px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  font-size: 13px;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.status-Checking {
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(246, 137, 0, 0.3);
 | 
				
			||||||
 | 
					  padding: 4px 10px;
 | 
				
			||||||
 | 
					  background: rgba(246, 137, 0, 0.1);
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  line-height: 16px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  color: rgba(246, 137, 0, 1);
 | 
				
			||||||
 | 
					  font-size: 13px;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.p-driver {
 | 
				
			||||||
 | 
					  font-size: 18px;
 | 
				
			||||||
 | 
					  font-weight: 700;
 | 
				
			||||||
 | 
					  line-height: 24px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.02em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  color: rgba(15, 17, 28, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.p-driver-dark {
 | 
				
			||||||
 | 
					  font-size: 18px;
 | 
				
			||||||
 | 
					  font-weight: 700;
 | 
				
			||||||
 | 
					  line-height: 24px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.02em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  color: rgb(211, 211, 211);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.info-div {
 | 
				
			||||||
 | 
					  margin: 16px 24px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.info-body {
 | 
				
			||||||
 | 
					  border-radius: 12px;
 | 
				
			||||||
 | 
					  padding: 16px 24px;
 | 
				
			||||||
 | 
					  border: 1px solid rgba(215, 216, 224, 1);
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.info-body tr {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  padding: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.sub {
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  font-weight: 400;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  color: rgba(121, 123, 141, 1);
 | 
				
			||||||
 | 
					  width: 200px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.sub-dark {
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  font-weight: 400;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  color: rgb(221, 221, 221);
 | 
				
			||||||
 | 
					  width: 200px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.info {
 | 
				
			||||||
 | 
					  font-family: Inter;
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  color: rgba(15, 17, 28, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.info-dark {
 | 
				
			||||||
 | 
					  font-family: Inter;
 | 
				
			||||||
 | 
					  font-size: 14px;
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					  line-height: 20px;
 | 
				
			||||||
 | 
					  letter-spacing: -0.01em;
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  color: #bbb;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.pin {
 | 
				
			||||||
 | 
					  background: rgba(255, 255, 255, 1);
 | 
				
			||||||
 | 
					  border: 1px solid rgba(215, 216, 224, 1);
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.1);
 | 
				
			||||||
 | 
					  padding: 7px 10px;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.unpin {
 | 
				
			||||||
 | 
					  padding: 7px 10px;
 | 
				
			||||||
 | 
					  border-radius: 8px;
 | 
				
			||||||
 | 
					  background: rgba(246, 71, 71, 1);
 | 
				
			||||||
 | 
					  box-shadow: 0px 1px 3px 0px rgba(20, 22, 41, 0.1);
 | 
				
			||||||
 | 
					  border: none;
 | 
				
			||||||
 | 
					  outline: none;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ant-upload-wrapper .ant-upload-drag {
 | 
				
			||||||
 | 
					  border: 0.5px solid rgba(215, 216, 224, 1);
 | 
				
			||||||
 | 
					  padding: 25px 0;
 | 
				
			||||||
 | 
					  color: #333333;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.card_stat {
 | 
				
			||||||
 | 
					  font-weight: 500;
 | 
				
			||||||
 | 
					  font-size: 20px;
 | 
				
			||||||
 | 
					  padding: 20px;
 | 
				
			||||||
 | 
					  background: #deeeff;
 | 
				
			||||||
 | 
					  border-radius: 2px;
 | 
				
			||||||
 | 
					  width: 200px;
 | 
				
			||||||
 | 
					  height: 180px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  -webkit-box-shadow: 0px 0px 12px 1px rgba(34, 60, 80, 0.08);
 | 
				
			||||||
 | 
					  -moz-box-shadow: 0px 0px 12px 1px rgba(34, 60, 80, 0.08);
 | 
				
			||||||
 | 
					  box-shadow: 0px 0px 12px 1px rgba(34, 60, 80, 0.08);
 | 
				
			||||||
 | 
					  cursor: pointer;
 | 
				
			||||||
 | 
					  transition: 0.4s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.card_stat:hover {
 | 
				
			||||||
 | 
					  background: #cfe4fc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.card_stat span {
 | 
				
			||||||
 | 
					  font-weight: 700;
 | 
				
			||||||
 | 
					  font-size: 44px;
 | 
				
			||||||
 | 
					  display: block;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  margin-top: 15px;
 | 
				
			||||||
 | 
					  color: #464646;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.ant-modal-close {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.search-driver {
 | 
				
			||||||
 | 
					  margin-top: 20px;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  justify-content: space-between;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -0,0 +1,381 @@
 | 
				
			|||||||
 | 
					import React, { useEffect, useState } from "react";
 | 
				
			||||||
 | 
					import "./App.css";
 | 
				
			||||||
 | 
					import { Layout, Menu, ConfigProvider, Dropdown } from "antd";
 | 
				
			||||||
 | 
					import { Routes, Route, Navigate, useLocation } from "react-router-dom";
 | 
				
			||||||
 | 
					import { allMenu, mainItems, superItems } from "./Utils/sidebar";
 | 
				
			||||||
 | 
					import Login from "./Auth/Login";
 | 
				
			||||||
 | 
					import Notfound from "./Utils/Notfound";
 | 
				
			||||||
 | 
					import { LogoutApi } from "./API/auth/Logout";
 | 
				
			||||||
 | 
					import { Link } from "react-router-dom";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import themeBtn from "./assets/theme-btn.svg";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import avatar from "./assets/avatar-img.svg";
 | 
				
			||||||
 | 
					import Register from "./Auth/Register";
 | 
				
			||||||
 | 
					import Activate from "./Auth/Activate";
 | 
				
			||||||
 | 
					import Invite from "./Auth/Invite";
 | 
				
			||||||
 | 
					import ResetPassword from "./Auth/ResetPassword";
 | 
				
			||||||
 | 
					import ResetByEmail from "./Auth/ResetByEmail";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { Header, Sider, Content } = Layout;
 | 
				
			||||||
 | 
					const userJSON: any = localStorage.getItem("user");
 | 
				
			||||||
 | 
					const userObject = JSON.parse(userJSON);
 | 
				
			||||||
 | 
					export const timeZone = userObject?.timezone;
 | 
				
			||||||
 | 
					export const role = userObject?.role;
 | 
				
			||||||
 | 
					export const admin_id = localStorage.getItem("admin_id");
 | 
				
			||||||
 | 
					export const team_id = userObject?.team_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const App: React.FC = () => {
 | 
				
			||||||
 | 
					  const isAuthenticated = localStorage.getItem("access") as string;
 | 
				
			||||||
 | 
					  const authorized = isAuthenticated;
 | 
				
			||||||
 | 
					  const [collapsed, setCollapsed] = useState<any>(
 | 
				
			||||||
 | 
					    localStorage.getItem("collapsed") === "true" ? true : false
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					  const [theme, setTheme] = useState<any>(
 | 
				
			||||||
 | 
					    localStorage.getItem("theme") === "true" ? true : false
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    localStorage.setItem("theme", theme);
 | 
				
			||||||
 | 
					  }, [theme]);
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    localStorage.setItem("collapsed", collapsed);
 | 
				
			||||||
 | 
					  }, [collapsed]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  let location: any = useLocation();
 | 
				
			||||||
 | 
					  const clickLogout = () => {
 | 
				
			||||||
 | 
					    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 = () => {
 | 
				
			||||||
 | 
					    document.location.replace("/");
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const menu: any = (
 | 
				
			||||||
 | 
					    <Menu>
 | 
				
			||||||
 | 
					      <Menu.Item key="profile">
 | 
				
			||||||
 | 
					        <Link to="profile/">Profile</Link>
 | 
				
			||||||
 | 
					      </Menu.Item>
 | 
				
			||||||
 | 
					      <Menu.Item key="logout" danger onClick={clickLogout}>
 | 
				
			||||||
 | 
					        Logout
 | 
				
			||||||
 | 
					      </Menu.Item>
 | 
				
			||||||
 | 
					    </Menu>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <ConfigProvider theme={theme === true ? dark : light}>
 | 
				
			||||||
 | 
					      <div>
 | 
				
			||||||
 | 
					        {!authorized &&
 | 
				
			||||||
 | 
					          !(
 | 
				
			||||||
 | 
					            location.pathname.startsWith("/auth/register") ||
 | 
				
			||||||
 | 
					            location.pathname.startsWith("/auth/activate") ||
 | 
				
			||||||
 | 
					            location.pathname.startsWith("/auth/reset_password") ||
 | 
				
			||||||
 | 
					            location.pathname.startsWith("/auth/reset-password") ||
 | 
				
			||||||
 | 
					            location.pathname.startsWith("/auth/login") ||
 | 
				
			||||||
 | 
					            location.pathname.startsWith("/auth/invite")
 | 
				
			||||||
 | 
					          ) && (
 | 
				
			||||||
 | 
					            <Navigate
 | 
				
			||||||
 | 
					              to={{
 | 
				
			||||||
 | 
					                pathname: "/auth/login",
 | 
				
			||||||
 | 
					              }}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        {authorized && location.pathname === "/login" && (
 | 
				
			||||||
 | 
					          <Navigate
 | 
				
			||||||
 | 
					            to={{
 | 
				
			||||||
 | 
					              pathname: "/",
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					        {authorized ? (
 | 
				
			||||||
 | 
					          <Layout>
 | 
				
			||||||
 | 
					            <Sider
 | 
				
			||||||
 | 
					              theme={"dark"}
 | 
				
			||||||
 | 
					              collapsible
 | 
				
			||||||
 | 
					              collapsed={collapsed}
 | 
				
			||||||
 | 
					              onCollapse={(value) => setCollapsed(value)}
 | 
				
			||||||
 | 
					              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"}
 | 
				
			||||||
 | 
					                mode="inline"
 | 
				
			||||||
 | 
					                defaultSelectedKeys={[location.pathname]}
 | 
				
			||||||
 | 
					                items={allMenu}
 | 
				
			||||||
 | 
					                style={{
 | 
				
			||||||
 | 
					                  background:
 | 
				
			||||||
 | 
					                    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
 | 
				
			||||||
 | 
					                  style={{
 | 
				
			||||||
 | 
					                    float: "right",
 | 
				
			||||||
 | 
					                    marginRight: "35px",
 | 
				
			||||||
 | 
					                    display: "flex",
 | 
				
			||||||
 | 
					                    alignItems: "center",
 | 
				
			||||||
 | 
					                    alignSelf: "center",
 | 
				
			||||||
 | 
					                    minWidth: 150,
 | 
				
			||||||
 | 
					                    maxWidth: 500,
 | 
				
			||||||
 | 
					                    justifyContent: "space-between",
 | 
				
			||||||
 | 
					                  }}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <button
 | 
				
			||||||
 | 
					                    className="theme-btn"
 | 
				
			||||||
 | 
					                    onClick={(e) => setTheme(!theme)}
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <img src={themeBtn} alt="" />
 | 
				
			||||||
 | 
					                  </button>
 | 
				
			||||||
 | 
					                  <Dropdown overlay={menu} trigger={["click"]}>
 | 
				
			||||||
 | 
					                    <div
 | 
				
			||||||
 | 
					                      style={{ cursor: "pointer" }}
 | 
				
			||||||
 | 
					                      onClick={(e) => e.preventDefault()}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <div className="profile-dropdown">
 | 
				
			||||||
 | 
					                        <div className="profile-dropdown-ava">
 | 
				
			||||||
 | 
					                          <img src={avatar} alt="" />
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                        <div
 | 
				
			||||||
 | 
					                          className="d-flex profile-dropdown-text"
 | 
				
			||||||
 | 
					                          style={{ flexDirection: "column" }}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                          <p
 | 
				
			||||||
 | 
					                            className={
 | 
				
			||||||
 | 
					                              !theme ? "business-name" : "business-name-dark"
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                          >
 | 
				
			||||||
 | 
					                            {userObject?.username}
 | 
				
			||||||
 | 
					                          </p>
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                      </div>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                  </Dropdown>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </Header>
 | 
				
			||||||
 | 
					              <Content
 | 
				
			||||||
 | 
					                id="element"
 | 
				
			||||||
 | 
					                style={{
 | 
				
			||||||
 | 
					                  padding: 24,
 | 
				
			||||||
 | 
					                  minHeight: "92vh",
 | 
				
			||||||
 | 
					                  maxHeight: "calc(90vh - 10px)",
 | 
				
			||||||
 | 
					                  overflowY: "scroll",
 | 
				
			||||||
 | 
					                  background: theme === true ? "#202020" : "#fff",
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <Routes>
 | 
				
			||||||
 | 
					                  {mainItems &&
 | 
				
			||||||
 | 
					                    mainItems.map((u) => (
 | 
				
			||||||
 | 
					                      <Route key={u.key} path={u.path} element={u.component} />
 | 
				
			||||||
 | 
					                    ))}
 | 
				
			||||||
 | 
					                  {superItems &&
 | 
				
			||||||
 | 
					                    superItems.map((u) => (
 | 
				
			||||||
 | 
					                      <Route key={u.key} path={u.path} element={u.component} />
 | 
				
			||||||
 | 
					                    ))}
 | 
				
			||||||
 | 
					                  <Route path="*" element={<Notfound />} />
 | 
				
			||||||
 | 
					                </Routes>
 | 
				
			||||||
 | 
					              </Content>
 | 
				
			||||||
 | 
					            </Layout>
 | 
				
			||||||
 | 
					          </Layout>
 | 
				
			||||||
 | 
					        ) : (
 | 
				
			||||||
 | 
					          <></>
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					        <Routes>
 | 
				
			||||||
 | 
					          <Route path="/auth/login" element={<Login />} />
 | 
				
			||||||
 | 
					          <Route path="/auth/register" element={<Register />} />
 | 
				
			||||||
 | 
					          <Route path="/auth/activate" element={<Activate />} />
 | 
				
			||||||
 | 
					          <Route path="/auth/invite" element={<Invite />} />
 | 
				
			||||||
 | 
					          <Route path="/auth/reset_password" element={<ResetPassword />} />
 | 
				
			||||||
 | 
					          <Route path="/auth/reset-password" element={<ResetByEmail />} />
 | 
				
			||||||
 | 
					        </Routes>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </ConfigProvider>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default App;
 | 
				
			||||||
@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import { Navigate, useLocation } from "react-router-dom";
 | 
				
			||||||
 | 
					import { registryVerify } from "../API/auth/activate";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Activate = () => {
 | 
				
			||||||
 | 
					  const location = useLocation();
 | 
				
			||||||
 | 
					  const queryParameters = new URLSearchParams(location.search);
 | 
				
			||||||
 | 
					  const userId = queryParameters.get("user_id");
 | 
				
			||||||
 | 
					  const confirmationToken = queryParameters.get("confirmation_token");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (userId && confirmationToken) {
 | 
				
			||||||
 | 
					    registryVerify({
 | 
				
			||||||
 | 
					      user_id: userId,
 | 
				
			||||||
 | 
					      confirmation_token: confirmationToken,
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <div></div>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Activate;
 | 
				
			||||||
@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					import { useLocation } from "react-router-dom";
 | 
				
			||||||
 | 
					import { inviteVerify } from "../API/auth/activate";
 | 
				
			||||||
 | 
					import { message } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Invite = () => {
 | 
				
			||||||
 | 
					  const location = useLocation();
 | 
				
			||||||
 | 
					  const queryParameters = new URLSearchParams(location.search);
 | 
				
			||||||
 | 
					  const userId = queryParameters.get("user_id");
 | 
				
			||||||
 | 
					  const confirmationToken = queryParameters.get("confirmation_token");
 | 
				
			||||||
 | 
					  const business_id = queryParameters.get("business_id");
 | 
				
			||||||
 | 
					  const role_id = queryParameters.get("role_id");
 | 
				
			||||||
 | 
					  if (userId && confirmationToken) {
 | 
				
			||||||
 | 
					    inviteVerify({
 | 
				
			||||||
 | 
					      user_id: userId,
 | 
				
			||||||
 | 
					      confirmation_token: confirmationToken,
 | 
				
			||||||
 | 
					      role_id: role_id,
 | 
				
			||||||
 | 
					      business_id: business_id,
 | 
				
			||||||
 | 
					    }).then((status) => {
 | 
				
			||||||
 | 
					      console.log(status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (status === 200) {
 | 
				
			||||||
 | 
					        document.location.replace("/");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    message.warning({ content: "Your Activision is expired" });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <div>hello</div>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Invite;
 | 
				
			||||||
@ -0,0 +1,125 @@
 | 
				
			|||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import { Button, Card, Input, Space } from "antd";
 | 
				
			||||||
 | 
					import { Form, Field } from "react-final-form";
 | 
				
			||||||
 | 
					import { LockOutlined, UserOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					import { LoginApi } from "../API/auth/Login";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Login: React.FC = () => {
 | 
				
			||||||
 | 
					  const validate = (val: any) => {
 | 
				
			||||||
 | 
					    const err: any = {};
 | 
				
			||||||
 | 
					    if (!val.login) {
 | 
				
			||||||
 | 
					      err.login = "Required";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (!val.password) {
 | 
				
			||||||
 | 
					      err.password = "Required";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return err;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const sleep = (ms: any) => new Promise((resolve) => setTimeout(resolve, ms));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onSubmit = async (values: any) => {
 | 
				
			||||||
 | 
					    await sleep(300);
 | 
				
			||||||
 | 
					    await LoginApi({ username: values.login, password: values.password });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="ContainerClassName" style={{ height: "100vh" }}>
 | 
				
			||||||
 | 
					      <Form
 | 
				
			||||||
 | 
					        onSubmit={onSubmit}
 | 
				
			||||||
 | 
					        validate={validate}
 | 
				
			||||||
 | 
					        render={({ submitError, handleSubmit, submitting }) => (
 | 
				
			||||||
 | 
					          <Space
 | 
				
			||||||
 | 
					            direction="horizontal"
 | 
				
			||||||
 | 
					            style={{
 | 
				
			||||||
 | 
					              width: "100%",
 | 
				
			||||||
 | 
					              height: "100vh",
 | 
				
			||||||
 | 
					              display: "flex",
 | 
				
			||||||
 | 
					              justifyContent: "center",
 | 
				
			||||||
 | 
					              alignItems: "center",
 | 
				
			||||||
 | 
					              flexDirection: "column",
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Card
 | 
				
			||||||
 | 
					              bodyStyle={{ background: "rgb(250, 250, 250)" }}
 | 
				
			||||||
 | 
					              title="Login"
 | 
				
			||||||
 | 
					              className="login-form-card "
 | 
				
			||||||
 | 
					              style={{ width: 400 }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <form onSubmit={handleSubmit}>
 | 
				
			||||||
 | 
					                <Space
 | 
				
			||||||
 | 
					                  direction="vertical"
 | 
				
			||||||
 | 
					                  size="middle"
 | 
				
			||||||
 | 
					                  style={{ display: "flex", gap: "30px" }}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <Field name="login">
 | 
				
			||||||
 | 
					                    {({ input, meta }) => (
 | 
				
			||||||
 | 
					                      <div>
 | 
				
			||||||
 | 
					                        <Input
 | 
				
			||||||
 | 
					                          prefix={
 | 
				
			||||||
 | 
					                            <UserOutlined className="site-form-item-icon" />
 | 
				
			||||||
 | 
					                          }
 | 
				
			||||||
 | 
					                          size={"large"}
 | 
				
			||||||
 | 
					                          {...input}
 | 
				
			||||||
 | 
					                          type="text"
 | 
				
			||||||
 | 
					                          placeholder="username or e-mail"
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                        {(meta.error || meta.submitError) && meta.touched && (
 | 
				
			||||||
 | 
					                          <span style={{ color: "red" }}>
 | 
				
			||||||
 | 
					                            {meta.error || meta.submitError}
 | 
				
			||||||
 | 
					                          </span>
 | 
				
			||||||
 | 
					                        )}
 | 
				
			||||||
 | 
					                      </div>
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
 | 
					                  </Field>
 | 
				
			||||||
 | 
					                  <Field name="password">
 | 
				
			||||||
 | 
					                    {({ input, meta }) => (
 | 
				
			||||||
 | 
					                      <div>
 | 
				
			||||||
 | 
					                        <Input.Password
 | 
				
			||||||
 | 
					                          prefix={
 | 
				
			||||||
 | 
					                            <LockOutlined className="site-form-item-icon" />
 | 
				
			||||||
 | 
					                          }
 | 
				
			||||||
 | 
					                          size={"large"}
 | 
				
			||||||
 | 
					                          {...input}
 | 
				
			||||||
 | 
					                          type="password"
 | 
				
			||||||
 | 
					                          placeholder="Password"
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                        {meta.error && meta.touched && (
 | 
				
			||||||
 | 
					                          <span style={{ color: "red" }}>{meta.error}</span>
 | 
				
			||||||
 | 
					                        )}
 | 
				
			||||||
 | 
					                      </div>
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
 | 
					                  </Field>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  {submitError && (
 | 
				
			||||||
 | 
					                    <div style={{ color: "red" }} className="error">
 | 
				
			||||||
 | 
					                      {submitError}
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  <Button
 | 
				
			||||||
 | 
					                    className="Login-form-button"
 | 
				
			||||||
 | 
					                    size={"large"}
 | 
				
			||||||
 | 
					                    htmlType="submit"
 | 
				
			||||||
 | 
					                    type="primary"
 | 
				
			||||||
 | 
					                    disabled={submitting}
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    Log In
 | 
				
			||||||
 | 
					                  </Button>
 | 
				
			||||||
 | 
					                  {/* <h5>
 | 
				
			||||||
 | 
					                    <Link to='/auth/reset_password'>Forgot password?</Link>
 | 
				
			||||||
 | 
					                    <br />
 | 
				
			||||||
 | 
					                    Don't have an account?
 | 
				
			||||||
 | 
					                    <Link to='/auth/register'> Create one now</Link>
 | 
				
			||||||
 | 
					                  </h5> */}
 | 
				
			||||||
 | 
					                </Space>
 | 
				
			||||||
 | 
					              </form>
 | 
				
			||||||
 | 
					            </Card>
 | 
				
			||||||
 | 
					          </Space>
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Login;
 | 
				
			||||||
@ -0,0 +1,105 @@
 | 
				
			|||||||
 | 
					import React, { useState } from "react";
 | 
				
			||||||
 | 
					import { Button, Card, Input, Space } from "antd";
 | 
				
			||||||
 | 
					import { Form, Field } from "react-final-form";
 | 
				
			||||||
 | 
					import { UserOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					import { resetPass } from "../API/auth/resetPass";
 | 
				
			||||||
 | 
					import Success from "./Success";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ResetPassword: React.FC = () => {
 | 
				
			||||||
 | 
					  const [open, setOpen] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [email, setEmail] = useState("");
 | 
				
			||||||
 | 
					  const validate = (val: any) => {
 | 
				
			||||||
 | 
					    const err: any = {};
 | 
				
			||||||
 | 
					    if (!val.login) {
 | 
				
			||||||
 | 
					      err.login = "Required";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return err;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const sleep = (ms: any) => new Promise((resolve) => setTimeout(resolve, ms));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onSubmit = async (values: any) => {
 | 
				
			||||||
 | 
					    setEmail(values.login);
 | 
				
			||||||
 | 
					    await sleep(300);
 | 
				
			||||||
 | 
					    await resetPass({ login: values.login }).then(() => {
 | 
				
			||||||
 | 
					      setOpen(true);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className="ContainerClassName" style={{ height: "100vh" }}>
 | 
				
			||||||
 | 
					      <Form
 | 
				
			||||||
 | 
					        onSubmit={onSubmit}
 | 
				
			||||||
 | 
					        validate={validate}
 | 
				
			||||||
 | 
					        render={({ submitError, handleSubmit, submitting }) => (
 | 
				
			||||||
 | 
					          <Space
 | 
				
			||||||
 | 
					            direction="horizontal"
 | 
				
			||||||
 | 
					            style={{
 | 
				
			||||||
 | 
					              width: "100%",
 | 
				
			||||||
 | 
					              height: "100vh",
 | 
				
			||||||
 | 
					              display: "flex",
 | 
				
			||||||
 | 
					              justifyContent: "center",
 | 
				
			||||||
 | 
					              alignItems: "center",
 | 
				
			||||||
 | 
					              flexDirection: "column",
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Card
 | 
				
			||||||
 | 
					              bodyStyle={{ background: "rgb(250, 250, 250)" }}
 | 
				
			||||||
 | 
					              title="Login"
 | 
				
			||||||
 | 
					              className="login-form-card "
 | 
				
			||||||
 | 
					              style={{ width: 400 }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <form onSubmit={handleSubmit}>
 | 
				
			||||||
 | 
					                <Space
 | 
				
			||||||
 | 
					                  direction="vertical"
 | 
				
			||||||
 | 
					                  size="middle"
 | 
				
			||||||
 | 
					                  style={{ display: "flex", gap: "30px" }}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <Field name="login">
 | 
				
			||||||
 | 
					                    {({ input, meta }) => (
 | 
				
			||||||
 | 
					                      <div>
 | 
				
			||||||
 | 
					                        <Input
 | 
				
			||||||
 | 
					                          prefix={
 | 
				
			||||||
 | 
					                            <UserOutlined className="site-form-item-icon" />
 | 
				
			||||||
 | 
					                          }
 | 
				
			||||||
 | 
					                          size={"large"}
 | 
				
			||||||
 | 
					                          {...input}
 | 
				
			||||||
 | 
					                          type="text"
 | 
				
			||||||
 | 
					                          placeholder="username or e-mail"
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                        {(meta.error || meta.submitError) && meta.touched && (
 | 
				
			||||||
 | 
					                          <span style={{ color: "red" }}>
 | 
				
			||||||
 | 
					                            {meta.error || meta.submitError}
 | 
				
			||||||
 | 
					                          </span>
 | 
				
			||||||
 | 
					                        )}
 | 
				
			||||||
 | 
					                      </div>
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
 | 
					                  </Field>
 | 
				
			||||||
 | 
					                  {submitError && (
 | 
				
			||||||
 | 
					                    <div style={{ color: "red" }} className="error">
 | 
				
			||||||
 | 
					                      {submitError}
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  <Button
 | 
				
			||||||
 | 
					                    className="Login-form-button"
 | 
				
			||||||
 | 
					                    size={"large"}
 | 
				
			||||||
 | 
					                    htmlType="submit"
 | 
				
			||||||
 | 
					                    type="primary"
 | 
				
			||||||
 | 
					                    disabled={submitting}
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    Send
 | 
				
			||||||
 | 
					                  </Button>
 | 
				
			||||||
 | 
					                </Space>
 | 
				
			||||||
 | 
					              </form>
 | 
				
			||||||
 | 
					            </Card>
 | 
				
			||||||
 | 
					          </Space>
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <Success open={open} setOpen={setOpen} email={email} />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ResetPassword;
 | 
				
			||||||
@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					import { Modal } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Success = ({
 | 
				
			||||||
 | 
					  open,
 | 
				
			||||||
 | 
					  setOpen,
 | 
				
			||||||
 | 
					  email,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  email: string;
 | 
				
			||||||
 | 
					  open: boolean;
 | 
				
			||||||
 | 
					  setOpen(open: boolean): void;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setOpen(!open);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Modal open={open} title="Success!" onCancel={handleCancel} footer={null}>
 | 
				
			||||||
 | 
					        <p>
 | 
				
			||||||
 | 
					            A password-reset-link has been sent to your email! To reset your
 | 
				
			||||||
 | 
					          password you will need to follow the link provided in the message. The
 | 
				
			||||||
 | 
					          letter was sent to:{" "}
 | 
				
			||||||
 | 
					          <span style={{ textDecoration: "underline" }}>{email}</span>
 | 
				
			||||||
 | 
					          <br />
 | 
				
			||||||
 | 
					          <br />
 | 
				
			||||||
 | 
					            If for some reason you do not reset your password, within three days,
 | 
				
			||||||
 | 
					          the link sent to your e-mail will expire. You can request for
 | 
				
			||||||
 | 
					          control letter again.
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					      </Modal>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Success;
 | 
				
			||||||
@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					import React, { useState } from "react";
 | 
				
			||||||
 | 
					import CallTable from "./CallTable";
 | 
				
			||||||
 | 
					import { useCallData } from "../../Hooks/CallRequests";
 | 
				
			||||||
 | 
					import { Radio, RadioChangeEvent } from "antd";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Call = () => {
 | 
				
			||||||
 | 
					  const [status, setStatus] = useState("Awaiting");
 | 
				
			||||||
 | 
					  const { data, isLoading, refetch } = useCallData({ status: status });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <div>
 | 
				
			||||||
 | 
					        <div className="header d-flex">
 | 
				
			||||||
 | 
					          <p className="title">Call Requests</p>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div className="filter d-flex">
 | 
				
			||||||
 | 
					          <Radio.Group
 | 
				
			||||||
 | 
					            onChange={(e: RadioChangeEvent) => setStatus(e.target.value)}
 | 
				
			||||||
 | 
					            size="middle"
 | 
				
			||||||
 | 
					            value={status}
 | 
				
			||||||
 | 
					            style={{ marginLeft: 20 }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Radio.Button value={"Awaiting"}>Awaiting</Radio.Button>
 | 
				
			||||||
 | 
					            <Radio.Button value={"Resolved"}>Resolved</Radio.Button>
 | 
				
			||||||
 | 
					          </Radio.Group>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <CallTable data={data} isLoading={isLoading} refetch={refetch} />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Call;
 | 
				
			||||||
@ -0,0 +1,155 @@
 | 
				
			|||||||
 | 
					import { Button, Input, Modal, Space, Table } from "antd";
 | 
				
			||||||
 | 
					import { TCall } from "../../types/CallRequests/TCall";
 | 
				
			||||||
 | 
					import { EditOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					import moment from "moment";
 | 
				
			||||||
 | 
					import { callController } from "../../API/LayoutApi/callrequests";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					const CallTable = ({
 | 
				
			||||||
 | 
					  data,
 | 
				
			||||||
 | 
					  isLoading,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  data: TCall[] | undefined;
 | 
				
			||||||
 | 
					  isLoading: boolean;
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TCall[], unknown>>;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const statusClick = (record: TCall | any) => {
 | 
				
			||||||
 | 
					    callController
 | 
				
			||||||
 | 
					      .callPatch({ note: undefined, status: "Resolved" }, record.id)
 | 
				
			||||||
 | 
					      .then(() => {
 | 
				
			||||||
 | 
					        refetch();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [modalVisible, setModalVisible] = useState(false);
 | 
				
			||||||
 | 
					  const [note, setNote] = useState("");
 | 
				
			||||||
 | 
					  const [id, setId] = useState<number>();
 | 
				
			||||||
 | 
					  const addNote = (a: any) => {
 | 
				
			||||||
 | 
					    setModalVisible(true);
 | 
				
			||||||
 | 
					    setId(a.id);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleOk = () => {
 | 
				
			||||||
 | 
					    if (id) {
 | 
				
			||||||
 | 
					      callController
 | 
				
			||||||
 | 
					        .callPatch({ note: note, status: undefined }, id)
 | 
				
			||||||
 | 
					        .then(() => {
 | 
				
			||||||
 | 
					          refetch();
 | 
				
			||||||
 | 
					          setNote("");
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    setModalVisible(false);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setModalVisible(false);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleNoteChange = (e: React.ChangeEvent<HTMLInputElement>) => {
 | 
				
			||||||
 | 
					    setNote(e.target.value);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Table
 | 
				
			||||||
 | 
					        loading={isLoading}
 | 
				
			||||||
 | 
					        dataSource={data?.map((u, i) => ({
 | 
				
			||||||
 | 
					          ...u,
 | 
				
			||||||
 | 
					          no: i + 1,
 | 
				
			||||||
 | 
					          id: u?.id,
 | 
				
			||||||
 | 
					          company: u?.company?.name,
 | 
				
			||||||
 | 
					          driver: u?.driver?.name,
 | 
				
			||||||
 | 
					          time: moment(u?.created_at, "YYYY-MM-DD HH:mm:ss").format(
 | 
				
			||||||
 | 
					            "DD.MM.YYYY HH:mm"
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          action: u,
 | 
				
			||||||
 | 
					        }))}
 | 
				
			||||||
 | 
					        columns={[
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					            dataIndex: "no",
 | 
				
			||||||
 | 
					            width: "5%",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Company",
 | 
				
			||||||
 | 
					            dataIndex: "company",
 | 
				
			||||||
 | 
					            width: "20%",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Driver",
 | 
				
			||||||
 | 
					            dataIndex: "driver",
 | 
				
			||||||
 | 
					            width: "20%",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Note",
 | 
				
			||||||
 | 
					            dataIndex: "note",
 | 
				
			||||||
 | 
					            width: "15%",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          // {
 | 
				
			||||||
 | 
					          //   title: "Status",
 | 
				
			||||||
 | 
					          //   dataIndex: "status",
 | 
				
			||||||
 | 
					          //   width: "8%",
 | 
				
			||||||
 | 
					          //   render: (status: string) => (
 | 
				
			||||||
 | 
					          //     <span>
 | 
				
			||||||
 | 
					          //       {status === "Awaiting" && (
 | 
				
			||||||
 | 
					          //         <p className="status-new">Awaiting</p>
 | 
				
			||||||
 | 
					          //       )}
 | 
				
			||||||
 | 
					          //       {status === "Resolved" && (
 | 
				
			||||||
 | 
					          //         <p className="status-done">Resolved</p>
 | 
				
			||||||
 | 
					          //       )}
 | 
				
			||||||
 | 
					          //     </span>
 | 
				
			||||||
 | 
					          //   ),
 | 
				
			||||||
 | 
					          // },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Requested at",
 | 
				
			||||||
 | 
					            dataIndex: "time",
 | 
				
			||||||
 | 
					            width: "15%",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Actions",
 | 
				
			||||||
 | 
					            dataIndex: "action",
 | 
				
			||||||
 | 
					            width: "100px",
 | 
				
			||||||
 | 
					            render: (text, record) => {
 | 
				
			||||||
 | 
					              return (
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                  {record.status !== "Resolved" && (
 | 
				
			||||||
 | 
					                    <Button type="primary" onClick={() => statusClick(record)}>
 | 
				
			||||||
 | 
					                      Resolve
 | 
				
			||||||
 | 
					                    </Button>
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					                  <Button
 | 
				
			||||||
 | 
					                    style={{ marginLeft: 16 }}
 | 
				
			||||||
 | 
					                    type="primary"
 | 
				
			||||||
 | 
					                    onClick={(e) => addNote(record)}
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <EditOutlined />
 | 
				
			||||||
 | 
					                  </Button>
 | 
				
			||||||
 | 
					                  <Modal
 | 
				
			||||||
 | 
					                    title="Add note"
 | 
				
			||||||
 | 
					                    visible={modalVisible}
 | 
				
			||||||
 | 
					                    onOk={handleOk}
 | 
				
			||||||
 | 
					                    onCancel={handleCancel}
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <Input value={note} onChange={(e) => handleNoteChange(e)} />
 | 
				
			||||||
 | 
					                  </Modal>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              );
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ]}
 | 
				
			||||||
 | 
					        rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					          index % 2 === 0 ? "odd-row" : "even-row"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default CallTable;
 | 
				
			||||||
@ -0,0 +1,115 @@
 | 
				
			|||||||
 | 
					import { Input, Modal, Form as FormAnt, Switch, Select } from "antd";
 | 
				
			||||||
 | 
					import { companyController } from "../../API/LayoutApi/companies";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					import { TCompany } from "../../types/Company/TCompany";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AddCompany = ({
 | 
				
			||||||
 | 
					  open,
 | 
				
			||||||
 | 
					  setOpen,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TCompany[], unknown>>;
 | 
				
			||||||
 | 
					  open: boolean;
 | 
				
			||||||
 | 
					  setOpen(open: boolean): void;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const [form] = FormAnt.useForm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setOpen(!open);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const eld = [
 | 
				
			||||||
 | 
					    { name: "Zippy" },
 | 
				
			||||||
 | 
					    { name: "EVO" },
 | 
				
			||||||
 | 
					    { name: "Ontime" },
 | 
				
			||||||
 | 
					    { name: "Zeelog" },
 | 
				
			||||||
 | 
					    { name: "TT" },
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Modal
 | 
				
			||||||
 | 
					        open={open}
 | 
				
			||||||
 | 
					        title="Add Company"
 | 
				
			||||||
 | 
					        okText="Create"
 | 
				
			||||||
 | 
					        cancelText="Cancel"
 | 
				
			||||||
 | 
					        onCancel={handleCancel}
 | 
				
			||||||
 | 
					        onOk={() => {
 | 
				
			||||||
 | 
					          form.validateFields().then(async (values) => {
 | 
				
			||||||
 | 
					            await companyController
 | 
				
			||||||
 | 
					              .addCompanyController(values)
 | 
				
			||||||
 | 
					              .then((data) => {
 | 
				
			||||||
 | 
					                if (data) {
 | 
				
			||||||
 | 
					                  form.resetFields();
 | 
				
			||||||
 | 
					                  setOpen(!open);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					            refetch();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <FormAnt
 | 
				
			||||||
 | 
					          form={form}
 | 
				
			||||||
 | 
					          layout="horizontal"
 | 
				
			||||||
 | 
					          name="form_in_modal"
 | 
				
			||||||
 | 
					          initialValues={{ modifier: "public" }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Name"
 | 
				
			||||||
 | 
					            name="name"
 | 
				
			||||||
 | 
					            rules={[{ required: true, message: "Please enter company name!" }]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Input />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Source"
 | 
				
			||||||
 | 
					            name="source"
 | 
				
			||||||
 | 
					            rules={[{ required: false, message: "Please input owner name!" }]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Select
 | 
				
			||||||
 | 
					              options={eld?.map((item) => ({
 | 
				
			||||||
 | 
					                label: item?.name,
 | 
				
			||||||
 | 
					                value: item?.name,
 | 
				
			||||||
 | 
					              }))}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Is Active"
 | 
				
			||||||
 | 
					            name="is_active"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: false, message: "Please input company status!" },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Switch defaultChecked={true} />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="USDOT"
 | 
				
			||||||
 | 
					            name="usdot"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: false, message: "Please input company status!" },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Input />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="API Key"
 | 
				
			||||||
 | 
					            name="api_key"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: false, message: "Please input company status!" },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Input />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					        </FormAnt>
 | 
				
			||||||
 | 
					      </Modal>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default AddCompany;
 | 
				
			||||||
@ -0,0 +1,120 @@
 | 
				
			|||||||
 | 
					import { Input, Modal, Form as FormAnt, Select } from "antd";
 | 
				
			||||||
 | 
					import { customerController } from "../../API/LayoutApi/customers";
 | 
				
			||||||
 | 
					import { useCompanyData, useCompanyOne } 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 { useState } from "react";
 | 
				
			||||||
 | 
					const AddDriver = ({
 | 
				
			||||||
 | 
					  open,
 | 
				
			||||||
 | 
					  id,
 | 
				
			||||||
 | 
					  setOpen,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  id: any;
 | 
				
			||||||
 | 
					  open: boolean;
 | 
				
			||||||
 | 
					  setOpen(open: boolean): void;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const [form] = FormAnt.useForm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setOpen(!open);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const companyData = useCompanyOne(id);
 | 
				
			||||||
 | 
					  const companyDataAll = useCompanyData({ name: "" });
 | 
				
			||||||
 | 
					  const [companyName, setCompanyName] = useState<string>();
 | 
				
			||||||
 | 
					  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 (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Modal
 | 
				
			||||||
 | 
					        open={open}
 | 
				
			||||||
 | 
					        title="Add Driver"
 | 
				
			||||||
 | 
					        okText="Create"
 | 
				
			||||||
 | 
					        cancelText="Cancel"
 | 
				
			||||||
 | 
					        onCancel={handleCancel}
 | 
				
			||||||
 | 
					        onOk={() => {
 | 
				
			||||||
 | 
					          form.validateFields().then(async (values) => {
 | 
				
			||||||
 | 
					            form.resetFields();
 | 
				
			||||||
 | 
					            const updatedValues = { ...values };
 | 
				
			||||||
 | 
					            updatedValues.company_id = id;
 | 
				
			||||||
 | 
					            await customerController.addCustomerController(updatedValues);
 | 
				
			||||||
 | 
					            setOpen(!open);
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <FormAnt
 | 
				
			||||||
 | 
					          form={form}
 | 
				
			||||||
 | 
					          layout="horizontal"
 | 
				
			||||||
 | 
					          name="form_in_modal"
 | 
				
			||||||
 | 
					          initialValues={{ modifier: "public" }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Name"
 | 
				
			||||||
 | 
					            name="name"
 | 
				
			||||||
 | 
					            rules={[{ required: true, message: "Please input Name!" }]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Input />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Company"
 | 
				
			||||||
 | 
					            name="company_id"
 | 
				
			||||||
 | 
					            rules={[{ required: false, message: "Please input company!" }]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            {id ? (
 | 
				
			||||||
 | 
					              <Input defaultValue={companyData?.data?.name} readOnly />
 | 
				
			||||||
 | 
					            ) : (
 | 
				
			||||||
 | 
					              <Select
 | 
				
			||||||
 | 
					                showSearch
 | 
				
			||||||
 | 
					                placeholder="Search Company"
 | 
				
			||||||
 | 
					                onSearch={(value: any) => setCompanyName(value)}
 | 
				
			||||||
 | 
					                options={companyDataAll?.data?.map((item: any) => ({
 | 
				
			||||||
 | 
					                  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
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					        </FormAnt>
 | 
				
			||||||
 | 
					      </Modal>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default AddDriver;
 | 
				
			||||||
@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					import { useRef, useState } from "react";
 | 
				
			||||||
 | 
					import AddCompany from "./AddCompanies";
 | 
				
			||||||
 | 
					import CompanyTable from "./CompaniesTable";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import IconSearch from "../../assets/searchIcon.png";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { useCompanyData } from "../../Hooks/Companies";
 | 
				
			||||||
 | 
					//@ts-ignore
 | 
				
			||||||
 | 
					import addicon from "../../assets/addiconpng.png";
 | 
				
			||||||
 | 
					const theme = localStorage.getItem("theme") === "true" ? true : false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Company = () => {
 | 
				
			||||||
 | 
					  const [open, setOpen] = useState(false);
 | 
				
			||||||
 | 
					  const showModal = () => {
 | 
				
			||||||
 | 
					    setOpen(true);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [search, setSearch] = useState<any>("");
 | 
				
			||||||
 | 
					  const { data, isLoading, refetch } = useCompanyData({
 | 
				
			||||||
 | 
					    name: search,
 | 
				
			||||||
 | 
					    is_active: undefined,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const timerRef = useRef<NodeJS.Timeout | null>(null);
 | 
				
			||||||
 | 
					  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
 | 
				
			||||||
 | 
					    if (timerRef.current) {
 | 
				
			||||||
 | 
					      clearTimeout(timerRef.current);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const searchText = e.target.value;
 | 
				
			||||||
 | 
					    timerRef.current = setTimeout(() => {
 | 
				
			||||||
 | 
					      setSearch(searchText);
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      {open && <AddCompany open={open} refetch={refetch} setOpen={setOpen} />}
 | 
				
			||||||
 | 
					      <div className="header d-flex">
 | 
				
			||||||
 | 
					        <h1 className="title">Companies</h1>
 | 
				
			||||||
 | 
					        <button
 | 
				
			||||||
 | 
					          style={{ marginRight: 0 }}
 | 
				
			||||||
 | 
					          className="btn-add d-flex"
 | 
				
			||||||
 | 
					          onClick={showModal}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <img src={addicon} style={{ marginRight: 8 }} alt="" />
 | 
				
			||||||
 | 
					          Add Company
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className="filter d-flex">
 | 
				
			||||||
 | 
					        <div className="search-div">
 | 
				
			||||||
 | 
					          <img src={IconSearch} alt="" />
 | 
				
			||||||
 | 
					          <input
 | 
				
			||||||
 | 
					            className={`search-input-${theme}`}
 | 
				
			||||||
 | 
					            type="text"
 | 
				
			||||||
 | 
					            placeholder="Search"
 | 
				
			||||||
 | 
					            onChange={handleSearchChange}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      <CompanyTable data={data} isLoading={isLoading} />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Company;
 | 
				
			||||||
@ -0,0 +1,359 @@
 | 
				
			|||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import { useNavigate, useParams } from "react-router-dom";
 | 
				
			||||||
 | 
					import { useCompanyOne } from "../../Hooks/Companies";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Form,
 | 
				
			||||||
 | 
					  Spin,
 | 
				
			||||||
 | 
					  Watermark,
 | 
				
			||||||
 | 
					  Space,
 | 
				
			||||||
 | 
					  Tabs,
 | 
				
			||||||
 | 
					  Row,
 | 
				
			||||||
 | 
					  Col,
 | 
				
			||||||
 | 
					  Input,
 | 
				
			||||||
 | 
					  Button,
 | 
				
			||||||
 | 
					  Tag,
 | 
				
			||||||
 | 
					  Radio,
 | 
				
			||||||
 | 
					  RadioChangeEvent,
 | 
				
			||||||
 | 
					  Select,
 | 
				
			||||||
 | 
					} from "antd";
 | 
				
			||||||
 | 
					import { companyController } from "../../API/LayoutApi/companies";
 | 
				
			||||||
 | 
					import { DashboardOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					import Notfound from "../../Utils/Notfound";
 | 
				
			||||||
 | 
					import Table from "antd/es/table";
 | 
				
			||||||
 | 
					import AddDriver from "./AddDriver";
 | 
				
			||||||
 | 
					import { useCustomerByComanyData } from "../../Hooks/Customers";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// @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";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIcon from "../../assets/infoIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIconActive from "../../assets/infoIconActive.png";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					import { useTeamData } from "../../Hooks/Teams";
 | 
				
			||||||
 | 
					import { validateLocaleAndSetLanguage } from "typescript";
 | 
				
			||||||
 | 
					const TabPane = Tabs.TabPane;
 | 
				
			||||||
 | 
					type params = {
 | 
				
			||||||
 | 
					  readonly id: any;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					type MyObjectType = {
 | 
				
			||||||
 | 
					  [key: string | number]: any;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const CompanyEdit = () => {
 | 
				
			||||||
 | 
					  const [open, setOpen] = useState(false);
 | 
				
			||||||
 | 
					  const { id } = useParams<params>();
 | 
				
			||||||
 | 
					  const customerData = useCustomerByComanyData({ id: id });
 | 
				
			||||||
 | 
					  const { data, refetch, status }: MyObjectType = useCompanyOne(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const showModal = () => {
 | 
				
			||||||
 | 
					    setOpen(true);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  let navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onSubmit = async (value: any) => {
 | 
				
			||||||
 | 
					    value.team_id = team;
 | 
				
			||||||
 | 
					    await companyController.companyPatch(value, id);
 | 
				
			||||||
 | 
					    refetch();
 | 
				
			||||||
 | 
					    navigate(-1);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const ClickDelete = () => {
 | 
				
			||||||
 | 
					    const shouldDelete = window.confirm(
 | 
				
			||||||
 | 
					      "Вы уверены, что хотите удалить эту компанию?"
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    if (shouldDelete && id !== undefined) {
 | 
				
			||||||
 | 
					      companyController.deleteCompanyController(id).then(() => {
 | 
				
			||||||
 | 
					        document.location.replace(`/#/companies`);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [value, setValue] = useState(1);
 | 
				
			||||||
 | 
					  const onChange = (e: RadioChangeEvent) => {
 | 
				
			||||||
 | 
					    console.log("radio checked", e.target.value);
 | 
				
			||||||
 | 
					    setValue(e.target.value);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [activeTab, setActiveTab] = useState("1");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const TeamData = useTeamData("");
 | 
				
			||||||
 | 
					  const noTeamOption = { label: " - - - - - -", value: "" };
 | 
				
			||||||
 | 
					  const TeamOption: { label: string; value: any }[] | undefined =
 | 
				
			||||||
 | 
					    TeamData?.data?.map((item) => ({
 | 
				
			||||||
 | 
					      label: item?.name,
 | 
				
			||||||
 | 
					      value: item?.id,
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  if (TeamOption) {
 | 
				
			||||||
 | 
					    TeamOption.unshift(noTeamOption);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [team, setTeam] = useState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					        <Watermark style={{ height: "100%" }}>
 | 
				
			||||||
 | 
					          {status === "loading" ? (
 | 
				
			||||||
 | 
					            <Spin size="large" spinning={!data} />
 | 
				
			||||||
 | 
					          ) : data ? (
 | 
				
			||||||
 | 
					            <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					              <Space
 | 
				
			||||||
 | 
					                direction="vertical"
 | 
				
			||||||
 | 
					                size="middle"
 | 
				
			||||||
 | 
					                style={{ display: "flex" }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <Tabs
 | 
				
			||||||
 | 
					                  defaultActiveKey="1"
 | 
				
			||||||
 | 
					                  activeKey={activeTab}
 | 
				
			||||||
 | 
					                  onChange={(key) => setActiveTab(key)}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <TabPane
 | 
				
			||||||
 | 
					                    tab={
 | 
				
			||||||
 | 
					                      <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					                        <img
 | 
				
			||||||
 | 
					                          style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                          src={activeTab === "1" ? infoIconActive : infoIcon}
 | 
				
			||||||
 | 
					                          alt=""
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                        Information
 | 
				
			||||||
 | 
					                      </span>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    key="1"
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <Space
 | 
				
			||||||
 | 
					                      direction="vertical"
 | 
				
			||||||
 | 
					                      size="middle"
 | 
				
			||||||
 | 
					                      style={{ display: "flex" }}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <Form
 | 
				
			||||||
 | 
					                        name="basic"
 | 
				
			||||||
 | 
					                        layout="vertical"
 | 
				
			||||||
 | 
					                        wrapperCol={{ span: 16 }}
 | 
				
			||||||
 | 
					                        initialValues={{ ...data }}
 | 
				
			||||||
 | 
					                        onFinish={onSubmit}
 | 
				
			||||||
 | 
					                        autoComplete="off"
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        <Row gutter={[16, 10]}>
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label={"Name"}
 | 
				
			||||||
 | 
					                              name="name"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Input />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="USDOT"
 | 
				
			||||||
 | 
					                              name="usdot"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Input />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="Team"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Select
 | 
				
			||||||
 | 
					                                options={TeamOption}
 | 
				
			||||||
 | 
					                                defaultValue={data?.team?.name}
 | 
				
			||||||
 | 
					                                onChange={(e) => setTeam(e)}
 | 
				
			||||||
 | 
					                              />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                        </Row>
 | 
				
			||||||
 | 
					                        <Row gutter={[16, 10]}>
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="API Key"
 | 
				
			||||||
 | 
					                              name="api_key"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Input />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                          <Col span={12}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="Source"
 | 
				
			||||||
 | 
					                              name="source"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Radio.Group
 | 
				
			||||||
 | 
					                                onChange={onChange}
 | 
				
			||||||
 | 
					                                value={value}
 | 
				
			||||||
 | 
					                                style={{
 | 
				
			||||||
 | 
					                                  display: "flex",
 | 
				
			||||||
 | 
					                                  justifyContent: "space-between",
 | 
				
			||||||
 | 
					                                }}
 | 
				
			||||||
 | 
					                              >
 | 
				
			||||||
 | 
					                                <Radio value="TT">
 | 
				
			||||||
 | 
					                                  <img
 | 
				
			||||||
 | 
					                                    style={{ width: 50, height: 50 }}
 | 
				
			||||||
 | 
					                                    src={tt}
 | 
				
			||||||
 | 
					                                    alt=""
 | 
				
			||||||
 | 
					                                  />
 | 
				
			||||||
 | 
					                                </Radio>
 | 
				
			||||||
 | 
					                                <Radio value="EVO">
 | 
				
			||||||
 | 
					                                  <img
 | 
				
			||||||
 | 
					                                    style={{ width: 50, height: 50 }}
 | 
				
			||||||
 | 
					                                    src={evo}
 | 
				
			||||||
 | 
					                                    alt=""
 | 
				
			||||||
 | 
					                                  />
 | 
				
			||||||
 | 
					                                </Radio>
 | 
				
			||||||
 | 
					                                <Radio value="Zippy">
 | 
				
			||||||
 | 
					                                  <img
 | 
				
			||||||
 | 
					                                    style={{ width: 50, height: 50 }}
 | 
				
			||||||
 | 
					                                    src={zippy}
 | 
				
			||||||
 | 
					                                    alt=""
 | 
				
			||||||
 | 
					                                  />
 | 
				
			||||||
 | 
					                                </Radio>
 | 
				
			||||||
 | 
					                                <Radio value="Ontime">
 | 
				
			||||||
 | 
					                                  <img
 | 
				
			||||||
 | 
					                                    style={{ width: 50, height: 50 }}
 | 
				
			||||||
 | 
					                                    src={ontime}
 | 
				
			||||||
 | 
					                                    alt=""
 | 
				
			||||||
 | 
					                                  />
 | 
				
			||||||
 | 
					                                </Radio>
 | 
				
			||||||
 | 
					                                <Radio value="Zeelog">
 | 
				
			||||||
 | 
					                                  <img
 | 
				
			||||||
 | 
					                                    style={{ width: 50, height: 50 }}
 | 
				
			||||||
 | 
					                                    src={zeelog}
 | 
				
			||||||
 | 
					                                    alt=""
 | 
				
			||||||
 | 
					                                  />
 | 
				
			||||||
 | 
					                                </Radio>
 | 
				
			||||||
 | 
					                              </Radio.Group>
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                        </Row>
 | 
				
			||||||
 | 
					                        <Form.Item>
 | 
				
			||||||
 | 
					                          {role === "Owner" && (
 | 
				
			||||||
 | 
					                            <Button
 | 
				
			||||||
 | 
					                              onClick={() => ClickDelete()}
 | 
				
			||||||
 | 
					                              type="primary"
 | 
				
			||||||
 | 
					                              style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                              danger
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              Delete
 | 
				
			||||||
 | 
					                            </Button>
 | 
				
			||||||
 | 
					                          )}
 | 
				
			||||||
 | 
					                          {role === "Owner" && (
 | 
				
			||||||
 | 
					                            <Button type="primary" htmlType="submit">
 | 
				
			||||||
 | 
					                              Submit
 | 
				
			||||||
 | 
					                            </Button>
 | 
				
			||||||
 | 
					                          )}
 | 
				
			||||||
 | 
					                        </Form.Item>
 | 
				
			||||||
 | 
					                      </Form>
 | 
				
			||||||
 | 
					                    </Space>
 | 
				
			||||||
 | 
					                  </TabPane>
 | 
				
			||||||
 | 
					                  <TabPane
 | 
				
			||||||
 | 
					                    tab={
 | 
				
			||||||
 | 
					                      <span>
 | 
				
			||||||
 | 
					                        <DashboardOutlined />
 | 
				
			||||||
 | 
					                        Drivers
 | 
				
			||||||
 | 
					                      </span>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    key="2"
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <Table
 | 
				
			||||||
 | 
					                      onRow={(record) => {
 | 
				
			||||||
 | 
					                        let isTextSelected = false;
 | 
				
			||||||
 | 
					                        document.addEventListener("selectionchange", () => {
 | 
				
			||||||
 | 
					                          const selection = window.getSelection();
 | 
				
			||||||
 | 
					                          if (
 | 
				
			||||||
 | 
					                            selection !== null &&
 | 
				
			||||||
 | 
					                            selection.toString() !== ""
 | 
				
			||||||
 | 
					                          ) {
 | 
				
			||||||
 | 
					                            isTextSelected = true;
 | 
				
			||||||
 | 
					                          } else {
 | 
				
			||||||
 | 
					                            isTextSelected = false;
 | 
				
			||||||
 | 
					                          }
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                        return {
 | 
				
			||||||
 | 
					                          onClick: (event: any) => {
 | 
				
			||||||
 | 
					                            if (isTextSelected) {
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            document.location.replace(
 | 
				
			||||||
 | 
					                              `/#/customers/${record.id}`
 | 
				
			||||||
 | 
					                            );
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        };
 | 
				
			||||||
 | 
					                      }}
 | 
				
			||||||
 | 
					                      dataSource={customerData?.data?.map((u, i) => ({
 | 
				
			||||||
 | 
					                        ...u,
 | 
				
			||||||
 | 
					                        no: i + 1,
 | 
				
			||||||
 | 
					                        key: u?.id,
 | 
				
			||||||
 | 
					                      }))}
 | 
				
			||||||
 | 
					                      columns={[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                          title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					                          dataIndex: "no",
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                          title: "Name",
 | 
				
			||||||
 | 
					                          dataIndex: "name",
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                          title: "Role",
 | 
				
			||||||
 | 
					                          dataIndex: "profession",
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                          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: any, record: any) => {
 | 
				
			||||||
 | 
					                            return record.isActive === value;
 | 
				
			||||||
 | 
					                          },
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                      ]}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    {open && (
 | 
				
			||||||
 | 
					                      <AddDriver id={id} open={open} setOpen={setOpen} />
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
 | 
					                    <Button
 | 
				
			||||||
 | 
					                      type="primary"
 | 
				
			||||||
 | 
					                      style={{ marginLeft: "auto" }}
 | 
				
			||||||
 | 
					                      size={"middle"}
 | 
				
			||||||
 | 
					                      onClick={showModal}
 | 
				
			||||||
 | 
					                      disabled={role !== "Owner"}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      Add Driver
 | 
				
			||||||
 | 
					                    </Button>
 | 
				
			||||||
 | 
					                  </TabPane>
 | 
				
			||||||
 | 
					                </Tabs>
 | 
				
			||||||
 | 
					              </Space>
 | 
				
			||||||
 | 
					            </Spin>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            <Notfound />
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        </Watermark>
 | 
				
			||||||
 | 
					      </Spin>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default CompanyEdit;
 | 
				
			||||||
@ -0,0 +1,177 @@
 | 
				
			|||||||
 | 
					import React, { useState } from "react";
 | 
				
			||||||
 | 
					import { Button, Space, Table, Tooltip, message } from "antd";
 | 
				
			||||||
 | 
					import { Link } from "react-router-dom";
 | 
				
			||||||
 | 
					import { SyncOutlined, EyeOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					import { companyController } from "../../API/LayoutApi/companies";
 | 
				
			||||||
 | 
					import { TCompany } from "../../types/Company/TCompany";
 | 
				
			||||||
 | 
					// @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";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function CompanyTable({
 | 
				
			||||||
 | 
					  data,
 | 
				
			||||||
 | 
					  isLoading,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  data?: TCompany[] | undefined;
 | 
				
			||||||
 | 
					  isLoading?: boolean;
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
					  const moment = require("moment");
 | 
				
			||||||
 | 
					  const [loadings, setLoadings] = useState<boolean[]>([]);
 | 
				
			||||||
 | 
					  function getStatusClassName() {
 | 
				
			||||||
 | 
					    if (role !== "Owner") {
 | 
				
			||||||
 | 
					      return "isnot";
 | 
				
			||||||
 | 
					    } else if (role === "Owner") {
 | 
				
			||||||
 | 
					      return "super";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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 (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Table
 | 
				
			||||||
 | 
					        dataSource={data?.map((u, i) => ({
 | 
				
			||||||
 | 
					          ...u,
 | 
				
			||||||
 | 
					          no: i + 1,
 | 
				
			||||||
 | 
					          created: moment(u?.created_at, "YYYY-MM-DD HH:mm:ss").format(
 | 
				
			||||||
 | 
					            "DD.MM.YYYY HH:mm"
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          key: u?.id,
 | 
				
			||||||
 | 
					          action: { ...u },
 | 
				
			||||||
 | 
					        }))}
 | 
				
			||||||
 | 
					        loading={isLoading}
 | 
				
			||||||
 | 
					        columns={[
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					            dataIndex: "no",
 | 
				
			||||||
 | 
					            width: "5%",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Company",
 | 
				
			||||||
 | 
					            dataIndex: "name",
 | 
				
			||||||
 | 
					            width: "25%",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            render: (text, record) => (
 | 
				
			||||||
 | 
					              <Tooltip placement="topLeft" title={text}>
 | 
				
			||||||
 | 
					                <div style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					                  {record?.source && (
 | 
				
			||||||
 | 
					                    <img
 | 
				
			||||||
 | 
					                      src={getImageSource(record?.source)}
 | 
				
			||||||
 | 
					                      alt=""
 | 
				
			||||||
 | 
					                      style={{ width: 20, height: 20, marginRight: 10 }}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					                  {text}
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              </Tooltip>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Team",
 | 
				
			||||||
 | 
					            dataIndex: "team",
 | 
				
			||||||
 | 
					            render: (status: string, record: TCompany) => (
 | 
				
			||||||
 | 
					              <span className={getStatusClassName()}>{record?.team?.name}</span>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "USDOT",
 | 
				
			||||||
 | 
					            dataIndex: "usdot",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "API KEY",
 | 
				
			||||||
 | 
					            dataIndex: "api_key",
 | 
				
			||||||
 | 
					            render: (status: string, record: TCompany) => (
 | 
				
			||||||
 | 
					              <span className={getStatusClassName()}>{status}</span>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Created at",
 | 
				
			||||||
 | 
					            dataIndex: "created",
 | 
				
			||||||
 | 
					            responsive: ["lg"],
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            width: "20%",
 | 
				
			||||||
 | 
					            title: "Actions",
 | 
				
			||||||
 | 
					            dataIndex: "action",
 | 
				
			||||||
 | 
					            render: ({ id, api }: { id: string; api: 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 (
 | 
				
			||||||
 | 
					                <Space>
 | 
				
			||||||
 | 
					                  <Link to={`${id}`}>
 | 
				
			||||||
 | 
					                    {role === "Owner" && <Button type="primary">Edit</Button>}
 | 
				
			||||||
 | 
					                    {role !== "Owner" && (
 | 
				
			||||||
 | 
					                      <Button type="primary" icon={<EyeOutlined />}></Button>
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
 | 
					                  </Link>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                  {role === "Owner" && (
 | 
				
			||||||
 | 
					                    <Button
 | 
				
			||||||
 | 
					                      type="primary"
 | 
				
			||||||
 | 
					                      icon={<SyncOutlined />}
 | 
				
			||||||
 | 
					                      loading={loadings[Number(id)]}
 | 
				
			||||||
 | 
					                      onClick={() => enterLoading(Number(id), api)}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					                </Space>
 | 
				
			||||||
 | 
					              );
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ]}
 | 
				
			||||||
 | 
					        rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					          index % 2 === 0 ? "odd-row" : "even-row"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        size="middle"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default CompanyTable;
 | 
				
			||||||
@ -0,0 +1,122 @@
 | 
				
			|||||||
 | 
					import { Input, Modal, Form as FormAnt, Select } from "antd";
 | 
				
			||||||
 | 
					import { customerController } from "../../API/LayoutApi/customers";
 | 
				
			||||||
 | 
					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";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AddCustomer = ({
 | 
				
			||||||
 | 
					  open,
 | 
				
			||||||
 | 
					  setOpen,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  open: boolean;
 | 
				
			||||||
 | 
					  refetch: any;
 | 
				
			||||||
 | 
					  setOpen(open: boolean): void;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const [form] = FormAnt.useForm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setOpen(!open);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [companyName, setCompanyName] = useState<string>("");
 | 
				
			||||||
 | 
					  const { data } = useCompanyData({ name: companyName });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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 (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Modal
 | 
				
			||||||
 | 
					        open={open}
 | 
				
			||||||
 | 
					        title="Add Driver"
 | 
				
			||||||
 | 
					        okText="Create"
 | 
				
			||||||
 | 
					        cancelText="Cancel"
 | 
				
			||||||
 | 
					        onCancel={handleCancel}
 | 
				
			||||||
 | 
					        onOk={() => {
 | 
				
			||||||
 | 
					          form.validateFields().then(async (values) => {
 | 
				
			||||||
 | 
					            form.resetFields();
 | 
				
			||||||
 | 
					            await customerController
 | 
				
			||||||
 | 
					              .addCustomerController(values)
 | 
				
			||||||
 | 
					              .then((data) => {
 | 
				
			||||||
 | 
					                if (data) {
 | 
				
			||||||
 | 
					                  setOpen(!open);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					            refetch();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <FormAnt
 | 
				
			||||||
 | 
					          form={form}
 | 
				
			||||||
 | 
					          layout="horizontal"
 | 
				
			||||||
 | 
					          name="form_in_modal"
 | 
				
			||||||
 | 
					          initialValues={{ modifier: "public" }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Name"
 | 
				
			||||||
 | 
					            name="name"
 | 
				
			||||||
 | 
					            rules={[{ required: true, message: "Please input Driver name!" }]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Input />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Company"
 | 
				
			||||||
 | 
					            name="company_id"
 | 
				
			||||||
 | 
					            rules={[{ required: false, message: "Please input Company name!" }]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Select
 | 
				
			||||||
 | 
					              showSearch
 | 
				
			||||||
 | 
					              placeholder="Search Company"
 | 
				
			||||||
 | 
					              onSearch={(value: any) => setCompanyName(value)}
 | 
				
			||||||
 | 
					              options={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
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					        </FormAnt>
 | 
				
			||||||
 | 
					      </Modal>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default AddCustomer;
 | 
				
			||||||
@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					import { useRef, useState } from "react";
 | 
				
			||||||
 | 
					import AddCustomer from "./AddCustomer";
 | 
				
			||||||
 | 
					import CustomerTable from "./CustomersTable";
 | 
				
			||||||
 | 
					import { useCustomerData } from "../../Hooks/Customers";
 | 
				
			||||||
 | 
					//@ts-ignore
 | 
				
			||||||
 | 
					import addicon from "../../assets/addiconpng.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import IconSearch from "../../assets/searchIcon.png";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Customer = () => {
 | 
				
			||||||
 | 
					  const [open, setOpen] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const showModal = () => {
 | 
				
			||||||
 | 
					    setOpen(true);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [search, setSearch] = useState("");
 | 
				
			||||||
 | 
					  const { isLoading, data, refetch } = useCustomerData({
 | 
				
			||||||
 | 
					    name: search,
 | 
				
			||||||
 | 
					    is_active: undefined,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const timerRef = useRef<NodeJS.Timeout | null>(null);
 | 
				
			||||||
 | 
					  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
 | 
				
			||||||
 | 
					    if (timerRef.current) {
 | 
				
			||||||
 | 
					      clearTimeout(timerRef.current);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const searchText = e.target.value;
 | 
				
			||||||
 | 
					    timerRef.current = setTimeout(() => {
 | 
				
			||||||
 | 
					      setSearch(searchText);
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const theme = localStorage.getItem("theme") === "true" ? true : false;
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      {open && <AddCustomer open={open} setOpen={setOpen} refetch={refetch} />}
 | 
				
			||||||
 | 
					      <div className="header d-flex">
 | 
				
			||||||
 | 
					        <p className="title">Drivers</p>
 | 
				
			||||||
 | 
					        <button className="btn-add d-flex" onClick={showModal}>
 | 
				
			||||||
 | 
					          <img src={addicon} style={{ marginRight: 8 }} alt="" />
 | 
				
			||||||
 | 
					          Add Driver
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className="filter d-flex">
 | 
				
			||||||
 | 
					        <div className="search-div">
 | 
				
			||||||
 | 
					          <img src={IconSearch} alt="" />
 | 
				
			||||||
 | 
					          <input
 | 
				
			||||||
 | 
					            className={`search-input-${theme}`}
 | 
				
			||||||
 | 
					            type="text"
 | 
				
			||||||
 | 
					            placeholder="Search"
 | 
				
			||||||
 | 
					            onChange={handleSearchChange}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <CustomerTable data={data} isLoading={isLoading} />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Customer;
 | 
				
			||||||
@ -0,0 +1,151 @@
 | 
				
			|||||||
 | 
					import { useParams } from "react-router-dom";
 | 
				
			||||||
 | 
					import { useCustomerOne } from "../../Hooks/Customers";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Form,
 | 
				
			||||||
 | 
					  Spin,
 | 
				
			||||||
 | 
					  Watermark,
 | 
				
			||||||
 | 
					  Space,
 | 
				
			||||||
 | 
					  Tabs,
 | 
				
			||||||
 | 
					  Row,
 | 
				
			||||||
 | 
					  Col,
 | 
				
			||||||
 | 
					  Input,
 | 
				
			||||||
 | 
					  Button,
 | 
				
			||||||
 | 
					} from "antd";
 | 
				
			||||||
 | 
					import { customerController } from "../../API/LayoutApi/customers";
 | 
				
			||||||
 | 
					import Notfound from "../../Utils/Notfound";
 | 
				
			||||||
 | 
					import { useCompanyOne } from "../../Hooks/Companies";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIcon from "../../assets/infoIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIconActive from "../../assets/infoIconActive.png";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TabPane = Tabs.TabPane;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type params = {
 | 
				
			||||||
 | 
					  readonly id: any;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const CustomerEdit = () => {
 | 
				
			||||||
 | 
					  const { id } = useParams<params>();
 | 
				
			||||||
 | 
					  const { data, refetch, status } = useCustomerOne(id);
 | 
				
			||||||
 | 
					  const onSubmit = async (value: any) => {
 | 
				
			||||||
 | 
					    await customerController.customerPatch(value, id);
 | 
				
			||||||
 | 
					    refetch();
 | 
				
			||||||
 | 
					    window.location.replace("/#/customers/");
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const companyData = useCompanyOne(data?.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const ClickDelete = () => {
 | 
				
			||||||
 | 
					    const shouldDelete = window.confirm(
 | 
				
			||||||
 | 
					      "Are you sure, you want to delete this Driver?"
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    if (shouldDelete && id !== undefined) {
 | 
				
			||||||
 | 
					      customerController.deleteCustomerController(id).then((data: any) => {
 | 
				
			||||||
 | 
					        document.location.replace(`/#/customers`);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [activeTab, setActiveTab] = useState("1");
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					        <Watermark style={{ height: "100%" }}>
 | 
				
			||||||
 | 
					          {status === "loading" ? (
 | 
				
			||||||
 | 
					            <Spin size="large" spinning={!data} />
 | 
				
			||||||
 | 
					          ) : data ? (
 | 
				
			||||||
 | 
					            <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					              <Space
 | 
				
			||||||
 | 
					                direction="vertical"
 | 
				
			||||||
 | 
					                size="middle"
 | 
				
			||||||
 | 
					                style={{ display: "flex" }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <Tabs
 | 
				
			||||||
 | 
					                  defaultActiveKey="1"
 | 
				
			||||||
 | 
					                  activeKey={activeTab}
 | 
				
			||||||
 | 
					                  onChange={(key) => setActiveTab(key)}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <TabPane
 | 
				
			||||||
 | 
					                    tab={
 | 
				
			||||||
 | 
					                      <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					                        <img
 | 
				
			||||||
 | 
					                          style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                          src={activeTab === "1" ? infoIconActive : infoIcon}
 | 
				
			||||||
 | 
					                          alt=""
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                        Information
 | 
				
			||||||
 | 
					                      </span>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    key="1"
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <Space
 | 
				
			||||||
 | 
					                      direction="vertical"
 | 
				
			||||||
 | 
					                      size="middle"
 | 
				
			||||||
 | 
					                      style={{ display: "flex" }}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <Form
 | 
				
			||||||
 | 
					                        name="basic"
 | 
				
			||||||
 | 
					                        layout="vertical"
 | 
				
			||||||
 | 
					                        wrapperCol={{ span: 16 }}
 | 
				
			||||||
 | 
					                        initialValues={{ ...data }}
 | 
				
			||||||
 | 
					                        onFinish={onSubmit}
 | 
				
			||||||
 | 
					                        autoComplete="off"
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        <Row gutter={[16, 10]}>
 | 
				
			||||||
 | 
					                          {companyData?.data && (
 | 
				
			||||||
 | 
					                            <Col span={6}>
 | 
				
			||||||
 | 
					                              <Form.Item 
 | 
				
			||||||
 | 
					                                wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                                label="Company"
 | 
				
			||||||
 | 
					                              >
 | 
				
			||||||
 | 
					                                <Input
 | 
				
			||||||
 | 
					                                  defaultValue={companyData?.data?.name}
 | 
				
			||||||
 | 
					                                  readOnly
 | 
				
			||||||
 | 
					                                />
 | 
				
			||||||
 | 
					                              </Form.Item>
 | 
				
			||||||
 | 
					                            </Col>
 | 
				
			||||||
 | 
					                          )}
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="Name"
 | 
				
			||||||
 | 
					                              name="name"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Input />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                        </Row>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        <Form.Item>
 | 
				
			||||||
 | 
					                          {role === "Owner" && (
 | 
				
			||||||
 | 
					                            <Button
 | 
				
			||||||
 | 
					                              onClick={() => ClickDelete()}
 | 
				
			||||||
 | 
					                              type="primary"
 | 
				
			||||||
 | 
					                              style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                              danger
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              Delete
 | 
				
			||||||
 | 
					                            </Button>
 | 
				
			||||||
 | 
					                          )}
 | 
				
			||||||
 | 
					                          <Button type="primary" htmlType="submit">
 | 
				
			||||||
 | 
					                            Submit
 | 
				
			||||||
 | 
					                          </Button>
 | 
				
			||||||
 | 
					                        </Form.Item>
 | 
				
			||||||
 | 
					                      </Form>
 | 
				
			||||||
 | 
					                    </Space>
 | 
				
			||||||
 | 
					                  </TabPane>
 | 
				
			||||||
 | 
					                </Tabs>
 | 
				
			||||||
 | 
					              </Space>
 | 
				
			||||||
 | 
					            </Spin>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            <Notfound />
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        </Watermark>
 | 
				
			||||||
 | 
					      </Spin>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default CustomerEdit;
 | 
				
			||||||
@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					import { Table } from "antd";
 | 
				
			||||||
 | 
					import { useCompanyData } from "../../Hooks/Companies";
 | 
				
			||||||
 | 
					import { TCustomer } from "../../types/Customer/TCustomer";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function CustomerTable({
 | 
				
			||||||
 | 
					  data,
 | 
				
			||||||
 | 
					  isLoading,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  data?: TCustomer[] | undefined;
 | 
				
			||||||
 | 
					  isLoading?: boolean;
 | 
				
			||||||
 | 
					}) {
 | 
				
			||||||
 | 
					  const CompanyData = useCompanyData({
 | 
				
			||||||
 | 
					    name: undefined,
 | 
				
			||||||
 | 
					    page: undefined,
 | 
				
			||||||
 | 
					    is_active: undefined,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  type RowProps = {
 | 
				
			||||||
 | 
					    id: number;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Row = (record: RowProps) => {
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      onClick: () => {
 | 
				
			||||||
 | 
					        role !== "Checker" &&
 | 
				
			||||||
 | 
					          document.location.replace(`/#/customers/${record.id}`);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Table
 | 
				
			||||||
 | 
					        onRow={(record) => Row(record)}
 | 
				
			||||||
 | 
					        loading={isLoading}
 | 
				
			||||||
 | 
					        dataSource={data?.map((u, i) => ({
 | 
				
			||||||
 | 
					          ...u,
 | 
				
			||||||
 | 
					          no: i + 1,
 | 
				
			||||||
 | 
					          company_id:
 | 
				
			||||||
 | 
					            CompanyData?.data?.find(
 | 
				
			||||||
 | 
					              (company: any) => company.id === u?.company_id
 | 
				
			||||||
 | 
					            )?.name || "",
 | 
				
			||||||
 | 
					        }))}
 | 
				
			||||||
 | 
					        columns={[
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					            dataIndex: "no",
 | 
				
			||||||
 | 
					            width: "5%",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Name",
 | 
				
			||||||
 | 
					            dataIndex: "name",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Company",
 | 
				
			||||||
 | 
					            dataIndex: "company_id",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ]}
 | 
				
			||||||
 | 
					        rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					          index % 2 === 0 ? "odd-row" : "even-row"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default CustomerTable;
 | 
				
			||||||
@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					import { Form as FormAnt, Input, Button } from "antd";
 | 
				
			||||||
 | 
					import { prof } from "../../API/LayoutApi/profile";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ChangePassword = () => {
 | 
				
			||||||
 | 
					  const [form] = FormAnt.useForm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const submit = () => {
 | 
				
			||||||
 | 
					    form.validateFields().then(async (values) => {
 | 
				
			||||||
 | 
					      form.resetFields();
 | 
				
			||||||
 | 
					      console.log(values);
 | 
				
			||||||
 | 
					      await prof.changePass(values);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div style={{ width: 500 }}>
 | 
				
			||||||
 | 
					      <FormAnt
 | 
				
			||||||
 | 
					        form={form}
 | 
				
			||||||
 | 
					        layout="horizontal"
 | 
				
			||||||
 | 
					        name="form_in_modal"
 | 
				
			||||||
 | 
					        initialValues={{ modifier: "public" }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <FormAnt.Item
 | 
				
			||||||
 | 
					          label="Old Password"
 | 
				
			||||||
 | 
					          name="old_password"
 | 
				
			||||||
 | 
					          rules={[{ required: true, message: "Your old password!" }]}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <Input.Password />
 | 
				
			||||||
 | 
					        </FormAnt.Item>
 | 
				
			||||||
 | 
					        <FormAnt.Item
 | 
				
			||||||
 | 
					          name="new_password"
 | 
				
			||||||
 | 
					          label="New Password"
 | 
				
			||||||
 | 
					          rules={[
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              required: true,
 | 
				
			||||||
 | 
					              message: "Please input your password!",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              min: 8,
 | 
				
			||||||
 | 
					              message: "Password must be at least 8 characters long!",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          ]}
 | 
				
			||||||
 | 
					          hasFeedback
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <Input.Password />
 | 
				
			||||||
 | 
					        </FormAnt.Item>
 | 
				
			||||||
 | 
					        <FormAnt.Item
 | 
				
			||||||
 | 
					          name="password_confirm"
 | 
				
			||||||
 | 
					          label="Confirm Password"
 | 
				
			||||||
 | 
					          dependencies={["new_password"]}
 | 
				
			||||||
 | 
					          hasFeedback
 | 
				
			||||||
 | 
					          rules={[
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					              required: true,
 | 
				
			||||||
 | 
					              message: "Please confirm your password!",
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            ({ getFieldValue }) => ({
 | 
				
			||||||
 | 
					              validator(_, value) {
 | 
				
			||||||
 | 
					                if (!value || getFieldValue("new_password") === value) {
 | 
				
			||||||
 | 
					                  return Promise.resolve();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return Promise.reject(
 | 
				
			||||||
 | 
					                  new Error("The new password that you entered do not match!")
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            }),
 | 
				
			||||||
 | 
					          ]}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <Input.Password />
 | 
				
			||||||
 | 
					        </FormAnt.Item>
 | 
				
			||||||
 | 
					      </FormAnt>
 | 
				
			||||||
 | 
					      <Button onClick={submit} type="primary">
 | 
				
			||||||
 | 
					        save
 | 
				
			||||||
 | 
					      </Button>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ChangePassword;
 | 
				
			||||||
@ -0,0 +1,271 @@
 | 
				
			|||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import { TProfilePutParams, prof } from "../../API/LayoutApi/profile";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Button,
 | 
				
			||||||
 | 
					  Col,
 | 
				
			||||||
 | 
					  DatePicker,
 | 
				
			||||||
 | 
					  Form,
 | 
				
			||||||
 | 
					  Input,
 | 
				
			||||||
 | 
					  Row,
 | 
				
			||||||
 | 
					  Select,
 | 
				
			||||||
 | 
					  Space,
 | 
				
			||||||
 | 
					  Spin,
 | 
				
			||||||
 | 
					  Table,
 | 
				
			||||||
 | 
					  Tabs,
 | 
				
			||||||
 | 
					  Watermark,
 | 
				
			||||||
 | 
					} from "antd";
 | 
				
			||||||
 | 
					import TabPane from "antd/es/tabs/TabPane";
 | 
				
			||||||
 | 
					import { Link } from "react-router-dom";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  useMyHistoryData,
 | 
				
			||||||
 | 
					  useMystatsData,
 | 
				
			||||||
 | 
					  useProfData,
 | 
				
			||||||
 | 
					} from "../../Hooks/Profile";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					import ChangePassword from "./ChangePassword";
 | 
				
			||||||
 | 
					const { Option } = Select;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Profile = () => {
 | 
				
			||||||
 | 
					  const { data, refetch } = useProfData();
 | 
				
			||||||
 | 
					  const [range, setRange] = useState<any>(1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onSubmit = async (value: TProfilePutParams) => {
 | 
				
			||||||
 | 
					    await prof.profPatch(value);
 | 
				
			||||||
 | 
					    refetch();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const moment = require("moment-timezone");
 | 
				
			||||||
 | 
					  const nowUtcPlus5 = moment.tz("Asia/Tashkent");
 | 
				
			||||||
 | 
					  const formattedTimeMinusFiveSeconds = nowUtcPlus5
 | 
				
			||||||
 | 
					    .subtract(range, "days")
 | 
				
			||||||
 | 
					    .format("YYYY-MM-DDTHH:mm:ss");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const historyData = useMyHistoryData({
 | 
				
			||||||
 | 
					    start_date: formattedTimeMinusFiveSeconds,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { RangePicker } = DatePicker;
 | 
				
			||||||
 | 
					  const currentDate = moment();
 | 
				
			||||||
 | 
					  const start_date = `${currentDate.format("YYYY-MM")}-01 00:00:00`;
 | 
				
			||||||
 | 
					  const [startDate, setStartDate] = useState(start_date);
 | 
				
			||||||
 | 
					  const [endDate, setEndDate] = useState<string | undefined>(undefined);
 | 
				
			||||||
 | 
					  const datePick = (a: any, b: any) => {
 | 
				
			||||||
 | 
					    if (b[0] && b[1]) {
 | 
				
			||||||
 | 
					      setStartDate(`${b[0]} 00:00:00`);
 | 
				
			||||||
 | 
					      setEndDate(`${b[1]} 23:59:59`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { data: lineData } = useMystatsData({
 | 
				
			||||||
 | 
					    start_date: startDate,
 | 
				
			||||||
 | 
					    end_date: endDate,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					        <Watermark style={{ height: "100%" }}>
 | 
				
			||||||
 | 
					          <Space direction="vertical" size="middle" style={{ display: "flex" }}>
 | 
				
			||||||
 | 
					            <Tabs>
 | 
				
			||||||
 | 
					              <TabPane tab={<span>Information</span>} key="1">
 | 
				
			||||||
 | 
					                <Space
 | 
				
			||||||
 | 
					                  direction="vertical"
 | 
				
			||||||
 | 
					                  size="middle"
 | 
				
			||||||
 | 
					                  style={{ display: "flex" }}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  {data !== undefined && (
 | 
				
			||||||
 | 
					                    <Form
 | 
				
			||||||
 | 
					                      name="basic"
 | 
				
			||||||
 | 
					                      layout="vertical"
 | 
				
			||||||
 | 
					                      wrapperCol={{ span: 16 }}
 | 
				
			||||||
 | 
					                      initialValues={{ ...data }}
 | 
				
			||||||
 | 
					                      autoComplete="off"
 | 
				
			||||||
 | 
					                      onFinish={onSubmit}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <Row gutter={[16, 10]}>
 | 
				
			||||||
 | 
					                        <Col span={6}>
 | 
				
			||||||
 | 
					                          <Form.Item
 | 
				
			||||||
 | 
					                            wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                            label="First name"
 | 
				
			||||||
 | 
					                            name="first_name"
 | 
				
			||||||
 | 
					                          >
 | 
				
			||||||
 | 
					                            <Input />
 | 
				
			||||||
 | 
					                          </Form.Item>
 | 
				
			||||||
 | 
					                        </Col>
 | 
				
			||||||
 | 
					                        <Col span={6}>
 | 
				
			||||||
 | 
					                          <Form.Item
 | 
				
			||||||
 | 
					                            wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                            label="Last name"
 | 
				
			||||||
 | 
					                            name="last_name"
 | 
				
			||||||
 | 
					                          >
 | 
				
			||||||
 | 
					                            <Input />
 | 
				
			||||||
 | 
					                          </Form.Item>
 | 
				
			||||||
 | 
					                        </Col>
 | 
				
			||||||
 | 
					                        <Col span={6}>
 | 
				
			||||||
 | 
					                          <Form.Item
 | 
				
			||||||
 | 
					                            wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                            label="Username"
 | 
				
			||||||
 | 
					                            name="username"
 | 
				
			||||||
 | 
					                          >
 | 
				
			||||||
 | 
					                            <Input />
 | 
				
			||||||
 | 
					                          </Form.Item>
 | 
				
			||||||
 | 
					                        </Col>
 | 
				
			||||||
 | 
					                        <Col span={6}>
 | 
				
			||||||
 | 
					                          <Form.Item
 | 
				
			||||||
 | 
					                            wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                            label="E-mail"
 | 
				
			||||||
 | 
					                            name="email"
 | 
				
			||||||
 | 
					                          >
 | 
				
			||||||
 | 
					                            <Input />
 | 
				
			||||||
 | 
					                          </Form.Item>
 | 
				
			||||||
 | 
					                        </Col>
 | 
				
			||||||
 | 
					                      </Row>
 | 
				
			||||||
 | 
					                      <Form.Item>
 | 
				
			||||||
 | 
					                        <Button type="primary" htmlType="submit">
 | 
				
			||||||
 | 
					                          Submit
 | 
				
			||||||
 | 
					                        </Button>
 | 
				
			||||||
 | 
					                      </Form.Item>
 | 
				
			||||||
 | 
					                    </Form>
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					                  {data !== undefined && (
 | 
				
			||||||
 | 
					                    <Form
 | 
				
			||||||
 | 
					                      name="basic"
 | 
				
			||||||
 | 
					                      layout="vertical"
 | 
				
			||||||
 | 
					                      wrapperCol={{ span: 16 }}
 | 
				
			||||||
 | 
					                      initialValues={{ ...data }}
 | 
				
			||||||
 | 
					                      autoComplete="off"
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <Row gutter={[16, 10]}>
 | 
				
			||||||
 | 
					                        {data && data.team !== "" && (
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="Team"
 | 
				
			||||||
 | 
					                              name="team"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Input readOnly />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                        )}
 | 
				
			||||||
 | 
					                      </Row>
 | 
				
			||||||
 | 
					                    </Form>
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					                  <div className="">
 | 
				
			||||||
 | 
					                    <h2 style={{ marginBottom: 20 }}>Your Statistics</h2>
 | 
				
			||||||
 | 
					                    <div
 | 
				
			||||||
 | 
					                      style={{
 | 
				
			||||||
 | 
					                        display: "flex",
 | 
				
			||||||
 | 
					                        justifyContent: "flex-start",
 | 
				
			||||||
 | 
					                      }}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <RangePicker onCalendarChange={datePick} />
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                    <div
 | 
				
			||||||
 | 
					                      style={{
 | 
				
			||||||
 | 
					                        display: "flex",
 | 
				
			||||||
 | 
					                        width: "100%",
 | 
				
			||||||
 | 
					                        height: "70vh",
 | 
				
			||||||
 | 
					                      }}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <div
 | 
				
			||||||
 | 
					                        style={{
 | 
				
			||||||
 | 
					                          marginBottom: 50,
 | 
				
			||||||
 | 
					                          marginTop: 20,
 | 
				
			||||||
 | 
					                          marginLeft: 30,
 | 
				
			||||||
 | 
					                          width: "80%",
 | 
				
			||||||
 | 
					                          display: "flex",
 | 
				
			||||||
 | 
					                          justifyContent: "space-between",
 | 
				
			||||||
 | 
					                        }}
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        <p className="card_stat">
 | 
				
			||||||
 | 
					                          Average:{" "}
 | 
				
			||||||
 | 
					                          <span>{lineData?.avg_stats_for_period} </span>
 | 
				
			||||||
 | 
					                          {role === "Owner" ? "tasks" : "pts"}/day
 | 
				
			||||||
 | 
					                        </p>
 | 
				
			||||||
 | 
					                        <p className="card_stat">
 | 
				
			||||||
 | 
					                          Total: <span>{lineData?.total_for_period} </span>
 | 
				
			||||||
 | 
					                          {role === "Owner" ? "tasks" : "pts"}
 | 
				
			||||||
 | 
					                        </p>
 | 
				
			||||||
 | 
					                        <p className="card_stat">
 | 
				
			||||||
 | 
					                          Contribution: <span>{lineData?.contribution}</span>%
 | 
				
			||||||
 | 
					                        </p>
 | 
				
			||||||
 | 
					                      </div>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                  </div>
 | 
				
			||||||
 | 
					                </Space>
 | 
				
			||||||
 | 
					              </TabPane>
 | 
				
			||||||
 | 
					              <TabPane tab={<span>History</span>} key="2">
 | 
				
			||||||
 | 
					                <Select
 | 
				
			||||||
 | 
					                  style={{ width: "20%", marginBottom: 10 }}
 | 
				
			||||||
 | 
					                  placeholder="1 day"
 | 
				
			||||||
 | 
					                  onChange={(value: any) =>
 | 
				
			||||||
 | 
					                    value ? setRange(value) : setRange("1")
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  allowClear
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <Option value="3">3 days</Option>
 | 
				
			||||||
 | 
					                  <Option value="7">a week</Option>
 | 
				
			||||||
 | 
					                  <Option value="30">a month</Option>
 | 
				
			||||||
 | 
					                </Select>
 | 
				
			||||||
 | 
					                <Table
 | 
				
			||||||
 | 
					                  dataSource={historyData?.data?.map((u, i) => ({
 | 
				
			||||||
 | 
					                    no: i + 1,
 | 
				
			||||||
 | 
					                    task: { id: u.task },
 | 
				
			||||||
 | 
					                    action: u?.action,
 | 
				
			||||||
 | 
					                    description:
 | 
				
			||||||
 | 
					                      role !== "Owner"
 | 
				
			||||||
 | 
					                        ? "You finished this task and earned another 5 points!"
 | 
				
			||||||
 | 
					                        : `You ${u?.description.slice(
 | 
				
			||||||
 | 
					                            u?.description.indexOf(" ") + 1
 | 
				
			||||||
 | 
					                          )}`,
 | 
				
			||||||
 | 
					                    timestamp: u.timestamp
 | 
				
			||||||
 | 
					                      ? moment(u.timestamp).format("DD.MM.YYYY, HH:mm")
 | 
				
			||||||
 | 
					                      : "",
 | 
				
			||||||
 | 
					                    key: u.id,
 | 
				
			||||||
 | 
					                  }))}
 | 
				
			||||||
 | 
					                  columns={[
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      title: <img alt="" src={tagIcon} />,
 | 
				
			||||||
 | 
					                      dataIndex: "no",
 | 
				
			||||||
 | 
					                      key: "no",
 | 
				
			||||||
 | 
					                      width: "5%",
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      title: "Task",
 | 
				
			||||||
 | 
					                      dataIndex: "task",
 | 
				
			||||||
 | 
					                      key: "task",
 | 
				
			||||||
 | 
					                      render: ({ id }: { id: number }) => (
 | 
				
			||||||
 | 
					                        <Link to={`/${id}`}>{id}</Link>
 | 
				
			||||||
 | 
					                      ),
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      title: "Action",
 | 
				
			||||||
 | 
					                      dataIndex: "action",
 | 
				
			||||||
 | 
					                      key: "action",
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      title: "Description",
 | 
				
			||||||
 | 
					                      dataIndex: "description",
 | 
				
			||||||
 | 
					                      key: "description",
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    {
 | 
				
			||||||
 | 
					                      title: "Timestamp",
 | 
				
			||||||
 | 
					                      dataIndex: "timestamp",
 | 
				
			||||||
 | 
					                      key: "timestamp",
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  ]}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </TabPane>
 | 
				
			||||||
 | 
					              <TabPane tab={<span>Change Password</span>} key="3">
 | 
				
			||||||
 | 
					                <ChangePassword />
 | 
				
			||||||
 | 
					              </TabPane>
 | 
				
			||||||
 | 
					            </Tabs>
 | 
				
			||||||
 | 
					          </Space>
 | 
				
			||||||
 | 
					        </Watermark>
 | 
				
			||||||
 | 
					      </Spin>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Profile;
 | 
				
			||||||
@ -0,0 +1,79 @@
 | 
				
			|||||||
 | 
					import { useRef, useState } from "react";
 | 
				
			||||||
 | 
					import { useRequestsData } from "../../Hooks/Requests";
 | 
				
			||||||
 | 
					import RequestsTable from "./RequestsTable";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import IconSearch from "../../assets/searchIcon.png";
 | 
				
			||||||
 | 
					import { Radio, RadioChangeEvent } from "antd";
 | 
				
			||||||
 | 
					import RequestsEdit from "./RequestsEdit";
 | 
				
			||||||
 | 
					import { TRequests } from "../../types/Requests/TRequests";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Requests = () => {
 | 
				
			||||||
 | 
					  const [search, setSearch] = useState("");
 | 
				
			||||||
 | 
					  const [status, setStatus] = useState("Pending");
 | 
				
			||||||
 | 
					  const [modalOpen, setModalOpen] = useState(false);
 | 
				
			||||||
 | 
					  const [requestData, setRequestData] = useState<TRequests>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { data, refetch, isLoading } = useRequestsData({
 | 
				
			||||||
 | 
					    search: search,
 | 
				
			||||||
 | 
					    status: status,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const timerRef = useRef<NodeJS.Timeout | null>(null);
 | 
				
			||||||
 | 
					  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
 | 
				
			||||||
 | 
					    if (timerRef.current) {
 | 
				
			||||||
 | 
					      clearTimeout(timerRef.current);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const searchText = e.target.value;
 | 
				
			||||||
 | 
					    timerRef.current = setTimeout(() => {
 | 
				
			||||||
 | 
					      setSearch(searchText);
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const theme = localStorage.getItem("theme") === "true" ? true : false;
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      {modalOpen && (
 | 
				
			||||||
 | 
					        <RequestsEdit
 | 
				
			||||||
 | 
					          modalOpen={modalOpen}
 | 
				
			||||||
 | 
					          setModalOpen={setModalOpen}
 | 
				
			||||||
 | 
					          requestData={requestData}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      <div className="header d-flex">
 | 
				
			||||||
 | 
					        <p className="title">Requests</p>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className="filter d-flex">
 | 
				
			||||||
 | 
					        <div className="search-div">
 | 
				
			||||||
 | 
					          <img src={IconSearch} alt="" />
 | 
				
			||||||
 | 
					          <input
 | 
				
			||||||
 | 
					            className={`search-input-${theme}`}
 | 
				
			||||||
 | 
					            type="text"
 | 
				
			||||||
 | 
					            placeholder="Search"
 | 
				
			||||||
 | 
					            onChange={handleSearchChange}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <Radio.Group
 | 
				
			||||||
 | 
					          onChange={(e: RadioChangeEvent) => setStatus(e.target.value)}
 | 
				
			||||||
 | 
					          size="middle"
 | 
				
			||||||
 | 
					          value={status}
 | 
				
			||||||
 | 
					          style={{ marginLeft: 20 }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <Radio.Button value={"Pending"}>Pending</Radio.Button>
 | 
				
			||||||
 | 
					          <Radio.Button value={"Assigned"}>Assigned</Radio.Button>
 | 
				
			||||||
 | 
					          <Radio.Button value={"Rejected"}>Rejected</Radio.Button>
 | 
				
			||||||
 | 
					          <Radio.Button value={undefined}>All</Radio.Button>
 | 
				
			||||||
 | 
					        </Radio.Group>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <RequestsTable
 | 
				
			||||||
 | 
					        data={data}
 | 
				
			||||||
 | 
					        isLoading={isLoading}
 | 
				
			||||||
 | 
					        refetch={refetch}
 | 
				
			||||||
 | 
					        setOpenModal={setModalOpen}
 | 
				
			||||||
 | 
					        setRequestData={setRequestData}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Requests;
 | 
				
			||||||
@ -0,0 +1,172 @@
 | 
				
			|||||||
 | 
					import { Modal, Select, Button } from "antd";
 | 
				
			||||||
 | 
					import { TRequests } from "../../types/Requests/TRequests";
 | 
				
			||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import { useCustomerData } from "../../Hooks/Customers";
 | 
				
			||||||
 | 
					import { requestsController } from "../../API/LayoutApi/requests";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import plus from "../../assets/add-icon.png";
 | 
				
			||||||
 | 
					const RequestsEdit = ({
 | 
				
			||||||
 | 
					  modalOpen,
 | 
				
			||||||
 | 
					  setModalOpen,
 | 
				
			||||||
 | 
					  requestData,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  modalOpen: any;
 | 
				
			||||||
 | 
					  setModalOpen: any;
 | 
				
			||||||
 | 
					  requestData: TRequests | undefined;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const theme = localStorage.getItem("theme") === "true" ? true : false;
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setModalOpen(!modalOpen);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [customerName, setCustomerName] = useState<string>();
 | 
				
			||||||
 | 
					  const [driverId, setDriverId] = useState<number>();
 | 
				
			||||||
 | 
					  const customerData = useCustomerData({
 | 
				
			||||||
 | 
					    name: customerName,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const assignClick = () => {
 | 
				
			||||||
 | 
					    const value = {
 | 
				
			||||||
 | 
					      ...requestData,
 | 
				
			||||||
 | 
					      status: "Assigned",
 | 
				
			||||||
 | 
					      customer_id: driverId,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    requestsController.requestPatch(value, requestData?.id);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Modal
 | 
				
			||||||
 | 
					        onCancel={handleCancel}
 | 
				
			||||||
 | 
					        footer={null}
 | 
				
			||||||
 | 
					        open={modalOpen}
 | 
				
			||||||
 | 
					        width={800}
 | 
				
			||||||
 | 
					        maskClosable={true}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <div className="info-div">
 | 
				
			||||||
 | 
					          <div
 | 
				
			||||||
 | 
					            className="d-flex"
 | 
				
			||||||
 | 
					            style={{ alignItems: "center", marginBottom: 16 }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <p
 | 
				
			||||||
 | 
					              style={{
 | 
				
			||||||
 | 
					                fontSize: 18,
 | 
				
			||||||
 | 
					                fontWeight: 700,
 | 
				
			||||||
 | 
					                lineHeight: "24px",
 | 
				
			||||||
 | 
					                letterSpacing: "-0.02em",
 | 
				
			||||||
 | 
					              }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              Requested Driver Info
 | 
				
			||||||
 | 
					            </p>
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              style={{ marginLeft: 12, display: "flex", alignItems: "center" }}
 | 
				
			||||||
 | 
					              className={`status-${requestData?.status}`}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              {requestData?.status}
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div className="info-body">
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					              <p className={!theme ? "sub" : "sub-dark"}>Full Name</p>
 | 
				
			||||||
 | 
					              <p className={!theme ? "info" : "info-dark"}>
 | 
				
			||||||
 | 
					                {requestData?.full_name}
 | 
				
			||||||
 | 
					              </p>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					              <p className={!theme ? "sub" : "sub-dark"}>Company</p>
 | 
				
			||||||
 | 
					              <p className={!theme ? "info" : "info-dark"}>
 | 
				
			||||||
 | 
					                {requestData?.company_name}
 | 
				
			||||||
 | 
					              </p>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					              <p className={!theme ? "sub" : "sub-dark"}>USDOT</p>
 | 
				
			||||||
 | 
					              <p className={!theme ? "info" : "info-dark"}>
 | 
				
			||||||
 | 
					                {requestData?.company_usdot}
 | 
				
			||||||
 | 
					              </p>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          {requestData?.status === "Assigned" && (
 | 
				
			||||||
 | 
					            <div className="info-div" style={{ margin: 0 }}>
 | 
				
			||||||
 | 
					              <div
 | 
				
			||||||
 | 
					                className="d-flex"
 | 
				
			||||||
 | 
					                style={{ alignItems: "center", marginBottom: 16 }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <p
 | 
				
			||||||
 | 
					                  style={{
 | 
				
			||||||
 | 
					                    fontSize: 18,
 | 
				
			||||||
 | 
					                    fontWeight: 700,
 | 
				
			||||||
 | 
					                    lineHeight: "24px",
 | 
				
			||||||
 | 
					                    marginTop: 20,
 | 
				
			||||||
 | 
					                    letterSpacing: "-0.02em",
 | 
				
			||||||
 | 
					                  }}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  Assigned Driver Info
 | 
				
			||||||
 | 
					                </p>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <div className="info-body">
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "sub" : "sub-dark"}>Driver name</p>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "info" : "info-dark"}>
 | 
				
			||||||
 | 
					                    {requestData?.potential_driver?.name}
 | 
				
			||||||
 | 
					                  </p>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "sub" : "sub-dark"}>Company</p>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "info" : "info-dark"}>
 | 
				
			||||||
 | 
					                    {requestData?.potential_driver?.company?.name}
 | 
				
			||||||
 | 
					                  </p>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <div />
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					          {requestData?.status === "Pending" && (
 | 
				
			||||||
 | 
					            <div className="search-driver">
 | 
				
			||||||
 | 
					              <div className="d-flex">
 | 
				
			||||||
 | 
					                <Select
 | 
				
			||||||
 | 
					                  showSearch
 | 
				
			||||||
 | 
					                  style={{ width: 325 }}
 | 
				
			||||||
 | 
					                  placeholder="Search Driver"
 | 
				
			||||||
 | 
					                  onSearch={(value: any) => setCustomerName(value)}
 | 
				
			||||||
 | 
					                  onChange={(e: any) => setDriverId(e)}
 | 
				
			||||||
 | 
					                  options={customerData?.data?.map((item) => ({
 | 
				
			||||||
 | 
					                    label: item?.name,
 | 
				
			||||||
 | 
					                    value: item?.id,
 | 
				
			||||||
 | 
					                  }))}
 | 
				
			||||||
 | 
					                  value={customerName}
 | 
				
			||||||
 | 
					                  filterOption={false}
 | 
				
			||||||
 | 
					                  autoClearSearchValue={false}
 | 
				
			||||||
 | 
					                  allowClear
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					                <Button
 | 
				
			||||||
 | 
					                  type="primary"
 | 
				
			||||||
 | 
					                  onClick={assignClick}
 | 
				
			||||||
 | 
					                  disabled={driverId ? false : true}
 | 
				
			||||||
 | 
					                  style={{ marginLeft: 15 }}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  Assign
 | 
				
			||||||
 | 
					                </Button>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <Button
 | 
				
			||||||
 | 
					                onClick={assignClick}
 | 
				
			||||||
 | 
					                disabled={driverId ? true : false}
 | 
				
			||||||
 | 
					                style={{
 | 
				
			||||||
 | 
					                  display: "flex",
 | 
				
			||||||
 | 
					                  alignItems: "center",
 | 
				
			||||||
 | 
					                  padding: "6px 15px",
 | 
				
			||||||
 | 
					                  margin: 0,
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					                className="btn-add"
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <img src={plus} alt="" style={{ marginRight: 8 }} />
 | 
				
			||||||
 | 
					                Add new driver
 | 
				
			||||||
 | 
					              </Button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </Modal>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default RequestsEdit;
 | 
				
			||||||
@ -0,0 +1,143 @@
 | 
				
			|||||||
 | 
					import { Button, Space, Table } from "antd";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					import moment from "moment";
 | 
				
			||||||
 | 
					import { TRequests } from "../../types/Requests/TRequests";
 | 
				
			||||||
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
 | 
					import { requestsController } from "../../API/LayoutApi/requests";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const RequestsTable = ({
 | 
				
			||||||
 | 
					  data,
 | 
				
			||||||
 | 
					  isLoading,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					  setOpenModal,
 | 
				
			||||||
 | 
					  setRequestData,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  setOpenModal: React.Dispatch<React.SetStateAction<boolean>>;
 | 
				
			||||||
 | 
					  setRequestData: React.Dispatch<React.SetStateAction<TRequests | undefined>>;
 | 
				
			||||||
 | 
					  data: TRequests[] | undefined;
 | 
				
			||||||
 | 
					  isLoading: boolean;
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TRequests[], unknown>>;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const [isTextSelected, setIsTextSelected] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    const handleSelectionChange = () => {
 | 
				
			||||||
 | 
					      const selection = window.getSelection();
 | 
				
			||||||
 | 
					      setIsTextSelected(selection !== null && selection.toString() !== "");
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    document.addEventListener("selectionchange", handleSelectionChange);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return () => {
 | 
				
			||||||
 | 
					      document.removeEventListener("selectionchange", handleSelectionChange);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Row = (record: TRequests, event: any) => {
 | 
				
			||||||
 | 
					    if (isTextSelected) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      event.target.classList.contains("ant-table-cell") &&
 | 
				
			||||||
 | 
					      record.status !== "Rejected"
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      setRequestData(record);
 | 
				
			||||||
 | 
					      setOpenModal(true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const patchRequest = (record: TRequests) => {
 | 
				
			||||||
 | 
					    requestsController.delete(record?.id).then(() => {
 | 
				
			||||||
 | 
					      refetch();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Table
 | 
				
			||||||
 | 
					        onRow={(record) => ({
 | 
				
			||||||
 | 
					          onClick: (event) => Row(record, event),
 | 
				
			||||||
 | 
					        })}
 | 
				
			||||||
 | 
					        dataSource={data?.map((u, i) => ({
 | 
				
			||||||
 | 
					          no: i + 1,
 | 
				
			||||||
 | 
					          action: { id: u.id },
 | 
				
			||||||
 | 
					          created: moment(u?.created_at, "YYYY-MM-DD HH:mm:ss").format(
 | 
				
			||||||
 | 
					            "DD.MM.YYYY HH:mm"
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          ...u,
 | 
				
			||||||
 | 
					        }))}
 | 
				
			||||||
 | 
					        loading={isLoading}
 | 
				
			||||||
 | 
					        size="middle"
 | 
				
			||||||
 | 
					        columns={[
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					            dataIndex: "no",
 | 
				
			||||||
 | 
					            width: "5%",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Full name",
 | 
				
			||||||
 | 
					            dataIndex: "full_name",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Company",
 | 
				
			||||||
 | 
					            dataIndex: "company_name",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "USDOT",
 | 
				
			||||||
 | 
					            dataIndex: "company_usdot",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Created at",
 | 
				
			||||||
 | 
					            dataIndex: "created",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Actions",
 | 
				
			||||||
 | 
					            dataIndex: "action",
 | 
				
			||||||
 | 
					            render: (text: string, record: TRequests) => {
 | 
				
			||||||
 | 
					              return (
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                  {record?.status === "Pending" && (
 | 
				
			||||||
 | 
					                    <Space>
 | 
				
			||||||
 | 
					                      <Button
 | 
				
			||||||
 | 
					                        type="primary"
 | 
				
			||||||
 | 
					                        onClick={() => patchRequest(record)}
 | 
				
			||||||
 | 
					                        danger
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        Reject
 | 
				
			||||||
 | 
					                      </Button>
 | 
				
			||||||
 | 
					                    </Space>
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              );
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ]}
 | 
				
			||||||
 | 
					        rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					          index % 2 === 0 ? "odd-row" : "even-row"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default RequestsTable;
 | 
				
			||||||
@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					import { Input, Modal, Form as FormAnt } from "antd";
 | 
				
			||||||
 | 
					import { serviceController } from "../../API/LayoutApi/services";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AddService = ({  
 | 
				
			||||||
 | 
					  open,
 | 
				
			||||||
 | 
					  setOpen,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  open: boolean;
 | 
				
			||||||
 | 
					  setOpen(open: boolean): void;
 | 
				
			||||||
 | 
					  refetch(): void;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const [form] = FormAnt.useForm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setOpen(!open);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Modal
 | 
				
			||||||
 | 
					        open={open}
 | 
				
			||||||
 | 
					        title="Add service"
 | 
				
			||||||
 | 
					        okText="Create"
 | 
				
			||||||
 | 
					        cancelText="Cancel"
 | 
				
			||||||
 | 
					        onCancel={handleCancel}
 | 
				
			||||||
 | 
					        onOk={() => {
 | 
				
			||||||
 | 
					          form
 | 
				
			||||||
 | 
					            .validateFields()
 | 
				
			||||||
 | 
					            .then(async (values) => {
 | 
				
			||||||
 | 
					              form.resetFields();
 | 
				
			||||||
 | 
					              await serviceController.addServiceController(values);
 | 
				
			||||||
 | 
					              setOpen(!open);
 | 
				
			||||||
 | 
					              refetch();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					              refetch();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <FormAnt
 | 
				
			||||||
 | 
					          form={form}
 | 
				
			||||||
 | 
					          layout="horizontal"
 | 
				
			||||||
 | 
					          name="form_in_modal"
 | 
				
			||||||
 | 
					          initialValues={{ modifier: "public" }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Title"
 | 
				
			||||||
 | 
					            name="title"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: true, message: "Please input service title!" },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Input />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Points"
 | 
				
			||||||
 | 
					            name="points"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: true, message: "Please input service points!" },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Input />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					        </FormAnt>
 | 
				
			||||||
 | 
					      </Modal>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default AddService;
 | 
				
			||||||
@ -0,0 +1,146 @@
 | 
				
			|||||||
 | 
					import { useParams } from "react-router-dom";
 | 
				
			||||||
 | 
					import { useServiceOne } from "../../Hooks/Services";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Form,
 | 
				
			||||||
 | 
					  Spin,
 | 
				
			||||||
 | 
					  Watermark,
 | 
				
			||||||
 | 
					  Space,
 | 
				
			||||||
 | 
					  Tabs,
 | 
				
			||||||
 | 
					  Row,
 | 
				
			||||||
 | 
					  Col,
 | 
				
			||||||
 | 
					  Input,
 | 
				
			||||||
 | 
					  Button,
 | 
				
			||||||
 | 
					} from "antd";
 | 
				
			||||||
 | 
					import { serviceController } from "../../API/LayoutApi/services";
 | 
				
			||||||
 | 
					import { FormOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					import Notfound from "../../Utils/Notfound";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIcon from "../../assets/infoIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIconActive from "../../assets/infoIconActive.png";
 | 
				
			||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TabPane = Tabs.TabPane;
 | 
				
			||||||
 | 
					type params = {
 | 
				
			||||||
 | 
					  readonly id: any;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					type MyObjectType = {
 | 
				
			||||||
 | 
					  [key: string | number]: any;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const ServiceEdit = () => {
 | 
				
			||||||
 | 
					  const { id } = useParams<params>();
 | 
				
			||||||
 | 
					  const { data, refetch, status }: MyObjectType = useServiceOne(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onSubmit = async (value: any) => {
 | 
				
			||||||
 | 
					    await serviceController.servicePatch(value, id);
 | 
				
			||||||
 | 
					    refetch();
 | 
				
			||||||
 | 
					    document.location.replace("/#/services");
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const ClickDelete = () => {
 | 
				
			||||||
 | 
					    const shouldDelete = window.confirm(
 | 
				
			||||||
 | 
					      "Вы уверены, что хотите удалить эту сервис?"
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    if (shouldDelete && id !== undefined) {
 | 
				
			||||||
 | 
					      serviceController.deleteServiceController(id).then((data: any) => {
 | 
				
			||||||
 | 
					        document.location.replace(`/#/services`);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [activeTab, setActiveTab] = useState("1");
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					        <Watermark style={{ height: "100%" }}>
 | 
				
			||||||
 | 
					          {status === "loading" ? (
 | 
				
			||||||
 | 
					            <Spin size="large" spinning={!data} />
 | 
				
			||||||
 | 
					          ) : data ? (
 | 
				
			||||||
 | 
					            <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					              <Space
 | 
				
			||||||
 | 
					                direction="vertical"
 | 
				
			||||||
 | 
					                size="middle"
 | 
				
			||||||
 | 
					                style={{ display: "flex" }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <Tabs
 | 
				
			||||||
 | 
					                  defaultActiveKey="1"
 | 
				
			||||||
 | 
					                  activeKey={activeTab}
 | 
				
			||||||
 | 
					                  onChange={(key) => setActiveTab(key)}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <TabPane
 | 
				
			||||||
 | 
					                    tab={
 | 
				
			||||||
 | 
					                      <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					                        <img
 | 
				
			||||||
 | 
					                          style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                          src={activeTab === "1" ? infoIconActive : infoIcon}
 | 
				
			||||||
 | 
					                          alt=""
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                        Information
 | 
				
			||||||
 | 
					                      </span>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    key="1"
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <Space
 | 
				
			||||||
 | 
					                      direction="vertical"
 | 
				
			||||||
 | 
					                      size="middle"
 | 
				
			||||||
 | 
					                      style={{ display: "flex" }}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <Form
 | 
				
			||||||
 | 
					                        name="basic"
 | 
				
			||||||
 | 
					                        layout="vertical"
 | 
				
			||||||
 | 
					                        wrapperCol={{ span: 16 }}
 | 
				
			||||||
 | 
					                        initialValues={{ ...data }}
 | 
				
			||||||
 | 
					                        onFinish={onSubmit}
 | 
				
			||||||
 | 
					                        autoComplete="off"
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        <Row gutter={[16, 10]}>
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="title"
 | 
				
			||||||
 | 
					                              name="title"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Input />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="points"
 | 
				
			||||||
 | 
					                              name="points"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Input />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                        </Row>
 | 
				
			||||||
 | 
					                        <Form.Item>
 | 
				
			||||||
 | 
					                          {role !== "Checker" && (
 | 
				
			||||||
 | 
					                            <Button
 | 
				
			||||||
 | 
					                              onClick={() => ClickDelete()}
 | 
				
			||||||
 | 
					                              type="primary"
 | 
				
			||||||
 | 
					                              style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                              danger
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              Delete
 | 
				
			||||||
 | 
					                            </Button>
 | 
				
			||||||
 | 
					                          )}
 | 
				
			||||||
 | 
					                          <Button type="primary" htmlType="submit">
 | 
				
			||||||
 | 
					                            Submit
 | 
				
			||||||
 | 
					                          </Button>
 | 
				
			||||||
 | 
					                        </Form.Item>
 | 
				
			||||||
 | 
					                      </Form>
 | 
				
			||||||
 | 
					                    </Space>
 | 
				
			||||||
 | 
					                  </TabPane>
 | 
				
			||||||
 | 
					                </Tabs>
 | 
				
			||||||
 | 
					              </Space>
 | 
				
			||||||
 | 
					            </Spin>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            <Notfound />
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        </Watermark>
 | 
				
			||||||
 | 
					      </Spin>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ServiceEdit;
 | 
				
			||||||
@ -0,0 +1,80 @@
 | 
				
			|||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					import { Table } from "antd";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					import { TService } from "../../types/Service/TService";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					type numStr = string | number;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface serviceSource {
 | 
				
			||||||
 | 
					  no: numStr;
 | 
				
			||||||
 | 
					  title: numStr;
 | 
				
			||||||
 | 
					  points: numStr;
 | 
				
			||||||
 | 
					  id: numStr;
 | 
				
			||||||
 | 
					  action: { id: numStr };
 | 
				
			||||||
 | 
					  key: React.Key;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					const ServiceTable = ({
 | 
				
			||||||
 | 
					  data,
 | 
				
			||||||
 | 
					  isLoading,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  data: TService[] | undefined;
 | 
				
			||||||
 | 
					  isLoading: boolean | undefined;
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TService[], unknown>>;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const columns: object[] = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					      dataIndex: "no",
 | 
				
			||||||
 | 
					      width: "5%",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      title: "Title",
 | 
				
			||||||
 | 
					      dataIndex: "title",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      title: "Points",
 | 
				
			||||||
 | 
					      dataIndex: "points",
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Table
 | 
				
			||||||
 | 
					        loading={isLoading}
 | 
				
			||||||
 | 
					        onRow={(record) => {
 | 
				
			||||||
 | 
					          return {
 | 
				
			||||||
 | 
					            onClick: () => {
 | 
				
			||||||
 | 
					              role !== "Checker" &&
 | 
				
			||||||
 | 
					                document.location.replace(`/#/services/${record.id}`);
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        dataSource={data?.map((u: any, i: number): serviceSource => {
 | 
				
			||||||
 | 
					          const obj: serviceSource = {
 | 
				
			||||||
 | 
					            no: i + 1,
 | 
				
			||||||
 | 
					            title: u?.title,
 | 
				
			||||||
 | 
					            points: u?.points,
 | 
				
			||||||
 | 
					            id: u?.id,
 | 
				
			||||||
 | 
					            action: { id: u.id },
 | 
				
			||||||
 | 
					            key: u.id,
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          return obj;
 | 
				
			||||||
 | 
					        })}
 | 
				
			||||||
 | 
					        columns={columns}
 | 
				
			||||||
 | 
					        rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					          index % 2 === 0 ? "odd-row" : "even-row"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default ServiceTable;
 | 
				
			||||||
@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import { useServiceData } from "../../Hooks/Services";
 | 
				
			||||||
 | 
					import AddService from "./AddService";
 | 
				
			||||||
 | 
					import ServiceTable from "./ServiceTable";
 | 
				
			||||||
 | 
					//@ts-ignore
 | 
				
			||||||
 | 
					import addicon from "../../assets/addiconpng.png";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Service = () => {
 | 
				
			||||||
 | 
					  const { data, isLoading, refetch } = useServiceData();
 | 
				
			||||||
 | 
					  const [open, setOpen] = useState(false);
 | 
				
			||||||
 | 
					  const showModal = () => {
 | 
				
			||||||
 | 
					    setOpen(true);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      {open && <AddService refetch={refetch} open={open} setOpen={setOpen} />}
 | 
				
			||||||
 | 
					      <div className="header d-flex">
 | 
				
			||||||
 | 
					        <p className="title">Services</p>
 | 
				
			||||||
 | 
					        {role !== "Checker" && (
 | 
				
			||||||
 | 
					          <button onClick={showModal} className="btn-add d-flex">
 | 
				
			||||||
 | 
					            <img src={addicon} style={{ marginRight: 8 }} alt="" />
 | 
				
			||||||
 | 
					            Add
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <ServiceTable data={data} isLoading={isLoading} refetch={refetch} />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Service;
 | 
				
			||||||
@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					import { useRef, useState } from "react";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					import { statController } from "../../API/LayoutApi/statistic";
 | 
				
			||||||
 | 
					import { useTeamData } from "../../Hooks/Teams/index";
 | 
				
			||||||
 | 
					import { useStatTeamData, useStatsData } from "../../Hooks/Stats";
 | 
				
			||||||
 | 
					import { TStatTeam } from "../../types/Statistic/TStat";
 | 
				
			||||||
 | 
					import StatTable from "./StatisticTable";
 | 
				
			||||||
 | 
					import StatTeamTable from "./StatisticTeamTable";
 | 
				
			||||||
 | 
					import dayjs from "dayjs";
 | 
				
			||||||
 | 
					import { Button, DatePicker, DatePickerProps, Select, Tabs } from "antd";
 | 
				
			||||||
 | 
					import TabPane from "antd/es/tabs/TabPane";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import IconSearch from "../../assets/searchIcon.png";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Stat = () => {
 | 
				
			||||||
 | 
					  const now = dayjs();
 | 
				
			||||||
 | 
					  const { RangePicker } = DatePicker;
 | 
				
			||||||
 | 
					  const moment = require("moment");
 | 
				
			||||||
 | 
					  const currentDate = moment();
 | 
				
			||||||
 | 
					  const nextMonth = currentDate.clone().add(1, "months");
 | 
				
			||||||
 | 
					  const start_date = `${currentDate.format("YYYY-MM")}-01 00:00:00`;
 | 
				
			||||||
 | 
					  const end_date = `${nextMonth.format("YYYY-MM")}-01 00:00:00`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [search, setSearch] = useState<string>("");
 | 
				
			||||||
 | 
					  const [team, setTeam] = useState<any>("");
 | 
				
			||||||
 | 
					  const [startDate, setStartDate] = useState(start_date);
 | 
				
			||||||
 | 
					  const [endDate, setEndDate] = useState(end_date);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const teamData = useTeamData("");
 | 
				
			||||||
 | 
					  const teamOptions: { label: string; value: any }[] | undefined =
 | 
				
			||||||
 | 
					    teamData?.data?.map((item) => ({
 | 
				
			||||||
 | 
					      label: item?.name,
 | 
				
			||||||
 | 
					      value: item?.name,
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  const additionalOption = {
 | 
				
			||||||
 | 
					    label: "all",
 | 
				
			||||||
 | 
					    value: "",
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  if (teamOptions) {
 | 
				
			||||||
 | 
					    teamOptions.unshift(additionalOption);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleSave = (a: string) => {
 | 
				
			||||||
 | 
					    const trimmedStartDate = startDate.slice(0, 10);
 | 
				
			||||||
 | 
					    const trimmedEndDate = endDate.slice(0, 10);
 | 
				
			||||||
 | 
					    const fileName = `${trimmedStartDate}-${trimmedEndDate}`;
 | 
				
			||||||
 | 
					    if (a === "team") {
 | 
				
			||||||
 | 
					      const teamName = `${team}_${fileName}`;
 | 
				
			||||||
 | 
					      statController.saveUsersStats(teamName, startDate, endDate, team);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      statController.saveTeamStats(fileName, startDate, endDate);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const datePick = (a: any, b: any) => {
 | 
				
			||||||
 | 
					    if (b[0] && b[1]) {
 | 
				
			||||||
 | 
					      setStartDate(`${b[0]} 00:00:00`);
 | 
				
			||||||
 | 
					      setEndDate(`${b[1]} 23:59:59`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onChangeDate: DatePickerProps["onChange"] = (date) => {
 | 
				
			||||||
 | 
					    if (!date) {
 | 
				
			||||||
 | 
					      setStartDate("");
 | 
				
			||||||
 | 
					      setEndDate("");
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      const firstDate = date;
 | 
				
			||||||
 | 
					      const secondDate = date?.add(1, "month");
 | 
				
			||||||
 | 
					      const yearStart = Number(firstDate?.year());
 | 
				
			||||||
 | 
					      const monthStart = Number(firstDate?.month()) + 1;
 | 
				
			||||||
 | 
					      const yearEnd = Number(secondDate?.year());
 | 
				
			||||||
 | 
					      const monthEnd = Number(secondDate?.month()) + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      setStartDate(`${yearStart}-${monthStart}-01 00:00:00`);
 | 
				
			||||||
 | 
					      setEndDate(`${yearEnd}-${monthEnd}-01 00:00:00`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { data, refetch, isLoading } = useStatsData({
 | 
				
			||||||
 | 
					    search: search,
 | 
				
			||||||
 | 
					    team: team,
 | 
				
			||||||
 | 
					    start_date: startDate,
 | 
				
			||||||
 | 
					    end_date: endDate,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  interface DataType {
 | 
				
			||||||
 | 
					    data?: TStatTeam[];
 | 
				
			||||||
 | 
					    refetch: <TPageData>(
 | 
				
			||||||
 | 
					      options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					    ) => Promise<QueryObserverResult<TStatTeam[], unknown>>;
 | 
				
			||||||
 | 
					    isLoading: boolean;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const TeamData: DataType = useStatTeamData({
 | 
				
			||||||
 | 
					    search: "",
 | 
				
			||||||
 | 
					    start_date: startDate,
 | 
				
			||||||
 | 
					    end_date: endDate,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const timerRef = useRef<NodeJS.Timeout | null>(null);
 | 
				
			||||||
 | 
					  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
 | 
				
			||||||
 | 
					    if (timerRef.current) {
 | 
				
			||||||
 | 
					      clearTimeout(timerRef.current);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const searchText = e.target.value;
 | 
				
			||||||
 | 
					    timerRef.current = setTimeout(() => {
 | 
				
			||||||
 | 
					      setSearch(searchText);
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const theme = localStorage.getItem("theme") === "true" ? true : false;
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <div className="header d-flex" style={{ marginBottom: 16 }}>
 | 
				
			||||||
 | 
					        <p className="title">Statistics</p>
 | 
				
			||||||
 | 
					        <div className="">
 | 
				
			||||||
 | 
					          <DatePicker
 | 
				
			||||||
 | 
					            onChange={onChangeDate}
 | 
				
			||||||
 | 
					            picker="month"
 | 
				
			||||||
 | 
					            format={"MMMM"}
 | 
				
			||||||
 | 
					            defaultValue={now}
 | 
				
			||||||
 | 
					            style={{ marginRight: 10, width: 120 }}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <RangePicker style={{ width: 260 }} onCalendarChange={datePick} />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <Tabs defaultActiveKey="1">
 | 
				
			||||||
 | 
					        <TabPane tab={<span>Users</span>} key="1">
 | 
				
			||||||
 | 
					          <span
 | 
				
			||||||
 | 
					            style={{
 | 
				
			||||||
 | 
					              display: "flex",
 | 
				
			||||||
 | 
					              alignItems: "center",
 | 
				
			||||||
 | 
					              marginBottom: 10,
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <div className="search-div" style={{ marginRight: 12 }}>
 | 
				
			||||||
 | 
					              <img src={IconSearch} alt="" />
 | 
				
			||||||
 | 
					              <input
 | 
				
			||||||
 | 
					                className={`search-input-${theme}`}
 | 
				
			||||||
 | 
					                type="text"
 | 
				
			||||||
 | 
					                placeholder="Search"
 | 
				
			||||||
 | 
					                onChange={handleSearchChange}
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <Select
 | 
				
			||||||
 | 
					              style={{ width: 260 }}
 | 
				
			||||||
 | 
					              placeholder="team"
 | 
				
			||||||
 | 
					              onChange={(value: any) => setTeam(value)}
 | 
				
			||||||
 | 
					              options={teamOptions}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					          <StatTable
 | 
				
			||||||
 | 
					            data={{ data: data }}
 | 
				
			||||||
 | 
					            isLoading={isLoading}
 | 
				
			||||||
 | 
					            refetch={refetch}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <Button type="primary" onClick={(e) => handleSave("team")}>
 | 
				
			||||||
 | 
					            Save as file
 | 
				
			||||||
 | 
					          </Button>
 | 
				
			||||||
 | 
					        </TabPane>
 | 
				
			||||||
 | 
					        <TabPane tab={<span>Teams</span>} key="2">
 | 
				
			||||||
 | 
					          <StatTeamTable
 | 
				
			||||||
 | 
					            data={TeamData?.data}
 | 
				
			||||||
 | 
					            isLoading={TeamData?.isLoading}
 | 
				
			||||||
 | 
					            refetch={TeamData?.refetch}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <Button type="primary" onClick={(e) => handleSave("")}>
 | 
				
			||||||
 | 
					            Save as file
 | 
				
			||||||
 | 
					          </Button>
 | 
				
			||||||
 | 
					        </TabPane>
 | 
				
			||||||
 | 
					      </Tabs>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Stat;
 | 
				
			||||||
@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					import { Table } from "antd";
 | 
				
			||||||
 | 
					import { TStat } from "../../types/Statistic/TStat";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					const StatTable = ({
 | 
				
			||||||
 | 
					  data,
 | 
				
			||||||
 | 
					  isLoading,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TStat[], unknown>>;
 | 
				
			||||||
 | 
					  data: { data: TStat[] | undefined };
 | 
				
			||||||
 | 
					  isLoading: boolean;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Table
 | 
				
			||||||
 | 
					        size="small"
 | 
				
			||||||
 | 
					        loading={isLoading}
 | 
				
			||||||
 | 
					        dataSource={data?.data?.map((u, i) => ({
 | 
				
			||||||
 | 
					          no: i + 1,
 | 
				
			||||||
 | 
					          ...u,
 | 
				
			||||||
 | 
					        }))}
 | 
				
			||||||
 | 
					        columns={[
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					            dataIndex: "no",
 | 
				
			||||||
 | 
					            key: "no",
 | 
				
			||||||
 | 
					            width: "5%",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Support specialist",
 | 
				
			||||||
 | 
					            dataIndex: "username",
 | 
				
			||||||
 | 
					            key: "username",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Team",
 | 
				
			||||||
 | 
					            dataIndex: "team_name",
 | 
				
			||||||
 | 
					            key: "team_name ",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Points",
 | 
				
			||||||
 | 
					            dataIndex: "total_points",
 | 
				
			||||||
 | 
					            key: "total_points",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ]}
 | 
				
			||||||
 | 
					        pagination={{
 | 
				
			||||||
 | 
					          pageSize: 14,
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					          index % 2 === 0 ? "odd-row" : "even-row"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default StatTable;
 | 
				
			||||||
@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					import { Table, Tag } from "antd";
 | 
				
			||||||
 | 
					import { TStatTeam } from "../../types/Statistic/TStat";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					const StatTeamTable = ({
 | 
				
			||||||
 | 
					  data,
 | 
				
			||||||
 | 
					  isLoading,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TStatTeam[], unknown>>;
 | 
				
			||||||
 | 
					  data: TStatTeam[] | undefined;
 | 
				
			||||||
 | 
					  isLoading: boolean;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div style={{ maxHeight: "400px", overflow: "auto" }}>
 | 
				
			||||||
 | 
					      <Table
 | 
				
			||||||
 | 
					        loading={isLoading}
 | 
				
			||||||
 | 
					        size="small"
 | 
				
			||||||
 | 
					        dataSource={data?.map((u, i) => ({
 | 
				
			||||||
 | 
					          no: i + 1,
 | 
				
			||||||
 | 
					          ...u,
 | 
				
			||||||
 | 
					        }))}
 | 
				
			||||||
 | 
					        columns={[
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					            dataIndex: "no",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Team",
 | 
				
			||||||
 | 
					            dataIndex: "name",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Total points",
 | 
				
			||||||
 | 
					            dataIndex: "total_points",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            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: TStatTeam) => {
 | 
				
			||||||
 | 
					              return record.is_active === value;
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ]}
 | 
				
			||||||
 | 
					        pagination={{
 | 
				
			||||||
 | 
					          pageSize: 5,
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					          index % 2 === 0 ? "odd-row" : "even-row"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default StatTeamTable;
 | 
				
			||||||
@ -0,0 +1,327 @@
 | 
				
			|||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Input,
 | 
				
			||||||
 | 
					  Modal,
 | 
				
			||||||
 | 
					  Form as FormAnt,
 | 
				
			||||||
 | 
					  Select,
 | 
				
			||||||
 | 
					  Upload,
 | 
				
			||||||
 | 
					  Switch,
 | 
				
			||||||
 | 
					  Button,
 | 
				
			||||||
 | 
					  Row,
 | 
				
			||||||
 | 
					  Col,
 | 
				
			||||||
 | 
					} from "antd";
 | 
				
			||||||
 | 
					import { taskController } from "../../API/LayoutApi/tasks";
 | 
				
			||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import { useServiceData } from "../../Hooks/Services";
 | 
				
			||||||
 | 
					import { UploadOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					import { useTeamData } from "../../Hooks/Teams";
 | 
				
			||||||
 | 
					import { useCompanyData } from "../../Hooks/Companies";
 | 
				
			||||||
 | 
					import { useCustomerByComanyData } from "../../Hooks/Customers";
 | 
				
			||||||
 | 
					// @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 AddCustomer from "../Customers/AddCustomer";
 | 
				
			||||||
 | 
					import AddDriver from "../Companies/AddDriver";
 | 
				
			||||||
 | 
					import TextArea from "antd/es/input/TextArea";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { Option } = Select;
 | 
				
			||||||
 | 
					const AddTask = ({
 | 
				
			||||||
 | 
					  open,
 | 
				
			||||||
 | 
					  setOpen,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  open: boolean;
 | 
				
			||||||
 | 
					  setOpen(open: boolean): void;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const [form] = FormAnt.useForm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setOpen(!open);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [fileIds, setFileIds] = useState([]);
 | 
				
			||||||
 | 
					  const [companyName, setCompanyName] = useState<string>();
 | 
				
			||||||
 | 
					  const [customerName, setCustomerName] = useState<string>();
 | 
				
			||||||
 | 
					  const [companyId, setCompanyId] = useState<string>();
 | 
				
			||||||
 | 
					  const ServiceData = useServiceData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const TeamData = useTeamData("");
 | 
				
			||||||
 | 
					  const companyData = useCompanyData({ name: companyName });
 | 
				
			||||||
 | 
					  const customerData = useCustomerByComanyData({
 | 
				
			||||||
 | 
					    id: companyId,
 | 
				
			||||||
 | 
					    name: customerName,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [driverOpen, setDriverOpen] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [previewImage, setPreviewImage] = useState<string | null>(null);
 | 
				
			||||||
 | 
					  function handlePaste(event: any) {
 | 
				
			||||||
 | 
					    const clipboardData = event.clipboardData || window.Clipboard;
 | 
				
			||||||
 | 
					    if (clipboardData && clipboardData.items.length > 0) {
 | 
				
			||||||
 | 
					      const clipboardItem = clipboardData.items[0];
 | 
				
			||||||
 | 
					      if (clipboardItem.kind === "file") {
 | 
				
			||||||
 | 
					        const file = clipboardItem.getAsFile();
 | 
				
			||||||
 | 
					        const formData = new FormData();
 | 
				
			||||||
 | 
					        formData.append("file", file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const reader = new FileReader();
 | 
				
			||||||
 | 
					        reader.onload = (e) => {
 | 
				
			||||||
 | 
					          if (e.target && e.target.result) {
 | 
				
			||||||
 | 
					            setPreviewImage(e.target.result as string);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        reader.readAsDataURL(file);
 | 
				
			||||||
 | 
					        taskController
 | 
				
			||||||
 | 
					          .addTaskFile(formData)
 | 
				
			||||||
 | 
					          .then((response) => {
 | 
				
			||||||
 | 
					            const fileId = response.id;
 | 
				
			||||||
 | 
					            setFileIds((prevFileIds): any => [...prevFileIds, fileId]);
 | 
				
			||||||
 | 
					            const updatedValues = form.getFieldsValue();
 | 
				
			||||||
 | 
					            updatedValues.attachment_ids = [
 | 
				
			||||||
 | 
					              ...updatedValues.attachment_ids,
 | 
				
			||||||
 | 
					              fileId,
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					            form.setFieldsValue(updatedValues);
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .catch((error) => {});
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [openDrive, setOpenDrive] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div onPaste={(event) => handlePaste(event)}>
 | 
				
			||||||
 | 
					      {openDrive && (
 | 
				
			||||||
 | 
					        <AddCustomer
 | 
				
			||||||
 | 
					          refetch={customerData.refetch}
 | 
				
			||||||
 | 
					          open={openDrive}
 | 
				
			||||||
 | 
					          setOpen={setOpenDrive}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      <AddDriver id={companyId} open={driverOpen} setOpen={setDriverOpen} />
 | 
				
			||||||
 | 
					      <Modal
 | 
				
			||||||
 | 
					        open={open}
 | 
				
			||||||
 | 
					        width={600}
 | 
				
			||||||
 | 
					        title="Add task"
 | 
				
			||||||
 | 
					        okText="Create"
 | 
				
			||||||
 | 
					        cancelText="Cancel"
 | 
				
			||||||
 | 
					        onCancel={handleCancel}
 | 
				
			||||||
 | 
					        onOk={() => {
 | 
				
			||||||
 | 
					          form.validateFields().then(async (values) => {
 | 
				
			||||||
 | 
					            const updatedValues = { ...values };
 | 
				
			||||||
 | 
					            updatedValues.attachment_ids = fileIds;
 | 
				
			||||||
 | 
					            form.resetFields();
 | 
				
			||||||
 | 
					            await taskController.addTaskController(updatedValues);
 | 
				
			||||||
 | 
					            setOpen(!open);
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <FormAnt
 | 
				
			||||||
 | 
					          form={form}
 | 
				
			||||||
 | 
					          layout="horizontal"
 | 
				
			||||||
 | 
					          name="form_in_modal"
 | 
				
			||||||
 | 
					          initialValues={{ modifier: "public" }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Company"
 | 
				
			||||||
 | 
					            name="company_id"
 | 
				
			||||||
 | 
					            rules={[{ required: false, message: "Please input 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)}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <div
 | 
				
			||||||
 | 
					            style={{
 | 
				
			||||||
 | 
					              display: "flex",
 | 
				
			||||||
 | 
					              justifyContent: "space-between",
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <FormAnt.Item
 | 
				
			||||||
 | 
					              label="Driver"
 | 
				
			||||||
 | 
					              name="customer_id"
 | 
				
			||||||
 | 
					              style={{ width: "85%" }}
 | 
				
			||||||
 | 
					              rules={[
 | 
				
			||||||
 | 
					                { required: false, message: "Please input service points!" },
 | 
				
			||||||
 | 
					              ]}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <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
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
 | 
					            </FormAnt.Item>
 | 
				
			||||||
 | 
					            <Button onClick={(e) => setDriverOpen(true)} type="primary">
 | 
				
			||||||
 | 
					              Add
 | 
				
			||||||
 | 
					            </Button>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Service"
 | 
				
			||||||
 | 
					            name="service_id"
 | 
				
			||||||
 | 
					            rules={[{ required: true, message: "Please select service!" }]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Select
 | 
				
			||||||
 | 
					              options={ServiceData?.data?.map((item) => ({
 | 
				
			||||||
 | 
					                label: item?.title,
 | 
				
			||||||
 | 
					                value: item?.id,
 | 
				
			||||||
 | 
					              }))}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Assigned to"
 | 
				
			||||||
 | 
					            name="assigned_to_id"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                required: true,
 | 
				
			||||||
 | 
					                message: "Please select one of the teams!",
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Select
 | 
				
			||||||
 | 
					              options={TeamData?.data?.map((item) => ({
 | 
				
			||||||
 | 
					                label: item?.name,
 | 
				
			||||||
 | 
					                value: item?.id,
 | 
				
			||||||
 | 
					              }))}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Status"
 | 
				
			||||||
 | 
					            name="status"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: false, message: "Please input service points!" },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Select defaultValue="New">
 | 
				
			||||||
 | 
					              <Option value="New">New</Option>
 | 
				
			||||||
 | 
					              <Option value="Checking">Checking</Option>
 | 
				
			||||||
 | 
					              <Option value="Done">Done</Option>
 | 
				
			||||||
 | 
					            </Select>
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="PTI"
 | 
				
			||||||
 | 
					            name="pti"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: false, message: "Please input service points!" },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Switch />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Note"
 | 
				
			||||||
 | 
					            name="note"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: false, message: "Please input service points!" },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <TextArea
 | 
				
			||||||
 | 
					              style={{ padding: "7px 11px" }}
 | 
				
			||||||
 | 
					              placeholder="note"
 | 
				
			||||||
 | 
					              autoSize={{ minRows: 3, maxRows: 3 }}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					        </FormAnt>
 | 
				
			||||||
 | 
					        <FormAnt>
 | 
				
			||||||
 | 
					          <FormAnt.Item name="attachment">
 | 
				
			||||||
 | 
					            <div>
 | 
				
			||||||
 | 
					              <Upload.Dragger
 | 
				
			||||||
 | 
					                name="file"
 | 
				
			||||||
 | 
					                multiple={true}
 | 
				
			||||||
 | 
					                customRequest={({ file, onSuccess }: any) => {
 | 
				
			||||||
 | 
					                  const formData = new FormData();
 | 
				
			||||||
 | 
					                  formData.append("file", file);
 | 
				
			||||||
 | 
					                  taskController
 | 
				
			||||||
 | 
					                    .addTaskFile(formData)
 | 
				
			||||||
 | 
					                    .then((response) => {
 | 
				
			||||||
 | 
					                      const fileId = response.id;
 | 
				
			||||||
 | 
					                      setFileIds((prevFileIds): any => [
 | 
				
			||||||
 | 
					                        ...prevFileIds,
 | 
				
			||||||
 | 
					                        fileId,
 | 
				
			||||||
 | 
					                      ]);
 | 
				
			||||||
 | 
					                      onSuccess();
 | 
				
			||||||
 | 
					                      const updatedValues = form.getFieldsValue();
 | 
				
			||||||
 | 
					                      updatedValues.attachment_ids = [
 | 
				
			||||||
 | 
					                        ...updatedValues.attachment_ids,
 | 
				
			||||||
 | 
					                        fileId,
 | 
				
			||||||
 | 
					                      ];
 | 
				
			||||||
 | 
					                      form.setFieldsValue(updatedValues);
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .catch((error) => {
 | 
				
			||||||
 | 
					                      onSuccess(error);
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <p className="ant-upload-drag-icon">
 | 
				
			||||||
 | 
					                  <UploadOutlined style={{ color: "rgba(249, 158, 44, 1)" }} />
 | 
				
			||||||
 | 
					                </p>
 | 
				
			||||||
 | 
					                <p
 | 
				
			||||||
 | 
					                  className="ant-upload-text"
 | 
				
			||||||
 | 
					                  style={{ color: "rgba(249, 158, 44, 1)" }}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  Click or drag a file here to upload
 | 
				
			||||||
 | 
					                </p>
 | 
				
			||||||
 | 
					              </Upload.Dragger>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					        </FormAnt>
 | 
				
			||||||
 | 
					      </Modal>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default AddTask;
 | 
				
			||||||
@ -0,0 +1,556 @@
 | 
				
			|||||||
 | 
					import { TTask } from "../../types/Tasks/TTasks";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Dropdown,
 | 
				
			||||||
 | 
					  MenuProps,
 | 
				
			||||||
 | 
					  Modal,
 | 
				
			||||||
 | 
					  Table,
 | 
				
			||||||
 | 
					  Tabs,
 | 
				
			||||||
 | 
					  Tooltip,
 | 
				
			||||||
 | 
					  message,
 | 
				
			||||||
 | 
					} from "antd";
 | 
				
			||||||
 | 
					import TabPane from "antd/es/tabs/TabPane";
 | 
				
			||||||
 | 
					import { timeZone } from "../../App";
 | 
				
			||||||
 | 
					import { useTaskHistory } from "../../Hooks/Tasks";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import closeIcon from "../../assets/closeIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import editIcon from "../../assets/editIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import historyIcon from "../../assets/hisoryIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import attachmentIcon from "../../assets/attachmentIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIcon from "../../assets/infoIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import uploadIcon from "../../assets/uploadIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import pdficon from "../../assets/pdficon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import letssee from "../../assets/letssee.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import svgicon from "../../assets/svgicon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import pngicon from "../../assets/pngicon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import jpgicon from "../../assets/jpgicon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import jpegicon from "../../assets/jpegicon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import xlsicon from "../../assets/xlsicon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import docicon from "../../assets/docicon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import forwardIcon from "../../assets/forward.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import driverIcon from "../../assets/drivericon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					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, UserOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TaskModal = ({
 | 
				
			||||||
 | 
					  modalOpen,
 | 
				
			||||||
 | 
					  setModalOpen,
 | 
				
			||||||
 | 
					  recordTask,
 | 
				
			||||||
 | 
					  uploadOpen,
 | 
				
			||||||
 | 
					  setUploadOpen,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  recordTask: TTask | undefined;
 | 
				
			||||||
 | 
					  modalOpen: any;
 | 
				
			||||||
 | 
					  setModalOpen: any;
 | 
				
			||||||
 | 
					  uploadOpen: any;
 | 
				
			||||||
 | 
					  setUploadOpen: any;
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TPagination<TTask[]>, unknown>>;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const moment = require("moment-timezone");
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setModalOpen(!modalOpen);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const showUploadModal = () => {
 | 
				
			||||||
 | 
					    setUploadOpen(!uploadOpen);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  function getFileType(fileName: any) {
 | 
				
			||||||
 | 
					    var fileExtension = fileName.split(".").pop()?.toLowerCase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (fileExtension) {
 | 
				
			||||||
 | 
					      case "jpg":
 | 
				
			||||||
 | 
					        return <img style={{ marginRight: 12 }} src={jpgicon} alt="" />;
 | 
				
			||||||
 | 
					      case "jpeg":
 | 
				
			||||||
 | 
					        return <img style={{ marginRight: 12 }} src={jpegicon} alt="" />;
 | 
				
			||||||
 | 
					      case "png":
 | 
				
			||||||
 | 
					        return <img style={{ marginRight: 12 }} src={pngicon} alt="" />;
 | 
				
			||||||
 | 
					      case "pdf":
 | 
				
			||||||
 | 
					        return <img style={{ marginRight: 12 }} src={pdficon} alt="" />;
 | 
				
			||||||
 | 
					      case "svg":
 | 
				
			||||||
 | 
					        return <img style={{ marginRight: 12 }} src={svgicon} alt="" />;
 | 
				
			||||||
 | 
					      case "xls":
 | 
				
			||||||
 | 
					        return <img style={{ marginRight: 12 }} src={xlsicon} alt="" />;
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        return <img style={{ marginRight: 12 }} src={docicon} alt="" />;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const [text, setText] = useState<string | undefined>(recordTask?.note);
 | 
				
			||||||
 | 
					  const [pti, setPti] = useState<boolean | undefined>(recordTask?.pti);
 | 
				
			||||||
 | 
					  const theme = localStorage.getItem("theme") === "true" ? true : false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { data, isLoading } = useTaskHistory(recordTask?.id);
 | 
				
			||||||
 | 
					  const patchTask = () => {
 | 
				
			||||||
 | 
					    taskController
 | 
				
			||||||
 | 
					      .taskPatch({ note: text, pti: pti }, recordTask?.id)
 | 
				
			||||||
 | 
					      .then(() => {
 | 
				
			||||||
 | 
					        message.success({ content: "Saved!" });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [status, setStatus] = useState(recordTask?.status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const statuspatch = (status: string) => {
 | 
				
			||||||
 | 
					    setStatus(status);
 | 
				
			||||||
 | 
					    taskController.taskPatch({ status: status }, recordTask?.id).then(() => {
 | 
				
			||||||
 | 
					      message.success({ content: "Success", duration: 1 });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [teamName, setTeamName] = useState(recordTask?.assigned_to?.name);
 | 
				
			||||||
 | 
					  const teampatch = (item: TTeam) => {
 | 
				
			||||||
 | 
					    setTeamName(item?.name);
 | 
				
			||||||
 | 
					    taskController
 | 
				
			||||||
 | 
					      .taskPatch({ assigned_to_id: item?.id }, recordTask?.id)
 | 
				
			||||||
 | 
					      .then(() => {
 | 
				
			||||||
 | 
					        message.success({ content: "Success", duration: 1 });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const teamData = useTeamData("");
 | 
				
			||||||
 | 
					  const teams: MenuProps["items"] = teamData?.data?.map((item) => ({
 | 
				
			||||||
 | 
					    key: item?.id,
 | 
				
			||||||
 | 
					    label: <p>{item?.name}</p>,
 | 
				
			||||||
 | 
					    onClick: () => teampatch(item),
 | 
				
			||||||
 | 
					  }));
 | 
				
			||||||
 | 
					  const items: MenuProps["items"] = [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      key: "1",
 | 
				
			||||||
 | 
					      label: <p>New</p>,
 | 
				
			||||||
 | 
					      onClick: () => statuspatch("New"),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      key: "2",
 | 
				
			||||||
 | 
					      label: <p>Checking</p>,
 | 
				
			||||||
 | 
					      onClick: () => statuspatch("Checking"),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      key: "3",
 | 
				
			||||||
 | 
					      label: <p>Done</p>,
 | 
				
			||||||
 | 
					      onClick: () => statuspatch("Done"),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const getImageSource = (source: string) => {
 | 
				
			||||||
 | 
					    switch (source) {
 | 
				
			||||||
 | 
					      case "driver":
 | 
				
			||||||
 | 
					        return driverIcon;
 | 
				
			||||||
 | 
					      case "user":
 | 
				
			||||||
 | 
					        return userIcon;
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        return userIcon;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Modal
 | 
				
			||||||
 | 
					      onCancel={handleCancel}
 | 
				
			||||||
 | 
					      footer={null}
 | 
				
			||||||
 | 
					      open={modalOpen}
 | 
				
			||||||
 | 
					      width={800}
 | 
				
			||||||
 | 
					      maskClosable={true}
 | 
				
			||||||
 | 
					      // style={{ position: "fixed", right: 0, top: 0, bottom: 0, height: 1000 }}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <div className={!theme ? "TaskModal-header" : "TaskModal-header-dark"}>
 | 
				
			||||||
 | 
					        <div className={!theme ? "TaskModal-title" : "TaskModal-title-dark"}>
 | 
				
			||||||
 | 
					          <p className={!theme ? "p-driver" : "p-driver-dark"}>
 | 
				
			||||||
 | 
					            {recordTask?.customer?.name}
 | 
				
			||||||
 | 
					          </p>
 | 
				
			||||||
 | 
					          <Dropdown
 | 
				
			||||||
 | 
					            menu={{ items }}
 | 
				
			||||||
 | 
					            placement="bottom"
 | 
				
			||||||
 | 
					            arrow={{ pointAtCenter: true }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              style={{ marginLeft: 12, display: "flex", alignItems: "center" }}
 | 
				
			||||||
 | 
					              className={`status-${status}`}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              {status}
 | 
				
			||||||
 | 
					              <EditOutlined style={{ marginLeft: 4 }} />
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					          </Dropdown>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div className="mdoal-actions">
 | 
				
			||||||
 | 
					          <Dropdown
 | 
				
			||||||
 | 
					            disabled={recordTask?.status !== "New"}
 | 
				
			||||||
 | 
					            menu={{ items: teams }}
 | 
				
			||||||
 | 
					            placement="bottom"
 | 
				
			||||||
 | 
					            arrow={{ pointAtCenter: true }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <button
 | 
				
			||||||
 | 
					              disabled={recordTask?.status !== "New"}
 | 
				
			||||||
 | 
					              style={{ marginRight: 12 }}
 | 
				
			||||||
 | 
					              className={`btn-modal-action-${theme && "dark"}`}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <img src={forwardIcon} alt="" />
 | 
				
			||||||
 | 
					              Forward
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					          </Dropdown>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            style={{ marginLeft: 12 }}
 | 
				
			||||||
 | 
					            className={`btn-modal-action-${theme && "dark"}`}
 | 
				
			||||||
 | 
					            onClick={showUploadModal}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <img src={uploadIcon} alt="" />
 | 
				
			||||||
 | 
					            Upload file
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            onClick={handleCancel}
 | 
				
			||||||
 | 
					            style={{ marginLeft: 20 }}
 | 
				
			||||||
 | 
					            className={`btn-modal-action-${theme && "dark"}`}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <img style={{ margin: 2 }} src={closeIcon} alt="" />
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className="TaskModal-content">
 | 
				
			||||||
 | 
					        <Tabs>
 | 
				
			||||||
 | 
					          <TabPane
 | 
				
			||||||
 | 
					            tab={
 | 
				
			||||||
 | 
					              <span
 | 
				
			||||||
 | 
					                style={{
 | 
				
			||||||
 | 
					                  display: "flex",
 | 
				
			||||||
 | 
					                  alignItems: "center",
 | 
				
			||||||
 | 
					                  marginLeft: 24,
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <img style={{ marginRight: 10 }} src={infoIcon} alt="" />
 | 
				
			||||||
 | 
					                Information
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            key="1"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <div className="info-div">
 | 
				
			||||||
 | 
					              <p
 | 
				
			||||||
 | 
					                style={{
 | 
				
			||||||
 | 
					                  fontSize: 18,
 | 
				
			||||||
 | 
					                  fontWeight: 700,
 | 
				
			||||||
 | 
					                  lineHeight: "24px",
 | 
				
			||||||
 | 
					                  letterSpacing: "-0.02em",
 | 
				
			||||||
 | 
					                  marginBottom: 16,
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                Information
 | 
				
			||||||
 | 
					              </p>
 | 
				
			||||||
 | 
					              <div className="info-body">
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "sub" : "sub-dark"}>Comapany</p>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "info" : "info-dark"}>
 | 
				
			||||||
 | 
					                    {recordTask?.company?.name}
 | 
				
			||||||
 | 
					                  </p>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "sub" : "sub-dark"}>Driver</p>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "info" : "info-dark"}>
 | 
				
			||||||
 | 
					                    {recordTask?.customer?.name}
 | 
				
			||||||
 | 
					                  </p>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "sub" : "sub-dark"}>Service</p>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "info" : "info-dark"}>
 | 
				
			||||||
 | 
					                    {recordTask?.service?.title}
 | 
				
			||||||
 | 
					                  </p>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "sub" : "sub-dark"}>Team</p>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "info" : "info-dark"}>{teamName}</p>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "sub" : "sub-dark"}>Assignee</p>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "info" : "info-dark"}>
 | 
				
			||||||
 | 
					                    {recordTask?.in_charge?.username}
 | 
				
			||||||
 | 
					                  </p>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "sub" : "sub-dark"}>PTI</p>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "info" : "info-dark"}>
 | 
				
			||||||
 | 
					                    {pti === false ? "Do" : "No need"}
 | 
				
			||||||
 | 
					                  </p>
 | 
				
			||||||
 | 
					                  <button
 | 
				
			||||||
 | 
					                    style={{
 | 
				
			||||||
 | 
					                      marginLeft: 10,
 | 
				
			||||||
 | 
					                      background: "#cecece",
 | 
				
			||||||
 | 
					                      outline: "none",
 | 
				
			||||||
 | 
					                      border: "1px solid rgba(246, 137, 0, 1)",
 | 
				
			||||||
 | 
					                      padding: 4,
 | 
				
			||||||
 | 
					                      borderRadius: 4,
 | 
				
			||||||
 | 
					                    }}
 | 
				
			||||||
 | 
					                    onClick={(e) => setPti(!pti)}
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    change
 | 
				
			||||||
 | 
					                  </button>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "sub" : "sub-dark"}>Created at</p>
 | 
				
			||||||
 | 
					                  <p className={!theme ? "info" : "info-dark"}>
 | 
				
			||||||
 | 
					                    {moment(
 | 
				
			||||||
 | 
					                      recordTask?.created_at,
 | 
				
			||||||
 | 
					                      "YYYY-MM-DD HH:mm:ss"
 | 
				
			||||||
 | 
					                    ).format("DD.MM.YYYY HH:mm")}
 | 
				
			||||||
 | 
					                  </p>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <div style={{ marginTop: 20 }}>
 | 
				
			||||||
 | 
					                <label className={!theme ? "sub" : "sub-dark"}>Note:</label>
 | 
				
			||||||
 | 
					                <TextArea
 | 
				
			||||||
 | 
					                  style={{ padding: "7px 11px", marginTop: 10 }}
 | 
				
			||||||
 | 
					                  placeholder="Description"
 | 
				
			||||||
 | 
					                  defaultValue={text}
 | 
				
			||||||
 | 
					                  autoSize={{ minRows: 3, maxRows: 3 }}
 | 
				
			||||||
 | 
					                  onChange={(e) => setText(e.target.value)}
 | 
				
			||||||
 | 
					                />
 | 
				
			||||||
 | 
					              </div>
 | 
				
			||||||
 | 
					              <button
 | 
				
			||||||
 | 
					                style={{ marginTop: 20 }}
 | 
				
			||||||
 | 
					                className={`btn-modal-action-${theme && "dark"}`}
 | 
				
			||||||
 | 
					                onClick={(e) => patchTask()}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <img src={editIcon} alt="" />
 | 
				
			||||||
 | 
					                Save
 | 
				
			||||||
 | 
					              </button>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          </TabPane>
 | 
				
			||||||
 | 
					          <TabPane
 | 
				
			||||||
 | 
					            tab={
 | 
				
			||||||
 | 
					              <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					                <img style={{ marginRight: 10 }} src={attachmentIcon} alt="" />
 | 
				
			||||||
 | 
					                Attachments
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            key="2"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <div className="info-div">
 | 
				
			||||||
 | 
					              <p
 | 
				
			||||||
 | 
					                style={{
 | 
				
			||||||
 | 
					                  fontSize: 18,
 | 
				
			||||||
 | 
					                  fontWeight: 700,
 | 
				
			||||||
 | 
					                  lineHeight: "24px",
 | 
				
			||||||
 | 
					                  letterSpacing: "-0.02em",
 | 
				
			||||||
 | 
					                  marginBottom: 16,
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                Attachments
 | 
				
			||||||
 | 
					              </p>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <Table
 | 
				
			||||||
 | 
					              size="small"
 | 
				
			||||||
 | 
					              style={{ margin: "0 12px" }}
 | 
				
			||||||
 | 
					              dataSource={recordTask?.attachment_set?.map((u, i) => ({
 | 
				
			||||||
 | 
					                no: i + 1,
 | 
				
			||||||
 | 
					                ...u,
 | 
				
			||||||
 | 
					                created: moment(u?.updated_at)
 | 
				
			||||||
 | 
					                  .tz(timeZone)
 | 
				
			||||||
 | 
					                  .format("DD.MM.YYYY HH:mm"),
 | 
				
			||||||
 | 
					                action: { ...u },
 | 
				
			||||||
 | 
					              }))}
 | 
				
			||||||
 | 
					              columns={[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  title: "Name/Description",
 | 
				
			||||||
 | 
					                  dataIndex: "file_name",
 | 
				
			||||||
 | 
					                  width: "30%",
 | 
				
			||||||
 | 
					                  key: 1,
 | 
				
			||||||
 | 
					                  ellipsis: {
 | 
				
			||||||
 | 
					                    showTitle: false,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  title: "Uploaded date",
 | 
				
			||||||
 | 
					                  dataIndex: "created",
 | 
				
			||||||
 | 
					                  key: 2,
 | 
				
			||||||
 | 
					                  width: "30%",
 | 
				
			||||||
 | 
					                  ellipsis: {
 | 
				
			||||||
 | 
					                    showTitle: false,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  title: "Attachments",
 | 
				
			||||||
 | 
					                  dataIndex: "action",
 | 
				
			||||||
 | 
					                  key: 3,
 | 
				
			||||||
 | 
					                  width: "40%",
 | 
				
			||||||
 | 
					                  render: (text, record) => {
 | 
				
			||||||
 | 
					                    return (
 | 
				
			||||||
 | 
					                      <a
 | 
				
			||||||
 | 
					                        href={record?.path}
 | 
				
			||||||
 | 
					                        target="_blank"
 | 
				
			||||||
 | 
					                        rel="noreferrer"
 | 
				
			||||||
 | 
					                        style={{
 | 
				
			||||||
 | 
					                          padding: "6px 10px",
 | 
				
			||||||
 | 
					                          display: "flex",
 | 
				
			||||||
 | 
					                          alignItems: "center",
 | 
				
			||||||
 | 
					                          justifyContent: "space-between",
 | 
				
			||||||
 | 
					                          borderRadius: 8,
 | 
				
			||||||
 | 
					                          color: !theme ? "rgba(15, 17, 28, 1)" : "#bbb",
 | 
				
			||||||
 | 
					                          border: "1px solid rgba(215, 216, 224, 1)",
 | 
				
			||||||
 | 
					                          boxShadow: "0px 1px 3px 0px rgba(20, 22, 41, 0.1)",
 | 
				
			||||||
 | 
					                        }}
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        {getFileType(record?.file_name)}
 | 
				
			||||||
 | 
					                        <span style={{ overflow: "hidden" }}>
 | 
				
			||||||
 | 
					                          {record?.file_name}
 | 
				
			||||||
 | 
					                        </span>
 | 
				
			||||||
 | 
					                        <img
 | 
				
			||||||
 | 
					                          src={letssee}
 | 
				
			||||||
 | 
					                          alt=""
 | 
				
			||||||
 | 
					                          style={{ textAlign: "right" }}
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                      </a>
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                  ellipsis: {
 | 
				
			||||||
 | 
					                    showTitle: false,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              ]}
 | 
				
			||||||
 | 
					              rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					                index % 2 === 0 ? "even-row" : "odd-row"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </TabPane>
 | 
				
			||||||
 | 
					          <TabPane
 | 
				
			||||||
 | 
					            tab={
 | 
				
			||||||
 | 
					              <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					                <img style={{ marginRight: 10 }} src={historyIcon} alt="" />
 | 
				
			||||||
 | 
					                History
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            key="3"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <div className="info-div">
 | 
				
			||||||
 | 
					              <p
 | 
				
			||||||
 | 
					                style={{
 | 
				
			||||||
 | 
					                  fontSize: 18,
 | 
				
			||||||
 | 
					                  fontWeight: 700,
 | 
				
			||||||
 | 
					                  lineHeight: "24px",
 | 
				
			||||||
 | 
					                  letterSpacing: "-0.02em",
 | 
				
			||||||
 | 
					                  marginBottom: 16,
 | 
				
			||||||
 | 
					                }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                History
 | 
				
			||||||
 | 
					              </p>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <Table
 | 
				
			||||||
 | 
					              style={{ margin: "0 24px" }}
 | 
				
			||||||
 | 
					              loading={isLoading}
 | 
				
			||||||
 | 
					              size="small"
 | 
				
			||||||
 | 
					              dataSource={data?.map((u, i) => ({
 | 
				
			||||||
 | 
					                no: i + 1,
 | 
				
			||||||
 | 
					                ...u,
 | 
				
			||||||
 | 
					                by: u.user
 | 
				
			||||||
 | 
					                  ? { user: u?.user?.username }
 | 
				
			||||||
 | 
					                  : { driver: u?.driver?.name },
 | 
				
			||||||
 | 
					                created: moment(u?.timestamp)
 | 
				
			||||||
 | 
					                  .tz(timeZone)
 | 
				
			||||||
 | 
					                  .format("DD.MM.YYYY HH:mm"),
 | 
				
			||||||
 | 
					                // action: { ...u. },
 | 
				
			||||||
 | 
					              }))}
 | 
				
			||||||
 | 
					              columns={[
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  title: "User/Driver",
 | 
				
			||||||
 | 
					                  dataIndex: "by",
 | 
				
			||||||
 | 
					                  width: "25%",
 | 
				
			||||||
 | 
					                  key: 1,
 | 
				
			||||||
 | 
					                  ellipsis: {
 | 
				
			||||||
 | 
					                    showTitle: false,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                  render: (text: any, record: any) => (
 | 
				
			||||||
 | 
					                    <Tooltip placement="topLeft" title={text}>
 | 
				
			||||||
 | 
					                      <div style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					                        {text?.user ? (
 | 
				
			||||||
 | 
					                          <>
 | 
				
			||||||
 | 
					                            <img
 | 
				
			||||||
 | 
					                              src={getImageSource("user")}
 | 
				
			||||||
 | 
					                              alt=""
 | 
				
			||||||
 | 
					                              style={{ width: 15, height: 15, marginRight: 10 }}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                            <p>
 | 
				
			||||||
 | 
					                              {typeof text.user === "string" ? text.user : ""}
 | 
				
			||||||
 | 
					                            </p>
 | 
				
			||||||
 | 
					                          </>
 | 
				
			||||||
 | 
					                        ) : (
 | 
				
			||||||
 | 
					                          <>
 | 
				
			||||||
 | 
					                            <img
 | 
				
			||||||
 | 
					                              src={getImageSource("driver")}
 | 
				
			||||||
 | 
					                              alt=""
 | 
				
			||||||
 | 
					                              style={{ width: 20, height: 15, marginRight: 10 }}
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                            <p>
 | 
				
			||||||
 | 
					                              {typeof text.driver === "string"
 | 
				
			||||||
 | 
					                                ? text.driver
 | 
				
			||||||
 | 
					                                : ""}
 | 
				
			||||||
 | 
					                            </p>
 | 
				
			||||||
 | 
					                          </>
 | 
				
			||||||
 | 
					                        )}
 | 
				
			||||||
 | 
					                      </div>
 | 
				
			||||||
 | 
					                    </Tooltip>
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  title: "Action",
 | 
				
			||||||
 | 
					                  dataIndex: "action",
 | 
				
			||||||
 | 
					                  width: "15%",
 | 
				
			||||||
 | 
					                  key: 2,
 | 
				
			||||||
 | 
					                  ellipsis: {
 | 
				
			||||||
 | 
					                    showTitle: false,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  title: "Description",
 | 
				
			||||||
 | 
					                  dataIndex: "description",
 | 
				
			||||||
 | 
					                  width: "40%",
 | 
				
			||||||
 | 
					                  key: 3,
 | 
				
			||||||
 | 
					                  ellipsis: {
 | 
				
			||||||
 | 
					                    showTitle: false,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                  render: (note: string) => (
 | 
				
			||||||
 | 
					                    <Tooltip placement="topLeft" title={note}>
 | 
				
			||||||
 | 
					                      {note}
 | 
				
			||||||
 | 
					                    </Tooltip>
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                  title: "Timestamp",
 | 
				
			||||||
 | 
					                  dataIndex: "created",
 | 
				
			||||||
 | 
					                  key: 4,
 | 
				
			||||||
 | 
					                  width: "20%",
 | 
				
			||||||
 | 
					                  ellipsis: {
 | 
				
			||||||
 | 
					                    showTitle: false,
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					              ]}
 | 
				
			||||||
 | 
					              rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					                index % 2 === 0 ? "even-row" : "odd-row"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </TabPane>
 | 
				
			||||||
 | 
					        </Tabs>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </Modal>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default TaskModal;
 | 
				
			||||||
@ -0,0 +1,354 @@
 | 
				
			|||||||
 | 
					import { Button, Modal, Space, Table, Tooltip } from "antd";
 | 
				
			||||||
 | 
					import "../../App.css";
 | 
				
			||||||
 | 
					import { useEffect, useMemo, useState } from "react";
 | 
				
			||||||
 | 
					import { taskController } from "../../API/LayoutApi/tasks";
 | 
				
			||||||
 | 
					import { TPagination } from "../../types/common/TPagination";
 | 
				
			||||||
 | 
					import { TTask } from "../../types/Tasks/TTasks";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					  UseQueryResult,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					import { TCompany } from "../../types/Company/TCompany";
 | 
				
			||||||
 | 
					import { TService } from "../../types/Service/TService";
 | 
				
			||||||
 | 
					import { TCustomer } from "../../types/Customer/TCustomer";
 | 
				
			||||||
 | 
					import { TUser } from "../../types/User/TUser";
 | 
				
			||||||
 | 
					// @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";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const admin_id = localStorage.getItem("admin_id");
 | 
				
			||||||
 | 
					const TaskTable = ({
 | 
				
			||||||
 | 
					  data,
 | 
				
			||||||
 | 
					  isLoading,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					  showTaskModal,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  data: {
 | 
				
			||||||
 | 
					    characters: TTask[] | undefined;
 | 
				
			||||||
 | 
					    CompanyData: UseQueryResult<TCompany[], unknown>;
 | 
				
			||||||
 | 
					    CustomerData: UseQueryResult<TCustomer[], unknown>;
 | 
				
			||||||
 | 
					    ServiceData: UseQueryResult<TService[], unknown>;
 | 
				
			||||||
 | 
					    AdminData: UseQueryResult<TUser[], unknown>;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  showTaskModal: any;
 | 
				
			||||||
 | 
					  isLoading: boolean;
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TPagination<TTask[]>, unknown>>;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const moment = require("moment");
 | 
				
			||||||
 | 
					  const statusClick = (record: any) => {
 | 
				
			||||||
 | 
					    if (record.status === "New") {
 | 
				
			||||||
 | 
					      Modal.confirm({
 | 
				
			||||||
 | 
					        title: "Confirmation",
 | 
				
			||||||
 | 
					        content: `Are you sure you want to be in charge for this task?`,
 | 
				
			||||||
 | 
					        onOk: () => {
 | 
				
			||||||
 | 
					          const value = {
 | 
				
			||||||
 | 
					            status: "Checking",
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          taskController.taskPatch(value, record.id);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (record.status === "Checking") {
 | 
				
			||||||
 | 
					      Modal.confirm({
 | 
				
			||||||
 | 
					        title: "Confirmation",
 | 
				
			||||||
 | 
					        content: `Are you sure you want to finish this task?`,
 | 
				
			||||||
 | 
					        onOk: () => {
 | 
				
			||||||
 | 
					          const value = {
 | 
				
			||||||
 | 
					            status: "Done",
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					          taskController.taskPatch(value, record.id);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [isTextSelected, setIsTextSelected] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    const handleSelectionChange = () => {
 | 
				
			||||||
 | 
					      const selection = window.getSelection();
 | 
				
			||||||
 | 
					      setIsTextSelected(selection !== null && selection.toString() !== "");
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    document.addEventListener("selectionchange", handleSelectionChange);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return () => {
 | 
				
			||||||
 | 
					      document.removeEventListener("selectionchange", handleSelectionChange);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleRowClick = (record: TTask, event: any) => {
 | 
				
			||||||
 | 
					    if (isTextSelected) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      event.target.classList.contains("ant-table-cell") &&
 | 
				
			||||||
 | 
					      (record?.in_charge?.id === null ||
 | 
				
			||||||
 | 
					        (!!admin_id && record?.in_charge?.id === +admin_id) ||
 | 
				
			||||||
 | 
					        role !== "Checker")
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      showTaskModal(record);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const rowClassName = (record: TTask) => {
 | 
				
			||||||
 | 
					    if (record.status === "New") {
 | 
				
			||||||
 | 
					      return "new-status-row";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return "";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const columns = useMemo(() => {
 | 
				
			||||||
 | 
					    const columns = [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					        dataIndex: "no",
 | 
				
			||||||
 | 
					        width: "5%",
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: "Company",
 | 
				
			||||||
 | 
					        dataIndex: "company",
 | 
				
			||||||
 | 
					        width: "13%",
 | 
				
			||||||
 | 
					        responsive: ["xl"],
 | 
				
			||||||
 | 
					        ellipsis: {
 | 
				
			||||||
 | 
					          showTitle: true,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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>
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: "Driver",
 | 
				
			||||||
 | 
					        dataIndex: "customer",
 | 
				
			||||||
 | 
					        width: "13%",
 | 
				
			||||||
 | 
					        ellipsis: {
 | 
				
			||||||
 | 
					          showTitle: false,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        render: (item: { name: string; id: number }) => (
 | 
				
			||||||
 | 
					          <Tooltip placement="topLeft" title={item?.name}>
 | 
				
			||||||
 | 
					            {item?.name}
 | 
				
			||||||
 | 
					          </Tooltip>
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: "Service",
 | 
				
			||||||
 | 
					        dataIndex: "service",
 | 
				
			||||||
 | 
					        width: "7%",
 | 
				
			||||||
 | 
					        ellipsis: {
 | 
				
			||||||
 | 
					          showTitle: false,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        render: (item: { title: string; id: number }) => (
 | 
				
			||||||
 | 
					          <Tooltip placement="topLeft" title={item?.title}>
 | 
				
			||||||
 | 
					            {item.title}
 | 
				
			||||||
 | 
					          </Tooltip>
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: "Status",
 | 
				
			||||||
 | 
					        dataIndex: "status",
 | 
				
			||||||
 | 
					        width: "8%",
 | 
				
			||||||
 | 
					        ellipsis: {
 | 
				
			||||||
 | 
					          showTitle: false,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        render: (status: string) => (
 | 
				
			||||||
 | 
					          <span>
 | 
				
			||||||
 | 
					            {status === "Done" && <p className="status-done">Done</p>}
 | 
				
			||||||
 | 
					            {status === "Checking" && (
 | 
				
			||||||
 | 
					              <p className="status-in-progress">Checking</p>
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					            {status === "New" && <p className="status-new">New</p>}
 | 
				
			||||||
 | 
					          </span>
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: "Team",
 | 
				
			||||||
 | 
					        dataIndex: "assigned_to",
 | 
				
			||||||
 | 
					        width: "8%",
 | 
				
			||||||
 | 
					        ellipsis: {
 | 
				
			||||||
 | 
					          showTitle: false,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        render: (item: { name: string }) => (
 | 
				
			||||||
 | 
					          <Tooltip placement="topLeft" title={item?.name}>
 | 
				
			||||||
 | 
					            {item?.name}
 | 
				
			||||||
 | 
					          </Tooltip>
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: "Assignee",
 | 
				
			||||||
 | 
					        dataIndex: "in_charge",
 | 
				
			||||||
 | 
					        width: "12%",
 | 
				
			||||||
 | 
					        ellipsis: {
 | 
				
			||||||
 | 
					          showTitle: false,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        render: (item: { username: string }) => (
 | 
				
			||||||
 | 
					          <Tooltip placement="topLeft" title={item?.username}>
 | 
				
			||||||
 | 
					            {item?.username}
 | 
				
			||||||
 | 
					          </Tooltip>
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: "PTI",
 | 
				
			||||||
 | 
					        dataIndex: "pti",
 | 
				
			||||||
 | 
					        width: "6%",
 | 
				
			||||||
 | 
					        responsive: ["lg"],
 | 
				
			||||||
 | 
					        render: (pti: boolean) => (pti ? "No need" : "Do"),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: "Note",
 | 
				
			||||||
 | 
					        dataIndex: "note",
 | 
				
			||||||
 | 
					        width: "12%",
 | 
				
			||||||
 | 
					        responsive: ["lg"],
 | 
				
			||||||
 | 
					        ellipsis: {
 | 
				
			||||||
 | 
					          showTitle: false,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        render: (note: string) => (
 | 
				
			||||||
 | 
					          <Tooltip placement="topLeft" title={note}>
 | 
				
			||||||
 | 
					            {note}
 | 
				
			||||||
 | 
					          </Tooltip>
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: "Created at",
 | 
				
			||||||
 | 
					        dataIndex: "created",
 | 
				
			||||||
 | 
					        width: "12%",
 | 
				
			||||||
 | 
					        responsive: ["xxl"],
 | 
				
			||||||
 | 
					        ellipsis: {
 | 
				
			||||||
 | 
					          showTitle: false,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        render: (note: string) => (
 | 
				
			||||||
 | 
					          <Tooltip placement="topLeft" title={note}>
 | 
				
			||||||
 | 
					            {note}
 | 
				
			||||||
 | 
					          </Tooltip>
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: "Actions",
 | 
				
			||||||
 | 
					        dataIndex: "action",
 | 
				
			||||||
 | 
					        width: "8%",
 | 
				
			||||||
 | 
					        render: (text: string, record: TTask) => {
 | 
				
			||||||
 | 
					          return (
 | 
				
			||||||
 | 
					            <div>
 | 
				
			||||||
 | 
					              {role === "Checker" ? (
 | 
				
			||||||
 | 
					                <Space>
 | 
				
			||||||
 | 
					                  {record.status === "New" && (
 | 
				
			||||||
 | 
					                    <Button
 | 
				
			||||||
 | 
					                      type="primary"
 | 
				
			||||||
 | 
					                      style={{ background: "#595959" }}
 | 
				
			||||||
 | 
					                      onClick={() => statusClick(record)}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      Assign
 | 
				
			||||||
 | 
					                    </Button>
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					                  {record.status === "Checking" &&
 | 
				
			||||||
 | 
					                    !!admin_id &&
 | 
				
			||||||
 | 
					                    record?.in_charge?.id === +admin_id && (
 | 
				
			||||||
 | 
					                      <Button
 | 
				
			||||||
 | 
					                        type="primary"
 | 
				
			||||||
 | 
					                        style={{ background: "#595959" }}
 | 
				
			||||||
 | 
					                        onClick={() => statusClick(record)}
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        Finish
 | 
				
			||||||
 | 
					                      </Button>
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
 | 
					                </Space>
 | 
				
			||||||
 | 
					              ) : (
 | 
				
			||||||
 | 
					                <Space>
 | 
				
			||||||
 | 
					                  <Button
 | 
				
			||||||
 | 
					                    type="primary"
 | 
				
			||||||
 | 
					                    danger
 | 
				
			||||||
 | 
					                    onClick={(e) => {
 | 
				
			||||||
 | 
					                      const shouldDelete = window.confirm(
 | 
				
			||||||
 | 
					                        "Are you sure, you want to delete this task?"
 | 
				
			||||||
 | 
					                      );
 | 
				
			||||||
 | 
					                      if (shouldDelete && record.id !== undefined) {
 | 
				
			||||||
 | 
					                        taskController.deleteTaskController(record.id);
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                    }}
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    Delete
 | 
				
			||||||
 | 
					                  </Button>
 | 
				
			||||||
 | 
					                </Space>
 | 
				
			||||||
 | 
					              )}
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (role === "Checker") {
 | 
				
			||||||
 | 
					      const teamColIndex = columns.findIndex((c) => c.title === "Team");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      teamColIndex !== -1 && columns.splice(teamColIndex, 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return columns;
 | 
				
			||||||
 | 
					  }, [role]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Table
 | 
				
			||||||
 | 
					        onRow={(record: any) => ({
 | 
				
			||||||
 | 
					          onClick: (event) => handleRowClick(record, event),
 | 
				
			||||||
 | 
					        })}
 | 
				
			||||||
 | 
					        dataSource={data?.characters?.map((u, i) => ({
 | 
				
			||||||
 | 
					          ...u,
 | 
				
			||||||
 | 
					          no: i + 1,
 | 
				
			||||||
 | 
					          created: moment(u?.created_at, "YYYY-MM-DD HH:mm:ss").format(
 | 
				
			||||||
 | 
					            "DD.MM.YYYY HH:mm"
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          key: u?.id,
 | 
				
			||||||
 | 
					        }))}
 | 
				
			||||||
 | 
					        size="small"
 | 
				
			||||||
 | 
					        columns={columns as any}
 | 
				
			||||||
 | 
					        pagination={false}
 | 
				
			||||||
 | 
					        loading={isLoading}
 | 
				
			||||||
 | 
					        rowClassName={rowClassName}
 | 
				
			||||||
 | 
					        bordered
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default TaskTable;
 | 
				
			||||||
@ -0,0 +1,114 @@
 | 
				
			|||||||
 | 
					import { Modal, Upload, Button, Space } from "antd";
 | 
				
			||||||
 | 
					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 { TTask } from "../../types/Tasks/TTasks";
 | 
				
			||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import TextArea from "antd/es/input/TextArea";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TaskUploadModal = ({
 | 
				
			||||||
 | 
					  uploadOpen,
 | 
				
			||||||
 | 
					  recordTask,
 | 
				
			||||||
 | 
					  setUploadOpen,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  recordTask: TTask | undefined;
 | 
				
			||||||
 | 
					  uploadOpen: boolean;
 | 
				
			||||||
 | 
					  setUploadOpen(open: boolean): void;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setUploadOpen(!uploadOpen);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [fileData, setFileData] = useState();
 | 
				
			||||||
 | 
					  const [text, setText] = useState<any>();
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Modal
 | 
				
			||||||
 | 
					      open={uploadOpen}
 | 
				
			||||||
 | 
					      title="Upload file"
 | 
				
			||||||
 | 
					      okText="Upload"
 | 
				
			||||||
 | 
					      cancelText="Cancel"
 | 
				
			||||||
 | 
					      onCancel={handleCancel}
 | 
				
			||||||
 | 
					      width={720}
 | 
				
			||||||
 | 
					      footer={
 | 
				
			||||||
 | 
					        <Space>
 | 
				
			||||||
 | 
					          <Button
 | 
				
			||||||
 | 
					            onClick={handleCancel}
 | 
				
			||||||
 | 
					            style={{ display: "flex", alignItems: "center" }}
 | 
				
			||||||
 | 
					            icon={<CloseOutlined />}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            Cancel
 | 
				
			||||||
 | 
					          </Button>
 | 
				
			||||||
 | 
					          <Button
 | 
				
			||||||
 | 
					            type="primary"
 | 
				
			||||||
 | 
					            onClick={() => {
 | 
				
			||||||
 | 
					              const updatedValues: any = {};
 | 
				
			||||||
 | 
					              updatedValues.task_id = recordTask?.id;
 | 
				
			||||||
 | 
					              updatedValues.file = fileData;
 | 
				
			||||||
 | 
					              updatedValues.description = text;
 | 
				
			||||||
 | 
					              taskController.addTaskFile(updatedValues).then(() => {
 | 
				
			||||||
 | 
					                setUploadOpen(!uploadOpen);
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					            icon={<img alt="" src={createIcon} />}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            Upload
 | 
				
			||||||
 | 
					          </Button>
 | 
				
			||||||
 | 
					        </Space>
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <div>
 | 
				
			||||||
 | 
					        <Upload.Dragger
 | 
				
			||||||
 | 
					          name="file"
 | 
				
			||||||
 | 
					          multiple={true}
 | 
				
			||||||
 | 
					          customRequest={({ file, onSuccess }: any) => {
 | 
				
			||||||
 | 
					            setFileData(file);
 | 
				
			||||||
 | 
					            if (file) {
 | 
				
			||||||
 | 
					              onSuccess();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <p className="ant-upload-drag-icon">
 | 
				
			||||||
 | 
					            <img src={uploadfile} alt="" />
 | 
				
			||||||
 | 
					          </p>
 | 
				
			||||||
 | 
					          <p
 | 
				
			||||||
 | 
					            className="ant-upload-text"
 | 
				
			||||||
 | 
					            style={{
 | 
				
			||||||
 | 
					              color: "rgba(15, 17, 28, 1)",
 | 
				
			||||||
 | 
					              fontWeight: 600,
 | 
				
			||||||
 | 
					              fontSize: 14,
 | 
				
			||||||
 | 
					              lineHeight: "20px",
 | 
				
			||||||
 | 
					              letterSpacing: "-1%",
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            Drag and drop files or{" "}
 | 
				
			||||||
 | 
					            <span style={{ color: "rgba(249, 158, 44, 1)" }}>
 | 
				
			||||||
 | 
					              Click to select
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					            <br />
 | 
				
			||||||
 | 
					            <span
 | 
				
			||||||
 | 
					              style={{
 | 
				
			||||||
 | 
					                color: "rgba(155, 157, 170, 1)",
 | 
				
			||||||
 | 
					                fontWeight: 400,
 | 
				
			||||||
 | 
					                fontSize: 13,
 | 
				
			||||||
 | 
					                lineHeight: "15.73px",
 | 
				
			||||||
 | 
					                letterSpacing: "-2%",
 | 
				
			||||||
 | 
					              }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              Maximum file size is 10 MB
 | 
				
			||||||
 | 
					            </span>
 | 
				
			||||||
 | 
					          </p>
 | 
				
			||||||
 | 
					        </Upload.Dragger>
 | 
				
			||||||
 | 
					        <TextArea
 | 
				
			||||||
 | 
					          style={{ padding: "7px 11px", marginTop: 20 }}
 | 
				
			||||||
 | 
					          placeholder="Description"
 | 
				
			||||||
 | 
					          autoSize={{ minRows: 3, maxRows: 3 }}
 | 
				
			||||||
 | 
					          onChange={(e) => setText(e.target.value)}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </Modal>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default TaskUploadModal;
 | 
				
			||||||
@ -0,0 +1,356 @@
 | 
				
			|||||||
 | 
					import { useCallback, useEffect, useRef, useState } from "react";
 | 
				
			||||||
 | 
					import AddTask from "./AddTask";
 | 
				
			||||||
 | 
					import { Button, Input, Select, Space, message, notification } from "antd";
 | 
				
			||||||
 | 
					import TaskTable from "./TaskTable";
 | 
				
			||||||
 | 
					import { useTeamData } from "../../Hooks/Teams";
 | 
				
			||||||
 | 
					import { StepForwardOutlined, StepBackwardOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					import { useTasks } from "../../Hooks/Tasks";
 | 
				
			||||||
 | 
					import { TTask } from "../../types/Tasks/TTasks";
 | 
				
			||||||
 | 
					import { useCompanyData } from "../../Hooks/Companies";
 | 
				
			||||||
 | 
					import { useCustomerData } from "../../Hooks/Customers";
 | 
				
			||||||
 | 
					import { useUserData } from "../../Hooks/Users";
 | 
				
			||||||
 | 
					import { useServiceData } from "../../Hooks/Services";
 | 
				
			||||||
 | 
					import { admin_id, role, team_id } from "../../App";
 | 
				
			||||||
 | 
					//@ts-ignore
 | 
				
			||||||
 | 
					import addicon from "../../assets/addiconpng.png";
 | 
				
			||||||
 | 
					//@ts-ignore
 | 
				
			||||||
 | 
					import refreshicon from "../../assets/refreshIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import IconSearch from "../../assets/searchIcon.png";
 | 
				
			||||||
 | 
					import TaskModal from "./TaskModal";
 | 
				
			||||||
 | 
					import TaskUploadModal from "./TaskUploadModal";
 | 
				
			||||||
 | 
					import { NotificationPlacement } from "antd/es/notification/interface";
 | 
				
			||||||
 | 
					import { TCall } from "../../types/CallRequests/TCall";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { Option } = Select;
 | 
				
			||||||
 | 
					const Task = () => {
 | 
				
			||||||
 | 
					  const [open, setOpen] = useState(false);
 | 
				
			||||||
 | 
					  const [modalOpen, setModalOpen] = useState(false);
 | 
				
			||||||
 | 
					  const [characters, setCharacters] = useState<TTask[] | undefined>();
 | 
				
			||||||
 | 
					  const [team, setTeam] = useState<any>();
 | 
				
			||||||
 | 
					  const [search, setSearch] = useState<string>("");
 | 
				
			||||||
 | 
					  const [status, setStatus] = useState<any>();
 | 
				
			||||||
 | 
					  const [page, setPage] = useState<any>(1);
 | 
				
			||||||
 | 
					  const [uploadOpen, setUploadOpen] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const CompanyData = useCompanyData({});
 | 
				
			||||||
 | 
					  const CustomerData = useCustomerData({});
 | 
				
			||||||
 | 
					  const AdminData = useUserData({});
 | 
				
			||||||
 | 
					  const ServiceData = useServiceData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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(() => {
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					      socketData &&
 | 
				
			||||||
 | 
					      ((role !== "Checker" &&
 | 
				
			||||||
 | 
					        (!team || team.includes(socketData?.task?.assigned_to?.id))) ||
 | 
				
			||||||
 | 
					        role === "Checker") &&
 | 
				
			||||||
 | 
					      (!status || status.includes(socketData.task.status))
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					      setCharacters((prev: TTask[] | undefined) => {
 | 
				
			||||||
 | 
					        if (prev && prev?.length >= 15) {
 | 
				
			||||||
 | 
					          prev?.pop();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (socketData.type === "task_create") {
 | 
				
			||||||
 | 
					          return [socketData.task, ...(prev || [])];
 | 
				
			||||||
 | 
					        } else if (socketData.type === "task_update") {
 | 
				
			||||||
 | 
					          if (role !== "Checker") {
 | 
				
			||||||
 | 
					            const updatedData =
 | 
				
			||||||
 | 
					              prev?.filter((b: TTask) => b.id !== socketData.task.id) || [];
 | 
				
			||||||
 | 
					            const data: TTask[] = [socketData.task, ...updatedData];
 | 
				
			||||||
 | 
					            data.sort((a: TTask, b: TTask) => {
 | 
				
			||||||
 | 
					              if (a.status === "New" && b.status === "New") {
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (a.status === "New") {
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (b.status === "New") {
 | 
				
			||||||
 | 
					                return 1;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              return 0;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            return data;
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            const data = (prev || []).map((b: TTask) =>
 | 
				
			||||||
 | 
					              b.id === socketData.task.id ? socketData.task : b
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            return data;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } else if (socketData.type === "task_delete") {
 | 
				
			||||||
 | 
					          const data = (prev || []).filter(
 | 
				
			||||||
 | 
					            (b: TTask) => b.id !== socketData.task.id
 | 
				
			||||||
 | 
					          );
 | 
				
			||||||
 | 
					          return data;
 | 
				
			||||||
 | 
					        } else if (socketData.type === "task_forward") {
 | 
				
			||||||
 | 
					          if (role === "Checker") {
 | 
				
			||||||
 | 
					            if (socketData.task.assigned_to.id === team_id) {
 | 
				
			||||||
 | 
					              return [socketData.task, ...(prev || [])];
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              const data = (prev || []).filter(
 | 
				
			||||||
 | 
					                (b: TTask) => b.id !== socketData.task.id
 | 
				
			||||||
 | 
					              );
 | 
				
			||||||
 | 
					              return data;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            const updatedData =
 | 
				
			||||||
 | 
					              prev?.filter((b: TTask) => b.id !== socketData.task.id) || [];
 | 
				
			||||||
 | 
					            const data: TTask[] = [socketData.task, ...updatedData];
 | 
				
			||||||
 | 
					            data.sort((a: TTask, b: TTask) => {
 | 
				
			||||||
 | 
					              if (a.status === "New" && b.status === "New") {
 | 
				
			||||||
 | 
					                return 0;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (a.status === "New") {
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (b.status === "New") {
 | 
				
			||||||
 | 
					                return 1;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              return 0;
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            return data;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } else if (socketData.type === "callback_request") {
 | 
				
			||||||
 | 
					          if (socketData?.callback_request) {
 | 
				
			||||||
 | 
					            console.log("run");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            openNotification("bottomRight", socketData?.callback_request);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return prev;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [socketData, openNotification]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const teamData = useTeamData("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const teamOptions: { label: string; value: any }[] | undefined =
 | 
				
			||||||
 | 
					    teamData?.data?.map((item) => ({
 | 
				
			||||||
 | 
					      label: item?.name,
 | 
				
			||||||
 | 
					      value: item?.id,
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { data, isLoading, refetch } = useTasks({
 | 
				
			||||||
 | 
					    search,
 | 
				
			||||||
 | 
					    status,
 | 
				
			||||||
 | 
					    team,
 | 
				
			||||||
 | 
					    page,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (data) {
 | 
				
			||||||
 | 
					      setCharacters(data?.data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [data]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    setPage(1);
 | 
				
			||||||
 | 
					  }, [search, status, team]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const showModal = () => {
 | 
				
			||||||
 | 
					    setOpen(true);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [recordTask, setRecordTask] = useState<TTask>();
 | 
				
			||||||
 | 
					  const showTaskModal = (e: TTask) => {
 | 
				
			||||||
 | 
					    setRecordTask(e);
 | 
				
			||||||
 | 
					    setModalOpen(true);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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 handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
 | 
				
			||||||
 | 
					    if (timerRef.current) {
 | 
				
			||||||
 | 
					      clearTimeout(timerRef.current);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const searchText = e.target.value;
 | 
				
			||||||
 | 
					    timerRef.current = setTimeout(() => {
 | 
				
			||||||
 | 
					      setSearch(searchText);
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const theme = localStorage.getItem("theme") === "true" ? true : false;
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      {contextHolder}
 | 
				
			||||||
 | 
					      {open && <AddTask open={open} setOpen={setOpen} />}
 | 
				
			||||||
 | 
					      {uploadOpen && (
 | 
				
			||||||
 | 
					        <TaskUploadModal
 | 
				
			||||||
 | 
					          recordTask={recordTask}
 | 
				
			||||||
 | 
					          uploadOpen={uploadOpen}
 | 
				
			||||||
 | 
					          setUploadOpen={setUploadOpen}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      {modalOpen && (
 | 
				
			||||||
 | 
					        <TaskModal
 | 
				
			||||||
 | 
					          uploadOpen={uploadOpen}
 | 
				
			||||||
 | 
					          setUploadOpen={setUploadOpen}
 | 
				
			||||||
 | 
					          recordTask={recordTask}
 | 
				
			||||||
 | 
					          modalOpen={modalOpen}
 | 
				
			||||||
 | 
					          setModalOpen={setModalOpen}
 | 
				
			||||||
 | 
					          refetch={refetch}
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					      <div className="header d-flex">
 | 
				
			||||||
 | 
					        <div className="header-title d-flex">
 | 
				
			||||||
 | 
					          <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 className="d-flex">
 | 
				
			||||||
 | 
					          {role !== "Checker" && (
 | 
				
			||||||
 | 
					            <button className="btn-add d-flex" onClick={showModal}>
 | 
				
			||||||
 | 
					              <img style={{ marginRight: 8 }} src={addicon} alt="" />
 | 
				
			||||||
 | 
					              Add Task
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            className={`btn-refresh-${theme && "dark"} d-flex`}
 | 
				
			||||||
 | 
					            onClick={() => {
 | 
				
			||||||
 | 
					              refetch();
 | 
				
			||||||
 | 
					              connect();
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <img style={{ marginRight: 8 }} src={refreshicon} alt="" />
 | 
				
			||||||
 | 
					            Refresh
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className="filter d-flex">
 | 
				
			||||||
 | 
					        <div className="search-div">
 | 
				
			||||||
 | 
					          <img src={IconSearch} alt="" />
 | 
				
			||||||
 | 
					          <input
 | 
				
			||||||
 | 
					            className={`search-input-${theme}`}
 | 
				
			||||||
 | 
					            type="text"
 | 
				
			||||||
 | 
					            placeholder="Search"
 | 
				
			||||||
 | 
					            onChange={handleSearchChange}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <Select
 | 
				
			||||||
 | 
					          style={{ width: 260, marginLeft: 12 }}
 | 
				
			||||||
 | 
					          placeholder="status"
 | 
				
			||||||
 | 
					          onChange={(value: any) => setStatus(value)}
 | 
				
			||||||
 | 
					          mode="multiple"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <Option value="New">New</Option>
 | 
				
			||||||
 | 
					          <Option value="Checking">Checking</Option>
 | 
				
			||||||
 | 
					          <Option value="Done">Done</Option>
 | 
				
			||||||
 | 
					        </Select>
 | 
				
			||||||
 | 
					        {role !== "Checker" && (
 | 
				
			||||||
 | 
					          <Select
 | 
				
			||||||
 | 
					            mode="multiple"
 | 
				
			||||||
 | 
					            style={{ width: 260, marginLeft: 12 }}
 | 
				
			||||||
 | 
					            placeholder="team"
 | 
				
			||||||
 | 
					            onChange={(value: any) => setTeam(value)}
 | 
				
			||||||
 | 
					            options={teamOptions}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        )}
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <TaskTable
 | 
				
			||||||
 | 
					        data={{ characters, CompanyData, CustomerData, ServiceData, AdminData }}
 | 
				
			||||||
 | 
					        isLoading={isLoading}
 | 
				
			||||||
 | 
					        refetch={refetch}
 | 
				
			||||||
 | 
					        showTaskModal={showTaskModal}
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <Space style={{ width: "100%", marginTop: 10 }} direction="vertical">
 | 
				
			||||||
 | 
					        <Space style={{ width: "100%", justifyContent: "flex-end" }} wrap>
 | 
				
			||||||
 | 
					          <Button
 | 
				
			||||||
 | 
					            type="primary"
 | 
				
			||||||
 | 
					            icon={<StepBackwardOutlined />}
 | 
				
			||||||
 | 
					            onClick={Previos}
 | 
				
			||||||
 | 
					          ></Button>
 | 
				
			||||||
 | 
					          <Input
 | 
				
			||||||
 | 
					            style={{ width: 50, textAlign: "right" }}
 | 
				
			||||||
 | 
					            value={page}
 | 
				
			||||||
 | 
					            onChange={(e) => {
 | 
				
			||||||
 | 
					              let num = e.target.value;
 | 
				
			||||||
 | 
					              if (Number(num) && num !== "0") {
 | 
				
			||||||
 | 
					                setPage(num);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					          <Button
 | 
				
			||||||
 | 
					            type="primary"
 | 
				
			||||||
 | 
					            icon={<StepForwardOutlined />}
 | 
				
			||||||
 | 
					            onClick={Next}
 | 
				
			||||||
 | 
					          ></Button>
 | 
				
			||||||
 | 
					        </Space>
 | 
				
			||||||
 | 
					      </Space>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Task;
 | 
				
			||||||
@ -0,0 +1,76 @@
 | 
				
			|||||||
 | 
					import { Input, Modal, Form as FormAnt, Select } from "antd";
 | 
				
			||||||
 | 
					import { teamController } from "../../API/LayoutApi/teams";
 | 
				
			||||||
 | 
					import { useUserData } from "../../Hooks/Users";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AddTeam = ({
 | 
				
			||||||
 | 
					  open,
 | 
				
			||||||
 | 
					  setOpen,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  open: boolean;
 | 
				
			||||||
 | 
					  setOpen(open: boolean): void;
 | 
				
			||||||
 | 
					  refetch(): void;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const [form] = FormAnt.useForm();
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setOpen(!open);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const { data } = useUserData({ name: "", team: "", role: "Checker" });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Modal
 | 
				
			||||||
 | 
					        open={open}
 | 
				
			||||||
 | 
					        title="Add new team"
 | 
				
			||||||
 | 
					        okText="Create"
 | 
				
			||||||
 | 
					        cancelText="Cancel"
 | 
				
			||||||
 | 
					        onCancel={handleCancel}
 | 
				
			||||||
 | 
					        onOk={() => {
 | 
				
			||||||
 | 
					          form
 | 
				
			||||||
 | 
					            .validateFields()
 | 
				
			||||||
 | 
					            .then(async (values) => {
 | 
				
			||||||
 | 
					              form.resetFields();
 | 
				
			||||||
 | 
					              await teamController.addTeamController(values);
 | 
				
			||||||
 | 
					              setOpen(!open);
 | 
				
			||||||
 | 
					              refetch();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					              refetch();
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <FormAnt
 | 
				
			||||||
 | 
					          form={form}
 | 
				
			||||||
 | 
					          layout="horizontal"
 | 
				
			||||||
 | 
					          name="form_in_modal"
 | 
				
			||||||
 | 
					          initialValues={{ modifier: "public" }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Name"
 | 
				
			||||||
 | 
					            name="name"
 | 
				
			||||||
 | 
					            rules={[{ required: true, message: "Please input team name!" }]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Input />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Include users to this team"
 | 
				
			||||||
 | 
					            name="user_ids"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: false, message: "Please input company status!" },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Select
 | 
				
			||||||
 | 
					              mode="multiple"
 | 
				
			||||||
 | 
					              options={data?.map((items) => ({
 | 
				
			||||||
 | 
					                label: items.username,
 | 
				
			||||||
 | 
					                value: items.id,
 | 
				
			||||||
 | 
					              }))}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					        </FormAnt>
 | 
				
			||||||
 | 
					      </Modal>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default AddTeam;
 | 
				
			||||||
@ -0,0 +1,200 @@
 | 
				
			|||||||
 | 
					import React, { useState } from "react";
 | 
				
			||||||
 | 
					import { useNavigate, useParams } from "react-router-dom";
 | 
				
			||||||
 | 
					import { useTeamOne } from "../../Hooks/Teams";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Form,
 | 
				
			||||||
 | 
					  Spin,
 | 
				
			||||||
 | 
					  Watermark,
 | 
				
			||||||
 | 
					  Space,
 | 
				
			||||||
 | 
					  Tabs,
 | 
				
			||||||
 | 
					  Row,
 | 
				
			||||||
 | 
					  Col,
 | 
				
			||||||
 | 
					  Input,
 | 
				
			||||||
 | 
					  Button,
 | 
				
			||||||
 | 
					  Table,
 | 
				
			||||||
 | 
					} from "antd";
 | 
				
			||||||
 | 
					import { teamController } from "../../API/LayoutApi/teams";
 | 
				
			||||||
 | 
					import { FormOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					import Notfound from "../../Utils/Notfound";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					import { useUserData } from "../../Hooks/Users";
 | 
				
			||||||
 | 
					import AddUserToTeam from "./AddUserToTeam";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIcon from "../../assets/infoIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIconActive from "../../assets/infoIconActive.png";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TabPane = Tabs.TabPane;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type params = {
 | 
				
			||||||
 | 
					  readonly id: any;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type MyObjectType = {
 | 
				
			||||||
 | 
					  [key: string | number]: any;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const TeamEdit = () => {
 | 
				
			||||||
 | 
					  const { id } = useParams<params>();
 | 
				
			||||||
 | 
					  const { data, refetch, status }: MyObjectType = useTeamOne(id);
 | 
				
			||||||
 | 
					  let navigate = useNavigate();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onSubmit = async (value: any) => {
 | 
				
			||||||
 | 
					    await teamController.teamPatch(value, id);
 | 
				
			||||||
 | 
					    refetch();
 | 
				
			||||||
 | 
					    navigate(-1);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const ClickDelete = () => {
 | 
				
			||||||
 | 
					    const shouldDelete = window.confirm(
 | 
				
			||||||
 | 
					      "Вы уверены, что хотите удалить эту команду?"
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    if (shouldDelete && id !== undefined) {
 | 
				
			||||||
 | 
					      teamController.deleteTeamController(id).then((data: any) => {
 | 
				
			||||||
 | 
					        navigate(-1);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const userData = useUserData({ name: "", team: id });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [open, setOpen] = useState(false);
 | 
				
			||||||
 | 
					  const showModal = () => {
 | 
				
			||||||
 | 
					    setOpen(true);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [activeTab, setActiveTab] = useState("1");
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					        <Watermark style={{ height: "100%" }}>
 | 
				
			||||||
 | 
					          {status === "loading" ? (
 | 
				
			||||||
 | 
					            <Spin size="large" spinning={!data} />
 | 
				
			||||||
 | 
					          ) : data ? (
 | 
				
			||||||
 | 
					            <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					              <Space
 | 
				
			||||||
 | 
					                direction="vertical"
 | 
				
			||||||
 | 
					                size="middle"
 | 
				
			||||||
 | 
					                style={{ display: "flex" }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <Tabs
 | 
				
			||||||
 | 
					                  defaultActiveKey="1"
 | 
				
			||||||
 | 
					                  activeKey={activeTab}
 | 
				
			||||||
 | 
					                  onChange={(key) => setActiveTab(key)}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <TabPane
 | 
				
			||||||
 | 
					                    tab={
 | 
				
			||||||
 | 
					                      <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					                        <img
 | 
				
			||||||
 | 
					                          style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                          src={activeTab === "1" ? infoIconActive : infoIcon}
 | 
				
			||||||
 | 
					                          alt=""
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                        Information
 | 
				
			||||||
 | 
					                      </span>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    key="1"
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <Space
 | 
				
			||||||
 | 
					                      direction="vertical"
 | 
				
			||||||
 | 
					                      size="middle"
 | 
				
			||||||
 | 
					                      style={{ display: "flex" }}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <Form
 | 
				
			||||||
 | 
					                        name="basic"
 | 
				
			||||||
 | 
					                        layout="vertical"
 | 
				
			||||||
 | 
					                        wrapperCol={{ span: 16 }}
 | 
				
			||||||
 | 
					                        initialValues={{ ...data }}
 | 
				
			||||||
 | 
					                        onFinish={onSubmit}
 | 
				
			||||||
 | 
					                        autoComplete="off"
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        <Row gutter={[16, 10]}>
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="Name"
 | 
				
			||||||
 | 
					                              name="name"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Input />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                        </Row>
 | 
				
			||||||
 | 
					                        <Form.Item>
 | 
				
			||||||
 | 
					                          {role !== "Checker" && (
 | 
				
			||||||
 | 
					                            <Button
 | 
				
			||||||
 | 
					                              onClick={() => ClickDelete()}
 | 
				
			||||||
 | 
					                              type="primary"
 | 
				
			||||||
 | 
					                              style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                              danger
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              Delete
 | 
				
			||||||
 | 
					                            </Button>
 | 
				
			||||||
 | 
					                          )}
 | 
				
			||||||
 | 
					                          <Button type="primary" htmlType="submit">
 | 
				
			||||||
 | 
					                            Submit
 | 
				
			||||||
 | 
					                          </Button>
 | 
				
			||||||
 | 
					                        </Form.Item>
 | 
				
			||||||
 | 
					                      </Form>
 | 
				
			||||||
 | 
					                    </Space>
 | 
				
			||||||
 | 
					                  </TabPane>
 | 
				
			||||||
 | 
					                  <TabPane
 | 
				
			||||||
 | 
					                    tab={
 | 
				
			||||||
 | 
					                      <span>
 | 
				
			||||||
 | 
					                        <FormOutlined />
 | 
				
			||||||
 | 
					                        Users
 | 
				
			||||||
 | 
					                      </span>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    key="2"
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <Table
 | 
				
			||||||
 | 
					                      dataSource={userData?.data?.map((item, i) => ({
 | 
				
			||||||
 | 
					                        no: i + 1,
 | 
				
			||||||
 | 
					                        ...item,
 | 
				
			||||||
 | 
					                      }))}
 | 
				
			||||||
 | 
					                      columns={[
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                          title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					                          dataIndex: "no",
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                          title: "Username",
 | 
				
			||||||
 | 
					                          dataIndex: "username",
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                          title: "First name",
 | 
				
			||||||
 | 
					                          dataIndex: "first_name",
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        {
 | 
				
			||||||
 | 
					                          title: "Last name",
 | 
				
			||||||
 | 
					                          dataIndex: "last_name",
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                      ]}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <AddUserToTeam
 | 
				
			||||||
 | 
					                      team={id}
 | 
				
			||||||
 | 
					                      refetch={refetch}
 | 
				
			||||||
 | 
					                      open={open}
 | 
				
			||||||
 | 
					                      setOpen={setOpen}
 | 
				
			||||||
 | 
					                    />
 | 
				
			||||||
 | 
					                    <Button
 | 
				
			||||||
 | 
					                      type="primary"
 | 
				
			||||||
 | 
					                      style={{ marginLeft: "auto" }}
 | 
				
			||||||
 | 
					                      size={"large"}
 | 
				
			||||||
 | 
					                      onClick={showModal}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      Add User
 | 
				
			||||||
 | 
					                    </Button>
 | 
				
			||||||
 | 
					                  </TabPane>
 | 
				
			||||||
 | 
					                </Tabs>
 | 
				
			||||||
 | 
					              </Space>
 | 
				
			||||||
 | 
					            </Spin>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            <Notfound />
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        </Watermark>
 | 
				
			||||||
 | 
					      </Spin>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default TeamEdit;
 | 
				
			||||||
@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					// // @ts-ignore
 | 
				
			||||||
 | 
					// import closeIcon from "../../assets/closeIcon.png";
 | 
				
			||||||
 | 
					// // @ts-ignore
 | 
				
			||||||
 | 
					// import editIcon from "../../assets/editIcon.png";
 | 
				
			||||||
 | 
					// // @ts-ignore
 | 
				
			||||||
 | 
					// import deleteIcon from "../../assets/deleteIconRed.png";
 | 
				
			||||||
 | 
					// import { TTeam } from "../../types/Team/TTeam";
 | 
				
			||||||
 | 
					// import { Table } from "antd";
 | 
				
			||||||
 | 
					// // @ts-ignore
 | 
				
			||||||
 | 
					// import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					// import { useUserByTeam } from "../../Hooks/Users";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// const TeamModal = ({
 | 
				
			||||||
 | 
					//   modalOpen,
 | 
				
			||||||
 | 
					//   setModalOpen,
 | 
				
			||||||
 | 
					//   recordTeam,
 | 
				
			||||||
 | 
					// }: {
 | 
				
			||||||
 | 
					//   recordTeam: TTeam | undefined;
 | 
				
			||||||
 | 
					//   modalOpen: any;
 | 
				
			||||||
 | 
					//   setModalOpen: any;
 | 
				
			||||||
 | 
					// }) => {
 | 
				
			||||||
 | 
					//   const handleCancel = () => {
 | 
				
			||||||
 | 
					//     setModalOpen(!modalOpen);
 | 
				
			||||||
 | 
					//   };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//   const { data, isLoading, refetch } = useUserByTeam(recordTeam?.uuid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//   return (
 | 
				
			||||||
 | 
					//     <div className="TaskModal">
 | 
				
			||||||
 | 
					//       <div className="TaskModal-header">
 | 
				
			||||||
 | 
					//         <div className="TaskModal-title">
 | 
				
			||||||
 | 
					//           <p className="p-driver">{recordTeam?.name}</p>
 | 
				
			||||||
 | 
					//         </div>
 | 
				
			||||||
 | 
					//         <div className="mdoal-actions">
 | 
				
			||||||
 | 
					//           <button className="btn-modal-action">
 | 
				
			||||||
 | 
					//             <img src={editIcon} alt="" />
 | 
				
			||||||
 | 
					//             Edit
 | 
				
			||||||
 | 
					//           </button>
 | 
				
			||||||
 | 
					//           <button style={{ marginLeft: 12 }} className="btn-modal-action">
 | 
				
			||||||
 | 
					//             <img src={deleteIcon} alt="" />
 | 
				
			||||||
 | 
					//             Delete
 | 
				
			||||||
 | 
					//           </button>
 | 
				
			||||||
 | 
					//           <button
 | 
				
			||||||
 | 
					//             onClick={handleCancel}
 | 
				
			||||||
 | 
					//             style={{ marginLeft: 20 }}
 | 
				
			||||||
 | 
					//             className="btn-modal-action"
 | 
				
			||||||
 | 
					//           >
 | 
				
			||||||
 | 
					//             <img style={{ margin: 2 }} src={closeIcon} alt="" />
 | 
				
			||||||
 | 
					//           </button>
 | 
				
			||||||
 | 
					//         </div>
 | 
				
			||||||
 | 
					//       </div>
 | 
				
			||||||
 | 
					//       <div className="TaskModal-content">
 | 
				
			||||||
 | 
					//         <p
 | 
				
			||||||
 | 
					//           style={{
 | 
				
			||||||
 | 
					//             fontSize: 18,
 | 
				
			||||||
 | 
					//             fontWeight: 700,
 | 
				
			||||||
 | 
					//             lineHeight: "24px",
 | 
				
			||||||
 | 
					//             letterSpacing: "-0.02em",
 | 
				
			||||||
 | 
					//             marginLeft: 24
 | 
				
			||||||
 | 
					//           }}
 | 
				
			||||||
 | 
					//         >
 | 
				
			||||||
 | 
					//           Users
 | 
				
			||||||
 | 
					//         </p>
 | 
				
			||||||
 | 
					//         <div className="users-table-by-team">
 | 
				
			||||||
 | 
					//           <Table
 | 
				
			||||||
 | 
					//             loading={isLoading}
 | 
				
			||||||
 | 
					//             rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					//               index % 2 === 0 ? "even-row" : "odd-row"
 | 
				
			||||||
 | 
					//             }
 | 
				
			||||||
 | 
					//             dataSource={data?.map((u, i) => {
 | 
				
			||||||
 | 
					//               return {
 | 
				
			||||||
 | 
					//                 ...u,
 | 
				
			||||||
 | 
					//                 no: i + 1,
 | 
				
			||||||
 | 
					//                 key: u?.uid,
 | 
				
			||||||
 | 
					//               };
 | 
				
			||||||
 | 
					//             })}
 | 
				
			||||||
 | 
					//             columns={[
 | 
				
			||||||
 | 
					//               {
 | 
				
			||||||
 | 
					//                 title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					//                 dataIndex: "no",
 | 
				
			||||||
 | 
					//                 width: "5%",
 | 
				
			||||||
 | 
					//               },
 | 
				
			||||||
 | 
					//               {
 | 
				
			||||||
 | 
					//                 title: "Name",
 | 
				
			||||||
 | 
					//                 dataIndex: "full_name",
 | 
				
			||||||
 | 
					//               },
 | 
				
			||||||
 | 
					//               {
 | 
				
			||||||
 | 
					//                 title: "Username",
 | 
				
			||||||
 | 
					//                 dataIndex: "username",
 | 
				
			||||||
 | 
					//               },
 | 
				
			||||||
 | 
					//               {
 | 
				
			||||||
 | 
					//                 title: "Actions",
 | 
				
			||||||
 | 
					//                 dataIndex: "actions",
 | 
				
			||||||
 | 
					//               },
 | 
				
			||||||
 | 
					//             ]}
 | 
				
			||||||
 | 
					//           />
 | 
				
			||||||
 | 
					//         </div>
 | 
				
			||||||
 | 
					//       </div>
 | 
				
			||||||
 | 
					//     </div>
 | 
				
			||||||
 | 
					//   );
 | 
				
			||||||
 | 
					// };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// export default TeamModal;
 | 
				
			||||||
 | 
					import React from 'react'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const TeamModal = () => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>TeamModal</div>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default TeamModal
 | 
				
			||||||
@ -0,0 +1,86 @@
 | 
				
			|||||||
 | 
					import { Table, Tag } from "antd";
 | 
				
			||||||
 | 
					import { TTeam } from "../../types/Team/TTeam";
 | 
				
			||||||
 | 
					import { useNavigate } from "react-router-dom";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					import { timeZone } from "../../App";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					const TeamTable = ({
 | 
				
			||||||
 | 
					  data,
 | 
				
			||||||
 | 
					  isLoading,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  data: TTeam[] | undefined;
 | 
				
			||||||
 | 
					  isLoading: boolean | undefined;
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TTeam[], unknown>>;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					  const moment = require("moment-timezone");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Table
 | 
				
			||||||
 | 
					      loading={isLoading}
 | 
				
			||||||
 | 
					      onRow={(record) => {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          onClick: () => {
 | 
				
			||||||
 | 
					            navigate(`/teams/${record.id}`);
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					      dataSource={data?.map((u, i) => ({
 | 
				
			||||||
 | 
					        ...u,
 | 
				
			||||||
 | 
					        no: i + 1,
 | 
				
			||||||
 | 
					        action: { id: u.id },
 | 
				
			||||||
 | 
					        created: moment(u?.created_at).tz(timeZone).format("DD.MM.YYYY HH:mm"),
 | 
				
			||||||
 | 
					        key: u.id,
 | 
				
			||||||
 | 
					      }))}
 | 
				
			||||||
 | 
					      size="middle"
 | 
				
			||||||
 | 
					      columns={[
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					          dataIndex: "no",
 | 
				
			||||||
 | 
					          width: "5%",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          title: "Name",
 | 
				
			||||||
 | 
					          dataIndex: "name",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          title: "Created at",
 | 
				
			||||||
 | 
					          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"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    />
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default TeamTable;
 | 
				
			||||||
@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import { useTeamData } from "../../Hooks/Teams";
 | 
				
			||||||
 | 
					import TeamTable from "./TeamTable";
 | 
				
			||||||
 | 
					//@ts-ignore
 | 
				
			||||||
 | 
					import addicon from "../../assets/addiconpng.png";
 | 
				
			||||||
 | 
					import AddTeam from "./AddTeam";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Team = () => {
 | 
				
			||||||
 | 
					  const { data, isLoading, refetch } = useTeamData("");
 | 
				
			||||||
 | 
					  const [open, setOpen] = useState(false);
 | 
				
			||||||
 | 
					  const showModal = () => {
 | 
				
			||||||
 | 
					    setOpen(true);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      {open && <AddTeam refetch={refetch} open={open} setOpen={setOpen} />}
 | 
				
			||||||
 | 
					      <div className="header d-flex" style={{ marginBottom: 16 }}>
 | 
				
			||||||
 | 
					        <p className="title">Teams</p>
 | 
				
			||||||
 | 
					        <button
 | 
				
			||||||
 | 
					          className="btn-add d-flex"
 | 
				
			||||||
 | 
					          style={{ marginRight: 0 }}
 | 
				
			||||||
 | 
					          onClick={showModal}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <img src={addicon} style={{ marginRight: 8 }} alt="" />
 | 
				
			||||||
 | 
					          Add
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <TeamTable data={data} isLoading={isLoading} refetch={refetch} />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Team;
 | 
				
			||||||
@ -0,0 +1,198 @@
 | 
				
			|||||||
 | 
					import { Input, Modal, Form as FormAnt, Select, Upload } from "antd";
 | 
				
			||||||
 | 
					import { updateController } from "../../API/LayoutApi/update";
 | 
				
			||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import { UploadOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					import { taskController } from "../../API/LayoutApi/tasks";
 | 
				
			||||||
 | 
					import { useCompanyData } from "../../Hooks/Companies";
 | 
				
			||||||
 | 
					import { useCustomerByComanyData } from "../../Hooks/Customers";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					import { TUpdate } from "../../types/Update/TUpdate";
 | 
				
			||||||
 | 
					const { Option } = Select;
 | 
				
			||||||
 | 
					const AddUpdate = ({
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					  open,
 | 
				
			||||||
 | 
					  setOpen,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TUpdate[], unknown>>;
 | 
				
			||||||
 | 
					  open: boolean;
 | 
				
			||||||
 | 
					  setOpen(open: boolean): void;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const [form] = FormAnt.useForm();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    refetch();
 | 
				
			||||||
 | 
					    setOpen(!open);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [fileIds, setFileIds] = useState([]);
 | 
				
			||||||
 | 
					  const [companyName, setCompanyName] = useState<string>("");
 | 
				
			||||||
 | 
					  const [customerName, setCustomerName] = useState<string>("");
 | 
				
			||||||
 | 
					  const [companyId, setCompanyId] = useState<string>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const companyData = useCompanyData({ name: companyName });
 | 
				
			||||||
 | 
					  const customerData = useCustomerByComanyData({
 | 
				
			||||||
 | 
					    id: companyId,
 | 
				
			||||||
 | 
					    name: customerName,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [imgname, setImgname] = useState<any>([]);
 | 
				
			||||||
 | 
					  function handlePaste(event: any) {
 | 
				
			||||||
 | 
					    const clipboardData = event.clipboardData || window.Clipboard;
 | 
				
			||||||
 | 
					    if (clipboardData && clipboardData.items.length > 0) {
 | 
				
			||||||
 | 
					      const clipboardItem = clipboardData.items[0];
 | 
				
			||||||
 | 
					      if (clipboardItem.kind === "file") {
 | 
				
			||||||
 | 
					        const file = clipboardItem.getAsFile();
 | 
				
			||||||
 | 
					        const formData = new FormData();
 | 
				
			||||||
 | 
					        formData.append("file", file);
 | 
				
			||||||
 | 
					        taskController.addTaskFile(formData).then((response) => {
 | 
				
			||||||
 | 
					          const fileId = response.id;
 | 
				
			||||||
 | 
					          const n = [response.file];
 | 
				
			||||||
 | 
					          setImgname((prev: any) => [...prev, ...n]);
 | 
				
			||||||
 | 
					          setFileIds((prevFileIds): any => [...prevFileIds, fileId]);
 | 
				
			||||||
 | 
					          const updatedValues = form.getFieldsValue();
 | 
				
			||||||
 | 
					          updatedValues.attachment_ids = [
 | 
				
			||||||
 | 
					            ...updatedValues.attachment_ids,
 | 
				
			||||||
 | 
					            fileId,
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					          form.setFieldsValue(updatedValues);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div onPaste={(event) => handlePaste(event)}>
 | 
				
			||||||
 | 
					      <Modal
 | 
				
			||||||
 | 
					        open={open}
 | 
				
			||||||
 | 
					        title="Add update"
 | 
				
			||||||
 | 
					        okText="Create"
 | 
				
			||||||
 | 
					        cancelText="Cancel"
 | 
				
			||||||
 | 
					        onCancel={handleCancel}
 | 
				
			||||||
 | 
					        onOk={() => {
 | 
				
			||||||
 | 
					          form.validateFields().then(async (values) => {
 | 
				
			||||||
 | 
					            const updatedValues = { ...values };
 | 
				
			||||||
 | 
					            updatedValues.attachment_ids = fileIds;
 | 
				
			||||||
 | 
					            form.resetFields();
 | 
				
			||||||
 | 
					            await updateController.addUpdateController(updatedValues);
 | 
				
			||||||
 | 
					            setOpen(!open);
 | 
				
			||||||
 | 
					            refetch();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <FormAnt
 | 
				
			||||||
 | 
					          form={form}
 | 
				
			||||||
 | 
					          layout="horizontal"
 | 
				
			||||||
 | 
					          name="form_in_modal"
 | 
				
			||||||
 | 
					          initialValues={{ modifier: "public" }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Company"
 | 
				
			||||||
 | 
					            name="company_id"
 | 
				
			||||||
 | 
					            rules={[{ required: false, message: "Please input company!" }]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Select
 | 
				
			||||||
 | 
					              showSearch
 | 
				
			||||||
 | 
					              placeholder="Search Company"
 | 
				
			||||||
 | 
					              onSearch={(value: any) => setCompanyName(value)}
 | 
				
			||||||
 | 
					              options={companyData?.data?.map((item) => ({
 | 
				
			||||||
 | 
					                label: item?.name,
 | 
				
			||||||
 | 
					                value: item?.id,
 | 
				
			||||||
 | 
					              }))}
 | 
				
			||||||
 | 
					              value={companyName}
 | 
				
			||||||
 | 
					              filterOption={false}
 | 
				
			||||||
 | 
					              autoClearSearchValue={false}
 | 
				
			||||||
 | 
					              allowClear
 | 
				
			||||||
 | 
					              onChange={(value: any) => setCompanyId(value)}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Driver"
 | 
				
			||||||
 | 
					            name="customer_id"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: false, message: "Please input service points!" },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <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
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Note"
 | 
				
			||||||
 | 
					            name="note"
 | 
				
			||||||
 | 
					            rules={[{ required: true, message: "Make note!" }]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Input />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Status"
 | 
				
			||||||
 | 
					            name="status"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: false, message: "Please input service points!" },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Select defaultValue="New" style={{ width: 120 }}>
 | 
				
			||||||
 | 
					              <Option value="New">New</Option>
 | 
				
			||||||
 | 
					              <Option value="In Progress">In Progress</Option>
 | 
				
			||||||
 | 
					              <Option value="Done">Done</Option>
 | 
				
			||||||
 | 
					              <Option value="Paper">Paper</Option>
 | 
				
			||||||
 | 
					              <Option value="Setup">Setup</Option>
 | 
				
			||||||
 | 
					            </Select>
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					        </FormAnt>
 | 
				
			||||||
 | 
					        <FormAnt>
 | 
				
			||||||
 | 
					          <FormAnt.Item label="File" name="attachment">
 | 
				
			||||||
 | 
					            <Upload.Dragger
 | 
				
			||||||
 | 
					              name="file"
 | 
				
			||||||
 | 
					              multiple={true}
 | 
				
			||||||
 | 
					              customRequest={({ file, onSuccess }: any) => {
 | 
				
			||||||
 | 
					                const formData = new FormData();
 | 
				
			||||||
 | 
					                formData.append("file", file);
 | 
				
			||||||
 | 
					                taskController
 | 
				
			||||||
 | 
					                  .addTaskFile(formData)
 | 
				
			||||||
 | 
					                  .then((response) => {
 | 
				
			||||||
 | 
					                    const fileId = response.id;
 | 
				
			||||||
 | 
					                    setFileIds((prevFileIds): any => [...prevFileIds, fileId]);
 | 
				
			||||||
 | 
					                    onSuccess();
 | 
				
			||||||
 | 
					                    const updatedValues = form.getFieldsValue();
 | 
				
			||||||
 | 
					                    updatedValues.attachment_ids = [
 | 
				
			||||||
 | 
					                      ...updatedValues.attachment_ids,
 | 
				
			||||||
 | 
					                      fileId,
 | 
				
			||||||
 | 
					                    ];
 | 
				
			||||||
 | 
					                    form.setFieldsValue(updatedValues);
 | 
				
			||||||
 | 
					                  })
 | 
				
			||||||
 | 
					                  .catch((error) => {
 | 
				
			||||||
 | 
					                    onSuccess(error);
 | 
				
			||||||
 | 
					                  });
 | 
				
			||||||
 | 
					              }}
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <p className="ant-upload-drag-icon">
 | 
				
			||||||
 | 
					                <UploadOutlined style={{ color: "#36cfc9" }} />
 | 
				
			||||||
 | 
					              </p>
 | 
				
			||||||
 | 
					              <p className="ant-upload-text" style={{ color: "#36cfc9" }}>
 | 
				
			||||||
 | 
					                Click or drag file to this area to upload
 | 
				
			||||||
 | 
					              </p>
 | 
				
			||||||
 | 
					            </Upload.Dragger>
 | 
				
			||||||
 | 
					            <p>{imgname.join(",\n")}</p>
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					        </FormAnt>
 | 
				
			||||||
 | 
					      </Modal>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default AddUpdate;
 | 
				
			||||||
@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					import AddUpdate from "./AddUpdate";
 | 
				
			||||||
 | 
					import { Button, Select } from "antd";
 | 
				
			||||||
 | 
					import UpdateTable from "./UpdateTable";
 | 
				
			||||||
 | 
					import { useUpdateData } from "../../Hooks/Update";
 | 
				
			||||||
 | 
					//@ts-ignore
 | 
				
			||||||
 | 
					import addicon from "../../assets/addiconpng.png";
 | 
				
			||||||
 | 
					//@ts-ignore
 | 
				
			||||||
 | 
					import refreshicon from "../../assets/refreshIcon.png";
 | 
				
			||||||
 | 
					const Update = () => {
 | 
				
			||||||
 | 
					  const [open, setOpen] = useState(false);
 | 
				
			||||||
 | 
					  const [status, setStatus] = useState<any>([
 | 
				
			||||||
 | 
					    "New",
 | 
				
			||||||
 | 
					    "In Progress",
 | 
				
			||||||
 | 
					    "Paper",
 | 
				
			||||||
 | 
					    "Setup",
 | 
				
			||||||
 | 
					  ]);
 | 
				
			||||||
 | 
					  const { Option } = Select;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { data, refetch, isLoading } = useUpdateData(status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const showModal = () => {
 | 
				
			||||||
 | 
					    setOpen(true);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const theme = localStorage.getItem("theme") === "true" ? true : false;
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      {open && <AddUpdate refetch={refetch} open={open} setOpen={setOpen} />}
 | 
				
			||||||
 | 
					      <div className="header d-flex" style={{ marginBottom: 16 }}>
 | 
				
			||||||
 | 
					        <p className="title">Updates</p>
 | 
				
			||||||
 | 
					        <div className="d-flex">
 | 
				
			||||||
 | 
					          <button className="btn-add d-flex" onClick={showModal}>
 | 
				
			||||||
 | 
					            <img style={{ marginRight: 8 }} src={addicon} alt="" />
 | 
				
			||||||
 | 
					            Add
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button
 | 
				
			||||||
 | 
					            className={`btn-refresh-${theme && "dark"} d-flex`}
 | 
				
			||||||
 | 
					            onClick={() => {
 | 
				
			||||||
 | 
					              refetch();
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <img style={{ marginRight: 8 }} src={refreshicon} alt="" />
 | 
				
			||||||
 | 
					            Refresh
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className="filter d-flex">
 | 
				
			||||||
 | 
					        <Select
 | 
				
			||||||
 | 
					          style={{ width: 260, marginLeft: 10 }}
 | 
				
			||||||
 | 
					          placeholder="status"
 | 
				
			||||||
 | 
					          onChange={(value: any) => setStatus(value)}
 | 
				
			||||||
 | 
					          mode="multiple"
 | 
				
			||||||
 | 
					          defaultValue={[]}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <Option value="New">New</Option>
 | 
				
			||||||
 | 
					          <Option value="In Progress">In Progress</Option>
 | 
				
			||||||
 | 
					          <Option value="Done">Done</Option>
 | 
				
			||||||
 | 
					          <Option value="Paper">Paper</Option>
 | 
				
			||||||
 | 
					          <Option value="Setup">Setup</Option>
 | 
				
			||||||
 | 
					        </Select>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <UpdateTable data={data} refetch={refetch} isLoading={isLoading} />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Update;
 | 
				
			||||||
@ -0,0 +1,439 @@
 | 
				
			|||||||
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
 | 
					import { useParams } from "react-router-dom";
 | 
				
			||||||
 | 
					import { useUpdateOne } from "../../Hooks/Update";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Form,
 | 
				
			||||||
 | 
					  Spin,
 | 
				
			||||||
 | 
					  Watermark,
 | 
				
			||||||
 | 
					  Space,
 | 
				
			||||||
 | 
					  Tabs,
 | 
				
			||||||
 | 
					  Row,
 | 
				
			||||||
 | 
					  Col,
 | 
				
			||||||
 | 
					  Input,
 | 
				
			||||||
 | 
					  Button,
 | 
				
			||||||
 | 
					  Select,
 | 
				
			||||||
 | 
					  Upload,
 | 
				
			||||||
 | 
					} from "antd";
 | 
				
			||||||
 | 
					import { updateController } from "../../API/LayoutApi/update";
 | 
				
			||||||
 | 
					import { UploadOutlined } from "@ant-design/icons";
 | 
				
			||||||
 | 
					import Notfound from "../../Utils/Notfound";
 | 
				
			||||||
 | 
					import { companyController } from "../../API/LayoutApi/companies";
 | 
				
			||||||
 | 
					import { customerController } from "../../API/LayoutApi/customers";
 | 
				
			||||||
 | 
					import { taskController } from "../../API/LayoutApi/tasks";
 | 
				
			||||||
 | 
					import TextArea from "antd/es/input/TextArea";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIcon from "../../assets/infoIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIconActive from "../../assets/infoIconActive.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import attachmentIcon from "../../assets/attachmentIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import attachmentIconActive from "../../assets/attachmentIconActive.png";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const { Option } = Select;
 | 
				
			||||||
 | 
					const TabPane = Tabs.TabPane;
 | 
				
			||||||
 | 
					type params = {
 | 
				
			||||||
 | 
					  readonly id: any;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					type MyObjectType = {
 | 
				
			||||||
 | 
					  [key: string | number]: any;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const UpdateEdit = () => {
 | 
				
			||||||
 | 
					  const { id } = useParams<params>();
 | 
				
			||||||
 | 
					  const { data, refetch, status }: MyObjectType = useUpdateOne(id);
 | 
				
			||||||
 | 
					  const onSubmit = async (value: any) => {
 | 
				
			||||||
 | 
					    if (value.status === "Done") {
 | 
				
			||||||
 | 
					      if (value.solution !== "") {
 | 
				
			||||||
 | 
					        await updateController.updatePut(value, id);
 | 
				
			||||||
 | 
					        refetch();
 | 
				
			||||||
 | 
					        document.location.replace("/#/updates/");
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        alert("solution is empty!!!!!!!!!!!!!!!!!!!!!");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      await updateController.updatePut(value, id);
 | 
				
			||||||
 | 
					      refetch();
 | 
				
			||||||
 | 
					      document.location.replace("/#/updates/");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const admin_id = localStorage.getItem("admin_id");
 | 
				
			||||||
 | 
					  const [companyId, setCompanyId] = useState<any>(null);
 | 
				
			||||||
 | 
					  const [companyValue, setCompanyValue] = useState<any>();
 | 
				
			||||||
 | 
					  const [companyData, setCompanyData] = useState<MyObjectType>();
 | 
				
			||||||
 | 
					  const [customerId, setCustomerId] = useState<any>(null);
 | 
				
			||||||
 | 
					  const [customerValue, setCustomerValue] = useState<any>();
 | 
				
			||||||
 | 
					  const [customerData, setCustomerData] = useState<MyObjectType>();
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (data) {
 | 
				
			||||||
 | 
					      if (data.company_id === null) {
 | 
				
			||||||
 | 
					        setCompanyId(null);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (data.customer_id === null) {
 | 
				
			||||||
 | 
					        setCustomerId(null);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const companyIdFromData = data.company_id;
 | 
				
			||||||
 | 
					      const customerIdFromData = data.customer_id;
 | 
				
			||||||
 | 
					      setCompanyId(companyIdFromData);
 | 
				
			||||||
 | 
					      setCustomerId(customerIdFromData);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [data]);
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (companyId !== null) {
 | 
				
			||||||
 | 
					      companyController.companyOne(companyId).then((CompanyData) => {
 | 
				
			||||||
 | 
					        setCompanyData(CompanyData);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [companyId]);
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (customerId !== null) {
 | 
				
			||||||
 | 
					      customerController.customerOne(customerId).then((CustomerData) => {
 | 
				
			||||||
 | 
					        setCustomerData(CustomerData);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [customerId]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (companyData && companyData.name) {
 | 
				
			||||||
 | 
					      setCompanyValue(companyData.name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [companyData]);
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (customerData && customerData.name) {
 | 
				
			||||||
 | 
					      setCustomerValue(customerData.name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [customerData]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const handleClickDelete = (id: any) => {
 | 
				
			||||||
 | 
					    if (id !== undefined) {
 | 
				
			||||||
 | 
					      taskController.deleteAttachmentController(id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [inCharge, setInChage] = useState<any>();
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    if (data?.in_charge_id) {
 | 
				
			||||||
 | 
					      setInChage(data.in_charge_id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }, [data]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const ClickDelete = () => {
 | 
				
			||||||
 | 
					    const shouldDelete = window.confirm(
 | 
				
			||||||
 | 
					      "Вы уверены, что хотите удалить эту задачу?"
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    if (shouldDelete && id !== undefined) {
 | 
				
			||||||
 | 
					      updateController.deleteUpdateController(id).then((data: any) => {
 | 
				
			||||||
 | 
					        document.location.replace(`/#/updates/`);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [imgname, setImgname] = useState<any>([]);
 | 
				
			||||||
 | 
					  function handlePaste(event: any) {
 | 
				
			||||||
 | 
					    // Обработка вставки из буфера обмена
 | 
				
			||||||
 | 
					    const clipboardData = event.clipboardData || window.Clipboard;
 | 
				
			||||||
 | 
					    if (clipboardData && clipboardData.items.length > 0) {
 | 
				
			||||||
 | 
					      const clipboardItem = clipboardData.items[0];
 | 
				
			||||||
 | 
					      if (clipboardItem.kind === "file") {
 | 
				
			||||||
 | 
					        const file = clipboardItem.getAsFile();
 | 
				
			||||||
 | 
					        const formData = new FormData();
 | 
				
			||||||
 | 
					        formData.append("file", file);
 | 
				
			||||||
 | 
					        formData.append("shift_update_id", id);
 | 
				
			||||||
 | 
					        taskController.addTaskFile(formData).then((response) => {
 | 
				
			||||||
 | 
					          const n = [response.file];
 | 
				
			||||||
 | 
					          setImgname((prev: any) => [...prev, ...n]);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const [activeTab, setActiveTab] = useState("1");
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      {role !== "Checker" || inCharge == admin_id || inCharge == null ? (
 | 
				
			||||||
 | 
					        <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					          <Watermark style={{ height: "100%" }}>
 | 
				
			||||||
 | 
					            {status === "loading" ? (
 | 
				
			||||||
 | 
					              <Spin size="large" spinning={!data} />
 | 
				
			||||||
 | 
					            ) : data ? (
 | 
				
			||||||
 | 
					              <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					                <Space
 | 
				
			||||||
 | 
					                  direction="vertical"
 | 
				
			||||||
 | 
					                  size="middle"
 | 
				
			||||||
 | 
					                  style={{ display: "flex" }}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <Tabs
 | 
				
			||||||
 | 
					                    defaultActiveKey="1"
 | 
				
			||||||
 | 
					                    activeKey={activeTab}
 | 
				
			||||||
 | 
					                    onChange={(key) => setActiveTab(key)}
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <TabPane
 | 
				
			||||||
 | 
					                      tab={
 | 
				
			||||||
 | 
					                        <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					                          <img
 | 
				
			||||||
 | 
					                            style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                            src={activeTab === "1" ? infoIconActive : infoIcon}
 | 
				
			||||||
 | 
					                            alt=""
 | 
				
			||||||
 | 
					                          />
 | 
				
			||||||
 | 
					                          Information
 | 
				
			||||||
 | 
					                        </span>
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                      key="1"
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <Space
 | 
				
			||||||
 | 
					                        direction="vertical"
 | 
				
			||||||
 | 
					                        size="middle"
 | 
				
			||||||
 | 
					                        style={{ display: "flex" }}
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        <Form
 | 
				
			||||||
 | 
					                          name="newBasic"
 | 
				
			||||||
 | 
					                          layout="vertical"
 | 
				
			||||||
 | 
					                          wrapperCol={{ span: 16 }}
 | 
				
			||||||
 | 
					                          initialValues={{ ...data }}
 | 
				
			||||||
 | 
					                          autoComplete="off"
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                          <Row gutter={[16, 10]}>
 | 
				
			||||||
 | 
					                            {companyId !== null && (
 | 
				
			||||||
 | 
					                              <Col span={6}>
 | 
				
			||||||
 | 
					                                <Form.Item
 | 
				
			||||||
 | 
					                                  wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                                  label="Company"
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                  {companyValue !== undefined && (
 | 
				
			||||||
 | 
					                                    <Input
 | 
				
			||||||
 | 
					                                      defaultValue={companyValue}
 | 
				
			||||||
 | 
					                                      readOnly
 | 
				
			||||||
 | 
					                                    />
 | 
				
			||||||
 | 
					                                  )}
 | 
				
			||||||
 | 
					                                </Form.Item>
 | 
				
			||||||
 | 
					                              </Col>
 | 
				
			||||||
 | 
					                            )}
 | 
				
			||||||
 | 
					                            {customerId !== null && (
 | 
				
			||||||
 | 
					                              <Col span={6}>
 | 
				
			||||||
 | 
					                                <Form.Item
 | 
				
			||||||
 | 
					                                  wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                                  label="Driver"
 | 
				
			||||||
 | 
					                                >
 | 
				
			||||||
 | 
					                                  {customerValue !== undefined && (
 | 
				
			||||||
 | 
					                                    <Input
 | 
				
			||||||
 | 
					                                      defaultValue={customerValue}
 | 
				
			||||||
 | 
					                                      readOnly
 | 
				
			||||||
 | 
					                                    />
 | 
				
			||||||
 | 
					                                  )}
 | 
				
			||||||
 | 
					                                </Form.Item>
 | 
				
			||||||
 | 
					                              </Col>
 | 
				
			||||||
 | 
					                            )}
 | 
				
			||||||
 | 
					                          </Row>
 | 
				
			||||||
 | 
					                        </Form>
 | 
				
			||||||
 | 
					                        <Form
 | 
				
			||||||
 | 
					                          name="basic"
 | 
				
			||||||
 | 
					                          layout="vertical"
 | 
				
			||||||
 | 
					                          wrapperCol={{ span: 16 }}
 | 
				
			||||||
 | 
					                          initialValues={{ ...data }}
 | 
				
			||||||
 | 
					                          onFinish={onSubmit}
 | 
				
			||||||
 | 
					                          autoComplete="off"
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                          <Row gutter={[16, 10]}>
 | 
				
			||||||
 | 
					                            <Col span={8}>
 | 
				
			||||||
 | 
					                              <Form.Item
 | 
				
			||||||
 | 
					                                wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                                label="Note"
 | 
				
			||||||
 | 
					                                name="note"
 | 
				
			||||||
 | 
					                              >
 | 
				
			||||||
 | 
					                                <TextArea />
 | 
				
			||||||
 | 
					                              </Form.Item>
 | 
				
			||||||
 | 
					                            </Col>
 | 
				
			||||||
 | 
					                            <Col span={8}>
 | 
				
			||||||
 | 
					                              <Form.Item
 | 
				
			||||||
 | 
					                                wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                                label="Solution"
 | 
				
			||||||
 | 
					                                name="solution"
 | 
				
			||||||
 | 
					                              >
 | 
				
			||||||
 | 
					                                <TextArea />
 | 
				
			||||||
 | 
					                              </Form.Item>
 | 
				
			||||||
 | 
					                            </Col>
 | 
				
			||||||
 | 
					                            <Col span={4}>
 | 
				
			||||||
 | 
					                              <Form.Item
 | 
				
			||||||
 | 
					                                wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                                label="Status"
 | 
				
			||||||
 | 
					                                name="status"
 | 
				
			||||||
 | 
					                              >
 | 
				
			||||||
 | 
					                                <Select style={{ width: 120 }}>
 | 
				
			||||||
 | 
					                                  <Option value="New">New</Option>
 | 
				
			||||||
 | 
					                                  <Option value="In Progress">
 | 
				
			||||||
 | 
					                                    In Progress
 | 
				
			||||||
 | 
					                                  </Option>
 | 
				
			||||||
 | 
					                                  <Option value="Done">Done</Option>
 | 
				
			||||||
 | 
					                                  <Option value="Paper">Paper</Option>
 | 
				
			||||||
 | 
					                                  <Option value="Setup">Setup</Option>
 | 
				
			||||||
 | 
					                                </Select>
 | 
				
			||||||
 | 
					                              </Form.Item>
 | 
				
			||||||
 | 
					                            </Col>
 | 
				
			||||||
 | 
					                          </Row>
 | 
				
			||||||
 | 
					                          <Form.Item>
 | 
				
			||||||
 | 
					                            {role !== "Chceker" && (
 | 
				
			||||||
 | 
					                              <Button
 | 
				
			||||||
 | 
					                                type="primary"
 | 
				
			||||||
 | 
					                                danger
 | 
				
			||||||
 | 
					                                onClick={ClickDelete}
 | 
				
			||||||
 | 
					                              >
 | 
				
			||||||
 | 
					                                Delete
 | 
				
			||||||
 | 
					                              </Button>
 | 
				
			||||||
 | 
					                            )}
 | 
				
			||||||
 | 
					                            <Button
 | 
				
			||||||
 | 
					                              style={{ margin: 10 }}
 | 
				
			||||||
 | 
					                              type="primary"
 | 
				
			||||||
 | 
					                              htmlType="submit"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              Save
 | 
				
			||||||
 | 
					                            </Button>
 | 
				
			||||||
 | 
					                          </Form.Item>
 | 
				
			||||||
 | 
					                        </Form>
 | 
				
			||||||
 | 
					                      </Space>
 | 
				
			||||||
 | 
					                    </TabPane>
 | 
				
			||||||
 | 
					                    <TabPane
 | 
				
			||||||
 | 
					                      tab={
 | 
				
			||||||
 | 
					                        <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					                          <img
 | 
				
			||||||
 | 
					                            style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                            src={
 | 
				
			||||||
 | 
					                              activeTab === "2"
 | 
				
			||||||
 | 
					                                ? attachmentIconActive
 | 
				
			||||||
 | 
					                                : attachmentIcon
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                            alt=""
 | 
				
			||||||
 | 
					                          />
 | 
				
			||||||
 | 
					                          Attachments
 | 
				
			||||||
 | 
					                        </span>
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                      key="2"
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <div
 | 
				
			||||||
 | 
					                        onPaste={(event) => handlePaste(event)}
 | 
				
			||||||
 | 
					                        style={{ height: 800, width: 1000 }}
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        <Space
 | 
				
			||||||
 | 
					                          direction="vertical"
 | 
				
			||||||
 | 
					                          size="middle"
 | 
				
			||||||
 | 
					                          style={{ display: "flex" }}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                          <Form
 | 
				
			||||||
 | 
					                            name="basicFuck"
 | 
				
			||||||
 | 
					                            layout="vertical"
 | 
				
			||||||
 | 
					                            wrapperCol={{ span: 16 }}
 | 
				
			||||||
 | 
					                            initialValues={{ ...data.attachment_set[0] }}
 | 
				
			||||||
 | 
					                            autoComplete="off"
 | 
				
			||||||
 | 
					                            onFinish={onSubmit}
 | 
				
			||||||
 | 
					                          >
 | 
				
			||||||
 | 
					                            <Row gutter={[16, 10]}>
 | 
				
			||||||
 | 
					                              <Col span={24}>
 | 
				
			||||||
 | 
					                                <Form.Item wrapperCol={{ span: "100%" }}>
 | 
				
			||||||
 | 
					                                  {data.attachment_set.map((item: any) => (
 | 
				
			||||||
 | 
					                                    <div
 | 
				
			||||||
 | 
					                                      style={{
 | 
				
			||||||
 | 
					                                        display: "flex",
 | 
				
			||||||
 | 
					                                        alignSelf: "center",
 | 
				
			||||||
 | 
					                                        alignItems: "center",
 | 
				
			||||||
 | 
					                                        justifyContent: "space-between",
 | 
				
			||||||
 | 
					                                        background: "rgb(239 239 239)",
 | 
				
			||||||
 | 
					                                        padding: 15,
 | 
				
			||||||
 | 
					                                        borderRadius: 8,
 | 
				
			||||||
 | 
					                                        marginBottom: 20,
 | 
				
			||||||
 | 
					                                      }}
 | 
				
			||||||
 | 
					                                      key={item.id}
 | 
				
			||||||
 | 
					                                    >
 | 
				
			||||||
 | 
					                                      <a
 | 
				
			||||||
 | 
					                                        style={{
 | 
				
			||||||
 | 
					                                          width: "20%",
 | 
				
			||||||
 | 
					                                          display: "flex",
 | 
				
			||||||
 | 
					                                          alignItems: "center",
 | 
				
			||||||
 | 
					                                          alignSelf: "center",
 | 
				
			||||||
 | 
					                                        }}
 | 
				
			||||||
 | 
					                                        href={item.file_path}
 | 
				
			||||||
 | 
					                                        target="_blank"
 | 
				
			||||||
 | 
					                                        rel="noopener noreferrer"
 | 
				
			||||||
 | 
					                                      >
 | 
				
			||||||
 | 
					                                        <img
 | 
				
			||||||
 | 
					                                          src={item.file_path}
 | 
				
			||||||
 | 
					                                          alt=""
 | 
				
			||||||
 | 
					                                          style={{
 | 
				
			||||||
 | 
					                                            width: "30%",
 | 
				
			||||||
 | 
					                                            maxHeight: "200px",
 | 
				
			||||||
 | 
					                                            marginRight: 20,
 | 
				
			||||||
 | 
					                                          }}
 | 
				
			||||||
 | 
					                                        />
 | 
				
			||||||
 | 
					                                        {item.file_name}
 | 
				
			||||||
 | 
					                                      </a>
 | 
				
			||||||
 | 
					                                      <Button
 | 
				
			||||||
 | 
					                                        onClick={() =>
 | 
				
			||||||
 | 
					                                          handleClickDelete(item.id)
 | 
				
			||||||
 | 
					                                        }
 | 
				
			||||||
 | 
					                                        type="primary"
 | 
				
			||||||
 | 
					                                        danger
 | 
				
			||||||
 | 
					                                      >
 | 
				
			||||||
 | 
					                                        Delete
 | 
				
			||||||
 | 
					                                      </Button>
 | 
				
			||||||
 | 
					                                    </div>
 | 
				
			||||||
 | 
					                                  ))}
 | 
				
			||||||
 | 
					                                </Form.Item>
 | 
				
			||||||
 | 
					                                <Form.Item label="File" name="attachment">
 | 
				
			||||||
 | 
					                                  <Upload.Dragger
 | 
				
			||||||
 | 
					                                    name="file"
 | 
				
			||||||
 | 
					                                    customRequest={({
 | 
				
			||||||
 | 
					                                      file,
 | 
				
			||||||
 | 
					                                      onSuccess,
 | 
				
			||||||
 | 
					                                    }: any) => {
 | 
				
			||||||
 | 
					                                      const formData = new FormData();
 | 
				
			||||||
 | 
					                                      formData.append("file", file);
 | 
				
			||||||
 | 
					                                      formData.append("shift_update_id", id);
 | 
				
			||||||
 | 
					                                      taskController
 | 
				
			||||||
 | 
					                                        .addTaskFile(formData)
 | 
				
			||||||
 | 
					                                        .then(() => {
 | 
				
			||||||
 | 
					                                          onSuccess();
 | 
				
			||||||
 | 
					                                        })
 | 
				
			||||||
 | 
					                                        .catch((error) => {
 | 
				
			||||||
 | 
					                                          onSuccess(error);
 | 
				
			||||||
 | 
					                                        });
 | 
				
			||||||
 | 
					                                    }}
 | 
				
			||||||
 | 
					                                  >
 | 
				
			||||||
 | 
					                                    <p className="ant-upload-drag-icon">
 | 
				
			||||||
 | 
					                                      <UploadOutlined
 | 
				
			||||||
 | 
					                                        style={{ color: "#b5f5ec" }}
 | 
				
			||||||
 | 
					                                      />
 | 
				
			||||||
 | 
					                                    </p>
 | 
				
			||||||
 | 
					                                    <p
 | 
				
			||||||
 | 
					                                      className="ant-upload-text"
 | 
				
			||||||
 | 
					                                      style={{ color: "#b5f5ec" }}
 | 
				
			||||||
 | 
					                                    >
 | 
				
			||||||
 | 
					                                      Click or drag file to this area to upload
 | 
				
			||||||
 | 
					                                    </p>
 | 
				
			||||||
 | 
					                                  </Upload.Dragger>
 | 
				
			||||||
 | 
					                                  <p>{imgname.join(",\n")}</p>
 | 
				
			||||||
 | 
					                                </Form.Item>
 | 
				
			||||||
 | 
					                                <Form.Item>
 | 
				
			||||||
 | 
					                                  <Button type="primary" htmlType="submit">
 | 
				
			||||||
 | 
					                                    Save
 | 
				
			||||||
 | 
					                                  </Button>
 | 
				
			||||||
 | 
					                                </Form.Item>
 | 
				
			||||||
 | 
					                              </Col>
 | 
				
			||||||
 | 
					                            </Row>
 | 
				
			||||||
 | 
					                          </Form>
 | 
				
			||||||
 | 
					                        </Space>
 | 
				
			||||||
 | 
					                      </div>
 | 
				
			||||||
 | 
					                    </TabPane>
 | 
				
			||||||
 | 
					                  </Tabs>
 | 
				
			||||||
 | 
					                </Space>
 | 
				
			||||||
 | 
					              </Spin>
 | 
				
			||||||
 | 
					            ) : (
 | 
				
			||||||
 | 
					              <Notfound />
 | 
				
			||||||
 | 
					            )}
 | 
				
			||||||
 | 
					          </Watermark>
 | 
				
			||||||
 | 
					        </Spin>
 | 
				
			||||||
 | 
					      ) : (
 | 
				
			||||||
 | 
					        <div>
 | 
				
			||||||
 | 
					          <Spin size="large" spinning={!data}></Spin>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      )}
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default UpdateEdit;
 | 
				
			||||||
@ -0,0 +1,141 @@
 | 
				
			|||||||
 | 
					// // @ts-ignore
 | 
				
			||||||
 | 
					// import closeIcon from "../../assets/closeIcon.png";
 | 
				
			||||||
 | 
					// // @ts-ignore
 | 
				
			||||||
 | 
					// import editIcon from "../../assets/editIcon.png";
 | 
				
			||||||
 | 
					// // @ts-ignore
 | 
				
			||||||
 | 
					// import deleteIcon from "../../assets/deleteIconRed.png";
 | 
				
			||||||
 | 
					// // @ts-ignore
 | 
				
			||||||
 | 
					// import attachmentIcon from "../../assets/attachmentIcon.png";
 | 
				
			||||||
 | 
					// // @ts-ignore
 | 
				
			||||||
 | 
					// import infoIcon from "../../assets/infoIcon.png";
 | 
				
			||||||
 | 
					// // @ts-ignore
 | 
				
			||||||
 | 
					// import uploadIcon from "../../assets/uploadIcon.png";
 | 
				
			||||||
 | 
					// import { Tabs } from "antd";
 | 
				
			||||||
 | 
					// import TabPane from "antd/es/tabs/TabPane";
 | 
				
			||||||
 | 
					// import { TUpdate } from "../../types/Update/TUpdate";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// const UpdateModal = ({
 | 
				
			||||||
 | 
					//   modalOpen,
 | 
				
			||||||
 | 
					//   setModalOpen,
 | 
				
			||||||
 | 
					//   recordUpdate,
 | 
				
			||||||
 | 
					// }: {
 | 
				
			||||||
 | 
					//   recordUpdate: TUpdate | undefined;
 | 
				
			||||||
 | 
					//   modalOpen: any;
 | 
				
			||||||
 | 
					//   setModalOpen: any;
 | 
				
			||||||
 | 
					// }) => {
 | 
				
			||||||
 | 
					//   const handleCancel = () => {
 | 
				
			||||||
 | 
					//     setModalOpen(!modalOpen);
 | 
				
			||||||
 | 
					//   };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//   return (
 | 
				
			||||||
 | 
					//     <div className="TaskModal">
 | 
				
			||||||
 | 
					//       <div className="TaskModal-header">
 | 
				
			||||||
 | 
					//         <div className="TaskModal-title">
 | 
				
			||||||
 | 
					//           <p className="p-driver">{recordUpdate?.company}</p>
 | 
				
			||||||
 | 
					//           <p
 | 
				
			||||||
 | 
					//             style={{ marginLeft: 12 }}
 | 
				
			||||||
 | 
					//             className={`status-${recordUpdate?.status}`}
 | 
				
			||||||
 | 
					//           >
 | 
				
			||||||
 | 
					//             {recordUpdate?.status}
 | 
				
			||||||
 | 
					//           </p>
 | 
				
			||||||
 | 
					//         </div>
 | 
				
			||||||
 | 
					//         <div className="mdoal-actions">
 | 
				
			||||||
 | 
					//           <button className="btn-modal-action">
 | 
				
			||||||
 | 
					//             <img src={editIcon} alt="" />
 | 
				
			||||||
 | 
					//             Edit
 | 
				
			||||||
 | 
					//           </button>
 | 
				
			||||||
 | 
					//           <button style={{ marginLeft: 12 }} className="btn-modal-action">
 | 
				
			||||||
 | 
					//             <img src={uploadIcon} alt="" />
 | 
				
			||||||
 | 
					//             Upload file
 | 
				
			||||||
 | 
					//           </button>
 | 
				
			||||||
 | 
					//           <button style={{ marginLeft: 12 }} className="btn-modal-action">
 | 
				
			||||||
 | 
					//             <img src={deleteIcon} alt="" />
 | 
				
			||||||
 | 
					//             Delete
 | 
				
			||||||
 | 
					//           </button>
 | 
				
			||||||
 | 
					//           <button
 | 
				
			||||||
 | 
					//             onClick={handleCancel}
 | 
				
			||||||
 | 
					//             style={{ marginLeft: 20 }}
 | 
				
			||||||
 | 
					//             className="btn-modal-action"
 | 
				
			||||||
 | 
					//           >
 | 
				
			||||||
 | 
					//             <img style={{ margin: 2 }} src={closeIcon} alt="" />
 | 
				
			||||||
 | 
					//           </button>
 | 
				
			||||||
 | 
					//         </div>
 | 
				
			||||||
 | 
					//       </div>
 | 
				
			||||||
 | 
					//       <div className="TaskModal-content">
 | 
				
			||||||
 | 
					//         <Tabs>
 | 
				
			||||||
 | 
					//           <TabPane
 | 
				
			||||||
 | 
					//             tab={
 | 
				
			||||||
 | 
					//               <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					//                 <img style={{ marginRight: 10 }} src={infoIcon} alt="" />
 | 
				
			||||||
 | 
					//                 Information
 | 
				
			||||||
 | 
					//               </span>
 | 
				
			||||||
 | 
					//             }
 | 
				
			||||||
 | 
					//             key="1"
 | 
				
			||||||
 | 
					//           >
 | 
				
			||||||
 | 
					//             <div className="info-div">
 | 
				
			||||||
 | 
					//               <p
 | 
				
			||||||
 | 
					//                 style={{
 | 
				
			||||||
 | 
					//                   fontSize: 18,
 | 
				
			||||||
 | 
					//                   fontWeight: 700,
 | 
				
			||||||
 | 
					//                   lineHeight: "24px",
 | 
				
			||||||
 | 
					//                   letterSpacing: "-0.02em",
 | 
				
			||||||
 | 
					//                   marginBottom: 16,
 | 
				
			||||||
 | 
					//                 }}
 | 
				
			||||||
 | 
					//               >
 | 
				
			||||||
 | 
					//                 Information
 | 
				
			||||||
 | 
					//               </p>
 | 
				
			||||||
 | 
					//               <div className="info-body">
 | 
				
			||||||
 | 
					//                 <tr>
 | 
				
			||||||
 | 
					//                   <p className="sub">Comapany</p>
 | 
				
			||||||
 | 
					//                   <p className="info">{recordUpdate?.company}</p>
 | 
				
			||||||
 | 
					//                 </tr>
 | 
				
			||||||
 | 
					//                 <tr>
 | 
				
			||||||
 | 
					//                   <p className="sub">Driver</p>
 | 
				
			||||||
 | 
					//                   <p className="info">{recordUpdate?.customer}</p>
 | 
				
			||||||
 | 
					//                 </tr>
 | 
				
			||||||
 | 
					//                 <tr>
 | 
				
			||||||
 | 
					//                   <p className="sub">Created by</p>
 | 
				
			||||||
 | 
					//                   <p className="info">{recordUpdate?.provider}</p>
 | 
				
			||||||
 | 
					//                 </tr>
 | 
				
			||||||
 | 
					//                 <tr>
 | 
				
			||||||
 | 
					//                   <p className="sub">Created at</p>
 | 
				
			||||||
 | 
					//                   <p className="info">{recordUpdate?.created_at}</p>
 | 
				
			||||||
 | 
					//                 </tr>
 | 
				
			||||||
 | 
					//                 <tr>
 | 
				
			||||||
 | 
					//                   <p className="sub">Completed_by</p>
 | 
				
			||||||
 | 
					//                   <p className="info">{recordUpdate?.executor}</p>
 | 
				
			||||||
 | 
					//                 </tr>
 | 
				
			||||||
 | 
					//                 <tr>
 | 
				
			||||||
 | 
					//                   <p className="sub">Solution</p>
 | 
				
			||||||
 | 
					//                   <p className="info">{recordUpdate?.solution}</p>
 | 
				
			||||||
 | 
					//                 </tr>
 | 
				
			||||||
 | 
					//                 <tr>
 | 
				
			||||||
 | 
					//                   <p className="sub">Note</p>
 | 
				
			||||||
 | 
					//                   <p className="info">{recordUpdate?.note}</p>
 | 
				
			||||||
 | 
					//                 </tr>
 | 
				
			||||||
 | 
					//               </div>
 | 
				
			||||||
 | 
					//             </div>
 | 
				
			||||||
 | 
					//           </TabPane>
 | 
				
			||||||
 | 
					//           <TabPane
 | 
				
			||||||
 | 
					//             tab={
 | 
				
			||||||
 | 
					//               <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					//                 <img style={{ marginRight: 10 }} src={attachmentIcon} alt="" />
 | 
				
			||||||
 | 
					//                 Attachments
 | 
				
			||||||
 | 
					//               </span>
 | 
				
			||||||
 | 
					//             }
 | 
				
			||||||
 | 
					//             key="2"
 | 
				
			||||||
 | 
					//           ></TabPane>
 | 
				
			||||||
 | 
					//         </Tabs>
 | 
				
			||||||
 | 
					//       </div>
 | 
				
			||||||
 | 
					//     </div>
 | 
				
			||||||
 | 
					//   );
 | 
				
			||||||
 | 
					// };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// export default UpdateModal;
 | 
				
			||||||
 | 
					import React from "react";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const UpdateModal = () => {
 | 
				
			||||||
 | 
					  return <div>UpdateModal</div>;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default UpdateModal;
 | 
				
			||||||
@ -0,0 +1,300 @@
 | 
				
			|||||||
 | 
					import { Space, Table, Tooltip } from "antd";
 | 
				
			||||||
 | 
					import moment from "moment";
 | 
				
			||||||
 | 
					import { useCompanyData } from "../../Hooks/Companies";
 | 
				
			||||||
 | 
					import { useCustomerData } from "../../Hooks/Customers";
 | 
				
			||||||
 | 
					import { useUserData } from "../../Hooks/Users";
 | 
				
			||||||
 | 
					import { updateController } from "../../API/LayoutApi/update";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					import { TUpdate } from "../../types/Update/TUpdate";
 | 
				
			||||||
 | 
					import { useEffect, useState } from "react";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import pin from "../../assets/pinicon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import unpin from "../../assets/unpinicon.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";
 | 
				
			||||||
 | 
					const UpdateTable = ({
 | 
				
			||||||
 | 
					  data = [],
 | 
				
			||||||
 | 
					  isLoading,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  data: TUpdate[] | undefined;
 | 
				
			||||||
 | 
					  isLoading?: boolean;
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TUpdate[], unknown>>;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const CompanyData = useCompanyData({});
 | 
				
			||||||
 | 
					  const CustomerData = useCustomerData({});
 | 
				
			||||||
 | 
					  const AdminData = useUserData({});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const [isTextSelected, setIsTextSelected] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  useEffect(() => {
 | 
				
			||||||
 | 
					    const handleSelectionChange = () => {
 | 
				
			||||||
 | 
					      const selection = window.getSelection();
 | 
				
			||||||
 | 
					      setIsTextSelected(selection !== null && selection.toString() !== "");
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    document.addEventListener("selectionchange", handleSelectionChange);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return () => {
 | 
				
			||||||
 | 
					      document.removeEventListener("selectionchange", handleSelectionChange);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Row = (record: TUpdate, event: any) => {
 | 
				
			||||||
 | 
					    if (isTextSelected) {
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (event.target.classList.contains("ant-table-cell")) {
 | 
				
			||||||
 | 
					      document.location.replace(`/#/updates/${record.id}`);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  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 (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Table
 | 
				
			||||||
 | 
					        onRow={(record) => ({
 | 
				
			||||||
 | 
					          onClick: (event) => Row(record, event),
 | 
				
			||||||
 | 
					        })}
 | 
				
			||||||
 | 
					        dataSource={data?.map((u, i) => ({
 | 
				
			||||||
 | 
					          no: i + 1,
 | 
				
			||||||
 | 
					          ...u,
 | 
				
			||||||
 | 
					          company_name: CompanyData?.data?.find(
 | 
				
			||||||
 | 
					            (company: any) => company.id === u.company_id
 | 
				
			||||||
 | 
					          )?.name,
 | 
				
			||||||
 | 
					          customer_name: CustomerData?.data?.find(
 | 
				
			||||||
 | 
					            (customer: any) => customer.id === u.customer_id
 | 
				
			||||||
 | 
					          )?.name,
 | 
				
			||||||
 | 
					          in_charge_name: AdminData?.data?.find(
 | 
				
			||||||
 | 
					            (admin: any) => admin.id === u.provider_id
 | 
				
			||||||
 | 
					          )?.username,
 | 
				
			||||||
 | 
					          executor_name: AdminData?.data?.find(
 | 
				
			||||||
 | 
					            (admin: any) => admin.id === u.executor_id
 | 
				
			||||||
 | 
					          )?.username,
 | 
				
			||||||
 | 
					          created: moment(u?.created_at, "YYYY-MM-DD HH:mm:ss").format(
 | 
				
			||||||
 | 
					            "DD.MM.YYYY HH:mm"
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          action: { ...u },
 | 
				
			||||||
 | 
					        }))}
 | 
				
			||||||
 | 
					        columns={[
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					            dataIndex: "no",
 | 
				
			||||||
 | 
					            width: "5%",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Company",
 | 
				
			||||||
 | 
					            dataIndex: "company",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            width: "10%",
 | 
				
			||||||
 | 
					            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>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Driver",
 | 
				
			||||||
 | 
					            dataIndex: "customer",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            width: "10%",
 | 
				
			||||||
 | 
					            render: (item: { name: string }) => (
 | 
				
			||||||
 | 
					              <Tooltip placement="topLeft" title={item?.name}>
 | 
				
			||||||
 | 
					                {item?.name}
 | 
				
			||||||
 | 
					              </Tooltip>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Created by",
 | 
				
			||||||
 | 
					            dataIndex: "provider ",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            responsive: ["xl"],
 | 
				
			||||||
 | 
					            width: "10%",
 | 
				
			||||||
 | 
					            render: (note: string) => (
 | 
				
			||||||
 | 
					              <Tooltip placement="topLeft" title={note}>
 | 
				
			||||||
 | 
					                {note}
 | 
				
			||||||
 | 
					              </Tooltip>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Complited by",
 | 
				
			||||||
 | 
					            dataIndex: "executor",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            responsive: ["lg"],
 | 
				
			||||||
 | 
					            width: "10%",
 | 
				
			||||||
 | 
					            render: (note: string) => (
 | 
				
			||||||
 | 
					              <Tooltip placement="topLeft" title={note}>
 | 
				
			||||||
 | 
					                {note}
 | 
				
			||||||
 | 
					              </Tooltip>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Status",
 | 
				
			||||||
 | 
					            dataIndex: "status",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            width: "10%",
 | 
				
			||||||
 | 
					            render: (status: string) => (
 | 
				
			||||||
 | 
					              <span>
 | 
				
			||||||
 | 
					                {status === "Done" && <p className="status-done">Done</p>}
 | 
				
			||||||
 | 
					                {status === "Checking" && (
 | 
				
			||||||
 | 
					                  <p className="status-in-progress">Checking</p>
 | 
				
			||||||
 | 
					                )}
 | 
				
			||||||
 | 
					                {status === "New" && <p className="status-new">New</p>}
 | 
				
			||||||
 | 
					                {status === "Setup" && <p className="status-setup">Setup</p>}
 | 
				
			||||||
 | 
					                {status === "Paper" && <p className="status-paper">Paper</p>}
 | 
				
			||||||
 | 
					              </span>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Note",
 | 
				
			||||||
 | 
					            dataIndex: "note",
 | 
				
			||||||
 | 
					            width: "10%",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            render: (note: string) => (
 | 
				
			||||||
 | 
					              <Tooltip placement="topLeft" title={note}>
 | 
				
			||||||
 | 
					                {note}
 | 
				
			||||||
 | 
					              </Tooltip>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Solution",
 | 
				
			||||||
 | 
					            dataIndex: "solution",
 | 
				
			||||||
 | 
					            width: "10%",
 | 
				
			||||||
 | 
					            responsive: ["lg"],
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            render: (note: string) => (
 | 
				
			||||||
 | 
					              <Tooltip placement="topLeft" title={note}>
 | 
				
			||||||
 | 
					                {note}
 | 
				
			||||||
 | 
					              </Tooltip>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Created at",
 | 
				
			||||||
 | 
					            dataIndex: "created",
 | 
				
			||||||
 | 
					            ellipsis: {
 | 
				
			||||||
 | 
					              showTitle: false,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            responsive: ["xxl"],
 | 
				
			||||||
 | 
					            width: "10%",
 | 
				
			||||||
 | 
					            render: (note: string) => (
 | 
				
			||||||
 | 
					              <Tooltip placement="topLeft" title={note}>
 | 
				
			||||||
 | 
					                {note}
 | 
				
			||||||
 | 
					              </Tooltip>
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Actions",
 | 
				
			||||||
 | 
					            dataIndex: "action",
 | 
				
			||||||
 | 
					            width: "8%",
 | 
				
			||||||
 | 
					            render: (record: TUpdate) => {
 | 
				
			||||||
 | 
					              return (
 | 
				
			||||||
 | 
					                <div className="notedit">
 | 
				
			||||||
 | 
					                  {record.status !== "Done" && (
 | 
				
			||||||
 | 
					                    <Space>
 | 
				
			||||||
 | 
					                      {record.is_pinned ? (
 | 
				
			||||||
 | 
					                        <button
 | 
				
			||||||
 | 
					                          className="btn-unpin"
 | 
				
			||||||
 | 
					                          onClick={(e) => {
 | 
				
			||||||
 | 
					                            const updateData = {
 | 
				
			||||||
 | 
					                              is_pinned: false,
 | 
				
			||||||
 | 
					                            };
 | 
				
			||||||
 | 
					                            updateController
 | 
				
			||||||
 | 
					                              .updatePatch(updateData, record.id)
 | 
				
			||||||
 | 
					                              .then(() => {
 | 
				
			||||||
 | 
					                                refetch();
 | 
				
			||||||
 | 
					                              });
 | 
				
			||||||
 | 
					                          }}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                          <img src={unpin} alt="" />
 | 
				
			||||||
 | 
					                        </button>
 | 
				
			||||||
 | 
					                      ) : (
 | 
				
			||||||
 | 
					                        <button
 | 
				
			||||||
 | 
					                          className="btn-pin"
 | 
				
			||||||
 | 
					                          style={{ paddingTop: 2 }}
 | 
				
			||||||
 | 
					                          onClick={(e) => {
 | 
				
			||||||
 | 
					                            const updateData = {
 | 
				
			||||||
 | 
					                              is_pinned: true,
 | 
				
			||||||
 | 
					                            };
 | 
				
			||||||
 | 
					                            updateController
 | 
				
			||||||
 | 
					                              .updatePatch(updateData, record.id)
 | 
				
			||||||
 | 
					                              .then(() => {
 | 
				
			||||||
 | 
					                                refetch();
 | 
				
			||||||
 | 
					                              });
 | 
				
			||||||
 | 
					                          }}
 | 
				
			||||||
 | 
					                        >
 | 
				
			||||||
 | 
					                          <img src={pin} alt="" />
 | 
				
			||||||
 | 
					                        </button>
 | 
				
			||||||
 | 
					                      )}
 | 
				
			||||||
 | 
					                    </Space>
 | 
				
			||||||
 | 
					                  )}
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					              );
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ]}
 | 
				
			||||||
 | 
					        rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					          index % 2 === 0 ? "odd-row" : "even-row"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        loading={isLoading}
 | 
				
			||||||
 | 
					        size="small"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default UpdateTable;
 | 
				
			||||||
@ -0,0 +1,87 @@
 | 
				
			|||||||
 | 
					import { Input, Modal, Form as FormAnt, Select } from "antd";
 | 
				
			||||||
 | 
					import { useRoleData } from "../../Hooks/Role";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					import { TUser } from "../../types/User/TUser";
 | 
				
			||||||
 | 
					import { inviteVerify } from "../../API/auth/invite";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const AddUser = ({
 | 
				
			||||||
 | 
					  open,
 | 
				
			||||||
 | 
					  setOpen,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TUser[], unknown>>;
 | 
				
			||||||
 | 
					  open: boolean;
 | 
				
			||||||
 | 
					  setOpen(open: boolean): void;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const [form] = FormAnt.useForm();
 | 
				
			||||||
 | 
					  const handleCancel = () => {
 | 
				
			||||||
 | 
					    setOpen(!open);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const roleData = useRoleData();
 | 
				
			||||||
 | 
					  const filteredRoleData = roleData?.data?.filter(role => role.name !== 'Owner');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Modal
 | 
				
			||||||
 | 
					        open={open}
 | 
				
			||||||
 | 
					        title="Add user"
 | 
				
			||||||
 | 
					        okText="Create"
 | 
				
			||||||
 | 
					        cancelText="Cancel"
 | 
				
			||||||
 | 
					        onCancel={handleCancel}
 | 
				
			||||||
 | 
					        onOk={() => {
 | 
				
			||||||
 | 
					          form.validateFields().then(async (values) => {
 | 
				
			||||||
 | 
					            if (typeof values.groups === "number") {
 | 
				
			||||||
 | 
					              values.groups = [values.groups];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            form.resetFields();
 | 
				
			||||||
 | 
					            delete values.Confirm;
 | 
				
			||||||
 | 
					            inviteVerify(values);
 | 
				
			||||||
 | 
					            setOpen(!open);
 | 
				
			||||||
 | 
					            refetch();
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        <FormAnt
 | 
				
			||||||
 | 
					          form={form}
 | 
				
			||||||
 | 
					          layout="horizontal"
 | 
				
			||||||
 | 
					          name="form_in_modal"
 | 
				
			||||||
 | 
					          initialValues={{ modifier: "public" }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="E-mail"
 | 
				
			||||||
 | 
					            name="email"
 | 
				
			||||||
 | 
					            rules={[
 | 
				
			||||||
 | 
					              { required: true },
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                type: "email",
 | 
				
			||||||
 | 
					                message: "The input is not valid E-mail!",
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            ]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Input />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					          <FormAnt.Item
 | 
				
			||||||
 | 
					            label="Role"
 | 
				
			||||||
 | 
					            name="role_id"
 | 
				
			||||||
 | 
					            rules={[{ required: true }]}
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <Select
 | 
				
			||||||
 | 
					              options={filteredRoleData?.map(role => ({
 | 
				
			||||||
 | 
					                label: role.name,
 | 
				
			||||||
 | 
					                value: role.id,
 | 
				
			||||||
 | 
					              }))}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
 | 
					          </FormAnt.Item>
 | 
				
			||||||
 | 
					        </FormAnt>
 | 
				
			||||||
 | 
					      </Modal>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default AddUser;
 | 
				
			||||||
@ -0,0 +1,191 @@
 | 
				
			|||||||
 | 
					import { useParams } from "react-router-dom";
 | 
				
			||||||
 | 
					import { useUserOne } from "../../Hooks/Users";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  Form,
 | 
				
			||||||
 | 
					  Spin,
 | 
				
			||||||
 | 
					  Watermark,
 | 
				
			||||||
 | 
					  Space,
 | 
				
			||||||
 | 
					  Tabs,
 | 
				
			||||||
 | 
					  Row,
 | 
				
			||||||
 | 
					  Col,
 | 
				
			||||||
 | 
					  Input,
 | 
				
			||||||
 | 
					  Button,
 | 
				
			||||||
 | 
					  Select,
 | 
				
			||||||
 | 
					} from "antd";
 | 
				
			||||||
 | 
					import { userController } from "../../API/LayoutApi/users";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIcon from "../../assets/infoIcon.png";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import infoIconActive from "../../assets/infoIconActive.png";
 | 
				
			||||||
 | 
					import Notfound from "../../Utils/Notfound";
 | 
				
			||||||
 | 
					import { useTeamData } from "../../Hooks/Teams";
 | 
				
			||||||
 | 
					import { useRoleData } from "../../Hooks/Role";
 | 
				
			||||||
 | 
					import { role } from "../../App";
 | 
				
			||||||
 | 
					import { useState } from "react";
 | 
				
			||||||
 | 
					const TabPane = Tabs.TabPane;
 | 
				
			||||||
 | 
					type params = {
 | 
				
			||||||
 | 
					  readonly id: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					type MyObjectType = {
 | 
				
			||||||
 | 
					  [key: string | number]: any;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					const UserEdit = () => {
 | 
				
			||||||
 | 
					  const { id } = useParams<params>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { data, refetch, status }: MyObjectType = useUserOne(id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const onSubmit = async (value: any) => {
 | 
				
			||||||
 | 
					    id && (await userController.userPatch(value, id));
 | 
				
			||||||
 | 
					    refetch();
 | 
				
			||||||
 | 
					    document.location.replace("/#/users/");
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const TeamData = useTeamData("");
 | 
				
			||||||
 | 
					  const noTeamOption = { label: " - - - - - -", value: "" };
 | 
				
			||||||
 | 
					  const TeamOption: { label: string; value: any }[] | undefined =
 | 
				
			||||||
 | 
					    TeamData?.data?.map((item) => ({
 | 
				
			||||||
 | 
					      label: item?.name,
 | 
				
			||||||
 | 
					      value: item?.id,
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					  if (TeamOption) {
 | 
				
			||||||
 | 
					    TeamOption.unshift(noTeamOption);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const roleData = useRoleData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const ClickDelete = () => {
 | 
				
			||||||
 | 
					    const shouldDelete = window.confirm(
 | 
				
			||||||
 | 
					      "Вы уверены, что хотите удалить этот админ?"
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    if (shouldDelete && id !== undefined) {
 | 
				
			||||||
 | 
					      userController.deleteUserController(id).then(() => {
 | 
				
			||||||
 | 
					        document.location.replace(`/#/users`);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const [activeTab, setActiveTab] = useState("1");
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					        <Watermark style={{ height: "100%" }}>
 | 
				
			||||||
 | 
					          {status === "loading" ? (
 | 
				
			||||||
 | 
					            <Spin size="large" spinning={!data} />
 | 
				
			||||||
 | 
					          ) : data ? (
 | 
				
			||||||
 | 
					            <Spin size="large" spinning={!data}>
 | 
				
			||||||
 | 
					              <Space
 | 
				
			||||||
 | 
					                direction="vertical"
 | 
				
			||||||
 | 
					                size="middle"
 | 
				
			||||||
 | 
					                style={{ display: "flex" }}
 | 
				
			||||||
 | 
					              >
 | 
				
			||||||
 | 
					                <Tabs
 | 
				
			||||||
 | 
					                  defaultActiveKey="1"
 | 
				
			||||||
 | 
					                  activeKey={activeTab}
 | 
				
			||||||
 | 
					                  onChange={(key) => setActiveTab(key)}
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  <TabPane
 | 
				
			||||||
 | 
					                    tab={
 | 
				
			||||||
 | 
					                      <span style={{ display: "flex", alignItems: "center" }}>
 | 
				
			||||||
 | 
					                        <img
 | 
				
			||||||
 | 
					                          style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                          src={activeTab === "1" ? infoIconActive : infoIcon}
 | 
				
			||||||
 | 
					                          alt=""
 | 
				
			||||||
 | 
					                        />
 | 
				
			||||||
 | 
					                        Information
 | 
				
			||||||
 | 
					                      </span>
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    key="1"
 | 
				
			||||||
 | 
					                  >
 | 
				
			||||||
 | 
					                    <Space
 | 
				
			||||||
 | 
					                      direction="vertical"
 | 
				
			||||||
 | 
					                      size="middle"
 | 
				
			||||||
 | 
					                      style={{ display: "flex" }}
 | 
				
			||||||
 | 
					                    >
 | 
				
			||||||
 | 
					                      <Form
 | 
				
			||||||
 | 
					                        name="basic"
 | 
				
			||||||
 | 
					                        layout="vertical"
 | 
				
			||||||
 | 
					                        wrapperCol={{ span: 16 }}
 | 
				
			||||||
 | 
					                        initialValues={{ ...data }}
 | 
				
			||||||
 | 
					                        onFinish={onSubmit}
 | 
				
			||||||
 | 
					                        autoComplete="off"
 | 
				
			||||||
 | 
					                      >
 | 
				
			||||||
 | 
					                        <Row gutter={[16, 10]}>
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="First name"
 | 
				
			||||||
 | 
					                              name="first_name"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Input readOnly />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="Last name"
 | 
				
			||||||
 | 
					                              name="last_name"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Input readOnly />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                          <Col span={6}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="Username"
 | 
				
			||||||
 | 
					                              name="username"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Input readOnly />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                          <Col span={4}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="Team"
 | 
				
			||||||
 | 
					                              name="team_id"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Select options={TeamOption} />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                          <Col span={4}>
 | 
				
			||||||
 | 
					                            <Form.Item
 | 
				
			||||||
 | 
					                              wrapperCol={{ span: "100%" }}
 | 
				
			||||||
 | 
					                              label="Role"
 | 
				
			||||||
 | 
					                              name="role_id"
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              <Select
 | 
				
			||||||
 | 
					                                options={roleData?.data?.map((item) => ({
 | 
				
			||||||
 | 
					                                  label: item?.name,
 | 
				
			||||||
 | 
					                                  value: item?.id,
 | 
				
			||||||
 | 
					                                }))}
 | 
				
			||||||
 | 
					                              />
 | 
				
			||||||
 | 
					                            </Form.Item>
 | 
				
			||||||
 | 
					                          </Col>
 | 
				
			||||||
 | 
					                        </Row>
 | 
				
			||||||
 | 
					                        <Form.Item>
 | 
				
			||||||
 | 
					                          {role !== "Checker" && (
 | 
				
			||||||
 | 
					                            <Button
 | 
				
			||||||
 | 
					                              onClick={() => ClickDelete()}
 | 
				
			||||||
 | 
					                              type="primary"
 | 
				
			||||||
 | 
					                              style={{ marginRight: 10 }}
 | 
				
			||||||
 | 
					                              danger
 | 
				
			||||||
 | 
					                            >
 | 
				
			||||||
 | 
					                              Delete
 | 
				
			||||||
 | 
					                            </Button>
 | 
				
			||||||
 | 
					                          )}
 | 
				
			||||||
 | 
					                          <Button type="primary" htmlType="submit">
 | 
				
			||||||
 | 
					                            Submit
 | 
				
			||||||
 | 
					                          </Button>
 | 
				
			||||||
 | 
					                        </Form.Item>
 | 
				
			||||||
 | 
					                      </Form>
 | 
				
			||||||
 | 
					                    </Space>
 | 
				
			||||||
 | 
					                  </TabPane>
 | 
				
			||||||
 | 
					                </Tabs>
 | 
				
			||||||
 | 
					              </Space>
 | 
				
			||||||
 | 
					            </Spin>
 | 
				
			||||||
 | 
					          ) : (
 | 
				
			||||||
 | 
					            <Notfound />
 | 
				
			||||||
 | 
					          )}
 | 
				
			||||||
 | 
					        </Watermark>
 | 
				
			||||||
 | 
					      </Spin>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default UserEdit;
 | 
				
			||||||
@ -0,0 +1,108 @@
 | 
				
			|||||||
 | 
					import { Table, Tag } from "antd";
 | 
				
			||||||
 | 
					import { useTeamData } from "../../Hooks/Teams";
 | 
				
			||||||
 | 
					import { TUser } from "../../types/User/TUser";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  QueryObserverResult,
 | 
				
			||||||
 | 
					  RefetchOptions,
 | 
				
			||||||
 | 
					  RefetchQueryFilters,
 | 
				
			||||||
 | 
					} from "react-query";
 | 
				
			||||||
 | 
					import { useNavigate } from "react-router-dom";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import tagIcon from "../../assets/tagIcon.png";
 | 
				
			||||||
 | 
					const UserTable = ({
 | 
				
			||||||
 | 
					  data,
 | 
				
			||||||
 | 
					  isLoading,
 | 
				
			||||||
 | 
					  refetch,
 | 
				
			||||||
 | 
					}: {
 | 
				
			||||||
 | 
					  data: TUser[] | undefined;
 | 
				
			||||||
 | 
					  isLoading: boolean;
 | 
				
			||||||
 | 
					  refetch: <TPageData>(
 | 
				
			||||||
 | 
					    options?: (RefetchOptions & RefetchQueryFilters<TPageData>) | undefined
 | 
				
			||||||
 | 
					  ) => Promise<QueryObserverResult<TUser[], unknown>>;
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					  const navigate = useNavigate();
 | 
				
			||||||
 | 
					  const TeamData = useTeamData("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Row = (record: TUser) => {
 | 
				
			||||||
 | 
					    let isTextSelected = false;
 | 
				
			||||||
 | 
					    document.addEventListener("selectionchange", () => {
 | 
				
			||||||
 | 
					      const selection = window.getSelection();
 | 
				
			||||||
 | 
					      if (selection !== null && selection.toString() !== "") {
 | 
				
			||||||
 | 
					        isTextSelected = true;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        isTextSelected = false;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      onClick: () => {
 | 
				
			||||||
 | 
					        if (isTextSelected) {
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        navigate(`/users/${record.id}`);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Table
 | 
				
			||||||
 | 
					        onRow={(record) => Row(record)}
 | 
				
			||||||
 | 
					        dataSource={data?.map((u, i) => ({
 | 
				
			||||||
 | 
					          no: i + 1,
 | 
				
			||||||
 | 
					          team: TeamData?.data?.map((team: any) => {
 | 
				
			||||||
 | 
					            if (team.id === u?.team_id) {
 | 
				
			||||||
 | 
					              return team?.name;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              return null;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }),
 | 
				
			||||||
 | 
					          action: { id: u.id },
 | 
				
			||||||
 | 
					          ...u,
 | 
				
			||||||
 | 
					        }))}
 | 
				
			||||||
 | 
					        loading={isLoading}
 | 
				
			||||||
 | 
					        size="middle"
 | 
				
			||||||
 | 
					        columns={[
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: <img src={tagIcon} alt="" />,
 | 
				
			||||||
 | 
					            dataIndex: "no",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Username",
 | 
				
			||||||
 | 
					            dataIndex: "username",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            title: "Team",
 | 
				
			||||||
 | 
					            dataIndex: "team",
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            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: any, record: any) => {
 | 
				
			||||||
 | 
					              return record.is_active === value;
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					        ]}
 | 
				
			||||||
 | 
					        rowClassName={(record, index) =>
 | 
				
			||||||
 | 
					          index % 2 === 0 ? "odd-row" : "even-row"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default UserTable;
 | 
				
			||||||
@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					import { useRef, useState } from "react";
 | 
				
			||||||
 | 
					import { useUserData } from "../../Hooks/Users";
 | 
				
			||||||
 | 
					import AddUser from "./AddUser";
 | 
				
			||||||
 | 
					import UserTable from "./UserTable";
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import IconSearch from "../../assets/searchIcon.png";
 | 
				
			||||||
 | 
					//@ts-ignore
 | 
				
			||||||
 | 
					import addicon from "../../assets/addiconpng.png";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const User = () => {
 | 
				
			||||||
 | 
					  const [open, setOpen] = useState(false);
 | 
				
			||||||
 | 
					  const [search, setSearch] = useState("");
 | 
				
			||||||
 | 
					  const showModal = () => {
 | 
				
			||||||
 | 
					    setOpen(true);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const { data, refetch, isLoading } = useUserData({
 | 
				
			||||||
 | 
					    name: search,
 | 
				
			||||||
 | 
					    team: "",
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  const timerRef = useRef<NodeJS.Timeout | null>(null);
 | 
				
			||||||
 | 
					  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
 | 
				
			||||||
 | 
					    if (timerRef.current) {
 | 
				
			||||||
 | 
					      clearTimeout(timerRef.current);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const searchText = e.target.value;
 | 
				
			||||||
 | 
					    timerRef.current = setTimeout(() => {
 | 
				
			||||||
 | 
					      setSearch(searchText);
 | 
				
			||||||
 | 
					    }, 1000);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  const theme = localStorage.getItem("theme") === "true" ? true : false;
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      {open && <AddUser open={open} setOpen={setOpen} refetch={refetch} />}
 | 
				
			||||||
 | 
					      <div className="header d-flex">
 | 
				
			||||||
 | 
					        <p className="title">Users</p>
 | 
				
			||||||
 | 
					        <button
 | 
				
			||||||
 | 
					          className="btn-add d-flex"
 | 
				
			||||||
 | 
					          style={{ marginRight: 0 }}
 | 
				
			||||||
 | 
					          onClick={showModal}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <img src={addicon} style={{ marginRight: 8 }} alt="" />
 | 
				
			||||||
 | 
					          Invite User
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className="filter d-flex">
 | 
				
			||||||
 | 
					        <div className="search-div">
 | 
				
			||||||
 | 
					          <img src={IconSearch} alt="" />
 | 
				
			||||||
 | 
					          <input
 | 
				
			||||||
 | 
					            className={`search-input-${theme}`}
 | 
				
			||||||
 | 
					            type="text"
 | 
				
			||||||
 | 
					            placeholder="Search"
 | 
				
			||||||
 | 
					            onChange={handleSearchChange}
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <UserTable data={data} isLoading={isLoading} refetch={refetch} />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default User;
 | 
				
			||||||
@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import { callController } from "../../API/LayoutApi/callrequests";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useCallData = ({ status }: { status: string }) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`callback-requests/`, { status }],
 | 
				
			||||||
 | 
					    () => callController.read({ status }),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      refetchOnWindowFocus: false,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// export const useCompanyOne = (id: number | undefined) => {
 | 
				
			||||||
 | 
					//   return useQuery(
 | 
				
			||||||
 | 
					//     [`company/${id}/`, id],
 | 
				
			||||||
 | 
					//     () => companyController.companyOne(id),
 | 
				
			||||||
 | 
					//     { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					//   );
 | 
				
			||||||
 | 
					// };
 | 
				
			||||||
@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  TCompanyGetParams,
 | 
				
			||||||
 | 
					  companyController,
 | 
				
			||||||
 | 
					} from "../../API/LayoutApi/companies";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useCompanyData = ({
 | 
				
			||||||
 | 
					  name,
 | 
				
			||||||
 | 
					  page,
 | 
				
			||||||
 | 
					  is_active,
 | 
				
			||||||
 | 
					}: TCompanyGetParams) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`companies/`, name, page, is_active],
 | 
				
			||||||
 | 
					    () =>
 | 
				
			||||||
 | 
					      companyController.read({ name: name, page: page, is_active: is_active }),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useCompanyOne = (id: number | undefined) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`company/${id}/`, id],
 | 
				
			||||||
 | 
					    () => companyController.companyOne(id),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  TCustomerByCompanyGetParams,
 | 
				
			||||||
 | 
					  TCustomerGetParams,
 | 
				
			||||||
 | 
					  customerController,
 | 
				
			||||||
 | 
					} from "../../API/LayoutApi/customers";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useCustomerData = ({
 | 
				
			||||||
 | 
					  name,
 | 
				
			||||||
 | 
					  page,
 | 
				
			||||||
 | 
					  is_active,
 | 
				
			||||||
 | 
					  pageSize,
 | 
				
			||||||
 | 
					}: TCustomerGetParams) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`customers/`, name, page, is_active, pageSize],
 | 
				
			||||||
 | 
					    () =>
 | 
				
			||||||
 | 
					      customerController.read({
 | 
				
			||||||
 | 
					        name: name,
 | 
				
			||||||
 | 
					        page: page,
 | 
				
			||||||
 | 
					        is_active: is_active,
 | 
				
			||||||
 | 
					        pageSize: pageSize,
 | 
				
			||||||
 | 
					      }),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useCustomerByComanyData = ({
 | 
				
			||||||
 | 
					  name,
 | 
				
			||||||
 | 
					  id,
 | 
				
			||||||
 | 
					}: TCustomerByCompanyGetParams) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`customers-by-company/${id}`, name],
 | 
				
			||||||
 | 
					    () => customerController.customerByCompany(id, name),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useCustomerOne = (Id: number | undefined) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`customer/${Id}/`, Id],
 | 
				
			||||||
 | 
					    () => customerController.customerOne(Id),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import { TMyTaskHistoryGetParams, prof } from "../../API/LayoutApi/profile";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useMystatsData = ({
 | 
				
			||||||
 | 
					  start_date,
 | 
				
			||||||
 | 
					  end_date,
 | 
				
			||||||
 | 
					}: TMyTaskHistoryGetParams) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`stats/my-stats/`, start_date, end_date],
 | 
				
			||||||
 | 
					    () => prof.read({ start_date, end_date }),
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      refetchOnWindowFocus: false,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					// export const useMystatsData = ({
 | 
				
			||||||
 | 
					//   start_date,
 | 
				
			||||||
 | 
					//   end_date,
 | 
				
			||||||
 | 
					// }: TMyTaskHistoryGetParams) => {
 | 
				
			||||||
 | 
					//   return useQuery(
 | 
				
			||||||
 | 
					//     [`stats/my-stats/`, start_date, end_date],
 | 
				
			||||||
 | 
					//     () => prof.read({ start_date, end_date }),
 | 
				
			||||||
 | 
					//     {
 | 
				
			||||||
 | 
					//       refetchOnWindowFocus: false,
 | 
				
			||||||
 | 
					//     }
 | 
				
			||||||
 | 
					//   );
 | 
				
			||||||
 | 
					// };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useProfData = () => {
 | 
				
			||||||
 | 
					  return useQuery([`users/my-profile/`], () => prof.self(), {
 | 
				
			||||||
 | 
					    refetchOnWindowFocus: false,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useMyHistoryData = ({
 | 
				
			||||||
 | 
					  start_date,
 | 
				
			||||||
 | 
					  end_date,
 | 
				
			||||||
 | 
					}: TMyTaskHistoryGetParams) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`my-task-history/`, start_date, end_date],
 | 
				
			||||||
 | 
					    () => prof.myTaskHistory({ start_date, end_date }),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  requestsController,
 | 
				
			||||||
 | 
					  TRequestsGetParams,
 | 
				
			||||||
 | 
					} from "../../API/LayoutApi/requests";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useRequestsData = ({ search, status }: TRequestsGetParams) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`driver-requests/`, { search, status }],
 | 
				
			||||||
 | 
					    () => requestsController.read({ search, status }),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useRequestsOne = (userId: number | string | undefined): any => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`driver-requests/${userId || "all"}`, userId],
 | 
				
			||||||
 | 
					    () => requestsController.requestsOne(userId),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import { roleController } from "../../API/LayoutApi/role";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useRoleData = () => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`users/roles/`],
 | 
				
			||||||
 | 
					    () => roleController.read(),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useRoleOne = (id: string) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`users/role/${id}`, id],
 | 
				
			||||||
 | 
					    () => roleController.roleOne(id),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import { serviceController } from "../../API/LayoutApi/services";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useServiceData = () => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`services/`],
 | 
				
			||||||
 | 
					    () => serviceController.read(),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useServiceOne = (serviceId: number | undefined) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`service/${serviceId || "all"}`, serviceId],
 | 
				
			||||||
 | 
					    () => serviceController.serviceOne(serviceId),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import { TStatGetParams, statController } from "../../API/LayoutApi/statistic";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useStatsData = ({search, team, start_date, end_date}: TStatGetParams) => {
 | 
				
			||||||
 | 
					    return useQuery(
 | 
				
			||||||
 | 
					        [`stats/all-users/`, search, team, start_date, end_date],
 | 
				
			||||||
 | 
					        () => statController.read({search, team, start_date, end_date}),
 | 
				
			||||||
 | 
					        { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					export const useStatTeamData = ({search, start_date, end_date}: TStatGetParams) => {
 | 
				
			||||||
 | 
					    return useQuery(
 | 
				
			||||||
 | 
					        [`stats/all-teams/`, search, start_date, end_date],
 | 
				
			||||||
 | 
					        () => statController.team({search, start_date, end_date}),
 | 
				
			||||||
 | 
					        { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useCreatorsData = ({ start_date, end_date}: TStatGetParams) => {
 | 
				
			||||||
 | 
					    return useQuery(
 | 
				
			||||||
 | 
					        [`stats/task-creators/`, start_date, end_date],
 | 
				
			||||||
 | 
					        () => statController.creators({ start_date, end_date}),
 | 
				
			||||||
 | 
					        { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useCardData = ({ start_date, end_date}: TStatGetParams) => {
 | 
				
			||||||
 | 
					    return useQuery(
 | 
				
			||||||
 | 
					        [`stats/tasks-comparison/`, start_date, end_date],
 | 
				
			||||||
 | 
					        () => statController.cards({ start_date, end_date}),
 | 
				
			||||||
 | 
					        { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useStatOne = (
 | 
				
			||||||
 | 
					    statId: number | string | undefined
 | 
				
			||||||
 | 
					): any => {
 | 
				
			||||||
 | 
					    return useQuery(
 | 
				
			||||||
 | 
					        [`stat/${statId || "all"}`, statId],
 | 
				
			||||||
 | 
					        () => statController.statOne(statId),
 | 
				
			||||||
 | 
					        { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import { TTasksGetParams, taskController } from "../../API/LayoutApi/tasks";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useTasks = ({ search, status, team, page }: TTasksGetParams) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`tasks/`, search, status, team, page],
 | 
				
			||||||
 | 
					    () => taskController.read({ search, status, team, page }),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useTaskOne = (taskId: number) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`task/${taskId}/`, taskId],
 | 
				
			||||||
 | 
					    () => taskController.taskOne(taskId),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useTaskHistory = (Id: number | undefined) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`customer/${Id}/`, Id],
 | 
				
			||||||
 | 
					    () => taskController.getHistory(Id),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import { teamController } from "../../API/LayoutApi/teams";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useTeamData = (name: string) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`teams/?name=${name}/`, name],
 | 
				
			||||||
 | 
					    () => teamController.read(name),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useTeamOne = (
 | 
				
			||||||
 | 
					  teamId: number | string | undefined
 | 
				
			||||||
 | 
					): any => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`team/${teamId || "all"}`, teamId],
 | 
				
			||||||
 | 
					    () => teamController.teamOne(teamId),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import { updateController } from "../../API/LayoutApi/update";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// export const useUpdateData = (status: string): any => {
 | 
				
			||||||
 | 
					//   return useQuery(
 | 
				
			||||||
 | 
					//     [`updates/${status}`, status],
 | 
				
			||||||
 | 
					//     () => updateController.read(status),
 | 
				
			||||||
 | 
					//     { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					//   );
 | 
				
			||||||
 | 
					// };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useUpdateData = (status: string) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`shift-updates`, status],
 | 
				
			||||||
 | 
					    () => updateController.read(status),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useUpdateOne = (updateId: number | string | undefined): any => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`update/${updateId || "all"}`, updateId],
 | 
				
			||||||
 | 
					    () => updateController.updateOne(updateId),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					import { useQuery } from "react-query";
 | 
				
			||||||
 | 
					import { TUsersGetParams, userController } from "../../API/LayoutApi/users";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useUserData = ({name, team, role}: TUsersGetParams) => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`users/admins/`, {name, team, role}],
 | 
				
			||||||
 | 
					    () => userController.read({name, team, role}),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useUserOne = (
 | 
				
			||||||
 | 
					  userId: number | string | undefined
 | 
				
			||||||
 | 
					): any => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`user/${userId || "all"}`, userId],
 | 
				
			||||||
 | 
					    () => userController.userOne(userId),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const useCheckUser = (
 | 
				
			||||||
 | 
					  username: string 
 | 
				
			||||||
 | 
					): any => {
 | 
				
			||||||
 | 
					  return useQuery(
 | 
				
			||||||
 | 
					    [`user/${username}/`],
 | 
				
			||||||
 | 
					    () => userController.CheckUsername(username),
 | 
				
			||||||
 | 
					    { refetchOnWindowFocus: false }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					const NotInvitedYet = () => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default NotInvitedYet
 | 
				
			||||||
@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					import { Button, Result } from "antd";
 | 
				
			||||||
 | 
					import { Link } from "react-router-dom";
 | 
				
			||||||
 | 
					const Notfound = () => {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div>
 | 
				
			||||||
 | 
					      <Result
 | 
				
			||||||
 | 
					        status="404"
 | 
				
			||||||
 | 
					        title="404"
 | 
				
			||||||
 | 
					        subTitle="Sorry, the page you visited does not exist."
 | 
				
			||||||
 | 
					        extra={
 | 
				
			||||||
 | 
					          <Button type="primary">
 | 
				
			||||||
 | 
					            <Link to="/">Come back</Link>
 | 
				
			||||||
 | 
					          </Button>
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default Notfound;
 | 
				
			||||||
@ -0,0 +1,103 @@
 | 
				
			|||||||
 | 
					export const common = [
 | 
				
			||||||
 | 
					  "123456",
 | 
				
			||||||
 | 
					  "password",
 | 
				
			||||||
 | 
					  "12345678",
 | 
				
			||||||
 | 
					  "qwerty",
 | 
				
			||||||
 | 
					  "123456789",
 | 
				
			||||||
 | 
					  "12345",
 | 
				
			||||||
 | 
					  "1234",
 | 
				
			||||||
 | 
					  "111111",
 | 
				
			||||||
 | 
					  "1234567",
 | 
				
			||||||
 | 
					  "dragon",
 | 
				
			||||||
 | 
					  "123123",
 | 
				
			||||||
 | 
					  "baseball",
 | 
				
			||||||
 | 
					  "abc123",
 | 
				
			||||||
 | 
					  "football",
 | 
				
			||||||
 | 
					  "monkey",
 | 
				
			||||||
 | 
					  "letmein",
 | 
				
			||||||
 | 
					  "696969",
 | 
				
			||||||
 | 
					  "shadow",
 | 
				
			||||||
 | 
					  "master",
 | 
				
			||||||
 | 
					  "666666",
 | 
				
			||||||
 | 
					  "qwertyuiop",
 | 
				
			||||||
 | 
					  "123321",
 | 
				
			||||||
 | 
					  "mustang",
 | 
				
			||||||
 | 
					  "1234567890",
 | 
				
			||||||
 | 
					  "michael",
 | 
				
			||||||
 | 
					  "654321",
 | 
				
			||||||
 | 
					  "pussy",
 | 
				
			||||||
 | 
					  "superman",
 | 
				
			||||||
 | 
					  "1qaz2wsx",
 | 
				
			||||||
 | 
					  "7777777",
 | 
				
			||||||
 | 
					  "fuckyou",
 | 
				
			||||||
 | 
					  "121212",
 | 
				
			||||||
 | 
					  "000000",
 | 
				
			||||||
 | 
					  "qazwsx",
 | 
				
			||||||
 | 
					  "123qwe",
 | 
				
			||||||
 | 
					  "killer",
 | 
				
			||||||
 | 
					  "trustno1",
 | 
				
			||||||
 | 
					  "jordan",
 | 
				
			||||||
 | 
					  "jennifer",
 | 
				
			||||||
 | 
					  "zxcvbnm",
 | 
				
			||||||
 | 
					  "asdfgh",
 | 
				
			||||||
 | 
					  "hunter",
 | 
				
			||||||
 | 
					  "buster",
 | 
				
			||||||
 | 
					  "soccer",
 | 
				
			||||||
 | 
					  "harley",
 | 
				
			||||||
 | 
					  "batman",
 | 
				
			||||||
 | 
					  "andrew",
 | 
				
			||||||
 | 
					  "tigger",
 | 
				
			||||||
 | 
					  "sunshine",
 | 
				
			||||||
 | 
					  "iloveyou",
 | 
				
			||||||
 | 
					  "fuckme",
 | 
				
			||||||
 | 
					  "2000",
 | 
				
			||||||
 | 
					  "charlie",
 | 
				
			||||||
 | 
					  "robert",
 | 
				
			||||||
 | 
					  "thomas",
 | 
				
			||||||
 | 
					  "hockey",
 | 
				
			||||||
 | 
					  "ranger",
 | 
				
			||||||
 | 
					  "daniel",
 | 
				
			||||||
 | 
					  "starwars",
 | 
				
			||||||
 | 
					  "klaster",
 | 
				
			||||||
 | 
					  "112233",
 | 
				
			||||||
 | 
					  "george",
 | 
				
			||||||
 | 
					  "asshole",
 | 
				
			||||||
 | 
					  "computer",
 | 
				
			||||||
 | 
					  "michelle",
 | 
				
			||||||
 | 
					  "jessica",
 | 
				
			||||||
 | 
					  "pepper",
 | 
				
			||||||
 | 
					  "1111",
 | 
				
			||||||
 | 
					  "zxcvbn",
 | 
				
			||||||
 | 
					  "555555",
 | 
				
			||||||
 | 
					  "11111111",
 | 
				
			||||||
 | 
					  "131313",
 | 
				
			||||||
 | 
					  "freedom",
 | 
				
			||||||
 | 
					  "777777",
 | 
				
			||||||
 | 
					  "pass",
 | 
				
			||||||
 | 
					  "fuck",
 | 
				
			||||||
 | 
					  "maggie",
 | 
				
			||||||
 | 
					  "159753",
 | 
				
			||||||
 | 
					  "aaaaaa",
 | 
				
			||||||
 | 
					  "ginger",
 | 
				
			||||||
 | 
					  "princess",
 | 
				
			||||||
 | 
					  "joshua",
 | 
				
			||||||
 | 
					  "cheese",
 | 
				
			||||||
 | 
					  "amanda",
 | 
				
			||||||
 | 
					  "summer",
 | 
				
			||||||
 | 
					  "love",
 | 
				
			||||||
 | 
					  "ashley",
 | 
				
			||||||
 | 
					  "6969",
 | 
				
			||||||
 | 
					  "nicole",
 | 
				
			||||||
 | 
					  "chelsea",
 | 
				
			||||||
 | 
					  "biteme",
 | 
				
			||||||
 | 
					  "matthew",
 | 
				
			||||||
 | 
					  "access",
 | 
				
			||||||
 | 
					  "yankees",
 | 
				
			||||||
 | 
					  "987654321",
 | 
				
			||||||
 | 
					  "dallas",
 | 
				
			||||||
 | 
					  "austin",
 | 
				
			||||||
 | 
					  "thunder",
 | 
				
			||||||
 | 
					  "taylor",
 | 
				
			||||||
 | 
					  "matrix",
 | 
				
			||||||
 | 
					  "minecraft",
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					export const clear_local_storage = (): void => {
 | 
				
			||||||
 | 
					  localStorage.clear();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@ -0,0 +1,234 @@
 | 
				
			|||||||
 | 
					import { MenuProps } from "antd";
 | 
				
			||||||
 | 
					import { Link } from "react-router-dom";
 | 
				
			||||||
 | 
					import Company from "../Components/Companies/Companies";
 | 
				
			||||||
 | 
					import CompanyEdit from "../Components/Companies/CompaniesEdit";
 | 
				
			||||||
 | 
					import Customer from "../Components/Customers/Customers";
 | 
				
			||||||
 | 
					import CustomerEdit from "../Components/Customers/CustomersEdit";
 | 
				
			||||||
 | 
					import Service from "../Components/Services/Services";
 | 
				
			||||||
 | 
					import ServiceEdit from "../Components/Services/ServiceEdit";
 | 
				
			||||||
 | 
					import Task from "../Components/Tasks/Tasks";
 | 
				
			||||||
 | 
					import TeamEdit from "../Components/Teams/TeamEdit";
 | 
				
			||||||
 | 
					import Team from "../Components/Teams/Teams";
 | 
				
			||||||
 | 
					import User from "../Components/Users/Users";
 | 
				
			||||||
 | 
					import UserEdit from "../Components/Users/UserEdit";
 | 
				
			||||||
 | 
					import MenuItem from "antd/es/menu/MenuItem";
 | 
				
			||||||
 | 
					import Stat from "../Components/Statistics/Statistic";
 | 
				
			||||||
 | 
					import Profile from "../Components/Profile/Profile";
 | 
				
			||||||
 | 
					import Update from "../Components/Updates/Update";
 | 
				
			||||||
 | 
					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 = {
 | 
				
			||||||
 | 
					  path: string;
 | 
				
			||||||
 | 
					  component: JSX.Element;
 | 
				
			||||||
 | 
					  key: string;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const mainItems: TItems[] = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/companies/",
 | 
				
			||||||
 | 
					    component: <Company />,
 | 
				
			||||||
 | 
					    key: "/companies/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/companies/:id",
 | 
				
			||||||
 | 
					    component: <CompanyEdit />,
 | 
				
			||||||
 | 
					    key: "/company/:id",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/customers/",
 | 
				
			||||||
 | 
					    component: <Customer />,
 | 
				
			||||||
 | 
					    key: "/customers/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/customers/:id/",
 | 
				
			||||||
 | 
					    component: <CustomerEdit />,
 | 
				
			||||||
 | 
					    key: "/cusotmer/:id/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/services/",
 | 
				
			||||||
 | 
					    component: <Service />,
 | 
				
			||||||
 | 
					    key: "/services/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/services/:id/",
 | 
				
			||||||
 | 
					    component: <ServiceEdit />,
 | 
				
			||||||
 | 
					    key: "/service/:id/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/",
 | 
				
			||||||
 | 
					    component: <Task />,
 | 
				
			||||||
 | 
					    key: "tasks",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const superItems: TItems[] = [
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/teams/",
 | 
				
			||||||
 | 
					    component: <Team />,
 | 
				
			||||||
 | 
					    key: "/teams/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/teams/:id/",
 | 
				
			||||||
 | 
					    component: <TeamEdit />,
 | 
				
			||||||
 | 
					    key: "/team/:id/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/users/",
 | 
				
			||||||
 | 
					    component: <User />,
 | 
				
			||||||
 | 
					    key: "/users/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/users/:id/",
 | 
				
			||||||
 | 
					    component: <UserEdit />,
 | 
				
			||||||
 | 
					    key: "/user/:id/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/stats/",
 | 
				
			||||||
 | 
					    component: <Stat />,
 | 
				
			||||||
 | 
					    key: "/stats/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/profile/",
 | 
				
			||||||
 | 
					    component: <Profile />,
 | 
				
			||||||
 | 
					    key: "/profile/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/updates/",
 | 
				
			||||||
 | 
					    component: <Update />,
 | 
				
			||||||
 | 
					    key: "/updates/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/updates/:id/",
 | 
				
			||||||
 | 
					    component: <UpdateEdit />,
 | 
				
			||||||
 | 
					    key: "/update/:id/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/requests/",
 | 
				
			||||||
 | 
					    component: <Requests />,
 | 
				
			||||||
 | 
					    key: "/requests/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    path: "/call/",
 | 
				
			||||||
 | 
					    component: <Call />,
 | 
				
			||||||
 | 
					    key: "/call/",
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 360 B  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 511 B  | 
| 
		 After Width: | Height: | Size: 215 B  | 
| 
		 After Width: | Height: | Size: 215 B  | 
Some files were not shown because too many files have changed in this diff Show More
					Loading…
					
					
				
		Reference in new issue