live sync
parent
f99a0ab573
commit
831fa8e0ab
|
@ -15,6 +15,7 @@ import { UsersProvider } from "./Contexts/UsersContext";
|
|||
import HeaderProvider from "./Contexts/HeaderContext";
|
||||
import ConsolesProvider from "./Contexts/ConsolesContext";
|
||||
import ScannerProvider from "./Contexts/ScannerContext";
|
||||
import { CrmProvider } from "./Contexts/CrmContext";
|
||||
|
||||
export default function App() {
|
||||
const [notificationApi, notificationContextHolder] =
|
||||
|
@ -47,6 +48,7 @@ export default function App() {
|
|||
<UsersProvider>
|
||||
<ConsolesProvider>
|
||||
<ScannerProvider>
|
||||
<CrmProvider>
|
||||
<WebSocketProvider
|
||||
userSession={userSession}
|
||||
setUserSession={setUserSession}
|
||||
|
@ -63,6 +65,7 @@ export default function App() {
|
|||
setUserSession={setUserSession}
|
||||
/>
|
||||
</WebSocketProvider>
|
||||
</CrmProvider>
|
||||
</ScannerProvider>
|
||||
</ConsolesProvider>
|
||||
</UsersProvider>
|
||||
|
|
|
@ -272,7 +272,7 @@ export default function AppRoutes({ userSession, setUserSession }) {
|
|||
Constants.PERMISSIONS.CRM.SETTER_CLOSER.VIEW
|
||||
) && (
|
||||
<Route
|
||||
path={`${Constants.ROUTE_PATHS.CRM}:paramType`}
|
||||
path={`${Constants.ROUTE_PATHS.CRM}:paramType/:paramDealPhase`}
|
||||
element={
|
||||
<SuspenseFallback>
|
||||
<Crm />
|
||||
|
|
|
@ -178,7 +178,7 @@ export function SideMenuContent({
|
|||
crmGroup.children.push({
|
||||
label: t("sideMenu.crm.customers"),
|
||||
icon: <FileTextOutlined />,
|
||||
key: Constants.ROUTE_PATHS.CRM + Constants.CRM_TYPE.CUSTOMERS,
|
||||
key: `${Constants.ROUTE_PATHS.CRM}${Constants.CRM_TYPE.CUSTOMERS}/1`,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ export function SideMenuContent({
|
|||
crmGroup.children.push({
|
||||
label: t("sideMenu.crm.dmcPipeline"),
|
||||
icon: <FileTextOutlined />,
|
||||
key: Constants.ROUTE_PATHS.CRM + Constants.CRM_TYPE.DMC_PIPELINE,
|
||||
key: `${Constants.ROUTE_PATHS.CRM}${Constants.CRM_TYPE.DMC_PIPELINE}/1`,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ export function SideMenuContent({
|
|||
crmGroup.children.push({
|
||||
label: t("sideMenu.crm.setterCloser"),
|
||||
icon: <FileTextOutlined />,
|
||||
key: Constants.ROUTE_PATHS.CRM + Constants.CRM_TYPE.SETTER_CLOSER,
|
||||
key: `${Constants.ROUTE_PATHS.CRM}${Constants.CRM_TYPE.SETTER_CLOSER}/1`,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import { createContext, useContext, useRef, useState } from "react";
|
||||
|
||||
const preview = {
|
||||
paginationPage: 1,
|
||||
paginationPageRef: null,
|
||||
totalPages: 0,
|
||||
customers: [],
|
||||
openDrawerCustomerId: null,
|
||||
currentDrawerCustomer: null,
|
||||
currentDrawerCustomerRef: null,
|
||||
};
|
||||
|
||||
const CrmContext = createContext(preview);
|
||||
|
||||
export const useCrmContext = () => useContext(CrmContext);
|
||||
|
||||
export function CrmProvider({ children }) {
|
||||
const [paginationPage, setPaginationPage] = useState(1);
|
||||
const paginationPageRef = useRef(paginationPage);
|
||||
const [totalPages, setTotalPages] = useState(0);
|
||||
|
||||
const [customers, setCustomers] = useState([]);
|
||||
// will be used to store the customer id that is currently being viewed in the drawer
|
||||
const openDrawerCustomerId = useRef(null);
|
||||
// will be used to store the customer object that is currently being viewed in the drawer
|
||||
const [currentDrawerCustomer, setCurrentDrawerCustomer] = useState(null);
|
||||
// will be set on drawer open and used to check if the customer has changed
|
||||
const currentDrawerCustomerRef = useRef(null);
|
||||
|
||||
return (
|
||||
<CrmContext.Provider
|
||||
value={{
|
||||
paginationPage,
|
||||
setPaginationPage,
|
||||
paginationPageRef,
|
||||
totalPages,
|
||||
setTotalPages,
|
||||
customers,
|
||||
setCustomers,
|
||||
openDrawerCustomerId,
|
||||
currentDrawerCustomer,
|
||||
setCurrentDrawerCustomer,
|
||||
currentDrawerCustomerRef,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</CrmContext.Provider>
|
||||
);
|
||||
}
|
|
@ -16,6 +16,7 @@ import { useUsersContext } from "./UsersContext";
|
|||
import { useHeaderContext } from "./HeaderContext";
|
||||
import { useConsolesContext } from "./ConsolesContext";
|
||||
import { useScannerContext } from "./ScannerContext";
|
||||
import { useCrmContext } from "./CrmContext";
|
||||
|
||||
const WebSocketContext = createContext(null);
|
||||
|
||||
|
@ -44,6 +45,7 @@ export default function WebSocketProvider({
|
|||
const usersContext = useUsersContext();
|
||||
const consolesContext = useConsolesContext();
|
||||
const scannerContext = useScannerContext();
|
||||
const crmContext = useCrmContext();
|
||||
|
||||
if (wsConnectionEvent === null) {
|
||||
wsConnectionEvent = new CustomEvent(wsConnectionCustomEventName, {
|
||||
|
@ -103,7 +105,8 @@ export default function WebSocketProvider({
|
|||
adminAreaRolesContext,
|
||||
usersContext,
|
||||
consolesContext,
|
||||
scannerContext
|
||||
scannerContext,
|
||||
crmContext
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ export const ReceivedMessagesCommands = {
|
|||
AdminAreaManageCheckedForAvailableCategories: 44,
|
||||
AdminAreaManageLogManagerServerConnectionAdded: 45,
|
||||
AdminAreaManageLogManagerServerConnectionRemoved: 46,
|
||||
CrmCustomerUpdated: 47,
|
||||
};
|
||||
|
||||
// commands sent to the backend server
|
||||
|
@ -92,7 +93,8 @@ export function handleWebSocketMessage(
|
|||
adminAreaRolesContext,
|
||||
usersContext,
|
||||
consolesContext,
|
||||
scannerContext
|
||||
scannerContext,
|
||||
crmContext
|
||||
) {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
|
@ -1027,6 +1029,32 @@ export function handleWebSocketMessage(
|
|||
arr.filter((c) => c.Id !== body)
|
||||
);
|
||||
break;
|
||||
case ReceivedMessagesCommands.CrmCustomerUpdated:
|
||||
console.log("CrmCustomerUpdated", body);
|
||||
|
||||
console.log("current", crmContext.currentDrawerCustomerRef.current);
|
||||
|
||||
// update drawer customer if it is the same customer
|
||||
if (crmContext.currentDrawerCustomerRef.current !== null) {
|
||||
if (crmContext.currentDrawerCustomerRef.current.Id === body.Id) {
|
||||
crmContext.setCurrentDrawerCustomer(body);
|
||||
}
|
||||
}
|
||||
|
||||
// update customers list
|
||||
crmContext.setCustomers((arr) => {
|
||||
const newArr = [...arr];
|
||||
|
||||
const arrIndex = arr.findIndex((customer) => customer.Id === body.Id);
|
||||
|
||||
if (arrIndex !== -1) {
|
||||
newArr[arrIndex] = body;
|
||||
}
|
||||
|
||||
return newArr;
|
||||
});
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error("unknown command", cmd);
|
||||
|
|
|
@ -14,15 +14,25 @@ import {
|
|||
Typography,
|
||||
} from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { AppStyle, Constants } from "../../utils";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import {
|
||||
AppStyle,
|
||||
Constants,
|
||||
myFetch,
|
||||
wsConnectionCustomEventName,
|
||||
} from "../../utils";
|
||||
import { useEffect, useState } from "react";
|
||||
import { PlusOutlined } from "@ant-design/icons";
|
||||
import { t } from "i18next";
|
||||
import PageNotFound from "../PageNotFound";
|
||||
import { useCrmContext } from "../../Contexts/CrmContext";
|
||||
import MyPagination from "../../Components/MyPagination";
|
||||
|
||||
export default function Crm() {
|
||||
const { t } = useTranslation();
|
||||
const { paramType } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const crmContext = useCrmContext();
|
||||
const { paramType, paramDealPhase } = useParams();
|
||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false);
|
||||
|
||||
const title =
|
||||
|
@ -41,9 +51,7 @@ export default function Crm() {
|
|||
}
|
||||
);
|
||||
|
||||
const [selectedSegmentedValue, setSelectedSegmentedValue] = useState(
|
||||
segmentedOptions[0]
|
||||
);
|
||||
const [selectedSegmentedValue, setSelectedSegmentedValue] = useState([]);
|
||||
|
||||
const getTableContent = () => {
|
||||
return [
|
||||
|
@ -92,31 +100,72 @@ export default function Crm() {
|
|||
};
|
||||
|
||||
const getTableItems = () => {
|
||||
return [
|
||||
{
|
||||
key: "1",
|
||||
id: "",
|
||||
firstName: "Max",
|
||||
},
|
||||
{
|
||||
key: "2",
|
||||
id: "",
|
||||
firstName: "Peter",
|
||||
},
|
||||
{
|
||||
key: "3",
|
||||
id: "",
|
||||
firstName: "Anna",
|
||||
},
|
||||
];
|
||||
let items = [];
|
||||
|
||||
crmContext.customers.forEach((item) => {
|
||||
items.push({
|
||||
key: item.Id,
|
||||
id: item.Id,
|
||||
firstName: item.FirstName,
|
||||
lastName: item.LastName,
|
||||
createdAt: item.CreatedAt,
|
||||
telephone: item.Telephone,
|
||||
email: item.Email,
|
||||
lastContact: item.LastContact,
|
||||
createdBy: item.CreatedBy,
|
||||
notes: item.Notes,
|
||||
});
|
||||
});
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
const onPaginationChange = (page) => {
|
||||
crmContext.setPaginationPage(page);
|
||||
crmContext.paginationPageRef.current = page;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (paramType === Constants.CRM_TYPE.CUSTOMERS) return;
|
||||
|
||||
setSelectedSegmentedValue(segmentedOptions[0]);
|
||||
setSelectedSegmentedValue(segmentedOptions[paramDealPhase - 1]);
|
||||
}, [paramType]);
|
||||
|
||||
useEffect(() => {
|
||||
const customersRequest = () =>
|
||||
myFetch(
|
||||
`/crm/pipeline/${paramType}/${paramDealPhase}?page=${crmContext.paginationPage}`,
|
||||
"GET"
|
||||
).then((data) => {
|
||||
if (data.Customers !== undefined) {
|
||||
crmContext.setCustomers(data.Customers);
|
||||
}
|
||||
|
||||
if (data.TotalPages !== undefined) {
|
||||
crmContext.setTotalPages(data.TotalPages);
|
||||
}
|
||||
});
|
||||
|
||||
customersRequest();
|
||||
|
||||
const handleCustomersRequest = () => customersRequest();
|
||||
|
||||
document.addEventListener(
|
||||
wsConnectionCustomEventName,
|
||||
handleCustomersRequest
|
||||
);
|
||||
|
||||
return () =>
|
||||
document.removeEventListener(
|
||||
wsConnectionCustomEventName,
|
||||
handleCustomersRequest
|
||||
);
|
||||
}, [paramType, paramDealPhase]);
|
||||
|
||||
if (paramDealPhase > segmentedOptions.length) {
|
||||
return <PageNotFound />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
|
@ -135,8 +184,19 @@ export default function Crm() {
|
|||
{paramType !== Constants.CRM_TYPE.CUSTOMERS && (
|
||||
<Segmented
|
||||
value={selectedSegmentedValue}
|
||||
onChange={(value) => setSelectedSegmentedValue(value)}
|
||||
options={segmentedOptions}
|
||||
onChange={(value) => {
|
||||
setSelectedSegmentedValue(value);
|
||||
navigate(
|
||||
`/crm/${paramType}/${segmentedOptions.indexOf(value) + 1}`,
|
||||
true
|
||||
);
|
||||
}}
|
||||
options={segmentedOptions.map((item) => {
|
||||
return {
|
||||
value: item,
|
||||
label: item,
|
||||
};
|
||||
})}
|
||||
style={{ marginBottom: AppStyle.app.margin }}
|
||||
/>
|
||||
)}
|
||||
|
@ -145,16 +205,23 @@ export default function Crm() {
|
|||
scroll={{ x: "max-content" }}
|
||||
columns={getTableContent()}
|
||||
dataSource={getTableItems()}
|
||||
onRow={(record, rowIndex) => {
|
||||
pagination={false}
|
||||
onRow={(record) => {
|
||||
return {
|
||||
onClick: (event) => {
|
||||
console.log("row", record, rowIndex);
|
||||
onClick: () => {
|
||||
setIsDrawerOpen(true);
|
||||
crmContext.openDrawerCustomerId.current = record.id;
|
||||
},
|
||||
};
|
||||
}}
|
||||
/>
|
||||
|
||||
<MyPagination
|
||||
paginationPage={crmContext.paginationPage}
|
||||
setPaginationPage={(page) => onPaginationChange(page)}
|
||||
totalPages={crmContext.totalPages}
|
||||
/>
|
||||
|
||||
<CustomerDrawer
|
||||
isOpen={isDrawerOpen}
|
||||
onClose={() => setIsDrawerOpen(false)}
|
||||
|
@ -165,6 +232,7 @@ export default function Crm() {
|
|||
|
||||
function CustomerDrawer({ isOpen, onClose }) {
|
||||
const { t } = useTranslation();
|
||||
const crmContext = useCrmContext();
|
||||
|
||||
const tabItems = [
|
||||
{
|
||||
|
@ -184,14 +252,73 @@ function CustomerDrawer({ isOpen, onClose }) {
|
|||
},
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
console.log("isOpen", isOpen);
|
||||
|
||||
if (crmContext.openDrawerCustomerId.current === null) return;
|
||||
|
||||
const customerRequest = () => {
|
||||
if (!isOpen) return;
|
||||
|
||||
myFetch(
|
||||
`/crm/customer/view/${crmContext.openDrawerCustomerId.current}`,
|
||||
"GET"
|
||||
).then((data) => {
|
||||
console.log("customer", data);
|
||||
crmContext.setCurrentDrawerCustomer(data);
|
||||
crmContext.currentDrawerCustomerRef.current = data;
|
||||
});
|
||||
};
|
||||
|
||||
if (isOpen) {
|
||||
customerRequest();
|
||||
} else {
|
||||
// check if something has changed
|
||||
if (
|
||||
JSON.stringify(crmContext.currentDrawerCustomer) !==
|
||||
JSON.stringify(crmContext.currentDrawerCustomerRef.current)
|
||||
) {
|
||||
console.log("something has changed");
|
||||
|
||||
myFetch(
|
||||
`/crm/customer/update/${crmContext.openDrawerCustomerId.current}`,
|
||||
"POST",
|
||||
crmContext.currentDrawerCustomer
|
||||
).then((data) => {
|
||||
console.log("update", data);
|
||||
});
|
||||
} else {
|
||||
console.log("nothing has changed");
|
||||
}
|
||||
|
||||
crmContext.openDrawerCustomerId.current = null;
|
||||
crmContext.currentDrawerCustomer = null;
|
||||
crmContext.currentDrawerCustomerRef.current = null;
|
||||
}
|
||||
|
||||
const handleCustomerRequest = () => customerRequest();
|
||||
|
||||
document.addEventListener(
|
||||
wsConnectionCustomEventName,
|
||||
handleCustomerRequest
|
||||
);
|
||||
|
||||
return () =>
|
||||
document.removeEventListener(
|
||||
wsConnectionCustomEventName,
|
||||
handleCustomerRequest
|
||||
);
|
||||
}, [isOpen]);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
title={"loading..."}
|
||||
title={`${crmContext.currentDrawerCustomer?.FirstName} ${crmContext.currentDrawerCustomer?.LastName}`}
|
||||
placement="right"
|
||||
open={isOpen}
|
||||
onClose={onClose}
|
||||
width={720}
|
||||
>
|
||||
{console.log("drawer", crmContext.openDrawerCustomerId.current)}
|
||||
<Tabs defaultActiveKey="0" items={tabItems} centered />
|
||||
</Drawer>
|
||||
);
|
||||
|
@ -228,8 +355,7 @@ function CollapseContainer({ children, label }) {
|
|||
}
|
||||
|
||||
function TabContentDealInfo() {
|
||||
const [selectedPipeline, setSelectedPipeline] = useState(0);
|
||||
const [selectedDealPhase, setSelectedDealPhase] = useState(0);
|
||||
const crmContext = useCrmContext();
|
||||
|
||||
return (
|
||||
<Space direction="vertical" style={{ display: "flex" }}>
|
||||
|
@ -239,21 +365,27 @@ function TabContentDealInfo() {
|
|||
<Content>
|
||||
<Form.Item
|
||||
label={t("crm.tabContent.dealInfo.collapseDealStatus.pipeline")}
|
||||
initialValue={selectedPipeline}
|
||||
initialValue={crmContext.currentDrawerCustomer?.Pipeline}
|
||||
>
|
||||
<Select
|
||||
value={selectedPipeline}
|
||||
value={crmContext.currentDrawerCustomer?.Pipeline}
|
||||
onChange={(value) => {
|
||||
setSelectedPipeline(value);
|
||||
setSelectedDealPhase(0);
|
||||
//setSelectedPipeline(value);
|
||||
//setSelectedDealPhase(0);
|
||||
|
||||
crmContext.setCurrentDrawerCustomer({
|
||||
...crmContext.currentDrawerCustomer,
|
||||
Pipeline: value,
|
||||
DealPhase: 0,
|
||||
});
|
||||
}}
|
||||
options={[
|
||||
{
|
||||
value: 0,
|
||||
value: 1,
|
||||
label: t("crm.dmcPipeline.pageTitle"),
|
||||
},
|
||||
{
|
||||
value: 1,
|
||||
value: 2,
|
||||
label: t("crm.setterCloser.pageTitle"),
|
||||
},
|
||||
]}
|
||||
|
@ -262,19 +394,24 @@ function TabContentDealInfo() {
|
|||
|
||||
<Form.Item
|
||||
label={t("crm.tabContent.dealInfo.collapseDealStatus.dealPhase")}
|
||||
initialValue={selectedDealPhase}
|
||||
initialValue={crmContext.currentDrawerCustomer?.DealPhase}
|
||||
>
|
||||
<Select
|
||||
value={selectedDealPhase}
|
||||
onChange={(value) => setSelectedDealPhase(value)}
|
||||
value={crmContext.currentDrawerCustomer?.DealPhase}
|
||||
onChange={(value) =>
|
||||
crmContext.setCurrentDrawerCustomer({
|
||||
...crmContext.currentDrawerCustomer,
|
||||
DealPhase: value,
|
||||
})
|
||||
}
|
||||
options={t(
|
||||
selectedPipeline === 0
|
||||
crmContext.currentDrawerCustomer?.Pipeline === 1
|
||||
? "crm.dmcPipeline.segmentedOptions"
|
||||
: "crm.setterCloser.segmentedOptions",
|
||||
{ returnObjects: true }
|
||||
).map((item, index) => {
|
||||
return {
|
||||
value: index,
|
||||
value: index + 1,
|
||||
label: item,
|
||||
};
|
||||
})}
|
||||
|
@ -294,7 +431,15 @@ function TabContentDealInfo() {
|
|||
"crm.tabContent.dealInfo.collapseMasterDataOfContact.firstName"
|
||||
)}
|
||||
>
|
||||
<Input />
|
||||
<Input
|
||||
value={crmContext.currentDrawerCustomer?.FirstName}
|
||||
onChange={(e) =>
|
||||
crmContext.setCurrentDrawerCustomer({
|
||||
...crmContext.currentDrawerCustomer,
|
||||
FirstName: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
|
@ -302,7 +447,15 @@ function TabContentDealInfo() {
|
|||
"crm.tabContent.dealInfo.collapseMasterDataOfContact.lastName"
|
||||
)}
|
||||
>
|
||||
<Input />
|
||||
<Input
|
||||
value={crmContext.currentDrawerCustomer?.LastName}
|
||||
onChange={(e) =>
|
||||
crmContext.setCurrentDrawerCustomer({
|
||||
...crmContext.currentDrawerCustomer,
|
||||
LastName: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Content>
|
||||
|
||||
|
@ -312,7 +465,15 @@ function TabContentDealInfo() {
|
|||
"crm.tabContent.dealInfo.collapseMasterDataOfContact.telephone"
|
||||
)}
|
||||
>
|
||||
<Input />
|
||||
<Input
|
||||
value={crmContext.currentDrawerCustomer?.Telephone}
|
||||
onChange={(e) =>
|
||||
crmContext.setCurrentDrawerCustomer({
|
||||
...crmContext.currentDrawerCustomer,
|
||||
Telephone: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
|
@ -320,7 +481,15 @@ function TabContentDealInfo() {
|
|||
"crm.tabContent.dealInfo.collapseMasterDataOfContact.email"
|
||||
)}
|
||||
>
|
||||
<Input />
|
||||
<Input
|
||||
value={crmContext.currentDrawerCustomer?.Email}
|
||||
onChange={(e) =>
|
||||
crmContext.setCurrentDrawerCustomer({
|
||||
...crmContext.currentDrawerCustomer,
|
||||
Email: e.target.value,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Content>
|
||||
|
||||
|
|
Loading…
Reference in New Issue