IO-3020 IO-3036 Add additional upsell components.

This commit is contained in:
Patrick Fic
2024-12-09 18:47:32 -08:00
parent 962f471f0f
commit c7a2c8209a
28 changed files with 1015 additions and 122 deletions

View File

@@ -59704,6 +59704,152 @@
<folder_node> <folder_node>
<name>messages</name> <name>messages</name>
<children> <children>
<folder_node>
<name>accounting</name>
<children>
<folder_node>
<name>payables</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>payments</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>receivables</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> <folder_node>
<name>audit</name> <name>audit</name>
<children> <children>
@@ -59855,6 +60001,214 @@
</folder_node> </folder_node>
</children> </children>
</folder_node> </folder_node>
<folder_node>
<name>checklist</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>courtesycars</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>csi</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>dashboard</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> <folder_node>
<name>lifecycle</name> <name>lifecycle</name>
<children> <children>
@@ -60007,7 +60361,111 @@
</children> </children>
</folder_node> </folder_node>
<folder_node> <folder_node>
<name>scheduling</name> <name>payments</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>scoreboard</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>smartscheduling</name>
<children> <children>
<folder_node> <folder_node>
<name>datepicker</name> <name>datepicker</name>
@@ -60152,6 +60610,58 @@
</folder_node> </folder_node>
</children> </children>
</folder_node> </folder_node>
<folder_node>
<name>techconsole</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> <folder_node>
<name>timetickets</name> <name>timetickets</name>
<children> <children>
@@ -60251,6 +60761,58 @@
</folder_node> </folder_node>
</children> </children>
</folder_node> </folder_node>
<folder_node>
<name>visualboard</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>
</children> </children>
</folder_node> </folder_node>
</children> </children>

View File

