feat(roadmap): reschedule from the timeline, always audited
This commit is contained in:
parent
bed7af848e
commit
ecf5f0c173
1 changed files with 59 additions and 0 deletions
59
src/app/actions/reschedule.ts
Normal file
59
src/app/actions/reschedule.ts
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
|
||||
import { getServerPb } from "@/lib/pb/server";
|
||||
import { requireSession } from "@/lib/auth/session";
|
||||
import { logActivity } from "@/app/actions/activity";
|
||||
import type { CardRecord } from "@/lib/pb/types";
|
||||
|
||||
const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
||||
|
||||
/**
|
||||
* Move a card's target date from the timeline. Owner only.
|
||||
*
|
||||
* `target_date` is a CLIENT-OWNED field. The owner may write it — PocketBase
|
||||
* permits it — but doing so silently would mean a developer moving a date the
|
||||
* client chose with no record of it. The activity row below is what makes the
|
||||
* client's card history read "Dave moved the target date from 1 Oct to 15 Nov",
|
||||
* in their own view, without anyone having to tell them.
|
||||
*
|
||||
* Do not remove that call to make this faster.
|
||||
*/
|
||||
export async function rescheduleCardAction(input: {
|
||||
cardId: string;
|
||||
date: string;
|
||||
}): Promise<{ ok: boolean; message?: string }> {
|
||||
const session = await requireSession();
|
||||
if (session.role !== "owner") return { ok: false, message: "Not found" };
|
||||
|
||||
if (!ISO_DATE.test(input.date)) {
|
||||
return { ok: false, message: "Invalid date" };
|
||||
}
|
||||
|
||||
const pb = await getServerPb();
|
||||
|
||||
const card = await pb
|
||||
.collection("cards")
|
||||
.getOne<CardRecord>(input.cardId)
|
||||
.catch(() => null);
|
||||
if (!card) return { ok: false, message: "Card not found" };
|
||||
|
||||
const previous = (card.target_date ?? "").slice(0, 10);
|
||||
if (previous === input.date) return { ok: true };
|
||||
|
||||
await pb.collection("cards").update(input.cardId, { target_date: input.date });
|
||||
|
||||
await logActivity({
|
||||
project: card.project,
|
||||
card: card.id,
|
||||
actor: session.userId,
|
||||
action: "date_changed",
|
||||
field: "target_date",
|
||||
oldValue: card.target_date ?? "",
|
||||
newValue: input.date,
|
||||
});
|
||||
|
||||
revalidatePath("/plan");
|
||||
return { ok: true };
|
||||
}
|
||||
Loading…
Reference in a new issue