309 lines
16 KiB
JavaScript
309 lines
16 KiB
JavaScript
import { useEffect, useMemo, useState } from 'react';
|
|
import { Link, useNavigate, useSearchParams } from 'react-router';
|
|
import { Button, Card, Col, Container, Form, Row, Spinner } from 'react-bootstrap';
|
|
import { laravelGet, laravelPost, isLaravelSuccess } from '@/api/laravel';
|
|
import PageBreadcrumb from '@/components/PageBreadcrumb';
|
|
import { SPECIALITIES, STATUSES, displayValue, letterUrl } from './helpers';
|
|
|
|
function Field({ label, children }) {
|
|
return (
|
|
<Form.Group className="mb-3">
|
|
<Form.Label>{label}</Form.Label>
|
|
{children}
|
|
</Form.Group>
|
|
);
|
|
}
|
|
|
|
function ReadRow({ label, value }) {
|
|
return (
|
|
<p className="text-muted mb-2">
|
|
{label}: <strong>{displayValue(value)}</strong>
|
|
</p>
|
|
);
|
|
}
|
|
|
|
export default function NebReportDetail() {
|
|
const [params] = useSearchParams();
|
|
const navigate = useNavigate();
|
|
const id = params.get('id');
|
|
const mode = params.get('requesttype') === 'edit' ? 'edit' : 'view';
|
|
const filterQuery = useMemo(() => ({
|
|
state: params.get('state') || '',
|
|
from_date: params.get('from_date') || '',
|
|
to_date: params.get('to_date') || '',
|
|
status: params.get('status') || '',
|
|
}), [params]);
|
|
|
|
const [item, setItem] = useState(null);
|
|
const [doctors, setDoctors] = useState([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [saving, setSaving] = useState(false);
|
|
const [error, setError] = useState('');
|
|
const [message, setMessage] = useState('');
|
|
const [form, setForm] = useState({});
|
|
const [status, setStatus] = useState('');
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
(async () => {
|
|
setLoading(true);
|
|
setError('');
|
|
const response = await laravelGet('neblogistic/show', { id });
|
|
if (cancelled) return;
|
|
if (!isLaravelSuccess(response)) {
|
|
setError(response?.message || 'Unable to load record');
|
|
setItem(null);
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
const next = response.data?.item || {};
|
|
setItem(next);
|
|
setDoctors(response.data?.doctors || []);
|
|
setStatus(next.status || '');
|
|
setForm({
|
|
emp_id: next.emp_id || '',
|
|
employee_name: next.emp_name || '',
|
|
employee_phone: next.emp_phone || '',
|
|
employee_email: next.emp_email || '',
|
|
abm_name: next.abm_name || '',
|
|
abm_email: next.abm_email || '',
|
|
rbm_name: next.rbm_name || '',
|
|
dr_name: next.doctor_name || '',
|
|
doctor_mobile_number: next.doctor_phone || '',
|
|
speciality: next.doctor_speciality || '',
|
|
msl_code: next.msl_code || '',
|
|
type_of_nebulizer: next.type_of_nebulizer || 'Robust',
|
|
more_than_5_nebulizer: next.more_than_5_nebulizer || 'No',
|
|
no_of_nebulizer: next.no_of_nebulizer || '',
|
|
value_of_the_parcel: next.value_of_parcel || '',
|
|
clinic_hospital_home_name: next.clinic_hospital_name || '',
|
|
building_name: next.address_building || '',
|
|
address_type: next.address_type || '',
|
|
address_line_1: next.address_line_1 || '',
|
|
address_line_2: next.address_line_2 || '',
|
|
state: next.address_state || '',
|
|
city: next.address_city || '',
|
|
pin_code: next.address_pin_code || '',
|
|
team: next.team || '',
|
|
depot_name: next.depot_name || '',
|
|
rejected_reason: next.rejected_reason || '',
|
|
order_no: next.order_no || '',
|
|
invoice_no: next.invoice_no || '',
|
|
courier_name: next.courier_name || '',
|
|
lr_no: next.lr_no || '',
|
|
lr_date: next.lr_date ? String(next.lr_date).slice(0, 10) : '',
|
|
});
|
|
setLoading(false);
|
|
})();
|
|
return () => { cancelled = true; };
|
|
}, [id]);
|
|
|
|
const goNeighbor = async (direction) => {
|
|
const response = await laravelGet('neblogistic/neighbor', { id, direction, ...filterQuery });
|
|
if (!isLaravelSuccess(response)) {
|
|
setError(response?.message || 'No further entries available.');
|
|
return;
|
|
}
|
|
const next = new URLSearchParams({ ...filterQuery, id: response.data.id, requesttype: mode });
|
|
navigate(`/neblogisticreport/viewreportbyid?${next}`);
|
|
};
|
|
|
|
const save = async (payload) => {
|
|
setSaving(true);
|
|
setError('');
|
|
setMessage('');
|
|
const response = await laravelPost('neblogistic/update', { record_id: id, ...payload });
|
|
setSaving(false);
|
|
if (!isLaravelSuccess(response)) {
|
|
setError(response?.message || 'Save failed');
|
|
return;
|
|
}
|
|
setMessage(response.message || 'Data Saved');
|
|
};
|
|
|
|
if (loading) {
|
|
return <Container fluid className="py-5 text-center"><Spinner animation="border" /></Container>;
|
|
}
|
|
if (!item) {
|
|
return <Container fluid><div className="alert alert-danger">{error || 'Record not found'}</div></Container>;
|
|
}
|
|
|
|
const image = letterUrl(item.request_letter);
|
|
const canEdit = mode === 'edit';
|
|
|
|
return (
|
|
<Container fluid>
|
|
<PageBreadcrumb title={`${canEdit ? 'Edit' : 'View'} Neblogistic Report`} subtitle="Neb Logistics" />
|
|
{error ? <div className="alert alert-danger">{error}</div> : null}
|
|
{message ? <div className="alert alert-success">{message}</div> : null}
|
|
<div className="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-3">
|
|
<div>
|
|
RequestID: <strong>{item.id}</strong> <span className="text-muted">|</span> Status:{' '}
|
|
<span className="badge bg-info">{item.status}</span>
|
|
</div>
|
|
<div className="d-flex flex-wrap gap-2">
|
|
<Form.Select style={{ width: 180 }} value={status} onChange={(e) => setStatus(e.target.value)}>
|
|
<option value="">Select Status</option>
|
|
{STATUSES.map((value) => <option key={value} value={value}>{value}</option>)}
|
|
</Form.Select>
|
|
<Button size="sm" variant="dark" disabled={saving} onClick={() => save({ status, ...form })}>Change</Button>
|
|
<Button size="sm" variant="outline-dark" onClick={() => goNeighbor('prev')}>Prev</Button>
|
|
<Button size="sm" variant="outline-dark" onClick={() => goNeighbor('next')}>Next</Button>
|
|
<Button size="sm" variant="dark" as={Link} to="/neblogisticreports">Back</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<Row className="g-4">
|
|
<Col md={6}>
|
|
<Card>
|
|
<Card.Body>
|
|
<h4 className="text-primary">Employee Details</h4>
|
|
{canEdit ? (
|
|
<>
|
|
<Field label="Emp ID of TM"><Form.Control value={form.emp_id} onChange={(e) => setForm((p) => ({ ...p, emp_id: e.target.value }))} /></Field>
|
|
<Field label="Name of TM"><Form.Control value={form.employee_name} onChange={(e) => setForm((p) => ({ ...p, employee_name: e.target.value }))} /></Field>
|
|
<Field label="TM Mobile Number"><Form.Control value={form.employee_phone} onChange={(e) => setForm((p) => ({ ...p, employee_phone: e.target.value }))} /></Field>
|
|
<Field label="TM Email ID"><Form.Control type="email" value={form.employee_email} onChange={(e) => setForm((p) => ({ ...p, employee_email: e.target.value }))} /></Field>
|
|
<Field label="ABM Name"><Form.Control value={form.abm_name} onChange={(e) => setForm((p) => ({ ...p, abm_name: e.target.value }))} /></Field>
|
|
<Field label="ABM Email"><Form.Control value={form.abm_email} onChange={(e) => setForm((p) => ({ ...p, abm_email: e.target.value }))} /></Field>
|
|
<Field label="RBM Name"><Form.Control value={form.rbm_name} onChange={(e) => setForm((p) => ({ ...p, rbm_name: e.target.value }))} /></Field>
|
|
</>
|
|
) : (
|
|
<>
|
|
<ReadRow label="Emp ID of TM" value={item.emp_id} />
|
|
<ReadRow label="Name of TM" value={item.emp_name} />
|
|
<ReadRow label="TM Mobile Number" value={item.emp_phone} />
|
|
<ReadRow label="TM Email ID" value={item.emp_email} />
|
|
<ReadRow label="ABM Name" value={item.abm_name} />
|
|
<ReadRow label="RBM Name" value={item.rbm_name} />
|
|
</>
|
|
)}
|
|
<h4 className="text-primary mt-4">Doctor Details</h4>
|
|
{canEdit ? (
|
|
<>
|
|
<Field label="Dr Name"><Form.Control value={form.dr_name} onChange={(e) => setForm((p) => ({ ...p, dr_name: e.target.value }))} /></Field>
|
|
<Field label="Doctor Mobile Number"><Form.Control value={form.doctor_mobile_number} onChange={(e) => setForm((p) => ({ ...p, doctor_mobile_number: e.target.value }))} /></Field>
|
|
<Field label="Speciality">
|
|
<Form.Select value={form.speciality} onChange={(e) => setForm((p) => ({ ...p, speciality: e.target.value }))}>
|
|
<option value=""> -- Select -- </option>
|
|
{Object.entries(SPECIALITIES).map(([value, label]) => <option key={value} value={value}>{label}</option>)}
|
|
</Form.Select>
|
|
</Field>
|
|
<Field label="MSL CODE of Dr"><Form.Control value={form.msl_code} onChange={(e) => setForm((p) => ({ ...p, msl_code: e.target.value }))} /></Field>
|
|
<Field label="Type of Nebulizer">
|
|
<Form.Select value={form.type_of_nebulizer} onChange={(e) => setForm((p) => ({ ...p, type_of_nebulizer: e.target.value }))}>
|
|
{['Robust', 'Mini', 'Others'].map((value) => <option key={value}>{value}</option>)}
|
|
</Form.Select>
|
|
</Field>
|
|
<Field label="Do you need more than 5 nebulizers?">
|
|
<Form.Select value={form.more_than_5_nebulizer} onChange={(e) => setForm((p) => ({ ...p, more_than_5_nebulizer: e.target.value }))}>
|
|
<option>Yes</option>
|
|
<option>No</option>
|
|
</Form.Select>
|
|
</Field>
|
|
<Field label="No of Nebulizer"><Form.Control value={form.no_of_nebulizer} onChange={(e) => setForm((p) => ({ ...p, no_of_nebulizer: e.target.value }))} /></Field>
|
|
<Field label="Value of the Parcel"><Form.Control value={form.value_of_the_parcel} onChange={(e) => setForm((p) => ({ ...p, value_of_the_parcel: e.target.value }))} /></Field>
|
|
</>
|
|
) : (
|
|
<>
|
|
<ReadRow label="Dr Name" value={item.doctor_name} />
|
|
<ReadRow label="Doctor Mobile Number" value={item.doctor_phone} />
|
|
<ReadRow label="Speciality" value={item.doctor_speciality} />
|
|
<ReadRow label="MSL CODE of Dr" value={item.msl_code} />
|
|
<ReadRow label="Type of Nebulizer" value={item.type_of_nebulizer} />
|
|
<ReadRow label="Do you need more than 5 nebulizers" value={item.more_than_5_nebulizer} />
|
|
<ReadRow label="No of Nebulizer" value={item.no_of_nebulizer} />
|
|
<ReadRow label="Value of the Parcel" value={item.value_of_parcel} />
|
|
<ReadRow label="Team" value={item.team} />
|
|
</>
|
|
)}
|
|
</Card.Body>
|
|
</Card>
|
|
</Col>
|
|
<Col md={6}>
|
|
{image ? (
|
|
<Card className="mb-4">
|
|
<Card.Body>
|
|
<h4 className="text-primary">Request Letter</h4>
|
|
<img src={image} alt="Request Letter" className="img-fluid rounded border mb-2" style={{ maxHeight: 300, objectFit: 'contain' }} />
|
|
<a href={image} download>Download existing</a>
|
|
</Card.Body>
|
|
</Card>
|
|
) : null}
|
|
<Card>
|
|
<Card.Body>
|
|
<h4 className="text-primary">Drop Details</h4>
|
|
{canEdit ? (
|
|
<>
|
|
<Field label="Clinic / Hospital / Home Name"><Form.Control value={form.clinic_hospital_home_name} onChange={(e) => setForm((p) => ({ ...p, clinic_hospital_home_name: e.target.value }))} /></Field>
|
|
<Field label="Building Name"><Form.Control value={form.building_name} onChange={(e) => setForm((p) => ({ ...p, building_name: e.target.value }))} /></Field>
|
|
<Field label="Address Type"><Form.Control value={form.address_type} onChange={(e) => setForm((p) => ({ ...p, address_type: e.target.value }))} /></Field>
|
|
<Field label="Address line 1"><Form.Control value={form.address_line_1} onChange={(e) => setForm((p) => ({ ...p, address_line_1: e.target.value }))} /></Field>
|
|
<Field label="Address line 2"><Form.Control value={form.address_line_2} onChange={(e) => setForm((p) => ({ ...p, address_line_2: e.target.value }))} /></Field>
|
|
<Field label="State"><Form.Control value={form.state} onChange={(e) => setForm((p) => ({ ...p, state: e.target.value }))} /></Field>
|
|
<Field label="City"><Form.Control value={form.city} onChange={(e) => setForm((p) => ({ ...p, city: e.target.value }))} /></Field>
|
|
<Field label="Pin Code"><Form.Control value={form.pin_code} onChange={(e) => setForm((p) => ({ ...p, pin_code: e.target.value }))} /></Field>
|
|
<Field label="Depot"><Form.Control value={form.depot_name} onChange={(e) => setForm((p) => ({ ...p, depot_name: e.target.value }))} /></Field>
|
|
<Field label="Team"><Form.Control value={form.team} onChange={(e) => setForm((p) => ({ ...p, team: e.target.value }))} /></Field>
|
|
<Button disabled={saving} onClick={() => save({ ...form, status })}>Save Details</Button>
|
|
</>
|
|
) : (
|
|
<>
|
|
<ReadRow label="Clinic / Hospital / Home Name" value={item.clinic_hospital_name} />
|
|
<ReadRow label="Building Name" value={item.address_building} />
|
|
<ReadRow label="Address Type" value={item.address_type} />
|
|
<ReadRow label="Address line 1" value={item.address_line_1} />
|
|
<ReadRow label="Address line 2" value={item.address_line_2} />
|
|
<ReadRow label="State" value={item.address_state} />
|
|
<ReadRow label="City" value={item.address_city} />
|
|
<ReadRow label="Pin Code" value={item.address_pin_code} />
|
|
</>
|
|
)}
|
|
</Card.Body>
|
|
</Card>
|
|
{['Dispatched', 'Delivered'].includes(item.status) || status === 'Dispatched' ? (
|
|
<Card className="mt-4">
|
|
<Card.Body>
|
|
<h4 className="text-primary">Dispatch / Delivery Details</h4>
|
|
{canEdit ? (
|
|
<>
|
|
<Field label="Order No"><Form.Control value={form.order_no} onChange={(e) => setForm((p) => ({ ...p, order_no: e.target.value }))} /></Field>
|
|
<Field label="Invoice Number"><Form.Control value={form.invoice_no} onChange={(e) => setForm((p) => ({ ...p, invoice_no: e.target.value }))} /></Field>
|
|
<Field label="Courier Name"><Form.Control value={form.courier_name} onChange={(e) => setForm((p) => ({ ...p, courier_name: e.target.value }))} /></Field>
|
|
<Field label="LR Number"><Form.Control value={form.lr_no} onChange={(e) => setForm((p) => ({ ...p, lr_no: e.target.value }))} /></Field>
|
|
<Field label="LR Date"><Form.Control type="date" value={form.lr_date} onChange={(e) => setForm((p) => ({ ...p, lr_date: e.target.value }))} /></Field>
|
|
</>
|
|
) : (
|
|
<>
|
|
<ReadRow label="Invoice Number" value={item.invoice_no} />
|
|
<ReadRow label="Courier Name" value={item.courier_name} />
|
|
<ReadRow label="LR Number" value={item.lr_no} />
|
|
<ReadRow label="LR Date" value={item.lr_date} />
|
|
</>
|
|
)}
|
|
</Card.Body>
|
|
</Card>
|
|
) : null}
|
|
{status === 'Rejected' && canEdit ? (
|
|
<Card className="mt-4">
|
|
<Card.Body>
|
|
<Field label="Rejected Reason"><Form.Control as="textarea" rows={3} value={form.rejected_reason} onChange={(e) => setForm((p) => ({ ...p, rejected_reason: e.target.value }))} /></Field>
|
|
</Card.Body>
|
|
</Card>
|
|
) : null}
|
|
</Col>
|
|
</Row>
|
|
{doctors.length ? (
|
|
<Card className="mt-4">
|
|
<Card.Body>
|
|
<h4 className="text-primary">Other requests with same MSL</h4>
|
|
{doctors.map((row) => (
|
|
<div key={row.id} className="small text-muted">{row.id} — {row.emp_name} — {row.status}</div>
|
|
))}
|
|
</Card.Body>
|
|
</Card>
|
|
) : null}
|
|
</Container>
|
|
);
|
|
}
|