diff --git a/client/src/components/bills-list-table/bills-list-table.component.jsx b/client/src/components/bills-list-table/bills-list-table.component.jsx
index 05c6324e7..efd1a5d0d 100644
--- a/client/src/components/bills-list-table/bills-list-table.component.jsx
+++ b/client/src/components/bills-list-table/bills-list-table.component.jsx
@@ -1,7 +1,8 @@
import { EditFilled, SyncOutlined } from "@ant-design/icons";
import { Button, Card, Checkbox, Input, Space, Table } from "antd";
-import React, { useState } from "react";
+import React, { useRef, useState } from "react";
import { useTranslation } from "react-i18next";
+import { FaTasks } from "react-icons/fa";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
@@ -13,10 +14,11 @@ import { alphaSort, dateSort } from "../../utils/sorters";
import { TemplateList } from "../../utils/TemplateConstants";
import BillDeleteButton from "../bill-delete-button/bill-delete-button.component";
import BillDetailEditReturnComponent from "../bill-detail-edit/bill-detail-edit-return.component";
-import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
-import { FaTasks } from "react-icons/fa";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
import LockerWrapperComponent from "../lock-wrapper/lock-wrapper.component";
+import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
+import UpsellComponent from "../upsell/upsell.component";
+import upsellEnum from "../upsell/upsell.enum";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
@@ -59,6 +61,7 @@ export function BillsListTableComponent({
// const search = queryString.parse(useLocation().search);
// const selectedBill = search.billid;
const [searchText, setSearchText] = useState("");
+ const containerRef = useRef(null);
const Templates = TemplateList("bill");
const bills = billsQuery.data ? billsQuery.data.bills : [];
@@ -237,14 +240,7 @@ export function BillsListTableComponent({
onChange={handleTableChange}
locale={{
...(!hasBillsAccess && {
- emptyText: (
-
- Upsell
- {
- //TODO:Upsell
- }
-
- )
+ emptyText:
})
}}
/>
diff --git a/client/src/components/report-center-modal/report-center-modal.component.jsx b/client/src/components/report-center-modal/report-center-modal.component.jsx
index 6cedc34ee..af73868a6 100644
--- a/client/src/components/report-center-modal/report-center-modal.component.jsx
+++ b/client/src/components/report-center-modal/report-center-modal.component.jsx
@@ -16,6 +16,7 @@ import { TemplateList } from "../../utils/TemplateConstants";
import dayjs from "../../utils/day";
import EmployeeSearchSelectEmail from "../employee-search-select/employee-search-select-email.component";
import EmployeeSearchSelect from "../employee-search-select/employee-search-select.component";
+import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
import ReportCenterModalFiltersSortersComponent from "./report-center-modal-filters-sorters-component";
@@ -130,9 +131,12 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
const grouped = _.groupBy(FilteredReportsList, "group");
const groupExcludeKeyFilter = [
- ...(!HasFeatureAccess({ featureName: "bills", bodyshop }) ? ["purchases"] : []),
- ...(!HasFeatureAccess({ featureName: "timetickets", bodyshop }) ? ["payroll"] : [])
+ ...(!HasFeatureAccess({ featureName: "bills", bodyshop }) ? [{ key: "purchases", featureName: "bills" }] : []),
+ ...(!HasFeatureAccess({ featureName: "timetickets", bodyshop })
+ ? [{ key: "payroll", featureName: "timetickets" }]
+ : [])
];
+
//TODO: Find a way to filter out / blur on demand.
return (
@@ -165,15 +169,31 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
}}
>
{t(`reportcenter.labels.groups.${key}`)}
-
- {grouped[key].map((item) => (
- -
-
- {item.title}
-
-
- ))}
-
+ {groupExcludeKeyFilter.find((g) => g.key === key) ? (
+
g.key === key).featureName}
+ >
+
+ {grouped[key].map((item) => (
+ -
+
+ {item.title}
+
+
+ ))}
+
+
+ ) : (
+
+ {grouped[key].map((item) => (
+ -
+
+ {item.title}
+
+
+ ))}
+
+ )}
))}
@@ -278,7 +298,8 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
{
validator: (_, value) => {
if (
- (!import.meta.env.VITE_APP_IS_TEST && import.meta.env.PROD) &&
+ !import.meta.env.VITE_APP_IS_TEST &&
+ import.meta.env.PROD &&
value &&
value[0] &&
value[1]
diff --git a/client/src/components/upsell/upsell.component.jsx b/client/src/components/upsell/upsell.component.jsx
new file mode 100644
index 000000000..f2b3fd07f
--- /dev/null
+++ b/client/src/components/upsell/upsell.component.jsx
@@ -0,0 +1,39 @@
+import { AppstoreAddOutlined } from "@ant-design/icons";
+import { Result } from "antd";
+import React, { useEffect, useRef } from "react";
+import { useTranslation } from "react-i18next";
+import upsellEnum from "./upsell.enum";
+
+export default function UpsellComponent({ featureName, subFeatureName, upsell, disableMask = false }) {
+ const { t } = useTranslation();
+ const resultProps = upsell || upsellEnum[featureName][subFeatureName];
+ const componentRef = useRef(null);
+
+ useEffect(() => {
+ if (disableMask) return;
+ const parentElement = componentRef.current?.parentElement;
+ if (parentElement) {
+ const mask = document.createElement("div");
+ mask.style.position = "absolute";
+ mask.style.top = 0;
+ mask.style.left = 0;
+ mask.style.width = "100%";
+ mask.style.height = "100%";
+ mask.style.backgroundColor = "rgba(0, 0, 0, 0.25)";
+ mask.style.zIndex = 9999;
+ parentElement.style.position = "relative";
+ parentElement.appendChild(mask);
+
+ return () => {
+ parentElement.removeChild(mask);
+ };
+ }
+ }, []);
+
+ if (!resultProps) return
;
+ return (
+
+ } {...resultProps} />
+
+ );
+}
diff --git a/client/src/components/upsell/upsell.enum.js b/client/src/components/upsell/upsell.enum.js
new file mode 100644
index 000000000..aead53ea8
--- /dev/null
+++ b/client/src/components/upsell/upsell.enum.js
@@ -0,0 +1,34 @@
+import i18n from "i18next";
+
+const upsellEnum = {
+ bills: {
+ postbills: {
+ icon: null,
+ title: i18n.t("upsell.messages.bills.postbills.title"),
+ subTitle: i18n.t("upsell.messages.bills.postbills.subtitle"),
+ status: null //Nullable
+ },
+ reconcile: {
+ icon: null,
+ title: i18n.t("upsell.messages.bills.reconcile.title"),
+ subTitle: i18n.t("upsell.messages.bills.reconcile.subtitle"),
+ status: null //Nullable
+ },
+ table: {
+ //icon: null,
+ title: i18n.t("upsell.messages.bills.table.title"),
+ subTitle: i18n.t("upsell.messages.bills.table.subtitle"),
+ //status: null //Nullable
+ }
+ },
+ timetickets: {
+ table: {
+ icon: null,
+ title: i18n.t("upsell.messages.timetickets.table.title"),
+ subTitle: i18n.t("upsell.messages.timetickets.table.subtitle"),
+ status: null //Nullable
+ }
+ }
+};
+
+export default upsellEnum;