@@ -129,6 +129,7 @@ const featureNameList = [
"media", "media",
"visualboard", "visualboard",
"scoreboard", "scoreboard",
"techconsole",
"checklist", "checklist",
"smartscheduling", "smartscheduling",
"roguard", "roguard",

View File

@@ -1,11 +1,21 @@
import { AppstoreAddOutlined, CalendarOutlined, CarOutlined, MobileOutlined } from "@ant-design/icons"; import {
import { Result, Button, Card } from "antd"; AppstoreAddOutlined,
BuildOutlined,
CalendarOutlined,
CarOutlined,
DashboardOutlined,
DollarOutlined,
LineChartOutlined,
MobileOutlined,
StarOutlined
} from "@ant-design/icons";
import { Button, Card, Result } from "antd";
import i18n from "i18next";
import React, { useEffect, useRef } from "react"; import React, { useEffect, useRef } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import i18n from "i18next";
import "./upsell.styles.scss"; import "./upsell.styles.scss";
export default function UpsellComponent({ featureName, subFeatureName, upsell, disableMask = false }) { export default function UpsellComponent({ featureName, subFeatureName, upsell, disableMask }) {
const { t } = useTranslation(); const { t } = useTranslation();
const resultProps = upsell || upsellEnum[featureName][subFeatureName]; const resultProps = upsell || upsellEnum[featureName][subFeatureName];
const componentRef = useRef(null); const componentRef = useRef(null);
@@ -27,7 +37,9 @@ export default function UpsellComponent({ featureName, subFeatureName, upsell, d
parentElement.prepend(mask); parentElement.prepend(mask);
return () => { return () => {
parentElement.removeChild(mask); if (mask && parentElement.contains(mask)) {
parentElement.removeChild(mask);
}
}; };
} }
}, [disableMask]); }, [disableMask]);
@@ -40,7 +52,7 @@ export default function UpsellComponent({ featureName, subFeatureName, upsell, d
); );
} }
//Kept in the same function as the result props line must mirror and doesnt warrant a separate function. //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 }) { export function UpsellMaskWrapper({ children, upsell, featureName, subFeatureName }) {
const resultProps = upsell || upsellEnum[featureName][subFeatureName]; const resultProps = upsell || upsellEnum[featureName][subFeatureName];
return ( return (
<div className="mask-wrapper"> <div className="mask-wrapper">
@@ -71,6 +83,24 @@ export const upsellEnum = {
//status: null //status: null
} }
}, },
checklist: {
general: {
//icon: null,
title: i18n.t("upsell.messages.checklist.general.title"),
subTitle: i18n.t("upsell.messages.checklist.general.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
//status: null
}
},
payments: {
general: {
//icon: null,
title: i18n.t("upsell.messages.payments.general.title"),
subTitle: i18n.t("upsell.messages.payments.general.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
//status: null
}
},
audit: { audit: {
general: { general: {
//icon: null, //icon: null,
@@ -136,5 +166,73 @@ export const upsellEnum = {
subTitle: i18n.t("upsell.messages.smartscheduling.datepicker.subtitle"), subTitle: i18n.t("upsell.messages.smartscheduling.datepicker.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button> extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
} }
},
accounting: {
payables: {
icon: <DollarOutlined />,
title: i18n.t("upsell.messages.accounting.payables.title"),
subTitle: i18n.t("upsell.messages.accounting.payables.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
},
receivables: {
icon: <DollarOutlined />,
title: i18n.t("upsell.messages.accounting.receivables.title"),
subTitle: i18n.t("upsell.messages.accounting.receivables.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
},
payments: {
icon: <DollarOutlined />,
title: i18n.t("upsell.messages.accounting.payments.title"),
subTitle: i18n.t("upsell.messages.accounting.payments.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
}
},
courtesycars: {
general: {
icon: <CarOutlined />,
title: i18n.t("upsell.messages.courtesycars.general.title"),
subTitle: i18n.t("upsell.messages.courtesycars.general.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
}
},
dashboard: {
general: {
icon: <DashboardOutlined />,
title: i18n.t("upsell.messages.dashboard.general.title"),
subTitle: i18n.t("upsell.messages.dashboard.general.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
}
},
visualboard: {
general: {
icon: <BuildOutlined />,
title: i18n.t("upsell.messages.visualboard.general.title"),
subTitle: i18n.t("upsell.messages.visualboard.general.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
}
},
scoreboard: {
general: {
icon: <LineChartOutlined />,
title: i18n.t("upsell.messages.scoreboard.general.title"),
subTitle: i18n.t("upsell.messages.scoreboard.general.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
}
},
techconsole: {
general: {
icon: <LineChartOutlined />,
title: i18n.t("upsell.messages.techconsole.general.title"),
subTitle: i18n.t("upsell.messages.techconsole.general.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
}
},
csi: {
general: {
icon: <StarOutlined />,
title: i18n.t("upsell.messages.csi.general.title"),
subTitle: i18n.t("upsell.messages.csi.general.subtitle"),
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
}
} }
}; };

View File

@@ -13,6 +13,8 @@ import { selectPartnerVersion } from "../../redux/application/application.select
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
import { Card } from "antd";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -59,11 +61,10 @@ export function AccountingPayablesContainer({ bodyshop, setBreadcrumbs, setSelec
<div> <div>
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="export" featureName="export"
noAuth noauth={
upsellComponent={ <Card>
{ <UpsellComponent upsell={upsellEnum.accounting.payables} />
//TODO:Upsell </Card>
}
} }
> >
<RbacWrapper action="accounting:payables"> <RbacWrapper action="accounting:payables">

View File

@@ -13,6 +13,8 @@ import { checkPartnerStatus } from "../../components/partner-ping/partner-ping.c
import { selectPartnerVersion } from "../../redux/application/application.selectors"; import { selectPartnerVersion } from "../../redux/application/application.selectors";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
import { Card } from "antd";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -57,10 +59,10 @@ export function AccountingPaymentsContainer({ bodyshop, setBreadcrumbs, setSelec
<div> <div>
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="export" featureName="export"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.accounting.payments} />
} </Card>
} }
> >
<RbacWrapper action="accounting:payments"> <RbacWrapper action="accounting:payments">

View File

@@ -13,6 +13,8 @@ import { checkPartnerStatus } from "../../components/partner-ping/partner-ping.c
import { selectPartnerVersion } from "../../redux/application/application.selectors"; import { selectPartnerVersion } from "../../redux/application/application.selectors";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { Card } from "antd";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -62,10 +64,10 @@ export function AccountingReceivablesContainer({ bodyshop, setBreadcrumbs, setSe
<div> <div>
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="export" featureName="export"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.accounting.receivables} />
} </Card>
} }
> >
<RbacWrapper action="accounting:receivables"> <RbacWrapper action="accounting:receivables">

View File

@@ -13,6 +13,8 @@ import BillsPageComponent from "./bills.page.component";
import { pageLimit } from "../../utils/config"; import { pageLimit } from "../../utils/config";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { Card } from "antd";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
@@ -55,10 +57,10 @@ export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="bills" featureName="bills"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.bills.general} />
} </Card>
} }
> >
<RbacWrapper action="bills:list"> <RbacWrapper action="bills:list">

View File

@@ -1,5 +1,5 @@
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Form, notification } from "antd"; import { Card, Form, notification } from "antd";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -13,6 +13,7 @@ import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/appli
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import ContractCreatePageComponent from "./contract-create.page.component"; import ContractCreatePageComponent from "./contract-create.page.component";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -122,10 +123,10 @@ export function ContractCreatePageContainer({ bodyshop, setBreadcrumbs, setSelec
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="courtesycars" featureName="courtesycars"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.courtesycars.general} />
} </Card>
} }
> >
<RbacWrapper action="contracts:create"> <RbacWrapper action="contracts:create">

View File

@@ -1,5 +1,5 @@
import { useMutation, useQuery } from "@apollo/client"; import { useMutation, useQuery } from "@apollo/client";
import { Form, notification } from "antd"; import { Card, Form, notification } from "antd";
import dayjs from "../../utils/day"; import dayjs from "../../utils/day";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -16,6 +16,7 @@ import ContractDetailPageComponent from "./contract-detail.page.component";
import NotFound from "../../components/not-found/not-found.component"; import NotFound from "../../components/not-found/not-found.component";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
@@ -105,15 +106,15 @@ export function ContractDetailPageContainer({ setBreadcrumbs, addRecentItem, set
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;
if (loading) return <LoadingSpinner />; if (loading) return <LoadingSpinner />;
if (!!!data.cccontracts_by_pk) return <NotFound />; if (!data.cccontracts_by_pk) return <NotFound />;
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="courtesycars" featureName="courtesycars"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.courtesycars.general} />
} </Card>
} }
> >
<RbacWrapper action="contracts:detail"> <RbacWrapper action="contracts:detail">

