Files
bodyshop/client/src/components/report-center-modal/report-center-modal.component.jsx
2025-12-15 08:37:32 -08:00

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 }
];