feature/IO-3096-GlobalNotifications - Watchers - Third version, final.
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
import { useCallback, useMemo, useState } from "react";
|
||||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import { useMutation, useQuery } from "@apollo/client";
|
||||
import { EyeFilled, EyeOutlined, UserOutlined } from "@ant-design/icons";
|
||||
import { ADD_JOB_WATCHER, GET_JOB_WATCHERS, REMOVE_JOB_WATCHER } from "../../graphql/jobs.queries.js";
|
||||
import { Avatar, Button, List, Popover, Tooltip, Typography } from "antd";
|
||||
import { Avatar, Button, Divider, List, Popover, Select, Tooltip, Typography } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors.js";
|
||||
import EmployeeSearchSelectComponent from "../../components/employee-search-select/employee-search-select.component.jsx";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component.jsx"; // Ensure correct path
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component.jsx";
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
@@ -24,6 +24,7 @@ const JobWatcherToggle = ({ job, currentUser, bodyshop }) => {
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [selectedWatcher, setSelectedWatcher] = useState(null); // New state for selected value
|
||||
const [selectedTeam, setSelectedTeam] = useState(null); // New state to track selected team
|
||||
|
||||
// Fetch current watchers
|
||||
const { data: watcherData, loading: watcherLoading } = useQuery(GET_JOB_WATCHERS, { variables: { jobid } });
|
||||
@@ -75,6 +76,45 @@ const JobWatcherToggle = ({ job, currentUser, bodyshop }) => {
|
||||
setSelectedWatcher(null);
|
||||
};
|
||||
|
||||
const handleTeamSelect = (team) => {
|
||||
const selectedTeamMembers = JSON.parse(team); // Parse the array of emails
|
||||
|
||||
const newWatchers = selectedTeamMembers.filter(
|
||||
(email) => !jobWatchers.some((watcher) => watcher.user_email === email)
|
||||
);
|
||||
|
||||
// Add each new watcher
|
||||
newWatchers.forEach((email) => {
|
||||
addWatcher({ variables: { jobid, userEmail: email } }).catch((err) =>
|
||||
console.error(`Error adding job watcher: ${err.message}`)
|
||||
);
|
||||
});
|
||||
|
||||
// Clear selection
|
||||
setSelectedTeam(null);
|
||||
};
|
||||
|
||||
const handleRenderItem = (watcher) => {
|
||||
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 (
|
||||
<List.Item
|
||||
actions={[
|
||||
<Button type="link" danger size="small" onClick={() => handleRemoveWatcher(watcher.user_email)}>
|
||||
{t("notifications.actions.remove")}
|
||||
</Button>
|
||||
]}
|
||||
>
|
||||
<List.Item.Meta
|
||||
avatar={<Avatar icon={<UserOutlined />} />}
|
||||
title={<Text>{displayName}</Text>}
|
||||
description={watcher.user_email} // Keep the email for reference
|
||||
/>
|
||||
</List.Item>
|
||||
);
|
||||
};
|
||||
|
||||
// Popover content
|
||||
const popoverContent = (
|
||||
<div style={{ width: 600 }}>
|
||||
@@ -88,52 +128,54 @@ const JobWatcherToggle = ({ job, currentUser, bodyshop }) => {
|
||||
>
|
||||
{isWatching ? t("notifications.tooltips.unwatch") : t("notifications.tooltips.watch")}
|
||||
</Button>
|
||||
|
||||
{/* List of Watchers */}
|
||||
<Text type="secondary" style={{ marginBottom: 8, display: "block" }}>
|
||||
{t("notifications.labels.watching-issue")}
|
||||
</Text>
|
||||
|
||||
{watcherLoading ? (
|
||||
<LoadingSpinner />
|
||||
) : (
|
||||
<List
|
||||
dataSource={jobWatchers}
|
||||
renderItem={(watcher) => {
|
||||
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 (
|
||||
<List.Item
|
||||
actions={[
|
||||
<Button type="link" danger size="small" onClick={() => handleRemoveWatcher(watcher.user_email)}>
|
||||
{t("notifications.actions.remove")}
|
||||
</Button>
|
||||
]}
|
||||
>
|
||||
<List.Item.Meta
|
||||
avatar={<Avatar icon={<UserOutlined />} />}
|
||||
title={<Text>{displayName}</Text>}
|
||||
description={watcher.user_email} // Keep the email for reference
|
||||
/>
|
||||
</List.Item>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{watcherLoading ? <LoadingSpinner /> : <List dataSource={jobWatchers} renderItem={handleRenderItem} />}
|
||||
{/* Employee Search Select (for adding watchers) */}
|
||||
<Divider />
|
||||
|
||||
<Text type="secondary">{t("notifications.labels.add-watchers")}</Text>
|
||||
<EmployeeSearchSelectComponent
|
||||
style={{ minWidth: "100%" }}
|
||||
options={bodyshop.employees.filter((e) => jobWatchers.every((w) => w.user_email !== e.user_email))}
|
||||
placeholder={t("production.labels.employeesearch")}
|
||||
placeholder={t("notifications.labels.employee-search")}
|
||||
value={selectedWatcher} // Controlled value
|
||||
onChange={(value) => {
|
||||
setSelectedWatcher(value); // Update selected state
|
||||
handleWatcherSelect(value); // Add watcher logic
|
||||
}}
|
||||
/>
|
||||
{/* Divider for UI separation */}
|
||||
{/* Only show team selection if there are available teams */}
|
||||
{bodyshop?.employee_teams?.length > 0 && (
|
||||
<>
|
||||
<Divider />
|
||||
<Text type="secondary">{t("notifications.labels.add-watchers-team")}</Text>
|
||||
|
||||
<Select
|
||||
showSearch
|
||||
style={{ minWidth: "100%" }}
|
||||
placeholder={t("notifications.labels.teams-search")}
|
||||
value={selectedTeam} // Controlled value
|
||||
onChange={handleTeamSelect}
|
||||
options={bodyshop.employee_teams.map((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); // Remove nulls
|
||||
|
||||
return {
|
||||
value: JSON.stringify(teamMembers), // Store array as string
|
||||
label: team.name // Use team name as label
|
||||
};
|
||||
})}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user