diff --git a/client/.eslintrc b/client/.eslintrc
index cc0f939b4..25e7bdb80 100644
--- a/client/.eslintrc
+++ b/client/.eslintrc
@@ -1,5 +1,8 @@
{
"extends": [
"react-app"
- ]
+ ],
+ "rules": {
+ "no-useless-rename": "off"
+ }
}
diff --git a/client/src/components/bills-list-table/bills-list-table.component.jsx b/client/src/components/bills-list-table/bills-list-table.component.jsx
index 03541a5ca..5329c43b0 100644
--- a/client/src/components/bills-list-table/bills-list-table.component.jsx
+++ b/client/src/components/bills-list-table/bills-list-table.component.jsx
@@ -14,6 +14,7 @@ import { TemplateList } from "../../utils/TemplateConstants";
import BillDeleteButton from "../bill-delete-button/bill-delete-button.component";
import BillDetailEditReturnComponent from "../bill-detail-edit/bill-detail-edit-return.component";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
+import { FaTasks } from "react-icons/fa";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
@@ -21,9 +22,21 @@ const mapStateToProps = createStructuredSelector({
});
const mapDispatchToProps = (dispatch) => ({
- setPartsOrderContext: (context) => dispatch(setModalContext({ context: context, modal: "partsOrder" })),
- setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" })),
- setReconciliationContext: (context) => dispatch(setModalContext({ context: context, modal: "reconciliation" }))
+ setBillEnterContext: (context) =>
+ dispatch(
+ setModalContext({
+ context: context,
+ modal: "billEnter"
+ })
+ ),
+ setReconciliationContext: (context) =>
+ dispatch(
+ setModalContext({
+ context: context,
+ modal: "reconciliation"
+ })
+ ),
+ setTaskUpsertContext: (context) => dispatch(setModalContext({ context, modal: "taskUpsert" }))
});
export function BillsListTableComponent({
@@ -32,9 +45,9 @@ export function BillsListTableComponent({
job,
billsQuery,
handleOnRowClick,
- setPartsOrderContext,
setBillEnterContext,
- setReconciliationContext
+ setReconciliationContext,
+ setTaskUpsertContext
}) {
const { t } = useTranslation();
@@ -48,6 +61,7 @@ export function BillsListTableComponent({
const Templates = TemplateList("bill");
const bills = billsQuery.data ? billsQuery.data.bills : [];
const { refetch } = billsQuery;
+
const recordActions = (record, showView = false) => (
{showView && (
@@ -55,6 +69,19 @@ export function BillsListTableComponent({
)}
+
({
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
+});
+export default connect(mapStateToProps, mapDispatchToProps)(FormDateTimePickerEnhanced);
+
+const dateFormat = "MM/DD/YYYY h:mm a";
+
+export function FormDateTimePickerEnhanced({
+ bodyshop,
+ value,
+ onBlur,
+ onlyFuture,
+ onlyToday,
+ isDateOnly = true,
+ ...restProps
+}) {
+ const ref = useRef();
+ return (
+
+ {
+ if (onlyToday) {
+ return !dayjs().isSame(d, "day");
+ } else if (onlyFuture) {
+ return dayjs().subtract(1, "day").isAfter(d);
+ }
+ }}
+ {...restProps}
+ />
+
+ );
+}
diff --git a/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx b/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx
index 8c11ece9d..23af7008a 100644
--- a/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx
+++ b/client/src/components/form-date-time-picker/form-date-time-picker.component.jsx
@@ -1,7 +1,7 @@
import React, { forwardRef } from "react";
//import DatePicker from "react-datepicker";
//import "react-datepicker/src/stylesheets/datepicker.scss";
-import { TimePicker } from "antd";
+import { Space, TimePicker } from "antd";
import dayjs from "../../utils/day";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
//To be used as a form element only.
@@ -14,7 +14,7 @@ const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, ...restProps
// };
return (
-
+
-
+
);
};
diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx
index d0683154e..d795e6f54 100644
--- a/client/src/components/header/header.component.jsx
+++ b/client/src/components/header/header.component.jsx
@@ -17,6 +17,7 @@ import Icon, {
LineChartOutlined,
PaperClipOutlined,
PhoneOutlined,
+ PlusCircleOutlined,
QuestionCircleFilled,
ScheduleOutlined,
SettingOutlined,
@@ -30,7 +31,7 @@ import { Layout, Menu, Switch, Tooltip } from "antd";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { BsKanban } from "react-icons/bs";
-import { FaCalendarAlt, FaCarCrash, FaCreditCard, FaFileInvoiceDollar } from "react-icons/fa";
+import { FaCalendarAlt, FaCarCrash, FaCreditCard, FaFileInvoiceDollar, FaTasks } from "react-icons/fa";
import { GiPayMoney, GiPlayerTime, GiSettingsKnobs } from "react-icons/gi";
import { IoBusinessOutline } from "react-icons/io5";
import { RiSurveyLine } from "react-icons/ri";
@@ -54,12 +55,43 @@ const mapStateToProps = createStructuredSelector({
});
const mapDispatchToProps = (dispatch) => ({
- setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" })),
- setTimeTicketContext: (context) => dispatch(setModalContext({ context: context, modal: "timeTicket" })),
+ setBillEnterContext: (context) =>
+ dispatch(
+ setModalContext({
+ context: context,
+ modal: "billEnter"
+ })
+ ),
+ setTimeTicketContext: (context) =>
+ dispatch(
+ setModalContext({
+ context: context,
+ modal: "timeTicket"
+ })
+ ),
setPaymentContext: (context) => dispatch(setModalContext({ context: context, modal: "payment" })),
- setReportCenterContext: (context) => dispatch(setModalContext({ context: context, modal: "reportCenter" })),
+ setReportCenterContext: (context) =>
+ dispatch(
+ setModalContext({
+ context: context,
+ modal: "reportCenter"
+ })
+ ),
signOutStart: () => dispatch(signOutStart()),
- setCardPaymentContext: (context) => dispatch(setModalContext({ context: context, modal: "cardPayment" }))
+ setCardPaymentContext: (context) =>
+ dispatch(
+ setModalContext({
+ context: context,
+ modal: "cardPayment"
+ })
+ ),
+ setTaskUpsertContext: (context) =>
+ dispatch(
+ setModalContext({
+ context: context,
+ modal: "taskUpsert"
+ })
+ )
});
function Header({
@@ -73,7 +105,8 @@ function Header({
setPaymentContext,
setReportCenterContext,
recentItems,
- setCardPaymentContext
+ setCardPaymentContext,
+ setTaskUpsertContext
}) {
const {
treatments: { ImEXPay, DmsAp, Simple_Inventory }
@@ -441,6 +474,35 @@ function Header({
}
]
: []),
+ {
+ key: "tasks",
+ id: "tasks",
+ icon: ,
+ label: t("menus.header.tasks"),
+ children: [
+ {
+ key: "createTask",
+ icon: ,
+ label: t("menus.header.create_task"),
+ onClick: () => {
+ setTaskUpsertContext({
+ actions: {},
+ context: {}
+ });
+ }
+ },
+ {
+ key: "mytasks",
+ icon: ,
+ label: {t("menus.header.my_tasks")}
+ },
+ {
+ key: "all_tasks",
+ icon: ,
+ label: {t("menus.header.all_tasks")}
+ }
+ ]
+ },
{
key: "shopsubmenu",
icon: ,
diff --git a/client/src/components/job-detail-lines/job-lines-expander.component.jsx b/client/src/components/job-detail-lines/job-lines-expander.component.jsx
index 16d2d6fa5..53ca81457 100644
--- a/client/src/components/job-detail-lines/job-lines-expander.component.jsx
+++ b/client/src/components/job-detail-lines/job-lines-expander.component.jsx
@@ -7,17 +7,18 @@ import { GET_JOB_LINE_ORDERS } from "../../graphql/jobs.queries";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter";
import AlertComponent from "../alert/alert.component";
-
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
+import { QUERY_JOBLINE_TASKS_PAGINATED } from "../../graphql/tasks.queries.js";
+import TaskListContainer from "../task-list/task-list.container.jsx";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
});
-const mapDispatchToProps = (dispatch) => ({
- //setUserLanguage: language => dispatch(setUserLanguage(language))
-});
+
+const mapDispatchToProps = (dispatch) => ({});
+
export default connect(mapStateToProps, mapDispatchToProps)(JobLinesExpander);
export function JobLinesExpander({ jobline, jobid, bodyshop }) {
@@ -146,6 +147,15 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
}
/>
+
+
+
);
}
diff --git a/client/src/components/job-detail-lines/job-lines.component.jsx b/client/src/components/job-detail-lines/job-lines.component.jsx
index 291c02305..ff963337c 100644
--- a/client/src/components/job-detail-lines/job-lines.component.jsx
+++ b/client/src/components/job-detail-lines/job-lines.component.jsx
@@ -42,6 +42,7 @@ import JobSendPartPriceChangeComponent from "../job-send-parts-price-change/job-
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
import JobLinesExpander from "./job-lines-expander.component";
import JobLinesPartPriceChange from "./job-lines-part-price-change.component";
+import { FaTasks } from "react-icons/fa";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -52,7 +53,8 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({
setJobLineEditContext: (context) => dispatch(setModalContext({ context: context, modal: "jobLineEdit" })),
setPartsOrderContext: (context) => dispatch(setModalContext({ context: context, modal: "partsOrder" })),
- setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" }))
+ setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" })),
+ setTaskUpsertContext: (context) => dispatch(setModalContext({ context, modal: "taskUpsert" }))
});
export function JobLinesComponent({
@@ -67,7 +69,8 @@ export function JobLinesComponent({
job,
setJobLineEditContext,
form,
- setBillEnterContext
+ setBillEnterContext,
+ setTaskUpsertContext
}) {
const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK);
const {
@@ -331,6 +334,24 @@ export function JobLinesComponent({
>
+ >
+ )}
+
+
+ {(record.manual_line || jobIsPrivate) && (
+ <>