220 lines
7.4 KiB
JavaScript
220 lines
7.4 KiB
JavaScript
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
import { useMutation, useQuery } from "@apollo/client";
|
|
import { ADD_JOB_WATCHER, GET_JOB_WATCHERS, REMOVE_JOB_WATCHER } from "../../graphql/jobs.queries.js";
|
|
import { connect } from "react-redux";
|
|
import { createStructuredSelector } from "reselect";
|
|
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors.js";
|
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
|
import JobWatcherToggleComponent from "./job-watcher-toggle.component.jsx";
|
|
|
|
const mapStateToProps = createStructuredSelector({
|
|
bodyshop: selectBodyshop,
|
|
currentUser: selectCurrentUser
|
|
});
|
|
|
|
function JobWatcherToggleContainer({ job, currentUser, bodyshop }) {
|
|
const {
|
|
treatments: { Enhanced_Payroll }
|
|
} = useSplitTreatments({
|
|
attributes: {},
|
|
names: ["Enhanced_Payroll"],
|
|
splitKey: bodyshop && bodyshop.imexshopid
|
|
});
|
|
|
|
const userEmail = currentUser.email;
|
|
const jobid = job.id;
|
|
|
|
const [open, setOpen] = useState(false);
|
|
const [selectedWatcher, setSelectedWatcher] = useState(null);
|
|
const [selectedTeam, setSelectedTeam] = useState(null);
|
|
|
|
// Fetch current watchers with refetch capability
|
|
const {
|
|
data: watcherData,
|
|
loading: watcherLoading,
|
|
refetch
|
|
} = useQuery(GET_JOB_WATCHERS, {
|
|
variables: { jobid },
|
|
fetchPolicy: "cache-and-network" // Ensure fresh data from server
|
|
});
|
|
|
|
// Refetch jobWatchers when the popover opens (open changes to true)
|
|
useEffect(() => {
|
|
if (open) {
|
|
refetch().catch((err) =>
|
|
console.error(`Something went wrong fetching Notification Watchers on popover open: ${err?.message}`, {
|
|
stack: err?.stack
|
|
})
|
|
);
|
|
}
|
|
}, [open, refetch]);
|
|
|
|
const jobWatchers = useMemo(() => (watcherData?.job_watchers ? [...watcherData.job_watchers] : []), [watcherData]);
|
|
const isWatching = jobWatchers.some((w) => w.user_email === userEmail);
|
|
|
|
const [addWatcher, { loading: adding }] = useMutation(ADD_JOB_WATCHER, {
|
|
onCompleted: () =>
|
|
refetch().catch((err) =>
|
|
console.error(`Something went wrong fetching Notification Watchers after add: ${err?.message}`, {
|
|
stack: err?.stack
|
|
})
|
|
),
|
|
onError: (err) => {
|
|
if (err.graphQLErrors && err.graphQLErrors.length > 0) {
|
|
const errorMessage = err.graphQLErrors[0].message;
|
|
if (
|
|
errorMessage.includes("Uniqueness violation") ||
|
|
errorMessage.includes("idx_job_watchers_jobid_user_email_unique")
|
|
) {
|
|
console.warn("Watcher already exists for this job and user.");
|
|
refetch().catch((err) =>
|
|
console.error(
|
|
`Something went wrong fetching Notification Watchers after uniqueness violation: ${err?.message}`,
|
|
{ stack: err?.stack }
|
|
)
|
|
); // Sync with server to ensure UI reflects actual state
|
|
} else {
|
|
console.error(`Error adding job watcher: ${errorMessage}`);
|
|
}
|
|
} else {
|
|
console.error(`Unexpected error adding job watcher: ${err.message || JSON.stringify(err)}`);
|
|
}
|
|
},
|
|
update(cache, { data }) {
|
|
if (!data || !data.insert_job_watchers_one) {
|
|
console.warn("No data or insert_job_watchers_one returned from mutation, skipping cache update.");
|
|
refetch().catch((err) =>
|
|
console.error(`Something went wrong updating Notification Watchers after add: ${err?.message}`, {
|
|
stack: err?.stack
|
|
})
|
|
);
|
|
return;
|
|
}
|
|
|
|
const insert_job_watchers_one = data.insert_job_watchers_one;
|
|
const existingData = cache.readQuery({
|
|
query: GET_JOB_WATCHERS,
|
|
variables: { jobid }
|
|
});
|
|
|
|
cache.writeQuery({
|
|
query: GET_JOB_WATCHERS,
|
|
variables: { jobid },
|
|
data: {
|
|
...existingData,
|
|
job_watchers: [...(existingData?.job_watchers || []), insert_job_watchers_one]
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
const [removeWatcher, { loading: removing }] = useMutation(REMOVE_JOB_WATCHER, {
|
|
onCompleted: () =>
|
|
refetch().catch((err) =>
|
|
console.error(`Something went wrong fetching Notification Watchers after remove: ${err?.message}`, {
|
|
stack: err?.stack
|
|
})
|
|
), // Refetch to sync with server after success
|
|
onError: (err) => console.error(`Error removing job watcher: ${err.message}`),
|
|
update(cache, { data: { delete_job_watchers } }) {
|
|
const existingData = cache.readQuery({
|
|
query: GET_JOB_WATCHERS,
|
|
variables: { jobid }
|
|
});
|
|
|
|
const deletedWatcher = delete_job_watchers.returning[0];
|
|
const updatedWatchers = deletedWatcher
|
|
? (existingData?.job_watchers || []).filter((watcher) => watcher.user_email !== deletedWatcher.user_email)
|
|
: existingData?.job_watchers || [];
|
|
|
|
cache.writeQuery({
|
|
query: GET_JOB_WATCHERS,
|
|
variables: { jobid },
|
|
data: {
|
|
...existingData,
|
|
job_watchers: updatedWatchers
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
const handleToggleSelf = useCallback(async () => {
|
|
if (adding || removing) return;
|
|
if (isWatching) {
|
|
await removeWatcher({ variables: { jobid, userEmail } });
|
|
} else {
|
|
await addWatcher({ variables: { jobid, userEmail } });
|
|
}
|
|
}, [isWatching, addWatcher, removeWatcher, jobid, userEmail, adding, removing]);
|
|
|
|
const handleRemoveWatcher = useCallback(
|
|
async (email) => {
|
|
if (removing) return;
|
|
await removeWatcher({ variables: { jobid, userEmail: email } });
|
|
},
|
|
[removeWatcher, jobid, removing]
|
|
);
|
|
|
|
const handleWatcherSelect = useCallback(
|
|
async (selectedUser) => {
|
|
if (adding || removing) return;
|
|
const employee = bodyshop.employees.find((e) => e.id === selectedUser);
|
|
if (!employee) return;
|
|
|
|
const email = employee.user_email;
|
|
const isAlreadyWatching = jobWatchers.some((w) => w.user_email === email);
|
|
|
|
if (isAlreadyWatching) {
|
|
await handleRemoveWatcher(email);
|
|
} else {
|
|
await addWatcher({ variables: { jobid, userEmail: email } });
|
|
}
|
|
setSelectedWatcher(null);
|
|
},
|
|
[jobWatchers, addWatcher, handleRemoveWatcher, jobid, bodyshop, adding, removing]
|
|
);
|
|
|
|
const handleTeamSelect = useCallback(
|
|
async (team) => {
|
|
if (adding) return;
|
|
const selectedTeamMembers = JSON.parse(team);
|
|
const newWatchers = selectedTeamMembers.filter(
|
|
(email) => !jobWatchers.some((watcher) => watcher.user_email === email)
|
|
);
|
|
|
|
if (newWatchers.length === 0) {
|
|
console.warn("All selected team members are already watchers.");
|
|
setSelectedTeam(null);
|
|
return;
|
|
}
|
|
await Promise.all(newWatchers.map((email) => addWatcher({ variables: { jobid, userEmail: email } })));
|
|
},
|
|
[jobWatchers, addWatcher, jobid, adding]
|
|
);
|
|
|
|
return (
|
|
<JobWatcherToggleComponent
|
|
jobWatchers={jobWatchers}
|
|
isWatching={isWatching}
|
|
watcherLoading={watcherLoading}
|
|
adding={adding}
|
|
removing={removing}
|
|
open={open}
|
|
setOpen={setOpen}
|
|
selectedWatcher={selectedWatcher}
|
|
setSelectedWatcher={setSelectedWatcher}
|
|
selectedTeam={selectedTeam}
|
|
setSelectedTeam={setSelectedTeam}
|
|
bodyshop={bodyshop}
|
|
Enhanced_Payroll={Enhanced_Payroll}
|
|
handleToggleSelf={handleToggleSelf}
|
|
handleRemoveWatcher={handleRemoveWatcher}
|
|
handleWatcherSelect={handleWatcherSelect}
|
|
handleTeamSelect={handleTeamSelect}
|
|
currentUser={currentUser}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export default connect(mapStateToProps)(JobWatcherToggleContainer);
|