19-06 deploy

main
tteld 5 months ago
parent d12ed32c04
commit 82b59d8c54

Binary file not shown.

@ -43,6 +43,9 @@ export type TTaskPostFileParams = {
shift_update_id?: number; shift_update_id?: number;
description?: string; description?: string;
}; };
interface TMessageResponse {
message: string;
}
export const taskController = { export const taskController = {
async read(filterObject: TTasksGetParams) { async read(filterObject: TTasksGetParams) {
@ -76,12 +79,22 @@ export const taskController = {
}, },
async taskPatch(obj: TTasksPutParams, task_id: number | undefined) { async taskPatch(obj: TTasksPutParams, task_id: number | undefined) {
const { data } = await instance try {
.put<TTask>(`task/${task_id}/`, obj) const response = await instance.put<TTask | TMessageResponse>(
.then((u) => { `task/${task_id}/`,
return u; obj
}); );
return data; if (response.status === 202) {
const data = response.data as TMessageResponse;
message.success({ content: data.message });
}
return { data: response?.data as TTask, status: response?.status };
} catch (error: any) {
return {
data: error?.response?.data.data,
status: error?.response.status,
};
}
}, },
async addTaskController(obj: TTasksPostParams) { async addTaskController(obj: TTasksPostParams) {

@ -1,7 +1,7 @@
import axios from "axios"; import axios from "axios";
// const instance = axios.create({ // const instance = axios.create({
// baseURL: "http://10.10.10.12:8080/api/v1/", // baseURL: "http://10.10.10.19:8080/api/v1/",
// }); // });
const instance = axios.create({ const instance = axios.create({
baseURL: "https://api.tteld.co/api/v1/", baseURL: "https://api.tteld.co/api/v1/",

@ -25,21 +25,20 @@ export const RegisterApi = async (value: registerInterface) => {
timezone: data?.data.timezone, timezone: data?.data.timezone,
role: data?.data.role, role: data?.data.role,
}; };
message.success({
content: "Email sent successfully!",
duration: 3,
});
const userJSON = JSON.stringify(userObject); const userJSON = JSON.stringify(userObject);
localStorage.setItem("user", userJSON); localStorage.setItem("user", userJSON);
localStorage.setItem("access_token", data?.data.access_token); localStorage.setItem("access_token", data?.data.access_token);
localStorage.setItem("refresh_token", data?.data.refresh_token); localStorage.setItem("refresh_token", data?.data.refresh_token);
document.location.replace("/"); document.location.replace("/");
return status; return status;
} catch (error:any) { } catch (e) {}
setTimeout(() => {
message.error({ content: ' ', duration: 2 });
}, 1000);
}
}; };
export const validateUsername = async (value: any) => { export const validateUsername = async (value: any) => {
const { status } = await instance.get(`users/check/${value}/`); const { status } = await instance.get(`users/check/${value}/`);
return status return status;
}; };

@ -73,7 +73,7 @@ const App: React.FC = () => {
setData(data); setData(data);
}); });
} }
}, [admin_id]); }, []);
useEffect(() => { useEffect(() => {
if (data) { if (data) {
@ -137,8 +137,8 @@ const App: React.FC = () => {
<img alt="" src={requestIcon} /> <img alt="" src={requestIcon} />
), ),
getItem( getItem(
<Link to="call/">Call Requests</Link>, <Link to="calls/">Call Requests</Link>,
"call/", "calls/",
<img alt="" src={callIcon} /> <img alt="" src={callIcon} />
) )
); );
@ -209,8 +209,52 @@ const App: React.FC = () => {
</Menu.Item> </Menu.Item>
</Menu> </Menu>
); );
// const [isOnline, setIsOnline] = useState<boolean>(navigator.onLine);
// const reconnectingMessageKey = "reconnectingMessage";
// const reconnectingMessageContent = "Reconnecting...";
// useEffect(() => {
// let reconnectingTimeout: NodeJS.Timeout | null = null;
// const handleOnlineStatus = () => {
// setIsOnline(true);
// message.success({ content: "Reconnected!" });
// if (isOnline === false) {
// message.destroy(reconnectingMessageKey);
// }
// if (reconnectingTimeout) {
// clearTimeout(reconnectingTimeout);
// }
// };
// const handleOfflineStatus = () => {
// setIsOnline(false);
// if (isOnline !== false) {
// message.loading({
// content: reconnectingMessageContent,
// key: reconnectingMessageKey,
// duration: 0,
// });
// reconnectingTimeout = setTimeout(() => {
// message.destroy(reconnectingMessageKey);
// }, 30 * 60 * 1000); // 30 minutes
// }
// };
// window.addEventListener("online", handleOnlineStatus);
// window.addEventListener("offline", handleOfflineStatus);
// return () => {
// window.removeEventListener("online", handleOnlineStatus);
// window.removeEventListener("offline", handleOfflineStatus);
// if (reconnectingTimeout) {
// clearTimeout(reconnectingTimeout);
// }
// };
// }, [isOnline]);
let taskSocket: WebSocket; let taskSocket: WebSocket;
const [isLive, setIslive] = useState(true); const [isLive, setIslive] = useState(false);
const [socketData, setSocketData] = useState<any>(); const [socketData, setSocketData] = useState<any>();
const connect = async () => { const connect = async () => {
try { try {
@ -219,7 +263,7 @@ const App: React.FC = () => {
admin_id admin_id
) { ) {
// taskSocket = new WebSocket( // taskSocket = new WebSocket(
// `ws://10.10.10.12:8080/global/?user_id=${admin_id}` // `ws://10.10.10.19:8080/global/?user_id=${admin_id}`
// ); // );
taskSocket = new WebSocket( taskSocket = new WebSocket(
`wss://api.tteld.co/global/?user_id=${admin_id}` `wss://api.tteld.co/global/?user_id=${admin_id}`
@ -236,6 +280,7 @@ const App: React.FC = () => {
console.error("WebSocket error:", errorEvent); console.error("WebSocket error:", errorEvent);
}); });
taskSocket.addEventListener("close", (event) => { taskSocket.addEventListener("close", (event) => {
console.log("WebSocket: clocse");
setIslive(false); setIslive(false);
}); });
} }
@ -245,6 +290,15 @@ const App: React.FC = () => {
useEffect(() => { useEffect(() => {
connect(); connect();
}, []); }, []);
// function checkConnection() {
// if (!isLive) {
// connect();
// }
// }
// setInterval(checkConnection, 5000);
const [api, contextHolder] = notification.useNotification(); const [api, contextHolder] = notification.useNotification();
const openNotification = useCallback( const openNotification = useCallback(
(placement: NotificationPlacement, data: TCall) => { (placement: NotificationPlacement, data: TCall) => {
@ -436,7 +490,13 @@ const App: React.FC = () => {
<Route <Route
key={"task"} key={"task"}
path="/" path="/"
element={<Task socketData={socketData} />} element={
<Task
socketData={socketData}
connect={connect}
isLive={isLive}
/>
}
/> />
{mainItems && {mainItems &&
mainItems.map((u) => ( mainItems.map((u) => (

@ -38,12 +38,10 @@ const Register: React.FC = () => {
} }
}); });
} else if (status === 200) { } else if (status === 200) {
setTimeout(() => {
message.error({ message.error({
content: "This username already exists!", content: "This username already exists!",
duration: 2, duration: 2,
}); });
}, 1000);
} }
}); });
}; };

@ -11,6 +11,7 @@ import {
Col, Col,
Input, Input,
Button, Button,
Select,
} from "antd"; } from "antd";
import { customerController } from "../../API/LayoutApi/customers"; import { customerController } from "../../API/LayoutApi/customers";
import Notfound from "../../Utils/Notfound"; import Notfound from "../../Utils/Notfound";
@ -20,6 +21,17 @@ import { useState } from "react";
import infoIcon from "../../assets/infoIcon.png"; import infoIcon from "../../assets/infoIcon.png";
// @ts-ignore // @ts-ignore
import infoIconActive from "../../assets/infoIconActive.png"; import infoIconActive from "../../assets/infoIconActive.png";
// @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 { useCompanyData } from "../../Hooks/Companies";
const TabPane = Tabs.TabPane; const TabPane = Tabs.TabPane;
@ -29,11 +41,12 @@ type params = {
const CustomerEdit = () => { const CustomerEdit = () => {
const { id } = useParams<params>(); const { id } = useParams<params>();
const { data, refetch, status } = useCustomerOne(id); const { data, status } = useCustomerOne(id);
let navigate = useNavigate(); let navigate = useNavigate();
const onSubmit = async (value: any) => { const onSubmit = async (value: any) => {
value.company_id = companyVal;
await customerController.customerPatch(value, id); await customerController.customerPatch(value, id);
navigate(-1); window.location.replace("/#/customers/");
}; };
const ClickDelete = () => { const ClickDelete = () => {
@ -46,6 +59,28 @@ const CustomerEdit = () => {
} }
}; };
const [activeTab, setActiveTab] = useState("1"); const [activeTab, setActiveTab] = useState("1");
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 [companyName, setCompanyName] = useState<string>("");
const [companyVal, setCompanyVal] = useState<any>();
const { data: companyData } = useCompanyData({ name: companyName });
return ( return (
<div> <div>
<Spin size="large" spinning={!data}> <Spin size="large" spinning={!data}>
@ -96,9 +131,35 @@ const CustomerEdit = () => {
wrapperCol={{ span: "100%" }} wrapperCol={{ span: "100%" }}
label="Company" label="Company"
> >
<Input <Select
defaultValue={data?.company?.name} defaultValue={data?.company?.name}
readOnly onSearch={(value: any) => setCompanyName(value)}
onChange={(e: any) => {
setCompanyVal(e);
}}
options={companyData?.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,
}))}
filterOption={false}
autoClearSearchValue={false}
allowClear
// value={companyName}
/> />
</Form.Item> </Form.Item>
</Col> </Col>

@ -0,0 +1,45 @@
import { TTask } from "../../types/Tasks/TTasks";
import { Modal } from "antd";
import TaskTable from "./TaskTable";
const ErrorUncompletedTasksModal = ({
errorModal,
setErrorModal,
uncomletedData,
}: {
uncomletedData: TTask[] | undefined;
errorModal: boolean;
setErrorModal: any;
}) => {
const handleCancel = () => {
setErrorModal(!errorModal);
};
return (
<Modal
onCancel={handleCancel}
footer={null}
open={errorModal}
width={1400}
maskClosable={true}
>
<div className="uncomleted-tasks-modal">
<p
className="p-driver"
style={{ textAlign: "center", marginBottom: 10, color: "red" }}
>
You have unfinished tasks. You cannot assign another one until they
are completed.
</p>
<TaskTable
data={{ characters: uncomletedData }}
showTaskModal={false}
showErrorModal={false}
isLoading={false}
setErrorModal={setErrorModal}
/>
</div>
</Modal>
);
};
export default ErrorUncompletedTasksModal;

@ -16,7 +16,7 @@ import { useEffect, useState } from "react";
import { taskController } from "../../API/LayoutApi/tasks"; import { taskController } from "../../API/LayoutApi/tasks";
import { useTeamData } from "../../Hooks/Teams"; import { useTeamData } from "../../Hooks/Teams";
import { TTeam } from "../../types/Team/TTeam"; import { TTeam } from "../../types/Team/TTeam";
import { EditOutlined, CaretRightOutlined } from "@ant-design/icons"; import { EditOutlined } from "@ant-design/icons";
import { TSocket } from "../../types/common/TSocket"; import { TSocket } from "../../types/common/TSocket";
// @ts-ignore // @ts-ignore
import closeIcon from "../../assets/closeIcon.png"; import closeIcon from "../../assets/closeIcon.png";
@ -201,9 +201,9 @@ const TaskModal = ({
setModalOpen(!modalOpen); setModalOpen(!modalOpen);
}; };
const nextStatus = (status : string) => { // const nextStatus = (status : string) => {
console.log(); // console.log();
} // }
useEffect(() => { useEffect(() => {
if (socketData && socketData.task) { if (socketData && socketData.task) {

@ -25,12 +25,16 @@ const TaskTable = ({
data, data,
isLoading, isLoading,
showTaskModal, showTaskModal,
showErrorModal,
setErrorModal,
}: { }: {
data: { data: {
characters: TTask[] | undefined; characters: TTask[] | undefined;
}; };
showTaskModal: any; showTaskModal: any;
showErrorModal: any;
isLoading: boolean; isLoading: boolean;
setErrorModal: React.Dispatch<React.SetStateAction<boolean>>;
}) => { }) => {
const moment = require("moment"); const moment = require("moment");
const statusClick = (record: any) => { const statusClick = (record: any) => {
@ -42,7 +46,13 @@ const TaskTable = ({
const value = { const value = {
status: "Checking", status: "Checking",
}; };
taskController.taskPatch(value, record.id); taskController
.taskPatch(value, record?.id)
.then((response: { data: TTask; status: number }) => {
if (response?.status == 403) {
showErrorModal(response);
}
});
}, },
}); });
} }
@ -54,7 +64,9 @@ const TaskTable = ({
const value = { const value = {
status: "Done", status: "Done",
}; };
taskController.taskPatch(value, record.id); taskController.taskPatch(value, record.id).then(() => {
setErrorModal(false);
});
}, },
}); });
} }
@ -138,7 +150,7 @@ const TaskTable = ({
justifyContent: "space-around", justifyContent: "space-around",
}} }}
> >
{record.via_telegram && ( {record?.via_telegram && (
<Tooltip placement="topLeft" title={"Created via Telegram"}> <Tooltip placement="topLeft" title={"Created via Telegram"}>
<img src={tgIcon} alt="" style={{ width: 20, height: 20 }} /> <img src={tgIcon} alt="" style={{ width: 20, height: 20 }} />
</Tooltip> </Tooltip>
@ -162,7 +174,7 @@ const TaskTable = ({
width: isMobile ? "1%" : "5%", width: isMobile ? "1%" : "5%",
fixed: isMobile ? "left" : false, fixed: isMobile ? "left" : false,
key: "2", key: "2",
render: (text: any, record: TTask) => ( render: (text?: any, record?: TTask) => (
<div <div
style={{ style={{
display: "flex", display: "flex",
@ -220,9 +232,9 @@ const TaskTable = ({
ellipsis: { ellipsis: {
showTitle: false, showTitle: false,
}, },
render: (item: { title: string; id: number }, record: TTask) => ( render: (item?: { title?: string; id: number }, record?: TTask) => (
<Tooltip placement="topLeft" title={item?.title}> <Tooltip placement="topLeft" title={item?.title}>
{item.title} {item?.title}
</Tooltip> </Tooltip>
), ),
}, },
@ -234,7 +246,7 @@ const TaskTable = ({
ellipsis: { ellipsis: {
showTitle: false, showTitle: false,
}, },
render: (status: string) => ( render: (status?: string) => (
<span> <span>
{status === "Done" && <p className="status-done">Done</p>} {status === "Done" && <p className="status-done">Done</p>}
{status === "Checking" && ( {status === "Checking" && (

@ -16,9 +16,18 @@ import IconSearch from "../../assets/searchIcon.png";
import TaskModal from "./TaskModal"; import TaskModal from "./TaskModal";
import TaskUploadModal from "./TaskUploadModal"; import TaskUploadModal from "./TaskUploadModal";
import { TSocket } from "../../types/common/TSocket"; import { TSocket } from "../../types/common/TSocket";
import ErrorUncompletedTasksModal from "./ErrorUncompletedTasksModal";
const { Option } = Select; const { Option } = Select;
const Task = ({ socketData }: { socketData: TSocket | undefined }) => { const Task = ({
socketData,
connect,
isLive,
}: {
socketData: TSocket | undefined;
connect: () => Promise<void>;
isLive: boolean;
}) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [modalOpen, setModalOpen] = useState(false); const [modalOpen, setModalOpen] = useState(false);
const [characters, setCharacters] = useState<TTask[] | undefined>(); const [characters, setCharacters] = useState<TTask[] | undefined>();
@ -27,6 +36,8 @@ const Task = ({ socketData }: { socketData: TSocket | undefined }) => {
const [status, setStatus] = useState<any>(); const [status, setStatus] = useState<any>();
const [page, setPage] = useState(1); const [page, setPage] = useState(1);
const [uploadOpen, setUploadOpen] = useState(false); const [uploadOpen, setUploadOpen] = useState(false);
const [errorModal, setErrorModal] = useState(false);
const [uncomletedData, setUncomletedData] = useState<TTask[]>();
useEffect(() => { useEffect(() => {
if ( if (
@ -34,8 +45,8 @@ const Task = ({ socketData }: { socketData: TSocket | undefined }) => {
socketData.task && socketData.task &&
((role !== "Checker" && ((role !== "Checker" &&
(!team || team.includes(socketData?.task?.assigned_to?.id))) || (!team || team.includes(socketData?.task?.assigned_to?.id))) ||
role === "Checker") && role === "Checker")
(!status || status.includes(socketData?.task?.status)) // &&(!status || status.includes(socketData?.task?.status))
) { ) {
setCharacters((prev: any) => { setCharacters((prev: any) => {
if (prev && prev?.length >= 15) { if (prev && prev?.length >= 15) {
@ -139,6 +150,11 @@ const Task = ({ socketData }: { socketData: TSocket | undefined }) => {
setRecordTask(e); setRecordTask(e);
setModalOpen(true); setModalOpen(true);
}; };
const showErrorModal = (e: { data: TTask[]; status: number }) => {
setUncomletedData(e?.data);
setErrorModal(true);
};
const Next = () => { const Next = () => {
const a = Number(page) + 1; const a = Number(page) + 1;
@ -164,6 +180,7 @@ const Task = ({ socketData }: { socketData: TSocket | undefined }) => {
}, 1000); }, 1000);
}; };
const theme = localStorage.getItem("theme") === "true" ? true : false; const theme = localStorage.getItem("theme") === "true" ? true : false;
return ( return (
<div> <div>
{open && <AddTask open={open} setOpen={setOpen} />} {open && <AddTask open={open} setOpen={setOpen} />}
@ -185,6 +202,13 @@ const Task = ({ socketData }: { socketData: TSocket | undefined }) => {
setModalOpen={setModalOpen} setModalOpen={setModalOpen}
/> />
)} )}
{errorModal && (
<ErrorUncompletedTasksModal
errorModal={errorModal}
setErrorModal={setErrorModal}
uncomletedData={uncomletedData}
/>
)}
<div className="header d-flex"> <div className="header d-flex">
<div className="header-title d-flex"> <div className="header-title d-flex">
<p className="title">Tasks</p> <p className="title">Tasks</p>
@ -204,7 +228,9 @@ const Task = ({ socketData }: { socketData: TSocket | undefined }) => {
className={`btn-refresh-${theme && "dark"} d-flex`} className={`btn-refresh-${theme && "dark"} d-flex`}
onClick={() => { onClick={() => {
refetch(); refetch();
// connect(); if (!isLive) {
connect();
}
}} }}
> >
<img <img
@ -255,6 +281,8 @@ const Task = ({ socketData }: { socketData: TSocket | undefined }) => {
data={{ characters }} data={{ characters }}
isLoading={isLoading} isLoading={isLoading}
showTaskModal={showTaskModal} showTaskModal={showTaskModal}
showErrorModal={showErrorModal}
setErrorModal={setErrorModal}
/> />
<Space style={{ width: "100%", marginTop: 10 }} direction="vertical"> <Space style={{ width: "100%", marginTop: 10 }} direction="vertical">
<Space style={{ width: "100%", justifyContent: "flex-end" }} wrap> <Space style={{ width: "100%", justifyContent: "flex-end" }} wrap>

@ -1,12 +1,5 @@
import { TUser } from "../User/TUser"; import { TUser } from "../User/TUser";
type data = {
id: number;
name?: string;
title?: string;
username?: string;
};
export type TTask = { export type TTask = {
id: number; id: number;
note: string; note: string;

Loading…
Cancel
Save