Formatting portfolio page and pulled through default recommendation cost

This commit is contained in:
Khalim Conn-Kowlessar 2023-11-24 14:34:47 +00:00
parent 7f1a09f96a
commit 138153f876
5 changed files with 48 additions and 12 deletions

View file

@ -11,6 +11,7 @@ import {
bigint,
} from "drizzle-orm/pg-core";
import { portfolio, PortfolioStatus } from "./portfolio";
import { recommendation } from "./recommendations";
import { InferModel, relations } from "drizzle-orm";
// This is a placeholder for the property schema
@ -184,13 +185,25 @@ export const propertyTargets = pgTable("property_targets", {
});
// one to one relationship between property and propertyTargets
export const propertyTargetRelations = relations(property, ({ one }) => ({
export const propertyRelations = relations(property, ({ one, many }) => ({
target: one(propertyTargets, {
fields: [property.id],
references: [propertyTargets.propertyId],
}),
recommendations: many(recommendation),
}));
// Define the other side of the one to many relation between a property and its recomendations
export const recommendationsRelations = relations(
recommendation,
({ one }) => ({
author: one(property, {
fields: [recommendation.propertyId],
references: [property.id],
}),
})
);
// TODO: We'll need a property details buildings materials for verisk data?
export type Property = InferModel<typeof property, "select">;
@ -199,7 +212,11 @@ export type PropertyDetailsEpc = InferModel<
"select"
>;
// This type is used for the getProperties function in src/app/portfolio/[slug]/utils.ts
export interface PropertyWithTarget {
export interface PropertyToRecommendation {
estimatedCost?: number | null;
}
export interface PropertyWithRelations {
status: string | null;
id: bigint;
portfolioId: bigint;
@ -207,5 +224,6 @@ export interface PropertyWithTarget {
address: string | null;
postcode: string | null;
target: { epc?: string | null; heatDemand?: number | null };
recommendations: PropertyToRecommendation[];
cost?: number | null;
}

View file

@ -1,9 +1,8 @@
import { HomeIcon } from "@heroicons/react/24/outline";
import { getPortfolio, getProperties } from "../utils";
import { Toolbar } from "@/app/components/portfolio/Toolbar";
import DataTable from "@/app/portfolio/[slug]/components/propertyTable";
import { columns } from "@/app/portfolio/[slug]/components/propertyTableColumns";
import { PropertyWithTarget } from "@/app/db/schema/property";
import { PropertyWithRelations } from "@/app/db/schema/property";
// We enfore caching of data for 60 seconds
export const revalidate = 60;
@ -206,7 +205,7 @@ export default async function Page({
} = await getPortfolio(portfolioId);
// Default limit to 1000 and offset to 0 for now - will handle pagination later
const properties: PropertyWithTarget[] = await getProperties(
const properties: PropertyWithRelations[] = await getProperties(
portfolioId,
1000,
0

View file

@ -17,7 +17,10 @@ import { FunnelIcon } from "@heroicons/react/24/outline";
import { formatNumber } from "@/app/utils";
import { cn } from "@/lib/utils";
import { PortfolioStatus } from "@/app/db/schema/portfolio";
import { PropertyWithTarget } from "@/app/db/schema/property";
import {
PropertyToRecommendation,
PropertyWithRelations,
} from "@/app/db/schema/property";
interface DataTableColumnHeaderProps<TData, TValue>
extends React.HTMLAttributes<HTMLDivElement> {
@ -64,7 +67,7 @@ export function DataTableFilterHeader<TData, TValue>({
);
}
export const columns: ColumnDef<PropertyWithTarget>[] = [
export const columns: ColumnDef<PropertyWithRelations>[] = [
{
accessorKey: "address",
header: ({ column }) => {
@ -124,7 +127,17 @@ export const columns: ColumnDef<PropertyWithTarget>[] = [
accessorKey: "cost",
header: () => <div className="flex justify-center">Cost</div>,
cell: ({ row }) => {
const cost = parseFloat(row.getValue("cost"));
const recommendations = row.original.recommendations;
const cost = recommendations.reduce(
(acc: number, rec: PropertyToRecommendation) => {
if (rec.estimatedCost === null || rec.estimatedCost === undefined) {
return acc;
}
return acc + rec.estimatedCost;
},
0
);
const creationStatus = row.original.creationStatus;
if (creationStatus === "LOADING") {

View file

@ -8,7 +8,7 @@ import { db } from "@/app/db/db";
import { portfolio } from "@/app/db/schema/portfolio";
import { property } from "@/app/db/schema/property";
import type { Portfolio } from "@/app/db/schema/portfolio";
import type { PropertyWithTarget } from "@/app/db/schema/property";
import type { PropertyWithRelations } from "@/app/db/schema/property";
import { plan, planRecommendations } from "@/app/db/schema/recommendations";
export async function getPortfolio(portfolioId: string): Promise<Portfolio> {
@ -32,8 +32,8 @@ export async function getProperties(
portfolioId: string,
limit: number = 1000,
offset: number = 0
): Promise<PropertyWithTarget[]> {
const data: PropertyWithTarget[] = await db.query.property.findMany({
): Promise<PropertyWithRelations[]> {
const data: PropertyWithRelations[] = await db.query.property.findMany({
limit: limit,
offset: offset,
columns: {
@ -51,6 +51,12 @@ export async function getProperties(
epc: true,
},
},
recommendations: {
columns: {
estimatedCost: true,
},
where: eq(recommendation.default, true),
},
},
});

View file

@ -83,7 +83,7 @@ export function formatNumber(number: number): string {
const formattedNumber: string = (
roundedNumber / Math.pow(1000, suffixIndex)
).toString();
).toFixed(2);
return formattedNumber + suffixes[suffixIndex];
}