View File

@@ -12,6 +12,8 @@ import ContractsPageComponent from "./contracts.page.component";
import { pageLimit } from "../../utils/config"; import { pageLimit } from "../../utils/config";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { Card } from "antd";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
@@ -58,10 +60,10 @@ export function ContractsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="courtesycars" featureName="courtesycars"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.courtesycars.general} />
} </Card>
} }
> >
<RbacWrapper action="contracts:list"> <RbacWrapper action="contracts:list">

View File

@@ -1,5 +1,5 @@
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Form, notification } from "antd"; import { Card, Form, notification } from "antd";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -12,6 +12,7 @@ import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/appli
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -70,10 +71,10 @@ export function CourtesyCarCreateContainer({ bodyshop, setBreadcrumbs, setSelect
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="courtesycars" featureName="courtesycars"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.courtesycars.general} />
} </Card>
} }
> >
<RbacWrapper action="courtesycar:create"> <RbacWrapper action="courtesycar:create">

View File

@@ -9,6 +9,8 @@ import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/appli
import CourtesyCarsPageComponent from "./courtesy-cars.page.component"; import CourtesyCarsPageComponent from "./courtesy-cars.page.component";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { Card } from "antd";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
@@ -36,10 +38,10 @@ export function CourtesyCarsPageContainer({ setBreadcrumbs, setSelectedHeader })
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="courtesycars" featureName="courtesycars"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.courtesycars.general} />
} </Card>
} }
> >
<RbacWrapper action="courtesycar:list"> <RbacWrapper action="courtesycar:list">

