Latest Changes
This commit is contained in:
parent
c11db48dbf
commit
03cf1cf98d
@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import { useParams, useNavigate, useSearchParams } from 'react-router-dom';
|
import { useParams, useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
import { useAssetDetails, useAssetMutations } from '../hooks/useAsset';
|
import { useAssetDetails, useAssetMutations } from '../hooks/useAsset';
|
||||||
import { FaArrowLeft, FaSave, FaEdit, FaQrcode } from 'react-icons/fa';
|
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 LinkField from '../components/LinkField';
|
||||||
import apiService from '../services/apiService'; // ✅ your ApiService
|
import apiService from '../services/apiService'; // ✅ your ApiService
|
||||||
@ -51,6 +51,15 @@ const AssetDetail: React.FC = () => {
|
|||||||
available_for_use_date: isNewAsset ? new Date().toISOString().split('T')[0] : undefined
|
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
|
// Load user details on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function loadUserDetails() {
|
async function loadUserDetails() {
|
||||||
@ -65,6 +74,38 @@ const AssetDetail: React.FC = () => {
|
|||||||
loadUserDetails();
|
loadUserDetails();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const addFinanceRow = () => {
|
||||||
|
setFormData(prev => ({
|
||||||
|
...prev,
|
||||||
|
finance_books: [
|
||||||
|
...(prev.finance_books || []),
|
||||||
|
{
|
||||||
|
finance_book: '',
|
||||||
|
depreciation_method: '',
|
||||||
|
total_number_of_depreciations: 0,
|
||||||
|
frequency_of_depreciation: '',
|
||||||
|
depreciation_start_date: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
// Update department filters when company or userSiteName changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const filters: Record<string, any> = {};
|
const filters: Record<string, any> = {};
|
||||||
@ -436,7 +477,8 @@ const AssetDetail: React.FC = () => {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</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">
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||||
Asset ID <span className="text-red-500">*</span>
|
Asset ID <span className="text-red-500">*</span>
|
||||||
</label>
|
</label>
|
||||||
@ -452,6 +494,22 @@ const AssetDetail: React.FC = () => {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -619,7 +677,7 @@ const AssetDetail: React.FC = () => {
|
|||||||
disabled={!isEditing}
|
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">
|
||||||
Building
|
Building
|
||||||
</label>
|
</label>
|
||||||
@ -632,9 +690,9 @@ const AssetDetail: React.FC = () => {
|
|||||||
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"
|
||||||
/>
|
/>
|
||||||
</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">
|
||||||
Area/Unit
|
Area/Unit
|
||||||
</label>
|
</label>
|
||||||
@ -644,7 +702,7 @@ const AssetDetail: React.FC = () => {
|
|||||||
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"
|
||||||
/>
|
/>
|
||||||
</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">
|
||||||
@ -975,6 +1033,237 @@ const AssetDetail: React.FC = () => {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Asset Finance Book child table — shown only when checkbox checked */}
|
||||||
|
{formData.calculate_depreciation && (
|
||||||
|
<div className="mt-6">
|
||||||
|
|
||||||
|
{/* Header with Add Row button */}
|
||||||
|
<div className="flex justify-between items-center mb-3">
|
||||||
|
<h3 className="text-md font-semibold text-gray-800 dark:text-white">
|
||||||
|
Asset Finance Book
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{isEditing && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={addFinanceRow}
|
||||||
|
className="px-3 py-1 bg-blue-600 text-white rounded-md hover:bg-blue-700"
|
||||||
|
>
|
||||||
|
+ Add Row
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* TABLE HEADER */}
|
||||||
|
<div className="hidden md:grid grid-cols-6 gap-4 text-sm font-semibold text-gray-700 dark:text-gray-300 border-b pb-2 mb-2">
|
||||||
|
<div>Finance Book</div>
|
||||||
|
<div>Depreciation Method</div>
|
||||||
|
<div>Total Depreciations</div>
|
||||||
|
<div>Frequency</div>
|
||||||
|
<div>Start Date</div>
|
||||||
|
<div className="text-right">Action</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* TABLE ROWS */}
|
||||||
|
<div className="space-y-3">
|
||||||
|
|
||||||
|
{(formData.finance_books || []).map((row: AssetFinanceBookRow, idx: number) => (
|
||||||
|
<div
|
||||||
|
key={idx}
|
||||||
|
className="md:grid md:grid-cols-6 gap-4 items-center border rounded-md p-3 bg-white dark:bg-gray-800"
|
||||||
|
>
|
||||||
|
{/* Finance Book */}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={row.finance_book || ''}
|
||||||
|
onChange={(e) => updateFinanceRow(idx, { finance_book: e.target.value })}
|
||||||
|
disabled={!isEditing}
|
||||||
|
className="w-full px-2 py-1 border rounded-md dark:bg-gray-700 dark:text-white"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Depreciation Method */}
|
||||||
|
<select
|
||||||
|
value={row.depreciation_method || ''}
|
||||||
|
onChange={(e) => updateFinanceRow(idx, { depreciation_method: e.target.value })}
|
||||||
|
disabled={!isEditing}
|
||||||
|
className="w-full px-2 py-1 border rounded-md dark:bg-gray-700 dark:text-white"
|
||||||
|
>
|
||||||
|
<option value="">Select</option>
|
||||||
|
<option value="Straight Line">Straight Line</option>
|
||||||
|
<option value="Reducing Balance">Reducing Balance</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
{/* Total Depreciations */}
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={row.total_number_of_depreciations ?? ''}
|
||||||
|
onChange={(e) =>
|
||||||
|
updateFinanceRow(idx, {
|
||||||
|
total_number_of_depreciations: Number(e.target.value),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
disabled={!isEditing}
|
||||||
|
className="w-full px-2 py-1 border rounded-md dark:bg-gray-700 dark:text-white"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Frequency */}
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={row.frequency_of_depreciation || ''}
|
||||||
|
onChange={(e) =>
|
||||||
|
updateFinanceRow(idx, { frequency_of_depreciation: e.target.value })
|
||||||
|
}
|
||||||
|
disabled={!isEditing}
|
||||||
|
className="w-full px-2 py-1 border rounded-md dark:bg-gray-700 dark:text-white"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Start Date */}
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
value={row.depreciation_start_date || ''}
|
||||||
|
onChange={(e) =>
|
||||||
|
updateFinanceRow(idx, { depreciation_start_date: e.target.value })
|
||||||
|
}
|
||||||
|
disabled={!isEditing}
|
||||||
|
className="w-full px-2 py-1 border rounded-md dark:bg-gray-700 dark:text-white"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* REMOVE BUTTON */}
|
||||||
|
{isEditing && (
|
||||||
|
<div className="text-right">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => removeFinanceRow(idx)}
|
||||||
|
className="px-3 py-1 bg-red-600 text-white rounded-md hover:bg-red-700"
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* {formData.calculate_depreciation && (
|
||||||
|
<div className="mt-6">
|
||||||
|
<div className="flex justify-between items-center mb-3">
|
||||||
|
<h3 className="text-md font-semibold text-gray-800 dark:text-white">Asset Finance Book</h3>
|
||||||
|
{isEditing && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={addFinanceRow}
|
||||||
|
className="px-3 py-1 bg-blue-600 text-white rounded-md hover:bg-blue-700"
|
||||||
|
>
|
||||||
|
+ Add Row
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="space-y-4">
|
||||||
|
{(formData.finance_books || []).length === 0 && (
|
||||||
|
<div className="text-sm text-gray-500 dark:text-gray-400">No finance book rows added.</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
{(formData.finance_books || []).map((row: AssetFinanceBookRow, idx: number) => (
|
||||||
|
<div key={idx} className="border rounded-md p-3 bg-white dark:bg-gray-800">
|
||||||
|
<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">
|
||||||
|
Finance Book
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={row.finance_book || ''}
|
||||||
|
onChange={(e) => updateFinanceRow(idx, { finance_book: 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 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">
|
||||||
|
Depreciation Method
|
||||||
|
</label>
|
||||||
|
<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 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="Reducing Balance">Reducing Balance</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||||
|
Total Number of Depreciations
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={row.total_number_of_depreciations ?? ''}
|
||||||
|
onChange={(e) => updateFinanceRow(idx, { total_number_of_depreciations: Number(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 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">
|
||||||
|
Frequency of Depreciation
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={row.frequency_of_depreciation || ''}
|
||||||
|
onChange={(e) => updateFinanceRow(idx, { frequency_of_depreciation: e.target.value })}
|
||||||
|
disabled={!isEditing}
|
||||||
|
placeholder="e.g. Monthly, Yearly"
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">
|
||||||
|
Depreciation Start Date
|
||||||
|
</label>
|
||||||
|
<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 bg-white dark:bg-gray-700 text-gray-900 dark:text-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Row actions */}
|
||||||
|
{/* {isEditing && (
|
||||||
|
<div className="mt-3 flex justify-end gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => removeFinanceRow(idx)}
|
||||||
|
className="px-3 py-1 rounded-md bg-red-600 text-white hover:bg-red-700"
|
||||||
|
>
|
||||||
|
Remove
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)} */}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -67,6 +67,15 @@ export interface AssetStats {
|
|||||||
total_amount: number;
|
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 {
|
export interface CreateAssetData {
|
||||||
asset_name: string;
|
asset_name: string;
|
||||||
company: string;
|
company: string;
|
||||||
@ -87,6 +96,7 @@ export interface CreateAssetData {
|
|||||||
custom_site_contractor?: string;
|
custom_site_contractor?: string;
|
||||||
custom_total_amount?: number;
|
custom_total_amount?: number;
|
||||||
calculate_depreciation?: boolean;
|
calculate_depreciation?: boolean;
|
||||||
|
finance_books?: AssetFinanceBookRow[];
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user