Merge branch 'release/AIO/2024-05-10' into test-AIO

This commit is contained in:
Patrick Fic
2024-05-08 15:16:55 -07:00
6 changed files with 837 additions and 815 deletions

View File

@@ -13,6 +13,7 @@ import PhoneFormItem, { PhoneItemFormatterValidation } from "../form-items-forma
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component"; import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import FeatureWrapper, { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
// TODO: Client Update, this might break // TODO: Client Update, this might break
const timeZonesList = Intl.supportedValuesOf("timeZone"); const timeZonesList = Intl.supportedValuesOf("timeZone");
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
@@ -144,285 +145,289 @@ export function ShopInfoGeneral({ form, bodyshop }) {
<InputNumber min={0} /> <InputNumber min={0} />
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow header={t("bodyshop.labels.accountingsetup")} id="accountingsetup"> <FeatureWrapper featureName="export" noauth={() => null}>
<Form.Item label={t("bodyshop.labels.qbo")} valuePropName="checked" name={["accountingconfig", "qbo"]}> <LayoutFormRow header={t("bodyshop.labels.accountingsetup")} id="accountingsetup">
<Switch /> <Form.Item label={t("bodyshop.labels.qbo")} valuePropName="checked" name={["accountingconfig", "qbo"]}>
</Form.Item> <Switch />
{InstanceRenderManager({ </Form.Item>
imex: ( {InstanceRenderManager({
<Form.Item shouldUpdate noStyle> imex: (
{() => ( <Form.Item shouldUpdate noStyle>
{() => (
<Form.Item
label={t("bodyshop.labels.qbo_usa")}
shouldUpdate
valuePropName="checked"
name={["accountingconfig", "qbo_usa"]}
>
<Switch disabled={!form.getFieldValue(["accountingconfig", "qbo"])} />
</Form.Item>
)}
</Form.Item>
)
})}
<Form.Item label={t("bodyshop.labels.qbo_departmentid")} name={["accountingconfig", "qbo_departmentid"]}>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.labels.accountingtiers")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["accountingconfig", "tiers"]}
>
<Radio.Group>
<Radio value={2}>2</Radio>
<Radio value={3}>3</Radio>
</Radio.Group>
</Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item <Form.Item
label={t("bodyshop.labels.qbo_usa")} label={t("bodyshop.labels.2tiersetup")}
shouldUpdate shouldUpdate
valuePropName="checked" rules={[
name={["accountingconfig", "qbo_usa"]} {
required: form.getFieldValue(["accountingconfig", "tiers"]) === 2
//message: t("general.validation.required"),
}
]}
name={["accountingconfig", "twotierpref"]}
> >
<Switch disabled={!form.getFieldValue(["accountingconfig", "qbo"])} /> <Radio.Group disabled={form.getFieldValue(["accountingconfig", "tiers"]) === 3}>
<Radio value="name">{t("bodyshop.labels.2tiername")}</Radio>
<Radio value="source">{t("bodyshop.labels.2tiersource")}</Radio>
</Radio.Group>
</Form.Item> </Form.Item>
)} );
</Form.Item> }}
) </Form.Item>
})} <Form.Item
<Form.Item label={t("bodyshop.labels.qbo_departmentid")} name={["accountingconfig", "qbo_departmentid"]}> label={t("bodyshop.labels.printlater")}
<Input /> valuePropName="checked"
</Form.Item> name={["accountingconfig", "printlater"]}
<Form.Item >
label={t("bodyshop.labels.accountingtiers")} <Switch />
rules={[ </Form.Item>
{ <Form.Item
required: true label={t("bodyshop.labels.emaillater")}
//message: t("general.validation.required"), valuePropName="checked"
} name={["accountingconfig", "emaillater"]}
]} >
name={["accountingconfig", "tiers"]} <Switch />
> </Form.Item>
<Radio.Group> <Form.Item
<Radio value={2}>2</Radio> label={t("bodyshop.fields.inhousevendorid")}
<Radio value={3}>3</Radio> name={"inhousevendorid"}
</Radio.Group> rules={[
</Form.Item> {
<Form.Item shouldUpdate> required: true
{() => { //message: t("general.validation.required"),
return ( }
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.default_adjustment_rate")}
name={"default_adjustment_rate"}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} precision={2} />
</Form.Item>
{InstanceRenderManager({
imex: (
<Form.Item label={t("bodyshop.fields.federal_tax_id")} name="federal_tax_id">
<Input />
</Form.Item>
)
})}
<Form.Item label={t("bodyshop.fields.state_tax_id")} name="state_tax_id">
<Input />
</Form.Item>
{InstanceRenderManager({
imex: (
<Form.Item <Form.Item
label={t("bodyshop.labels.2tiersetup")} label={t("bodyshop.fields.invoice_federal_tax_rate")}
shouldUpdate name={["bill_tax_rates", "federal_tax_rate"]}
rules={[ rules={[
{ {
required: form.getFieldValue(["accountingconfig", "tiers"]) === 2 required: true
//message: t("general.validation.required"), //message: t("general.validation.required"),
} }
]} ]}
name={["accountingconfig", "twotierpref"]}
> >
<Radio.Group disabled={form.getFieldValue(["accountingconfig", "tiers"]) === 3}> <InputNumber />
<Radio value="name">{t("bodyshop.labels.2tiername")}</Radio>
<Radio value="source">{t("bodyshop.labels.2tiersource")}</Radio>
</Radio.Group>
</Form.Item> </Form.Item>
); )
}} })}
</Form.Item> <Form.Item
<Form.Item label={t("bodyshop.fields.invoice_state_tax_rate")}
label={t("bodyshop.labels.printlater")} name={["bill_tax_rates", "state_tax_rate"]}
valuePropName="checked" rules={[
name={["accountingconfig", "printlater"]} {
> required: true
<Switch /> //message: t("general.validation.required"),
</Form.Item> }
<Form.Item ]}
label={t("bodyshop.labels.emaillater")} >
valuePropName="checked" <InputNumber />
name={["accountingconfig", "emaillater"]} </Form.Item>
> <Form.Item
<Switch /> label={t("bodyshop.fields.invoice_local_tax_rate")}
</Form.Item> name={["bill_tax_rates", "local_tax_rate"]}
<Form.Item rules={[
label={t("bodyshop.fields.inhousevendorid")} {
name={"inhousevendorid"} required: true
rules={[ //message: t("general.validation.required"),
{ }
required: true ]}
//message: t("general.validation.required"), >
} <InputNumber />
]} </Form.Item>
> <Form.Item
<Input /> name={["md_payment_types"]}
</Form.Item> label={t("bodyshop.fields.md_payment_types")}
<Form.Item rules={[
label={t("bodyshop.fields.default_adjustment_rate")} {
name={"default_adjustment_rate"} required: true,
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} precision={2} />
</Form.Item>
{InstanceRenderManager({
imex: (
<Form.Item label={t("bodyshop.fields.federal_tax_id")} name="federal_tax_id">
<Input />
</Form.Item>
)
})}
<Form.Item label={t("bodyshop.fields.state_tax_id")} name="state_tax_id">
<Input />
</Form.Item>
{InstanceRenderManager({
imex: (
<Form.Item
label={t("bodyshop.fields.invoice_federal_tax_rate")}
name={["bill_tax_rates", "federal_tax_rate"]}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<InputNumber />
</Form.Item>
)
})}
<Form.Item
label={t("bodyshop.fields.invoice_state_tax_rate")}
name={["bill_tax_rates", "state_tax_rate"]}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.invoice_local_tax_rate")}
name={["bill_tax_rates", "local_tax_rate"]}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<InputNumber />
</Form.Item>
<Form.Item
name={["md_payment_types"]}
label={t("bodyshop.fields.md_payment_types")}
rules={[
{
required: true,
//message: t("general.validation.required"),
type: "array"
}
]}
>
<Select mode="tags" />
</Form.Item>
<Form.Item
name={["md_categories"]}
label={t("bodyshop.fields.md_categories")}
rules={[
{
//message: t("general.validation.required"),
type: "array"
}
]}
>
<Select mode="tags" />
</Form.Item>
<Form.Item name={["enforce_class"]} label={t("bodyshop.fields.enforce_class")} valuePropName="checked">
<Switch />
</Form.Item>
<Form.Item
name={["accountingconfig", "ReceivableCustomField1"]}
label={t("bodyshop.fields.ReceivableCustomField", { number: 1 })}
>
{ReceivableCustomFieldSelect}
</Form.Item>
<Form.Item
name={["accountingconfig", "ReceivableCustomField2"]}
label={t("bodyshop.fields.ReceivableCustomField", { number: 2 })}
>
{ReceivableCustomFieldSelect}
</Form.Item>
<Form.Item
name={["accountingconfig", "ReceivableCustomField3"]}
label={t("bodyshop.fields.ReceivableCustomField", { number: 3 })}
>
{ReceivableCustomFieldSelect}
</Form.Item>
<Form.Item
name={["md_classes"]}
label={t("bodyshop.fields.md_classes")}
rules={[
({ getFieldValue }) => {
return {
required: getFieldValue("enforce_class"),
//message: t("general.validation.required"), //message: t("general.validation.required"),
type: "array" type: "array"
}; }
} ]}
]} >
> <Select mode="tags" />
<Select mode="tags" /> </Form.Item>
</Form.Item> <Form.Item
{ClosingPeriod.treatment === "on" && ( name={["md_categories"]}
<> label={t("bodyshop.fields.md_categories")}
<Form.Item rules={[
name={["accountingconfig", "ClosingPeriod"]} {
label={t("bodyshop.fields.closingperiod")} //{t("reportcenter.labels.dates")} //message: t("general.validation.required"),
> type: "array"
<DatePicker.RangePicker format="MM/DD/YYYY" presets={DatePickerRanges} /> }
</Form.Item> ]}
</> >
)} <Select mode="tags" />
</LayoutFormRow> </Form.Item>
<LayoutFormRow header={t("bodyshop.labels.scoreboardsetup")} id="scoreboardsetup"> <Form.Item name={["enforce_class"]} label={t("bodyshop.fields.enforce_class")} valuePropName="checked">
<Form.Item <Switch />
label={t("bodyshop.fields.dailypainttarget")} </Form.Item>
name={["scoreboard_target", "dailyPaintTarget"]} <Form.Item
rules={[ name={["accountingconfig", "ReceivableCustomField1"]}
{ label={t("bodyshop.fields.ReceivableCustomField", { number: 1 })}
required: true >
//message: t("general.validation.required"), {ReceivableCustomFieldSelect}
} </Form.Item>
]} <Form.Item
> name={["accountingconfig", "ReceivableCustomField2"]}
<InputNumber min={0} precision={0} /> label={t("bodyshop.fields.ReceivableCustomField", { number: 2 })}
</Form.Item> >
{ReceivableCustomFieldSelect}
</Form.Item>
<Form.Item
name={["accountingconfig", "ReceivableCustomField3"]}
label={t("bodyshop.fields.ReceivableCustomField", { number: 3 })}
>
{ReceivableCustomFieldSelect}
</Form.Item>
<Form.Item
name={["md_classes"]}
label={t("bodyshop.fields.md_classes")}
rules={[
({ getFieldValue }) => {
return {
required: getFieldValue("enforce_class"),
//message: t("general.validation.required"),
type: "array"
};
}
]}
>
<Select mode="tags" />
</Form.Item>
{ClosingPeriod.treatment === "on" && (
<>
<Form.Item
name={["accountingconfig", "ClosingPeriod"]}
label={t("bodyshop.fields.closingperiod")} //{t("reportcenter.labels.dates")}
>
<DatePicker.RangePicker format="MM/DD/YYYY" presets={DatePickerRanges} />
</Form.Item>
</>
)}
</LayoutFormRow>
</FeatureWrapper>
<FeatureWrapper featureName="scoreboard" noauth={() => null}>
<LayoutFormRow header={t("bodyshop.labels.scoreboardsetup")} id="scoreboardsetup">
<Form.Item
label={t("bodyshop.fields.dailypainttarget")}
name={["scoreboard_target", "dailyPaintTarget"]}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} precision={0} />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.dailybodytarget")} label={t("bodyshop.fields.dailybodytarget")}
name={["scoreboard_target", "dailyBodyTarget"]} name={["scoreboard_target", "dailyBodyTarget"]}
rules={[ rules={[
{ {
required: true required: true
//message: t("general.validation.required"), //message: t("general.validation.required"),
} }
]} ]}
> >
<InputNumber min={0} precision={0} /> <InputNumber min={0} precision={0} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.lastnumberworkingdays")} label={t("bodyshop.fields.lastnumberworkingdays")}
name={["scoreboard_target", "lastNumberWorkingDays"]} name={["scoreboard_target", "lastNumberWorkingDays"]}
rules={[ rules={[
{ {
required: true required: true
//message: t("general.validation.required"), //message: t("general.validation.required"),
} }
]} ]}
> >
<InputNumber min={0} max={12} precision={0} /> <InputNumber min={0} max={12} precision={0} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.ignoreblockeddays")} label={t("bodyshop.fields.ignoreblockeddays")}
name={["scoreboard_target", "ignoreblockeddays"]} name={["scoreboard_target", "ignoreblockeddays"]}
valuePropName="checked" valuePropName="checked"
> >
<Switch /> <Switch />
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.prodtargethrs")} label={t("bodyshop.fields.prodtargethrs")}
name={["prodtargethrs"]} name={["prodtargethrs"]}
rules={[ rules={[
{ {
required: true required: true
//message: t("general.validation.required"), //message: t("general.validation.required"),
} }
]} ]}
> >
<InputNumber min={1} precision={1} /> <InputNumber min={1} precision={1} />
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
</FeatureWrapper>
<LayoutFormRow header={t("bodyshop.labels.systemsettings")} id="systemsettings"> <LayoutFormRow header={t("bodyshop.labels.systemsettings")} id="systemsettings">
<Form.Item <Form.Item
name={["md_referral_sources"]} name={["md_referral_sources"]}
@@ -567,27 +572,32 @@ export function ShopInfoGeneral({ form, bodyshop }) {
> >
<Select mode="tags" /> <Select mode="tags" />
</Form.Item> </Form.Item>
<Form.Item
name={["tt_allow_post_to_invoiced"]} {HasFeatureAccess({ featureName: "timetickets", bodyshop }) && (
label={t("bodyshop.fields.tt_allow_post_to_invoiced")} <>
valuePropName="checked" <Form.Item
> name={["tt_allow_post_to_invoiced"]}
<Switch /> label={t("bodyshop.fields.tt_allow_post_to_invoiced")}
</Form.Item> valuePropName="checked"
<Form.Item >
name={["tt_enforce_hours_for_tech_console"]} <Switch />
label={t("bodyshop.fields.tt_enforce_hours_for_tech_console")} </Form.Item>
valuePropName="checked" <Form.Item
> name={["tt_enforce_hours_for_tech_console"]}
<Switch /> label={t("bodyshop.fields.tt_enforce_hours_for_tech_console")}
</Form.Item> valuePropName="checked"
<Form.Item >
name={["bill_allow_post_to_closed"]} <Switch />
label={t("bodyshop.fields.bill_allow_post_to_closed")} </Form.Item>
valuePropName="checked" <Form.Item
> name={["bill_allow_post_to_closed"]}
<Switch /> label={t("bodyshop.fields.bill_allow_post_to_closed")}
</Form.Item> valuePropName="checked"
>
<Switch />
</Form.Item>
</>
)}
<Form.Item <Form.Item
name={["md_ded_notes"]} name={["md_ded_notes"]}
label={t("bodyshop.fields.md_ded_notes")} label={t("bodyshop.fields.md_ded_notes")}
@@ -1042,111 +1052,118 @@ export function ShopInfoGeneral({ form, bodyshop }) {
}} }}
</Form.List> </Form.List>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow grow header={t("bodyshop.fields.md_ccc_rates")} id="md_ccc_rates"> <FeatureWrapper featureName="courtesycars" noauth={() => null}>
<Form.List name={["md_ccc_rates"]}> <LayoutFormRow grow header={t("bodyshop.fields.md_ccc_rates")} id="md_ccc_rates">
{(fields, { add, remove, move }) => { <Form.List name={["md_ccc_rates"]}>
return ( {(fields, { add, remove, move }) => {
<div> return (
{fields.map((field, index) => ( <div>
<Form.Item key={field.key}> {fields.map((field, index) => (
<LayoutFormRow noDivider> <Form.Item key={field.key}>
<Form.Item label={t("general.labels.label")} key={`${index}label`} name={[field.name, "label"]}> <LayoutFormRow noDivider>
<Input /> <Form.Item label={t("general.labels.label")} key={`${index}label`} name={[field.name, "label"]}>
</Form.Item> <Input />
<Form.Item label={t("contracts.fields.actax")} key={`${index}actax`} name={[field.name, "actax"]}> </Form.Item>
<InputNumber precision={2} /> <Form.Item
</Form.Item> label={t("contracts.fields.actax")}
<Form.Item key={`${index}actax`}
label={t("contracts.fields.dailyfreekm")} name={[field.name, "actax"]}
key={`${index}dailyfreekm`} >
name={[field.name, "dailyfreekm"]} <InputNumber precision={2} />
> </Form.Item>
<InputNumber precision={2} /> <Form.Item
</Form.Item> label={t("contracts.fields.dailyfreekm")}
<Form.Item key={`${index}dailyfreekm`}
label={t("contracts.fields.refuelcharge")} name={[field.name, "dailyfreekm"]}
key={`${index}refuelcharge`} >
name={[field.name, "refuelcharge"]} <InputNumber precision={2} />
> </Form.Item>
<InputNumber precision={2} /> <Form.Item
</Form.Item> label={t("contracts.fields.refuelcharge")}
<Form.Item key={`${index}refuelcharge`}
label={t("contracts.fields.excesskmrate")} name={[field.name, "refuelcharge"]}
key={`${index}excesskmrate`} >
name={[field.name, "excesskmrate"]} <InputNumber precision={2} />
> </Form.Item>
<InputNumber precision={2} /> <Form.Item
</Form.Item> label={t("contracts.fields.excesskmrate")}
<Form.Item key={`${index}excesskmrate`}
label={t("contracts.fields.cleanupcharge")} name={[field.name, "excesskmrate"]}
key={`${index}cleanupcharge`} >
name={[field.name, "cleanupcharge"]} <InputNumber precision={2} />
> </Form.Item>
<InputNumber precision={2} /> <Form.Item
</Form.Item> label={t("contracts.fields.cleanupcharge")}
<Form.Item key={`${index}cleanupcharge`}
label={t("contracts.fields.damagewaiver")} name={[field.name, "cleanupcharge"]}
key={`${index}damagewaiver`} >
name={[field.name, "damagewaiver"]} <InputNumber precision={2} />
> </Form.Item>
<InputNumber precision={2} /> <Form.Item
</Form.Item> label={t("contracts.fields.damagewaiver")}
<Form.Item key={`${index}damagewaiver`}
label={t("contracts.fields.federaltax")} name={[field.name, "damagewaiver"]}
key={`${index}federaltax`} >
name={[field.name, "federaltax"]} <InputNumber precision={2} />
> </Form.Item>
<InputNumber precision={2} /> <Form.Item
</Form.Item> label={t("contracts.fields.federaltax")}
<Form.Item key={`${index}federaltax`}
label={t("contracts.fields.statetax")} name={[field.name, "federaltax"]}
key={`${index}statetax`} >
name={[field.name, "statetax"]} <InputNumber precision={2} />
> </Form.Item>
<InputNumber precision={2} /> <Form.Item
</Form.Item> label={t("contracts.fields.statetax")}
<Form.Item key={`${index}statetax`}
label={t("contracts.fields.localtax")} name={[field.name, "statetax"]}
key={`${index}localtax`} >
name={[field.name, "localtax"]} <InputNumber precision={2} />
> </Form.Item>
<InputNumber precision={2} /> <Form.Item
</Form.Item> label={t("contracts.fields.localtax")}
<Form.Item key={`${index}localtax`}
label={t("contracts.fields.coverage")} name={[field.name, "localtax"]}
key={`${index}coverage`} >
name={[field.name, "coverage"]} <InputNumber precision={2} />
> </Form.Item>
<InputNumber precision={2} /> <Form.Item
</Form.Item> label={t("contracts.fields.coverage")}
key={`${index}coverage`}
name={[field.name, "coverage"]}
>
<InputNumber precision={2} />
</Form.Item>
<Space wrap> <Space wrap>
<DeleteFilled <DeleteFilled
onClick={() => { onClick={() => {
remove(field.name); remove(field.name);
}} }}
/> />
<FormListMoveArrows move={move} index={index} total={fields.length} /> <FormListMoveArrows move={move} index={index} total={fields.length} />
</Space> </Space>
</LayoutFormRow> </LayoutFormRow>
</Form.Item>
))}
<Form.Item>
<Button
type="dashed"
onClick={() => {
add();
}}
style={{ width: "100%" }}
>
{t("general.actions.add")}
</Button>
</Form.Item> </Form.Item>
))} </div>
<Form.Item> );
<Button }}
type="dashed" </Form.List>
onClick={() => { </LayoutFormRow>
add(); </FeatureWrapper>
}}
style={{ width: "100%" }}
>
{t("general.actions.add")}
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
</LayoutFormRow>
<LayoutFormRow grow header={t("bodyshop.fields.md_jobline_presets")} id="md_jobline_presets"> <LayoutFormRow grow header={t("bodyshop.fields.md_jobline_presets")} id="md_jobline_presets">
<Form.List name={["md_jobline_presets"]}> <Form.List name={["md_jobline_presets"]}>
{(fields, { add, remove, move }) => { {(fields, { add, remove, move }) => {

View File

@@ -1,12 +1,13 @@
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import { Form, InputNumber } from "antd"; import { Form, InputNumber } from "antd";
import React from "react"; import React 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 { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -29,210 +30,227 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
return ( return (
<RbacWrapper action="shop:rbac"> <RbacWrapper action="shop:rbac">
<LayoutFormRow> <LayoutFormRow>
<Form.Item {HasFeatureAccess({ featureName: "export", bodyshop }) && (
label={t("bodyshop.fields.rbac.accounting.exportlog")} <>
rules={[ <Form.Item
{ label={t("bodyshop.fields.rbac.accounting.exportlog")}
required: true rules={[
//message: t("general.validation.required"), {
} required: true
]} //message: t("general.validation.required"),
name={["md_rbac", "accounting:exportlog"]} }
> ]}
<InputNumber /> name={["md_rbac", "accounting:exportlog"]}
</Form.Item> >
<Form.Item <InputNumber />
label={t("bodyshop.fields.rbac.accounting.payables")} </Form.Item>
rules={[ <Form.Item
{ label={t("bodyshop.fields.rbac.accounting.payables")}
required: true rules={[
//message: t("general.validation.required"), {
} required: true
]} //message: t("general.validation.required"),
name={["md_rbac", "accounting:payables"]} }
> ]}
<InputNumber /> name={["md_rbac", "accounting:payables"]}
</Form.Item> >
<Form.Item <InputNumber />
label={t("bodyshop.fields.rbac.accounting.payments")} </Form.Item>
rules={[ <Form.Item
{ label={t("bodyshop.fields.rbac.accounting.payments")}
required: true rules={[
//message: t("general.validation.required"), {
} required: true
]} //message: t("general.validation.required"),
name={["md_rbac", "accounting:payments"]} }
> ]}
<InputNumber /> name={["md_rbac", "accounting:payments"]}
</Form.Item> >
<Form.Item <InputNumber />
label={t("bodyshop.fields.rbac.accounting.receivables")} </Form.Item>
rules={[ <Form.Item
{ label={t("bodyshop.fields.rbac.accounting.receivables")}
required: true rules={[
//message: t("general.validation.required"), {
} required: true
]} //message: t("general.validation.required"),
name={["md_rbac", "accounting:receivables"]} }
> ]}
<InputNumber /> name={["md_rbac", "accounting:receivables"]}
</Form.Item> >
<Form.Item <InputNumber />
label={t("bodyshop.fields.rbac.bills.delete")} </Form.Item>
rules={[ </>
{ )}
required: true {HasFeatureAccess({ featureName: "bills", bodyshop }) && (
//message: t("general.validation.required"), <>
} <Form.Item
]} label={t("bodyshop.fields.rbac.bills.delete")}
name={["md_rbac", "bills:delete"]} rules={[
> {
<InputNumber /> required: true
</Form.Item> //message: t("general.validation.required"),
<Form.Item }
label={t("bodyshop.fields.rbac.bills.enter")} ]}
rules={[ name={["md_rbac", "bills:delete"]}
{ >
required: true <InputNumber />
//message: t("general.validation.required"), </Form.Item>
} <Form.Item
]} label={t("bodyshop.fields.rbac.bills.enter")}
name={["md_rbac", "bills:enter"]} rules={[
> {
<InputNumber /> required: true
</Form.Item> //message: t("general.validation.required"),
<Form.Item }
label={t("bodyshop.fields.rbac.bills.list")} ]}
rules={[ name={["md_rbac", "bills:enter"]}
{ >
required: true <InputNumber />
//message: t("general.validation.required"), </Form.Item>
} <Form.Item
]} label={t("bodyshop.fields.rbac.bills.list")}
name={["md_rbac", "bills:list"]} rules={[
> {
<InputNumber /> required: true
</Form.Item> //message: t("general.validation.required"),
<Form.Item }
label={t("bodyshop.fields.rbac.bills.reexport")} ]}
rules={[ name={["md_rbac", "bills:list"]}
{ >
required: true <InputNumber />
//message: t("general.validation.required"), </Form.Item>
} <Form.Item
]} label={t("bodyshop.fields.rbac.bills.reexport")}
name={["md_rbac", "bills:reexport"]} rules={[
> {
<InputNumber /> required: true
</Form.Item> //message: t("general.validation.required"),
<Form.Item }
label={t("bodyshop.fields.rbac.bills.view")} ]}
rules={[ name={["md_rbac", "bills:reexport"]}
{ >
required: true <InputNumber />
//message: t("general.validation.required"), </Form.Item>
} <Form.Item
]} label={t("bodyshop.fields.rbac.bills.view")}
name={["md_rbac", "bills:view"]} rules={[
> {
<InputNumber /> required: true
</Form.Item> //message: t("general.validation.required"),
<Form.Item }
label={t("bodyshop.fields.rbac.contracts.create")} ]}
rules={[ name={["md_rbac", "bills:view"]}
{ >
required: true <InputNumber />
//message: t("general.validation.required"), </Form.Item>
} </>
]} )}
name={["md_rbac", "contracts:create"]}
> {HasFeatureAccess({ featureName: "courtesycars", bodyshop }) && (
<InputNumber /> <>
</Form.Item> <Form.Item
<Form.Item label={t("bodyshop.fields.rbac.contracts.create")}
label={t("bodyshop.fields.rbac.contracts.detail")} rules={[
rules={[ {
{ required: true
required: true //message: t("general.validation.required"),
//message: t("general.validation.required"), }
} ]}
]} name={["md_rbac", "contracts:create"]}
name={["md_rbac", "contracts:detail"]} >
> <InputNumber />
<InputNumber /> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label={t("bodyshop.fields.rbac.contracts.detail")}
label={t("bodyshop.fields.rbac.contracts.list")} rules={[
rules={[ {
{ required: true
required: true //message: t("general.validation.required"),
//message: t("general.validation.required"), }
} ]}
]} name={["md_rbac", "contracts:detail"]}
name={["md_rbac", "contracts:list"]} >
> <InputNumber />
<InputNumber /> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label={t("bodyshop.fields.rbac.contracts.list")}
label={t("bodyshop.fields.rbac.courtesycar.create")} rules={[
rules={[ {
{ required: true
required: true //message: t("general.validation.required"),
//message: t("general.validation.required"), }
} ]}
]} name={["md_rbac", "contracts:list"]}
name={["md_rbac", "courtesycar:create"]} >
> <InputNumber />
<InputNumber /> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label={t("bodyshop.fields.rbac.courtesycar.create")}
label={t("bodyshop.fields.rbac.courtesycar.detail")} rules={[
rules={[ {
{ required: true
required: true //message: t("general.validation.required"),
//message: t("general.validation.required"), }
} ]}
]} name={["md_rbac", "courtesycar:create"]}
name={["md_rbac", "courtesycar:detail"]} >
> <InputNumber />
<InputNumber /> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label={t("bodyshop.fields.rbac.courtesycar.detail")}
label={t("bodyshop.fields.rbac.courtesycar.list")} rules={[
rules={[ {
{ required: true
required: true //message: t("general.validation.required"),
//message: t("general.validation.required"), }
} ]}
]} name={["md_rbac", "courtesycar:detail"]}
name={["md_rbac", "courtesycar:list"]} >
> <InputNumber />
<InputNumber /> </Form.Item>
</Form.Item> <Form.Item
<Form.Item label={t("bodyshop.fields.rbac.courtesycar.list")}
label={t("bodyshop.fields.rbac.csi.export")} rules={[
rules={[ {
{ required: true
required: true //message: t("general.validation.required"),
//message: t("general.validation.required"), }
} ]}
]} name={["md_rbac", "courtesycar:list"]}
name={["md_rbac", "csi:export"]} >
> <InputNumber />
<InputNumber /> </Form.Item>
</Form.Item> </>
<Form.Item )}
label={t("bodyshop.fields.rbac.csi.page")} {HasFeatureAccess({ featureName: "csi", bodyshop }) && (
rules={[ <>
{ <Form.Item
required: true label={t("bodyshop.fields.rbac.csi.export")}
//message: t("general.validation.required"), rules={[
} {
]} required: true
name={["md_rbac", "csi:page"]} //message: t("general.validation.required"),
> }
<InputNumber /> ]}
</Form.Item> name={["md_rbac", "csi:export"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.csi.page")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "csi:page"]}
>
<InputNumber />
</Form.Item>
</>
)}
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.employees.page")} label={t("bodyshop.fields.rbac.employees.page")}
rules={[ rules={[
@@ -425,18 +443,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.bills.list")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "bills:list"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.employees.page")} label={t("bodyshop.fields.rbac.employees.page")}
rules={[ rules={[
@@ -510,18 +516,21 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item {HasFeatureAccess({ featureName: "visualboard", bodyshop }) && (
label={t("bodyshop.fields.rbac.production.board")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.production.board")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "production:board"]} ]}
> name={["md_rbac", "production:board"]}
<InputNumber /> >
</Form.Item> <InputNumber />
</Form.Item>
)}
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.production.list")} label={t("bodyshop.fields.rbac.production.list")}
rules={[ rules={[
@@ -546,102 +555,144 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item {HasFeatureAccess({ featureName: "scoreboard", bodyshop }) && (
label={t("bodyshop.fields.rbac.scoreboard.view")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.scoreboard.view")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "scoreboard:view"]} ]}
> name={["md_rbac", "scoreboard:view"]}
<InputNumber /> >
</Form.Item> <InputNumber />
<Form.Item </Form.Item>
label={t("bodyshop.fields.rbac.shiftclock.view")} )}
rules={[ {HasFeatureAccess({ featureName: "timetickets", bodyshop }) && (
{ <>
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.shiftclock.view")}
} rules={[
]} {
name={["md_rbac", "shiftclock:view"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item> ]}
<Form.Item name={["md_rbac", "shiftclock:view"]}
label={t("bodyshop.fields.rbac.shop.config")} >
rules={[ <InputNumber />
{ </Form.Item>
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.shop.config")}
} rules={[
]} {
name={["md_rbac", "shop:config"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item> ]}
<Form.Item name={["md_rbac", "shop:config"]}
label={t("bodyshop.fields.rbac.timetickets.edit")} >
rules={[ <InputNumber />
{ </Form.Item>
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.timetickets.edit")}
} rules={[
]} {
name={["md_rbac", "timetickets:edit"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item> ]}
<Form.Item name={["md_rbac", "timetickets:edit"]}
label={t("bodyshop.fields.rbac.timetickets.shiftedit")} >
rules={[ <InputNumber />
{ </Form.Item>
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.timetickets.shiftedit")}
} rules={[
]} {
name={["md_rbac", "timetickets:shiftedit"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item> ]}
<Form.Item name={["md_rbac", "timetickets:shiftedit"]}
label={t("bodyshop.fields.rbac.timetickets.editcommitted")} >
rules={[ <InputNumber />
{ </Form.Item>
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.timetickets.editcommitted")}
} rules={[
]} {
name={["md_rbac", "timetickets:editcommitted"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item> ]}
<Form.Item name={["md_rbac", "timetickets:editcommitted"]}
label={t("bodyshop.fields.rbac.ttapprovals.view")} >
rules={[ <InputNumber />
{ </Form.Item>
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.ttapprovals.view")}
} rules={[
]} {
name={["md_rbac", "ttapprovals:view"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item> ]}
<Form.Item name={["md_rbac", "ttapprovals:view"]}
label={t("bodyshop.fields.rbac.ttapprovals.approve")} >
rules={[ <InputNumber />
{ </Form.Item>
required: true <Form.Item
//message: t("general.validation.required"), label={t("bodyshop.fields.rbac.ttapprovals.approve")}
} rules={[
]} {
name={["md_rbac", "ttapprovals:approve"]} required: true
> //message: t("general.validation.required"),
<InputNumber /> }
</Form.Item> ]}
name={["md_rbac", "ttapprovals:approve"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.enter")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "timetickets:enter"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.list")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "timetickets:list"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.shiftedit")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "timetickets:shiftedit"]}
>
<InputNumber />
</Form.Item>
</>
)}
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.shop.vendors")} label={t("bodyshop.fields.rbac.shop.vendors")}
rules={[ rules={[
@@ -690,7 +741,7 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item>
<Form.Item {/* <Form.Item
label={t("bodyshop.fields.rbac.shop.templates")} label={t("bodyshop.fields.rbac.shop.templates")}
rules={[ rules={[
{ {
@@ -701,79 +752,22 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
name={["md_rbac", "shop:templates"]} name={["md_rbac", "shop:templates"]}
> >
<InputNumber /> <InputNumber />
</Form.Item> </Form.Item> */}
<Form.Item {HasFeatureAccess({ featureName: "media", bodyshop }) && (
label={t("bodyshop.fields.rbac.shop.vendors")} <Form.Item
rules={[ label={t("bodyshop.fields.rbac.temporarydocs.view")}
{ rules={[
required: true {
//message: t("general.validation.required"), required: true
} //message: t("general.validation.required"),
]} }
name={["md_rbac", "shop:vendors"]} ]}
> name={["md_rbac", "temporarydocs:view"]}
<InputNumber /> >
</Form.Item> <InputNumber />
<Form.Item </Form.Item>
label={t("bodyshop.fields.rbac.temporarydocs.view")} )}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "temporarydocs:view"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.edit")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "timetickets:edit"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.enter")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "timetickets:enter"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.list")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "timetickets:list"]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.rbac.timetickets.shiftedit")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["md_rbac", "timetickets:shiftedit"]}
>
<InputNumber />
</Form.Item>
<Form.Item <Form.Item
label={t("bodyshop.fields.rbac.users.editaccess")} label={t("bodyshop.fields.rbac.users.editaccess")}
rules={[ rules={[

View File

@@ -339,7 +339,7 @@ export function ShopInfoROStatusComponent({ bodyshop, form }) {
{(fields, { add, remove, move }) => { {(fields, { add, remove, move }) => {
return ( return (
<div> <div>
<LayoutFormRow> <Space size='large' wrap>
{fields.map((field, index) => ( {fields.map((field, index) => (
<Form.Item key={field.key}> <Form.Item key={field.key}>
<Space direction="vertical"> <Space direction="vertical">
@@ -386,7 +386,7 @@ export function ShopInfoROStatusComponent({ bodyshop, form }) {
</Space> </Space>
</Form.Item> </Form.Item>
))} ))}
</LayoutFormRow> </Space>
<Form.Item> <Form.Item>
<Button <Button
type="dashed" type="dashed"

View File

@@ -1,4 +1,4 @@
import { Button, Result } from "antd"; import { Result } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -16,19 +16,5 @@ export default connect(mapStateToProps, mapDispatchToProps)(ShopSubStatus);
export function ShopSubStatus({ bodyshop }) { export function ShopSubStatus({ bodyshop }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { sub_status } = bodyshop; const { sub_status } = bodyshop;
return ( return <Result status="403" title={t(`general.labels.sub_status.${sub_status}`)} />;
<Result
status="403"
title={t(`general.labels.sub_status.${sub_status}`)}
extra={
<Button
onClick={() => {
alert("Not implemented yet.");
}}
>
{t("general.actions.submitticket")}
</Button>
}
/>
);
} }

View File

@@ -72,10 +72,17 @@ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
}); });
} }
items.push({ InstanceRenderManager({
key: "licensing", executeFunction: true,
label: t("bodyshop.labels.licensing"), args: [],
children: <ShopInfoUsersComponent /> imex: () => {
items.push({
key: "licensing",
label: t("bodyshop.labels.licensing"),
children: <ShopInfoUsersComponent />
});
},
rome: "USE_IMEX"
}); });
if (HasFeatureAccess({ featureName: "csi", bodyshop })) { if (HasFeatureAccess({ featureName: "csi", bodyshop })) {

View File

@@ -15,6 +15,7 @@ import { getToken } from "firebase/messaging";
import i18next from "i18next"; import i18next from "i18next";
import LogRocket from "logrocket"; import LogRocket from "logrocket";
import { all, call, delay, put, select, takeLatest } from "redux-saga/effects"; import { all, call, delay, put, select, takeLatest } from "redux-saga/effects";
import { Userpilot } from "userpilot";
import { factory } from "../../App/App.container"; import { factory } from "../../App/App.container";
import { import {
analytics, analytics,
@@ -25,6 +26,10 @@ import {
messaging, messaging,
updateCurrentUser updateCurrentUser
} from "../../firebase/firebase.utils"; } from "../../firebase/firebase.utils";
import { QUERY_EULA } from "../../graphql/bodyshop.queries";
import client from "../../utils/GraphQLClient";
import day from "../../utils/day";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { import {
checkInstanceId, checkInstanceId,
sendPasswordResetFailure, sendPasswordResetFailure,
@@ -43,11 +48,6 @@ import {
validatePasswordResetSuccess validatePasswordResetSuccess
} from "./user.actions"; } from "./user.actions";
import UserActionTypes from "./user.types"; import UserActionTypes from "./user.types";
import client from "../../utils/GraphQLClient";
import { QUERY_EULA } from "../../graphql/bodyshop.queries";
import day from "../../utils/day";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { Userpilot } from "userpilot";
const fpPromise = FingerprintJS.load(); const fpPromise = FingerprintJS.load();
@@ -310,10 +310,28 @@ export function* SetAuthLevelFromShopDetails({ payload }) {
updateUserDetailsSuccess(authRecord[0] ? { validemail: authRecord[0].user.validemail } : { validemail: false }) updateUserDetailsSuccess(authRecord[0] ? { validemail: authRecord[0].user.validemail } : { validemail: false })
); );
const user = yield select((state) => state.user.currentUser);
if (payload.features.singleDeviceOnly) { if (payload.features.singleDeviceOnly) {
const user = yield select((state) => state.user.currentUser); if (!(user.email.includes("@imex.") || user.email.includes("@rome.") || user.email.includes("@promanager.")))
yield put(setInstanceId(user.uid));
}
if (!(user.email.includes("@imex.") || user.email.includes("@rome."))) yield put(setInstanceId(user.uid)); //For Rome, check to make sure it's not a PM shop.
try {
InstanceRenderManager({
executeFunction: true,
args: [],
rome: () => {
if (
payload.imexshopid.toLowerCase().startsWith("pm_") &&
!(user.email.includes("@imex.") || user.email.includes("@rome.") || user.email.includes("@promanager."))
) {
throw new Error("You are not authorized to use this application.");
}
}
});
} catch (error) {
yield put(setInstanceConflict());
} }
try { try {