added other materials tab

This commit is contained in:
xCyanGrizzly
2026-02-18 21:55:39 +01:00
parent ec04e1bd0b
commit 32683ecf5e
14 changed files with 1272 additions and 7 deletions

View File

@@ -3,7 +3,7 @@ import { prisma } from "@/lib/prisma";
interface LowStockItem {
id: string;
name: string;
type: "filament" | "resin" | "paint";
type: "filament" | "resin" | "paint" | "supply";
colorHex: string;
remaining: number;
total: number;
@@ -33,7 +33,7 @@ export async function getDashboardStats(
userId: string,
lowStockThreshold: number
): Promise<DashboardStats> {
const [filaments, resins, paints, usageLogs24h, recentLogs] = await Promise.all([
const [filaments, resins, paints, supplies, usageLogs24h, recentLogs] = await Promise.all([
prisma.filament.findMany({
where: { userId, archived: false },
select: {
@@ -67,6 +67,17 @@ export async function getDashboardStats(
cost: true,
},
}),
prisma.supply.findMany({
where: { userId, archived: false },
select: {
id: true,
name: true,
colorHex: true,
totalAmount: true,
usedAmount: true,
cost: true,
},
}),
prisma.usageLog.count({
where: {
userId,
@@ -81,16 +92,18 @@ export async function getDashboardStats(
filament: { select: { name: true } },
resin: { select: { name: true } },
paint: { select: { name: true } },
supply: { select: { name: true } },
},
}),
]);
const totalItems = filaments.length + resins.length + paints.length;
const totalItems = filaments.length + resins.length + paints.length + supplies.length;
const inventoryValue =
filaments.reduce((sum: number, f: { cost: number | null }) => sum + (f.cost ?? 0), 0) +
resins.reduce((sum: number, r: { cost: number | null }) => sum + (r.cost ?? 0), 0) +
paints.reduce((sum: number, p: { cost: number | null }) => sum + (p.cost ?? 0), 0);
paints.reduce((sum: number, p: { cost: number | null }) => sum + (p.cost ?? 0), 0) +
supplies.reduce((sum: number, s: { cost: number | null }) => sum + (s.cost ?? 0), 0);
const lowStockItems: LowStockItem[] = [];
@@ -142,6 +155,22 @@ export async function getDashboardStats(
}
}
for (const s of supplies) {
const remaining = s.totalAmount - s.usedAmount;
const percent = s.totalAmount > 0 ? (remaining / s.totalAmount) * 100 : 0;
if (percent <= lowStockThreshold && percent > 0) {
lowStockItems.push({
id: s.id,
name: s.name,
type: "supply",
colorHex: s.colorHex ?? "#6b7280",
remaining,
total: s.totalAmount,
percent,
});
}
}
lowStockItems.sort((a, b) => a.percent - b.percent);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -153,7 +182,7 @@ export async function getDashboardStats(
notes: log.notes,
createdAt: log.createdAt,
itemName:
log.filament?.name ?? log.resin?.name ?? log.paint?.name ?? "Unknown",
log.filament?.name ?? log.resin?.name ?? log.paint?.name ?? log.supply?.name ?? "Unknown",
}));
return {

View File

@@ -0,0 +1,80 @@
import { prisma } from "@/lib/prisma";
import { Prisma } from "@prisma/client";
import type { DataTableSearchParams } from "@/types/table.types";
interface SupplySearchParams extends DataTableSearchParams {
category?: string | string[];
vendor?: string | string[];
location?: string | string[];
}
export async function getSupplies(userId: string, params: SupplySearchParams) {
const page = Number(params.page) || 1;
const perPage = Number(params.perPage) || 20;
const skip = (page - 1) * perPage;
const categories = Array.isArray(params.category)
? params.category
: params.category
? [params.category]
: [];
const vendorIds = Array.isArray(params.vendor)
? params.vendor
: params.vendor
? [params.vendor]
: [];
const locationIds = Array.isArray(params.location)
? params.location
: params.location
? [params.location]
: [];
const where: Prisma.SupplyWhereInput = {
userId,
archived: params.archived === "true" ? undefined : false,
...(params.search && {
OR: [
{ name: { contains: params.search, mode: "insensitive" as Prisma.QueryMode } },
{ brand: { contains: params.search, mode: "insensitive" as Prisma.QueryMode } },
{ color: { contains: params.search, mode: "insensitive" as Prisma.QueryMode } },
],
}),
...(categories.length > 0 && { category: { in: categories } }),
...(vendorIds.length > 0 && { vendorId: { in: vendorIds } }),
...(locationIds.length > 0 && { locationId: { in: locationIds } }),
};
const sortField = params.sort || "createdAt";
const sortOrder = params.order || "desc";
const [data, totalCount] = await Promise.all([
prisma.supply.findMany({
where,
orderBy: { [sortField]: sortOrder },
skip,
take: perPage,
include: {
vendor: { select: { id: true, name: true } },
location: { select: { id: true, name: true } },
},
}),
prisma.supply.count({ where }),
]);
return {
data,
pageCount: Math.ceil(totalCount / perPage),
totalCount,
};
}
export async function getSupplyById(id: string, userId: string) {
return prisma.supply.findFirst({
where: { id, userId },
include: {
vendor: { select: { id: true, name: true } },
location: { select: { id: true, name: true } },
tags: { include: { tag: true } },
},
});
}