diff --git a/index.html b/index.html
index 085e1ff..070a639 100644
--- a/index.html
+++ b/index.html
@@ -2,9 +2,9 @@
-
+
- react-revamp
+ SeekRight
diff --git a/public/favicon.png b/public/favicon.png
new file mode 100644
index 0000000..0830af7
Binary files /dev/null and b/public/favicon.png differ
diff --git a/src/api/activityFeedsService.ts b/src/api/activityFeedsService.ts
index d9e3abf..0ce2555 100644
--- a/src/api/activityFeedsService.ts
+++ b/src/api/activityFeedsService.ts
@@ -77,5 +77,10 @@ export const activityFeedsService = {
getFalseAnomaly: async (params: any) => {
const response = await axiosClient.get('/api/audit/asset/get-false-Anomaly', { params });
return response;
+ },
+
+ bulkDelete: async (payload: any) => {
+ const response = await axiosClient.post('/api/audit/bulk/delete', payload);
+ return response;
}
};
diff --git a/src/components/common/BulkDeleteDialog.tsx b/src/components/common/BulkDeleteDialog.tsx
new file mode 100644
index 0000000..59b466d
--- /dev/null
+++ b/src/components/common/BulkDeleteDialog.tsx
@@ -0,0 +1,335 @@
+import React, { useState, useEffect } from 'react';
+import {
+ Dialog, DialogContent, Typography, Box, IconButton, Button,
+ TextField, RadioGroup, FormControlLabel, Radio, Checkbox,
+ CircularProgress, Select, MenuItem
+} from '@mui/material';
+import CloseIcon from '@mui/icons-material/Close';
+import { useFeedStore } from '../../store/feedStore';
+import { useAuthStore } from '../../store/authStore';
+import { activityFeedsService } from '../../api/activityFeedsService';
+
+interface BulkDeleteDialogProps {
+ open: boolean;
+ onClose: () => void;
+}
+
+const REASONS = ['Low Light', 'Bad Image', 'Wrong Algorithm', 'Out of Range'];
+
+export const BulkDeleteDialog: React.FC = ({ open, onClose }) => {
+ const { assetTypes, selectedSite, sites } = useFeedStore();
+ const { user } = useAuthStore();
+
+ const [fromDate, setFromDate] = useState('');
+ const [tillDate, setTillDate] = useState('');
+ const [auditType, setAuditType] = useState('manual');
+ const [reason, setReason] = useState('Bad Image');
+ const [selectedAssets, setSelectedAssets] = useState>(new Set());
+ const [isLoading, setIsLoading] = useState(false);
+ const [localSite, setLocalSite] = useState(selectedSite?.site_id || 'All Sites');
+
+ // Reset state when dialog opens
+ useEffect(() => {
+ if (open) {
+ setFromDate('');
+ setTillDate('');
+ setAuditType('manual');
+ setReason('Bad Image');
+ setSelectedAssets(new Set());
+ setLocalSite(selectedSite?.site_id || 'All Sites');
+ }
+ }, [open, selectedSite?.site_id]);
+
+ // Extract all asset IDs for "Select All" functionality
+ const allAssetIds = React.useMemo(() => {
+ const ids: number[] = [];
+ assetTypes.forEach((type: any) => {
+ type.assets?.forEach((a: any) => ids.push(a.asset_id));
+ });
+ return ids;
+ }, [assetTypes]);
+
+ const isAllSelected = selectedAssets.size > 0 && selectedAssets.size === allAssetIds.length;
+
+ const handleSelectAll = (checked: boolean) => {
+ if (checked) {
+ setSelectedAssets(new Set(allAssetIds));
+ } else {
+ setSelectedAssets(new Set());
+ }
+ };
+
+ const handleSelectCategory = (type: any, checked: boolean) => {
+ const newSelected = new Set(selectedAssets);
+ type.assets?.forEach((a: any) => {
+ if (checked) {
+ newSelected.add(a.asset_id);
+ } else {
+ newSelected.delete(a.asset_id);
+ }
+ });
+ setSelectedAssets(newSelected);
+ };
+
+ const handleSelectAsset = (assetId: number, checked: boolean) => {
+ const newSelected = new Set(selectedAssets);
+ if (checked) {
+ newSelected.add(assetId);
+ } else {
+ newSelected.delete(assetId);
+ }
+ setSelectedAssets(newSelected);
+ };
+
+ const handleApply = async () => {
+ if (!fromDate || !tillDate) {
+ alert("Please select both From and Till dates.");
+ return;
+ }
+ if (selectedAssets.size === 0) {
+ alert("Please select at least one asset.");
+ return;
+ }
+
+ let siteIds: number[] = [];
+ if (localSite === 'All Sites') {
+ sites.forEach((s: any) => {
+ if (s.site_id) {
+ siteIds.push(...String(s.site_id).split(',').map(id => Number(id.trim())));
+ }
+ });
+ } else {
+ siteIds = String(localSite).split(',').map(id => Number(id.trim()));
+ }
+
+ const payload = {
+ dbName: user?.db_name,
+ asset_id: Array.from(selectedAssets),
+ site_id: siteIds,
+ fromDate: fromDate,
+ toDate: tillDate,
+ user_id: Number(user?.user_id),
+ audit_value: reason,
+ isBulkDelete: true,
+ audit_type: auditType
+ };
+
+ try {
+ setIsLoading(true);
+ await activityFeedsService.bulkDelete(payload);
+ alert("Bulk delete successful!");
+ onClose();
+ } catch (err: any) {
+ console.error("Bulk delete failed", err);
+ alert("Bulk delete failed. " + (err?.response?.data?.message || err.message || ""));
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ return (
+
+ );
+};
diff --git a/src/components/common/TopFilterBar.tsx b/src/components/common/TopFilterBar.tsx
index 5716ae8..c210d3b 100644
--- a/src/components/common/TopFilterBar.tsx
+++ b/src/components/common/TopFilterBar.tsx
@@ -5,6 +5,7 @@ import HistoryIcon from '@mui/icons-material/History';
import { useFeedStore } from '../../store/feedStore';
import { FeedFilters } from '../../pages/activity-feeds/FeedFilters';
import { activityFeedsService } from '../../api/activityFeedsService';
+import { BulkDeleteDialog } from './BulkDeleteDialog';
const DEBOUNCE_MS = 600; // wait 600ms after user stops changing before committing to store
@@ -112,6 +113,7 @@ export const TopFilterBar: React.FC = () => {
};
const [historyDates, setHistoryDates] = useState([]);
+ const [isBulkDeleteDialogOpen, setIsBulkDeleteDialogOpen] = useState(false);
const [loadingHistory, setLoadingHistory] = useState(false);
const [isHistoryDialogOpen, setIsHistoryDialogOpen] = useState(false);
const [selectedHistoryDate, setSelectedHistoryDate] = useState('2026-06-12');
@@ -199,6 +201,13 @@ export const TopFilterBar: React.FC = () => {
>
RECTIFICATION HISTORY
+