Added QB like calculator field for numbers that can be used. Resolved issue for unsaved changes indicator BOD-245 BOD-220
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
PaymentRequestButtonElement,
|
PaymentRequestButtonElement,
|
||||||
useStripe
|
useStripe,
|
||||||
} from "@stripe/react-stripe-js";
|
} from "@stripe/react-stripe-js";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -9,6 +9,8 @@ import { logImEXEvent } from "../../firebase/firebase.utils";
|
|||||||
import { setEmailOptions } from "../../redux/email/email.actions";
|
import { setEmailOptions } from "../../redux/email/email.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
|
import { Input, InputNumber, Popover } from "antd";
|
||||||
|
import { isInteger } from "lodash";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -18,13 +20,14 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
setEmailOptions: (e) => dispatch(setEmailOptions(e)),
|
setEmailOptions: (e) => dispatch(setEmailOptions(e)),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function Test({ bodyshop, setEmailOptions }) {
|
function Test({ bodyshop, setEmailOptions }) {
|
||||||
const stripe = useStripe();
|
const stripe = useStripe();
|
||||||
|
|
||||||
const [paymentRequest, setPaymentRequest] = useState(null);
|
const [paymentRequest, setPaymentRequest] = useState(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (stripe) {
|
if (stripe) {
|
||||||
console.log("in useeff");
|
|
||||||
const pr = stripe.paymentRequest({
|
const pr = stripe.paymentRequest({
|
||||||
country: "CA",
|
country: "CA",
|
||||||
displayItems: [{ label: "Deductible", amount: 1099 }],
|
displayItems: [{ label: "Deductible", amount: 1099 }],
|
||||||
@@ -37,10 +40,8 @@ function Test({ bodyshop, setEmailOptions }) {
|
|||||||
requestPayerEmail: true,
|
requestPayerEmail: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("pr", pr);
|
|
||||||
// Check the availability of the Payment Request API.
|
// Check the availability of the Payment Request API.
|
||||||
pr.canMakePayment().then((result) => {
|
pr.canMakePayment().then((result) => {
|
||||||
console.log("result", result);
|
|
||||||
if (result) {
|
if (result) {
|
||||||
setPaymentRequest(pr);
|
setPaymentRequest(pr);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const ContractStatusComponent = (
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onChange) {
|
if (value !== option && onChange) {
|
||||||
onChange(option);
|
onChange(option);
|
||||||
}
|
}
|
||||||
}, [option, onChange]);
|
}, [option, onChange]);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const CourtesyCarFuelComponent = ({ value = 100, onChange }, ref) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onChange) {
|
if (value !== option && onChange) {
|
||||||
onChange(option);
|
onChange(option);
|
||||||
}
|
}
|
||||||
}, [option, onChange]);
|
}, [option, onChange]);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const CourtesyCarStatusComponent = (
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onChange) {
|
if (value !== option && onChange) {
|
||||||
onChange(option);
|
onChange(option);
|
||||||
}
|
}
|
||||||
}, [option, onChange]);
|
}, [option, onChange]);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const EmployeeSearchSelect = (
|
|||||||
const [option, setOption] = useState(value);
|
const [option, setOption] = useState(value);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onChange) {
|
if (value !== option && onChange) {
|
||||||
onChange(option);
|
onChange(option);
|
||||||
}
|
}
|
||||||
}, [option, onChange]);
|
}, [option, onChange]);
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import { Input, Popover } from "antd";
|
||||||
|
import React, { useEffect, useState, forwardRef } from "react";
|
||||||
|
|
||||||
|
const FieldInputNUmberCalculator = (
|
||||||
|
{ value: formValue, onChange: formOnChange },
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const [value, setValue] = useState(formValue);
|
||||||
|
const [total, setTotal] = useState(0);
|
||||||
|
const [history, setHistory] = useState([]);
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
const key = e.target.value;
|
||||||
|
switch (key) {
|
||||||
|
case "/":
|
||||||
|
case "*":
|
||||||
|
case "+":
|
||||||
|
case "-":
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
setValue(key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (e) => {
|
||||||
|
const { key } = e;
|
||||||
|
|
||||||
|
let action;
|
||||||
|
switch (key) {
|
||||||
|
case "/":
|
||||||
|
case "*":
|
||||||
|
case "+":
|
||||||
|
case "-":
|
||||||
|
action = key;
|
||||||
|
break;
|
||||||
|
case "Enter":
|
||||||
|
action = "=";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const val = parseFloat(value);
|
||||||
|
setValue(null);
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
setHistory([...history, val, action]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (value !== formValue && formOnChange) formOnChange(value);
|
||||||
|
}, [formOnChange, value]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (history.length > 2) {
|
||||||
|
const subTotal = history.reduce((acc, val, idx) => {
|
||||||
|
if (idx === 0) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
switch (val) {
|
||||||
|
case "/":
|
||||||
|
case "*":
|
||||||
|
case "+":
|
||||||
|
case "-":
|
||||||
|
return acc;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//Weve got math on our hands. Find the last operator, and apply it accordingly.
|
||||||
|
switch (history[idx - 1]) {
|
||||||
|
case "/":
|
||||||
|
return acc / val;
|
||||||
|
case "*":
|
||||||
|
return acc * val;
|
||||||
|
case "+":
|
||||||
|
return acc + val;
|
||||||
|
case "-":
|
||||||
|
return acc - val;
|
||||||
|
default:
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
setTotal(subTotal);
|
||||||
|
if (history[history.length - 1] === "=") setValue(subTotal);
|
||||||
|
}
|
||||||
|
}, [history]);
|
||||||
|
|
||||||
|
const popContent = (
|
||||||
|
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
History
|
||||||
|
{history.map((h, idx) => (
|
||||||
|
<div style={{ marginLeft: "auto" }} key={idx}>
|
||||||
|
{h}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<div>{total}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Popover content={popContent} visible={history.length > 0}>
|
||||||
|
<Input
|
||||||
|
ref={ref}
|
||||||
|
value={value}
|
||||||
|
defaultValue={value}
|
||||||
|
onChange={handleChange}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
onBlur={(e) => setHistory([])}
|
||||||
|
/>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default forwardRef(FieldInputNUmberCalculator);
|
||||||
@@ -8,16 +8,16 @@ import { useTranslation } from "react-i18next";
|
|||||||
const DateTimePicker = ({ value, onChange, onBlur }, ref) => {
|
const DateTimePicker = ({ value, onChange, onBlur }, ref) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleChange = (value) => {
|
const handleChange = (newDate) => {
|
||||||
if (onChange) {
|
if (value !== newDate && onChange) {
|
||||||
onChange(value);
|
onChange(newDate);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DatePicker
|
<DatePicker
|
||||||
className='ant-picker ant-picker-input'
|
className="ant-picker ant-picker-input"
|
||||||
data-lpignore='true'
|
data-lpignore="true"
|
||||||
selected={value ? new Date(value) : null}
|
selected={value ? new Date(value) : null}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
showTimeSelect
|
showTimeSelect
|
||||||
@@ -25,7 +25,7 @@ const DateTimePicker = ({ value, onChange, onBlur }, ref) => {
|
|||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
isClearable
|
isClearable
|
||||||
placeholderText={t("general.labels.selectdate")}
|
placeholderText={t("general.labels.selectdate")}
|
||||||
dateFormat='MMMM d, yyyy h:mm aa'
|
dateFormat="MMMM d, yyyy h:mm aa"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const InvoiceLineSearchSelect = (
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onChange) {
|
if (value !== option && onChange) {
|
||||||
onChange(option);
|
onChange(option);
|
||||||
}
|
}
|
||||||
}, [option, onChange]);
|
}, [option, onChange]);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const JobSearchSelect = (
|
|||||||
const [option, setOption] = useState(value);
|
const [option, setOption] = useState(value);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onChange) {
|
if (value !== option && onChange) {
|
||||||
onChange(option);
|
onChange(option);
|
||||||
}
|
}
|
||||||
}, [option, onChange]);
|
}, [option, onChange]);
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import JobTotalsTable from "../job-totals-table/job-totals-table.component";
|
|||||||
import FormRow from "../layout-form-row/layout-form-row.component";
|
import FormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||||
|
|
||||||
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 FieldInputNumberCalculator from "../field-input-number-calculator/field-input-number-calculator.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const VendorSearchSelect = (
|
|||||||
const [option, setOption] = useState(value);
|
const [option, setOption] = useState(value);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (onChange) {
|
if (value !== option && onChange) {
|
||||||
onChange(option);
|
onChange(option);
|
||||||
}
|
}
|
||||||
}, [option, onChange]);
|
}, [option, onChange]);
|
||||||
|
|||||||
@@ -180,11 +180,7 @@ export function Manage({ match, conflict }) {
|
|||||||
component={TestComponent}
|
component={TestComponent}
|
||||||
/>
|
/>
|
||||||
<Route exact path={`${match.path}`} component={ManageRootPage} />
|
<Route exact path={`${match.path}`} component={ManageRootPage} />
|
||||||
<Route
|
|
||||||
exact
|
|
||||||
path={`${match.path}/_test`}
|
|
||||||
component={TestComponent}
|
|
||||||
/>
|
|
||||||
<Route exact path={`${match.path}/jobs`} component={JobsPage} />
|
<Route exact path={`${match.path}/jobs`} component={JobsPage} />
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
|
|||||||
Reference in New Issue
Block a user