fix(inventory): envelope transfer responses and add defensive array guards in UI
This commit is contained in:
@@ -216,16 +216,20 @@ export function ChangeInventoryPage() {
|
||||
setLoadingTransfers(true);
|
||||
try {
|
||||
const list = await apiV26.projectTransfers.list(user.project_id, "outgoing");
|
||||
setTransfers(list);
|
||||
setTransfers(Array.isArray(list) ? list : []);
|
||||
} catch (err) {
|
||||
console.error("Failed to load project transfers:", err);
|
||||
setTransfers([]);
|
||||
} finally {
|
||||
setLoadingTransfers(false);
|
||||
}
|
||||
}, [user?.project_id]);
|
||||
|
||||
useEffect(() => {
|
||||
api.projects.list().then(setAllProjects).catch(() => {});
|
||||
api.projects
|
||||
.list()
|
||||
.then((res) => setAllProjects(Array.isArray(res) ? res : []))
|
||||
.catch(() => setAllProjects([]));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -651,7 +655,7 @@ export function ChangeInventoryPage() {
|
||||
onChange={(e) => setToProjectId(e.target.value)}
|
||||
>
|
||||
<option value="">— انتخاب پروژه مقصد —</option>
|
||||
{allProjects
|
||||
{(allProjects || [])
|
||||
.filter((p) => p.id !== user?.project_id)
|
||||
.map((p) => (
|
||||
<option key={p.id} value={p.id}>
|
||||
@@ -840,11 +844,11 @@ export function ChangeInventoryPage() {
|
||||
onChange={(e) => setNote(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
{type === "PROJECT_TRANSFER" && matchedStock && matchedStock.length > 0 && (
|
||||
{type === "PROJECT_TRANSFER" && (matchedStock?.length ?? 0) > 0 && (
|
||||
<div className="field md:col-span-2 rounded-lg border border-line/70 bg-bg/50 p-3 text-xs">
|
||||
<div className="font-semibold text-muted mb-1.5">موجودیهای فعلی این متریال در انبار مبدأ ({whName(warehouses, whId)}):</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{matchedStock.map((s) => (
|
||||
{(matchedStock || []).map((s) => (
|
||||
<div key={s.id} className="rounded-md border border-line bg-panel px-2.5 py-1 text-[11.5px] shadow-2xs">
|
||||
<span className="font-medium">{s.brand?.name || "بدون برند"}</span>
|
||||
<span className="text-muted"> — {Object.entries(s.specs || {}).map(([k, v]) => `${k}: ${v}`).join(" · ") || "بدون مشخصه"} — </span>
|
||||
@@ -940,7 +944,7 @@ export function ChangeInventoryPage() {
|
||||
|
||||
{loadingTransfers ? (
|
||||
<div className="py-8 text-center text-xs text-muted">در حال بارگذاری سوابق…</div>
|
||||
) : !transfers.length ? (
|
||||
) : !(transfers || []).length ? (
|
||||
<div className="py-8 text-center text-xs text-muted">هیچ انتقال بین کارگاهی از این پروژه ثبت نشده است.</div>
|
||||
) : (
|
||||
<div className="mt-3 overflow-x-auto">
|
||||
@@ -957,7 +961,7 @@ export function ChangeInventoryPage() {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-line/50">
|
||||
{transfers.map((t) => {
|
||||
{(transfers || []).map((t) => {
|
||||
const isInTransit = t.status === "in_transit";
|
||||
return (
|
||||
<tr key={t.id} className="hover:bg-bg/40">
|
||||
@@ -1057,7 +1061,7 @@ export function ChangeInventoryPage() {
|
||||
value={editToProjectId}
|
||||
onChange={(e) => setEditToProjectId(e.target.value)}
|
||||
>
|
||||
{allProjects
|
||||
{(allProjects || [])
|
||||
.filter((p) => p.id !== user?.project_id)
|
||||
.map((p) => (
|
||||
<option key={p.id} value={p.id}>
|
||||
|
||||
Reference in New Issue
Block a user