Lated Updated for QR code

This commit is contained in:
Duradundi Hadimani 2025-11-14 15:31:18 +05:30
parent 18ed88bff0
commit c11db48dbf
4 changed files with 348 additions and 79 deletions

View File

@ -1,5 +1,5 @@
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import apiService from '../services/apiService'; // ✅ your ApiService import apiService from '../services/apiService';
interface LinkFieldProps { interface LinkFieldProps {
label: string; label: string;
@ -8,6 +8,7 @@ interface LinkFieldProps {
onChange: (value: string) => void; onChange: (value: string) => void;
placeholder?: string; placeholder?: string;
disabled?: boolean; disabled?: boolean;
filters?: Record<string, any>;
} }
const LinkField: React.FC<LinkFieldProps> = ({ const LinkField: React.FC<LinkFieldProps> = ({
@ -17,29 +18,43 @@ const LinkField: React.FC<LinkFieldProps> = ({
onChange, onChange,
placeholder, placeholder,
disabled = false, disabled = false,
filters = {},
}) => { }) => {
const [searchResults, setSearchResults] = useState<{ value: string; description?: string }[]>([]); const [searchResults, setSearchResults] = useState<{ value: string; description?: string }[]>([]);
const [searchText, setSearchText] = useState(''); const [searchText, setSearchText] = useState('');
const [isDropdownOpen, setDropdownOpen] = useState(false); const [isDropdownOpen, setDropdownOpen] = useState(false);
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);
// Fetch link options from ERPNext // Fetch link options from ERPNext with filters
const searchLink = async (text: string = '') => { const searchLink = async (text: string = '') => {
try { try {
const params = new URLSearchParams({ doctype, txt: text }); const params = new URLSearchParams({
doctype,
txt: text,
});
// Add filters if provided
if (filters && Object.keys(filters).length > 0) {
// Convert filters to JSON string for Frappe API
params.append('filters', JSON.stringify(filters));
}
const response = await apiService.apiCall<{ value: string; description?: string }[]>( const response = await apiService.apiCall<{ value: string; description?: string }[]>(
`/api/method/frappe.desk.search.search_link?${params.toString()}` `/api/method/frappe.desk.search.search_link?${params.toString()}`
); );
setSearchResults(response || []); setSearchResults(response || []);
} catch (error) { } catch (error) {
console.error(`Error fetching ${doctype} links:`, error); console.error(`Error fetching ${doctype} links:`, error);
setSearchResults([]);
} }
}; };
// Fetch default options when dropdown opens // Fetch default options when dropdown opens or filters change
useEffect(() => { useEffect(() => {
if (isDropdownOpen) searchLink(''); if (isDropdownOpen) {
}, [isDropdownOpen]); searchLink(searchText || '');
}
}, [isDropdownOpen, filters]); // Re-fetch when filters change
// Close dropdown when clicking outside // Close dropdown when clicking outside
useEffect(() => { useEffect(() => {
@ -54,7 +69,9 @@ const LinkField: React.FC<LinkFieldProps> = ({
return ( return (
<div ref={containerRef} className="relative w-full mb-4"> <div ref={containerRef} className="relative w-full mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">{label}</label> <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
{label}
</label>
<input <input
type="text" type="text"
@ -62,47 +79,8 @@ const LinkField: React.FC<LinkFieldProps> = ({
placeholder={placeholder || `Select ${label}`} placeholder={placeholder || `Select ${label}`}
disabled={disabled} disabled={disabled}
className={`w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md 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 disabled:bg-gray-100 dark:disabled:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:bg-gray-100 dark:disabled:bg-gray-700
bg-white dark:bg-gray-700 text-gray-900 dark:text-white`} bg-white dark:bg-gray-700 text-gray-900 dark:text-white`}
onFocus={() => !disabled && setDropdownOpen(true)}
onChange={(e) => {
const text = e.target.value;
setSearchText(text);
searchLink(text);
onChange(text);
}}
/>
{isDropdownOpen && searchResults.length > 0 && !disabled && (
<ul className="absolute z-50 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600
rounded-md mt-1 max-h-48 overflow-auto w-full shadow-lg">
{searchResults.map((item, idx) => (
<li
key={idx}
onClick={() => {
onChange(item.value);
setDropdownOpen(false);
}}
className={`px-3 py-2 cursor-pointer
text-gray-900 dark:text-gray-100
hover:bg-blue-500 dark:hover:bg-blue-600
${value === item.value ? 'bg-blue-50 dark:bg-blue-700 font-semibold' : ''}`}
>
{item.value}
{item.description && (
<span className="text-gray-600 dark:text-gray-300 text-xs ml-2">{item.description}</span>
)}
</li>
))}
</ul>
)}
{/* <input
type="text"
value={value}
placeholder={placeholder || `Select ${label}`}
disabled={disabled}
onFocus={() => !disabled && setDropdownOpen(true)} onFocus={() => !disabled && setDropdownOpen(true)}
onChange={(e) => { onChange={(e) => {
const text = e.target.value; const text = e.target.value;
@ -110,17 +88,11 @@ const LinkField: React.FC<LinkFieldProps> = ({
searchLink(text); searchLink(text);
onChange(text); onChange(text);
}} }}
className={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500
disabled:bg-gray-100 dark:disabled:bg-gray-700
border-gray-300 dark:border-gray-600
bg-white dark:bg-gray-700 text-gray-900 dark:text-white`}
/> />
{isDropdownOpen && searchResults.length > 0 && ( {isDropdownOpen && searchResults.length > 0 && !disabled && (
<ul <ul className="absolute z-50 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600
className="absolute z-50 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600 rounded-md mt-1 max-h-48 overflow-auto w-full shadow-lg">
rounded-md mt-1 max-h-48 overflow-auto w-full shadow-lg"
>
{searchResults.map((item, idx) => ( {searchResults.map((item, idx) => (
<li <li
key={idx} key={idx}
@ -128,22 +100,137 @@ const LinkField: React.FC<LinkFieldProps> = ({
onChange(item.value); onChange(item.value);
setDropdownOpen(false); setDropdownOpen(false);
}} }}
className={`px-3 py-2 hover:bg-blue-100 dark:hover:bg-gray-700 cursor-pointer className={`px-3 py-2 cursor-pointer
${value === item.value ? 'bg-blue-50 dark:bg-gray-600 font-semibold' : ''}`} text-gray-900 dark:text-gray-100
hover:bg-blue-500 dark:hover:bg-blue-600 hover:text-white
${value === item.value ? 'bg-blue-50 dark:bg-blue-700 font-semibold' : ''}`}
> >
<div>{item.value}</div> {item.value}
{item.description && ( {item.description && (
<div className="text-gray-500 dark:text-gray-400 text-xs">{item.description}</div> <span className="text-gray-600 dark:text-gray-300 text-xs ml-2">
{item.description}
</span>
)} )}
</li> </li>
))} ))}
</ul> </ul>
)} */} )}
{/* Show message when no results found */}
{isDropdownOpen && searchResults.length === 0 && !disabled && (
<div className="absolute z-50 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600
rounded-md mt-1 w-full shadow-lg p-3 text-center text-gray-500 dark:text-gray-400 text-sm">
No results found
</div>
)}
</div> </div>
); );
}; };
export default LinkField; export default LinkField;
// import React, { useState, useEffect, useRef } from 'react';
// import apiService from '../services/apiService'; // ✅ your ApiService
// interface LinkFieldProps {
// label: string;
// doctype: string;
// value: string;
// onChange: (value: string) => void;
// placeholder?: string;
// disabled?: boolean;
// filters?: Record<string, any>
// }
// const LinkField: React.FC<LinkFieldProps> = ({
// label,
// doctype,
// value,
// onChange,
// placeholder,
// disabled = false,
// }) => {
// const [searchResults, setSearchResults] = useState<{ value: string; description?: string }[]>([]);
// const [searchText, setSearchText] = useState('');
// const [isDropdownOpen, setDropdownOpen] = useState(false);
// const containerRef = useRef<HTMLDivElement>(null);
// // Fetch link options from ERPNext
// const searchLink = async (text: string = '') => {
// try {
// const params = new URLSearchParams({ doctype, txt: text });
// const response = await apiService.apiCall<{ value: string; description?: string }[]>(
// `/api/method/frappe.desk.search.search_link?${params.toString()}`
// );
// setSearchResults(response || []);
// } catch (error) {
// console.error(`Error fetching ${doctype} links:`, error);
// }
// };
// // Fetch default options when dropdown opens
// useEffect(() => {
// if (isDropdownOpen) searchLink('');
// }, [isDropdownOpen]);
// // Close dropdown when clicking outside
// useEffect(() => {
// const handleClickOutside = (event: MouseEvent) => {
// if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
// setDropdownOpen(false);
// }
// };
// document.addEventListener('mousedown', handleClickOutside);
// return () => document.removeEventListener('mousedown', handleClickOutside);
// }, []);
// return (
// <div ref={containerRef} className="relative w-full mb-4">
// <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">{label}</label>
// <input
// type="text"
// value={value}
// placeholder={placeholder || `Select ${label}`}
// disabled={disabled}
// 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 disabled:bg-gray-100 dark:disabled:bg-gray-700
// bg-white dark:bg-gray-700 text-gray-900 dark:text-white`}
// onFocus={() => !disabled && setDropdownOpen(true)}
// onChange={(e) => {
// const text = e.target.value;
// setSearchText(text);
// searchLink(text);
// onChange(text);
// }}
// />
// {isDropdownOpen && searchResults.length > 0 && !disabled && (
// <ul className="absolute z-50 bg-white dark:bg-gray-800 border border-gray-300 dark:border-gray-600
// rounded-md mt-1 max-h-48 overflow-auto w-full shadow-lg">
// {searchResults.map((item, idx) => (
// <li
// key={idx}
// onClick={() => {
// onChange(item.value);
// setDropdownOpen(false);
// }}
// className={`px-3 py-2 cursor-pointer
// text-gray-900 dark:text-gray-100
// hover:bg-blue-500 dark:hover:bg-blue-600
// ${value === item.value ? 'bg-blue-50 dark:bg-blue-700 font-semibold' : ''}`}
// >
// {item.value}
// {item.description && (
// <span className="text-gray-600 dark:text-gray-300 text-xs ml-2">{item.description}</span>
// )}
// </li>
// ))}
// </ul>
// )}
// </div>
// );
// };
// export default LinkField;

View File

@ -5,6 +5,7 @@ import { FaArrowLeft, FaSave, FaEdit, FaQrcode } from 'react-icons/fa';
import type { CreateAssetData } from '../services/assetService'; import type { CreateAssetData } from '../services/assetService';
import LinkField from '../components/LinkField'; import LinkField from '../components/LinkField';
import apiService from '../services/apiService'; // ✅ your ApiService
const AssetDetail: React.FC = () => { const AssetDetail: React.FC = () => {
@ -23,6 +24,10 @@ const AssetDetail: React.FC = () => {
const { createAsset, updateAsset, loading: saving } = useAssetMutations(); const { createAsset, updateAsset, loading: saving } = useAssetMutations();
const [isEditing, setIsEditing] = useState(isNewAsset); const [isEditing, setIsEditing] = useState(isNewAsset);
const [userSiteName, setUserSiteName] = useState('');
const [departmentFilters, setDepartmentFilters] = useState<Record<string, any>>({});
const [formData, setFormData] = useState<CreateAssetData>({ const [formData, setFormData] = useState<CreateAssetData>({
asset_name: '', asset_name: '',
company: '', company: '',
@ -41,9 +46,53 @@ const AssetDetail: React.FC = () => {
custom_modality: '', custom_modality: '',
custom_attach_image: '', custom_attach_image: '',
custom_site_contractor: '', custom_site_contractor: '',
custom_total_amount: 0 custom_total_amount: 0,
calculate_depreciation: false,
available_for_use_date: isNewAsset ? new Date().toISOString().split('T')[0] : undefined
}); });
// Load user details on mount
useEffect(() => {
async function loadUserDetails() {
try {
const user = await apiService.getUserDetails();
setUserSiteName(user.custom_site_name || '');
} catch (err) {
console.error('Error loading user details', err);
}
}
loadUserDetails();
}, []);
// Update department filters when company or userSiteName changes
useEffect(() => {
const filters: Record<string, any> = {};
// Base filter: company must match
if (formData.company) {
filters['company'] = formData.company;
}
// Apply department name filters based on site name and company
const isMobileSite =
(userSiteName && userSiteName.startsWith('Mobile')) ||
(formData.company && formData.company.startsWith('Mobile'));
if (isMobileSite) {
// For Mobile sites, exclude Non Bio departments (show Bio departments)
// Frappe filter format: ['not like', 'pattern']
filters['department_name'] = ['not like', 'Non Bio%'];
} else if (userSiteName || formData.company) {
// For non-Mobile sites, exclude Bio departments (show Non-Bio departments)
filters['department_name'] = ['not like', 'Bio%'];
}
console.log('Department filters updated:', filters); // Debug log
setDepartmentFilters(filters);
}, [formData.company, userSiteName]);
// Load asset data for editing or duplicating // Load asset data for editing or duplicating
useEffect(() => { useEffect(() => {
if (asset) { if (asset) {
@ -65,11 +114,52 @@ const AssetDetail: React.FC = () => {
custom_modality: asset.custom_modality || '', custom_modality: asset.custom_modality || '',
custom_attach_image: asset.custom_attach_image || '', custom_attach_image: asset.custom_attach_image || '',
custom_site_contractor: asset.custom_site_contractor || '', custom_site_contractor: asset.custom_site_contractor || '',
custom_total_amount: asset.custom_total_amount || 0 custom_total_amount: asset.custom_total_amount || 0,
gross_purchase_amount:asset.gross_purchase_amount || 0,
available_for_use_date: asset.available_for_use_date || '',
calculate_depreciation: asset.calculate_depreciation || false
}); });
} }
}, [asset, isDuplicating]); }, [asset, isDuplicating]);
const [qrCodeUrl, setQrCodeUrl] = useState<string | null>(null);
useEffect(() => {
if (!assetName || assetName === "new") return;
const fetchQRCode = async () => {
try {
// Try fixed predictable URL
const directUrl = `/files/${assetName}-qr.png`;
console.log(directUrl)
// Quickly test if file exists
const response = await fetch(directUrl, { method: "HEAD" });
console.log(response)
if (response.ok) {
setQrCodeUrl(directUrl);
return;
}
// If not available, fallback to File doctype API
const fileRes = await apiService.apiCall<any>(
`/api/resource/File?filters=[["File","attached_to_name","=","${assetName}"]]`
);
if (fileRes?.data?.length > 0) {
setQrCodeUrl(fileRes.data[0].file_url);
}
} catch (error) {
console.error("Error loading QR code:", error);
}
};
fetchQRCode();
}, [assetName, asset]);
const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => { const handleChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => {
const { name, value } = e.target; const { name, value } = e.target;
setFormData(prev => ({ setFormData(prev => ({
@ -98,6 +188,10 @@ const AssetDetail: React.FC = () => {
try { try {
if (isNewAsset || isDuplicating) { if (isNewAsset || isDuplicating) {
const newAsset = await createAsset(formData); const newAsset = await createAsset(formData);
if (newAsset.name) {
const qrUrl = `/files/${newAsset.name}-qr.png`;
setQrCodeUrl(qrUrl);
}
const successMessage = isDuplicating const successMessage = isDuplicating
? 'Asset duplicated successfully!' ? 'Asset duplicated successfully!'
: 'Asset created successfully!'; : 'Asset created successfully!';
@ -292,6 +386,7 @@ const AssetDetail: React.FC = () => {
doctype="Asset Type" doctype="Asset Type"
value={formData.custom_asset_type || ''} value={formData.custom_asset_type || ''}
onChange={(val) => setFormData({ ...formData, custom_asset_type: val })} onChange={(val) => setFormData({ ...formData, custom_asset_type: val })}
disabled={!isEditing}
/> />
@ -319,6 +414,7 @@ const AssetDetail: React.FC = () => {
doctype="Modality" doctype="Modality"
value={formData.custom_modality || ''} value={formData.custom_modality || ''}
onChange={(val) => setFormData({ ...formData, custom_modality: val })} onChange={(val) => setFormData({ ...formData, custom_modality: val })}
disabled={!isEditing}
/> />
@ -420,8 +516,9 @@ const AssetDetail: React.FC = () => {
<LinkField <LinkField
label="Manufacturer" label="Manufacturer"
doctype="Manufacturer" doctype="Manufacturer"
value={formData.manufacturer || ''} value={formData.custom_manufacturer || ''}
onChange={(val) => setFormData({ ...formData, manufacturer: val })} onChange={(val) => setFormData({ ...formData, custom_manufacturer: val })}
disabled={!isEditing}
/> />
<div> <div>
@ -478,7 +575,13 @@ const AssetDetail: React.FC = () => {
label="Hospital" label="Hospital"
doctype="Company" doctype="Company"
value={formData.company || ''} value={formData.company || ''}
onChange={(val) => setFormData({ ...formData, company: val })} onChange={(val) => {
setFormData({ ...formData, company: val, department: '' }); // Clear department when company changes
}}
disabled={!isEditing}
filters={{ domain: 'Healthcare' }}
// onChange={(val) => setFormData({ ...formData, company: val })}
// disabled={!isEditing}
/> />
{/* <div> {/* <div>
@ -504,6 +607,16 @@ const AssetDetail: React.FC = () => {
doctype="Department" doctype="Department"
value={formData.department || ''} value={formData.department || ''}
onChange={(val) => setFormData({ ...formData, department: val })} onChange={(val) => setFormData({ ...formData, department: val })}
disabled={!isEditing}
filters={departmentFilters}
/>
<LinkField
label="Location"
doctype="Location"
value={formData.location || ''}
onChange={(val) => setFormData({ ...formData, location: val })}
disabled={!isEditing}
/> />
<div> <div>
@ -604,10 +717,19 @@ const AssetDetail: React.FC = () => {
Service Agreement Service Agreement
</label> </label>
<select <select
name="custom_service_agreement"
value={formData.custom_service_agreement}
onChange={handleChange}
disabled={!isEditing} disabled={!isEditing}
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 disabled:bg-gray-100 dark:disabled:bg-gray-700 bg-white dark:bg-gray-700 text-gray-900 dark:text-white" 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 disabled:bg-gray-100 dark:disabled:bg-gray-700 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
> >
<option value="">Select</option> <option value="">Select Service Agreement</option>
<option value="Warranty">Warranty</option>
<option value="Contract">Contract</option>
<option value="Frame Work">Frame Work</option>
<option value="Out of warranty">Out of warranty</option>
<option value="Under Dismantle">Under Dismantle</option>
<option value="Under Installation">Under Installation</option>
</select> </select>
</div> </div>
@ -616,10 +738,17 @@ const AssetDetail: React.FC = () => {
Service Coverage Service Coverage
</label> </label>
<select <select
name="custom_service_coverage"
value={formData.custom_service_coverage}
onChange={handleChange}
disabled={!isEditing} disabled={!isEditing}
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 disabled:bg-gray-100 dark:disabled:bg-gray-700 bg-white dark:bg-gray-700 text-gray-900 dark:text-white" 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 disabled:bg-gray-100 dark:disabled:bg-gray-700 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
> >
<option value="">Select</option> <option value="">Select Service Coverage</option>
<option value="PM Only">PM Only</option>
<option value="Labour">Labour</option>
<option value="Labour & Parts">Labour & Parts</option>
<option value="Comprehensive">Comprehensive</option>
</select> </select>
</div> </div>
@ -688,7 +817,7 @@ const AssetDetail: React.FC = () => {
/> />
</div> </div>
<div> {/* <div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"> <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Supplier/Vendor Supplier/Vendor
</label> </label>
@ -698,18 +827,27 @@ const AssetDetail: React.FC = () => {
> >
<option value="">Select</option> <option value="">Select</option>
</select> </select>
</div> </div> */}
<LinkField
label="Supplier/Vendor"
doctype="Supplier"
value={formData.supplier || ''}
onChange={(val) => setFormData({ ...formData, supplier: val })}
disabled={!isEditing}
/>
<div> <div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"> <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Gross Purchase Amount Gross Purchase Amount
</label> </label>
<select <input
type="number"
name="gross_purchase_amount"
value={formData.gross_purchase_amount}
onChange={handleChange}
disabled={!isEditing} disabled={!isEditing}
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 disabled:bg-gray-100 dark:disabled:bg-gray-700 bg-white dark:bg-gray-700 text-gray-900 dark:text-white" 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 disabled:bg-gray-100 dark:disabled:bg-gray-700 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
> />
<option value="">Price</option>
</select>
</div> </div>
<div> <div>
@ -740,6 +878,11 @@ const AssetDetail: React.FC = () => {
</label> </label>
<input <input
type="date" type="date"
name="available_for_use_date"
value={formData.available_for_use_date || ''}
onChange={(e) =>
setFormData((prev) => ({ ...prev, available_for_use_date: e.target.value }))
}
disabled={!isEditing} disabled={!isEditing}
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 disabled:bg-gray-100 dark:disabled:bg-gray-700 bg-white dark:bg-gray-700 text-gray-900 dark:text-white" 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 disabled:bg-gray-100 dark:disabled:bg-gray-700 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
/> />
@ -809,6 +952,29 @@ const AssetDetail: React.FC = () => {
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 disabled:bg-gray-100 dark:disabled:bg-gray-700 bg-white dark:bg-gray-700 text-gray-900 dark:text-white" 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 disabled:bg-gray-100 dark:disabled:bg-gray-700 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
/> />
</div> </div>
<div className="flex items-center mt-4">
<input
id="calculate_depreciation"
type="checkbox"
checked={formData.calculate_depreciation}
onChange={(e) =>
setFormData({
...formData,
calculate_depreciation: e.target.checked,
})
}
disabled={!isEditing}
className="h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
/>
<label
htmlFor="calculate_depreciation"
className="ml-2 text-sm font-medium text-gray-700 dark:text-gray-300"
>
Calculate Depreciation
</label>
</div>
</div> </div>
</div> </div>
@ -868,12 +1034,22 @@ const AssetDetail: React.FC = () => {
</div> </div>
{/* QR Code */} {/* QR Code */}
<div className="flex justify-center my-6"> <div className="flex justify-center my-6">
<div className="border-2 border-gray-300 dark:border-gray-600 p-4 rounded-lg"> <div className="border-2 border-gray-300 dark:border-gray-600 p-4 rounded-lg">
<FaQrcode size={120} className="text-gray-400 dark:text-gray-500" /> {qrCodeUrl ? (
<img
src={qrCodeUrl}
alt="QR Code"
className="w-40 h-40 object-contain"
/>
) : (
<FaQrcode size={120} className="text-gray-400 dark:text-gray-500" />
)}
</div> </div>
</div> </div>
<div className="mb-4"> <div className="mb-4">
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"> <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
Description Description

View File

@ -24,6 +24,7 @@ interface UserDetails {
creation: string; creation: string;
modified: string; modified: string;
language: string; language: string;
custom_site_name:string;
} }
interface DocTypeRecord { interface DocTypeRecord {

View File

@ -26,6 +26,10 @@ export interface Asset {
modified?: string; modified?: string;
owner?: string; owner?: string;
modified_by?: string; modified_by?: string;
calculate_depreciation?: boolean;
gross_purchase_amount?: number;
available_for_use_date?:string;
} }
export interface AssetListResponse { export interface AssetListResponse {
@ -82,6 +86,7 @@ export interface CreateAssetData {
custom_attach_image?: string; custom_attach_image?: string;
custom_site_contractor?: string; custom_site_contractor?: string;
custom_total_amount?: number; custom_total_amount?: number;
calculate_depreciation?: boolean;
[key: string]: any; [key: string]: any;
} }