Files
bodyshop/client/src/components/task-upsert-modal/task-upsert-modal.component.jsx
Dave Richer 678ca591c1 - enhancements / improvements / stuff
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-21 12:50:11 -04:00

295 lines
9.8 KiB
JavaScript

import { Col, Form, Input, Row, Select, Switch } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { createStructuredSelector } from "reselect";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors.js";
import dayjs from "../../utils/day";
import { connect } from "react-redux";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component.jsx";
import JobSearchSelectComponent from "../job-search-select/job-search-select.component.jsx";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
currentUser: selectCurrentUser
});
const mapDispatchToProps = () => ({});
export default connect(mapStateToProps, mapDispatchToProps)(TaskUpsertModalComponent);
export function TaskUpsertModalComponent({
form,
bodyshop,
currentUser,
selectedJobId,
setSelectedJobId,
selectedJobDetails,
existingTask,
loading,
error
}) {
const { t } = useTranslation();
const datePickerPresets = [
{ label: t("tasks.date_presets.today"), value: dayjs().add(1, "hour") },
{ label: t("tasks.date_presets.tomorrow"), value: dayjs().add(1, "day").startOf("day") },
{ label: t("tasks.date_presets.next_week"), value: dayjs().add(1, "week").startOf("day") },
{ label: t("tasks.date_presets.two_weeks"), value: dayjs().add(2, "weeks").startOf("day") },
{ label: t("tasks.date_presets.three_weeks"), value: dayjs().add(3, "weeks").startOf("day") },
{ label: t("tasks.date_presets.one_month"), value: dayjs().add(1, "month").startOf("day") },
{ label: t("tasks.date_presets.three_months"), value: dayjs().add(3, "month").startOf("day") }
];
const generatePresets = (job) => {
if (!job || !selectedJobDetails) return datePickerPresets; // return default presets if no job selected
const relativePresets = [];
if (selectedJobDetails?.scheduled_completion) {
const scheduledCompletion = dayjs(selectedJobDetails.scheduled_completion);
if (scheduledCompletion.isAfter(dayjs())) {
relativePresets.push(
{
label: `${t("tasks.date_presets.completion")} -1 ${t("tasks.date_presets.day")}`,
value: scheduledCompletion.subtract(1, "day").startOf("day")
},
{
label: `${t("tasks.date_presets.completion")} -2 ${t("tasks.date_presets.days")}`,
value: scheduledCompletion.subtract(2, "day").startOf("day")
},
{
label: `${t("tasks.date_presets.completion")} -3 ${t("tasks.date_presets.days")}`,
value: scheduledCompletion.subtract(3, "day").startOf("day")
}
);
}
}
if (selectedJobDetails?.scheduled_delivery) {
const scheduledDelivery = dayjs(selectedJobDetails.scheduled_delivery);
if (scheduledDelivery.isAfter(dayjs())) {
relativePresets.push(
{
label: `${t("tasks.date_presets.delivery")} -1 ${t("tasks.date_presets.day")}`,
value: scheduledDelivery.subtract(1, "day").startOf("day")
},
{
label: `${t("tasks.date_presets.delivery")} -2 ${t("tasks.date_presets.days")}`,
value: scheduledDelivery.subtract(2, "day").startOf("day")
},
{
label: `${t("tasks.date_presets.delivery")} -3 ${t("tasks.date_presets.days")}`,
value: scheduledDelivery.subtract(3, "day").startOf("day")
}
);
}
}
return [...relativePresets, ...datePickerPresets];
};
const clearRelations = () => {
form.setFieldsValue({
billid: null,
partsorderid: null,
joblineid: null
});
};
/**
* Change the selected job id
* @param jobId
*/
const changeJobId = (jobId) => {
setSelectedJobId(jobId || null);
// Reset the form fields when selectedJobId changes
clearRelations();
};
if (loading || error) return <LoadingSkeleton active />;
return (
<>
<Row gutter={[16, 16]}>
<Col span={16}>
<Form.Item
label={t("tasks.fields.title")}
name="title"
rules={[
{
required: true
}
]}
>
<Input placeholder={t("tasks.fields.title")} />
</Form.Item>
</Col>
<Col span={4}>
<Form.Item label={t("tasks.fields.priority")} name="priority" initialValue={2}>
<Select
options={[
{ value: 3, label: t("tasks.fields.priorities.low") },
{ value: 2, label: t("tasks.fields.priorities.medium") },
{ value: 1, label: t("tasks.fields.priorities.high") }
]}
/>
</Form.Item>
</Col>
<Col span={4}>
<Form.Item
label={t("tasks.fields.completed")}
name="completed"
valuePropName="checked"
initialValue={false}
rules={[
{
required: true
}
]}
>
<Switch />
</Form.Item>
</Col>
</Row>
<Row gutter={[16, 16]}>
<Col span={24}>
<Form.Item
name="jobid"
initialValue={selectedJobId}
label={t("tasks.fields.jobid")}
rules={[
{
required: true
}
]}
>
<JobSearchSelectComponent
placeholder={t("tasks.placeholders.jobid")}
onSelect={changeJobId}
onClear={changeJobId}
autoFocus={false}
/>
</Form.Item>
</Col>
</Row>
<Row gutter={[16, 16]}>
<Col span={8}>
<Form.Item label={t("tasks.fields.joblineid")} name="joblineid">
<Select
allowClear
placeholder={t("tasks.placeholders.joblineid")}
disabled={!selectedJobDetails || !selectedJobId}
options={selectedJobDetails?.joblines?.map((jobline) => ({
key: jobline.id,
value: jobline.id,
label: jobline.line_desc
}))}
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label={t("tasks.fields.partsorderid")} name="partsorderid">
<Select
allowClear
placeholder={t("tasks.placeholders.partsorderid")}
disabled={!selectedJobDetails || !selectedJobId}
options={selectedJobDetails?.parts_orders?.map((partsOrder) => ({
key: partsOrder.id,
value: partsOrder.id,
label: `${partsOrder.order_number} - ${partsOrder.vendor.name}`
}))}
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label={t("tasks.fields.billid")} name="billid">
<Select
allowClear
placeholder={t("tasks.placeholders.billid")}
disabled={!selectedJobDetails || !selectedJobId}
options={selectedJobDetails?.bills?.map((bill) => ({
key: bill.id,
value: bill.id,
label: `${bill.invoice_number} - ${bill.vendor.name}`
}))}
/>
</Form.Item>
</Col>
</Row>
<Row gutter={[16, 16]}>
<Col span={8}>
<Form.Item
label={t("tasks.fields.assigned_to")}
name="assigned_to"
initialValue={
bodyshop.employees.find((employee) => employee?.user_email === currentUser.email && employee.active)?.id
}
rules={[
{
required: true
}
]}
>
<Select
placeholder={t("tasks.placeholders.assigned_to")}
options={bodyshop.employees
.filter((x) => x.active && x.user_email)
.map((employee) => ({
key: employee.id,
value: employee.id,
label: `${employee.first_name} ${employee.last_name}`
}))}
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label={t("tasks.fields.due_date")} name="due_date">
<DateTimePicker
isDateOnly
onlyFuture
format="MM/DD/YYYY"
presets={generatePresets(selectedJobDetails)}
rules={[
{
validator: (_, value) => {
if (!value || existingTask?.due_date === value || dayjs(value).isAfter(dayjs())) {
return Promise.resolve();
}
return Promise.reject(new Error(t("tasks.validation.due_at_error_message")));
}
}
]}
/>
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
label={t("tasks.fields.remind_at")}
name="remind_at"
rules={[
{
validator: (_, value) => {
if (!value || existingTask?.remind_at === value || dayjs(value).isAfter(dayjs().add(15, "minute"))) {
return Promise.resolve();
}
return Promise.reject(new Error(t("tasks.validation.remind_at_error_message")));
}
}
]}
>
<DateTimePicker onlyFuture presets={generatePresets(selectedJobDetails)} />
</Form.Item>
</Col>
</Row>
<Row gutter={[16, 16]}>
<Col span={24}>
<Form.Item label={t("tasks.fields.description")} name="description">
<Input.TextArea rows={8} placeholder={t("tasks.fields.description")} />
</Form.Item>
</Col>
</Row>
</>
);
}