397 lines
16 KiB
JavaScript
397 lines
16 KiB
JavaScript
import { useLazyQuery } from "@apollo/client";
|
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
|
import { Button, Card, Col, DatePicker, Form, Input, Radio, Row, Typography } from "antd";
|
|
import _ from "lodash";
|
|
import { useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { connect } from "react-redux";
|
|
import { createStructuredSelector } from "reselect";
|
|
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
|
import { QUERY_ACTIVE_EMPLOYEES, QUERY_ACTIVE_EMPLOYEES_WITH_EMAIL } from "../../graphql/employees.queries";
|
|
import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries";
|
|
import { selectReportCenter } from "../../redux/modals/modals.selectors";
|
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
import DatePickerRanges from "../../utils/DatePickerRanges";
|
|
import { GenerateDocument } from "../../utils/RenderTemplate";
|
|
import { TemplateList } from "../../utils/TemplateConstants";
|
|
import dayjs from "../../utils/day";
|
|
import EmployeeSearchSelectEmail from "../employee-search-select/employee-search-select-email.component";
|
|
import EmployeeSearchSelect from "../employee-search-select/employee-search-select.component";
|
|
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
|
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
|
import LockWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
|
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
|
import ReportCenterModalFiltersSortersComponent from "./report-center-modal-filters-sorters-component";
|
|
import "./report-center-modal.styles.scss";
|
|
|
|
const mapStateToProps = createStructuredSelector({
|
|
reportCenterModal: selectReportCenter,
|
|
bodyshop: selectBodyshop
|
|
});
|
|
const mapDispatchToProps = () => ({
|
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
|
});
|
|
export default connect(mapStateToProps, mapDispatchToProps)(ReportCenterModalComponent);
|
|
|
|
export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
|
|
const [form] = Form.useForm();
|
|
const [search, setSearch] = useState("");
|
|
const {
|
|
treatments: { Enhanced_Payroll, ADPPayroll }
|
|
} = useSplitTreatments({
|
|
attributes: {},
|
|
names: ["Enhanced_Payroll", "ADPPayroll"],
|
|
splitKey: bodyshop.imexshopid
|
|
});
|
|
const notification = useNotification();
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
const { t } = useTranslation();
|
|
const Templates = TemplateList("report_center");
|
|
const ReportsList = Object.keys(Templates)
|
|
.map((key) => Templates[key])
|
|
.filter((temp) => {
|
|
const enhancedPayrollOn = Enhanced_Payroll.treatment === "on";
|
|
const adpPayrollOn = ADPPayroll.treatment === "on";
|
|
|
|
if (enhancedPayrollOn && adpPayrollOn) {
|
|
return temp.enhanced_payroll !== false || temp.adp_payroll !== false;
|
|
}
|
|
if (enhancedPayrollOn) {
|
|
return temp.enhanced_payroll !== false && temp.adp_payroll !== true;
|
|
}
|
|
if (adpPayrollOn) {
|
|
return temp.adp_payroll !== false && temp.enhanced_payroll !== true;
|
|
}
|
|
|
|
return temp.enhanced_payroll !== true && temp.adp_payroll !== true;
|
|
});
|
|
|
|
const { open } = reportCenterModal;
|
|
|
|
const [callVendorQuery, { data: vendorData, called: vendorCalled }] = useLazyQuery(QUERY_ALL_VENDORS, {
|
|
skip: !(open && Templates[form.getFieldValue("key")] && Templates[form.getFieldValue("key")].idtype)
|
|
});
|
|
|
|
const [callEmployeeQuery, { data: employeeData, called: employeeCalled }] = useLazyQuery(QUERY_ACTIVE_EMPLOYEES, {
|
|
skip: !(open && Templates[form.getFieldValue("key")] && Templates[form.getFieldValue("key")].idtype)
|
|
});
|
|
|
|
const [callEmployeeWithEmailQuery, { data: employeeWithEmailData, called: employeeWithEmailCalled }] = useLazyQuery(
|
|
QUERY_ACTIVE_EMPLOYEES_WITH_EMAIL,
|
|
{
|
|
skip: !(open && Templates[form.getFieldValue("key")] && Templates[form.getFieldValue("key")].idtype)
|
|
}
|
|
);
|
|
|
|
const handleFinish = async (values) => {
|
|
setLoading(true);
|
|
const start = values.dates ? values.dates[0] : null;
|
|
const end = values.dates ? values.dates[1] : null;
|
|
const { id } = values;
|
|
|
|
const templateConfig = {
|
|
name: values.key,
|
|
variables: {
|
|
...(start ? { start: dayjs(start).startOf("day").format("YYYY-MM-DD") } : {}),
|
|
...(end ? { end: dayjs(end).endOf("day").format("YYYY-MM-DD") } : {}),
|
|
...(start ? { starttz: dayjs(start).startOf("day") } : {}),
|
|
...(end ? { endtz: dayjs(end).endOf("day") } : {}),
|
|
|
|
...(id ? { id: id } : {})
|
|
},
|
|
filters: values.filters,
|
|
sorters: values.sorters
|
|
};
|
|
|
|
if (_.isString(values.defaultSorters) && !_.isEmpty(values.defaultSorters)) {
|
|
templateConfig.defaultSorters = JSON.parse(values.defaultSorters);
|
|
}
|
|
|
|
await GenerateDocument(
|
|
templateConfig,
|
|
{
|
|
to: values.to,
|
|
subject: Templates[values.key]?.subject
|
|
},
|
|
values.sendbytext === "text"
|
|
? values.sendbytext
|
|
: values.sendbyexcel === "excel"
|
|
? "x"
|
|
: values.sendby === "email"
|
|
? "e"
|
|
: "p",
|
|
id,
|
|
notification
|
|
);
|
|
setLoading(false);
|
|
};
|
|
|
|
const FilteredReportsList =
|
|
search !== "" ? ReportsList.filter((r) => r.title.toLowerCase().includes(search.toLowerCase())) : ReportsList;
|
|
|
|
//Group it, create cards, and then filter out.
|
|
|
|
const grouped = _.groupBy(FilteredReportsList, "group");
|
|
|
|
const groupExcludeKeyFilter = [
|
|
...(!HasFeatureAccess({ featureName: "bills", bodyshop }) ? [{ key: "purchases", featureName: "bills" }] : []),
|
|
...(!HasFeatureAccess({ featureName: "timetickets", bodyshop })
|
|
? [{ key: "payroll", featureName: "timetickets" }]
|
|
: [])
|
|
];
|
|
|
|
//TODO: Find a way to filter out / blur on demand.
|
|
return (
|
|
<div className="report-center-modal">
|
|
<Form onFinish={handleFinish} autoComplete={"off"} layout="vertical" form={form}>
|
|
<Input.Search onChange={(e) => setSearch(e.target.value)} value={search} />
|
|
<Form.Item name="defaultSorters" hidden />
|
|
<Form.Item
|
|
name="key"
|
|
label={t("reportcenter.labels.key")}
|
|
// className="radio-group-columns"
|
|
rules={[
|
|
{
|
|
required: true
|
|
//message: t("general.validation.required"),
|
|
}
|
|
]}
|
|
>
|
|
<Radio.Group>
|
|
<Row gutter={[16, 16]}>
|
|
{Object.keys(grouped)
|
|
//.filter((key) => !groupExcludeKeyFilter.includes(key))
|
|
.map((key) => (
|
|
<Col xs={24} sm={12} md={Object.keys(grouped).length === 1 ? 24 : 8} key={key}>
|
|
<Card.Grid
|
|
style={{
|
|
width: "100%",
|
|
height: "100%",
|
|
maxHeight: "33vh",
|
|
overflowY: "scroll",
|
|
minWidth: "200px"
|
|
}}
|
|
>
|
|
<Typography.Title level={4}>{t(`reportcenter.labels.groups.${key}`)}</Typography.Title>
|
|
{groupExcludeKeyFilter.find((g) => g.key === key) ? (
|
|
<BlurWrapperComponent
|
|
featureName={groupExcludeKeyFilter.find((g) => g.key === key).featureName}
|
|
>
|
|
<ul style={{ listStyleType: "none", columns: grouped[key].length > 4 ? "2 auto" : "1", padding: 0, margin: 0 }}>
|
|
{grouped[key].map((item) => (
|
|
<li key={item.key}>
|
|
<Radio key={item.key} value={item.key}>
|
|
{item.title}
|
|
</Radio>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</BlurWrapperComponent>
|
|
) : (
|
|
<ul style={{ listStyleType: "none", columns: grouped[key].length > 4 ? "2 auto" : "1", padding: 0, margin: 0 }}>
|
|
{grouped[key].map((item) =>
|
|
item.featureNameRestricted ? (
|
|
<li key={item.key}>
|
|
<LockWrapperComponent featureName={item.featureNameRestricted}>
|
|
<Radio key={item.key} value={item.key}>
|
|
{item.title}
|
|
</Radio>
|
|
</LockWrapperComponent>
|
|
</li>
|
|
) : (
|
|
<li key={item.key}>
|
|
<Radio key={item.key} value={item.key}>
|
|
{item.title}
|
|
</Radio>
|
|
</li>
|
|
)
|
|
)}
|
|
</ul>
|
|
)}
|
|
</Card.Grid>
|
|
</Col>
|
|
))}
|
|
</Row>
|
|
</Radio.Group>
|
|
</Form.Item>
|
|
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
|
|
{() => {
|
|
const key = form.getFieldValue("key");
|
|
if (!key) return null;
|
|
//Kind of Id
|
|
const rangeFilter = Templates[key] && Templates[key].rangeFilter;
|
|
if (!rangeFilter) return null;
|
|
return (
|
|
<div>
|
|
{t("reportcenter.labels.filterson", {
|
|
object: rangeFilter.object,
|
|
field: rangeFilter.field
|
|
})}
|
|
</div>
|
|
);
|
|
}}
|
|
</Form.Item>
|
|
<ReportCenterModalFiltersSortersComponent form={form} bodyshop={bodyshop} />
|
|
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
|
|
{() => {
|
|
const key = form.getFieldValue("key");
|
|
const currentId = form.getFieldValue("id");
|
|
if (!key) return null;
|
|
//Kind of Id
|
|
const idtype = Templates[key] && Templates[key].idtype;
|
|
if (!idtype && currentId) {
|
|
form.setFieldsValue({ id: null });
|
|
return null;
|
|
}
|
|
if (!vendorCalled && idtype === "vendor") callVendorQuery();
|
|
if (!employeeCalled && idtype === "employee") callEmployeeQuery();
|
|
if (!employeeWithEmailCalled && idtype === "employeeWithEmail") callEmployeeWithEmailQuery();
|
|
if (idtype === "vendor")
|
|
return (
|
|
<Form.Item
|
|
name="id"
|
|
label={t("reportcenter.labels.vendor")}
|
|
rules={[
|
|
{
|
|
required: true
|
|
//message: t("general.validation.required"),
|
|
}
|
|
]}
|
|
>
|
|
<VendorSearchSelect options={vendorData ? vendorData.vendors : []} />
|
|
</Form.Item>
|
|
);
|
|
if (idtype === "employee")
|
|
return (
|
|
<Form.Item
|
|
name="id"
|
|
label={t("reportcenter.labels.employee")}
|
|
rules={[
|
|
{
|
|
required: true
|
|
//message: t("general.validation.required"),
|
|
}
|
|
]}
|
|
>
|
|
<EmployeeSearchSelect options={employeeData ? employeeData.employees : []} />
|
|
</Form.Item>
|
|
);
|
|
//This was introduced with tasks before assigned_to was shifted to UUID. Keeping in place for reference in the future if needed.
|
|
if (idtype === "employeeWithEmail")
|
|
return (
|
|
<Form.Item
|
|
name="id"
|
|
label={t("reportcenter.labels.employee")}
|
|
rules={[
|
|
{
|
|
required: true
|
|
//message: t("general.validation.required"),
|
|
}
|
|
]}
|
|
>
|
|
<EmployeeSearchSelectEmail options={employeeWithEmailData ? employeeWithEmailData.employees : []} />
|
|
</Form.Item>
|
|
);
|
|
else return null;
|
|
}}
|
|
</Form.Item>
|
|
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
|
|
{() => {
|
|
const key = form.getFieldValue("key");
|
|
const datedisable = Templates[key] && Templates[key].datedisable;
|
|
if (datedisable !== true) {
|
|
return (
|
|
<Form.Item
|
|
name="dates"
|
|
label={t("reportcenter.labels.dates")}
|
|
rules={[
|
|
{
|
|
required: true
|
|
//message: t("general.validation.required"),
|
|
},
|
|
{
|
|
validator: (_, value) => {
|
|
if (value && value[0] && value[1]) {
|
|
const relatedRestrictedReport = restrictedReports.find((r) => r.key === key);
|
|
if (relatedRestrictedReport) {
|
|
const diffInDays = (value[1] - value[0]) / (1000 * 3600 * 24);
|
|
if (diffInDays > relatedRestrictedReport.days) {
|
|
return Promise.reject(t("general.validation.dateRangeExceeded"));
|
|
}
|
|
}
|
|
}
|
|
return Promise.resolve();
|
|
}
|
|
}
|
|
]}
|
|
>
|
|
<DatePicker.RangePicker format="MM/DD/YYYY" presets={DatePickerRanges} />
|
|
</Form.Item>
|
|
);
|
|
} else return null;
|
|
}}
|
|
</Form.Item>
|
|
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
|
|
{() => {
|
|
const key = form.getFieldValue("key");
|
|
//Kind of Id
|
|
const reporttype = Templates[key] && Templates[key].reporttype;
|
|
|
|
if (reporttype === "excel")
|
|
return (
|
|
<Form.Item label={t("general.labels.sendby")} name="sendbyexcel" initialValue="excel">
|
|
<Radio.Group>
|
|
<Radio value="excel">{t("general.labels.excel")}</Radio>
|
|
</Radio.Group>
|
|
</Form.Item>
|
|
);
|
|
if (reporttype === "text")
|
|
return (
|
|
<Form.Item label={t("general.labels.sendby")} name="sendbytext" initialValue="text">
|
|
<Radio.Group>
|
|
<Radio value="text">{t("general.labels.text")}</Radio>
|
|
</Radio.Group>
|
|
</Form.Item>
|
|
);
|
|
if (reporttype !== "excel" || reporttype !== "text")
|
|
return (
|
|
<Form.Item label={t("general.labels.sendby")} name="sendby" initialValue="print">
|
|
<Radio.Group>
|
|
<Radio value="email">{t("general.labels.email")}</Radio>
|
|
<Radio value="print">{t("general.labels.print")}</Radio>
|
|
</Radio.Group>
|
|
</Form.Item>
|
|
);
|
|
}}
|
|
</Form.Item>
|
|
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
justifyContent: "center",
|
|
marginTop: "1rem"
|
|
}}
|
|
>
|
|
<Button onClick={() => form.submit()} style={{}} loading={loading}>
|
|
{t("reportcenter.actions.generate")}
|
|
</Button>
|
|
</div>
|
|
</Form>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const restrictedReports = [
|
|
{ key: "job_costing_ro", days: 183 },
|
|
{ key: "job_costing_ro_date_summary", days: 183 },
|
|
{ key: "job_costing_ro_csr", days: 183 },
|
|
{ key: "job_costing_ro_ins_co", days: 183 },
|
|
{ key: "job_costing_ro_date_detail", days: 183 },
|
|
{ key: "job_costing_ro_estimator", days: 183 },
|
|
{ key: "job_lifecycle_date_detail", days: 183 },
|
|
{ key: "job_lifecycle_date_summary", days: 183 },
|
|
{ key: "customer_list", days: 183 },
|
|
{ key: "customer_list_excel", days: 183 }
|
|
];
|