View File

@@ -6,6 +6,8 @@ import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions"; import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { Card } from "antd";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
@@ -34,10 +36,10 @@ export function ExportsLogPageContainer({ setBreadcrumbs, setSelectedHeader }) {
return ( return (
<FeatureWrapper <FeatureWrapper
featureName="dashboard" featureName="dashboard"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.dashboard.general} />
} </Card>
} }
> >
<RbacWrapper action="shop:dashboard"> <RbacWrapper action="shop:dashboard">

View File

@@ -6,6 +6,8 @@ import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/appli
import ExportLogsPage from "./export-logs.page.component"; import ExportLogsPage from "./export-logs.page.component";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { Card } from "antd";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
@@ -34,10 +36,10 @@ export function ExportsLogPageContainer({ setBreadcrumbs, setSelectedHeader }) {
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="export" featureName="export"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.accounting.receivables} />
} </Card>
} }
> >
<RbacWrapper action="accounting:exportlogs"> <RbacWrapper action="accounting:exportlogs">

View File

@@ -13,6 +13,8 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import JobchecklistComponent from "../../components/job-checklist/job-checklist.component"; import JobchecklistComponent from "../../components/job-checklist/job-checklist.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import { Card } from "antd";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
@@ -62,10 +64,10 @@ export function JobsDeliverContainer({ bodyshop, setBreadcrumbs, setSelectedHead
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="checklist" featureName="checklist"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.checklist.general} />
} </Card>
} }
> >
<RbacWrapper action="jobs:deliver"> <RbacWrapper action="jobs:deliver">

View File

@@ -11,9 +11,10 @@ import { QUERY_INTAKE_CHECKLIST } from "../../graphql/bodyshop.queries";
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions"; import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { Result } from "antd"; import { Card, Result } from "antd";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
@@ -66,10 +67,10 @@ export function JobsIntakeContainer({ bodyshop, setBreadcrumbs, setSelectedHeade
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="checklist" featureName="checklist"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.checklist.general} />
} </Card>
} }
> >
<RbacWrapper action="jobs:intake"> <RbacWrapper action="jobs:intake">

View File

@@ -14,6 +14,8 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import { pageLimit } from "../../utils/config"; import { pageLimit } from "../../utils/config";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
import { Card } from "antd";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -60,11 +62,12 @@ export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="payments" featureName="payments"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.payments.general} />
} </Card>
} }
z
> >
<RbacWrapper action="payments:list"> <RbacWrapper action="payments:list">
<PaymentsListPaginated <PaymentsListPaginated

View File

@@ -1,13 +1,15 @@
import { Card } from "antd";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions"; import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import ProductionBoardComponent from "./production-board.component";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import ProductionBoardComponent from "./production-board.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -40,10 +42,10 @@ export function ProductionBoardContainer({ setBreadcrumbs, bodyshop, setSelected
return ( return (
<FeatureWrapper <FeatureWrapper
featureName="visualboard" featureName="visualboard"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.visualboard.general} />
} </Card>
} }
> >
<RbacWrapper action="production:board"> <RbacWrapper action="production:board">

View File

