Initial commit

This commit is contained in:
2025-10-13 00:23:31 -03:00
commit 42921527f8
725 changed files with 91395 additions and 0 deletions
@@ -0,0 +1,387 @@
import React, { useContext, useEffect, useRef, useState } from "react";
import { useHistory } from "react-router-dom";
import { makeStyles } from "@material-ui/core/styles";
import Paper from "@material-ui/core/Paper";
import SearchIcon from "@material-ui/icons/Search";
import InputBase from "@material-ui/core/InputBase";
import Tabs from "@material-ui/core/Tabs";
import Tab from "@material-ui/core/Tab";
import Badge from "@material-ui/core/Badge";
import MoveToInboxIcon from "@material-ui/icons/MoveToInbox";
import CheckBoxIcon from "@material-ui/icons/CheckBox";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Switch from "@material-ui/core/Switch";
import NewTicketModal from "../NewTicketModal";
import TicketsList from "../TicketsListCustom";
import TabPanel from "../TabPanel";
import { i18n } from "../../translate/i18n";
import { AuthContext } from "../../context/Auth/AuthContext";
import { Can } from "../Can";
import TicketsQueueSelect from "../TicketsQueueSelect";
import { Button } from "@material-ui/core";
import { TagsFilter } from "../TagsFilter";
import { UsersFilter } from "../UsersFilter";
const useStyles = makeStyles(theme => ({
ticketsWrapper: {
position: "relative",
display: "flex",
height: "100%",
flexDirection: "column",
overflow: "hidden",
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
borderRadius:0,
},
tabsHeader: {
flex: "none",
backgroundColor: theme.palette.tabHeaderBackground,
},
tabsInternal: {
flex: "none",
backgroundColor: theme.palette.tabHeaderBackground
},
settingsIcon: {
alignSelf: "center",
marginLeft: "auto",
padding: 8,
},
tab: {
minWidth: 120,
width: 120,
},
internalTab: {
minWidth: 120,
width: 120,
padding: 5
},
ticketOptionsBox: {
display: "flex",
justifyContent: "space-between",
alignItems: "center",
background: theme.palette.optionsBackground,
padding: theme.spacing(1),
},
ticketSearchLine: {
padding: theme.spacing(1),
},
serachInputWrapper: {
flex: 1,
background: theme.palette.total,
display: "flex",
borderRadius: 40,
padding: 4,
marginRight: theme.spacing(1),
},
searchIcon: {
color: "grey",
marginLeft: 6,
marginRight: 6,
alignSelf: "center",
},
searchInput: {
flex: 1,
border: "none",
borderRadius: 30,
},
insiderTabPanel: {
height: '100%',
marginTop: "-72px",
paddingTop: "72px"
},
insiderDoubleTabPanel: {
display:"flex",
flexDirection: "column",
marginTop: "-72px",
paddingTop: "72px",
height: "100%"
},
labelContainer: {
width: "auto",
padding: 0
},
iconLabelWrapper: {
flexDirection: "row",
'& > *:first-child': {
marginBottom: '3px !important',
marginRight: 16
}
},
insiderTabLabel: {
[theme.breakpoints.down(1600)]: {
display:'none'
}
},
smallFormControl: {
'& .MuiOutlinedInput-input': {
padding: "12px 10px",
},
'& .MuiInputLabel-outlined': {
marginTop: "-6px"
}
}
}));
const TicketsManagerTabs = () => {
const classes = useStyles();
const history = useHistory();
const [searchParam, setSearchParam] = useState("");
const [tab, setTab] = useState("open");
const [tabOpen, setTabOpen] = useState("open");
const [newTicketModalOpen, setNewTicketModalOpen] = useState(false);
const [showAllTickets, setShowAllTickets] = useState(false);
const searchInputRef = useRef();
const { user } = useContext(AuthContext);
const { profile } = user;
const [openCount, setOpenCount] = useState(0);
const [pendingCount, setPendingCount] = useState(0);
const userQueueIds = user.queues.map((q) => q.id);
const [selectedQueueIds, setSelectedQueueIds] = useState(userQueueIds || []);
const [selectedTags, setSelectedTags] = useState([]);
const [selectedUsers, setSelectedUsers] = useState([]);
useEffect(() => {
if (user.profile.toUpperCase() === "ADMIN") {
setShowAllTickets(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (tab === "search") {
searchInputRef.current.focus();
}
}, [tab]);
let searchTimeout;
const handleSearch = (e) => {
const searchedTerm = e.target.value.toLowerCase();
clearTimeout(searchTimeout);
if (searchedTerm === "") {
setSearchParam(searchedTerm);
setTab("open");
return;
}
searchTimeout = setTimeout(() => {
setSearchParam(searchedTerm);
}, 500);
};
const handleChangeTab = (e, newValue) => {
setTab(newValue);
};
const handleChangeTabOpen = (e, newValue) => {
setTabOpen(newValue);
};
const applyPanelStyle = (status) => {
if (tabOpen !== status) {
return { width: 0, height: 0 };
}
};
const handleCloseOrOpenTicket = (ticket) => {
setNewTicketModalOpen(false);
if (ticket !== undefined && ticket.uuid !== undefined) {
history.push(`/tickets/${ticket.uuid}`);
}
};
const handleSelectedTags = (selecteds) => {
const tags = selecteds.map((t) => t.id);
setSelectedTags(tags);
};
const handleSelectedUsers = (selecteds) => {
const users = selecteds.map((t) => t.id);
setSelectedUsers(users);
};
return (
<Paper elevation={0} variant="outlined" className={classes.ticketsWrapper}>
<NewTicketModal
modalOpen={newTicketModalOpen}
onClose={(ticket) => {
handleCloseOrOpenTicket(ticket);
}}
/>
<Paper elevation={0} square className={classes.tabsHeader}>
<Tabs
value={tab}
onChange={handleChangeTab}
variant="fullWidth"
indicatorColor="primary"
textColor="primary"
aria-label="icon label tabs example"
>
<Tab
value={"open"}
icon={<MoveToInboxIcon />}
label={i18n.t("tickets.tabs.open.title")}
classes={{ root: classes.tab }}
/>
<Tab
value={"closed"}
icon={<CheckBoxIcon />}
label={i18n.t("tickets.tabs.closed.title")}
classes={{ root: classes.tab }}
/>
<Tab
value={"search"}
icon={<SearchIcon />}
label={i18n.t("tickets.tabs.search.title")}
classes={{ root: classes.tab }}
/>
</Tabs>
</Paper>
<Paper square elevation={0} className={classes.ticketOptionsBox}>
{tab === "search" ? (
<div className={classes.serachInputWrapper}>
<SearchIcon className={classes.searchIcon} />
<InputBase
className={classes.searchInput}
inputRef={searchInputRef}
placeholder={i18n.t("tickets.search.placeholder")}
type="search"
onChange={handleSearch}
/>
</div>
) : (
<>
<Button
variant="outlined"
color="primary"
onClick={() => setNewTicketModalOpen(true)}
>
{i18n.t("ticketsManager.buttons.newTicket")}
</Button>
<Can
role={user.profile}
perform="tickets-manager:showall"
yes={() => (
<FormControlLabel
label={i18n.t("tickets.buttons.showAll")}
labelPlacement="start"
control={
<Switch
size="small"
checked={showAllTickets}
onChange={() =>
setShowAllTickets((prevState) => !prevState)
}
name="showAllTickets"
color="primary"
/>
}
/>
)}
/>
</>
)}
<TicketsQueueSelect
style={{ marginLeft: 6 }}
selectedQueueIds={selectedQueueIds}
userQueues={user?.queues}
onChange={(values) => setSelectedQueueIds(values)}
/>
</Paper>
<TabPanel value={tab} name="open" className={classes.ticketsWrapper}>
<Tabs
value={tabOpen}
onChange={handleChangeTabOpen}
indicatorColor="primary"
textColor="primary"
variant="fullWidth"
>
<Tab
label={
<Badge
className={classes.badge}
badgeContent={openCount}
color="primary"
>
{i18n.t("ticketsList.assignedHeader")}
</Badge>
}
value={"open"}
/>
<Tab
label={
<Badge
className={classes.badge}
badgeContent={pendingCount}
color="secondary"
>
{i18n.t("ticketsList.pendingHeader")}
</Badge>
}
value={"pending"}
/>
</Tabs>
<Paper className={classes.ticketsWrapper}>
<TicketsList
status="open"
showAll={showAllTickets}
selectedQueueIds={selectedQueueIds}
updateCount={(val) => setOpenCount(val)}
style={applyPanelStyle("open")}
/>
<TicketsList
status="pending"
selectedQueueIds={selectedQueueIds}
updateCount={(val) => setPendingCount(val)}
style={applyPanelStyle("pending")}
/>
</Paper>
</TabPanel>
<TabPanel value={tab} name="closed" className={classes.ticketsWrapper}>
<TicketsList
status="closed"
showAll={true}
selectedQueueIds={selectedQueueIds}
/>
</TabPanel>
<TabPanel value={tab} name="search" className={classes.ticketsWrapper}>
<TagsFilter onFiltered={handleSelectedTags} />
{profile === "admin" && (
<UsersFilter onFiltered={handleSelectedUsers} />
)}
<TicketsList
searchParam={searchParam}
showAll={true}
tags={selectedTags}
users={selectedUsers}
selectedQueueIds={selectedQueueIds}
/>
</TabPanel>
</Paper>
);
};
export default TicketsManagerTabs;