import React, { useEffect, useState } from "react"; import { Button } from "../ui/button"; import { Input } from "../ui/input"; import { Switch } from "../ui/switch"; import { toast } from "sonner"; import { ApiError } from "../../lib/apiClient"; import { updateLocationsBulk, type LocationBulkUpdateItemVo } from "../../services/locationService"; import type { LocationDto } from "../../types/location"; const ZERO = "00000000-0000-0000-0000-000000000000"; function isValidBulkId(id: string): boolean { const s = (id ?? "").trim(); if (!s) return false; return s.toLowerCase() !== ZERO; } export type LocationBulkEditPageProps = { seed: LocationDto[]; onBack: () => void; onSaved: () => void; }; type RowState = LocationBulkUpdateItemVo & { locationCodeReadonly: string }; function locToRow(loc: LocationDto): RowState { return { id: loc.id, locationCodeReadonly: (loc.locationCode ?? loc.id ?? "").trim(), partner: loc.partner ?? "", groupName: loc.groupName ?? "", locationName: (loc.locationName ?? "").trim() || "", street: loc.street ?? "", city: loc.city ?? "", stateCode: loc.stateCode ?? "", country: loc.country ?? "", zipCode: loc.zipCode ?? "", phone: loc.phone ?? "", email: loc.email ?? "", latitude: loc.latitude ?? null, longitude: loc.longitude ?? null, state: loc.state !== false, }; } export function LocationBulkEditPage({ seed, onBack, onSaved }: LocationBulkEditPageProps) { const [rows, setRows] = useState([]); const [saving, setSaving] = useState(false); useEffect(() => { setRows(seed.map(locToRow)); }, [seed]); const updateRow = (idx: number, patch: Partial) => { setRows((prev) => { const next = [...prev]; next[idx] = { ...next[idx], ...patch }; return next; }); }; const handleSave = async () => { const items: LocationBulkUpdateItemVo[] = rows .filter((r) => isValidBulkId(r.id)) .map((r) => ({ id: r.id.trim(), partner: r.partner?.trim() || null, groupName: r.groupName?.trim() || null, locationName: r.locationName.trim(), street: r.street?.trim() || null, city: r.city?.trim() || null, stateCode: r.stateCode?.trim() || null, country: r.country?.trim() || null, zipCode: r.zipCode?.trim() || null, phone: r.phone?.trim() || null, email: r.email?.trim() || null, latitude: r.latitude, longitude: r.longitude, state: r.state !== false, })); if (items.length === 0) { toast.error("No valid rows", { description: "Select locations in the list first, then open Bulk Edit." }); return; } setSaving(true); try { const res = await updateLocationsBulk({ items }); toast.success("Bulk update finished", { description: `Success: ${res.successCount}, failed: ${res.failCount}`, }); if (res.errors?.length) { const preview = res.errors .slice(0, 5) .map((e) => `Row ${e.rowNumber ?? "?"}: ${e.message ?? ""}`) .join("\n"); toast.message("Errors (first 5)", { description: preview }); } onSaved(); onBack(); } catch (e) { const msg = e instanceof ApiError ? e.message : e instanceof Error ? e.message : "Save failed."; toast.error("Bulk save failed", { description: msg }); } finally { setSaving(false); } }; return (

Location bulk edit

{rows.map((r, idx) => ( ))}
# Location ID Company Region Location Name * Street City State Country Zip Phone Email Lat Lng Active
{idx + 1} updateRow(idx, { partner: e.target.value })} /> updateRow(idx, { groupName: e.target.value })} /> updateRow(idx, { locationName: e.target.value })} /> updateRow(idx, { street: e.target.value })} /> updateRow(idx, { city: e.target.value })} /> updateRow(idx, { stateCode: e.target.value })} /> updateRow(idx, { country: e.target.value })} /> updateRow(idx, { zipCode: e.target.value })} /> updateRow(idx, { phone: e.target.value })} /> updateRow(idx, { email: e.target.value })} /> { const v = e.target.value.trim(); updateRow(idx, { latitude: v === "" ? null : Number(v) }); }} /> { const v = e.target.value.trim(); updateRow(idx, { longitude: v === "" ? null : Number(v) }); }} />
updateRow(idx, { state: !!c })} />

Only the locations you selected in the list are shown here.

You can copy and paste from Excel or Google Sheets.

Columns marked * are required for each row.

); }