asset-management/src/pages/assets/AddAssetModal.jsx
vamsi.balaga 97dc3b6286 fix: show Asset Brand and Location first on the Add Asset form
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 12:31:39 +05:30

184 lines
5.6 KiB
JavaScript

import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { Button, Field, Icon, Modal, SelectInput } from '../../components/ui'
import ActivityFields from '../../components/activity/ActivityFields'
import {
ASSET_FIELDS,
ASSET_INIT_ACTIVITY_ID,
createAsset,
fetchAssignableEmployees,
uploadAssetFile,
} from '../../api/assets'
import { emptyValues, validateActivity } from '../../api/activityForm'
import { useAuth } from '../../store/AuthContext'
// Asset Brand and Asset Location come first, as on the Edit form; the rest
// keep the builder's order.
const FIRST_FIELDS = ['field_59', 'field_61']
const FORM_FIELDS = [
...FIRST_FIELDS.map((id) => ASSET_FIELDS.find((f) => f.id === id)),
...ASSET_FIELDS.filter((f) => !FIRST_FIELDS.includes(f.id)),
]
// Asset Owner sits after Condition, as in the builder.
const OWNER_AFTER = FORM_FIELDS.findIndex((f) => f.id === 'field_47') + 1
const FIELDS_BEFORE_OWNER = FORM_FIELDS.slice(0, OWNER_AFTER)
const FIELDS_AFTER_OWNER = FORM_FIELDS.slice(OWNER_AFTER)
const upload = (fieldId, file) => uploadAssetFile(ASSET_INIT_ACTIVITY_ID, fieldId, file)
/**
* "Add Asset" dialog. Fields are rendered straight from the Zino builder
* definition in api/assets.js, so the form always matches the activity.
* "Asset Owner" is a lookup, so it is picked from a list of active employees.
*/
export default function AddAssetModal({ open, onClose, onCreated }) {
const navigate = useNavigate()
const { logout } = useAuth()
const [values, setValues] = useState(() => emptyValues(ASSET_FIELDS))
const [employees, setEmployees] = useState([])
const [loadingEmployees, setLoadingEmployees] = useState(false)
const [ownerId, setOwnerId] = useState('')
const [errors, setErrors] = useState({})
const [serverError, setServerError] = useState('')
const [submitting, setSubmitting] = useState(false)
// A fresh employee list each time the dialog opens.
useEffect(() => {
if (!open) return undefined
let cancelled = false
setLoadingEmployees(true)
fetchAssignableEmployees()
.then((list) => !cancelled && setEmployees(list))
.catch((err) => {
if (cancelled) return
if (err?.status === 401) {
logout()
navigate('/login', { replace: true })
return
}
setServerError(err?.message || 'Could not load the employee list.')
})
.finally(() => !cancelled && setLoadingEmployees(false))
return () => {
cancelled = true
}
}, [open, logout, navigate])
function reset() {
setValues(emptyValues(ASSET_FIELDS))
setOwnerId('')
setErrors({})
setServerError('')
setSubmitting(false)
}
function close() {
if (submitting) return
reset()
onClose?.()
}
function handleChange(id, value) {
setValues((v) => ({ ...v, [id]: value }))
if (errors[id]) setErrors((er) => ({ ...er, [id]: undefined }))
if (serverError) setServerError('')
}
async function handleSubmit(e) {
e.preventDefault()
const nextErrors = validateActivity(ASSET_FIELDS, values)
setErrors(nextErrors)
if (Object.keys(nextErrors).length) return
setSubmitting(true)
setServerError('')
try {
const owner = employees.find((emp) => String(emp.id) === ownerId) ?? null
const response = await createAsset(values, owner)
onCreated?.(values, response)
reset()
onClose?.()
} catch (err) {
if (err?.status === 401) {
logout()
navigate('/login', { replace: true })
return
}
setServerError(err?.message || 'Could not create the asset. Please try again.')
setSubmitting(false)
}
}
return (
<Modal
open={open}
onClose={close}
title="Add Asset"
subtitle="Starts the asset onboarding workflow."
size="lg"
footer={
<>
<Button onClick={close} disabled={submitting}>
Cancel
</Button>
<Button
type="submit"
form="add-asset-form"
variant="primary"
icon={submitting ? undefined : 'plus'}
disabled={submitting}
>
{submitting ? 'Creating…' : 'Create Asset'}
</Button>
</>
}
>
{serverError && (
<div className="auth__alert" role="alert">
<Icon name="alert" size={15} />
<span>{serverError}</span>
</div>
)}
<form id="add-asset-form" className="form__grid" onSubmit={handleSubmit} noValidate>
<ActivityFields
fields={FIELDS_BEFORE_OWNER}
values={values}
errors={errors}
onChange={handleChange}
disabled={submitting}
upload={upload}
/>
<Field label="Asset Owner">
{(id) => (
<SelectInput
id={id}
value={ownerId}
onChange={(e) => {
setOwnerId(e.target.value)
if (serverError) setServerError('')
}}
options={employees.map((emp) => ({
value: String(emp.id),
label: emp.code ? `${emp.name} (${emp.code})` : emp.name,
}))}
placeholder={loadingEmployees ? 'Loading employees…' : 'Select employee'}
disabled={submitting || loadingEmployees}
/>
)}
</Field>
<ActivityFields
fields={FIELDS_AFTER_OWNER}
values={values}
errors={errors}
onChange={handleChange}
disabled={submitting}
upload={upload}
/>
</form>
</Modal>
)
}