link share
parent
20b70d5d57
commit
4568663ae4
|
@ -37,7 +37,8 @@
|
||||||
"yes": "Ja",
|
"yes": "Ja",
|
||||||
"no": "Nein",
|
"no": "Nein",
|
||||||
"more": "Mehr",
|
"more": "Mehr",
|
||||||
"pleaseInput": "Bitte eingeben"
|
"pleaseInput": "Bitte eingeben",
|
||||||
|
"pleaseInputValidUrl": "Bitte geben Sie eine gültige URL ein"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"inputsInvalid": {
|
"inputsInvalid": {
|
||||||
|
@ -363,6 +364,15 @@
|
||||||
},
|
},
|
||||||
"emails": {
|
"emails": {
|
||||||
"title": "E-Mails"
|
"title": "E-Mails"
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"title": "Links",
|
||||||
|
"buttonAddLink": "Link hinzufügen",
|
||||||
|
"addLinkModal": {
|
||||||
|
"title": "Link hinzufügen",
|
||||||
|
"name": "Name",
|
||||||
|
"link": "Link"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -37,7 +37,8 @@
|
||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"more": "More",
|
"more": "More",
|
||||||
"pleaseInput": "Please input"
|
"pleaseInput": "Please input",
|
||||||
|
"pleaseInputValidUrl": "Please input a valid URL"
|
||||||
},
|
},
|
||||||
"request": {
|
"request": {
|
||||||
"inputsInvalid": {
|
"inputsInvalid": {
|
||||||
|
@ -363,7 +364,15 @@
|
||||||
},
|
},
|
||||||
"emails": {
|
"emails": {
|
||||||
"title": "Emails"
|
"title": "Emails"
|
||||||
|
},
|
||||||
|
"links": {
|
||||||
|
"title": "Links",
|
||||||
|
"buttonAddLink": "Add Link",
|
||||||
|
"addLinkModal": {
|
||||||
|
"title": "Add Link",
|
||||||
|
"name": "Name",
|
||||||
|
"link": "Link"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,6 +12,10 @@ const preview = {
|
||||||
changedDrawerCustomerFieldsRef: null,
|
changedDrawerCustomerFieldsRef: null,
|
||||||
currentDrawerCallProtocols: [],
|
currentDrawerCallProtocols: [],
|
||||||
setCurrentDrawerCallProtocols: () => {},
|
setCurrentDrawerCallProtocols: () => {},
|
||||||
|
currentDrawerActivityLinks: [],
|
||||||
|
setCurrentDrawerActivityLinks: () => {},
|
||||||
|
currentDrawerActivityLinkHistory: [],
|
||||||
|
setCurrentDrawerActivityLinkHistory: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const CrmContext = createContext(preview);
|
const CrmContext = createContext(preview);
|
||||||
|
@ -36,6 +40,13 @@ export function CrmProvider({ children }) {
|
||||||
const [currentDrawerCallProtocols, setCurrentDrawerCallProtocols] = useState(
|
const [currentDrawerCallProtocols, setCurrentDrawerCallProtocols] = useState(
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
const [currentDrawerActivityLinks, setCurrentDrawerActivityLinks] = useState(
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const [
|
||||||
|
currentDrawerActivityLinkHistory,
|
||||||
|
setCurrentDrawerActivityLinkHistory,
|
||||||
|
] = useState([]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CrmContext.Provider
|
<CrmContext.Provider
|
||||||
|
@ -55,6 +66,10 @@ export function CrmProvider({ children }) {
|
||||||
changedDrawerCustomerFieldsRef,
|
changedDrawerCustomerFieldsRef,
|
||||||
currentDrawerCallProtocols,
|
currentDrawerCallProtocols,
|
||||||
setCurrentDrawerCallProtocols,
|
setCurrentDrawerCallProtocols,
|
||||||
|
currentDrawerActivityLinks,
|
||||||
|
setCurrentDrawerActivityLinks,
|
||||||
|
currentDrawerActivityLinkHistory,
|
||||||
|
setCurrentDrawerActivityLinkHistory,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -52,6 +52,9 @@ export const ReceivedMessagesCommands = {
|
||||||
CrmCustomerCreated: 48,
|
CrmCustomerCreated: 48,
|
||||||
CrmCallProtocolCreated: 49,
|
CrmCallProtocolCreated: 49,
|
||||||
CrmCallProtocolDeleted: 50,
|
CrmCallProtocolDeleted: 50,
|
||||||
|
CrmLinkCreated: 51,
|
||||||
|
CrmLinkUsed: 52,
|
||||||
|
CrmLinkDeleted: 53,
|
||||||
};
|
};
|
||||||
|
|
||||||
// commands sent to the backend server
|
// commands sent to the backend server
|
||||||
|
@ -1106,6 +1109,17 @@ export function handleWebSocketMessage(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ReceivedMessagesCommands.CrmLinkCreated:
|
||||||
|
crmContext.setCurrentDrawerActivityLinks((arr) => [...arr, body]);
|
||||||
|
break;
|
||||||
|
case ReceivedMessagesCommands.CrmLinkUsed:
|
||||||
|
crmContext.setCurrentDrawerActivityLinkHistory((arr) => [...arr, body]);
|
||||||
|
break;
|
||||||
|
case ReceivedMessagesCommands.CrmLinkDeleted:
|
||||||
|
crmContext.setCurrentDrawerActivityLinks((arr) =>
|
||||||
|
arr.filter((link) => link.Id !== body)
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.error("unknown command", cmd);
|
console.error("unknown command", cmd);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {
|
||||||
Empty,
|
Empty,
|
||||||
Flex,
|
Flex,
|
||||||
Popconfirm,
|
Popconfirm,
|
||||||
|
List,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import {
|
import {
|
||||||
|
@ -65,7 +66,7 @@ import MyModal, {
|
||||||
MyModalCloseCreateButtonFooter,
|
MyModalCloseCreateButtonFooter,
|
||||||
} from "../../Components/MyModal";
|
} from "../../Components/MyModal";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import Markdown from "react-markdown";
|
import { MyCopyIcon } from "../../Components/MyIcon";
|
||||||
|
|
||||||
const CRM_TYPE = {
|
const CRM_TYPE = {
|
||||||
CUSTOMERS: 0,
|
CUSTOMERS: 0,
|
||||||
|
@ -684,6 +685,11 @@ function CustomerDrawer({ isOpen, setIsOpen, onClose, notificationApi }) {
|
||||||
crmContext.currentDrawerCustomerRef.current = customer;
|
crmContext.currentDrawerCustomerRef.current = customer;
|
||||||
|
|
||||||
crmContext.setCurrentDrawerCallProtocols(data.CallProtocols);
|
crmContext.setCurrentDrawerCallProtocols(data.CallProtocols);
|
||||||
|
crmContext.setCurrentDrawerActivityLinks(data.Links);
|
||||||
|
|
||||||
|
if (data.LinkHistory !== null) {
|
||||||
|
crmContext.setCurrentDrawerActivityLinkHistory(data.LinkHistory);
|
||||||
|
}
|
||||||
|
|
||||||
formDealInfo.setFieldsValue({
|
formDealInfo.setFieldsValue({
|
||||||
Pipeline: customer.Pipeline,
|
Pipeline: customer.Pipeline,
|
||||||
|
@ -1214,9 +1220,19 @@ function TabContentDealInfo({ form }) {
|
||||||
function TabContentActivities({ notificationApi }) {
|
function TabContentActivities({ notificationApi }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const [activeTab, setActiveTab] = useState(0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MySupsenseFallback>
|
<MySupsenseFallback>
|
||||||
<Tabs
|
<Tabs
|
||||||
|
activeKey={activeTab}
|
||||||
|
onChange={(activeKey) => setActiveTab(activeKey)}
|
||||||
|
tabBarExtraContent={{
|
||||||
|
right:
|
||||||
|
activeTab === 2 ? (
|
||||||
|
<AddLinkModal notificationApi={notificationApi} />
|
||||||
|
) : null,
|
||||||
|
}}
|
||||||
items={[
|
items={[
|
||||||
{
|
{
|
||||||
key: 0,
|
key: 0,
|
||||||
|
@ -1230,6 +1246,11 @@ function TabContentActivities({ notificationApi }) {
|
||||||
label: t("crm.tabContent.activities.emails.title"),
|
label: t("crm.tabContent.activities.emails.title"),
|
||||||
disabled: true,
|
disabled: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 2,
|
||||||
|
label: t("crm.tabContent.activities.links.title"),
|
||||||
|
children: <ActivityLinks notificationApi={notificationApi} />,
|
||||||
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</MySupsenseFallback>
|
</MySupsenseFallback>
|
||||||
|
@ -1313,6 +1334,7 @@ function ActivityCallProtocols({ notificationApi }) {
|
||||||
avatarWidth={56}
|
avatarWidth={56}
|
||||||
userId={item.CreatedBy}
|
userId={item.CreatedBy}
|
||||||
allUsers={appContext.users}
|
allUsers={appContext.users}
|
||||||
|
tooltip
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
title={
|
title={
|
||||||
|
@ -1743,6 +1765,200 @@ function CallProtocolModal({ formDealInfo, notificationApi }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function AddLinkModal({ notificationApi }) {
|
||||||
|
const crmContext = useCrmContext();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
const handleCancel = () => setIsOpen(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen) {
|
||||||
|
form.resetFields();
|
||||||
|
}
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<PlusOutlined />}
|
||||||
|
onClick={() => setIsOpen(true)}
|
||||||
|
>
|
||||||
|
{t("crm.tabContent.activities.links.buttonAddLink")}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<MyModal
|
||||||
|
title={t("crm.tabContent.activities.links.addLinkModal.title")}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
footer={
|
||||||
|
<MyModalCloseCreateButtonFooter
|
||||||
|
onCancel={handleCancel}
|
||||||
|
onCreate={() => {
|
||||||
|
form
|
||||||
|
.validateFields()
|
||||||
|
.then((values) => {
|
||||||
|
myFetch("/crm/links", "POST", {
|
||||||
|
CustomerId: crmContext.openDrawerCustomerId.current,
|
||||||
|
Name: values.name,
|
||||||
|
Url: values.link,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
setIsOpen(false);
|
||||||
|
form.resetFields();
|
||||||
|
})
|
||||||
|
.catch(() =>
|
||||||
|
showUnkownErrorNotification(notificationApi, t)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(() => showInputsInvalidNotification(notificationApi, t));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MySupsenseFallback>
|
||||||
|
<Form form={form} layout="vertical" requiredMark={false}>
|
||||||
|
<Form.Item
|
||||||
|
name="name"
|
||||||
|
label={t("crm.tabContent.activities.links.addLinkModal.name")}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t("common.text.pleaseInput"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input placeholder="Instagram" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="link"
|
||||||
|
label={t("crm.tabContent.activities.links.addLinkModal.link")}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t("common.text.pleaseInput"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "url",
|
||||||
|
message: t("common.text.pleaseInputValidUrl"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
type="url"
|
||||||
|
placeholder="https://instagram.com/my_profile"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</MySupsenseFallback>
|
||||||
|
</MyModal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ActivityLinks({ notificationApi }) {
|
||||||
|
const appContext = useAppContext();
|
||||||
|
const crmContext = useCrmContext();
|
||||||
|
|
||||||
|
if (crmContext.currentDrawerActivityLinks.length === 0) return <Empty />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Space direction="vertical" style={{ width: "100%" }}>
|
||||||
|
{crmContext.currentDrawerActivityLinks.map((item) => (
|
||||||
|
<Collapse
|
||||||
|
key={item.Id}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
key: item.Id,
|
||||||
|
label: (
|
||||||
|
<Flex justify="space-between">
|
||||||
|
<Flex vertical>
|
||||||
|
<span>{item.Name}</span>
|
||||||
|
<a href={item.Url} target="_blank" rel="noreferrer">
|
||||||
|
{item.Url}
|
||||||
|
</a>
|
||||||
|
<span>{FormatDatetime(item.CreatedAt)}</span>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Space>
|
||||||
|
<span>
|
||||||
|
{
|
||||||
|
crmContext.currentDrawerActivityLinkHistory.filter(
|
||||||
|
(link) => link.LinkId === item.Id
|
||||||
|
).length
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<MyCopyIcon
|
||||||
|
text={`${Constants.CRM_LINK_SHARE_ADDRESS}${item.Id}`}
|
||||||
|
notificationApi={notificationApi}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<MyAvatar
|
||||||
|
avatarWidth={24}
|
||||||
|
userId={item.CreatedBy}
|
||||||
|
allUsers={appContext.users}
|
||||||
|
tooltip
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Popconfirm
|
||||||
|
placement="left"
|
||||||
|
title={"Möchten Sie diesen Link wirklich löschen?"}
|
||||||
|
cancelText={"Abbrechen"}
|
||||||
|
okText={"Bestätigen"}
|
||||||
|
onConfirm={() => {
|
||||||
|
myFetch(`/crm/links/${item.Id}`, "DELETE").catch(() =>
|
||||||
|
showUnkownErrorNotification(notificationApi, t)
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DeleteOutlined style={{ color: "darkred" }} />
|
||||||
|
</Popconfirm>
|
||||||
|
</Space>
|
||||||
|
</Flex>
|
||||||
|
),
|
||||||
|
children: (
|
||||||
|
<List
|
||||||
|
itemLayout="horizontal"
|
||||||
|
dataSource={crmContext.currentDrawerActivityLinkHistory
|
||||||
|
.filter((link) => link.LinkId === item.Id)
|
||||||
|
.sort((a, b) => new Date(b.UsedAt) - new Date(a.UsedAt))}
|
||||||
|
renderItem={(item) => (
|
||||||
|
<List.Item>
|
||||||
|
<List.Item.Meta
|
||||||
|
title={
|
||||||
|
<Flex vertical>
|
||||||
|
<span>
|
||||||
|
<span style={{ fontWeight: "bold" }}>
|
||||||
|
UserAgent:{" "}
|
||||||
|
</span>
|
||||||
|
{item.UserAgent}
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<span style={{ fontWeight: "bold" }}>
|
||||||
|
Used at:{" "}
|
||||||
|
</span>
|
||||||
|
{FormatDatetime(item.UsedAt)}
|
||||||
|
</span>
|
||||||
|
</Flex>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function TabContentNotes({ notes }) {
|
function TabContentNotes({ notes }) {
|
||||||
const crmContext = useCrmContext();
|
const crmContext = useCrmContext();
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ let roboticsApiAddress = "";
|
||||||
var roboticsSwaggerAddress = "";
|
var roboticsSwaggerAddress = "";
|
||||||
var telegramBotManagerAddress = "";
|
var telegramBotManagerAddress = "";
|
||||||
var telegramBotManagerStaticContentAddress = "";
|
var telegramBotManagerStaticContentAddress = "";
|
||||||
|
var crmLinkShareAddress = "";
|
||||||
|
|
||||||
if (window.location.hostname === "localhost" && window.location.port === "") {
|
if (window.location.hostname === "localhost" && window.location.port === "") {
|
||||||
// for docker container testing on localhost
|
// for docker container testing on localhost
|
||||||
|
@ -27,6 +28,7 @@ if (window.location.hostname === "localhost" && window.location.port === "") {
|
||||||
roboticsSwaggerAddress = "http://localhost/rcm/swagger/index.html";
|
roboticsSwaggerAddress = "http://localhost/rcm/swagger/index.html";
|
||||||
telegramBotManagerAddress = "http://localhost/tm/v1";
|
telegramBotManagerAddress = "http://localhost/tm/v1";
|
||||||
telegramBotManagerStaticContentAddress = "http://localhost/tm/";
|
telegramBotManagerStaticContentAddress = "http://localhost/tm/";
|
||||||
|
crmLinkShareAddress = "http://localhost/crm/link/";
|
||||||
} else if (window.location.hostname === "localhost") {
|
} else if (window.location.hostname === "localhost") {
|
||||||
// programming on localhost
|
// programming on localhost
|
||||||
apiAddress = "http://localhost:50050/v1";
|
apiAddress = "http://localhost:50050/v1";
|
||||||
|
@ -37,6 +39,7 @@ if (window.location.hostname === "localhost" && window.location.port === "") {
|
||||||
roboticsSwaggerAddress = "http://localhost:50055/swagger/index.html";
|
roboticsSwaggerAddress = "http://localhost:50055/swagger/index.html";
|
||||||
telegramBotManagerAddress = "http://localhost:50056/v1";
|
telegramBotManagerAddress = "http://localhost:50056/v1";
|
||||||
telegramBotManagerStaticContentAddress = "http://localhost:50056/";
|
telegramBotManagerStaticContentAddress = "http://localhost:50056/";
|
||||||
|
crmLinkShareAddress = "http://localhost:50050/v1/crm/link/";
|
||||||
/*} else if (window.location.hostname === "192.168.178.93") {
|
/*} else if (window.location.hostname === "192.168.178.93") {
|
||||||
apiAddress = "http://192.168.178.93:50050/v1";
|
apiAddress = "http://192.168.178.93:50050/v1";
|
||||||
staticContentAddress = "http://192.168.178.93:50050/";
|
staticContentAddress = "http://192.168.178.93:50050/";
|
||||||
|
@ -51,6 +54,7 @@ if (window.location.hostname === "localhost" && window.location.port === "") {
|
||||||
roboticsSwaggerAddress = `${window.location.protocol}${window.location.hostname}/rcm/swagger/index.html`;
|
roboticsSwaggerAddress = `${window.location.protocol}${window.location.hostname}/rcm/swagger/index.html`;
|
||||||
telegramBotManagerAddress = `${window.location.protocol}${window.location.hostname}/tm/v1`;
|
telegramBotManagerAddress = `${window.location.protocol}${window.location.hostname}/tm/v1`;
|
||||||
telegramBotManagerStaticContentAddress = `${window.location.protocol}${window.location.hostname}/tm/`;
|
telegramBotManagerStaticContentAddress = `${window.location.protocol}${window.location.hostname}/tm/`;
|
||||||
|
crmLinkShareAddress = `${window.location.protocol}${window.location.hostname}/api/v1/crm/link/`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Constants = {
|
export const Constants = {
|
||||||
|
@ -76,6 +80,7 @@ export const Constants = {
|
||||||
ROBOTICS_SWAGGER_ADDRESS: roboticsSwaggerAddress,
|
ROBOTICS_SWAGGER_ADDRESS: roboticsSwaggerAddress,
|
||||||
TELEGRAM_BOT_MANAGER_ADDRESS: telegramBotManagerAddress,
|
TELEGRAM_BOT_MANAGER_ADDRESS: telegramBotManagerAddress,
|
||||||
TELEGRAM_BOT_MANAGER_CONTENT_ADDRESS: telegramBotManagerStaticContentAddress,
|
TELEGRAM_BOT_MANAGER_CONTENT_ADDRESS: telegramBotManagerStaticContentAddress,
|
||||||
|
CRM_LINK_SHARE_ADDRESS: crmLinkShareAddress,
|
||||||
ROUTE_PATHS: {
|
ROUTE_PATHS: {
|
||||||
EQUIPMENT_DOCUMENTATION: "/equipment-documentation",
|
EQUIPMENT_DOCUMENTATION: "/equipment-documentation",
|
||||||
EQUIPMENT_DOCUMENTATION_VIEW: "/equipment-documentation/",
|
EQUIPMENT_DOCUMENTATION_VIEW: "/equipment-documentation/",
|
||||||
|
|
Loading…
Reference in New Issue