From f11d9dd804eb66a2e2adeb3b5ef532d8cf496eb2 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 6 Feb 2025 15:03:07 -0500 Subject: [PATCH] feature/IO-3096-GlobalNotifications - Watchers - First revision. --- .../jobs-detail-header.component.jsx | 3 +- client/src/graphql/jobs.queries.js | 30 ++++++++ .../job-watcher-toggle.component.jsx | 71 +++++++++++++++++++ .../jobs-detail.page.component.jsx | 12 +++- client/src/translations/en_us/common.json | 7 ++ hasura/metadata/cron_triggers.yaml | 16 ++--- hasura/metadata/tables.yaml | 59 +++++++-------- 7 files changed, 160 insertions(+), 38 deletions(-) create mode 100644 client/src/pages/jobs-detail/job-watcher-toggle.component.jsx diff --git a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx index ffe729b51..943b5aedd 100644 --- a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx +++ b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx @@ -51,6 +51,7 @@ const colSpan = { }; export function JobsDetailHeader({ job, bodyshop, disabled }) { + console.dir({ job }); const { t } = useTranslation(); const [notesClamped, setNotesClamped] = useState(true); const vehicleTitle = `${job.v_model_yr || ""} ${job.v_color || ""} @@ -119,7 +120,7 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) { {job.cccontracts.map((c, index) => ( - + {`${c.agreementnumber} - ${c.courtesycar.fleetnumber} ${c.courtesycar.year} ${c.courtesycar.make} ${c.courtesycar.model}`} {index !== job.cccontracts.length - 1 ? "," : null} diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index 1310c32da..09829db7e 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -524,6 +524,9 @@ export const GET_JOB_BY_PK = gql` invoice_final_note iouparent job_totals + job_watchers { + user_email + } joblines(where: { removed: { _eq: false } }, order_by: { line_no: asc }) { act_price act_price_before_ppc @@ -2566,3 +2569,30 @@ export const GET_JOB_BY_PK_QUICK_INTAKE = gql` } } `; + +export const GET_JOB_WATCHERS = gql` + query GET_JOB_WATCHERS($jobid: uuid!) { + job_watchers(where: { jobid: { _eq: $jobid } }) { + id + user_email + } + } +`; + +export const ADD_JOB_WATCHER = gql` + mutation ADD_JOB_WATCHER($jobid: uuid!, $userEmail: String!) { + insert_job_watchers_one(object: { jobid: $jobid, user_email: $userEmail }) { + id + jobid + user_email + } + } +`; + +export const REMOVE_JOB_WATCHER = gql` + mutation REMOVE_JOB_WATCHER($jobid: uuid!, $userEmail: String!) { + delete_job_watchers(where: { jobid: { _eq: $jobid }, user_email: { _eq: $userEmail } }) { + affected_rows + } + } +`; diff --git a/client/src/pages/jobs-detail/job-watcher-toggle.component.jsx b/client/src/pages/jobs-detail/job-watcher-toggle.component.jsx new file mode 100644 index 000000000..4a043e1ef --- /dev/null +++ b/client/src/pages/jobs-detail/job-watcher-toggle.component.jsx @@ -0,0 +1,71 @@ +import { useCallback, useMemo } from "react"; +import { useMutation, useQuery } from "@apollo/client"; +import { EyeFilled, EyeOutlined } from "@ant-design/icons"; +import { GET_JOB_WATCHERS, ADD_JOB_WATCHER, REMOVE_JOB_WATCHER } from "../../graphql/jobs.queries.js"; +import { Button, Tooltip } from "antd"; +import { useTranslation } from "react-i18next"; + +const JobWatcherToggle = ({ job, currentUser }) => { + const { t } = useTranslation(); + const userEmail = currentUser.email; + const jobid = job.id; + + // Fetch current watchers + const { data, loading } = useQuery(GET_JOB_WATCHERS, { + variables: { jobid } + }); + + // Extract current watchers list + const jobWatchers = useMemo(() => data?.job_watchers || [], [data]); + const isWatching = useMemo(() => !!jobWatchers.find((w) => w.user_email === userEmail), [jobWatchers, userEmail]); + + // Add watcher mutation + const [addWatcher] = useMutation(ADD_JOB_WATCHER, { + variables: { jobid, userEmail }, + refetchQueries: [{ query: GET_JOB_WATCHERS, variables: { jobid } }] + }); + + // Remove watcher mutation + const [removeWatcher] = useMutation(REMOVE_JOB_WATCHER, { + variables: { jobid, userEmail }, + refetchQueries: [{ query: GET_JOB_WATCHERS, variables: { jobid } }] + }); + + // Toggle watcher status + const handleToggle = useCallback(() => { + if (!isWatching) { + // Fix: Add if not watching, remove if watching + addWatcher().catch((err) => console.error(`Something went wrong adding a job watcher: ${err.message}`)); + } else { + removeWatcher().catch((err) => console.error(`Something went wrong removing a job watcher: ${err.message}`)); + } + }, [isWatching, addWatcher, removeWatcher]); + + if (loading) { + return ( + +