@iotready/nextjs-components-library 1.0.0-preview3 → 1.0.0-preview31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,14 @@
1
- import { UserType } from '../../types';
2
- declare const GroupUpdate: ({ userInfo, groupInfo, usersGroup, usersList, devicesList, handleAddUserToGroup, handleRemoveUserFromGroup, handleGetGroups, handleUpdateGroup, handleUpdateDevice, handleDeleteGroup, container, containerProps, afterUpdateCallback, afterRemoveCallback, confirmMui }: {
1
+ import { AssetType, TrackleDeviceType, UserType } from '../../types';
2
+ declare const GroupUpdate: ({ groupInfo, usersGroup, usersList, devicesList, handleAddUserToGroup, handleRemoveUserFromGroup, handleUpdateGroup, handleDeleteGroup, container, containerProps, afterUpdateCallback, afterRemoveCallback, confirmMui }: {
3
3
  userInfo: UserType;
4
4
  groupInfo: any;
5
5
  usersGroup: any[];
6
6
  usersList: any[];
7
- devicesList: {
8
- id: string;
9
- state: any;
10
- managers: any[];
11
- }[];
7
+ devicesList: AssetType[] | TrackleDeviceType[];
12
8
  handleAddUserToGroup: (groupID: string, userName: string, userID: string) => Promise<any>;
13
9
  handleRemoveUserFromGroup: (groupID: string, userID: string) => Promise<any>;
14
10
  handleUpdateDevice: (id: string, body: any, user: UserType) => Promise<any>;
15
- handleGetGroups: (productID: number, userInfo?: UserType) => Promise<any>;
11
+ handleGetGroups: (userInfo?: UserType) => Promise<any>;
16
12
  handleUpdateGroup: (id: string, group: any) => Promise<void>;
17
13
  handleDeleteGroup: (id: string) => Promise<void>;
18
14
  container?: "Box" | "Card";
@@ -8,15 +8,13 @@ import AddIcon from '@mui/icons-material/Add';
8
8
  import CloseIcon from '@mui/icons-material/Close';
9
9
  import DeleteIcon from '@mui/icons-material/Delete';
10
10
  import { LoadingButton } from '@mui/lab';
11
- const GroupUpdate = ({ userInfo, groupInfo, usersGroup, usersList, devicesList, handleAddUserToGroup, handleRemoveUserFromGroup, handleGetGroups, handleUpdateGroup, handleUpdateDevice, handleDeleteGroup, container = 'Box', containerProps = {}, afterUpdateCallback, afterRemoveCallback, confirmMui }) => {
11
+ const GroupUpdate = ({ groupInfo, usersGroup, usersList, devicesList, handleAddUserToGroup, handleRemoveUserFromGroup, handleUpdateGroup, handleDeleteGroup, container = 'Box', containerProps = {}, afterUpdateCallback, afterRemoveCallback, confirmMui }) => {
12
12
  const [group, setGroup] = useState(groupInfo);
13
13
  const [loadingUpdateButton, setLoadingUpdateButton] = useState(false);
14
14
  const [loadingRemoveUserButton, setLoadingRemoveUserButton] = useState(false);
15
15
  const [loadingAddUserButton, setLoadingAddUserButton] = useState(false);
16
16
  const [loadingDeleteGroupButton, setLoadingDeleteGroupButton] = useState(false);
17
17
  const [selectedUser, setSelectedUser] = useState(null);
18
- const [error, setError] = useState(null);
19
- const [success, setSuccess] = useState(null);
20
18
  function handleChange(event) {
21
19
  setGroup({ ...group, [event.target.name]: event.target.value });
22
20
  }
@@ -25,23 +23,6 @@ const GroupUpdate = ({ userInfo, groupInfo, usersGroup, usersList, devicesList,
25
23
  try {
26
24
  const response = await handleRemoveUserFromGroup(group.id, userId);
27
25
  if (response) {
28
- if (devicesList.length > 0) {
29
- // should check if device is present in other groups the user is member of
30
- const groupsData = await handleGetGroups(1008, { role: 'support', uid: userId });
31
- const userGroupIds = groupsData.map((group) => group.id);
32
- // for all devices in the group set the selectedUser as manager
33
- for (const device of devicesList) {
34
- // check device is in a group of user is member of
35
- const found = device.state.groups.some((gID) => userGroupIds.includes(gID));
36
- if (!found) {
37
- // remove user from managers
38
- const managers = device.managers && device.managers.filter(man => man !== userId) || [];
39
- await handleUpdateDevice(device.id, {
40
- managers
41
- }, userInfo);
42
- }
43
- }
44
- }
45
26
  if (afterUpdateCallback) {
46
27
  await afterUpdateCallback(group);
47
28
  }
@@ -60,17 +41,6 @@ const GroupUpdate = ({ userInfo, groupInfo, usersGroup, usersList, devicesList,
60
41
  try {
61
42
  const response = await handleAddUserToGroup(group.id, selectedUser.label, selectedUser.id);
62
43
  if (response) {
63
- if (devicesList.length > 0) {
64
- for (const device of devicesList) {
65
- // for all devices in the group set the selectedUser as manager
66
- await handleUpdateDevice(device.id, {
67
- managers: [
68
- ...(device?.managers || []),
69
- selectedUser.id
70
- ]
71
- }, userInfo);
72
- }
73
- }
74
44
  if (afterUpdateCallback) {
75
45
  await afterUpdateCallback(group);
76
46
  }
@@ -1,7 +1,6 @@
1
- import { UserType } from '../../types/user';
2
- import { Position } from "./Map";
3
1
  import { Theme } from "@emotion/react";
4
- declare const GroupsDevices: ({ userInfo, handleGetUsersList, handleAddUserToGroup, handleRemoveUserFromGroup, handleGetGroups, handleGetUsersGroup, handleGetDevices, handleUpdateDevice, handleGetPositions, handleAddDevicesToGroup, handleRemoveDevicesFromGroup, handleCreateGroup, handleDeleteGroup, handleUpdateGroup, group, columnsArray, containerDataGrid, props, propsDatagrid, loadingComponent, containerProps, enableMaps, mapsHeight, mapsClickCallback, theme, confirmMui }: {
2
+ import { UserType, AssetType, DevicePositionType, TrackleDeviceType } from "../../types";
3
+ declare const GroupsDevices: ({ userInfo, handleGetUsersList, handleAddUserToGroup, handleRemoveUserFromGroup, handleGetGroups, handleGetUsersGroup, handleGetDevices, handleUpdateDevice, handleGetPositions, handleAddDevicesToGroup, handleRemoveDevicesFromGroup, handleCreateGroup, handleDeleteGroup, handleUpdateGroup, group, columnsArray, containerDataGrid, props, propsDatagrid, loadingComponent, containerProps, enableMaps, mapsHeight, mapsClickCallback, theme, confirmMui, propsHeaderGroups, forceGetDevices, customToolbar, groupsLabelAll, addDevicesLabel, groupUpdateRoles }: {
5
4
  userInfo: UserType;
6
5
  handleGetUsersList: ({ page, pageSize }: {
7
6
  page: number;
@@ -11,27 +10,33 @@ declare const GroupsDevices: ({ userInfo, handleGetUsersList, handleAddUserToGro
11
10
  }>;
12
11
  handleAddUserToGroup: (groupID: string, userName: string, userID: string) => Promise<any>;
13
12
  handleRemoveUserFromGroup: (groupID: string, userID: string) => Promise<any>;
14
- handleGetGroups: (productID: number, userInfo?: UserType) => Promise<any>;
13
+ handleGetGroups: (userInfo?: UserType) => Promise<any>;
15
14
  handleGetUsersGroup: (groupID: string) => Promise<any>;
16
15
  handleCreateGroup: (group: any) => Promise<any>;
17
- handleGetDevices: (user: UserType, group: string, selected: string) => Promise<any>;
18
- handleGetPositions: (devices: any) => Promise<any>;
19
- handleAddDevicesToGroup: (user: UserType, group: string, devicesToPatch: any[]) => Promise<any>;
20
- handleRemoveDevicesFromGroup: (user: UserType, group: string, devicesToPatch: any[]) => Promise<any>;
16
+ handleGetDevices: (user: UserType, group: string, selectedGroup: string) => Promise<AssetType[] | TrackleDeviceType[]>;
17
+ handleGetPositions?: (devices: any) => Promise<DevicePositionType[]>;
18
+ handleAddDevicesToGroup: (user: UserType, group: string, devicesToPatch: AssetType[] | TrackleDeviceType[]) => Promise<TrackleDeviceType[]>;
19
+ handleRemoveDevicesFromGroup: (user: UserType, group: string, devicesToPatch: AssetType[] | TrackleDeviceType[]) => Promise<TrackleDeviceType[]>;
21
20
  handleDeleteGroup: (id: string) => Promise<void>;
22
21
  handleUpdateGroup: (id: string, group: any) => Promise<void>;
23
- handleUpdateDevice: (id: string, body: any, user: UserType) => Promise<any>;
22
+ handleUpdateDevice: (id: string, body: any, user: UserType) => Promise<void>;
24
23
  group: string;
25
24
  columnsArray: any[];
26
25
  containerDataGrid?: "Card" | "Box";
27
26
  props?: any;
28
27
  propsDatagrid?: any;
28
+ propsHeaderGroups?: any;
29
29
  loadingComponent?: React.ReactNode;
30
30
  containerProps?: any;
31
31
  enableMaps?: boolean;
32
32
  mapsHeight: string;
33
- mapsClickCallback?: (position: Position) => void;
33
+ mapsClickCallback?: (position: DevicePositionType) => void;
34
34
  theme: Theme;
35
35
  confirmMui?: (options?: any) => Promise<void>;
36
+ forceGetDevices?: number;
37
+ customToolbar?: string[];
38
+ groupsLabelAll?: string;
39
+ addDevicesLabel?: string;
40
+ groupUpdateRoles?: string[];
36
41
  }) => string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<import("react").ReactNode> | Promise<import("react").AwaitedReactNode> | null;
37
42
  export default GroupsDevices;
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { Box, CircularProgress, Autocomplete, TextField, Input, IconButton, Button, Card, CardContent, CardHeader, Modal, Typography, Stack, Tab } from "@mui/material";
4
- import { cloneElement, isValidElement, useEffect, useMemo, useState } from "react";
4
+ import { cloneElement, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
5
5
  import AddIcon from '@mui/icons-material/Add';
6
6
  import PlaylistAddIcon from '@mui/icons-material/PlaylistAdd';
7
7
  import EditIcon from '@mui/icons-material/Edit';
@@ -10,13 +10,13 @@ import ReadMoreIcon from '@mui/icons-material/ReadMore';
10
10
  import PlaylistRemoveIcon from '@mui/icons-material/PlaylistRemove';
11
11
  import CloseIcon from '@mui/icons-material/Close';
12
12
  import { LoadingButton, TabContext, TabList, TabPanel } from "@mui/lab";
13
- import { DataGrid, GridToolbar } from "@mui/x-data-grid";
13
+ import { DataGrid, GridToolbar, GridToolbarExport, GridToolbarFilterButton, GridToolbarQuickFilter } from "@mui/x-data-grid";
14
14
  import GroupUpdate from "./GroupUpdate";
15
15
  import BackIcon from '@mui/icons-material/ArrowBack';
16
16
  import dynamic from "next/dynamic";
17
17
  import { ThemeProvider } from '@mui/material/styles';
18
- const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, handleRemoveUserFromGroup, handleGetGroups, handleGetUsersGroup, handleGetDevices, handleUpdateDevice, handleGetPositions, handleAddDevicesToGroup, handleRemoveDevicesFromGroup, handleCreateGroup, handleDeleteGroup, handleUpdateGroup, group = 'all', columnsArray = [], containerDataGrid = 'Card', props = {}, propsDatagrid = {}, loadingComponent = _jsx(CircularProgress, {}), containerProps = {}, enableMaps = true, mapsHeight = '400px', mapsClickCallback = () => { }, theme, confirmMui }) => {
19
- const [devices, setDevices] = useState(null);
18
+ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, handleRemoveUserFromGroup, handleGetGroups, handleGetUsersGroup, handleGetDevices, handleUpdateDevice, handleGetPositions, handleAddDevicesToGroup, handleRemoveDevicesFromGroup, handleCreateGroup, handleDeleteGroup, handleUpdateGroup, group = 'all', columnsArray = [], containerDataGrid = 'Card', props = {}, propsDatagrid = {}, loadingComponent = _jsx(CircularProgress, {}), containerProps = {}, enableMaps = true, mapsHeight = '400px', mapsClickCallback = () => { }, theme, confirmMui, propsHeaderGroups, forceGetDevices, customToolbar, groupsLabelAll, addDevicesLabel, groupUpdateRoles }) => {
19
+ const [devices, setDevices] = useState([]);
20
20
  const [positions, setPositions] = useState([]);
21
21
  const [loadingDevices, setLoadingDevices] = useState(false);
22
22
  const [loadingGroups, setLoadingGroups] = useState(false);
@@ -24,17 +24,19 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
24
24
  const [editGroup, setEditGroup] = useState(false);
25
25
  const [checkboxSelection, setCheckboxSelection] = useState(false);
26
26
  const [devicesToAdd, setDevicesToAdd] = useState([]);
27
+ const [deviceSelectedObjs, setDeviceSelectedObjs] = useState([]);
27
28
  const [currentGroup, setCurrentGroup] = useState(group);
28
29
  const [selectedGroup, setSelectedGroup] = useState(group);
29
30
  const [groups, setGroups] = useState(null);
30
31
  const [usersList, setUsersList] = useState([]);
31
- const [usersGroup, setUsersGroup] = useState([]);
32
+ const [usersGroup, setUsersGroup] = useState(null);
32
33
  const [groupInfo, setGroupInfo] = useState(null);
33
34
  const [openAdd, setOpenAdd] = useState(false);
34
35
  const [groupName, setGroupName] = useState('');
35
36
  const [description, setDescription] = useState('');
36
37
  const [groupUpdateVisible, setGroupUpdateVisible] = useState(false);
37
38
  const [valueTab, setValueTab] = useState('1');
39
+ const clickedIdRef = useRef(null);
38
40
  const handleChangeTab = (event, newValue) => {
39
41
  setValueTab(newValue);
40
42
  };
@@ -60,7 +62,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
60
62
  moreData = usersList.users.length === pageSize;
61
63
  page++;
62
64
  }
63
- const userGroupsUserIds = usersGroup.map((ug) => ug.user.userId);
65
+ const userGroupsUserIds = usersGroup && usersGroup.map((ug) => ug.user.userId) || [];
64
66
  setUsersList(usersData.filter((user) => user.role === 'support' && !userGroupsUserIds.includes(user.uid)).map((user) => {
65
67
  const userName = user.name ? user.name.replace("/", " ") : "";
66
68
  return { label: `${userName} (${user.email})`, id: user.uid };
@@ -75,7 +77,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
75
77
  setLoadingDevices(true);
76
78
  const devices = await handleGetDevices(userInfo, group, selected);
77
79
  setDevices(devices);
78
- if (enableMaps) {
80
+ if (enableMaps && handleGetPositions) {
79
81
  const positions = await handleGetPositions(devices);
80
82
  setPositions(positions);
81
83
  }
@@ -89,7 +91,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
89
91
  };
90
92
  const getGroups = async () => {
91
93
  try {
92
- const responseData = await handleGetGroups(1008, userInfo);
94
+ const responseData = await handleGetGroups(userInfo);
93
95
  setGroups(responseData);
94
96
  }
95
97
  catch (err) {
@@ -111,18 +113,23 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
111
113
  }
112
114
  }, [userInfo]);
113
115
  useEffect(() => {
114
- if (usersGroup) {
115
- getUsersList();
116
- }
116
+ getUsersList();
117
117
  }, [usersGroup]);
118
118
  useEffect(() => {
119
119
  if (currentGroup && !checkboxSelection) {
120
120
  setSelectedGroup(currentGroup);
121
121
  setGroupInfo(groups && groups.find((g) => g.id === currentGroup));
122
- getUsersGroup(currentGroup);
122
+ if (currentGroup !== 'all') {
123
+ getUsersGroup(currentGroup);
124
+ }
123
125
  fetchDevices(currentGroup, currentGroup);
124
126
  }
125
127
  }, [currentGroup]);
128
+ useEffect(() => {
129
+ if (forceGetDevices !== 0) {
130
+ fetchDevices(currentGroup, currentGroup);
131
+ }
132
+ }, [forceGetDevices]);
126
133
  const handleSubmit = async (e) => {
127
134
  e.preventDefault();
128
135
  setLoadingAdd(true);
@@ -130,7 +137,6 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
130
137
  const newGroup = {
131
138
  name: groupName,
132
139
  description,
133
- productID: 1008, // Assuming this is the correct productID
134
140
  };
135
141
  const id = await handleCreateGroup(newGroup);
136
142
  await getGroups();
@@ -172,28 +178,11 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
172
178
  const addToSelectedGroup = async () => {
173
179
  setLoadingGroups(true);
174
180
  try {
175
- const selectedData = devices.filter((row) => devicesToAdd.includes(row.id));
176
- const devicesToPatch = selectedData?.map((device) => ({ id: device.id, groups: device.state.groups, managers: device.managers }));
177
- const devicesPatched = await handleAddDevicesToGroup(userInfo, selectedGroup, devicesToPatch);
178
- if (devicesPatched && devicesPatched.length > 0) {
179
- // get all members of the group
180
- const userIdsToAdd = usersGroup.map((ug) => ug.user.userId);
181
- if (userIdsToAdd.length > 0) {
182
- for (const device of devicesToPatch) {
183
- // add members to devices managers
184
- await handleUpdateDevice(device.id, {
185
- managers: [
186
- ...device.managers,
187
- ...userIdsToAdd
188
- ]
189
- }, userInfo);
190
- }
191
- }
192
- setLoadingGroups(false);
193
- setCurrentGroup(selectedGroup);
194
- setDevicesToAdd([...[]]);
195
- fetchDevices(selectedGroup, selectedGroup);
196
- }
181
+ await handleAddDevicesToGroup(userInfo, selectedGroup, deviceSelectedObjs);
182
+ setLoadingGroups(false);
183
+ setCurrentGroup(selectedGroup);
184
+ setDevicesToAdd([...[]]);
185
+ fetchDevices(selectedGroup, selectedGroup);
197
186
  }
198
187
  catch (err) {
199
188
  console.error(err);
@@ -205,32 +194,10 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
205
194
  const removeFromCurrentGroup = async () => {
206
195
  setLoadingGroups(true);
207
196
  try {
208
- const devicesToRemove = devices.filter((row) => devicesToAdd.includes(row.id));
209
- const devicesToPatch = devicesToRemove?.map((device) => ({ id: device.id, groups: device.state.groups, managers: device.managers }));
210
- const devicesPatched = await handleRemoveDevicesFromGroup(userInfo, selectedGroup, devicesToPatch);
211
- if (devicesPatched && devicesPatched.length > 0) {
212
- for (const device of devicesToPatch) {
213
- if (device.managers.length > 0) {
214
- let managersToKeep = device.managers || [];
215
- for (const manager of device.managers) {
216
- // should check if device is present in other groups the user is member of
217
- const groupsData = await handleGetGroups(1008, { role: 'support', uid: manager });
218
- const userGroupIds = groupsData.map((group) => group.id);
219
- const found = device.groups && device.groups.some((gID) => userGroupIds.includes(gID));
220
- if (!found) {
221
- // @ts-ignore
222
- managersToKeep = managersToKeep.filter(man => man !== manager);
223
- }
224
- }
225
- await handleUpdateDevice(device.id, {
226
- managers: managersToKeep
227
- }, userInfo);
228
- }
229
- }
230
- setLoadingGroups(false);
231
- setDevicesToAdd([]);
232
- fetchDevices(currentGroup, selectedGroup);
233
- }
197
+ await handleRemoveDevicesFromGroup(userInfo, selectedGroup, deviceSelectedObjs);
198
+ setLoadingGroups(false);
199
+ setDevicesToAdd([]);
200
+ fetchDevices(currentGroup, selectedGroup);
234
201
  }
235
202
  catch (err) {
236
203
  console.error(err);
@@ -247,14 +214,62 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
247
214
  setCheckboxSelection(!checkboxSelection);
248
215
  };
249
216
  const renderMaps = (_jsx(Map, { positions: positions, mapsClickCallback: mapsClickCallback, height: mapsHeight }));
250
- const renderDataGrid = (_jsx("div", { style: { display: 'flex', flexDirection: 'column', minHeight: 323 }, children: _jsx(DataGrid, { checkboxSelection: checkboxSelection, onRowSelectionModelChange: (ids) => {
251
- if (checkboxSelection) {
252
- setDevicesToAdd(ids);
253
- }
254
- }, rowSelectionModel: devicesToAdd, disableDensitySelector: true, disableColumnSelector: true, disableRowSelectionOnClick: true, loading: loadingDevices, rows: devices, columns: checkboxSelection ? columnsArray.filter(col => col.field !== 'id') : columnsArray, slots: {
255
- noRowsOverlay: () => (_jsx(Stack, { height: "100%", alignItems: "center", justifyContent: "center", children: currentGroup !== 'all' ? _jsxs(_Fragment, { children: [_jsx(Box, { children: "No devices in group" }), editGroup ? _jsxs(Button, { onClick: () => addDevicesToCurrentGroup(), variant: "outlined", color: "primary", size: "small", sx: { mt: 2 }, children: [_jsx(PlaylistAddIcon, { fontSize: "small", sx: { mr: 1 } }), " Add devices"] }) : ''] }) : "No devices" })),
217
+ useEffect(() => {
218
+ if (devicesToAdd.length <= 0) {
219
+ setDeviceSelectedObjs([]);
220
+ }
221
+ }, [devicesToAdd]);
222
+ const CustomToolbar = useCallback((props) => (_jsxs("div", { style: { display: 'flex', padding: '8px', justifyContent: 'space-between', paddingTop: '2px' }, children: [_jsxs("div", { style: { display: 'flex', gap: 8, marginRight: '20px' }, children: [customToolbar && customToolbar.includes('filters') ?
223
+ _jsx(GridToolbarFilterButton, {})
224
+ : '', customToolbar && customToolbar.includes('export') ?
225
+ _jsx(GridToolbarExport, {})
226
+ : ''] }), customToolbar && customToolbar.includes('quickfilter') && _jsx(GridToolbarQuickFilter, {})] })), []);
227
+ const renderDataGrid = (_jsx("div", { style: { display: 'flex', flexDirection: 'column', minHeight: 323 }, children: _jsx(DataGrid, { checkboxSelection: checkboxSelection,
228
+ // Se siamo in modalità aggiunta, includi gli ID già nel gruppo
229
+ rowSelectionModel: (checkboxSelection && currentGroup === 'all')
230
+ ? [
231
+ ...devices
232
+ .filter(d => d.groups?.includes(selectedGroup))
233
+ .map(d => d.id.toString()),
234
+ ...devicesToAdd,
235
+ ]
236
+ : devicesToAdd,
237
+ // Se siamo in modalità aggiunta, disabilita la selezione per i già nel gruppo
238
+ isRowSelectable: params => {
239
+ return (checkboxSelection && currentGroup === 'all')
240
+ ? !params.row.groups?.includes(selectedGroup)
241
+ : true;
242
+ }, onCellClick: (params) => {
243
+ clickedIdRef.current = params.id.toString(); // aggiornamento immediato
244
+ }, onRowSelectionModelChange: (ids) => {
245
+ if (!checkboxSelection || !clickedIdRef.current)
246
+ return;
247
+ const clickedId = clickedIdRef.current;
248
+ clickedIdRef.current = null; // resetta subito dopo l’uso
249
+ setDevicesToAdd(prevIds => {
250
+ const updated = prevIds.includes(clickedId)
251
+ ? prevIds.filter(id => id !== clickedId)
252
+ : [...prevIds, clickedId];
253
+ return updated;
254
+ });
255
+ setDeviceSelectedObjs(prevObjs => {
256
+ const isDeselecting = prevObjs.some(d => d.id.toString() === clickedId);
257
+ if (isDeselecting) {
258
+ return prevObjs.filter(d => d.id.toString() !== clickedId);
259
+ }
260
+ else {
261
+ const device = devices.find(d => d.id.toString() === clickedId);
262
+ return device ? [...prevObjs, device] : prevObjs;
263
+ }
264
+ });
265
+ }, disableDensitySelector: true, disableColumnSelector: true, disableRowSelectionOnClick: true, loading: loadingDevices, rows: devices, columns: checkboxSelection
266
+ ? columnsArray.filter(col => col.field !== 'id')
267
+ : columnsArray, slots: {
268
+ noRowsOverlay: () => (_jsx(Stack, { height: "100%", alignItems: "center", justifyContent: "center", children: currentGroup !== 'all'
269
+ ? (_jsxs(_Fragment, { children: [_jsx(Box, { children: "No devices in group" }), editGroup && (_jsxs(Button, { onClick: addDevicesToCurrentGroup, variant: "outlined", color: "primary", size: "small", sx: { mt: 2 }, children: [_jsx(PlaylistAddIcon, { fontSize: "small", sx: { mr: 1 } }), addDevicesLabel || 'Add devices'] }))] }))
270
+ : "No devices" })),
256
271
  noResultsOverlay: () => (_jsx(Stack, { height: "100%", alignItems: "center", justifyContent: "center", children: "Filter returns no result" })),
257
- toolbar: GridToolbar,
272
+ toolbar: customToolbar && customToolbar.length ? CustomToolbar : GridToolbar,
258
273
  }, slotProps: {
259
274
  toolbar: {
260
275
  showQuickFilter: true,
@@ -262,9 +277,7 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
262
277
  printOptions: { disableToolbarButton: true },
263
278
  },
264
279
  }, initialState: {
265
- sorting: {
266
- sortModel: [{ field: 'online', sort: 'desc' }],
267
- },
280
+ pagination: { paginationModel: { pageSize: 100 } },
268
281
  }, ...propsDatagrid }) }));
269
282
  const renderTabContext = (_jsxs(TabContext, { value: valueTab, children: [_jsx(Box, { sx: { borderBottom: 1, borderColor: 'divider' }, children: _jsxs(TabList, { onChange: handleChangeTab, sx: { minHeight: 20 }, children: [_jsx(Tab, { label: "List", value: "1", sx: { minHeight: 20 } }), _jsx(Tab, { label: "Map", value: "2", sx: { minHeight: 20 } })] }) }), _jsx(TabPanel, { value: "1", sx: { p: 0 }, children: renderDataGrid }), _jsx(TabPanel, { value: "2", sx: { p: 0 }, children: renderMaps })] }));
270
283
  const renderDatagridAndMaps = (enableMaps ?
@@ -273,16 +286,16 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
273
286
  _jsx(Card, { ...containerProps, children: renderDataGrid }) : _jsx(Box, { ...containerProps, children: renderDataGrid }));
274
287
  if (!userInfo || !groups || !devices)
275
288
  return loadingComponent;
276
- return (_jsx(ThemeProvider, { theme: theme, children: _jsxs(Box, { ...props, children: [_jsxs(Box, { component: "div", sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 1, backgroundColor: editGroup ? 'secondary.light' : '', borderRadius: 3, px: editGroup ? 2 : 0, py: 1, height: 50 }, children: [editGroup ? _jsxs(Typography, { variant: 'subtitle1', children: [_jsx(Box, { component: 'span', sx: { display: { xs: 'none' } }, children: "Edit group" }), " ", _jsx("b", { children: groupInfo?.name })] }) : '', groups && !checkboxSelection && !(editGroup && currentGroup === 'all') ?
277
- _jsx(Autocomplete, { disablePortal: true, onChange: handleChangeGroupSelect, value: groupInfo?.name || 'All devices', disableClearable: currentGroup === 'all', isOptionEqualToValue: (o, v) => o.label === v, options: [{ label: 'All devices', id: 'all' }, ...groups.map((grp) => ({ label: grp.name, id: grp.id }))], sx: { width: { xs: 200, sm: 300 }, textAlign: 'left' }, size: 'small', renderInput: (params) => _jsx(TextField, { ...params, label: "Group" }) })
278
- : '', userInfo.role === 'admin' &&
279
- _jsxs(Box, { children: [checkboxSelection ?
289
+ return (_jsx(ThemeProvider, { theme: theme, children: _jsxs(Box, { ...props, children: [_jsxs(Box, { component: "div", sx: { display: 'flex', alignItems: 'center', mb: 1, backgroundColor: editGroup ? 'secondary.light' : '', borderRadius: 3, px: editGroup ? 2 : 0, py: 1, height: 50, ...propsHeaderGroups }, children: [editGroup ? _jsxs(Typography, { variant: 'subtitle1', children: [_jsx(Box, { component: 'span', sx: { display: { xs: 'none' } }, children: "Edit group" }), " ", _jsx("b", { children: groupInfo?.name })] }) : '', groups && !checkboxSelection && !(editGroup && currentGroup === 'all') ?
290
+ _jsx(Autocomplete, { disablePortal: true, onChange: handleChangeGroupSelect, value: groupInfo?.name || groupsLabelAll || 'All devices', disableClearable: currentGroup === 'all', isOptionEqualToValue: (o, v) => o.label === v, options: [{ label: groupsLabelAll || 'All devices', id: 'all' }, ...groups.map((grp) => ({ label: grp.name, id: grp.id }))], sx: { width: { xs: 200, sm: 300 }, textAlign: 'left' }, size: 'small', renderInput: (params) => _jsx(TextField, { ...params, label: "Group" }) })
291
+ : '', userInfo.role === 'admin' || (groupUpdateRoles && groupUpdateRoles.includes(userInfo.role)) &&
292
+ _jsxs(Box, { sx: { ml: 2 }, children: [checkboxSelection ?
280
293
  _jsx(Input, { value: selectedGroup, type: 'hidden', size: 'small' })
281
294
  : '', selectedGroup === 'all' ? _jsxs(Button, { variant: "contained", color: "primary", onClick: () => { handleOpenAdd(); }, children: [_jsx(AddIcon, { sx: { mr: 1 } }), _jsx(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: "Create\u00A0" }), " group"] }) : '', editGroup ?
282
295
  currentGroup === 'all' ?
283
- checkboxSelection ? _jsxs(_Fragment, { children: [_jsxs(Button, { onClick: () => { setGroupUpdateVisible(false); setDevicesToAdd([]); setCurrentGroup(selectedGroup); setCheckboxSelection(true); fetchDevices(selectedGroup, selectedGroup); }, variant: "text", color: "inherit", size: "small", children: [_jsx(BackIcon, { fontSize: "small" }), _jsx(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: "\u00A0Group devices" })] }), _jsxs(LoadingButton, { loading: loadingGroups, onClick: () => addToSelectedGroup(), variant: 'contained', size: "small", disabled: devicesToAdd.length === 0 || selectedGroup === 'all' || loadingGroups, sx: { ml: 2 }, children: [_jsx(ReadMoreIcon, { sx: { mr: 1 } }), " Add to group"] })] }) : ''
284
- : devicesToAdd.length === 0 ? groupUpdateVisible ? _jsxs(Button, { onClick: () => setGroupUpdateVisible(false), sx: { ml: 2 }, variant: "text", color: "inherit", size: "small", children: [_jsx(BackIcon, { fontSize: "small" }), _jsx(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: "\u00A0Group devices" })] }) :
285
- _jsxs(_Fragment, { children: [_jsxs(Button, { onClick: () => addDevicesToCurrentGroup(), sx: { ml: 2 }, variant: "outlined", color: "primary", size: "small", children: [_jsx(PlaylistAddIcon, { fontSize: "small", sx: { mr: 1 } }), " Add devices"] }), _jsxs(Button, { onClick: () => setGroupUpdateVisible(true), sx: { ml: 2 }, variant: "outlined", color: "success", size: "small", children: [_jsx(SettingsIcon, { fontSize: "small" }), _jsx(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: "\u00A0Manage group" })] })] })
296
+ checkboxSelection ? _jsxs(_Fragment, { children: [_jsxs(Button, { onClick: () => { setGroupUpdateVisible(false); setDevicesToAdd([]); setCurrentGroup(selectedGroup); setCheckboxSelection(true); fetchDevices(selectedGroup, selectedGroup); }, variant: "text", color: "inherit", size: "small", children: [_jsx(BackIcon, { fontSize: "small" }), _jsx(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: "\u00A0Back to group" })] }), _jsxs(LoadingButton, { loading: loadingGroups, onClick: () => addToSelectedGroup(), variant: 'contained', size: "small", disabled: devicesToAdd.length === 0 || selectedGroup === 'all' || loadingGroups, sx: { ml: 2 }, children: [_jsx(ReadMoreIcon, { sx: { mr: 1 } }), " Add to group"] })] }) : ''
297
+ : devicesToAdd.length === 0 ? groupUpdateVisible ? _jsxs(Button, { onClick: () => setGroupUpdateVisible(false), sx: { ml: 2 }, variant: "text", color: "inherit", size: "small", children: [_jsx(BackIcon, { fontSize: "small" }), _jsx(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: "\u00A0Back to group" })] }) :
298
+ _jsxs(_Fragment, { children: [_jsxs(Button, { onClick: () => addDevicesToCurrentGroup(), sx: { ml: 2 }, variant: "outlined", color: "primary", size: "small", children: [_jsx(PlaylistAddIcon, { fontSize: "small", sx: { mr: 1 } }), " ", addDevicesLabel || 'Add devices'] }), _jsxs(Button, { onClick: () => setGroupUpdateVisible(true), sx: { ml: 2 }, variant: "outlined", color: "success", size: "small", children: [_jsx(SettingsIcon, { fontSize: "small" }), _jsx(Box, { component: 'span', sx: { display: { xs: 'none', sm: 'inline' } }, children: "\u00A0Manage group" })] })] })
286
299
  : _jsxs(LoadingButton, { loading: loadingGroups, onClick: async () => { setLoadingGroups(true); await removeFromCurrentGroup(); }, variant: "contained", color: "error", size: "small", disabled: loadingGroups, sx: { ml: 2 }, children: [_jsx(PlaylistRemoveIcon, { fontSize: "small", sx: { mr: 1 } }), " Remove from group"] })
287
300
  : '', selectedGroup !== 'all' ?
288
301
  _jsx(_Fragment, { children: editGroup ?
@@ -294,6 +307,6 @@ const GroupsDevices = ({ userInfo, handleGetUsersList, handleAddUserToGroup, han
294
307
  transform: 'translate(-50%, -50%)',
295
308
  width: 400,
296
309
  borderRadius: 4
297
- }, children: [_jsx(CardHeader, { title: "New Group", action: _jsx(IconButton, { onClick: handleCloseAdd, children: _jsx(CloseIcon, {}) }) }), _jsx(CardContent, { children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TextField, { fullWidth: true, label: "Group Name", value: groupName, onChange: (e) => setGroupName(e.target.value), required: true }), _jsx(TextField, { fullWidth: true, label: "Description", value: description, onChange: (e) => setDescription(e.target.value), margin: "normal", multiline: true, rows: 4 }), _jsxs(Box, { mt: 2, display: "flex", justifyContent: "space-between", children: [_jsx(Button, { variant: "contained", color: "info", onClick: handleCloseAdd, children: "Cancel" }), _jsx(LoadingButton, { loading: loadingAdd, variant: "contained", color: "primary", type: "submit", children: "Create" })] })] }) })] }) }), !groupUpdateVisible && renderDatagridAndMaps, groupInfo && editGroup && groupUpdateVisible && _jsx(GroupUpdate, { confirmMui: confirmMui, userInfo: userInfo, usersGroup: usersGroup, usersList: usersList, handleGetGroups: handleGetGroups, handleUpdateDevice: handleUpdateDevice, handleAddUserToGroup: handleAddUserToGroup, handleRemoveUserFromGroup: handleRemoveUserFromGroup, groupInfo: groupInfo, afterUpdateCallback: async (groupInfo) => { setGroupInfo(groupInfo); await getGroups(); await getUsersGroup(groupInfo.id); }, afterRemoveCallback: async () => { closeEditGroup(); await getGroups(); setCurrentGroup('all'); }, container: 'Card', handleDeleteGroup: handleDeleteGroup, handleUpdateGroup: handleUpdateGroup, devicesList: devices.map((device) => ({ id: device.id, state: device.state, managers: device.managers })) })] }) }));
310
+ }, children: [_jsx(CardHeader, { title: "New Group", action: _jsx(IconButton, { onClick: handleCloseAdd, children: _jsx(CloseIcon, {}) }) }), _jsx(CardContent, { children: _jsxs("form", { onSubmit: handleSubmit, children: [_jsx(TextField, { fullWidth: true, label: "Group Name", value: groupName, onChange: (e) => setGroupName(e.target.value), required: true }), _jsx(TextField, { fullWidth: true, label: "Description", value: description, onChange: (e) => setDescription(e.target.value), margin: "normal", multiline: true, rows: 4 }), _jsxs(Box, { mt: 2, display: "flex", justifyContent: "space-between", children: [_jsx(Button, { variant: "contained", color: "info", onClick: handleCloseAdd, children: "Cancel" }), _jsx(LoadingButton, { loading: loadingAdd, variant: "contained", color: "primary", type: "submit", children: "Create" })] })] }) })] }) }), !groupUpdateVisible && renderDatagridAndMaps, groupInfo && editGroup && groupUpdateVisible && _jsx(GroupUpdate, { confirmMui: confirmMui, userInfo: userInfo, usersGroup: usersGroup, usersList: usersList, handleGetGroups: handleGetGroups, handleUpdateDevice: handleUpdateDevice, handleAddUserToGroup: handleAddUserToGroup, handleRemoveUserFromGroup: handleRemoveUserFromGroup, groupInfo: groupInfo, afterUpdateCallback: async (groupInfo) => { setGroupInfo(groupInfo); await getGroups(); await getUsersGroup(groupInfo.id); }, afterRemoveCallback: async () => { closeEditGroup(); await getGroups(); setCurrentGroup('all'); }, container: 'Card', handleDeleteGroup: handleDeleteGroup, handleUpdateGroup: handleUpdateGroup, devicesList: devices })] }) }));
298
311
  };
299
312
  export default GroupsDevices;
@@ -1,14 +1,9 @@
1
1
  import 'leaflet/dist/leaflet.css';
2
2
  import "leaflet-defaulticon-compatibility";
3
3
  import "leaflet-defaulticon-compatibility/dist/leaflet-defaulticon-compatibility.css";
4
- export type Position = {
5
- deviceID: string;
6
- name: string;
7
- lat: number;
8
- lng: number;
9
- };
4
+ import { DevicePositionType } from "../../types/device";
10
5
  export default function Map({ positions, height, mapsClickCallback }: {
11
- positions: Position[];
6
+ positions: DevicePositionType[];
12
7
  height: string;
13
- mapsClickCallback: (position: Position) => void;
8
+ mapsClickCallback: (position: DevicePositionType) => void;
14
9
  }): import("react/jsx-runtime").JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { SvgIconProps } from "@mui/material/SvgIcon";
2
2
  import { Theme } from "@emotion/react";
3
+ import React from "react";
3
4
  interface MenuItem {
4
5
  name: string;
5
6
  description: string;
@@ -4,6 +4,7 @@ import { createElement, useState } from "react";
4
4
  import { Box, Card, CardContent, List, ListItemButton, ListItemText, styled, ThemeProvider } from "@mui/material";
5
5
  import Grid from "@mui/material/Grid2";
6
6
  import NavigateNextIcon from "@mui/icons-material/NavigateNext";
7
+ import React from "react";
7
8
  const ListItemButtonSettings = styled(ListItemButton)(({ theme, selected }) => ({
8
9
  backgroundColor: theme.palette.primary.main,
9
10
  color: theme.palette.primary.contrastText,
@@ -37,6 +38,6 @@ const DynamicMenu = ({ menuItems, selectedIndex = null, theme }) => {
37
38
  const handleMenuClick = (index) => {
38
39
  setSelected(index); // Assicurati di non chiamarlo nel rendering
39
40
  };
40
- return (_jsx(ThemeProvider, { theme: theme, children: _jsx(Grid, { container: true, spacing: 2, sx: { width: '100%' }, children: _jsx(Grid, { size: { xs: 12, lg: 9 }, children: _jsx(Card, { sx: { borderRadius: 2 }, children: _jsx(CardContent, { sx: { p: 0, "&:last-child": { p: 0 } }, children: _jsxs(Grid, { container: true, spacing: 2, children: [_jsx(Grid, { size: { xs: 12, sm: 4 }, sx: { display: { xs: selected !== null ? 'none' : 'block', sm: 'block' } }, children: _jsx(List, { sx: { p: 0, height: "100%", backgroundColor: "primary.main" }, children: menuItems.map((item, index) => (_jsxs(ListItemButtonSettings, { selected: selected === index, onClick: () => handleMenuClick(index), children: [item.icon && _jsx(Box, { sx: { mr: 2 }, children: item.icon }), _jsx(ListItemText, { primary: _jsx("b", { children: item.name }), secondary: item.description }), _jsx(NavigateNextIcon, { sx: { display: { xs: "block", sm: "none" } } })] }, index))) }) }), _jsx(Grid, { size: { xs: 12, sm: 8, md: 6 }, sx: { display: { xs: selected === null ? 'none' : 'block', sm: 'block' } }, children: _jsx(Box, { component: "div", sx: { p: { xs: 2 }, py: { sm: 3 } }, children: selected !== null ? createElement(menuItems[selected].page, { handleBack: () => { setSelected(null); } }) : "" }) })] }) }) }) }) }) }));
41
+ return (_jsx(ThemeProvider, { theme: theme, children: _jsx(Grid, { container: true, spacing: 2, sx: { width: '100%' }, children: _jsx(Grid, { size: { xs: 12, lg: 9 }, children: _jsx(Card, { sx: { borderRadius: 2 }, children: _jsx(CardContent, { sx: { p: 0, "&:last-child": { p: 0 } }, children: _jsxs(Grid, { container: true, spacing: 2, children: [_jsx(Grid, { size: { xs: 12, sm: 4 }, sx: { display: { xs: selected !== null ? 'none' : 'block', sm: 'block' } }, children: _jsx(List, { sx: { p: 0, height: "100%", backgroundColor: "primary.main" }, children: menuItems.map((item, index) => (_jsxs(ListItemButtonSettings, { selected: selected === index, onClick: () => handleMenuClick(index), children: [item.icon && _jsx(Box, { sx: { mr: 2 }, children: React.isValidElement(item.icon) ? item.icon : null }), _jsx(ListItemText, { primary: _jsx("b", { children: item.name }), secondary: item.description }), _jsx(NavigateNextIcon, { sx: { display: { xs: "block", sm: "none" } } })] }, index))) }) }), _jsx(Grid, { size: { xs: 12, sm: 8, md: 6 }, sx: { display: { xs: selected === null ? 'none' : 'block', sm: 'block' } }, children: _jsx(Box, { component: "div", sx: { p: { xs: 2 }, py: { sm: 3 } }, children: selected !== null ? createElement(menuItems[selected].page, { handleBack: () => { setSelected(null); } }) : "" }) })] }) }) }) }) }) }));
41
42
  };
42
43
  export default DynamicMenu;
@@ -1,7 +1,8 @@
1
+ import { GridSortModel } from '@mui/x-data-grid';
1
2
  import { UserType } from '../../types/user';
2
3
  import { Theme } from '@emotion/react';
3
- declare const UsersDataGrid: ({ handleGetUsersList, pageSize, container, containerProps, props, loadingComponent, theme }: {
4
- handleGetUsersList: ({ page, pageSize, filter }: {
4
+ declare const UsersDataGrid: ({ handleGetUsersList, pageSize, container, containerProps, props, loadingComponent, theme, columns }: {
5
+ handleGetUsersList: ({ page, pageSize, filter, sortModel }: {
5
6
  page: number;
6
7
  pageSize: number;
7
8
  filter?: {
@@ -9,6 +10,7 @@ declare const UsersDataGrid: ({ handleGetUsersList, pageSize, container, contain
9
10
  operator?: string;
10
11
  value: string;
11
12
  };
13
+ sortModel: GridSortModel;
12
14
  }) => Promise<{
13
15
  users: UserType[];
14
16
  rowCount: number;
@@ -19,5 +21,6 @@ declare const UsersDataGrid: ({ handleGetUsersList, pageSize, container, contain
19
21
  props?: object | undefined;
20
22
  loadingComponent?: React.ReactNode;
21
23
  theme: Theme;
24
+ columns: any[];
22
25
  }) => string | number | bigint | boolean | import("react/jsx-runtime").JSX.Element | Iterable<import("react").ReactNode> | Promise<import("react").AwaitedReactNode> | null;
23
26
  export default UsersDataGrid;