Merged release/2025-01-31 into feature/IO-2825-Node-22-Update
This commit is contained in:
@@ -1,26 +1,23 @@
|
|||||||
import { Collapse, Form, Input, InputNumber, Select, Space, Switch } from "antd";
|
import { Collapse, Form, Input, InputNumber, Select, Space, Switch } from "antd";
|
||||||
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 InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
||||||
import FormItemPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
import FormItemPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
||||||
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.component";
|
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.component";
|
||||||
import JobsDetailChangeFilehandler from "../jobs-detail-change-filehandler/jobs-detail-change-filehandler.component";
|
import JobsDetailChangeFilehandler from "../jobs-detail-change-filehandler/jobs-detail-change-filehandler.component";
|
||||||
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component";
|
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component";
|
||||||
import JobsDetailRatesParts from "../jobs-detail-rates/jobs-detail-rates.parts.component";
|
|
||||||
|
|
||||||
import JobsDetailRatesLabor from "../jobs-detail-rates/jobs-detail-rates.labor.component";
|
import JobsDetailRatesLabor from "../jobs-detail-rates/jobs-detail-rates.labor.component";
|
||||||
import JobsDetailRatesMaterials from "../jobs-detail-rates/jobs-detail-rates.materials.component";
|
import JobsDetailRatesMaterials from "../jobs-detail-rates/jobs-detail-rates.materials.component";
|
||||||
import JobsDetailRatesOther from "../jobs-detail-rates/jobs-detail-rates.other.component";
|
import JobsDetailRatesOther from "../jobs-detail-rates/jobs-detail-rates.other.component";
|
||||||
|
import JobsDetailRatesParts from "../jobs-detail-rates/jobs-detail-rates.parts.component";
|
||||||
import JobsDetailRatesTaxes from "../jobs-detail-rates/jobs-detail-rates.taxes.component";
|
import JobsDetailRatesTaxes from "../jobs-detail-rates/jobs-detail-rates.taxes.component";
|
||||||
|
|
||||||
import JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
|
import JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.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 DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
@@ -199,7 +196,9 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
|
|||||||
</Collapse.Panel>
|
</Collapse.Panel>
|
||||||
<Collapse.Panel forceRender key="financial" header={t("menus.jobsdetail.financials")}>
|
<Collapse.Panel forceRender key="financial" header={t("menus.jobsdetail.financials")}>
|
||||||
<JobsDetailRatesChangeButton form={form} />
|
<JobsDetailRatesChangeButton form={form} />
|
||||||
<JobsMarkPstExempt form={form} />
|
{InstanceRenderManager({
|
||||||
|
imex: <JobsMarkPstExempt form={form} />
|
||||||
|
})}
|
||||||
<LayoutFormRow>
|
<LayoutFormRow>
|
||||||
<Form.Item label={t("jobs.fields.ded_amt")} name="ded_amt">
|
<Form.Item label={t("jobs.fields.ded_amt")} name="ded_amt">
|
||||||
<CurrencyInput min={0} />
|
<CurrencyInput min={0} />
|
||||||
@@ -246,7 +245,6 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
|
|||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|
||||||
<LayoutFormRow>
|
<LayoutFormRow>
|
||||||
<Form.Item label={t("jobs.fields.rate_lab")} name="rate_lab">
|
<Form.Item label={t("jobs.fields.rate_lab")} name="rate_lab">
|
||||||
<CurrencyInput />
|
<CurrencyInput />
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import { Button, Input, Space, Spin } from "antd";
|
import { Button, Input, Space, Spin } from "antd";
|
||||||
import React, { useState } from "react";
|
import { useState } 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 { ExclamationCircleFilled, ExclamationCircleOutlined } from "@ant-design/icons";
|
import {
|
||||||
|
ExclamationCircleFilled,
|
||||||
|
ExclamationCircleOutlined,
|
||||||
|
UserDeleteOutlined,
|
||||||
|
UsergroupDeleteOutlined
|
||||||
|
} from "@ant-design/icons";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import EmployeeSearchSelectComponent from "../employee-search-select/employee-search-select.component";
|
import EmployeeSearchSelectComponent from "../employee-search-select/employee-search-select.component";
|
||||||
|
|
||||||
@@ -20,6 +25,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(ProductionBoardFilte
|
|||||||
export function ProductionBoardFilters({ bodyshop, filter, setFilter, loading }) {
|
export function ProductionBoardFilters({ bodyshop, filter, setFilter, loading }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [alertFilter, setAlertFilter] = useState(false);
|
const [alertFilter, setAlertFilter] = useState(false);
|
||||||
|
const [unassignedFilter, setUnassignedFilter] = useState(false);
|
||||||
|
|
||||||
const toggleAlertFilter = () => {
|
const toggleAlertFilter = () => {
|
||||||
const newAlertFilter = !alertFilter;
|
const newAlertFilter = !alertFilter;
|
||||||
@@ -27,6 +33,12 @@ export function ProductionBoardFilters({ bodyshop, filter, setFilter, loading })
|
|||||||
setFilter({ ...filter, alert: newAlertFilter });
|
setFilter({ ...filter, alert: newAlertFilter });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleUnassignedFilter = () => {
|
||||||
|
const newUnassignedFilter = !unassignedFilter;
|
||||||
|
setUnassignedFilter(newUnassignedFilter);
|
||||||
|
setFilter({ ...filter, unassigned: newUnassignedFilter });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
{loading && <Spin />}
|
{loading && <Spin />}
|
||||||
@@ -52,6 +64,13 @@ export function ProductionBoardFilters({ bodyshop, filter, setFilter, loading })
|
|||||||
>
|
>
|
||||||
{t("production.labels.alerts")}
|
{t("production.labels.alerts")}
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
type={unassignedFilter ? "primary" : "default"}
|
||||||
|
onClick={toggleUnassignedFilter}
|
||||||
|
icon={unassignedFilter ? <UserDeleteOutlined /> : <UsergroupDeleteOutlined />}
|
||||||
|
>
|
||||||
|
{t("production.labels.unassigned")}
|
||||||
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const sortByParentId = (arr) => {
|
|||||||
|
|
||||||
// Function to create board data based on statuses and jobs, with optional filtering
|
// Function to create board data based on statuses and jobs, with optional filtering
|
||||||
export const createBoardData = ({ statuses, data, filter, cardSettings }) => {
|
export const createBoardData = ({ statuses, data, filter, cardSettings }) => {
|
||||||
const { search, employeeId, alert } = filter;
|
const { search, employeeId, alert, unassigned } = filter;
|
||||||
|
|
||||||
const lanes = statuses.map((status) => ({
|
const lanes = statuses.map((status) => ({
|
||||||
id: status,
|
id: status,
|
||||||
@@ -40,6 +40,13 @@ export const createBoardData = ({ statuses, data, filter, cardSettings }) => {
|
|||||||
let filteredJobs =
|
let filteredJobs =
|
||||||
(search === "" || !search) && !employeeId ? data : data.filter((job) => checkFilter(search, employeeId, job));
|
(search === "" || !search) && !employeeId ? data : data.filter((job) => checkFilter(search, employeeId, job));
|
||||||
|
|
||||||
|
// Apply "Unassigned" filter
|
||||||
|
if (unassigned) {
|
||||||
|
filteredJobs = filteredJobs.filter(
|
||||||
|
(job) => !job.employee_body && !job.employee_prep && !job.employee_refinish && !job.employee_csr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Filter jobs by selectedMdInsCos if it has values
|
// Filter jobs by selectedMdInsCos if it has values
|
||||||
if (cardSettings?.selectedMdInsCos?.length > 0) {
|
if (cardSettings?.selectedMdInsCos?.length > 0) {
|
||||||
filteredJobs = filteredJobs.filter((job) => cardSettings.selectedMdInsCos.includes(job.ins_co_nm));
|
filteredJobs = filteredJobs.filter((job) => cardSettings.selectedMdInsCos.includes(job.ins_co_nm));
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, Card, Col, Form, Popover, Row, Tabs } from "antd";
|
import { Button, Card, Col, Form, Popover, Row, Tabs } from "antd";
|
||||||
import React, { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { UPDATE_KANBAN_SETTINGS } from "../../../graphql/user.queries.js";
|
import { UPDATE_KANBAN_SETTINGS } from "../../../graphql/user.queries.js";
|
||||||
import { defaultKanbanSettings, mergeWithDefaults } from "./defaultKanbanSettings.js";
|
import { defaultKanbanSettings, mergeWithDefaults } from "./defaultKanbanSettings.js";
|
||||||
@@ -11,6 +11,7 @@ import FilterSettings from "./FilterSettings.jsx";
|
|||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { isFunction } from "lodash";
|
import { isFunction } from "lodash";
|
||||||
import { useNotification } from "../../../contexts/Notifications/notificationContext.jsx";
|
import { useNotification } from "../../../contexts/Notifications/notificationContext.jsx";
|
||||||
|
import { SettingOutlined } from "@ant-design/icons";
|
||||||
|
|
||||||
function ProductionBoardKanbanSettings({ associationSettings, parentLoading, bodyshop, data, onSettingsChange }) {
|
function ProductionBoardKanbanSettings({ associationSettings, parentLoading, bodyshop, data, onSettingsChange }) {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
@@ -153,7 +154,7 @@ function ProductionBoardKanbanSettings({ associationSettings, parentLoading, bod
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover content={overlay} open={open} placement="topRight">
|
<Popover content={overlay} open={open} placement="topRight">
|
||||||
<Button loading={loading} onClick={() => setOpen(!open)}>
|
<Button icon={<SettingOutlined />} loading={loading} onClick={() => setOpen(!open)}>
|
||||||
{t("production.settings.board_settings")}
|
{t("production.settings.board_settings")}
|
||||||
</Button>
|
</Button>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Button, Dropdown } from "antd";
|
import { Button, Dropdown } from "antd";
|
||||||
import React, { useState } from "react";
|
import { useState } from "react";
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||||
@@ -7,6 +7,7 @@ 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 { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||||
|
import { PrinterFilled } from "@ant-design/icons";
|
||||||
|
|
||||||
const ProdTemplates = TemplateList("production");
|
const ProdTemplates = TemplateList("production");
|
||||||
const { production_by_technician_one, production_by_category_one, production_by_repair_status_one } =
|
const { production_by_technician_one, production_by_category_one, production_by_repair_status_one } =
|
||||||
@@ -123,7 +124,9 @@ export function ProductionListPrint({ bodyshop }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown trigger="click" menu={menu}>
|
<Dropdown trigger="click" menu={menu}>
|
||||||
<Button loading={loading}>{t("general.labels.print")}</Button>
|
<Button icon={<PrinterFilled />} loading={loading}>
|
||||||
|
{t("general.labels.print")}
|
||||||
|
</Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import React from "react";
|
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { Button } from "antd";
|
import { Button } from "antd";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
@@ -28,7 +27,6 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
* @param {Object} [props.buttonStyle={}] - Style object for the Ant Design button.
|
* @param {Object} [props.buttonStyle={}] - Style object for the Ant Design button.
|
||||||
* @param {Object} [props.buttonIconStyle={}] - Style object for the icon within the button.
|
* @param {Object} [props.buttonIconStyle={}] - Style object for the icon within the button.
|
||||||
* @param {string} [props.linkText] - Text to display on the button or link.
|
* @param {string} [props.linkText] - Text to display on the button or link.
|
||||||
* @param {Object} [props.additionalProps] - Additional props to pass to the rendered component.
|
|
||||||
* @returns {React.ReactElement} A button or text link for sharing to Microsoft Teams.
|
* @returns {React.ReactElement} A button or text link for sharing to Microsoft Teams.
|
||||||
*/
|
*/
|
||||||
const ShareToTeamsComponent = ({
|
const ShareToTeamsComponent = ({
|
||||||
@@ -40,8 +38,7 @@ const ShareToTeamsComponent = ({
|
|||||||
noIconStyle = {},
|
noIconStyle = {},
|
||||||
buttonStyle = {},
|
buttonStyle = {},
|
||||||
buttonIconStyle = {},
|
buttonIconStyle = {},
|
||||||
linkText,
|
linkText
|
||||||
...additionalProps
|
|
||||||
}) => {
|
}) => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -87,7 +84,7 @@ const ShareToTeamsComponent = ({
|
|||||||
|
|
||||||
if (noIcon) {
|
if (noIcon) {
|
||||||
return (
|
return (
|
||||||
<div style={{ cursor: "pointer", ...noIconStyle }} onClick={handleShare} {...additionalProps}>
|
<div style={{ cursor: "pointer", ...noIconStyle }} onClick={handleShare}>
|
||||||
{!linkText ? t("general.actions.sharetoteams") : linkText}
|
{!linkText ? t("general.actions.sharetoteams") : linkText}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -104,7 +101,6 @@ const ShareToTeamsComponent = ({
|
|||||||
icon={<SiMicrosoftteams style={{ color: "#FFFFFF", ...buttonIconStyle }} />}
|
icon={<SiMicrosoftteams style={{ color: "#FFFFFF", ...buttonIconStyle }} />}
|
||||||
onClick={handleShare}
|
onClick={handleShare}
|
||||||
title={linkText === null ? t("general.actions.sharetoteams") : linkText}
|
title={linkText === null ? t("general.actions.sharetoteams") : linkText}
|
||||||
{...additionalProps}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -117,8 +113,7 @@ ShareToTeamsComponent.propTypes = {
|
|||||||
noIconStyle: PropTypes.object,
|
noIconStyle: PropTypes.object,
|
||||||
buttonStyle: PropTypes.object,
|
buttonStyle: PropTypes.object,
|
||||||
buttonIconStyle: PropTypes.object,
|
buttonIconStyle: PropTypes.object,
|
||||||
linkText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
linkText: PropTypes.oneOfType([PropTypes.string, PropTypes.node])
|
||||||
additionalProps: PropTypes.oneOfType([PropTypes.object, PropTypes.node])
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(mapStateToProps)(ShareToTeamsComponent);
|
export default connect(mapStateToProps)(ShareToTeamsComponent);
|
||||||
|
|||||||
@@ -1527,7 +1527,7 @@
|
|||||||
"addDocuments": "Add Job Documents",
|
"addDocuments": "Add Job Documents",
|
||||||
"addNote": "Add Note",
|
"addNote": "Add Note",
|
||||||
"addtopartsqueue": "Add to Parts Queue",
|
"addtopartsqueue": "Add to Parts Queue",
|
||||||
"addtoproduction": "Add In Production Flag",
|
"addtoproduction": "Add to Production",
|
||||||
"addtoscoreboard": "Add to Scoreboard",
|
"addtoscoreboard": "Add to Scoreboard",
|
||||||
"allocate": "Allocate",
|
"allocate": "Allocate",
|
||||||
"autoallocate": "Auto Allocate",
|
"autoallocate": "Auto Allocate",
|
||||||
@@ -1570,7 +1570,7 @@
|
|||||||
"printCenter": "Print Center",
|
"printCenter": "Print Center",
|
||||||
"recalculate": "Recalculate",
|
"recalculate": "Recalculate",
|
||||||
"reconcile": "Reconcile",
|
"reconcile": "Reconcile",
|
||||||
"removefromproduction": "Remove In Production Flag",
|
"removefromproduction": "Remove from Production",
|
||||||
"schedule": "Schedule",
|
"schedule": "Schedule",
|
||||||
"sendcsi": "Send CSI",
|
"sendcsi": "Send CSI",
|
||||||
"sendpartspricechange": "Send Parts Price Change",
|
"sendpartspricechange": "Send Parts Price Change",
|
||||||
@@ -2859,7 +2859,8 @@
|
|||||||
"touchtime": "T/T",
|
"touchtime": "T/T",
|
||||||
"vertical": "Vertical",
|
"vertical": "Vertical",
|
||||||
"viewname": "View Name",
|
"viewname": "View Name",
|
||||||
"wide": "Wide"
|
"wide": "Wide",
|
||||||
|
"unassigned": "Unassigned"
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"horizontal": "Horizontal",
|
"horizontal": "Horizontal",
|
||||||
|
|||||||
@@ -2859,7 +2859,8 @@
|
|||||||
"touchtime": "",
|
"touchtime": "",
|
||||||
"vertical": "",
|
"vertical": "",
|
||||||
"viewname": "",
|
"viewname": "",
|
||||||
"wide": ""
|
"wide": "",
|
||||||
|
"unassigned": ""
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"horizontal": "",
|
"horizontal": "",
|
||||||
|
|||||||
@@ -2859,7 +2859,8 @@
|
|||||||
"touchtime": "",
|
"touchtime": "",
|
||||||
"vertical": "",
|
"vertical": "",
|
||||||
"viewname": "",
|
"viewname": "",
|
||||||
"wide": ""
|
"wide": "",
|
||||||
|
"unassigned": ""
|
||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"horizontal": "",
|
"horizontal": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user