commit
8cb36fc636
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "pwa-chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Chrome against localhost",
|
||||||
|
"url": "http://localhost:3000",
|
||||||
|
"webRoot": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20.6667 18.6667H19.6133L19.24 18.3067C20.5467 16.7867 21.3333 14.8133 21.3333 12.6667C21.3333 7.88 17.4533 4 12.6667 4C7.88 4 4 7.88 4 12.6667C4 17.4533 7.88 21.3333 12.6667 21.3333C14.8133 21.3333 16.7867 20.5467 18.3067 19.24L18.6667 19.6133V20.6667L25.3333 27.32L27.32 25.3333L20.6667 18.6667ZM12.6667 18.6667C9.34667 18.6667 6.66667 15.9867 6.66667 12.6667C6.66667 9.34667 9.34667 6.66667 12.6667 6.66667C15.9867 6.66667 18.6667 9.34667 18.6667 12.6667C18.6667 15.9867 15.9867 18.6667 12.6667 18.6667Z" fill="current" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 641 B |
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
|
@ -1,12 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import BtnBaseStyled from "./Btn.styled";
|
|
||||||
|
|
||||||
const BtnComponent = ({ text, bgcolor, fontcolor,...props }) => {
|
|
||||||
return (
|
|
||||||
<BtnBaseStyled bgcolor={bgcolor} fontcolor={fontcolor} {...props}>
|
|
||||||
{text}
|
|
||||||
</BtnBaseStyled>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default BtnComponent;
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import React from "react";
|
||||||
|
import { BadgeComponentStyled } from "./BadgeComponent.style";
|
||||||
|
|
||||||
|
const BadgeComponent = ({ counter,fontSize, position, top, left, right, bottom,bgcolor }) => {
|
||||||
|
return (
|
||||||
|
<BadgeComponentStyled position={position} top={top} left={left} right={right} bottom={bottom} fontSize={fontSize} bgcolor={bgcolor}>
|
||||||
|
{counter}
|
||||||
|
</BadgeComponentStyled>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BadgeComponent;
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { color } from "../../../style/varibles";
|
||||||
|
|
||||||
|
export const BadgeComponentStyled = styled.span`
|
||||||
|
position: ${({ position }) => (position ? position : "relative")};
|
||||||
|
top: ${({ top }) => (top ? top : "initial")};
|
||||||
|
left: ${({ left }) => (left ? left : "initial")};
|
||||||
|
right: ${({ right }) => (right ? right : "initial")};
|
||||||
|
bottom: ${({ bottom }) => (bottom ? bottom : "initial")};
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 50px;
|
||||||
|
object-fit: cover;
|
||||||
|
width: 21px;
|
||||||
|
height: 21px;
|
||||||
|
font-size: ${({ fontSize }) => (fontSize ? fontSize : "16px")};
|
||||||
|
color: ${color.pricinpal.blanco};
|
||||||
|
background-color: ${({ bgcolor }) => (bgcolor ? bgcolor : color.status.yes)};
|
||||||
|
`;
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import React from "react";
|
||||||
|
import BtnBaseStyled from "./Btn.styled";
|
||||||
|
|
||||||
|
const BtnComponent = ({ text, bgcolor, fontSize, fontcolor, ...props }) => {
|
||||||
|
return (
|
||||||
|
<BtnBaseStyled bgcolor={bgcolor} fontcolor={fontcolor} fontSize={fontSize} {...props}>
|
||||||
|
{text}
|
||||||
|
</BtnBaseStyled>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BtnComponent;
|
||||||
|
|
|
@ -8,7 +8,7 @@ const BtnBaseStyled = styled.button`
|
||||||
padding: 6px 16px 3px;
|
padding: 6px 16px 3px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
margin: 12px 0;
|
margin: 12px 0;
|
||||||
font-size: 18px;
|
font-size: ${({ fontSize }) => fontSize ? fontSize: "18px"};
|
||||||
font-family: "Helvetica55";
|
font-family: "Helvetica55";
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
transition: all 0.2s linear;
|
transition: all 0.2s linear;
|
|
@ -1,7 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import PageTitle from "../../PageTitle/PageTitle";
|
import PageTitle from "../../PageTitle/PageTitle";
|
||||||
|
|
||||||
|
|
||||||
import MainContainerStyled, {
|
import MainContainerStyled, {
|
||||||
TitleContainerStyled,
|
TitleContainerStyled,
|
||||||
ContentContainerStyled,
|
ContentContainerStyled,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
import { color } from "../../../style/varibles";
|
||||||
|
|
||||||
const MainContainerStyled = styled.main`
|
const MainContainerStyled = styled.main`
|
||||||
padding-left: 97px;
|
padding-left: 97px;
|
||||||
|
@ -21,6 +22,8 @@ const ContentContainerStyled = styled.div`
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: ${color.complement.azulOscuro};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default MainContainerStyled;
|
export default MainContainerStyled;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import BtnComponent from "../Base/BTN/Btn";
|
import BtnComponent from "../Base/Btn/Btn";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ConfirmationModalStyled,
|
ConfirmationModalStyled,
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import LoadingStyled from "./Loading.style"
|
|
||||||
|
|
||||||
const Loading = () => {
|
|
||||||
return <LoadingStyled/>;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Loading;
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import React from "react";
|
||||||
|
import LoadingStyled from "./LoadingScreen.style"
|
||||||
|
|
||||||
|
const LoadingScreen = () => {
|
||||||
|
return <LoadingStyled/>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoadingScreen;
|
|
@ -3,7 +3,7 @@ import { color } from "../../../../style/varibles";
|
||||||
|
|
||||||
const InputComponentStyled = styled.input`
|
const InputComponentStyled = styled.input`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: transparent;
|
background: ${color.complement.azulOscuro};
|
||||||
border: none;
|
border: none;
|
||||||
color: ${color.complement.azulCielo};
|
color: ${color.complement.azulCielo};
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -63,7 +63,7 @@ const MenuComponent = () => {
|
||||||
<MenuItem icon={<Tickets />} text="Tickets" to="/tickets" hover={hover} />
|
<MenuItem icon={<Tickets />} text="Tickets" to="/tickets" hover={hover} />
|
||||||
<MenuItem icon={<Contact />} text="Contatos" to="/contacts" hover={hover} />
|
<MenuItem icon={<Contact />} text="Contatos" to="/contacts" hover={hover} />
|
||||||
<MenuItem icon={<Reminder />} text="Lembretes" to="/schedulesReminder" hover={hover} />
|
<MenuItem icon={<Reminder />} text="Lembretes" to="/schedulesReminder" hover={hover} />
|
||||||
<MenuItem icon={<FastAanswer />} text="Respostas" to="" hover={hover} />
|
<MenuItem icon={<FastAanswer />} text="Respostas" to="/quickAnswers" hover={hover} />
|
||||||
<Divider />
|
<Divider />
|
||||||
<MenuItem icon={<Users />} text="Usuários" to="/users" hover={hover} />
|
<MenuItem icon={<Users />} text="Usuários" to="/users" hover={hover} />
|
||||||
<MenuItem icon={<Rows />} text="Filas" to="/Queues" hover={hover} />
|
<MenuItem icon={<Rows />} text="Filas" to="/Queues" hover={hover} />
|
||||||
|
|
|
@ -45,6 +45,7 @@ const useStyles = makeStyles((theme) => ({
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
padding: "20px 20px 20px 20px",
|
padding: "20px 20px 20px 20px",
|
||||||
overflowY: "scroll",
|
overflowY: "scroll",
|
||||||
|
height: "50vh",
|
||||||
[theme.breakpoints.down("sm")]: {
|
[theme.breakpoints.down("sm")]: {
|
||||||
paddingBottom: "90px",
|
paddingBottom: "90px",
|
||||||
},
|
},
|
||||||
|
@ -541,11 +542,6 @@ const MessagesList = ({ ticketId, isGroup }) => {
|
||||||
})}
|
})}
|
||||||
></span>
|
></span>
|
||||||
<div className={classes.quotedMsg}>
|
<div className={classes.quotedMsg}>
|
||||||
{!message.quotedMsg?.fromMe && (
|
|
||||||
<span className={classes.messageContactName}>
|
|
||||||
{message.quotedMsg?.contact?.name}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{message.quotedMsg?.body}
|
{message.quotedMsg?.body}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { useLocation } from "react-router-dom";
|
||||||
import { PageTitleStyled } from "./PageTitle.style";
|
import { PageTitleStyled } from "./PageTitle.style";
|
||||||
|
|
||||||
import UserBtn from "./UserBtn/UserBtn";
|
import UserBtn from "./UserBtn/UserBtn";
|
||||||
|
@ -7,15 +8,54 @@ import { AuthContext } from "../../context/Auth/AuthContext";
|
||||||
import logo from "../../assets/images/Logo.png";
|
import logo from "../../assets/images/Logo.png";
|
||||||
|
|
||||||
const PageTitle = () => {
|
const PageTitle = () => {
|
||||||
|
const path = useLocation();
|
||||||
|
const [title, setTitle] = React.useState();
|
||||||
const [modal, setModal] = React.useState(false);
|
const [modal, setModal] = React.useState(false);
|
||||||
const { user } = React.useContext(AuthContext);
|
const { user } = React.useContext(AuthContext);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
switch (path.pathname) {
|
||||||
|
case "/tickets":
|
||||||
|
setTitle("Tickets");
|
||||||
|
break;
|
||||||
|
case "/contacts":
|
||||||
|
setTitle("Contatos");
|
||||||
|
break;
|
||||||
|
case "/schedulesReminder":
|
||||||
|
setTitle("Lembretes");
|
||||||
|
break;
|
||||||
|
case "/quickAnswers":
|
||||||
|
setTitle("Respostas Rápidas");
|
||||||
|
break;
|
||||||
|
case "/users":
|
||||||
|
setTitle("Usuários");
|
||||||
|
break;
|
||||||
|
case "/Queues":
|
||||||
|
setTitle("Filas");
|
||||||
|
break;
|
||||||
|
case "/connections":
|
||||||
|
setTitle("Conexões");
|
||||||
|
break;
|
||||||
|
case "/report":
|
||||||
|
setTitle("Relatórios");
|
||||||
|
break;
|
||||||
|
case "/super":
|
||||||
|
setTitle("Supervisão");
|
||||||
|
break;
|
||||||
|
case "/Settings":
|
||||||
|
setTitle("Configurações");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
setTitle("Dashboard");
|
||||||
|
}
|
||||||
|
}, [path]);
|
||||||
|
|
||||||
const handleModal = () => {
|
const handleModal = () => {
|
||||||
setModal(!modal);
|
setModal(!modal);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<PageTitleStyled>
|
<PageTitleStyled>
|
||||||
<h1>PageTitle</h1>
|
<h1>{title}</h1>
|
||||||
<UserBtn user={user} img={logo} modal={modal} modalSet={handleModal} />
|
<UserBtn user={user} img={logo} modal={modal} modalSet={handleModal} />
|
||||||
</PageTitleStyled>
|
</PageTitleStyled>
|
||||||
);
|
);
|
||||||
|
|
|
@ -34,7 +34,7 @@ const UserBtn = ({ user, img, modal, modalSet }) => {
|
||||||
<UserItem title="Sair" icon={<Signoff />} onClick={handleModal} />
|
<UserItem title="Sair" icon={<Signoff />} onClick={handleModal} />
|
||||||
</UserModalListStyled>
|
</UserModalListStyled>
|
||||||
</UserModalStyled>
|
</UserModalStyled>
|
||||||
<UserModal modal={modalUser} click={handleModalUser}/>
|
<UserModal modal={modalUser} click={handleModalUser} userId={user.id}/>
|
||||||
<ConfirmationModal title="Sair?" modal={modalConfirm} click={{ handleModal, handleLogout }}>
|
<ConfirmationModal title="Sair?" modal={modalConfirm} click={{ handleModal, handleLogout }}>
|
||||||
Deseja Sair do sistema?
|
Deseja Sair do sistema?
|
||||||
</ConfirmationModal>
|
</ConfirmationModal>
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
import React from "react";
|
||||||
|
import { useParams, useHistory } from "react-router-dom";
|
||||||
|
|
||||||
|
import { toast } from "react-toastify";
|
||||||
|
import openSocket from "socket.io-client";
|
||||||
|
|
||||||
|
import ContactDrawer from "../ContactDrawer";
|
||||||
|
import MessageInput from "../MessageInput";
|
||||||
|
import TicketHeader from "../TicketHeader";
|
||||||
|
import TicketInfo from "../TicketInfo";
|
||||||
|
import TicketActionButtons from "../TicketActionButtons";
|
||||||
|
import MessagesList from "../MessagesList";
|
||||||
|
import api from "../../services/api";
|
||||||
|
import { ReplyMessageProvider } from "../../context/ReplyingMessage/ReplyingMessageContext";
|
||||||
|
import toastError from "../../errors/toastError";
|
||||||
|
|
||||||
|
const Ticket = () => {
|
||||||
|
const { ticketId } = useParams();
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
|
const [drawerOpen, setDrawerOpen] = React.useState(false);
|
||||||
|
const [loading, setLoading] = React.useState(true);
|
||||||
|
const [contact, setContact] = React.useState({});
|
||||||
|
const [ticket, setTicket] = React.useState({});
|
||||||
|
|
||||||
|
const [statusChatEnd, setStatusChatEnd] = React.useState({});
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
|
const delayDebounceFn = setTimeout(() => {
|
||||||
|
const fetchTicket = async () => {
|
||||||
|
try {
|
||||||
|
const { data } = await api.get("/tickets/" + ticketId);
|
||||||
|
|
||||||
|
setContact(data.contact.contact);
|
||||||
|
setTicket(data.contact);
|
||||||
|
|
||||||
|
setStatusChatEnd(data.statusChatEnd);
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
} catch (err) {
|
||||||
|
setLoading(false);
|
||||||
|
toastError(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fetchTicket();
|
||||||
|
}, 500);
|
||||||
|
return () => clearTimeout(delayDebounceFn);
|
||||||
|
}, [ticketId, history]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
|
||||||
|
|
||||||
|
socket.on("connect", () => socket.emit("joinChatBox", ticketId));
|
||||||
|
|
||||||
|
socket.on("ticket", (data) => {
|
||||||
|
if (data.action === "update") {
|
||||||
|
setTicket(data.ticket);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action === "delete") {
|
||||||
|
toast.success("Ticket deleted sucessfully.");
|
||||||
|
history.push("/tickets");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("contact", (data) => {
|
||||||
|
if (data.action === "update") {
|
||||||
|
setContact((prevState) => {
|
||||||
|
if (prevState.id === data.contact?.id) {
|
||||||
|
return { ...prevState, ...data.contact };
|
||||||
|
}
|
||||||
|
return prevState;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [ticketId, history]);
|
||||||
|
|
||||||
|
const handleDrawerOpen = () => {
|
||||||
|
setDrawerOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDrawerClose = () => {
|
||||||
|
setDrawerOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="test" >
|
||||||
|
<TicketHeader loading={loading}>
|
||||||
|
<div>
|
||||||
|
<TicketInfo contact={contact} ticket={ticket} onClick={handleDrawerOpen} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<TicketActionButtons ticket={ticket} statusChatEnd={statusChatEnd} />
|
||||||
|
</div>
|
||||||
|
</TicketHeader>
|
||||||
|
<ReplyMessageProvider>
|
||||||
|
<MessagesList ticketId={ticketId} isGroup={ticket.isGroup}></MessagesList>
|
||||||
|
<MessageInput ticketStatus={ticket.status} />
|
||||||
|
</ReplyMessageProvider>
|
||||||
|
|
||||||
|
<ContactDrawer
|
||||||
|
open={drawerOpen}
|
||||||
|
handleDrawerClose={handleDrawerClose}
|
||||||
|
contact={contact}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Ticket;
|
|
@ -0,0 +1,7 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { color } from "../../style/varibles";
|
||||||
|
|
||||||
|
export const TicketStyled = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
background-color: ${color.status.no};
|
||||||
|
`;
|
|
@ -0,0 +1,10 @@
|
||||||
|
import React from 'react'
|
||||||
|
import TicketSearchInput from './TicketSearchInput/TicketSearchInput'
|
||||||
|
|
||||||
|
const TicketSearch = ({spinning,setNewTicketModalOpen, handleSearch}) => {
|
||||||
|
return (
|
||||||
|
<TicketSearchInput spinning={spinning} setNewTicketModalOpen={setNewTicketModalOpen} handleSearch={handleSearch}/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TicketSearch
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import {TicketSearchBtnStyled} from "./TicketSearchBtn.styled"
|
||||||
|
|
||||||
|
const TicketSearchBtn = ({setNewTicketModalOpen}) => {
|
||||||
|
return (
|
||||||
|
<TicketSearchBtnStyled onClick={()=>setNewTicketModalOpen(true)}>+</TicketSearchBtnStyled>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TicketSearchBtn
|
|
@ -0,0 +1,12 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { color } from "../../../../style/varibles";
|
||||||
|
|
||||||
|
export const TicketSearchBtnStyled = styled.button`
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: transparent;
|
||||||
|
color: ${color.pricinpal.blanco};
|
||||||
|
font-size: 26px;
|
||||||
|
border: none;
|
||||||
|
font-family: "Helvetica55";
|
||||||
|
`;
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import {
|
||||||
|
TicketSearchDivStyled,
|
||||||
|
TicketSearchInputBoxStyled,
|
||||||
|
TicketSearchInputStyled,
|
||||||
|
} from "./TicketSearchInput.styled";
|
||||||
|
|
||||||
|
import { ReactComponent as SearchIcon } from "../../../../assets/icons/SearchInput/search.svg";
|
||||||
|
import TicketSearchBtn from "../TicketSearchBtn/TicketSearchBtn";
|
||||||
|
|
||||||
|
const TicketSearchInput = ({ spinning, setNewTicketModalOpen, handleSearch }) => {
|
||||||
|
return (
|
||||||
|
<TicketSearchDivStyled>
|
||||||
|
<TicketSearchInputBoxStyled spinning={spinning}>
|
||||||
|
<SearchIcon />
|
||||||
|
<TicketSearchInputStyled onChange={handleSearch} />
|
||||||
|
</TicketSearchInputBoxStyled>
|
||||||
|
<TicketSearchBtn setNewTicketModalOpen={setNewTicketModalOpen} />
|
||||||
|
</TicketSearchDivStyled>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TicketSearchInput;
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { color } from "../../../../style/varibles";
|
||||||
|
|
||||||
|
export const TicketSearchDivStyled = styled.div`
|
||||||
|
padding: 0 6px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
`;
|
||||||
|
export const TicketSearchInputBoxStyled = styled.div`
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
margin-right: 12px;
|
||||||
|
background-color: ${color.complement.azulOscuro};
|
||||||
|
border: 2px solid ${color.pricinpal.blanco};
|
||||||
|
color: ${color.pricinpal.blanco};
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 6px;
|
||||||
|
& svg {
|
||||||
|
fill: ${color.gradient.border};
|
||||||
|
}
|
||||||
|
&:after {
|
||||||
|
position: absolute;
|
||||||
|
right: 6px;
|
||||||
|
content: "";
|
||||||
|
display: ${({ spinning }) => (!spinning ? "none" : "block")};
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
border-top: 2px solid ${color.gradient.border};
|
||||||
|
border-left: 2px solid ${color.gradient.border};
|
||||||
|
border-bottom: 2px solid ${color.gradient.border};
|
||||||
|
border-right: 2px solid ${color.pricinpal.naranja};
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: spining 0.5s infinite linear;
|
||||||
|
}
|
||||||
|
@keyframes spining {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export const TicketSearchInputStyled = styled.input`
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
color: ${color.pricinpal.blanco};
|
||||||
|
background-color: ${color.complement.azulOscuro};
|
||||||
|
&:focus,
|
||||||
|
&:focus-visible {
|
||||||
|
border: none;
|
||||||
|
background-color: ${color.complement.azulOscuro};
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
import React from "react";
|
||||||
|
import { color } from "../../../../../style/varibles";
|
||||||
|
import { useHistory } from "react-router-dom";
|
||||||
|
import { parseISO, format, isSameDay } from "date-fns";
|
||||||
|
|
||||||
|
import { i18n } from "../../../../../translate/i18n";
|
||||||
|
|
||||||
|
import api from "../../../../../services/api";
|
||||||
|
import { AuthContext } from "../../../../../context/Auth/AuthContext";
|
||||||
|
import toastError from "../../../../../errors/toastError";
|
||||||
|
import Btn from "../../../../Base/Btn/Btn";
|
||||||
|
import {
|
||||||
|
TicketDateStyled,
|
||||||
|
TicketImgStyled,
|
||||||
|
TicketListItemStyled,
|
||||||
|
TicketTitleStyled,
|
||||||
|
} from "./TicketListItem.style";
|
||||||
|
import LoadingScreen from "../../../../LoadingScreen/LoadingScreen";
|
||||||
|
import BadgeComponent from "../../../../Base/Badge/BadgeComponent";
|
||||||
|
import DefaultUser from "../../../../../assets/images/User/clientDefault.png";
|
||||||
|
|
||||||
|
const TicketListItem = ({ tickets }) => {
|
||||||
|
const history = useHistory();
|
||||||
|
const [loading, setLoading] = React.useState(false);
|
||||||
|
const isMounted = React.useRef(true);
|
||||||
|
const { user } = React.useContext(AuthContext);
|
||||||
|
React.useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
isMounted.current = false;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleAcepptTicket = async (id) => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
await api.put(`/tickets/${id}`, {
|
||||||
|
status: "open",
|
||||||
|
userId: user?.id,
|
||||||
|
});
|
||||||
|
console.log("Passou no try", tickets.status, user?.id, id);
|
||||||
|
} catch (err) {
|
||||||
|
setLoading(false);
|
||||||
|
toastError(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMounted.current) {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
history.push(`/tickets/${id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelectTicket = (id) => {
|
||||||
|
history.push(`/tickets/${id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment key={tickets.id}>
|
||||||
|
<TicketListItemStyled
|
||||||
|
queuecolor={tickets.queue}
|
||||||
|
onClick={() => handleSelectTicket(tickets.id)}
|
||||||
|
>
|
||||||
|
{tickets.contact.profilePicUrl ? (
|
||||||
|
<TicketImgStyled src={tickets.contact.profilePicUrl} alt={tickets.id} />
|
||||||
|
) : (
|
||||||
|
<TicketImgStyled src={DefaultUser} alt={tickets.id} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
<TicketTitleStyled>
|
||||||
|
<p>{tickets.contact.name}</p>
|
||||||
|
<p>{tickets.lastMessage}</p>
|
||||||
|
{tickets.unreadMessages ? (
|
||||||
|
<BadgeComponent
|
||||||
|
counter={tickets.unreadMessages}
|
||||||
|
position="absolute"
|
||||||
|
right="6px"
|
||||||
|
top="6px"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
</TicketTitleStyled>
|
||||||
|
<TicketDateStyled>
|
||||||
|
{isSameDay(parseISO(tickets.updatedAt), new Date()) ? (
|
||||||
|
<>{format(parseISO(tickets.updatedAt), "HH:mm")}</>
|
||||||
|
) : (
|
||||||
|
<>{format(parseISO(tickets.updatedAt), "dd/MM/yyyy")}</>
|
||||||
|
)}
|
||||||
|
</TicketDateStyled>
|
||||||
|
{tickets.status === "pending" ? (
|
||||||
|
<Btn
|
||||||
|
onClick={() => handleAcepptTicket(tickets.id)}
|
||||||
|
text="Aceitar"
|
||||||
|
bgcolor={color.complement.azulCielo}
|
||||||
|
fontcolor={color.pricinpal.blanco}
|
||||||
|
fontSize="12px"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
</TicketListItemStyled>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TicketListItem;
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { color } from "../../../../../style/varibles";
|
||||||
|
|
||||||
|
export const TicketListItemStyled = styled.li`
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
background-color: ${color.complement.azulOscuro};
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.5rem 6px;
|
||||||
|
border-bottom: 1.5px solid ${color.gradient.border};
|
||||||
|
height: fit-content;
|
||||||
|
transition: filter .2s linear;
|
||||||
|
&:before {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
background-color: ${({ queuecolor }) => (queuecolor ? queuecolor : color.gradient.border)};
|
||||||
|
width: 4px;
|
||||||
|
height: 55px;
|
||||||
|
}
|
||||||
|
&:nth-child(1) {
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
filter: brightness(1.2);
|
||||||
|
transition: filter .2s linear;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TicketTitleStyled = styled.div`
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
row-gap: 6px;
|
||||||
|
& p {
|
||||||
|
color: ${color.pricinpal.blanco};
|
||||||
|
width: 190px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: "Helvetica55";
|
||||||
|
&:nth-child(1) {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: ${color.gradient.text};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export const TicketDateStyled = styled.div`
|
||||||
|
color: ${color.pricinpal.blanco};
|
||||||
|
font-size: 12px;
|
||||||
|
font-family: "Helvetica55";
|
||||||
|
display: block;
|
||||||
|
color: white;
|
||||||
|
margin-right: 1rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TicketImgStyled = styled.img`
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 0 6px;
|
||||||
|
`;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useState, useEffect, useRef, useContext } from "react";
|
import React, { useState, useEffect, useRef, useContext } from "react";
|
||||||
|
|
||||||
import { useHistory, useParams } from "react-router-dom";
|
import ReactDOM, { useHistory, useParams } from "react-router-dom";
|
||||||
import { parseISO, format, isSameDay } from "date-fns";
|
import { parseISO, format, isSameDay } from "date-fns";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
|
@ -145,7 +145,7 @@ const TicketListItem = ({ ticket }) => {
|
||||||
if (ticket.status === "pending") return;
|
if (ticket.status === "pending") return;
|
||||||
handleSelectTicket(ticket.id);
|
handleSelectTicket(ticket.id);
|
||||||
}}
|
}}
|
||||||
selected={ticketId && +ticketId === ticket.id}
|
selected={ticketId && +ticketId === ticket.id} ///img src{id}.jpg
|
||||||
className={clsx(classes.ticket, {
|
className={clsx(classes.ticket, {
|
||||||
[classes.pendingTicket]: ticket.status === "pending",
|
[classes.pendingTicket]: ticket.status === "pending",
|
||||||
})}
|
})}
|
|
@ -0,0 +1,212 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import openSocket from "socket.io-client";
|
||||||
|
|
||||||
|
import LoadingScreen from "../../../LoadingScreen/LoadingScreen";
|
||||||
|
|
||||||
|
import TicketListStyled from "./TicketsList.style";
|
||||||
|
import useTickets from "../../../../hooks/useTickets";
|
||||||
|
import TicketListItem from "../TicketsList/TicketListItem/TicketListItem";
|
||||||
|
import TicketsListSkeleton from "../TicketsListSkeleton/TicketListSkeleton";
|
||||||
|
|
||||||
|
import { i18n } from "../../../../translate/i18n";
|
||||||
|
import { AuthContext } from "../../../../context/Auth/AuthContext";
|
||||||
|
|
||||||
|
const reducer = (state, action) => {
|
||||||
|
if (action.type === "LOAD_TICKETS") {
|
||||||
|
const newTickets = action.payload;
|
||||||
|
newTickets.forEach((ticket) => {
|
||||||
|
const ticketIndex = state.findIndex((t) => t.id === ticket.id);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
state[ticketIndex] = ticket;
|
||||||
|
if (ticket.unreadMessages > 0) {
|
||||||
|
state.unshift(state.splice(ticketIndex, 1)[0]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.push(ticket);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return [...state];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.type === "RESET_UNREAD") {
|
||||||
|
const ticketId = action.payload;
|
||||||
|
|
||||||
|
const ticketIndex = state.findIndex((t) => t.id === ticketId);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
state[ticketIndex].unreadMessages = 0;
|
||||||
|
}
|
||||||
|
return [...state];
|
||||||
|
}
|
||||||
|
if (action.type === "UPDATE_TICKET") {
|
||||||
|
const ticket = action.payload;
|
||||||
|
|
||||||
|
const ticketIndex = state.findIndex((t) => t.id === ticket.id);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
state[ticketIndex] = ticket;
|
||||||
|
} else {
|
||||||
|
state.unshift(ticket);
|
||||||
|
}
|
||||||
|
return [...state];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.type === "UPDATE_TICKET_UNREAD_MESSAGES") {
|
||||||
|
const message = action.payload.message;
|
||||||
|
|
||||||
|
const ticket = action.payload.ticket;
|
||||||
|
|
||||||
|
const ticketIndex = state.findIndex((t) => t.id === ticket.id);
|
||||||
|
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
if (!message.fromMe) {
|
||||||
|
ticket.unreadMessages += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
state[ticketIndex] = ticket;
|
||||||
|
state.unshift(state.splice(ticketIndex, 1)[0]);
|
||||||
|
} else {
|
||||||
|
state.unshift(ticket);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...state];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.type === "UPDATE_TICKET_CONTACT") {
|
||||||
|
const contact = action.payload;
|
||||||
|
|
||||||
|
const ticketIndex = state.findIndex((t) => t.contactId === contact.id);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
state[ticketIndex].contact = contact;
|
||||||
|
}
|
||||||
|
return [...state];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.type === "DELETE_TICKET") {
|
||||||
|
const ticketId = action.payload;
|
||||||
|
|
||||||
|
const ticketIndex = state.findIndex((t) => t.id === ticketId);
|
||||||
|
if (ticketIndex !== -1) {
|
||||||
|
state.splice(ticketIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...state];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.type === "RESET") {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const TicketsList = ({ status, searchParam, showAll, selectedQueueIds, updateCount, valueTab }) => {
|
||||||
|
const [pageNumber, setPageNumber] = React.useState(1);
|
||||||
|
const [ticketsList, dispatch] = React.useReducer(reducer, []);
|
||||||
|
const { user } = React.useContext(AuthContext);
|
||||||
|
React.useEffect(() => {
|
||||||
|
dispatch({ type: "RESET" });
|
||||||
|
setPageNumber(1);
|
||||||
|
}, [status, searchParam, dispatch, showAll, selectedQueueIds]);
|
||||||
|
const { tickets, loading } = useTickets({
|
||||||
|
pageNumber,
|
||||||
|
searchParam,
|
||||||
|
status,
|
||||||
|
showAll,
|
||||||
|
queueIds: JSON.stringify(selectedQueueIds),
|
||||||
|
});
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (typeof updateCount === "function") {
|
||||||
|
updateCount(ticketsList.length);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [ticketsList]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!status && !searchParam) return;
|
||||||
|
dispatch({
|
||||||
|
type: "LOAD_TICKETS",
|
||||||
|
payload: tickets,
|
||||||
|
});
|
||||||
|
}, [tickets, status, searchParam]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
|
||||||
|
|
||||||
|
const shouldUpdateTicket = (ticket) =>
|
||||||
|
(!ticket.userId || ticket.userId === user?.id || showAll) &&
|
||||||
|
(!ticket.queueId || selectedQueueIds.indexOf(ticket.queueId) > -1);
|
||||||
|
|
||||||
|
const notBelongsToUserQueues = (ticket) =>
|
||||||
|
ticket.queueId && selectedQueueIds.indexOf(ticket.queueId) === -1;
|
||||||
|
|
||||||
|
socket.on("connect", () => {
|
||||||
|
if (status) {
|
||||||
|
socket.emit("joinTickets", status);
|
||||||
|
} else {
|
||||||
|
socket.emit("joinNotification");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("ticket", (data) => {
|
||||||
|
if (data.action === "updateUnread") {
|
||||||
|
dispatch({
|
||||||
|
type: "RESET_UNREAD",
|
||||||
|
payload: data.ticketId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action === "update" && shouldUpdateTicket(data.ticket)) {
|
||||||
|
dispatch({
|
||||||
|
type: "UPDATE_TICKET",
|
||||||
|
payload: data.ticket,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action === "update" && notBelongsToUserQueues(data.ticket)) {
|
||||||
|
dispatch({ type: "DELETE_TICKET", payload: data.ticket.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.action === "delete") {
|
||||||
|
dispatch({ type: "DELETE_TICKET", payload: data.ticketId });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("appMessage", (data) => {
|
||||||
|
if (data.action === "create" && shouldUpdateTicket(data.ticket)) {
|
||||||
|
// console.log('((((((((((((((((((( DATA.MESSAGE: ', data.message)
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: "UPDATE_TICKET_UNREAD_MESSAGES",
|
||||||
|
// payload: data.ticket,
|
||||||
|
payload: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("contact", (data) => {
|
||||||
|
if (data.action === "update") {
|
||||||
|
dispatch({
|
||||||
|
type: "UPDATE_TICKET_CONTACT",
|
||||||
|
payload: data.contact,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
socket.disconnect();
|
||||||
|
};
|
||||||
|
}, [status, showAll, user, selectedQueueIds]);
|
||||||
|
|
||||||
|
if (loading) return <TicketsListSkeleton />;
|
||||||
|
|
||||||
|
if (status === valueTab)
|
||||||
|
return (
|
||||||
|
<TicketListStyled>
|
||||||
|
{ticketsList.map((ticket) => (
|
||||||
|
<TicketListItem tickets={ticket} key={ticket.id} />
|
||||||
|
))}
|
||||||
|
</TicketListStyled>
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TicketsList;
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { color } from "../../../../style/varibles";
|
||||||
|
|
||||||
|
const TicketListStyled = styled.ul`
|
||||||
|
background-color: ${color.gradient.border};
|
||||||
|
height: 100vh;
|
||||||
|
margin-top: 16px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default TicketListStyled;
|
|
@ -5,12 +5,12 @@ import { makeStyles } from "@material-ui/core/styles";
|
||||||
import List from "@material-ui/core/List";
|
import List from "@material-ui/core/List";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
|
|
||||||
import TicketListItem from "../TicketListItem";
|
import TicketListItem from "../../../TicketListItem";
|
||||||
import TicketsListSkeleton from "../TicketsListSkeleton";
|
import TicketsListSkeleton from "../../../TicketsListSkeleton";
|
||||||
|
|
||||||
import useTickets from "../../hooks/useTickets";
|
import useTickets from "../../../../hooks/useTickets";
|
||||||
import { i18n } from "../../translate/i18n";
|
import { i18n } from "../../../../translate/i18n";
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
import { AuthContext } from "../../../../context/Auth/AuthContext";
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles(theme => ({
|
||||||
ticketsListWrapper: {
|
ticketsListWrapper: {
|
||||||
|
@ -74,8 +74,6 @@ const useStyles = makeStyles(theme => ({
|
||||||
const reducer = (state, action) => {
|
const reducer = (state, action) => {
|
||||||
if (action.type === "LOAD_TICKETS") {
|
if (action.type === "LOAD_TICKETS") {
|
||||||
const newTickets = action.payload;
|
const newTickets = action.payload;
|
||||||
|
|
||||||
|
|
||||||
newTickets.forEach(ticket => {
|
newTickets.forEach(ticket => {
|
||||||
|
|
||||||
// console.log('* ticket.unreadMessages: ',ticket.unreadMessages)
|
// console.log('* ticket.unreadMessages: ',ticket.unreadMessages)
|
|
@ -0,0 +1,42 @@
|
||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
TicketListSkeletonStyled,
|
||||||
|
TicketSkeletonItemStyled,
|
||||||
|
TicketSkeletonTitleStyled,
|
||||||
|
TicketSkeletonDateStyled,
|
||||||
|
TicketSkeletonImgStyled,
|
||||||
|
} from "./TicketListSkeleton.style";
|
||||||
|
|
||||||
|
const TicketsSkeleton = () => {
|
||||||
|
return (
|
||||||
|
<TicketListSkeletonStyled>
|
||||||
|
<TicketSkeletonItemStyled>
|
||||||
|
<TicketSkeletonImgStyled/>
|
||||||
|
<TicketSkeletonTitleStyled>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</TicketSkeletonTitleStyled>
|
||||||
|
<TicketSkeletonDateStyled/>
|
||||||
|
</TicketSkeletonItemStyled>
|
||||||
|
<TicketSkeletonItemStyled>
|
||||||
|
<TicketSkeletonImgStyled/>
|
||||||
|
<TicketSkeletonTitleStyled>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</TicketSkeletonTitleStyled>
|
||||||
|
<TicketSkeletonDateStyled/>
|
||||||
|
</TicketSkeletonItemStyled>
|
||||||
|
<TicketSkeletonItemStyled>
|
||||||
|
<TicketSkeletonImgStyled/>
|
||||||
|
<TicketSkeletonTitleStyled>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</TicketSkeletonTitleStyled>
|
||||||
|
<TicketSkeletonDateStyled/>
|
||||||
|
</TicketSkeletonItemStyled>
|
||||||
|
</TicketListSkeletonStyled>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TicketsSkeleton;
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { color } from "../../../../style/varibles";
|
||||||
|
|
||||||
|
export const TicketListSkeletonStyled = styled.ul`
|
||||||
|
background-color: ${color.gradient.border};
|
||||||
|
height: 100vh;
|
||||||
|
margin-top: 16px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TicketSkeletonItemStyled = styled.li`
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
background-color: ${color.complement.azulOscuro};
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.5rem 6px;
|
||||||
|
border-bottom: 1.5px solid ${color.gradient.border};
|
||||||
|
height: fit-content;
|
||||||
|
transition: filter 0.2s linear;
|
||||||
|
&:nth-child(1) {
|
||||||
|
margin-top: 6px;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
filter: brightness(1.2);
|
||||||
|
transition: filter 0.2s linear;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TicketSkeletonTitleStyled = styled.div`
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
row-gap: 6px;
|
||||||
|
opacity: 0.1;
|
||||||
|
& div {
|
||||||
|
color: ${color.pricinpal.blanco};
|
||||||
|
width: 190px;
|
||||||
|
font-size: 12px;
|
||||||
|
&:nth-child(1) {
|
||||||
|
width: 150px;
|
||||||
|
height: 18px;
|
||||||
|
background: linear-gradient(to right, ${color.gradient.border}, ${color.pricinpal.blanco});
|
||||||
|
animation: wave 0.8s infinite;
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
width: 150px;
|
||||||
|
height: 18px;
|
||||||
|
background: linear-gradient(to right, ${color.gradient.border}, ${color.pricinpal.blanco});
|
||||||
|
animation: wave 0.8s infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes wave {
|
||||||
|
to {
|
||||||
|
background-position: 150px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export const TicketSkeletonDateStyled = styled.div`
|
||||||
|
background: linear-gradient(to right, ${color.gradient.border}, ${color.pricinpal.blanco});
|
||||||
|
animation: wave 0.8s infinite;
|
||||||
|
opacity: 0.1;
|
||||||
|
display: block;
|
||||||
|
width: 40px;
|
||||||
|
height: 18px;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-right: 1rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TicketSkeletonImgStyled = styled.div`
|
||||||
|
background: linear-gradient(to right, ${color.gradient.border}, ${color.pricinpal.blanco});
|
||||||
|
animation: wave 0.8s infinite;
|
||||||
|
opacity: 0.1;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
object-fit: contain;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 0 6px;
|
||||||
|
`;
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import TicketsManagerStyled from "./TicketsManager.style";
|
||||||
|
import TicketsTabs from "./TicketsTabs/TicketsTabs";
|
||||||
|
|
||||||
|
import TicketSearch from "../TicketSearch/TicketSearch";
|
||||||
|
import TicketsList from "./TicketsList/TicketsList";
|
||||||
|
import NewTicketModal from "../../NewTicketModal";
|
||||||
|
|
||||||
|
import { AuthContext } from "../../../context/Auth/AuthContext";
|
||||||
|
|
||||||
|
const TicketsManager = () => {
|
||||||
|
const [valueTab, setValueTab] = React.useState("open");
|
||||||
|
const [searchParam, setSearchParam] = React.useState("");
|
||||||
|
const [spinning, setSpinning] = React.useState(false);
|
||||||
|
const [newTicketModalOpen, setNewTicketModalOpen] = React.useState(false);
|
||||||
|
const [openCount, setOpenCount] = React.useState(0);
|
||||||
|
const [pendingCount, setPendingCount] = React.useState(0);
|
||||||
|
const [closedCount, setClosedCount] = React.useState(0);
|
||||||
|
const [showAllTickets, setShowAllTickets] = React.useState(false);
|
||||||
|
const { user } = React.useContext(AuthContext);
|
||||||
|
const userQueueIds = user.queues.map((q) => q.id);
|
||||||
|
const [selectedQueueIds, setSelectedQueueIds] = React.useState(userQueueIds || []);
|
||||||
|
|
||||||
|
let searchTimeout;
|
||||||
|
const handleSearch = (e) => {
|
||||||
|
setSpinning(true);
|
||||||
|
const searchedTerm = e.target.value.toLowerCase();
|
||||||
|
|
||||||
|
clearTimeout(searchTimeout);
|
||||||
|
|
||||||
|
searchTimeout = setTimeout(() => {
|
||||||
|
setSearchParam(searchedTerm);
|
||||||
|
setSpinning(false);
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
if (searchedTerm === "") {
|
||||||
|
setSearchParam(searchedTerm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (user.profile.toUpperCase() === "ADMIN") {
|
||||||
|
setShowAllTickets(true);
|
||||||
|
}
|
||||||
|
}, [user.profile]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TicketsManagerStyled>
|
||||||
|
<TicketsTabs
|
||||||
|
setValueTab={setValueTab}
|
||||||
|
valueTab={valueTab}
|
||||||
|
count={{ openCount, pendingCount, closedCount }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TicketSearch
|
||||||
|
spinning={spinning}
|
||||||
|
handleSearch={handleSearch}
|
||||||
|
setNewTicketModalOpen={setNewTicketModalOpen}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TicketsList
|
||||||
|
status="open"
|
||||||
|
updateCount={(v) => setOpenCount(v)}
|
||||||
|
showAll={showAllTickets}
|
||||||
|
selectedQueueIds={selectedQueueIds}
|
||||||
|
searchParam={searchParam}
|
||||||
|
valueTab={valueTab}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TicketsList
|
||||||
|
status="pending"
|
||||||
|
updateCount={(v) => setPendingCount(v)}
|
||||||
|
selectedQueueIds={selectedQueueIds}
|
||||||
|
searchParam={searchParam}
|
||||||
|
valueTab={valueTab}
|
||||||
|
/>
|
||||||
|
<TicketsList
|
||||||
|
status="closed"
|
||||||
|
updateCount={(v) => setClosedCount(v)}
|
||||||
|
selectedQueueIds={selectedQueueIds}
|
||||||
|
searchParam={searchParam}
|
||||||
|
valueTab={valueTab}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<NewTicketModal
|
||||||
|
modalOpen={newTicketModalOpen}
|
||||||
|
onClose={(e) => setNewTicketModalOpen(false)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</TicketsManagerStyled>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TicketsManager;
|
|
@ -0,0 +1,13 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import {color} from "../../../style/varibles"
|
||||||
|
|
||||||
|
const TicketsManagerStyled = styled.div`
|
||||||
|
background-color: ${color.complement.azulOscuro};
|
||||||
|
display:flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
max-width: 425px;
|
||||||
|
border-right:1px solid ${color.gradient.border};
|
||||||
|
`
|
||||||
|
export default TicketsManagerStyled
|
|
@ -0,0 +1,43 @@
|
||||||
|
import React from "react";
|
||||||
|
import { TicketsTabStyled } from "./TicketsTab.style";
|
||||||
|
import { color } from "../../../../../style/varibles";
|
||||||
|
|
||||||
|
import BadgeComponent from "../../../../Base/Badge/BadgeComponent";
|
||||||
|
|
||||||
|
const TicketsTab = ({ text, id, setValueTab, valueTab, count }) => {
|
||||||
|
const [active, setActive] = React.useState(false);
|
||||||
|
|
||||||
|
const handleClick = ({ target }) => {
|
||||||
|
setValueTab(target.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
valueTab === id ? setActive(true) : setActive(false);
|
||||||
|
}, [valueTab, id]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TicketsTabStyled
|
||||||
|
id={id}
|
||||||
|
valueTab={valueTab}
|
||||||
|
onClick={handleClick}
|
||||||
|
className={active ? "active" : ""}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
{id !== "open" ? (
|
||||||
|
<BadgeComponent
|
||||||
|
counter={count}
|
||||||
|
position="absolute"
|
||||||
|
right="4px"
|
||||||
|
top="6px"
|
||||||
|
fontSize="12px"
|
||||||
|
bgcolor={id === "pending" ? color.status.warning : color.status.no}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
</TicketsTabStyled>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TicketsTab;
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { color } from "../../../../../style/varibles";
|
||||||
|
|
||||||
|
export const TicketsTabStyled = styled.li`
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: ${color.complement.azulOscuro};
|
||||||
|
color: ${color.pricinpal.blanco};
|
||||||
|
font-size: 0.9rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-family: "Helvetica85";
|
||||||
|
padding: 1rem 1.5rem;
|
||||||
|
text-align: center;
|
||||||
|
&:after {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 2px;
|
||||||
|
background-color: white;
|
||||||
|
transition: width 0.2s linear;
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
&:after {
|
||||||
|
width: 100%;
|
||||||
|
transition: width 0.2s linear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
border-left: 1px solid ${color.gradient.border};
|
||||||
|
border-right: 1px solid ${color.gradient.border};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
import React from "react";
|
||||||
|
import TicketsTab from "../TicketsTabs/TicketsTab/TicketsTab";
|
||||||
|
import { TicketTabsStyled } from "./TicketsTabs.style";
|
||||||
|
|
||||||
|
const TicketsTabs = ({ setValueTab, valueTab, count }) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TicketTabsStyled>
|
||||||
|
<TicketsTab
|
||||||
|
text="Aberto"
|
||||||
|
id="open"
|
||||||
|
setValueTab={setValueTab}
|
||||||
|
valueTab={valueTab}
|
||||||
|
count={count.openCount}
|
||||||
|
/>
|
||||||
|
<TicketsTab
|
||||||
|
text="Aguardando"
|
||||||
|
id="pending"
|
||||||
|
setValueTab={setValueTab}
|
||||||
|
valueTab={valueTab}
|
||||||
|
count={count.pendingCount}
|
||||||
|
/>
|
||||||
|
<TicketsTab
|
||||||
|
text="Fechado"
|
||||||
|
id="closed"
|
||||||
|
setValueTab={setValueTab}
|
||||||
|
valueTab={valueTab}
|
||||||
|
count={count.closedCount}
|
||||||
|
/>
|
||||||
|
</TicketTabsStyled>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TicketsTabs;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { color } from "../../../../style/varibles";
|
||||||
|
|
||||||
|
export const TicketTabsStyled = styled.ul`
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
border-bottom: 1px solid ${color.gradient.border};
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
`;
|
||||||
|
|
|
@ -9,20 +9,19 @@ import Tab from "@material-ui/core/Tab";
|
||||||
import Badge from "@material-ui/core/Badge";
|
import Badge from "@material-ui/core/Badge";
|
||||||
import MoveToInboxIcon from "@material-ui/icons/MoveToInbox";
|
import MoveToInboxIcon from "@material-ui/icons/MoveToInbox";
|
||||||
import CheckBoxIcon from "@material-ui/icons/CheckBox";
|
import CheckBoxIcon from "@material-ui/icons/CheckBox";
|
||||||
|
|
||||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
||||||
import Switch from "@material-ui/core/Switch";
|
import Switch from "@material-ui/core/Switch";
|
||||||
|
|
||||||
import NewTicketModal from "../NewTicketModal";
|
|
||||||
import TicketsList from "../TicketsList";
|
|
||||||
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 { Button } from "@material-ui/core";
|
||||||
|
|
||||||
|
import NewTicketModal from "../../NewTicketModal/index";
|
||||||
|
import TicketsList from "../../TicketsList";
|
||||||
|
import TabPanel from "../../TabPanel";
|
||||||
|
|
||||||
|
import { i18n } from "../../../translate/i18n";
|
||||||
|
import { AuthContext } from "../../../context/Auth/AuthContext";
|
||||||
|
import { Can } from "../../Can";
|
||||||
|
import TicketsQueueSelect from "../../TicketsQueueSelect";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
ticketsWrapper: {
|
ticketsWrapper: {
|
||||||
position: "relative",
|
position: "relative",
|
||||||
|
@ -112,7 +111,6 @@ const TicketsManager = () => {
|
||||||
if (user.profile.toUpperCase() === "ADMIN") {
|
if (user.profile.toUpperCase() === "ADMIN") {
|
||||||
setShowAllTickets(true);
|
setShowAllTickets(true);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
|
@ -19,64 +19,11 @@ import toastError from "../../errors/toastError";
|
||||||
|
|
||||||
const drawerWidth = 320;
|
const drawerWidth = 320;
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
|
||||||
root: {
|
|
||||||
display: "flex",
|
|
||||||
height: "100%",
|
|
||||||
position: "relative",
|
|
||||||
overflow: "hidden",
|
|
||||||
},
|
|
||||||
|
|
||||||
ticketInfo: {
|
|
||||||
maxWidth: "50%",
|
|
||||||
flexBasis: "50%",
|
|
||||||
[theme.breakpoints.down("sm")]: {
|
|
||||||
maxWidth: "80%",
|
|
||||||
flexBasis: "80%",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ticketActionButtons: {
|
|
||||||
maxWidth: "50%",
|
|
||||||
flexBasis: "50%",
|
|
||||||
display: "flex",
|
|
||||||
[theme.breakpoints.down("sm")]: {
|
|
||||||
maxWidth: "100%",
|
|
||||||
flexBasis: "100%",
|
|
||||||
marginBottom: "5px",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
mainWrapper: {
|
|
||||||
flex: 1,
|
|
||||||
height: "100%",
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
overflow: "hidden",
|
|
||||||
borderTopLeftRadius: 0,
|
|
||||||
borderBottomLeftRadius: 0,
|
|
||||||
borderLeft: "0",
|
|
||||||
marginRight: -drawerWidth,
|
|
||||||
transition: theme.transitions.create("margin", {
|
|
||||||
easing: theme.transitions.easing.sharp,
|
|
||||||
duration: theme.transitions.duration.leavingScreen,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
|
|
||||||
mainWrapperShift: {
|
|
||||||
borderTopRightRadius: 0,
|
|
||||||
borderBottomRightRadius: 0,
|
|
||||||
transition: theme.transitions.create("margin", {
|
|
||||||
easing: theme.transitions.easing.easeOut,
|
|
||||||
duration: theme.transitions.duration.enteringScreen,
|
|
||||||
}),
|
|
||||||
marginRight: 0,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const Ticket = () => {
|
const Ticket = () => {
|
||||||
const { ticketId } = useParams();
|
const { ticketId } = useParams();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const classes = useStyles();
|
|
||||||
|
|
||||||
const [drawerOpen, setDrawerOpen] = useState(false);
|
const [drawerOpen, setDrawerOpen] = useState(false);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
@ -91,13 +38,8 @@ const Ticket = () => {
|
||||||
const fetchTicket = async () => {
|
const fetchTicket = async () => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// maria julia
|
|
||||||
|
|
||||||
const { data } = await api.get("/tickets/" + ticketId);
|
const { data } = await api.get("/tickets/" + ticketId);
|
||||||
|
|
||||||
// setContact(data.contact);
|
|
||||||
// setTicket(data);
|
|
||||||
|
|
||||||
setContact(data.contact.contact);
|
setContact(data.contact.contact);
|
||||||
setTicket(data.contact);
|
setTicket(data.contact);
|
||||||
|
|
||||||
|
@ -155,23 +97,21 @@ const Ticket = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root} id="drawer-container">
|
<div id="drawer-container">
|
||||||
<Paper
|
<Paper
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
elevation={0}
|
elevation={0}
|
||||||
className={clsx(classes.mainWrapper, {
|
|
||||||
[classes.mainWrapperShift]: drawerOpen,
|
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
<TicketHeader loading={loading}>
|
<TicketHeader loading={loading}>
|
||||||
<div className={classes.ticketInfo}>
|
<div >
|
||||||
<TicketInfo
|
<TicketInfo
|
||||||
contact={contact}
|
contact={contact}
|
||||||
ticket={ticket}
|
ticket={ticket}
|
||||||
onClick={handleDrawerOpen}
|
onClick={handleDrawerOpen}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.ticketActionButtons}>
|
<div >
|
||||||
<TicketActionButtons ticket={ticket} statusChatEnd={statusChatEnd}/>
|
<TicketActionButtons ticket={ticket} statusChatEnd={statusChatEnd}/>
|
||||||
</div>
|
</div>
|
||||||
</TicketHeader>
|
</TicketHeader>
|
||||||
|
|
|
@ -12,167 +12,147 @@ import ButtonWithSpinner from "../ButtonWithSpinner";
|
||||||
import toastError from "../../errors/toastError";
|
import toastError from "../../errors/toastError";
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||||
|
|
||||||
import Modal from "../ChatEnd/ModalChatEnd";
|
import Modal from "../ChatEnd/ModalChatEnd";
|
||||||
import { render } from '@testing-library/react';
|
import { render } from "@testing-library/react";
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
actionButtons: {
|
actionButtons: {
|
||||||
marginRight: 6,
|
marginRight: 6,
|
||||||
flex: "none",
|
flex: "none",
|
||||||
alignSelf: "center",
|
alignSelf: "center",
|
||||||
marginLeft: "auto",
|
marginLeft: "auto",
|
||||||
"& > *": {
|
"& > *": {
|
||||||
margin: theme.spacing(1),
|
margin: theme.spacing(1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
const TicketActionButtons = ({ ticket, statusChatEnd }) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const [anchorEl, setAnchorEl] = useState(null);
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const ticketOptionsMenuOpen = Boolean(anchorEl);
|
const ticketOptionsMenuOpen = Boolean(anchorEl);
|
||||||
const { user } = useContext(AuthContext);
|
const { user } = useContext(AuthContext);
|
||||||
|
|
||||||
const handleOpenTicketOptionsMenu = e => {
|
|
||||||
setAnchorEl(e.currentTarget);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCloseTicketOptionsMenu = e => {
|
const handleOpenTicketOptionsMenu = (e) => {
|
||||||
setAnchorEl(null);
|
setAnchorEl(e.currentTarget);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCloseTicketOptionsMenu = (e) => {
|
||||||
const chatEndVal = (data) => {
|
setAnchorEl(null);
|
||||||
|
};
|
||||||
if(data){
|
|
||||||
|
|
||||||
data = {...data, 'ticketId': ticket.id}
|
const chatEndVal = (data) => {
|
||||||
|
if (data) {
|
||||||
console.log('ChatEnd: ',(data));
|
data = { ...data, ticketId: ticket.id };
|
||||||
|
|
||||||
handleUpdateTicketStatus(null, "closed", user?.id, data)
|
console.log("ChatEnd: ", data);
|
||||||
|
|
||||||
}
|
handleUpdateTicketStatus(null, "closed", user?.id, data);
|
||||||
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const handleModal = (/*status, userId*/) => {
|
||||||
|
render(
|
||||||
|
<Modal
|
||||||
|
modal_header={"Finalização de Atendimento"}
|
||||||
|
func={chatEndVal}
|
||||||
|
statusChatEnd={statusChatEnd}
|
||||||
|
ticketId={ticket.id}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const handleModal = (/*status, userId*/) => {
|
const handleUpdateTicketStatus = async (e, status, userId, schedulingData = {}) => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
if (status === "closed") {
|
||||||
|
await api.put(`/tickets/${ticket.id}`, {
|
||||||
|
status: status,
|
||||||
|
userId: userId || null,
|
||||||
|
schedulingNotifyData: JSON.stringify(schedulingData),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await api.put(`/tickets/${ticket.id}`, {
|
||||||
|
status: status,
|
||||||
|
userId: userId || null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
render(<Modal
|
setLoading(false);
|
||||||
modal_header={'Finalização de Atendimento'}
|
if (status === "open") {
|
||||||
func={chatEndVal}
|
history.push(`/tickets/${ticket.id}`);
|
||||||
statusChatEnd={statusChatEnd}
|
} else {
|
||||||
ticketId={ticket.id}
|
history.push("/tickets");
|
||||||
/>)
|
}
|
||||||
|
} catch (err) {
|
||||||
};
|
setLoading(false);
|
||||||
|
toastError(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleUpdateTicketStatus = async (e, status, userId, schedulingData={}) => {
|
return (
|
||||||
|
<div className={classes.actionButtons}>
|
||||||
setLoading(true);
|
{ticket.status === "closed" && (
|
||||||
try {
|
<ButtonWithSpinner
|
||||||
|
loading={loading}
|
||||||
if(status==='closed'){
|
startIcon={<Replay />}
|
||||||
|
size="small"
|
||||||
|
onClick={(e) => handleUpdateTicketStatus(e, "open", user?.id)}
|
||||||
|
>
|
||||||
|
{i18n.t("messagesList.header.buttons.reopen")}
|
||||||
|
</ButtonWithSpinner>
|
||||||
|
)}
|
||||||
|
{ticket.status === "open" && (
|
||||||
|
<>
|
||||||
|
<ButtonWithSpinner
|
||||||
|
loading={loading}
|
||||||
|
startIcon={<Replay />}
|
||||||
|
size="small"
|
||||||
|
onClick={(e) => handleUpdateTicketStatus(e, "pending", null)}
|
||||||
|
>
|
||||||
|
{i18n.t("messagesList.header.buttons.return")}
|
||||||
|
</ButtonWithSpinner>
|
||||||
|
|
||||||
await api.put(`/tickets/${ticket.id}`, {
|
<ButtonWithSpinner
|
||||||
status: status,
|
loading={loading}
|
||||||
userId: userId || null,
|
size="small"
|
||||||
schedulingNotifyData: JSON.stringify(schedulingData)
|
variant="contained"
|
||||||
});
|
color="primary"
|
||||||
|
onClick={(e) => {
|
||||||
|
handleModal();
|
||||||
|
// handleUpdateTicketStatus(e, "closed", user?.id)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18n.t("messagesList.header.buttons.resolve")}
|
||||||
|
</ButtonWithSpinner>
|
||||||
|
|
||||||
}
|
<IconButton onClick={handleOpenTicketOptionsMenu}>
|
||||||
else{
|
<MoreVert />
|
||||||
|
</IconButton>
|
||||||
await api.put(`/tickets/${ticket.id}`, {
|
<TicketOptionsMenu
|
||||||
status: status,
|
ticket={ticket}
|
||||||
userId: userId || null
|
anchorEl={anchorEl}
|
||||||
});
|
menuOpen={ticketOptionsMenuOpen}
|
||||||
|
handleClose={handleCloseTicketOptionsMenu}
|
||||||
}
|
/>
|
||||||
|
</>
|
||||||
setLoading(false);
|
)}
|
||||||
if (status === "open") {
|
{ticket.status === "pending" && (
|
||||||
history.push(`/tickets/${ticket.id}`);
|
<ButtonWithSpinner
|
||||||
} else {
|
loading={loading}
|
||||||
history.push("/tickets");
|
size="small"
|
||||||
}
|
variant="contained"
|
||||||
} catch (err) {
|
color="primary"
|
||||||
setLoading(false);
|
onClick={(e) => handleUpdateTicketStatus(e, "open", user?.id)}
|
||||||
toastError(err);
|
>
|
||||||
}
|
{i18n.t("messagesList.header.buttons.accept")}
|
||||||
|
</ButtonWithSpinner>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classes.actionButtons}>
|
|
||||||
{ticket.status === "closed" && (
|
|
||||||
<ButtonWithSpinner
|
|
||||||
loading={loading}
|
|
||||||
startIcon={<Replay />}
|
|
||||||
size="small"
|
|
||||||
onClick={e => handleUpdateTicketStatus(e, "open", user?.id)}
|
|
||||||
>
|
|
||||||
{i18n.t("messagesList.header.buttons.reopen")}
|
|
||||||
</ButtonWithSpinner>
|
|
||||||
)}
|
|
||||||
{ticket.status === "open" && (
|
|
||||||
<>
|
|
||||||
<ButtonWithSpinner
|
|
||||||
loading={loading}
|
|
||||||
startIcon={<Replay />}
|
|
||||||
size="small"
|
|
||||||
onClick={e => handleUpdateTicketStatus(e, "pending", null)}
|
|
||||||
>
|
|
||||||
{i18n.t("messagesList.header.buttons.return")}
|
|
||||||
</ButtonWithSpinner>
|
|
||||||
|
|
||||||
<ButtonWithSpinner
|
|
||||||
loading={loading}
|
|
||||||
size="small"
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
onClick={e => {
|
|
||||||
|
|
||||||
|
|
||||||
handleModal()
|
|
||||||
// handleUpdateTicketStatus(e, "closed", user?.id)
|
|
||||||
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n.t("messagesList.header.buttons.resolve")}
|
|
||||||
</ButtonWithSpinner>
|
|
||||||
|
|
||||||
<IconButton onClick={handleOpenTicketOptionsMenu}>
|
|
||||||
<MoreVert />
|
|
||||||
</IconButton>
|
|
||||||
<TicketOptionsMenu
|
|
||||||
ticket={ticket}
|
|
||||||
anchorEl={anchorEl}
|
|
||||||
menuOpen={ticketOptionsMenuOpen}
|
|
||||||
handleClose={handleCloseTicketOptionsMenu}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{ticket.status === "pending" && (
|
|
||||||
<ButtonWithSpinner
|
|
||||||
loading={loading}
|
|
||||||
size="small"
|
|
||||||
variant="contained"
|
|
||||||
color="primary"
|
|
||||||
onClick={e => handleUpdateTicketStatus(e, "open", user?.id)}
|
|
||||||
>
|
|
||||||
{i18n.t("messagesList.header.buttons.accept")}
|
|
||||||
</ButtonWithSpinner>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TicketActionButtons;
|
export default TicketActionButtons;
|
||||||
|
|
||||||
|
|
|
@ -6,55 +6,52 @@ import Select from "@material-ui/core/Select";
|
||||||
import { Checkbox, ListItemText } from "@material-ui/core";
|
import { Checkbox, ListItemText } from "@material-ui/core";
|
||||||
import { i18n } from "../../translate/i18n";
|
import { i18n } from "../../translate/i18n";
|
||||||
|
|
||||||
const TicketsQueueSelect = ({
|
const TicketsQueueSelect = ({ userQueues, selectedQueueIds = [], onChange }) => {
|
||||||
userQueues,
|
const handleChange = (e) => {
|
||||||
selectedQueueIds = [],
|
onChange(e.target.value);
|
||||||
onChange,
|
};
|
||||||
}) => {
|
|
||||||
const handleChange = e => {
|
|
||||||
onChange(e.target.value);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: 120, marginTop: -4 }}>
|
<div style={{ width: 120, marginTop: -4 }}>
|
||||||
<FormControl fullWidth margin="dense">
|
<FormControl fullWidth margin="dense">
|
||||||
<Select
|
<Select
|
||||||
multiple
|
multiple
|
||||||
displayEmpty
|
displayEmpty
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
value={selectedQueueIds}
|
value={selectedQueueIds}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
MenuProps={{
|
MenuProps={{
|
||||||
anchorOrigin: {
|
anchorOrigin: {
|
||||||
vertical: "bottom",
|
vertical: "bottom",
|
||||||
horizontal: "left",
|
horizontal: "left",
|
||||||
},
|
},
|
||||||
transformOrigin: {
|
transformOrigin: {
|
||||||
vertical: "top",
|
vertical: "top",
|
||||||
horizontal: "left",
|
horizontal: "left",
|
||||||
},
|
},
|
||||||
getContentAnchorEl: null,
|
getContentAnchorEl: null,
|
||||||
}}
|
}}
|
||||||
renderValue={() => i18n.t("ticketsQueueSelect.placeholder")}
|
renderValue={() => i18n.t("ticketsQueueSelect.placeholder")}
|
||||||
>
|
>
|
||||||
{userQueues?.length > 0 &&
|
{userQueues?.length > 0 &&
|
||||||
userQueues.map(queue => (
|
userQueues.map((queue) => (
|
||||||
<MenuItem dense key={queue.id} value={queue.id}>
|
<MenuItem dense key={queue.id} value={queue.id}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
style={{
|
style={{
|
||||||
color: queue.color,
|
color: queue.color,
|
||||||
}}
|
}}
|
||||||
size="small"
|
size="small"
|
||||||
color="primary"
|
color="primary"
|
||||||
checked={selectedQueueIds.indexOf(queue.id) > -1}
|
checked={selectedQueueIds.indexOf(queue.id) > -1}
|
||||||
/>
|
/>
|
||||||
<ListItemText primary={queue.name} />
|
<ListItemText primary={queue.name} />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TicketsQueueSelect;
|
export default TicketsQueueSelect;
|
||||||
|
|
||||||
|
|
|
@ -6,30 +6,62 @@ import api from "../../services/api";
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
import { AuthContext } from "../../context/Auth/AuthContext";
|
||||||
import { Can } from "../Can";
|
import { Can } from "../Can";
|
||||||
|
|
||||||
import BtnComponent from "../Base/BTN/Btn";
|
import BtnComponent from "../Base/Btn/Btn";
|
||||||
import FormComponent from "../Base/Form/FormComponent";
|
import FormComponent from "../Base/Form/FormComponent";
|
||||||
import InputComponent from "../Base/Form/Input/InputComponent";
|
import InputComponent from "../Base/Form/Input/InputComponent";
|
||||||
import UserModalComponent from "./UserModalImg/UserModalComponent";
|
import UserModalComponent from "./UserModalImg/UserModalComponent";
|
||||||
|
|
||||||
import UserImg from "../../assets/images/User/user.jpg";
|
import UserImg from "../../assets/images/User/user.jpg";
|
||||||
|
|
||||||
const UserModal = ({ modal, click }) => {
|
const UserModal = ({ modal, click, userId }) => {
|
||||||
const { user } = React.useContext(AuthContext);
|
const { user } = React.useContext(AuthContext);
|
||||||
|
|
||||||
const initalData = {
|
const InitalState = {
|
||||||
name: user.name,
|
name: "",
|
||||||
email: user.email,
|
email: "",
|
||||||
perfil:user.profile,
|
password: "",
|
||||||
}
|
profile: "",
|
||||||
console.log(user);
|
};
|
||||||
|
const [userData, setUserData] = React.useState(InitalState);
|
||||||
|
const [selectedQueueIds, setSelectedQueueIds] = React.useState([]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
// const fetchUser = async () => {
|
||||||
|
// if (!userId) return;
|
||||||
|
// try {
|
||||||
|
// const { data } = await api.get(`/users/${userId}`);
|
||||||
|
// setUserData((prevState) => {
|
||||||
|
// return console.log({ ...prevState, ...data });
|
||||||
|
// });
|
||||||
|
// const userQueueIds = data.queues?.map((queue) => queue.id);
|
||||||
|
// setSelectedQueueIds(userQueueIds);
|
||||||
|
// } catch (err) {
|
||||||
|
// alert(err);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// fetchUser();
|
||||||
|
}, [userId]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalOverlayStyled modal={modal}>
|
<ModalOverlayStyled modal={modal}>
|
||||||
<UserModalStyled>
|
<UserModalStyled>
|
||||||
<UserModalComponent img={UserImg} desc="Clique na imagem para alterar" />
|
<UserModalComponent img={UserImg} desc="Clique na imagem para alterar" />
|
||||||
<FormComponent method="get">
|
<FormComponent method="get">
|
||||||
<InputComponent id="nome" label="Nome" type="text" value={initalData.name}/>
|
<InputComponent
|
||||||
<InputComponent id="email" label="E-mail" type="email" value={initalData.email}/>
|
id="nome"
|
||||||
|
label="Nome"
|
||||||
|
type="text"
|
||||||
|
value={userData.name}
|
||||||
|
onChange={(event) => setUserData({ name: event.target.data })}
|
||||||
|
/>
|
||||||
|
<InputComponent
|
||||||
|
id="email"
|
||||||
|
label="E-mail"
|
||||||
|
type="email"
|
||||||
|
value={userData.email}
|
||||||
|
onChange={(event) => setUserData({ email: event.target.data })}
|
||||||
|
/>
|
||||||
<InputComponent id="password" label="Senha" type="password" />
|
<InputComponent id="password" label="Senha" type="password" />
|
||||||
<UserBtns>
|
<UserBtns>
|
||||||
<BtnComponent text="Cancelar" onClick={click} />
|
<BtnComponent text="Cancelar" onClick={click} />
|
||||||
|
@ -53,4 +85,5 @@ id: 2
|
||||||
name: "teste"
|
name: "teste"
|
||||||
profile: "master"
|
profile: "master"
|
||||||
queues: []
|
queues: []
|
||||||
tokenVersion: 0 */
|
tokenVersion: 0 */
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,16 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import Loading from "../components/LoadingScreen/Loading";
|
import LoadingScreen from "../components/LoadingScreen/LoadingScreen";
|
||||||
import MainContainer from "../components/Base/MainContainer/MainContainer";
|
import MainContainer from "../components/Base/MainContainer/MainContainer";
|
||||||
import { AuthContext } from "../context/Auth/AuthContext";
|
import { AuthContext } from "../context/Auth/AuthContext";
|
||||||
import { i18n } from "../translate/i18n";
|
import { i18n } from "../translate/i18n";
|
||||||
import MenuComponent from "../components/Menu/MenuComponent";
|
import MenuComponent from "../components/Menu/MenuComponent";
|
||||||
|
|
||||||
const LoggedInLayout = ({ children }) => {
|
const LoggedInLayout = ({ children }) => {
|
||||||
const { handleLogout, loading, isAuth } = React.useContext(AuthContext);
|
const { loading, user } = React.useContext(AuthContext);
|
||||||
const logout = (e) => {
|
|
||||||
handleLogout();
|
|
||||||
};
|
|
||||||
const { user } = React.useContext(AuthContext);
|
|
||||||
console.log(user.name);
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Loading />;
|
return <LoadingScreen />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,20 @@
|
||||||
|
import React from "react";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
|
||||||
|
import TicketsStyled from "./Tickets.style";
|
||||||
|
|
||||||
|
import TicketsManager from "../../components/Ticket/TicketsManager/TicketsManager";
|
||||||
|
import Ticket from "../../components/Ticket/Ticket";
|
||||||
|
|
||||||
|
const Tickets = () => {
|
||||||
|
const { ticketId } = useParams();
|
||||||
|
return (
|
||||||
|
<TicketsStyled>
|
||||||
|
<TicketsManager />
|
||||||
|
{ticketId ? <Ticket /> : <div>Não tem nada</div>}
|
||||||
|
</TicketsStyled>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Tickets;
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
const TicketsStyled = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
min-height: auto;
|
||||||
|
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default TicketsStyled
|
|
@ -4,7 +4,7 @@ import Grid from "@material-ui/core/Grid";
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
|
|
||||||
import TicketsManager from "../../components/TicketsManager/";
|
import TicketsManager from "../../components/Ticket/TicketsManager/index";
|
||||||
import Ticket from "../../components/Ticket/";
|
import Ticket from "../../components/Ticket/";
|
||||||
|
|
||||||
import { i18n } from "../../translate/i18n";
|
import { i18n } from "../../translate/i18n";
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { useContext } from "react";
|
||||||
import { Route as RouterRoute, Redirect } from "react-router-dom";
|
import { Route as RouterRoute, Redirect } from "react-router-dom";
|
||||||
|
|
||||||
import { AuthContext } from "../context/Auth/AuthContext";
|
import { AuthContext } from "../context/Auth/AuthContext";
|
||||||
import Loading from "../components/LoadingScreen/Loading"
|
import LoadingScreen from "../components/LoadingScreen/LoadingScreen"
|
||||||
|
|
||||||
const Route = ({ component: Component, isPrivate = false, ...rest }) => {
|
const Route = ({ component: Component, isPrivate = false, ...rest }) => {
|
||||||
const { isAuth, loading } = useContext(AuthContext);
|
const { isAuth, loading } = useContext(AuthContext);
|
||||||
|
@ -10,7 +10,7 @@ const Route = ({ component: Component, isPrivate = false, ...rest }) => {
|
||||||
if (!isAuth && isPrivate) {
|
if (!isAuth && isPrivate) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{loading && <Loading />}
|
{loading && <LoadingScreen />}
|
||||||
<Redirect to={{ pathname: "/login", state: { from: rest.location } }} />
|
<Redirect to={{ pathname: "/login", state: { from: rest.location } }} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -19,7 +19,7 @@ const Route = ({ component: Component, isPrivate = false, ...rest }) => {
|
||||||
if (isAuth && !isPrivate) {
|
if (isAuth && !isPrivate) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{loading && <Loading />}
|
{loading && <LoadingScreen />}
|
||||||
<Redirect to={{ pathname: "/", state: { from: rest.location } }} />;
|
<Redirect to={{ pathname: "/", state: { from: rest.location } }} />;
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -27,7 +27,7 @@ const Route = ({ component: Component, isPrivate = false, ...rest }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{loading && <Loading />}
|
{loading && <LoadingScreen />}
|
||||||
<RouterRoute {...rest} component={Component} />
|
<RouterRoute {...rest} component={Component} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,7 +10,7 @@ import SchedulesReminder from "../pages/SchedulesReminder/";
|
||||||
|
|
||||||
import Login from "../pages/Login/";
|
import Login from "../pages/Login/";
|
||||||
import Signup from "../pages/Signup/";
|
import Signup from "../pages/Signup/";
|
||||||
import Tickets from "../pages/Tickets/";
|
import Tickets from "../pages/Tickets/Tickets";
|
||||||
import Connections from "../pages/Connections/";
|
import Connections from "../pages/Connections/";
|
||||||
import Settings from "../pages/Settings/";
|
import Settings from "../pages/Settings/";
|
||||||
import Users from "../pages/Users";
|
import Users from "../pages/Users";
|
||||||
|
|
|
@ -39,22 +39,24 @@ export const color = {
|
||||||
grisOscuro: "#3C3C3B",
|
grisOscuro: "#3C3C3B",
|
||||||
blanco: "#FFFFFF",
|
blanco: "#FFFFFF",
|
||||||
},
|
},
|
||||||
complement:{
|
complement: {
|
||||||
azulCielo: "#55A5DC",
|
azulCielo: "#55A5DC",
|
||||||
azulOscuro: "#212F3C",
|
azulOscuro: "#212F3C",
|
||||||
crisClaro: "#F6F6F6",
|
crisClaro: "#F6F6F6",
|
||||||
},
|
},
|
||||||
status:{
|
status: {
|
||||||
no: "#FF0000",
|
no: "#FF0000",
|
||||||
yes: "#00BE1E",
|
yes: "#00BE1E",
|
||||||
warning: "#FFC700"
|
warning: "#ffc800c7",
|
||||||
},
|
},
|
||||||
gradient:{
|
gradient: {
|
||||||
bgOpacity:"#212F3CD8",
|
bgOpacity: "#212f3cd7",
|
||||||
placeholder:"#ffffff83"
|
placeholder: "#ffffff83",
|
||||||
|
border: "#55A5DC3F",
|
||||||
|
text: "#AEBAC1",
|
||||||
|
},
|
||||||
|
shadow: {
|
||||||
|
dark: "2px 2px 4px 2px",
|
||||||
},
|
},
|
||||||
shadow:{
|
|
||||||
dark:"2px 2px 4px 2px"
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue