You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

348 lines
10 KiB

import { useCallback, useEffect, useRef, useState } from "react";
import AddTask from "./AddTask";
import { Button, Input, Select, Space, 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 { 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);
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
refetch={refetch}
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 }}
isLoading={isLoading}
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;