IO-3020 IO-3036 Add upsell components to several components. Add upsell mask wrapper.
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
<preset_collections/>
|
||||
<framework>react-intl</framework>
|
||||
<filename>bodyshop_translations.babel</filename>
|
||||
<source_root_dir>client</source_root_dir>
|
||||
<source_root_dir>client/src</source_root_dir>
|
||||
<folder_node>
|
||||
<name></name>
|
||||
<children>
|
||||
@@ -40921,6 +40921,27 @@
|
||||
<folder_node>
|
||||
<name>fields</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>accountingid</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>address</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -52328,6 +52349,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>purchase_return_ratio_excel</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>purchase_return_ratio_grouped_by_vendor_detail</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -52853,6 +52895,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_loss_jobs</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>unclaimed_hrs</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -59609,6 +59672,589 @@
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>upsell</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>cta</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>learnmore</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>messages</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>audit</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>general</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>subtitle</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>title</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>bills</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>autoreconcile</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>subtitle</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>title</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>general</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>subtitle</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>title</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>lifecycle</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>general</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>subtitle</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>title</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>media</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>general</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>subtitle</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>title</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>mobile</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>subtitle</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>title</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>scheduling</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>datepicker</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>subtitle</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>title</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>general</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>subtitle</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>title</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>hrsdelta</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>subtitle</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>title</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>timetickets</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>allocations</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>subtitle</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>title</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>general</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>subtitle</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>title</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>user</name>
|
||||
<children>
|
||||
|
||||
@@ -18,7 +18,7 @@ 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";
|
||||
import { upsellEnum } from "../upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
@@ -240,7 +240,7 @@ export function BillsListTableComponent({
|
||||
onChange={handleTableChange}
|
||||
locale={{
|
||||
...(!hasBillsAccess && {
|
||||
emptyText: <UpsellComponent upsell={upsellEnum.bills.table} />
|
||||
emptyText: <UpsellComponent upsell={upsellEnum.bills.general} />
|
||||
})
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Button, Card, Col, Row, Table, Tag } from "antd";
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { QUERY_AUDIT_TRAIL } from "../../graphql/audit_trail.queries";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { QUERY_AUDIT_TRAIL } from "../../graphql/audit_trail.queries";
|
||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser
|
||||
currentUser: selectCurrentUser,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobAuditTrail);
|
||||
|
||||
export function JobAuditTrail({ currentUser, jobId }) {
|
||||
export function JobAuditTrail({ bodyshop, currentUser, jobId }) {
|
||||
const { t } = useTranslation();
|
||||
const { loading, data, refetch } = useQuery(QUERY_AUDIT_TRAIL, {
|
||||
variables: { jobid: jobId },
|
||||
@@ -137,11 +140,17 @@ export function JobAuditTrail({ currentUser, jobId }) {
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const hasAuditAccess = HasFeatureAccess({ bodyshop, featureName: "audit" });
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
{!hasAuditAccess && (
|
||||
<Col span={24}>
|
||||
<Card>
|
||||
<UpsellComponent upsell={upsellEnum.audit.general} disableMask />
|
||||
</Card>
|
||||
</Col>
|
||||
)}
|
||||
<Col span={24}>
|
||||
<Card
|
||||
title={t("jobs.labels.audit")}
|
||||
|
||||
@@ -7,8 +7,21 @@ import AlertComponent from "../alert/alert.component";
|
||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import "./job-bills-total.styles.scss";
|
||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
export default function JobBillsTotalComponent({
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export function JobBillsTotalComponent({
|
||||
bodyshop,
|
||||
loading,
|
||||
bills,
|
||||
partsOrders,
|
||||
@@ -120,10 +133,10 @@ export default function JobBillsTotalComponent({
|
||||
warningCallback({ key: "cm", warning: t("jobs.labels.outstanding_credit_memos") });
|
||||
}
|
||||
}
|
||||
|
||||
const hasBillsAccess = HasFeatureAccess({ bodyshop, featureName: "bills" });
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col md={24} lg={18}>
|
||||
<Col {...(hasBillsAccess ? { md: 24, lg: 18 } : { span: 12 })}>
|
||||
<Card title={t("jobs.labels.jobtotals")} style={{ height: "100%" }}>
|
||||
<Space wrap size="large">
|
||||
<Tooltip
|
||||
@@ -240,9 +253,6 @@ export default function JobBillsTotalComponent({
|
||||
</BlurWrapperComponent>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
{showWarning &&
|
||||
(discrepWithCms.getAmount() !== 0 ||
|
||||
discrepWithLbrAdj.getAmount() !== 0 ||
|
||||
@@ -321,11 +331,17 @@ export default function JobBillsTotalComponent({
|
||||
{showWarning && calculatedCreditsNotReceived.getAmount() > 0 && (
|
||||
<Alert style={{ margin: "8px 0px" }} type="warning" message={t("jobs.labels.outstanding_credit_memos")} />
|
||||
)}
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
</Card>
|
||||
</Col>
|
||||
{!hasBillsAccess && (
|
||||
<Col span={6}>
|
||||
<Card style={{ height: "100%" }}>
|
||||
<UpsellComponent upsell={upsellEnum.bills.autoreconcile} disableMask />
|
||||
</Card>
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobBillsTotalComponent);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Button, Checkbox, Form, notification, Popover, Tooltip } from "antd";
|
||||
import { Button, Form, notification, Popover, Tooltip } from "antd";
|
||||
import axios from "axios";
|
||||
import { t } from "i18next";
|
||||
import React, { useState } from "react";
|
||||
|
||||
@@ -9,6 +9,7 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
import "./job-lifecycle.styles.scss";
|
||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
|
||||
// show text on bar if text can fit
|
||||
export function JobLifecycleComponent({ job, statuses, ...rest }) {
|
||||
@@ -137,9 +138,10 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) {
|
||||
}
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
{" "}
|
||||
<Card type="inner" style={{ marginTop: "10px" }}>
|
||||
<UpsellComponent upsell={upsellEnum.lifecycle.general} />
|
||||
</Card>
|
||||
<BlurWrapperComponent featureName="lifecycle">
|
||||
<div
|
||||
id="bar-container"
|
||||
|
||||
@@ -4,10 +4,9 @@ import AlertComponent from "../alert/alert.component";
|
||||
import BillDetailEditcontainer from "../bill-detail-edit/bill-detail-edit.container";
|
||||
import BillsListTable from "../bills-list-table/bills-list-table.component";
|
||||
import JobBillsTotal from "../job-bills-total/job-bills-total.component";
|
||||
import PartsDispatchTable from "../parts-dispatch-table/parts-dispatch-table.component";
|
||||
import PartsOrderListTableComponent from "../parts-order-list-table/parts-order-list-table.component";
|
||||
import PartsOrderModal from "../parts-order-modal/parts-order-modal.container";
|
||||
import PartsDispatchTable from "../parts-dispatch-table/parts-dispatch-table.component";
|
||||
import FeatureWrapperComponent from "../feature-wrapper/feature-wrapper.component";
|
||||
|
||||
export default function JobsDetailPliComponent({
|
||||
job,
|
||||
|
||||
@@ -18,6 +18,7 @@ import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
@@ -114,7 +115,7 @@ function JobsDocumentsComponent({
|
||||
setgalleryImages(documents);
|
||||
}, [data, setgalleryImages, t]);
|
||||
const hasMediaAccess = HasFeatureAccess({ bodyshop, featureName: "media" });
|
||||
|
||||
const hasMobileAccess = HasFeatureAccess({ bodyshop, featureName: "mobile" });
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={[16, 16]}>
|
||||
@@ -129,9 +130,14 @@ function JobsDocumentsComponent({
|
||||
{!billId && <JobsDocumentsGalleryReassign galleryImages={galleryImages} callback={refetch} />}
|
||||
</Space>
|
||||
</Col>
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
{!hasMediaAccess && (
|
||||
<Col span={24}>
|
||||
<Card>
|
||||
<UpsellComponent upsell={upsellEnum.media.general} />
|
||||
</Card>
|
||||
</Col>
|
||||
)}
|
||||
|
||||
<Col span={24}>
|
||||
<Card>
|
||||
<DocumentsUploadComponent
|
||||
@@ -143,7 +149,13 @@ function JobsDocumentsComponent({
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
{hasMediaAccess && !hasMobileAccess && (
|
||||
<Col span={24}>
|
||||
<Card>
|
||||
<UpsellComponent upsell={upsellEnum.media.mobile} />
|
||||
</Card>
|
||||
</Col>
|
||||
)}
|
||||
<Col span={24}>
|
||||
<Card title={t("jobs.labels.documents-images")}>
|
||||
<Gallery
|
||||
|
||||
@@ -13,7 +13,7 @@ import LaborAllocationsAdjustmentEdit from "../labor-allocations-adjustment-edit
|
||||
import "./labor-allocations-table.styles.scss";
|
||||
import { CalculateAllocationsTotals } from "./labor-allocations-table.utility";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
technician: selectTechnician
|
||||
@@ -205,12 +205,9 @@ export function LaborAllocationsTable({
|
||||
locale={{
|
||||
...(!hasTimeTicketAccess && {
|
||||
emptyText: (
|
||||
<div>
|
||||
Upsell
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
</div>
|
||||
<Card>
|
||||
<UpsellComponent upsell={upsellEnum.timetickets.allocations} />
|
||||
</Card>
|
||||
)
|
||||
})
|
||||
}}
|
||||
@@ -251,12 +248,9 @@ export function LaborAllocationsTable({
|
||||
locale={{
|
||||
...(!hasTimeTicketAccess && {
|
||||
emptyText: (
|
||||
<div>
|
||||
Upsell
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
</div>
|
||||
<Card>
|
||||
<UpsellComponent upsell={upsellEnum.timetickets.allocations} />
|
||||
</Card>
|
||||
)
|
||||
})
|
||||
}}
|
||||
|
||||
@@ -20,14 +20,14 @@ import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import DataLabel from "../data-label/data-label.component";
|
||||
import FeatureWrapperComponent, { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import LockWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
||||
import PartsOrderBackorderEta from "../parts-order-backorder-eta/parts-order-backorder-eta.component";
|
||||
import PartsOrderCmReceived from "../parts-order-cm-received/parts-order-cm-received.component";
|
||||
import PartsOrderDeleteLine from "../parts-order-delete-line/parts-order-delete-line.component";
|
||||
import PartsOrderLineBackorderButton from "../parts-order-line-backorder-button/parts-order-line-backorder-button.component";
|
||||
import PartsReceiveModalContainer from "../parts-receive-modal/parts-receive-modal.container";
|
||||
import PrintWrapper from "../print-wrapper/print-wrapper.component";
|
||||
import LockWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
|
||||
@@ -14,11 +14,11 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import FeatureWrapperComponent, { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import LockWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
||||
import PartsReceiveModalContainer from "../parts-receive-modal/parts-receive-modal.container";
|
||||
import PrintWrapper from "../print-wrapper/print-wrapper.component";
|
||||
import PartsOrderDrawer from "./parts-order-list-table-drawer.component";
|
||||
import LockWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
|
||||
@@ -1,10 +1,3 @@
|
||||
import isBetween from "dayjs/plugin/isBetween";
|
||||
import isSameOrAfter from "dayjs/plugin/isSameOrAfter";
|
||||
import isSameOrBefore from "dayjs/plugin/isSameOrBefore";
|
||||
import localeData from "dayjs/plugin/localeData";
|
||||
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||
import minMax from "dayjs/plugin/minMax";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import { DateLocalizer } from "react-big-calendar";
|
||||
|
||||
function arrayWithHoles(arr) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Legend, PolarAngleAxis, PolarGrid, PolarRadiusAxis, Radar, RadarChart,
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||
import { UpsellMaskWrapper, upsellEnum } from "../upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -47,6 +48,7 @@ export function ScheduleCalendarHeaderGraph({ bodyshop, loadData }) {
|
||||
<strong>{loadData?.expectedJobCount}</strong>
|
||||
</BlurWrapperComponent>
|
||||
</Space>
|
||||
<UpsellMaskWrapper upsell={upsellEnum.smartscheduling.general}>
|
||||
<BlurWrapperComponent featureName="smartscheduling">
|
||||
<RadarChart
|
||||
// cx={300}
|
||||
@@ -65,9 +67,7 @@ export function ScheduleCalendarHeaderGraph({ bodyshop, loadData }) {
|
||||
<Legend />
|
||||
</RadarChart>
|
||||
</BlurWrapperComponent>
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
</UpsellMaskWrapper>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Icon from "@ant-design/icons";
|
||||
import { Popover, Space } from "antd";
|
||||
import { Card, Popover, Space } from "antd";
|
||||
import _ from "lodash";
|
||||
import dayjs from "../../utils/day";
|
||||
|
||||
@@ -12,14 +12,12 @@ import { createStructuredSelector } from "reselect";
|
||||
import { selectScheduleLoad, selectScheduleLoadCalculating } from "../../redux/application/application.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { default as BlurWrapper, default as BlurWrapperComponent } from "../feature-wrapper/blur-wrapper.component";
|
||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
|
||||
import ScheduleCalendarHeaderGraph from "./schedule-calendar-header-graph.component";
|
||||
import InstanceRenderMgr from "../../utils/instanceRenderMgr";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import BlurWrapper from "../feature-wrapper/blur-wrapper.component";
|
||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum, UpsellMaskWrapper } from "../upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -89,11 +87,11 @@ export function ScheduleCalendarHeaderComponent({
|
||||
</BlurWrapperComponent>
|
||||
</tr>
|
||||
)}
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<Card style={{ maxWidth: "30rem" }}>
|
||||
<UpsellComponent size="small" upsell={upsellEnum.smartscheduling.hrsdelta} />
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -131,9 +129,9 @@ export function ScheduleCalendarHeaderComponent({
|
||||
</BlurWrapperComponent>
|
||||
</tr>
|
||||
)}
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
<Card style={{ maxWidth: "30rem" }}>
|
||||
<UpsellComponent size="small" upsell={upsellEnum.smartscheduling.hrsdelta} />
|
||||
</Card>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
import dayjs from "../../utils/day";
|
||||
import { Alert, Collapse, Space } from "antd";
|
||||
import queryString from "query-string";
|
||||
import React from "react";
|
||||
import { Calendar } from "react-big-calendar";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectProblemJobs } from "../../redux/application/application.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import dayjs from "../../utils/day";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import Event from "../job-at-change/schedule-event.container";
|
||||
import JobDetailCards from "../job-detail-cards/job-detail-cards.component";
|
||||
import local from "./localizer";
|
||||
import HeaderComponent from "./schedule-calendar-header.component";
|
||||
import "./schedule-calendar.styles.scss";
|
||||
import JobDetailCards from "../job-detail-cards/job-detail-cards.component";
|
||||
import { selectProblemJobs } from "../../redux/application/application.selectors";
|
||||
import { Alert, Collapse, Space } from "antd";
|
||||
import { Trans, useTranslation } from "react-i18next";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import local from "./localizer";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
|
||||
@@ -17,6 +17,7 @@ import ScheduleExistingAppointmentsList from "../schedule-existing-appointments-
|
||||
import "./schedule-job-modal.scss";
|
||||
import LockWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
||||
import { BlurWrapper } from "../feature-wrapper/blur-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -66,6 +67,8 @@ export function ScheduleJobModalComponent({
|
||||
}
|
||||
};
|
||||
|
||||
const hasSmartSchedulingAccess = HasFeatureAccess({ bodyshop, featureName: "smartscheduling" });
|
||||
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={12}>
|
||||
@@ -110,11 +113,12 @@ export function ScheduleJobModalComponent({
|
||||
{t("appointments.actions.calculate")}
|
||||
</LockWrapperComponent>
|
||||
</Button>
|
||||
|
||||
{smartOptions.map((d, idx) => (
|
||||
<BlurWrapper featureName="smartscheduling" key={idx}>
|
||||
<Button
|
||||
key={idx}
|
||||
className="imex-flex-row__margin"
|
||||
disabled={!HasFeatureAccess({ bodyshop, featureName: "smartscheduling" })}
|
||||
disabled={!hasSmartSchedulingAccess}
|
||||
onClick={() => {
|
||||
const ssDate = dayjs(d);
|
||||
if (ssDate.isBefore(dayjs())) {
|
||||
@@ -127,13 +131,16 @@ export function ScheduleJobModalComponent({
|
||||
handleDateBlur();
|
||||
}}
|
||||
>
|
||||
<BlurWrapper featureName="smartscheduling">
|
||||
<span>
|
||||
<DateFormatter includeDay>{d}</DateFormatter>
|
||||
</Button>
|
||||
</span>
|
||||
</BlurWrapper>
|
||||
</Button>
|
||||
))}
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
{smartOptions.length > 1 && hasSmartSchedulingAccess && (
|
||||
<UpsellComponent upsell={upsellEnum.smartscheduling.general} />
|
||||
)}
|
||||
</Space>
|
||||
</>
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
|
||||
import TimeTicketEnterButton from "../time-ticket-enter-button/time-ticket-enter-button.component";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import LockWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -344,7 +345,6 @@ export function TimeTicketList({
|
||||
<Table.Summary.Cell>{t("general.labels.totals")}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell />
|
||||
<Table.Summary.Cell />
|
||||
<Table.Summary.Cell />
|
||||
<Table.Summary.Cell>{totals.productivehrs.toFixed(1)}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell>{totals.actualhrs.toFixed(1)}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell>
|
||||
@@ -363,12 +363,9 @@ export function TimeTicketList({
|
||||
locale={{
|
||||
...(!hasTimeTicketsAccess && {
|
||||
emptyText: (
|
||||
<div>
|
||||
Upsell
|
||||
{
|
||||
//TODO:Upsell
|
||||
}
|
||||
</div>
|
||||
<Card>
|
||||
<UpsellComponent upsell={upsellEnum.timetickets.general} />
|
||||
</Card>
|
||||
)
|
||||
})
|
||||
}}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { AppstoreAddOutlined } from "@ant-design/icons";
|
||||
import { Result } from "antd";
|
||||
import { AppstoreAddOutlined, CalendarOutlined, CarOutlined, MobileOutlined } from "@ant-design/icons";
|
||||
import { Result, Button, Card } from "antd";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import upsellEnum from "./upsell.enum";
|
||||
import i18n from "i18next";
|
||||
import "./upsell.styles.scss";
|
||||
|
||||
export default function UpsellComponent({ featureName, subFeatureName, upsell, disableMask = false }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -19,16 +20,17 @@ export default function UpsellComponent({ featureName, subFeatureName, upsell, d
|
||||
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;
|
||||
mask.style.backgroundColor = "rgba(0, 0, 0, 0.05)";
|
||||
// mask.style.zIndex = 9999;
|
||||
parentElement.style.position = "relative";
|
||||
parentElement.appendChild(mask);
|
||||
|
||||
parentElement.prepend(mask);
|
||||
|
||||
return () => {
|
||||
parentElement.removeChild(mask);
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
}, [disableMask]);
|
||||
|
||||
if (!resultProps) return <Result status="info" title={t("upsell.messages.generic")} />;
|
||||
return (
|
||||
@@ -37,3 +39,102 @@ export default function UpsellComponent({ featureName, subFeatureName, upsell, d
|
||||
</div>
|
||||
);
|
||||
}
|
||||
//Kept in the same function as the result props line must mirror and doesnt warrant a separate function.
|
||||
export function UpsellMaskWrapper({ children, upsell, featureName, subFeatureName, disableMask = false }) {
|
||||
const resultProps = upsell || upsellEnum[featureName][subFeatureName];
|
||||
return (
|
||||
<div className="mask-wrapper">
|
||||
<div className="mask-content">{children}</div>
|
||||
<div className="mask-overlay">
|
||||
<Card size="small">
|
||||
<Result status="info" icon={<AppstoreAddOutlined />} {...resultProps} />
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
//This is kept in this function as pulling it out into it's own util/enum prevents passing JSX as an `extra` prop
|
||||
export const upsellEnum = {
|
||||
bills: {
|
||||
autoreconcile: {
|
||||
//icon: null,
|
||||
title: i18n.t("upsell.messages.bills.autoreconcile.title"),
|
||||
subTitle: i18n.t("upsell.messages.bills.autoreconcile.subtitle"),
|
||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||
//status: null
|
||||
},
|
||||
general: {
|
||||
//icon: null,
|
||||
title: i18n.t("upsell.messages.bills.general.title"),
|
||||
subTitle: i18n.t("upsell.messages.bills.general.subtitle"),
|
||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||
//status: null
|
||||
}
|
||||
},
|
||||
audit: {
|
||||
general: {
|
||||
//icon: null,
|
||||
title: i18n.t("upsell.messages.audit.general.title"),
|
||||
subTitle: i18n.t("upsell.messages.audit.general.subtitle"),
|
||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||
//status: null
|
||||
}
|
||||
},
|
||||
lifecycle: {
|
||||
general: {
|
||||
//icon: null,
|
||||
title: i18n.t("upsell.messages.lifecycle.general.title"),
|
||||
subTitle: i18n.t("upsell.messages.lifecycle.general.subtitle"),
|
||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||
//status: null }
|
||||
}
|
||||
},
|
||||
media: {
|
||||
general: {
|
||||
//icon: null,
|
||||
title: i18n.t("upsell.messages.media.general.title"),
|
||||
subTitle: i18n.t("upsell.messages.media.general.subtitle"),
|
||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||
//status: null }
|
||||
},
|
||||
mobile: {
|
||||
icon: <MobileOutlined />,
|
||||
title: i18n.t("upsell.messages.media.mobile.title"),
|
||||
subTitle: i18n.t("upsell.messages.media.mobile.subtitle"),
|
||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||
//status: null }
|
||||
}
|
||||
},
|
||||
timetickets: {
|
||||
allocations: {
|
||||
title: i18n.t("upsell.messages.timetickets.allocations.title"),
|
||||
subTitle: i18n.t("upsell.messages.timetickets.allocations.subtitle"),
|
||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||
},
|
||||
general: {
|
||||
title: i18n.t("upsell.messages.timetickets.general.title"),
|
||||
subTitle: i18n.t("upsell.messages.timetickets.general.subtitle"),
|
||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||
}
|
||||
},
|
||||
smartscheduling: {
|
||||
general: {
|
||||
icon: <CalendarOutlined />,
|
||||
title: i18n.t("upsell.messages.smartscheduling.general.title"),
|
||||
subTitle: i18n.t("upsell.messages.smartscheduling.general.subtitle"),
|
||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||
},
|
||||
hrsdelta: {
|
||||
icon: <CarOutlined />,
|
||||
title: i18n.t("upsell.messages.smartscheduling.hrsdelta.title"),
|
||||
subTitle: i18n.t("upsell.messages.smartscheduling.hrsdelta.subtitle"),
|
||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||
},
|
||||
datepicker: {
|
||||
icon: <CarOutlined />,
|
||||
title: i18n.t("upsell.messages.smartscheduling.datepicker.title"),
|
||||
subTitle: i18n.t("upsell.messages.smartscheduling.datepicker.subtitle"),
|
||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
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;
|
||||
56
client/src/components/upsell/upsell.styles.scss
Normal file
56
client/src/components/upsell/upsell.styles.scss
Normal file
@@ -0,0 +1,56 @@
|
||||
.mask-wrapper {
|
||||
position: relative;
|
||||
//Newly added
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100px; /* Adjust as needed */
|
||||
}
|
||||
|
||||
.mask-content {
|
||||
// filter: blur(5px);
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
pointer-events: none;
|
||||
|
||||
//Newly added
|
||||
//width: 100%;
|
||||
}
|
||||
|
||||
.mask-overlay {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 10;
|
||||
// width: 100%
|
||||
}
|
||||
|
||||
.mask-overlay .ant-card {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
// .mask-wrapper {
|
||||
// position: relative;
|
||||
// display: inline-block;
|
||||
// }
|
||||
|
||||
// .mask-content {
|
||||
// filter: blur(5px);
|
||||
// pointer-events: none;
|
||||
// }
|
||||
|
||||
// .mask-overlay {
|
||||
// position: absolute;
|
||||
// top: 0;
|
||||
// left: 0;
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
// z-index: 10;
|
||||
// }
|
||||
|
||||
// .mask-overlay .ant-card {
|
||||
// max-width: 100%;
|
||||
// }
|
||||
@@ -3482,6 +3482,69 @@
|
||||
"calculate": "Calculate"
|
||||
}
|
||||
},
|
||||
"upsell": {
|
||||
"cta": {
|
||||
"learnmore": "Learn More"
|
||||
},
|
||||
"messages": {
|
||||
"audit": {
|
||||
"general": {
|
||||
"subtitle": "Know exactly what happened and when through the entire repair process.",
|
||||
"title": "Comprehensive Audit Trails"
|
||||
}
|
||||
},
|
||||
"bills": {
|
||||
"autoreconcile": {
|
||||
"subtitle": "Let your management system do the tedious work - take advantage of automatic job reconciliation today.",
|
||||
"title": "Did you account for every invoice?"
|
||||
},
|
||||
"general": {
|
||||
"subtitle": "Our Bills module allows you to precisely account for every penny on the repair order to ensure you maximize your bottom line.",
|
||||
"title": "Boost your profits by taking control of costs!"
|
||||
}
|
||||
},
|
||||
"lifecycle": {
|
||||
"general": {
|
||||
"subtitle": "Job life cycles tell you exactly how long the job stayed in each stage of the repair process to identify bottle necks and inefficiencies.",
|
||||
"title": "Are your repair KPIs suffering?"
|
||||
}
|
||||
},
|
||||
"media": {
|
||||
"general": {
|
||||
"subtitle": "Store your vehicle repair documentation, invoices, and related documents digitally to access them anywhere, any time.",
|
||||
"title": "Go paperless."
|
||||
},
|
||||
"mobile": {
|
||||
"subtitle": "Use our mobile app to attach images from your device to the job, increasing your efficiency.",
|
||||
"title": "Accelerate repair documentation with Mobile"
|
||||
}
|
||||
},
|
||||
"scheduling": {
|
||||
"datepicker": {
|
||||
"subtitle": "Smart Scsheduling gives you the best dates for a vehicle to come in based on your current and predicted production load.",
|
||||
"title": "When's the best time for this job to arrive?"
|
||||
},
|
||||
"general": {
|
||||
"subtitle": "Know exactly how busy you will be tomorrow, the day after, or next week to know exactly when to schedule your next repair.",
|
||||
"title": "Forecast your production with Smart Scheduling"
|
||||
},
|
||||
"hrsdelta": {
|
||||
"subtitle": "Understand changes to your Work in Progress and production load instantly.",
|
||||
"title": "Cars come and cars go."
|
||||
}
|
||||
},
|
||||
"timetickets": {
|
||||
"allocations": {
|
||||
"subtitle": "Ensure your technicians are paid out exactly what they are owed - not a penny less, not a penny more.",
|
||||
"title": "Technician Payments Done Just Right"
|
||||
},
|
||||
"general": {
|
||||
"subtitle": "Track your technicians time with precision, giving you insight to repair progress and labor efficiency.",
|
||||
"title": "Who did what and for how long?"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"actions": {
|
||||
"changepassword": "Change Password",
|
||||
|
||||
@@ -3482,6 +3482,69 @@
|
||||
"calculate": ""
|
||||
}
|
||||
},
|
||||
"upsell": {
|
||||
"cta": {
|
||||
"learnmore": ""
|
||||
},
|
||||
"messages": {
|
||||
"audit": {
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"bills": {
|
||||
"autoreconcile": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
},
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"lifecycle": {
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"media": {
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
},
|
||||
"mobile": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"scheduling": {
|
||||
"datepicker": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
},
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
},
|
||||
"hrsdelta": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"timetickets": {
|
||||
"allocations": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
},
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"actions": {
|
||||
"changepassword": "",
|
||||
|
||||
@@ -3482,6 +3482,69 @@
|
||||
"calculate": ""
|
||||
}
|
||||
},
|
||||
"upsell": {
|
||||
"cta": {
|
||||
"learnmore": ""
|
||||
},
|
||||
"messages": {
|
||||
"audit": {
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"bills": {
|
||||
"autoreconcile": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
},
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"lifecycle": {
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"media": {
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
},
|
||||
"mobile": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"scheduling": {
|
||||
"datepicker": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
},
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
},
|
||||
"hrsdelta": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"timetickets": {
|
||||
"allocations": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
},
|
||||
"general": {
|
||||
"subtitle": "",
|
||||
"title": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"actions": {
|
||||
"changepassword": "",
|
||||
|
||||
@@ -18,6 +18,7 @@ i18n
|
||||
.use(initReactI18next)
|
||||
.init(
|
||||
{
|
||||
ns: ["translation"],
|
||||
resources,
|
||||
//lng: "en",
|
||||
detection: {},
|
||||
|
||||
3931
package-lock.json
generated
3931
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user