@@ -1,5 +1,5 @@
import Icon, { FieldTimeOutlined } from "@ant-design/icons"; import Icon, { FieldTimeOutlined } from "@ant-design/icons";
import { Tabs } from "antd"; import { Card, Tabs } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -15,6 +15,7 @@ import ScoreboardTimeTickets from "../../components/scoreboard-timetickets/score
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions"; import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
/** /**
* Mapping state to props * Mapping state to props
@@ -68,10 +69,10 @@ export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
return ( return (
<FeatureWrapper <FeatureWrapper
featureName="scoreboard" featureName="scoreboard"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.scoreboard.general} />
} </Card>
} }
> >
<RbacWrapper action="scoreboard:view"> <RbacWrapper action="scoreboard:view">

View File

@@ -2,15 +2,17 @@ import React from "react";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import TimeTicketShift from "../../components/time-ticket-shift/time-ticket-shift.container"; import TimeTicketShift from "../../components/time-ticket-shift/time-ticket-shift.container";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import { Card } from "antd";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
export default function ShiftClock() { export default function ShiftClock() {
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="timetickets" featureName="timetickets"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.dashboard.general} />
} </Card>
} }
> >
<RbacWrapper action="shiftclock:view"> <RbacWrapper action="shiftclock:view">

View File

@@ -1,5 +1,5 @@
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Col, Row } from "antd"; import { Card, Col, Row } from "antd";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -12,6 +12,8 @@ import { QUERY_CSI_RESPONSE_PAGINATED } from "../../graphql/csi.queries";
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions"; import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -50,21 +52,30 @@ export function ShopCsiContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;
return ( return (
<RbacWrapper action="csi:page"> <FeatureWrapperComponent
<Row gutter={16}> featureName="csi"
<Col span={10}> noauth={
<CsiResponseListPaginated <Card>
refetch={refetch} <UpsellComponent upsell={upsellEnum.csi.general} />
loading={loading} </Card>
responses={data ? data.csi : []} }
total={data ? data.csi_aggregate.aggregate.count : 0} >
/> <RbacWrapper action="csi:page">
</Col> <Row gutter={16}>
<Col span={14}> <Col span={10}>
<CsiResponseFormContainer /> <CsiResponseListPaginated
</Col> refetch={refetch}
</Row> loading={loading}
</RbacWrapper> responses={data ? data.csi : []}
total={data ? data.csi_aggregate.aggregate.count : 0}
/>
</Col>
<Col span={14}>
<CsiResponseFormContainer />
</Col>
</Row>
</RbacWrapper>
</FeatureWrapperComponent>
); );
} }

View File

@@ -1,4 +1,4 @@
import { FloatButton, Layout } from "antd"; import { Card, FloatButton, Layout } from "antd";
import React, { lazy, Suspense, useEffect } from "react"; import React, { lazy, Suspense, useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -14,6 +14,7 @@ import UpdateAlert from "../../components/update-alert/update-alert.component";
import { selectTechnician } from "../../redux/tech/tech.selectors"; import { selectTechnician } from "../../redux/tech/tech.selectors";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import "./tech.page.styles.scss"; import "./tech.page.styles.scss";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component.jsx";
const TimeTicketModalContainer = lazy(() => import("../../components/time-ticket-modal/time-ticket-modal.container")); const TimeTicketModalContainer = lazy(() => import("../../components/time-ticket-modal/time-ticket-modal.container"));
const EmailOverlayContainer = lazy(() => import("../../components/email-overlay/email-overlay.container.jsx")); const EmailOverlayContainer = lazy(() => import("../../components/email-overlay/email-overlay.container.jsx"));
@@ -83,11 +84,11 @@ export function TechPage({ technician }) {
} }
> >
<FeatureWrapper <FeatureWrapper
featureName="tech-console" featureName="techconsole"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.techconsole.general} />
} </Card>
} }
> >
<TimeTicketModalContainer /> <TimeTicketModalContainer />

View File

@@ -8,6 +8,8 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import TemporaryDocsComponent from "./temporary-docs.component"; import TemporaryDocsComponent from "./temporary-docs.component";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { Card } from "antd";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -40,10 +42,10 @@ export function TempDocumentsContainer({ setBreadcrumbs, setSelectedHeader }) {
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="media" featureName="media"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.media.general} />
} </Card>
} }
> >
<RbacWrapper action="temporarydocs:view"> <RbacWrapper action="temporarydocs:view">

View File

@@ -1,5 +1,5 @@
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Col, Row, Space } from "antd"; import { Card, Col, Row, Space } from "antd";
import dayjs from "../../utils/day"; import dayjs from "../../utils/day";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -20,6 +20,7 @@ import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wr
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { useSplitTreatments } from "@splitsoftware/splitio-react"; import { useSplitTreatments } from "@splitsoftware/splitio-react";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -75,10 +76,10 @@ export function TimeTicketsContainer({ bodyshop, setBreadcrumbs, setSelectedHead
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="timetickets" featureName="timetickets"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.timetickets.general} />
} </Card>
} }
> >
<RbacWrapper action="timetickets:list"> <RbacWrapper action="timetickets:list">

View File

@@ -8,6 +8,8 @@ import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/appli
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { Card } from "antd";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -40,10 +42,10 @@ export function TtApprovalsPage({ setBreadcrumbs, setSelectedHeader }) {
return ( return (
<FeatureWrapperComponent <FeatureWrapperComponent
featureName="timetickets" featureName="timetickets"
upsellComponent={ noauth={
{ <Card>
//TODO:Upsell <UpsellComponent upsell={upsellEnum.timetickets.general} />
} </Card>
} }
> >
<RbacWrapper action="ttapprovals:view"> <RbacWrapper action="ttapprovals:view">

View File

@@ -3487,6 +3487,20 @@
"learnmore": "Learn More" "learnmore": "Learn More"
}, },
"messages": { "messages": {
"accounting": {
"payables": {
"subtitle": "Effortlessly send your bills and payables to QuickBooks Online or QuickBooks Desktop eliminating the need for duplicate data entry.",
"title": "Eliminate double data entry"
},
"payments": {
"subtitle": "Effortlessly send your bills and payables to QuickBooks Online or QuickBooks Desktop eliminating the need for duplicate data entry.",
"title": "Eliminate double data entry"
},
"receivables": {
"subtitle": "Effortlessly send your invoices to QuickBooks Online or QuickBooks Desktop eliminating the need for duplicate data entry.",
"title": "Eliminate double data entry"
}
},
"audit": { "audit": {
"general": { "general": {
"subtitle": "Know exactly what happened and when through the entire repair process.", "subtitle": "Know exactly what happened and when through the entire repair process.",
@@ -3503,6 +3517,30 @@
"title": "Boost your profits by taking control of costs!" "title": "Boost your profits by taking control of costs!"
} }
}, },
"checklist": {
"general": {
"subtitle": "Standardize your intake and delivery with digitized checklists and SOPs.",
"title": "Done right, the first time."
}
},
"courtesycars": {
"general": {
"subtitle": "Keep track of vehicles and contracts for your courtesy cars, all seamlessly synchronized with your Jobs.",
"title": "Manage your fleet with ease"
}
},
"csi": {
"general": {
"subtitle": "With our integrated CSI module, send follow up surveys to your customers to see how well you did.",
"title": "See what your customers have to say"
}
},
"dashboard": {
"general": {
"subtitle": "Make data based decisions and take control of your business using our real-time dashboard.",
"title": "Realtime Insight & Analytics"
}
},
"lifecycle": { "lifecycle": {
"general": { "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.", "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.",
@@ -3519,7 +3557,19 @@
"title": "Accelerate repair documentation with Mobile" "title": "Accelerate repair documentation with Mobile"
} }
}, },
"scheduling": { "payments": {
"general": {
"subtitle": "Manage outstanding balances and collect payments by credit card from your customers.",
"title": "Integrated Accounts Receivable & Payments"
}
},
"scoreboard": {
"general": {
"subtitle": "Understand hours produced and sold to facilitate employee incentive programs.",
"title": "Give credit where credit is due"
}
},
"smartscheduling": {
"datepicker": { "datepicker": {
"subtitle": "Smart Scsheduling gives you the best dates for a vehicle to come in based on your current and predicted production load.", "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?" "title": "When's the best time for this job to arrive?"
@@ -3533,6 +3583,12 @@
"title": "Cars come and cars go." "title": "Cars come and cars go."
} }
}, },
"techconsole": {
"general": {
"subtitle": "The technician's console allows technicians to see job information, media, documents and keep track of their time.",
"title": "Empower your Technicians"
}
},
"timetickets": { "timetickets": {
"allocations": { "allocations": {
"subtitle": "Ensure your technicians are paid out exactly what they are owed - not a penny less, not a penny more.", "subtitle": "Ensure your technicians are paid out exactly what they are owed - not a penny less, not a penny more.",
@@ -3542,6 +3598,12 @@
"subtitle": "Track your technicians time with precision, giving you insight to repair progress and labor efficiency.", "subtitle": "Track your technicians time with precision, giving you insight to repair progress and labor efficiency.",
"title": "Who did what and for how long?" "title": "Who did what and for how long?"
} }
},
"visualboard": {
"general": {
"subtitle": "The Visual Production Board makes it easier than ever before to manage your work in progress.",
"title": "A whole new kind of production board"
}
} }
} }
}, },

View File

@@ -3487,6 +3487,20 @@
"learnmore": "" "learnmore": ""
}, },
"messages": { "messages": {
"accounting": {
"payables": {
"subtitle": "",
"title": ""
},
"payments": {
"subtitle": "",
"title": ""
},
"receivables": {
"subtitle": "",
"title": ""
}
},
"audit": { "audit": {
"general": { "general": {
"subtitle": "", "subtitle": "",
@@ -3503,6 +3517,30 @@
"title": "" "title": ""
} }
}, },
"checklist": {
"general": {
"subtitle": "",
"title": ""
}
},
"courtesycars": {
"general": {
"subtitle": "",
"title": ""
}
},
"csi": {
"general": {
"subtitle": "",
"title": ""
}
},
"dashboard": {
"general": {
"subtitle": "",
"title": ""
}
},
"lifecycle": { "lifecycle": {
"general": { "general": {
"subtitle": "", "subtitle": "",
@@ -3519,7 +3557,19 @@
"title": "" "title": ""
} }
}, },
"scheduling": { "payments": {
"general": {
"subtitle": "",
"title": ""
}
},
"scoreboard": {
"general": {
"subtitle": "",
"title": ""
}
},
"smartscheduling": {
"datepicker": { "datepicker": {
"subtitle": "", "subtitle": "",
"title": "" "title": ""
@@ -3533,6 +3583,12 @@
"title": "" "title": ""
} }
}, },
"techconsole": {
"general": {
"subtitle": "",
"title": ""
}
},
"timetickets": { "timetickets": {
"allocations": { "allocations": {
"subtitle": "", "subtitle": "",
@@ -3542,6 +3598,12 @@
"subtitle": "", "subtitle": "",
"title": "" "title": ""
} }
},
"visualboard": {
"general": {
"subtitle": "",
"title": ""
}
} }
} }
}, },

View File

@@ -3487,6 +3487,20 @@
"learnmore": "" "learnmore": ""
}, },
"messages": { "messages": {
"accounting": {
"payables": {
"subtitle": "",
"title": ""
},
"payments": {
"subtitle": "",
"title": ""
},
"receivables": {
"subtitle": "",
"title": ""
}
},
"audit": { "audit": {
"general": { "general": {
"subtitle": "", "subtitle": "",
@@ -3503,6 +3517,30 @@
"title": "" "title": ""
} }
}, },
"checklist": {
"general": {
"subtitle": "",
"title": ""
}
},
"courtesycars": {
"general": {
"subtitle": "",
"title": ""
}
},
"csi": {
"general": {
"subtitle": "",
"title": ""
}
},
"dashboard": {
"general": {
"subtitle": "",
"title": ""
}
},
"lifecycle": { "lifecycle": {
"general": { "general": {
"subtitle": "", "subtitle": "",
@@ -3519,7 +3557,19 @@
"title": "" "title": ""
} }
}, },
"scheduling": { "payments": {
"general": {
"subtitle": "",
"title": ""
}
},
"scoreboard": {
"general": {
"subtitle": "",
"title": ""
}
},
"smartscheduling": {
"datepicker": { "datepicker": {
"subtitle": "", "subtitle": "",
"title": "" "title": ""
@@ -3533,6 +3583,12 @@
"title": "" "title": ""
} }
}, },
"techconsole": {
"general": {
"subtitle": "",
"title": ""
}
},
"timetickets": { "timetickets": {
"allocations": { "allocations": {
"subtitle": "", "subtitle": "",
@@ -3542,6 +3598,12 @@
"subtitle": "", "subtitle": "",
"title": "" "title": ""
} }
},
"visualboard": {
"general": {
"subtitle": "",
"title": ""
}
} }
} }
}, },