109 lines
3.3 KiB
JavaScript
109 lines
3.3 KiB
JavaScript
import { useMutation } from "@apollo/client/react";
|
|
import { Select, Space, Tag } from "antd";
|
|
import { useEffect, useMemo, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { connect } from "react-redux";
|
|
import { createStructuredSelector } from "reselect";
|
|
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
|
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
|
|
|
const mapStateToProps = createStructuredSelector({
|
|
bodyshop: selectBodyshop
|
|
});
|
|
const mapDispatchToProps = () => ({});
|
|
|
|
const CLEAR_VALUE = "__CLEAR_LOCATION__";
|
|
|
|
export function JobLineLocationPopup({ bodyshop, jobline, disabled }) {
|
|
const [editing, setEditing] = useState(false);
|
|
const [saving, setSaving] = useState(false);
|
|
const [location, setLocation] = useState(jobline.location);
|
|
const [updateJob] = useMutation(UPDATE_JOB_LINE);
|
|
const { t } = useTranslation();
|
|
const notification = useNotification();
|
|
|
|
useEffect(() => {
|
|
if (editing) setLocation(jobline.location);
|
|
}, [editing, jobline.location]);
|
|
|
|
const options = useMemo(() => {
|
|
const locs = bodyshop?.md_parts_locations || [];
|
|
return [
|
|
{ label: t("general.labels.none", "No location"), value: CLEAR_VALUE },
|
|
...locs.map((loc) => ({ label: loc, value: loc }))
|
|
];
|
|
}, [bodyshop?.md_parts_locations, t]);
|
|
|
|
const saveLocation = async (nextLocation) => {
|
|
setSaving(true);
|
|
|
|
try {
|
|
const result = await updateJob({
|
|
variables: { lineId: jobline.id, line: { location: nextLocation || "" } }
|
|
});
|
|
|
|
if (!result.errors) {
|
|
notification["success"]({ message: t("joblines.successes.saved") });
|
|
} else {
|
|
notification["error"]({
|
|
message: t("joblines.errors.saving", {
|
|
error: JSON.stringify(result.errors)
|
|
})
|
|
});
|
|
}
|
|
} catch (error) {
|
|
notification["error"]({
|
|
message: t("joblines.errors.saving", { error: error?.message || String(error) })
|
|
});
|
|
} finally {
|
|
setSaving(false);
|
|
setEditing(false);
|
|
}
|
|
};
|
|
|
|
const handleChange = async (value) => {
|
|
const next = value === CLEAR_VALUE ? null : value;
|
|
setLocation(next);
|
|
await saveLocation(next);
|
|
};
|
|
|
|
if (editing) {
|
|
return (
|
|
<div style={{ width: "100%", display: "flex", alignItems: "center" }}>
|
|
<Select
|
|
autoFocus
|
|
size="small"
|
|
value={location ?? undefined}
|
|
loading={saving}
|
|
disabled={saving}
|
|
style={{ flex: 1, minWidth: 0 }}
|
|
popupMatchSelectWidth={false}
|
|
getPopupContainer={(triggerNode) => triggerNode.parentNode}
|
|
onChange={handleChange}
|
|
onBlur={() => !saving && setEditing(false)}
|
|
options={options}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div
|
|
style={{ width: "100%", minHeight: "2rem", cursor: disabled ? "default" : "pointer" }}
|
|
onClick={() => !disabled && setEditing(true)}
|
|
>
|
|
<Space wrap>
|
|
{jobline.location ? (
|
|
<Tag>{jobline.location}</Tag>
|
|
) : (
|
|
<span style={{ opacity: 0.6 }}>{t("general.labels.none")}</span>
|
|
)}
|
|
{jobline.parts_dispatch_lines?.length > 0 && "-Disp"}
|
|
</Space>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(JobLineLocationPopup);
|