added number of properties aggregation

This commit is contained in:
Khalim Conn-Kowlessar 2023-08-21 19:28:07 +01:00
parent 35a1629336
commit 3c37a6e15e
4 changed files with 148 additions and 14 deletions

View file

@ -0,0 +1,84 @@
"use client";
import {
flexRender,
getCoreRowModel,
useReactTable,
ColumnDef,
} from "@tanstack/react-table";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/app/shadcn_components/ui/table";
import { Feature, GeneralFeature } from "@/app/db/schema/property";
interface DataTableProps<T extends Feature | GeneralFeature> {
columns: ColumnDef<T>[];
data: T[];
}
export default function FeatureTable<T extends Feature | GeneralFeature>({
data,
columns,
}: DataTableProps<T>) {
// Initialise the table
const table = useReactTable({
data,
columns,
getCoreRowModel: getCoreRowModel(),
});
return (
<div className="rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHead>
);
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
);
}

View file

@ -0,0 +1,24 @@
"use client";
import { PortfolioPlanRecommendation } from "@/app/db/schema/recommendations";
import { Badge } from "@/app/shadcn_components/ui/badge";
import { ColumnDef } from "@tanstack/react-table";
export const retrofitColumns: ColumnDef<PortfolioPlanRecommendation>[] = [
{
accessorKey: "materialType",
header: "Retrofit Measure",
},
{
accessorKey: "Number o",
header: "Number of Properties",
},
{
accessorKey: "quantity",
header: "Number of Properties",
},
{
accessorKey: "estimatedCost",
header: "Estimated Cost",
},
];

View file

@ -145,3 +145,19 @@ export type PlanRecommendations = InferModel<
// We allow recommendation types to be a string however we'll set up a typing for it here to control
// the types we expect
export type RecommendationType = "wall_insulation" | "floor_insulation";
export type UnnestedRecommendation = {
quantity: number;
quantityUnit: string;
estimatedCost: number;
materialType: string;
propertyId: string;
};
export interface PortfolioPlanRecommendation {
quantity: number;
quantityUnit: string;
estimatedCost: number;
materialType: string;
numberOfProperties: number;
}

View file

@ -1,5 +1,8 @@
import { recommendation } from "./../../db/schema/recommendations";
import { material } from "./../../db/schema/materials";
import {
recommendation,
UnnestedRecommendation,
PortfolioPlanRecommendation,
} from "./../../db/schema/recommendations";
import { and, eq, inArray } from "drizzle-orm";
import { db } from "@/app/db/db";
import { portfolio } from "@/app/db/schema/portfolio";
@ -8,13 +11,6 @@ import type { Portfolio } from "@/app/db/schema/portfolio";
import type { PropertyWithTarget } from "@/app/db/schema/property";
import { plan, planRecommendations } from "@/app/db/schema/recommendations";
type UnnestedRecommendation = {
quantity: number;
quantityUnit: string;
estimatedCost: number;
materialType: string;
};
export async function getPortfolio(portfolioId: string): Promise<Portfolio> {
const data = await db
.select()
@ -61,15 +57,21 @@ export async function getProperties(
return data;
}
interface Recommendation {
interface UnaggregatedPortfolioPlanRecommendation {
quantity: number;
quantityUnit: string;
estimatedCost: number;
materialType: string;
propertyId?: string;
numberOfProperties?: number; // Optional field to hold the count of unique propertyIds
}
function aggregateRecommendations(data: Recommendation[]): Recommendation[] {
const grouped: { [key: string]: Recommendation } = {};
function aggregateRecommendations(
data: UnaggregatedPortfolioPlanRecommendation[]
): PortfolioPlanRecommendation[] {
const grouped: {
[key: string]: PortfolioPlanRecommendation & { propertyIds: Set<string> };
} = {};
data.forEach((item) => {
// Use the combination of quantityUnit and materialType as a unique key
@ -78,19 +80,26 @@ function aggregateRecommendations(data: Recommendation[]): Recommendation[] {
if (!grouped[key]) {
grouped[key] = {
...item,
numberOfProperties: 0, // Initialize to 0
propertyIds: item.propertyId ? new Set([item.propertyId]) : new Set(),
};
} else {
grouped[key].quantity += item.quantity;
grouped[key].estimatedCost += item.estimatedCost;
if (item.propertyId) {
grouped[key].propertyIds.add(item.propertyId);
}
}
});
// Round the results to 2 decimal places
// Round the results to 2 decimal places and compute uniquePropertyCount
for (const key in grouped) {
grouped[key].quantity = parseFloat(grouped[key].quantity.toFixed(2));
grouped[key].estimatedCost = parseFloat(
grouped[key].estimatedCost.toFixed(2)
);
grouped[key].numberOfProperties = grouped[key].propertyIds.size;
delete (grouped[key] as any).propertyIds; // using type assertion to bypass the TS error
}
return Object.values(grouped);
@ -128,6 +137,7 @@ export async function getPortfolioPlan(portfolioId: string) {
inArray(recommendation.id, recommendationIds),
eq(recommendation.default, true)
),
columns: { propertyId: true },
with: {
recommendationMaterials: {
with: {
@ -154,6 +164,7 @@ export async function getPortfolioPlan(portfolioId: string) {
quantityUnit: material.quantityUnit,
estimatedCost: material.estimatedCost,
materialType: material.material.type,
propertyId: String(recommendation.propertyId),
})
);
return [...acc, ...materials];
@ -162,7 +173,6 @@ export async function getPortfolioPlan(portfolioId: string) {
);
const aggregated = aggregateRecommendations(unnestedRecommendations);
console.log(aggregated);
return aggregated;
}