Compare commits
3 Commits
a58fc89c46
...
fc091eb666
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc091eb666 | ||
|
|
34f8581b29 | ||
|
|
03cf1cf98d |
@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import { useParams, useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { useAssetDetails, useAssetMutations } from '../hooks/useAsset';
|
||||
import { FaArrowLeft, FaSave, FaEdit, FaQrcode } from 'react-icons/fa';
|
||||
import type { CreateAssetData } from '../services/assetService';
|
||||
import type { CreateAssetData, AssetFinanceBookRow } from '../services/assetService';
|
||||
|
||||
import LinkField from '../components/LinkField';
|
||||
import apiService from '../services/apiService'; // ✅ your ApiService
|
||||
@ -56,6 +56,15 @@ const AssetDetail: React.FC = () => {
|
||||
available_for_use_date: isNewAsset ? new Date().toISOString().split('T')[0] : undefined
|
||||
});
|
||||
|
||||
const emptyFinanceRow = {
|
||||
finance_book: "",
|
||||
depreciation_method: "",
|
||||
total_number_of_depreciations: 0,
|
||||
frequency_of_depreciation: "",
|
||||
depreciation_start_date: "",
|
||||
};
|
||||
|
||||
|
||||
// Load user details on mount
|
||||
useEffect(() => {
|
||||
async function loadUserDetails() {
|
||||
@ -70,6 +79,43 @@ const AssetDetail: React.FC = () => {
|
||||
loadUserDetails();
|
||||
}, []);
|
||||
|
||||
const addFinanceRow = () => {
|
||||
// Get today's date in YYYY-MM-DD format for date input
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
|
||||
const newRow: AssetFinanceBookRow = {
|
||||
finance_book: 'Depreciation Entries',
|
||||
depreciation_method: 'Straight Line',
|
||||
total_number_of_depreciations: 10,
|
||||
frequency_of_depreciation: 12,
|
||||
depreciation_start_date: today
|
||||
};
|
||||
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
finance_books: [
|
||||
...(prev.finance_books || []),
|
||||
newRow
|
||||
]
|
||||
}));
|
||||
};
|
||||
|
||||
const removeFinanceRow = (index: number) => {
|
||||
setFormData(prev => {
|
||||
const rows = [...(prev.finance_books || [])];
|
||||
rows.splice(index, 1);
|
||||
return { ...prev, finance_books: rows };
|
||||
});
|
||||
};
|
||||
|
||||
const updateFinanceRow = (index: number, patch: Partial<AssetFinanceBookRow>) => {
|
||||
setFormData(prev => {
|
||||
const rows = [...(prev.finance_books || [])];
|
||||
rows[index] = { ...(rows[index] || {}), ...patch };
|
||||
return { ...prev, finance_books: rows };
|
||||
});
|
||||
};
|
||||
|
||||
// Update department filters when company or userSiteName changes
|
||||
useEffect(() => {
|
||||
const filters: Record<string, any> = {};
|
||||
@ -444,7 +490,8 @@ const AssetDetail: React.FC = () => {
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-2">
|
||||
<div>
|
||||
{/* <div className="md:col-span-2"> */}
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Asset ID <span className="text-red-500">*</span>
|
||||
</label>
|
||||
@ -460,6 +507,22 @@ const AssetDetail: React.FC = () => {
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Device Status <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<select
|
||||
name="custom_device_status"
|
||||
value={formData.custom_device_status}
|
||||
onChange={handleChange}
|
||||
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"
|
||||
>
|
||||
{/* <option value="">Select class</option> */}
|
||||
<option value="Up">Up</option>
|
||||
<option value="Down">Down</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -627,7 +690,7 @@ const AssetDetail: React.FC = () => {
|
||||
disabled={!isEditing}
|
||||
/>
|
||||
|
||||
<div>
|
||||
{/* <div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Building
|
||||
</label>
|
||||
@ -640,9 +703,9 @@ const AssetDetail: React.FC = () => {
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
<div>
|
||||
{/* <div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Area/Unit
|
||||
</label>
|
||||
@ -652,7 +715,7 @@ const AssetDetail: React.FC = () => {
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
@ -898,73 +961,17 @@ const AssetDetail: React.FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Financial Details */}
|
||||
{/* Updated Financial Details */}
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
|
||||
<h2 className="text-lg font-semibold text-gray-800 dark:text-white mb-4">Financial Details</h2>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
|
||||
The depreciation method is an accounting method used to allocate the cost of a tangible asset over its useful life.
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Depreciation Method
|
||||
</label>
|
||||
<select
|
||||
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"
|
||||
>
|
||||
<option value="">Straight Line</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Depreciation Rate (%)
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Current Value
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-3">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Annual Rate
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-3">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||
Current Value
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
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"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center mt-4">
|
||||
<div className="flex items-center mb-6">
|
||||
<input
|
||||
id="calculate_depreciation"
|
||||
type="checkbox"
|
||||
|
||||
checked={formData.calculate_depreciation}
|
||||
onChange={(e) =>
|
||||
setFormData({
|
||||
@ -983,7 +990,162 @@ const AssetDetail: React.FC = () => {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Asset Finance Book child table — shown only when checkbox checked */}
|
||||
{formData.calculate_depreciation && (
|
||||
<div className="border-t pt-4">
|
||||
{/* Header with Add Row button */}
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className="text-md font-semibold text-gray-800 dark:text-white">
|
||||
Asset Finance Books
|
||||
</h3>
|
||||
{isEditing && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={addFinanceRow}
|
||||
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 flex items-center gap-2"
|
||||
>
|
||||
<span>+</span> Add Row
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Show message if no rows */}
|
||||
{(!formData.finance_books || formData.finance_books.length === 0) && (
|
||||
<div className="text-center py-8 text-gray-500 dark:text-gray-400 bg-gray-50 dark:bg-gray-900 rounded-lg">
|
||||
No finance books added yet. Click "Add Row" to add one.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* TABLE - Full width desktop view with overflow fix */}
|
||||
{formData.finance_books && formData.finance_books.length > 0 && (
|
||||
<div className="overflow-visible">
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full border-collapse">
|
||||
<thead>
|
||||
<tr className="bg-gray-100 dark:bg-gray-700 border-b border-gray-300 dark:border-gray-600">
|
||||
<th className="text-left px-4 py-3 text-sm font-semibold text-gray-700 dark:text-gray-300 min-w-[200px]">
|
||||
Finance Book
|
||||
</th>
|
||||
<th className="text-left px-4 py-3 text-sm font-semibold text-gray-700 dark:text-gray-300 min-w-[200px]">
|
||||
Depreciation Method*
|
||||
</th>
|
||||
<th className="text-left px-4 py-3 text-sm font-semibold text-gray-700 dark:text-gray-300 min-w-[180px]">
|
||||
Total Depreciations*
|
||||
</th>
|
||||
<th className="text-left px-4 py-3 text-sm font-semibold text-gray-700 dark:text-gray-300 min-w-[180px]">
|
||||
Frequency (Months)*
|
||||
</th>
|
||||
<th className="text-left px-4 py-3 text-sm font-semibold text-gray-700 dark:text-gray-300 min-w-[200px]">
|
||||
Depreciation Posting Date*
|
||||
</th>
|
||||
{isEditing && (
|
||||
<th className="text-center px-4 py-3 text-sm font-semibold text-gray-700 dark:text-gray-300 min-w-[120px]">
|
||||
Action
|
||||
</th>
|
||||
)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{formData.finance_books.map((row: AssetFinanceBookRow, idx: number) => (
|
||||
<tr
|
||||
key={idx}
|
||||
className="border-b border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-750"
|
||||
>
|
||||
{/* Finance Book - with overflow visible */}
|
||||
<td className="px-4 py-3 relative" style={{ overflow: 'visible' }}>
|
||||
<div className="relative z-20">
|
||||
<LinkField
|
||||
label=""
|
||||
doctype="Finance Book"
|
||||
value={row.finance_book || ''}
|
||||
onChange={(val) => updateFinanceRow(idx, { finance_book: val })}
|
||||
disabled={!isEditing}
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
{/* Depreciation Method */}
|
||||
<td className="px-4 py-3">
|
||||
<select
|
||||
value={row.depreciation_method || ''}
|
||||
onChange={(e) => updateFinanceRow(idx, { depreciation_method: e.target.value })}
|
||||
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"
|
||||
>
|
||||
<option value="">Select Method</option>
|
||||
<option value="Straight Line">Straight Line</option>
|
||||
<option value="Double Declining Balance">Double Declining Balance</option>
|
||||
<option value="Written Down Value">Written Down Value</option>
|
||||
<option value="Manual">Manual</option>
|
||||
</select>
|
||||
</td>
|
||||
|
||||
{/* Total Depreciations */}
|
||||
<td className="px-4 py-3">
|
||||
<input
|
||||
type="number"
|
||||
value={row.total_number_of_depreciations ?? ''}
|
||||
onChange={(e) =>
|
||||
updateFinanceRow(idx, {
|
||||
total_number_of_depreciations: Number(e.target.value),
|
||||
})
|
||||
}
|
||||
disabled={!isEditing}
|
||||
placeholder="0"
|
||||
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"
|
||||
/>
|
||||
</td>
|
||||
|
||||
{/* Frequency */}
|
||||
<td className="px-4 py-3">
|
||||
<input
|
||||
type="number"
|
||||
value={row.frequency_of_depreciation ?? ''}
|
||||
onChange={(e) =>
|
||||
updateFinanceRow(idx, {
|
||||
frequency_of_depreciation: Number(e.target.value),
|
||||
})
|
||||
}
|
||||
disabled={!isEditing}
|
||||
placeholder="0"
|
||||
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"
|
||||
/>
|
||||
</td>
|
||||
|
||||
{/* Start Date */}
|
||||
<td className="px-4 py-3">
|
||||
<input
|
||||
type="date"
|
||||
value={row.depreciation_start_date || ''}
|
||||
onChange={(e) =>
|
||||
updateFinanceRow(idx, { depreciation_start_date: e.target.value })
|
||||
}
|
||||
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"
|
||||
/>
|
||||
</td>
|
||||
|
||||
{/* REMOVE BUTTON */}
|
||||
{isEditing && (
|
||||
<td className="px-4 py-3 text-center">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeFinanceRow(idx)}
|
||||
className="px-3 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 transition-colors"
|
||||
>
|
||||
Remove
|
||||
</button>
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* End-of-Life Details */}
|
||||
|
||||
@ -67,6 +67,15 @@ export interface AssetStats {
|
||||
total_amount: number;
|
||||
}
|
||||
|
||||
// Add child row type
|
||||
export interface AssetFinanceBookRow {
|
||||
finance_book?: string;
|
||||
depreciation_method?: string;
|
||||
total_number_of_depreciations?: number;
|
||||
frequency_of_depreciation?: string;
|
||||
depreciation_start_date?: string; // YYYY-MM-DD
|
||||
}
|
||||
|
||||
export interface CreateAssetData {
|
||||
asset_name: string;
|
||||
company: string;
|
||||
@ -87,6 +96,7 @@ export interface CreateAssetData {
|
||||
custom_site_contractor?: string;
|
||||
custom_total_amount?: number;
|
||||
calculate_depreciation?: boolean;
|
||||
finance_books?: AssetFinanceBookRow[];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user