feat(vessels): remove IMO number tracking

This commit is contained in:
Hardik 2026-05-22 17:14:40 +05:30
parent 1ea22df2f7
commit 2c39f0225f
8 changed files with 24 additions and 97 deletions

View file

@ -31,7 +31,7 @@ export default async function SiteDetailPage({ params }: Props) {
db.site.findUnique({
where: { id },
include: {
vessels: { select: { id: true, name: true, imoNumber: true, isActive: true } },
vessels: { select: { id: true, name: true, isActive: true } },
inventory: {
include: { product: { select: { id: true, name: true, code: true } } },
orderBy: { quantity: "desc" },
@ -176,7 +176,6 @@ export default async function SiteDetailPage({ params }: Props) {
<Link key={v.id} href={`/admin/vessels/${v.id}`}
className="rounded-lg border border-neutral-200 px-3 py-1.5 text-sm font-medium text-neutral-700 hover:bg-neutral-50">
{v.name}
{v.imoNumber && <span className="ml-1.5 text-xs text-neutral-400 font-mono">IMO {v.imoNumber}</span>}
</Link>
))}
</div>

View file

@ -55,7 +55,6 @@ export default async function VesselDetailPage({ params }: Props) {
<div className="flex items-start justify-between gap-4">
<div>
<div className="flex items-center gap-3 mb-1">
{vessel.imoNumber && <span className="font-mono text-xs text-neutral-500">IMO {vessel.imoNumber}</span>}
<span className={`rounded-full px-2.5 py-0.5 text-xs font-medium ${vessel.isActive ? "bg-success-100 text-success-700" : "bg-neutral-100 text-neutral-500"}`}>
{vessel.isActive ? "Active" : "Inactive"}
</span>

View file

@ -10,7 +10,6 @@ type ActionResult = { ok: true } | { error: string };
const vesselSchema = z.object({
name: z.string().min(1, "Vessel name is required"),
imoNumber: z.string().optional(),
});
export async function createVessel(formData: FormData): Promise<ActionResult> {
@ -21,17 +20,10 @@ export async function createVessel(formData: FormData): Promise<ActionResult> {
const parsed = vesselSchema.safeParse({
name: formData.get("name"),
imoNumber: formData.get("imoNumber") || undefined,
});
if (!parsed.success) return { error: parsed.error.errors[0]?.message ?? "Validation failed" };
const data = parsed.data;
if (data.imoNumber) {
const exists = await db.vessel.findUnique({ where: { imoNumber: data.imoNumber } });
if (exists) return { error: "A vessel with that IMO number already exists" };
}
await db.vessel.create({ data: { name: data.name, imoNumber: data.imoNumber ?? null } });
await db.vessel.create({ data: { name: parsed.data.name } });
revalidatePath("/admin/vessels");
return { ok: true };
}
@ -47,17 +39,10 @@ export async function updateVessel(formData: FormData): Promise<ActionResult> {
const parsed = vesselSchema.safeParse({
name: formData.get("name"),
imoNumber: formData.get("imoNumber") || undefined,
});
if (!parsed.success) return { error: parsed.error.errors[0]?.message ?? "Validation failed" };
const data = parsed.data;
if (data.imoNumber) {
const conflict = await db.vessel.findFirst({ where: { imoNumber: data.imoNumber, id: { not: id } } });
if (conflict) return { error: "Another vessel already has that IMO number" };
}
await db.vessel.update({ where: { id }, data: { name: data.name, imoNumber: data.imoNumber ?? null } });
await db.vessel.update({ where: { id }, data: { name: parsed.data.name } });
revalidatePath("/admin/vessels");
return { ok: true };
}

View file

@ -29,7 +29,6 @@ export default async function AdminVesselsPage() {
<thead className="bg-neutral-50 border-b border-neutral-200">
<tr>
<th className="px-4 py-3 text-left font-medium text-neutral-600">Name</th>
<th className="px-4 py-3 text-left font-medium text-neutral-600">IMO Number</th>
<th className="px-4 py-3 text-left font-medium text-neutral-600">Status</th>
<th className="px-4 py-3"></th>
</tr>
@ -38,9 +37,6 @@ export default async function AdminVesselsPage() {
{vessels.map((vessel) => (
<tr key={vessel.id} className="hover:bg-neutral-50">
<td className="px-4 py-3 font-medium text-neutral-900">{vessel.name}</td>
<td className="px-4 py-3 font-mono text-xs text-neutral-600">
{vessel.imoNumber ?? <span className="text-neutral-400 italic"></span>}
</td>
<td className="px-4 py-3">
<span className={`rounded-full px-2.5 py-0.5 text-xs font-medium ${
vessel.isActive ? "bg-success-100 text-success-700" : "bg-neutral-100 text-neutral-500"
@ -53,7 +49,6 @@ export default async function AdminVesselsPage() {
<EditVesselButton vessel={{
id: vessel.id,
name: vessel.name,
imoNumber: vessel.imoNumber,
isActive: vessel.isActive,
}} />
<ConfirmDeleteButton onDelete={deleteVessel.bind(null, vessel.id)} label={vessel.name} />

View file

@ -8,7 +8,6 @@ import { createVessel, updateVessel, toggleVesselActive } from "./actions";
type VesselRow = {
id: string;
name: string;
imoNumber: string | null;
isActive: boolean;
};
@ -20,12 +19,6 @@ function VesselFormFields({ vessel }: { vessel?: VesselRow }) {
<input name="name" defaultValue={vessel?.name} required
className="w-full rounded-lg border border-neutral-300 px-3 py-2 text-sm focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20" />
</div>
<div>
<label className="block text-xs font-medium text-neutral-700 mb-1">IMO Number (optional)</label>
<input name="imoNumber" defaultValue={vessel?.imoNumber ?? ""}
className="w-full rounded-lg border border-neutral-300 px-3 py-2 text-sm focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20"
placeholder="e.g. 1234567" />
</div>
</div>
);
}

View file

@ -0,0 +1,3 @@
-- AlterTable
DROP INDEX IF EXISTS "Vessel_imoNumber_key";
ALTER TABLE "Vessel" DROP COLUMN IF EXISTS "imoNumber";

View file

@ -107,7 +107,6 @@ model Site {
model Vessel {
id String @id @default(cuid())
name String
imoNumber String? @unique
isActive Boolean @default(true)
siteId String?

View file

@ -157,71 +157,25 @@ async function main() {
});
// ─── Vessels (Cost Centres) ──────────────────────────────────────────────────
const mvStar = await db.vessel.upsert({
where: { imoNumber: "IMO9876543" },
update: {},
create: { name: "MV Pelagia Star", imoNumber: "IMO9876543", siteId: siteBOM.id },
});
const findOrCreateVessel = async (name: string, siteId: string) => {
const vessel = await db.vessel.findFirst({ where: { name } });
if (vessel) {
return db.vessel.update({ where: { id: vessel.id }, data: { siteId } });
}
return db.vessel.create({ data: { name, siteId } });
};
const mvWind = await db.vessel.upsert({
where: { imoNumber: "IMO9123456" },
update: {},
create: { name: "MV Aegean Wind", imoNumber: "IMO9123456", siteId: siteJNP.id },
});
const mvPoseidon = await db.vessel.upsert({
where: { imoNumber: "IMO9654321" },
update: {},
create: { name: "MV Poseidon", imoNumber: "IMO9654321", siteId: siteKDL.id },
});
const mvNereid = await db.vessel.upsert({
where: { imoNumber: "IMO9234567" },
update: {},
create: { name: "MV Nereid", imoNumber: "IMO9234567", siteId: siteCHE.id },
});
const mvThetis = await db.vessel.upsert({
where: { imoNumber: "IMO9345678" },
update: {},
create: { name: "MV Thetis", imoNumber: "IMO9345678", siteId: siteKOC.id },
});
const mvTriton = await db.vessel.upsert({
where: { imoNumber: "IMO9456789" },
update: {},
create: { name: "MV Triton", imoNumber: "IMO9456789", siteId: siteVIZ.id },
});
const mvAmphitrite = await db.vessel.upsert({
where: { imoNumber: "IMO9567890" },
update: {},
create: { name: "MV Amphitrite", imoNumber: "IMO9567890", siteId: siteHAL.id },
});
const mvProteus = await db.vessel.upsert({
where: { imoNumber: "IMO9678901" },
update: {},
create: { name: "MV Proteus", imoNumber: "IMO9678901", siteId: sitePAR.id },
});
const mvGalatea = await db.vessel.upsert({
where: { imoNumber: "IMO9789012" },
update: {},
create: { name: "MV Galatea", imoNumber: "IMO9789012", siteId: siteMNG.id },
});
const mvCallisto = await db.vessel.upsert({
where: { imoNumber: "IMO9890123" },
update: {},
create: { name: "MV Callisto", imoNumber: "IMO9890123", siteId: siteGOA.id },
});
await db.vessel.upsert({
where: { imoNumber: "IMO9901234" },
update: {},
create: { name: "MV Doris", imoNumber: "IMO9901234", siteId: siteCHE.id },
});
const mvStar = await findOrCreateVessel("MV Pelagia Star", siteBOM.id);
const mvWind = await findOrCreateVessel("MV Aegean Wind", siteJNP.id);
const mvPoseidon = await findOrCreateVessel("MV Poseidon", siteKDL.id);
const mvNereid = await findOrCreateVessel("MV Nereid", siteCHE.id);
const mvThetis = await findOrCreateVessel("MV Thetis", siteKOC.id);
const mvTriton = await findOrCreateVessel("MV Triton", siteVIZ.id);
const mvAmphitrite = await findOrCreateVessel("MV Amphitrite", siteHAL.id);
const mvProteus = await findOrCreateVessel("MV Proteus", sitePAR.id);
const mvGalatea = await findOrCreateVessel("MV Galatea", siteMNG.id);
const mvCallisto = await findOrCreateVessel("MV Callisto", siteGOA.id);
await findOrCreateVessel("MV Doris", siteCHE.id);
// ─── Accounts ────────────────────────────────────────────────────────────────
const accTechOps = await db.account.upsert({