diff --git a/src/pages/AssetDetail.tsx b/src/pages/AssetDetail.tsx index a87a9d1..2934296 100644 --- a/src/pages/AssetDetail.tsx +++ b/src/pages/AssetDetail.tsx @@ -1,8 +1,8 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { useParams, useNavigate, useSearchParams } from 'react-router-dom'; import { useAssetDetails, useAssetMutations } from '../hooks/useAsset'; import { useDocTypeMeta } from '../hooks/useDocTypeMeta'; -import { FaArrowLeft, FaSave, FaEdit, FaQrcode, FaCheck, FaCalendarAlt, FaHistory, FaFileAlt, FaTrashAlt} from 'react-icons/fa'; +import { FaArrowLeft, FaSave, FaEdit, FaQrcode, FaCheck, FaCalendarAlt, FaHistory, FaFileAlt, FaTrashAlt, FaChevronDown} from 'react-icons/fa'; import type { CreateAssetData,AssetFinanceBookRow } from '../services/assetService'; import LinkField from '../components/LinkField'; @@ -33,6 +33,22 @@ const AssetDetail: React.FC = () => { const isCancelled = docstatus === 2; const isDraft = docstatus === 0; + // Add dropdown state + const [isActionDropdownOpen, setIsActionDropdownOpen] = useState(false); + const actionDropdownRef = useRef(null); + + // Close dropdown when clicking outside + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (actionDropdownRef.current && !actionDropdownRef.current.contains(event.target as Node)) { + setIsActionDropdownOpen(false); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => document.removeEventListener('mousedown', handleClickOutside); + }, []); + // Debug logging (development only) useEffect(() => { if (import.meta.env.DEV && asset) { @@ -2068,81 +2084,121 @@ const handlePPMPlan = async () => {
{!isNewAsset && !isEditing && !isCancelled && ( - <> - {/* Print QR Button - Only show if QR code exists */} - {qrCodeUrl && ( - - + <> + {/* Actions Dropdown */} +
+ + + {/* Dropdown Menu */} + {isActionDropdownOpen && ( +
+
+ {/* Print QR - Only show if QR code exists */} + {qrCodeUrl && ( + + )} + + {/* Stay Plugged */} + + + {/* PPM Plan */} + + + {/* Asset History */} + + + {/* Installation Report */} + + + {/* Dismantling Report - Only show when status is Scrapped */} + {asset?.status === 'Scrapped' && ( + + )} +
+
)} - {/* Stay Plugged Button */} +
+ + + {/* Submit button - only show for Draft documents */} + {isDraft && ( - {/* PPM Plan Button */} - - {/* Asset History Button */} - - {/* Installation Report Button */} - - {/* Dismantling Report Button - Only show when status is Scrapped */} - {asset?.status === 'Scrapped' && ( - - )} - - {/* Submit button - only show for Draft documents */} - {isDraft && ( - - )} - - )} + )} + + )} {isCancelled && ( Cancelled documents cannot be edited @@ -2158,7 +2214,7 @@ const handlePPMPlan = async () => { setIsEditing(false); } }} - className="bg-gray-300 hover:bg-gray-400 text-gray-700 dark:text-gray-800 px-6 py-2 rounded-lg" + className="bg-gray-300 hover:bg-gray-400 text-gray-700 dark:text-gray-800 px-2 py-1 rounded-lg" disabled={saving} > Cancel @@ -2166,7 +2222,7 @@ const handlePPMPlan = async () => {
-
-

- Technical Error: {error} -

-
); @@ -336,7 +363,7 @@ const AssetList: React.FC = () => {
- {/* Search Bar */} - {/*
-
- - setSearchTerm(e.target.value)} - className="flex-1 outline-none text-gray-700 dark:text-gray-200 bg-transparent" - /> - {searchTerm && ( - - )} -
-
*/} - - {/* Filter Section */} -
-
-

Filters

- {hasActiveFilters && ( - - )} -
- - {/* First Row - 5 filters */} -
- {/* Asset ID Filter */} -
- setFilterAssetId(val)} - placeholder="Select Asset ID" - disabled={false} - compact={true} - /> -
- - {/* Company Filter */} -
- setFilterCompany(val)} - placeholder="Select Hospital" - disabled={false} - compact={true} - filters={{ domain: 'Healthcare' }} - /> -
- {/* Asset Name Filter - Text Input */} -
- -
- handleAssetNameChange(e.target.value)} - onKeyDown={(e) => handleKeyPress(e, 'assetName')} - placeholder="Type to search..." - className="w-full px-2 py-1 text-xs border border-gray-300 dark:border-gray-600 rounded focus:outline-none focus:ring-1 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white" - /> - {tempAssetName && tempAssetName !== filterAssetName && ( - - typing... + {/* Advanced Filter Panel */} +
+ {/* Filter Header */} +
+
+
+ + +
+ +

Advanced Filters

+
+ + {activeFilterCount > 0 && ( + + {activeFilterCount} )}
-

- Press Enter or wait -

-
- {/* Serial Number Filter - Text Input */} -
- -
- handleSerialNumberChange(e.target.value)} - onKeyDown={(e) => handleKeyPress(e, 'serialNumber')} - placeholder="Type to search..." - className="w-full px-2 py-1 text-xs border border-gray-300 dark:border-gray-600 rounded focus:outline-none focus:ring-1 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white" - /> - {tempSerialNumber && tempSerialNumber !== filterSerialNumber && ( - - typing... - +
+ {/* Quick Filter Buttons */} +
+ + +
+ + {/* Save Filter Button */} + {activeFilterCount > 0 && ( + + )} + + {/* Clear All Button */} + {hasActiveFilters && ( + )}
-

- Press Enter or wait -

-
- - {/* Location Filter */} -
- setFilterLocation(val)} - placeholder="Select Location" - disabled={false} - compact={true} - />
- {/* Second Row - 5 filters */} -
- {/* Manufacturer Filter */} -
- setFilterManufacturer(val)} - placeholder="Select Manufacturer" - disabled={false} - compact={true} - /> -
+ {/* Expandable Filter Content */} +
+
+ {/* Saved Filter Presets */} + {savedFilters.length > 0 && ( +
+

+ + Saved Filters +

+
+ {savedFilters.map((preset) => ( +
+ + +
+ ))} +
+
+ )} - {/* Supplier Filter */} -
- setFilterSupplier(val)} - placeholder="Select Supplier" - disabled={false} - compact={true} - /> -
+ {/* Filter Grid - Organized by Category */} +
+ {/* Asset Identification Group */} +
+ {/*

+ + Asset Identification +

*/} +
+
+ setFilterAssetId(val)} + placeholder="Select Asset ID" + disabled={false} + compact={true} + /> + {filterAssetId && ( + + )} +
- {/* Department Filter */} -
- setFilterDepartment(val)} - placeholder="Select Department" - disabled={false} - compact={true} - /> -
+
+ + handleAssetNameChange(e.target.value)} + onKeyDown={(e) => handleKeyPress(e, 'assetName')} + placeholder="Type to search..." + className="w-full px-2 py-1 text-xs border border-gray-300 dark:border-gray-600 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white" + /> + {tempAssetName && tempAssetName !== filterAssetName && ( + + typing... + + )} + {filterAssetName && ( + + )} +
- {/* Modality Filter */} -
- setFilterModality(val)} - placeholder="Select Modality" - disabled={false} - compact={true} - /> -
+
+ + handleSerialNumberChange(e.target.value)} + onKeyDown={(e) => handleKeyPress(e, 'serialNumber')} + placeholder="Type to search..." + className="w-full px-2 py-1 text-xs border border-gray-300 dark:border-gray-600 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white" + /> + {tempSerialNumber && tempSerialNumber !== filterSerialNumber && ( + + typing... + + )} + {filterSerialNumber && ( + + )} +
+
+ setFilterCompany(val)} + placeholder="Select Hospital" + disabled={false} + compact={true} + filters={{ domain: 'Healthcare' }} + /> + {filterCompany && ( + + )} +
- {/* Device Status Filter - Dropdown */} -
- - -
+
+ + + {filterDeviceStatus && ( + + )} +
+
+ setFilterLocation(val)} + placeholder="Select Location" + disabled={false} + compact={true} + /> + {filterLocation && ( + + )} +
+
+ setFilterDepartment(val)} + placeholder="Select Department" + disabled={false} + compact={true} + /> + {filterDepartment && ( + + )} +
+
+ setFilterModality(val)} + placeholder="Select Modality" + disabled={false} + compact={true} + /> + {filterModality && ( + + )} +
+
+ setFilterManufacturer(val)} + placeholder="Select Manufacturer" + disabled={false} + compact={true} + /> + {filterManufacturer && ( + + )} +
+ +
+ setFilterSupplier(val)} + placeholder="Select Supplier" + disabled={false} + compact={true} + /> + {filterSupplier && ( + + )} +
+
+
+
+ + {/* Active Filters Summary */} + {hasActiveFilters && ( +
+
+

+ Active Filters ({activeFilterCount}) +

+ +
+
+ {filterAssetId && ( + + Asset ID: {filterAssetId} + + + )} + {filterCompany && ( + + Hospital: {filterCompany} + + + )} + {filterAssetName && ( + + Name: {filterAssetName} + + + )} + {filterSerialNumber && ( + + Serial: {filterSerialNumber} + + + )} + {filterDeviceStatus && ( + + Status: {filterDeviceStatus} + + + )} + {filterLocation && ( + + Location: {filterLocation} + + + )} + {filterDepartment && ( + + Department: {filterDepartment} + + + )} + {filterModality && ( + + Modality: {filterModality} + + + )} + {filterManufacturer && ( + + Manufacturer: {filterManufacturer} + + + )} + {filterSupplier && ( + + Supplier: {filterSupplier} + + + )} +
+
+ )} +
- - {/* Active Filters Display */} - {hasActiveFilters && ( -
- {filterAssetId && ( - - Asset ID: {filterAssetId} - - - )} - {filterCompany && ( - - Hospital: {filterCompany} - - - )} - {filterLocation && ( - - Location: {filterLocation} - - - )} - {filterDepartment && ( - - Department: {filterDepartment} - - - )} - {filterModality && ( - - Modality: {filterModality} - - - )} - {filterManufacturer && ( - - Manufacturer: {filterManufacturer} - - - )} - {filterSupplier && ( - - Supplier: {filterSupplier} - - - )} - {filterDeviceStatus && ( - - Status: {filterDeviceStatus} - - - )} - {filterAssetName && ( - - Asset Name: "{filterAssetName}" - - - )} - {filterSerialNumber && ( - - Serial: "{filterSerialNumber}" - - - )} - {searchTerm && ( - - Search: "{searchTerm}" - - - )} -
- )}
+ {/* Save Filter Modal */} + {showSaveFilterModal && ( +
+
+

+ Save Filter Preset +

+ setFilterPresetName(e.target.value)} + placeholder="Enter filter name (e.g., 'My Active Assets')" + className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-white mb-4" + autoFocus + /> +
+ + +
+
+
+ )} + {/* Assets Table */}
@@ -723,13 +896,6 @@ const AssetList: React.FC = () => {

No assets found

- {/* */} - {hasActiveFilters ? ( )} -
@@ -771,15 +936,6 @@ const AssetList: React.FC = () => { {asset.custom_device_status || '-'} - {/* - {asset.custom_device_status || 'Unknown'} - */} {formatDate(asset.modified)} @@ -941,9 +1097,24 @@ const AssetList: React.FC = () => {
)} + +
); }; export default AssetList; -