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}`)} - + {groupExcludeKeyFilter.find((g) => g.key === key) ? ( + g.key === key).featureName} + > +
    + {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;