diff --git a/src/vertex/app/changelog.md b/src/vertex/app/changelog.md
index d87503fbea..6e8cfeb24c 100644
--- a/src/vertex/app/changelog.md
+++ b/src/vertex/app/changelog.md
@@ -4,6 +4,50 @@
---
+## Version 1.23.44
+**Released:** May 19, 2026
+
+### Device Management Scoped Banner Migration & Mutation Callback Cleanup
+
+Migrated feedback notifications from global floating toasts (`ReusableToast`) to context-aware `InfoBanner` components (`useBanner`) inside device management modules to keep alerts inline and centered within their active modal or dialog containers. Refactored React Query hook callbacks to push feedback responsibility to the UI components.
+
+
+Device Management — Scoped Banner Migration (7)
+
+- **Create Device Modal**: Integrated `useBanner` for scoped validation and creation alerts. The `showBanner` utility replaces the old inline red error block for missing network errors.
+- **Import Device Modal**: Integrated `useBanner` to surface a previously silent missing user ID warning and errors. Replaced old inline red error alerts and fixed a critical TypeScript compilation error where `importDevice.mutate()` was called with 3 arguments instead of 1-2 by merging the `onSuccess` and `onError` options into a single second argument. Added missing `getApiErrorMessage` import.
+- **Add Maintenance Log Modal**: Replaced `ReusableToast` with scoped `showBanner` for validation errors to align modal design feedback.
+- **Deploy Device Component**: Swapped 3 occurrences of `ReusableToast` with `showBanner` alerts.
+- **Recall Device Dialog**: Added `useBanner` support and shifted all success and error UI notifications from raw hook callbacks directly to try/catch blocks within the component.
+- **Device Details Modal**: Migrated all validation, detail update, and key decryption feedback from floating toasts to `showBanner`. Added local callback overrides to the `updateLocal` and `updateGlobal` mutate invocations.
+- **Device Assignment Modal**: Added `useBanner` with `scoped: false` (since this dialog extends base Radix `Dialog` rather than `ReusableDialog`), keeping assignment feedback in the modal itself instead of hook side-effects.
+
+
+
+
+Custom Hook & Callback Separation (1)
+
+- **useDevices Hooks Overhaul**: Removed imperative `ReusableToast` side-effects from `useRecallDevice`, `useUpdateDeviceLocal`, `useUpdateDeviceGlobal`, `useAssignDeviceToOrganization`, and `useDecryptDeviceKeys`. Hooks are now clean, focused solely on API interactions and cache invalidation.
+
+
+
+
+Files Modified (8)
+
+- `src/vertex/app/changelog.md` [MODIFIED]
+- `src/vertex/components/features/devices/create-device-modal.tsx` [MODIFIED]
+- `src/vertex/components/features/devices/import-device-modal.tsx` [MODIFIED]
+- `src/vertex/components/features/devices/add-maintenance-log-modal.tsx` [MODIFIED]
+- `src/vertex/components/features/devices/deploy-device-component.tsx` [MODIFIED]
+- `src/vertex/components/features/devices/recall-device-dialog.tsx` [MODIFIED]
+- `src/vertex/components/features/devices/device-details-modal.tsx` [MODIFIED]
+- `src/vertex/components/features/devices/device-assignment-modal.tsx` [MODIFIED]
+- `src/vertex/core/hooks/useDevices.ts` [MODIFIED]
+
+
+
+---
+
## Version 1.23.43
**Released:** May 17, 2026
diff --git a/src/vertex/components/features/devices/add-maintenance-log-modal.tsx b/src/vertex/components/features/devices/add-maintenance-log-modal.tsx
index 477f9b58fc..fe6a7917cf 100644
--- a/src/vertex/components/features/devices/add-maintenance-log-modal.tsx
+++ b/src/vertex/components/features/devices/add-maintenance-log-modal.tsx
@@ -9,7 +9,8 @@ import { useUserContext } from "@/core/hooks/useUserContext";
import { MultiSelectCombobox } from "@/components/ui/multi-select";
import { Switch } from "@/components/ui/switch";
import ReusableDialog from "@/components/shared/dialog/ReusableDialog";
-import ReusableToast from "@/components/shared/toast/ReusableToast";
+import { useBanner } from "@/context/banner-context";
+import { getApiErrorMessage } from "@/core/utils/getApiErrorMessage";
interface AddMaintenanceLogModalProps {
open: boolean;
@@ -51,6 +52,7 @@ const AddMaintenanceLogModal: React.FC = ({ open, o
const [maintenanceType, setMaintenanceType] = useState<"preventive" | "corrective">("preventive");
const { userDetails } = useUserContext();
+ const { showBanner } = useBanner();
const addMaintenanceLog = useAddMaintenanceLog();
// Reset form when modal opens/closes
@@ -65,7 +67,7 @@ const AddMaintenanceLogModal: React.FC = ({ open, o
const handleSubmit = async () => {
if (!date || selectedTags.length === 0) {
- ReusableToast({message: "Please fill all fields", type:"ERROR"})
+ showBanner({ severity: 'error', message: 'Please fill all required fields', scoped: true });
return;
}
@@ -81,8 +83,20 @@ const AddMaintenanceLogModal: React.FC = ({ open, o
user_id: userDetails?._id || "",
};
- await addMaintenanceLog.mutateAsync({ deviceName, logData });
- onOpenChange(false);
+ try {
+ await addMaintenanceLog.mutateAsync({ deviceName, logData });
+ setTimeout(() => {
+ showBanner({
+ severity: 'success',
+ title: 'Success',
+ message: `Maintenance log for ${deviceName} has been added successfully.`,
+ scoped: false
+ });
+ }, 300);
+ onOpenChange(false);
+ } catch (error) {
+ showBanner({ severity: 'error', message: `Failed to Add Maintenance Log: ${getApiErrorMessage(error)}`, scoped: true });
+ }
};
return (
diff --git a/src/vertex/components/features/devices/create-device-modal.tsx b/src/vertex/components/features/devices/create-device-modal.tsx
index 9d782806af..9f6b0bfb0d 100644
--- a/src/vertex/components/features/devices/create-device-modal.tsx
+++ b/src/vertex/components/features/devices/create-device-modal.tsx
@@ -10,6 +10,8 @@ import ReusableSelectInput from "@/components/shared/select/ReusableSelectInput"
import { MultiSelectCombobox } from "@/components/ui/multi-select";
import { DEFAULT_DEVICE_TAGS } from "@/core/constants/devices";
import { Label } from "@/components/ui/label";
+import { useBanner } from "@/context/banner-context";
+import { getApiErrorMessage } from "@/core/utils/getApiErrorMessage";
interface CreateDeviceModalProps {
open: boolean;
@@ -30,6 +32,7 @@ const CreateDeviceModal: React.FC = ({
});
const [errors, setErrors] = useState>({});
+ const { showBanner } = useBanner();
const activeNetwork = useAppSelector((state) => state.user.activeNetwork);
const createDevice = useCreateDevice();
@@ -56,7 +59,7 @@ const CreateDeviceModal: React.FC = ({
const effectiveNetworkName = networkName || activeNetwork?.net_name;
if (!effectiveNetworkName) {
- setErrors({ general: "No active Sensor Manufacturer found" });
+ showBanner({ severity: 'error', message: 'No active Sensor Manufacturer found', scoped: true });
return;
}
@@ -67,20 +70,26 @@ const CreateDeviceModal: React.FC = ({
description: formData.description.trim() || undefined,
network: effectiveNetworkName,
tags: formData.tags,
+ }, {
+ onSuccess: (data, variables) => {
+ setTimeout(() => {
+ showBanner({
+ severity: 'success',
+ title: 'Success',
+ message: `${variables.long_name.trim()} has been created successfully.`,
+ scoped: false
+ });
+ }, 300);
+ setFormData({ long_name: "", category: "", description: "", tags: [] });
+ setErrors({});
+ onOpenChange(false);
+ },
+ onError: (error) => {
+ showBanner({ severity: 'error', message: `Creation Failed: ${getApiErrorMessage(error)}`, scoped: true });
+ },
});
-
- // Reset form and close modal
- setFormData({
- long_name: "",
- category: "",
- description: "",
- tags: [],
- });
- setErrors({});
- onOpenChange(false);
} catch (error) {
- // Error handling is done in the hook
- console.error("Create device failed:", error);
+ showBanner({ severity: 'error', message: `Creation Failed: ${getApiErrorMessage(error)}`, scoped: true });
}
};
@@ -136,11 +145,6 @@ const CreateDeviceModal: React.FC = ({
}}
>
- {errors.general && (
-
- {errors.general}
-
- )}
import("../mini-map/mini-map"));
@@ -427,6 +428,7 @@ const DeployDeviceComponent = ({
onDeploymentError
}: DeployDeviceComponentProps) => {
const queryClient = useQueryClient();
+ const { showBanner } = useBanner();
const { userScope, userDetails } = useUserContext();
const { devices: allDevices } = useDevices({ enabled: userScope !== 'personal' });
const [currentStep, setCurrentStep] = React.useState(0);
@@ -608,10 +610,7 @@ const DeployDeviceComponent = ({
const handleNext = (): void => {
if (currentStep === 0 && !validateDeviceDetails()) {
- ReusableToast({
- type: "ERROR",
- message: "Incomplete Details: Please fill in all required device details.",
- });
+ showBanner({ severity: 'error', message: 'Incomplete Details: Please fill in all required device details.', scoped: true });
return;
}
setCurrentStep((prev) => Math.min(prev + 1, siteSource === 'new' ? 2 : 1));
@@ -642,18 +641,12 @@ const DeployDeviceComponent = ({
const handleDeploy = (): void => {
if (!userDetails?._id) {
- ReusableToast({
- type: "ERROR",
- message: "User information not available. Please reload the page.",
- });
+ showBanner({ severity: 'error', message: 'User information not available. Please reload the page.', scoped: true });
return;
}
if (siteSource === 'previous' && !deviceData.site_id) {
- ReusableToast({
- type: "ERROR",
- message: "Select a previous site to continue.",
- });
+ showBanner({ severity: 'error', message: 'Select a previous site to continue.', scoped: true });
return;
}
@@ -686,7 +679,15 @@ const DeployDeviceComponent = ({
queryClient.invalidateQueries({ queryKey: ["device-details", prefilledDevice._id] });
}
- // On successful deployment, reset form fields
+ setTimeout(() => {
+ showBanner({
+ severity: 'success',
+ title: 'Success',
+ message: `${deviceData.deviceName} has been deployed successfully.`,
+ scoped: false
+ });
+ }, 300);
+
setDeviceData({
deviceName: "",
deployment_date: undefined,
@@ -709,6 +710,22 @@ const DeployDeviceComponent = ({
if (onClose) onClose();
},
onError: (error) => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const errorData = (error as any)?.response?.data;
+ let errorMessage = getApiErrorMessage(error);
+
+ if (errorData?.failed_deployments?.length > 0) {
+ const failedMessages = errorData.failed_deployments
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ .map((deployment: any) => deployment.error?.message)
+ .filter(Boolean);
+
+ if (failedMessages.length > 0) {
+ errorMessage = failedMessages.join(', ');
+ }
+ }
+
+ showBanner({ severity: 'error', message: `Deployment Failed: ${errorMessage}`, scoped: true });
onDeploymentError?.(error instanceof Error ? error : new Error("Unknown error"));
},
}
diff --git a/src/vertex/components/features/devices/device-assignment-modal.tsx b/src/vertex/components/features/devices/device-assignment-modal.tsx
index 889d4b7e62..651d68e060 100644
--- a/src/vertex/components/features/devices/device-assignment-modal.tsx
+++ b/src/vertex/components/features/devices/device-assignment-modal.tsx
@@ -13,6 +13,8 @@ import { Button } from "@/components/ui/button";
import { useAppSelector } from "@/core/redux/hooks";
import { Device } from "@/app/types/devices";
import { useAssignDeviceToOrganization } from "@/core/hooks/useDevices";
+import { useBanner } from "@/context/banner-context";
+import { getApiErrorMessage } from "@/core/utils/getApiErrorMessage";
import { Label } from "@/components/ui/label";
import { ComboBox } from "@/components/ui/combobox";
import { useRouter } from "next/navigation";
@@ -45,16 +47,28 @@ const DeviceAssignmentModal: React.FC = ({
const [selectedDevice, setSelectedDevice] = useState("");
const assignDevice = useAssignDeviceToOrganization();
+ const { showBanner } = useBanner();
const handleAssign = async () => {
if (!selectedOrganization || !selectedDevice || !userDetails?._id) return;
- await assignDevice.mutateAsync({
- device_name: selectedDevice,
- organization_id: selectedOrganization,
- user_id: userDetails._id,
- });
- onSuccess();
+ try {
+ const data = await assignDevice.mutateAsync({
+ device_name: selectedDevice,
+ organization_id: selectedOrganization,
+ user_id: userDetails._id,
+ });
+ setTimeout(() => {
+ showBanner({
+ severity: 'success',
+ title: 'Success',
+ message: `${data.device.name} has been assigned successfully.`,
+ });
+ }, 300);
+ onSuccess();
+ } catch (error) {
+ showBanner({ severity: 'error', message: `Assignment Failed: ${getApiErrorMessage(error)}`, scoped: false });
+ }
};
const handleClose = () => {
diff --git a/src/vertex/components/features/devices/device-details-modal.tsx b/src/vertex/components/features/devices/device-details-modal.tsx
index 8e468d8fb0..3fde74c5b3 100644
--- a/src/vertex/components/features/devices/device-details-modal.tsx
+++ b/src/vertex/components/features/devices/device-details-modal.tsx
@@ -14,7 +14,8 @@ import ReusableButton from "@/components/shared/button/ReusableButton";
import ReusableSelectInput from "@/components/shared/select/ReusableSelectInput";
import ReusableInputField from "@/components/shared/inputfield/ReusableInputField";
import { AqEdit01 as AqEdit, AqKey01 } from "@airqo/icons-react";
-import ReusableToast from "@/components/shared/toast/ReusableToast";
+import { useBanner } from "@/context/banner-context";
+import { getApiErrorMessage } from "@/core/utils/getApiErrorMessage";
import logger from "@/lib/logger";
interface DeviceDetailsModalProps {
@@ -60,6 +61,7 @@ const DeviceDetailsModal: React.FC = ({ open, device, o
const updateLocal = useUpdateDeviceLocal();
const updateGlobal = useUpdateDeviceGlobal();
const decryptKeys = useDecryptDeviceKeys();
+ const { showBanner } = useBanner();
const form = useForm({
resolver: zodResolver(deviceUpdateSchema),
@@ -132,7 +134,7 @@ const DeviceDetailsModal: React.FC = ({ open, device, o
const onSubmitLocal = async (data: DeviceUpdateFormData) => {
if (!device?._id) {
- ReusableToast({ message: "Cannot update device: missing device ID", type: "WARNING" });
+ showBanner({ severity: 'warning', message: "Cannot update device: missing device ID", scoped: true });
return;
}
@@ -168,16 +170,20 @@ const DeviceDetailsModal: React.FC = ({ open, device, o
{ deviceId: device._id, deviceData: processedData },
{
onSuccess: () => {
+ showBanner({ severity: 'success', message: 'Device information has been updated locally.', scoped: true });
setIsEditMode(false);
form.reset(data);
},
+ onError: (error) => {
+ showBanner({ severity: 'error', message: `Update Failed: ${getApiErrorMessage(error)}`, scoped: true });
+ },
}
);
};
const onSubmitGlobal = async (data: DeviceUpdateFormData) => {
if (!device?._id) {
- ReusableToast({ message: "Cannot update device: missing device ID", type: "WARNING" });
+ showBanner({ severity: 'warning', message: "Cannot update device: missing device ID", scoped: true });
return;
}
@@ -213,9 +219,13 @@ const DeviceDetailsModal: React.FC = ({ open, device, o
{ deviceId: device._id, deviceData: processedData },
{
onSuccess: () => {
+ showBanner({ severity: 'success', message: 'Device information has been updated globally.', scoped: true });
setIsEditMode(false);
form.reset(data);
},
+ onError: (error) => {
+ showBanner({ severity: 'error', message: `Sync Failed: ${getApiErrorMessage(error)}`, scoped: true });
+ },
}
);
};
@@ -224,9 +234,9 @@ const DeviceDetailsModal: React.FC = ({ open, device, o
if (valueToCopy !== undefined && valueToCopy !== null) {
try {
await navigator.clipboard?.writeText(String(valueToCopy))
- ReusableToast({ message: "Decrypted Key Copied", type: "SUCCESS" })
+ showBanner({ severity: 'success', message: "Decrypted Key Copied", scoped: true });
} catch (err) {
- ReusableToast({ message: `Failed to copy key: ${String(err)}`, type: "ERROR" })
+ showBanner({ severity: 'error', message: `Failed to copy key: ${String(err)}`, scoped: true });
}
}
}
@@ -236,7 +246,7 @@ const DeviceDetailsModal: React.FC = ({ open, device, o
const deviceNumber = device.device_number;
if (!encryptedKey || !deviceNumber) {
- ReusableToast({ message: `No ${keyType} or device number available for decryption.`, type: "WARNING" });
+ showBanner({ severity: 'warning', message: `No ${keyType} or device number available for decryption.`, scoped: true });
return;
}
@@ -251,10 +261,11 @@ const DeviceDetailsModal: React.FC = ({ open, device, o
if (response.success && response.decrypted_keys && response.decrypted_keys.length > 0) {
handleCopy(response.decrypted_keys[0].decrypted_key);
} else {
- ReusableToast({ message: "Decryption failed or no key returned.", type: "ERROR" });
+ showBanner({ severity: 'error', message: "Decryption failed or no key returned.", scoped: true });
}
- } catch {
- logger.info("Decryption failed"); // simple log
+ } catch (error) {
+ showBanner({ severity: 'error', message: `Decryption Failed: ${getApiErrorMessage(error)}`, scoped: true });
+ logger.info("Decryption failed");
}
};
diff --git a/src/vertex/components/features/devices/import-device-modal.tsx b/src/vertex/components/features/devices/import-device-modal.tsx
index aee08f5417..a757485705 100644
--- a/src/vertex/components/features/devices/import-device-modal.tsx
+++ b/src/vertex/components/features/devices/import-device-modal.tsx
@@ -13,10 +13,13 @@ import { useGroupCohorts } from "@/core/hooks/useCohorts";
import { useAppSelector } from "@/core/redux/hooks";
import { usePathname } from "next/navigation";
import logger from "@/lib/logger";
+import { useBanner } from "@/context/banner-context";
import { NetworkRequestDialog } from "../networks/network-request-dialog";
import { MultiSelectCombobox } from "@/components/ui/multi-select";
import { DEFAULT_DEVICE_TAGS } from "@/core/constants/devices";
import { Label } from "@/components/ui/label";
+import { getApiErrorMessage } from "@/core/utils/getApiErrorMessage";
+
interface ImportDeviceModalProps {
open: boolean;
@@ -45,6 +48,7 @@ const ImportDeviceModal: React.FC = ({
const [showMore, setShowMore] = useState(false);
const [isRequestDialogOpen, setIsRequestDialogOpen] = useState(false);
const [errors, setErrors] = useState>({});
+ const { showBanner } = useBanner();
const importDevice = useImportDevice();
const { networks, isLoading: isLoadingNetworks } = useNetworks();
@@ -108,6 +112,7 @@ const ImportDeviceModal: React.FC = ({
if (!userId) {
logger.warn("User ID is missing");
+ showBanner({ severity: 'error', message: 'Unable to identify user. Please reload and try again.', scoped: true });
return;
}
@@ -117,7 +122,22 @@ const ImportDeviceModal: React.FC = ({
user_id: userId,
...(cohortId && { cohort_id: cohortId }),
},
- { onSuccess: () => onOpenChange(false) }
+ {
+ onSuccess: (data, variables) => {
+ onOpenChange(false);
+ setTimeout(() => {
+ showBanner({
+ severity: 'success',
+ title: 'Success',
+ message: `${variables.long_name.trim()} has been imported successfully.`,
+ scoped: false
+ });
+ }, 300);
+ },
+ onError: (error) => {
+ showBanner({ severity: 'error', message: `Import Failed: ${getApiErrorMessage(error)}`, scoped: true });
+ },
+ }
);
};
@@ -180,11 +200,6 @@ const ImportDeviceModal: React.FC = ({
}}
>
- {errors.general && (
-
- {errors.general}
-
- )}
("");
const recallDevice = useRecallDevice();
const { userDetails } = useUserContext();
+ const { showBanner } = useBanner();
const handleRecall = async () => {
if (!recallType || !userDetails?._id) {
@@ -46,13 +49,18 @@ export default function RecallDeviceDialog({
userName: userDetails.userName,
},
});
-
- // Reset form and close dialog
+ setTimeout(() => {
+ showBanner({
+ severity: 'success',
+ title: 'Success',
+ message: `${deviceDisplayName || deviceName} has been recalled successfully.`,
+ scoped: false
+ });
+ }, 300);
setRecallType("");
onOpenChange(false);
} catch (error) {
- // Error handling is done in the hook
- console.error("Recall failed:", error);
+ showBanner({ severity: 'error', message: `Recall Failed: ${getApiErrorMessage(error)}`, scoped: true });
}
};
diff --git a/src/vertex/core/hooks/useDevices.ts b/src/vertex/core/hooks/useDevices.ts
index e130c3b09c..6aa7c09f29 100644
--- a/src/vertex/core/hooks/useDevices.ts
+++ b/src/vertex/core/hooks/useDevices.ts
@@ -349,20 +349,10 @@ export const useAssignDeviceToOrganization = () => {
DeviceAssignmentRequest
>({
mutationFn: devices.assignDeviceToOrganization,
- onSuccess: data => {
- ReusableToast({
- message: `${data.device.name} has been assigned to the organization.`,
- type: 'SUCCESS',
- });
+ onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['myDevices'] });
queryClient.invalidateQueries({ queryKey: ['devices'] });
},
- onError: error => {
- ReusableToast({
- message: `Assignment Failed: ${getApiErrorMessage(error)}`,
- type: 'ERROR',
- });
- },
});
};
@@ -413,21 +403,11 @@ export const useUpdateDeviceLocal = () => {
deviceData: Partial;
}) => devices.updateDeviceLocal(deviceId, deviceData),
onSuccess: (data, variables) => {
- ReusableToast({
- message: 'Device information has been updated locally.',
- type: 'SUCCESS',
- });
queryClient.invalidateQueries({
queryKey: ['device-details', variables.deviceId],
});
queryClient.invalidateQueries({ queryKey: ['devices'] });
},
- onError: (error: AxiosError) => {
- ReusableToast({
- message: `Update Failed: ${getApiErrorMessage(error)}`,
- type: 'ERROR',
- });
- },
});
};
@@ -443,21 +423,11 @@ export const useUpdateDeviceGlobal = () => {
deviceData: Partial;
}) => devices.updateDeviceGlobal(deviceId, deviceData),
onSuccess: (data, variables) => {
- ReusableToast({
- message: 'Device information has been updated globally.',
- type: 'SUCCESS',
- });
queryClient.invalidateQueries({
queryKey: ['device-details', variables.deviceId],
});
queryClient.invalidateQueries({ queryKey: ['devices'] });
},
- onError: (error: AxiosError) => {
- ReusableToast({
- message: `Sync Failed: ${getApiErrorMessage(error)}`,
- type: 'ERROR',
- });
- },
});
};
@@ -517,11 +487,7 @@ export const useCreateDevice = () => {
};
return devices.createDevice(payload);
},
- onSuccess: (data, variables) => {
- ReusableToast({
- message: `${variables.long_name} has been created.`,
- type: 'SUCCESS',
- });
+ onSuccess: (data) => {
if (data.created_device && activeGroup?.grp_title) {
updateDeviceGroup.mutate({
deviceId: data.created_device._id || '',
@@ -532,12 +498,6 @@ export const useCreateDevice = () => {
queryClient.invalidateQueries({ queryKey: ['network-devices'] });
queryClient.invalidateQueries({ queryKey: ['deviceActivities'] });
},
- onError: error => {
- ReusableToast({
- message: `Creation Failed: ${getApiErrorMessage(error)}`,
- type: 'ERROR',
- });
- },
});
};
@@ -575,12 +535,7 @@ export const useImportDevice = () => {
};
return devices.importDevice(payload);
},
- onSuccess: (data, variables) => {
- ReusableToast({
- message: `${variables.long_name} has been imported.`,
- type: 'SUCCESS',
- });
-
+ onSuccess: () => {
// Refresh based on active module
if (isAdminModule) {
queryClient.invalidateQueries({ queryKey: ['network-devices'] });
@@ -595,13 +550,7 @@ export const useImportDevice = () => {
queryClient.invalidateQueries({ queryKey: ['deviceActivities'] });
}
}
- },
- onError: error => {
- ReusableToast({
- message: `Import Failed: ${getApiErrorMessage(error)}`,
- type: 'ERROR',
- });
- },
+ }
});
};
@@ -627,36 +576,12 @@ export const useDeployDevice = () => {
email?: string;
userName?: string;
}) => devices.deployDevice(deviceData),
- onSuccess: (data, variables) => {
- ReusableToast({
- message: `${variables.deviceName} has been deployed.`,
- type: 'SUCCESS',
- });
+ onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['devices'] });
queryClient.invalidateQueries({ queryKey: ['claimedDevices'] });
queryClient.invalidateQueries({ queryKey: ['myDevices'] });
queryClient.invalidateQueries({ queryKey: ['deviceActivities'] });
},
- onError: (error: AxiosError) => {
- let errorMessage = getApiErrorMessage(error);
- const errorData = error.response?.data as any;
-
- if (errorData?.failed_deployments?.length > 0) {
- const failedMessages = errorData.failed_deployments
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- .map((deployment: any) => deployment.error?.message)
- .filter(Boolean);
-
- if (failedMessages.length > 0) {
- errorMessage = failedMessages.join(', ');
- }
- }
-
- ReusableToast({
- message: `Deployment Failed: ${errorMessage}`,
- type: 'ERROR',
- });
- },
});
};
@@ -680,21 +605,11 @@ export const useRecallDevice = () => {
};
}) => devices.recallDevice(deviceName, recallData),
onSuccess: (data, variables) => {
- ReusableToast({
- message: `${variables.deviceName} has been recalled.`,
- type: 'SUCCESS',
- });
queryClient.invalidateQueries({ queryKey: ['devices'] });
queryClient.invalidateQueries({ queryKey: ['device-details'] });
queryClient.invalidateQueries({ queryKey: ['myDevices'] });
queryClient.invalidateQueries({ queryKey: ['deviceActivities'] });
},
- onError: error => {
- ReusableToast({
- message: `Recall Failed: ${getApiErrorMessage(error)}`,
- type: 'ERROR',
- });
- },
});
};
@@ -710,21 +625,11 @@ export const useAddMaintenanceLog = () => {
logData: MaintenanceLogData;
}) => devices.addMaintenanceLog(deviceName, logData),
onSuccess: (data, variables) => {
- ReusableToast({
- message: `Maintenance log has been added for ${variables.deviceName}.`,
- type: 'SUCCESS',
- });
queryClient.invalidateQueries({ queryKey: ['devices'] });
queryClient.invalidateQueries({ queryKey: ['device-details'] });
queryClient.invalidateQueries({ queryKey: ['deviceStatus'] });
queryClient.invalidateQueries({ queryKey: ['deviceActivities'] });
},
- onError: error => {
- ReusableToast({
- message: `Failed to Add Maintenance Log: ${getApiErrorMessage(error)}`,
- type: 'ERROR',
- });
- },
});
};
@@ -738,12 +643,6 @@ export const useDecryptDeviceKeys = () => {
onSuccess: () => {
logger.info('Keys decrypted successfully!');
},
- onError: error => {
- ReusableToast({
- message: `Decryption Failed: ${getApiErrorMessage(error)}`,
- type: 'ERROR',
- });
- },
});
};