From f8ae6dc5afc845ff6c6a1d65336154abc3e851f5 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Wed, 5 Mar 2025 11:07:28 -0500 Subject: [PATCH] IO-3166-Global-Notifications-Part-2 - Checkpoint --- .../components/header/header.component.jsx | 2 +- .../job-watcher-toggle.component.jsx | 141 +++++++++++ .../job-watcher-toggle.container.jsx | 218 +++++++++++++++++ .../notification-center.component.jsx | 6 +- .../job-watcher-toggle.component.jsx | 231 ------------------ .../jobs-detail.page.component.jsx | 4 +- client/src/translations/en_us/common.json | 3 +- client/src/translations/es/common.json | 3 +- client/src/translations/fr/common.json | 3 +- .../down.sql | 1 + .../up.sql | 2 + server/notifications/stringHelpers.js | 2 +- 12 files changed, 377 insertions(+), 239 deletions(-) create mode 100644 client/src/components/job-watcher-toggle/job-watcher-toggle.component.jsx create mode 100644 client/src/components/job-watcher-toggle/job-watcher-toggle.container.jsx delete mode 100644 client/src/pages/jobs-detail/job-watcher-toggle.component.jsx create mode 100644 hasura/migrations/1741145815435_create_index_idx_job_watchers_jobid_user_email_unique/down.sql create mode 100644 hasura/migrations/1741145815435_create_index_idx_job_watchers_jobid_user_email_unique/up.sql diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx index a5cc39e21..8399634ba 100644 --- a/client/src/components/header/header.component.jsx +++ b/client/src/components/header/header.component.jsx @@ -656,7 +656,7 @@ function Header({ icon: unreadLoading ? ( ) : ( - + ), diff --git a/client/src/components/job-watcher-toggle/job-watcher-toggle.component.jsx b/client/src/components/job-watcher-toggle/job-watcher-toggle.component.jsx new file mode 100644 index 000000000..54edf4465 --- /dev/null +++ b/client/src/components/job-watcher-toggle/job-watcher-toggle.component.jsx @@ -0,0 +1,141 @@ +import React from "react"; +import { EyeFilled, EyeOutlined, UserOutlined } from "@ant-design/icons"; +import { Avatar, Button, Divider, List, Popover, Select, Tooltip, Typography } from "antd"; +import { useTranslation } from "react-i18next"; +import EmployeeSearchSelectComponent from "../../components/employee-search-select/employee-search-select.component.jsx"; +import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component.jsx"; + +const { Text } = Typography; + +export default function JobWatcherToggleComponent({ + jobWatchers, + isWatching, + watcherLoading, + adding, + removing, + open, + setOpen, + selectedWatcher, + setSelectedWatcher, + selectedTeam, + bodyshop, + Enhanced_Payroll, + handleToggleSelf, + handleRemoveWatcher, + handleWatcherSelect, + handleTeamSelect +}) { + const { t } = useTranslation(); + + const handleRenderItem = (watcher) => { + // Check if watcher is defined and has user_email + if (!watcher || !watcher.user_email) { + return null; // Skip rendering invalid watchers + } + + const employee = bodyshop?.employees?.find((e) => e.user_email === watcher.user_email); + const displayName = employee ? `${employee.first_name} ${employee.last_name}` : watcher.user_email; + + return ( + handleRemoveWatcher(watcher.user_email)} + disabled={adding || removing} // Optional: Disable button during mutations + > + {t("notifications.actions.remove")} + + ]} + > + } />} + title={{displayName}} + description={watcher.user_email} + /> + + ); + }; + + const popoverContent = ( +
+ + + + + {t("notifications.labels.watching-issue")} + + {watcherLoading ? ( + + ) : jobWatchers && jobWatchers.length > 0 ? ( + + ) : ( + {t("notifications.labels.no-watchers")} + )} + + + {t("notifications.labels.add-watchers")} + jobWatchers.every((w) => w.user_email !== e.user_email)) || []} + placeholder={t("notifications.labels.employee-search")} + value={selectedWatcher} + onChange={(value) => { + setSelectedWatcher(value); + handleWatcherSelect(value); + }} + /> + {Enhanced_Payroll && bodyshop?.employee_teams?.length > 0 && ( + <> + + {t("notifications.labels.add-watchers-team")} + { - const teamMembers = team.employee_team_members - .map((member) => { - const employee = bodyshop.employees.find((e) => e.id === member.employeeid); - return employee ? employee.user_email : null; - }) - .filter(Boolean); - - return { - value: JSON.stringify(teamMembers), - label: team.name - }; - })} - /> - - )} -
- ); - - return ( - - -