Files
bodyshop/client/src/components/job-line-location-popup/job-line-location-popup.component.jsx

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);