feat(staff column order in aptmpt page)
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
import { Staff } from "@repo/db/types";
|
||||
import { Staff, StaffCreateInput, StaffUpdateInput } from "@repo/db/types";
|
||||
import { prisma as db } from "@repo/db/client";
|
||||
|
||||
export interface IStorage {
|
||||
getStaff(id: number): Promise<Staff | undefined>;
|
||||
getAllStaff(): Promise<Staff[]>;
|
||||
createStaff(staff: Staff): Promise<Staff>;
|
||||
updateStaff(id: number, updates: Partial<Staff>): Promise<Staff | undefined>;
|
||||
createStaff(staff: StaffCreateInput): Promise<Staff>;
|
||||
updateStaff(
|
||||
id: number,
|
||||
updates: StaffUpdateInput,
|
||||
): Promise<Staff | undefined>;
|
||||
deleteStaff(id: number): Promise<boolean>;
|
||||
countAppointmentsByStaffId(staffId: number): Promise<number>;
|
||||
countClaimsByStaffId(staffId: number): Promise<number>;
|
||||
@@ -19,38 +22,122 @@ export const staffStorage: IStorage = {
|
||||
},
|
||||
|
||||
async getAllStaff(): Promise<Staff[]> {
|
||||
const staff = await db.staff.findMany();
|
||||
return staff;
|
||||
},
|
||||
|
||||
async createStaff(staff: Staff): Promise<Staff> {
|
||||
const createdStaff = await db.staff.create({
|
||||
data: staff,
|
||||
return db.staff.findMany({
|
||||
orderBy: { displayOrder: "asc" },
|
||||
});
|
||||
return createdStaff;
|
||||
},
|
||||
|
||||
async createStaff(staff: StaffCreateInput): Promise<Staff> {
|
||||
const max = await db.staff.aggregate({
|
||||
where: {
|
||||
userId: staff.userId,
|
||||
displayOrder: { gt: 0 },
|
||||
},
|
||||
_max: { displayOrder: true },
|
||||
});
|
||||
|
||||
return db.staff.create({
|
||||
data: {
|
||||
...staff,
|
||||
displayOrder: (max._max.displayOrder ?? 0) + 1,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
async updateStaff(
|
||||
id: number,
|
||||
updates: Partial<Staff>
|
||||
updates: StaffUpdateInput,
|
||||
): Promise<Staff | undefined> {
|
||||
const updatedStaff = await db.staff.update({
|
||||
where: { id },
|
||||
data: updates,
|
||||
return db.$transaction(async (tx: any) => {
|
||||
const staff = await tx.staff.findUnique({ where: { id } });
|
||||
if (!staff) return undefined;
|
||||
|
||||
const { userId, displayOrder: oldOrder } = staff;
|
||||
const newOrder = updates.displayOrder;
|
||||
|
||||
if (newOrder === undefined || newOrder === oldOrder) {
|
||||
return tx.staff.update({
|
||||
where: { id },
|
||||
data: updates,
|
||||
});
|
||||
}
|
||||
|
||||
const totalStaff = await tx.staff.count({ where: { userId } });
|
||||
|
||||
if (newOrder < 1 || newOrder > totalStaff) {
|
||||
throw new Error(`displayOrder must be between 1 and ${totalStaff}`);
|
||||
}
|
||||
|
||||
const occupyingStaff = await tx.staff.findFirst({
|
||||
where: {
|
||||
userId,
|
||||
displayOrder: newOrder,
|
||||
},
|
||||
});
|
||||
|
||||
// CASE 1: staff already had a slot → SWAP
|
||||
if (oldOrder && oldOrder > 0 && occupyingStaff) {
|
||||
await tx.staff.update({
|
||||
where: { id: occupyingStaff.id },
|
||||
data: { displayOrder: oldOrder },
|
||||
});
|
||||
}
|
||||
|
||||
// CASE 2: first-time assignment (oldOrder = 0)
|
||||
if ((!oldOrder || oldOrder === 0) && occupyingStaff) {
|
||||
// find first free slot
|
||||
const usedOrders = await tx.staff.findMany({
|
||||
where: {
|
||||
userId,
|
||||
displayOrder: { gt: 0 },
|
||||
},
|
||||
select: { displayOrder: true },
|
||||
orderBy: { displayOrder: "asc" },
|
||||
});
|
||||
|
||||
const usedSet = new Set(usedOrders.map((s: any) => s.displayOrder));
|
||||
let freeSlot = 1;
|
||||
while (usedSet.has(freeSlot)) freeSlot++;
|
||||
|
||||
await tx.staff.update({
|
||||
where: { id: occupyingStaff.id },
|
||||
data: { displayOrder: freeSlot },
|
||||
});
|
||||
}
|
||||
|
||||
return tx.staff.update({
|
||||
where: { id },
|
||||
data: {
|
||||
...updates,
|
||||
displayOrder: newOrder,
|
||||
},
|
||||
});
|
||||
});
|
||||
return updatedStaff ?? undefined;
|
||||
},
|
||||
|
||||
async deleteStaff(id: number): Promise<boolean> {
|
||||
try {
|
||||
await db.staff.delete({ where: { id } });
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("Error deleting staff:", error);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
return db.$transaction(async (tx: any) => {
|
||||
const staff = await tx.staff.findUnique({ where: { id } });
|
||||
if (!staff) return false;
|
||||
|
||||
const { userId, displayOrder } = staff;
|
||||
|
||||
await tx.staff.delete({ where: { id } });
|
||||
|
||||
// Shift left to remove gap
|
||||
await tx.staff.updateMany({
|
||||
where: {
|
||||
userId,
|
||||
displayOrder: { gt: displayOrder },
|
||||
},
|
||||
data: {
|
||||
displayOrder: { decrement: 1 },
|
||||
},
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
},
|
||||
async countAppointmentsByStaffId(staffId: number): Promise<number> {
|
||||
return await db.appointment.count({ where: { staffId } });
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user