From 5e70c072a5ef751341c4331178da71c768e454b7 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 16 Aug 2023 14:33:14 +0100 Subject: [PATCH] Creating plans UI (WIP) --- src/app/db/schema/recommendations.ts | 44 ++++- .../[propertyId]/recommendations/page.tsx | 169 +++++++++++------- .../building-passport/[propertyId]/utils.ts | 38 ++++ 3 files changed, 176 insertions(+), 75 deletions(-) diff --git a/src/app/db/schema/recommendations.ts b/src/app/db/schema/recommendations.ts index 3197839..4f51e8b 100644 --- a/src/app/db/schema/recommendations.ts +++ b/src/app/db/schema/recommendations.ts @@ -10,6 +10,7 @@ import { bigint, } from "drizzle-orm/pg-core"; import { material } from "./materials"; +import { InferModel, relations } from "drizzle-orm"; export interface ComponentRecommendation { id: number; @@ -21,12 +22,6 @@ export interface ComponentRecommendation { sapPoints: number; } -export interface Recommendation { - Walls?: ComponentRecommendation[]; - Ventilation?: ComponentRecommendation[]; - Floor?: ComponentRecommendation[]; -} - export const recommendation = pgTable("recommendation", { id: bigserial("id", { mode: "bigint" }).primaryKey(), propertyId: bigint("property_id", { mode: "bigint" }) @@ -88,3 +83,40 @@ export const planRecommendations = pgTable("plan_recommendations", { .notNull() .references(() => recommendation.id), }); + +// create a one to many relation to map a plan to the details in the underlying recommendation +// create a many to many map from a plan to a recommendation +// A recommendation can be in multiple plans and therefore we have a many to many relationship between +// plan and recommendations. This relationship is facilitated by the planRecommdnations table + +export const planRelations = relations(plan, ({ many }) => ({ + planRecommendations: many(planRecommendations), +})); + +export const planRecommendationsRelations = relations( + planRecommendations, + ({ one }) => ({ + plan: one(plan, { + fields: [planRecommendations.planId], + references: [plan.id], + }), + recommendation: one(recommendation, { + fields: [planRecommendations.recommendationId], + references: [recommendation.id], + }), + }) +); + +export const recommendationRelations = relations( + planRecommendations, + ({ many }) => ({ + planRecommendations: many(planRecommendations), + }) +); + +export type Plan = InferModel; +export type Recommendation = InferModel; +export type PlanRecommendations = InferModel< + typeof planRecommendations, + "select" +>; diff --git a/src/app/portfolio/[slug]/building-passport/[propertyId]/recommendations/page.tsx b/src/app/portfolio/[slug]/building-passport/[propertyId]/recommendations/page.tsx index a47c737..b3f81c8 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/recommendations/page.tsx +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/recommendations/page.tsx @@ -1,7 +1,7 @@ import { Recommendation } from "@/app/db/schema/recommendations"; import { PropertyMeta } from "@/app/db/schema/property"; import RecommendationContainer from "@/app/components/building-passport/RecommendationContainer"; -import { getPropertyMeta } from "../utils"; +import { getPlans, getPropertyMeta } from "../utils"; export default async function Recommendations({ params, @@ -9,77 +9,108 @@ export default async function Recommendations({ params: { slug: string; propertyId: string }; }) { const propertyMeta = await getPropertyMeta(params.propertyId); - - const recommendations: Recommendation = { - Walls: [ - { - id: 1, - type: "internal_wall_insulation", - description: "140mm Mineral Wool internal wall insulation", - estimatedCost: 9_450, - default: true, - newUValue: 0.29, - sapPoints: 4, - }, - { - id: 2, - type: "internal_wall_insulation", - description: "30mm Vacuum Insulation Panels wall insulation", - estimatedCost: 10_135, - default: false, - newUValue: 0.28, - sapPoints: 12, - }, - { - id: 3, - type: "internal_external_wall_insulation", - description: - "80mm Mineral Wool External Wall Insulation and 30mm rigid insulation internal wall insulation", - estimatedCost: 13_450, - default: false, - newUValue: 0.25, - sapPoints: 14, - }, - ], - Ventilation: [ - { - id: 4, - type: "mechanical_ventilation", - description: "Two decentralised mechanical ventilation units", - estimatedCost: 750, - default: true, - sapPoints: -2, - }, - ], - Floor: [ - { - id: 5, - type: "suspended_floor_insulation", - description: "70mm Rigid insulation foam boards with floor screed", - estimatedCost: 3_450, - default: true, - newUValue: 0.24, - sapPoints: 7, - }, - { - id: 5, - type: "suspended_floor_insulation", - description: "90mm Rigid insulation foam boards with floor screed", - estimatedCost: 4_120, - default: true, - newUValue: 0.24, - sapPoints: 7, - }, - ], - }; + const plans = await getPlans(params.propertyId); + console.log("PLANS", plans); + console.log(plans[0].planRecommendations); return (
-
Recommendations
- +
Retrofit Plans
+ +
+ {plans.map((plan, index) => { + const totalEstimatedCost = plan.planRecommendations.reduce( + (acc, rec) => acc + rec.recommendation.estimatedCost, + 0 + ); + const totalSapPoints = plan.planRecommendations.reduce( + (acc, rec) => acc + rec.recommendation.sapPoints, + 0 + ); + + return ( +
+
Created At: {plan.createdAt.toISOString()}
+
Is Default: {plan.isDefault ? "Yes" : "No"}
+
Total Estimated Cost: £{totalEstimatedCost}
+
Total SAP Points: {totalSapPoints}
+
+ ); + })} +
); + + // const recommendations: Recommendation = { + // Walls: [ + // { + // id: 1, + // type: "internal_wall_insulation", + // description: "140mm Mineral Wool internal wall insulation", + // estimatedCost: 9_450, + // default: true, + // newUValue: 0.29, + // sapPoints: 4, + // }, + // { + // id: 2, + // type: "internal_wall_insulation", + // description: "30mm Vacuum Insulation Panels wall insulation", + // estimatedCost: 10_135, + // default: false, + // newUValue: 0.28, + // sapPoints: 12, + // }, + // { + // id: 3, + // type: "internal_external_wall_insulation", + // description: + // "80mm Mineral Wool External Wall Insulation and 30mm rigid insulation internal wall insulation", + // estimatedCost: 13_450, + // default: false, + // newUValue: 0.25, + // sapPoints: 14, + // }, + // ], + // Ventilation: [ + // { + // id: 4, + // type: "mechanical_ventilation", + // description: "Two decentralised mechanical ventilation units", + // estimatedCost: 750, + // default: true, + // sapPoints: -2, + // }, + // ], + // Floor: [ + // { + // id: 5, + // type: "suspended_floor_insulation", + // description: "70mm Rigid insulation foam boards with floor screed", + // estimatedCost: 3_450, + // default: true, + // newUValue: 0.24, + // sapPoints: 7, + // }, + // { + // id: 5, + // type: "suspended_floor_insulation", + // description: "90mm Rigid insulation foam boards with floor screed", + // estimatedCost: 4_120, + // default: true, + // newUValue: 0.24, + // sapPoints: 7, + // }, + // ], + // }; + + // return ( + //
+ //
Recommendations
+ // + //
+ // ); } diff --git a/src/app/portfolio/[slug]/building-passport/[propertyId]/utils.ts b/src/app/portfolio/[slug]/building-passport/[propertyId]/utils.ts index 2cb729c..75e0110 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/utils.ts +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/utils.ts @@ -1,3 +1,5 @@ +import { recommendation } from "./../../../../db/schema/recommendations"; +import { columns } from "./../../components/propertyTableColumns"; import { db } from "@/app/db/db"; import { Feature, @@ -6,9 +8,45 @@ import { PropertyMeta, propertyDetailsEpc, } from "@/app/db/schema/property"; +import { plan, Plan } from "@/app/db/schema/recommendations"; import { getRating } from "@/app/utils"; import { eq } from "drizzle-orm"; +// type PlanRelation = Plan & { +// planRecommendations: PlanRecommendations; +// }; + +type PlanRelation = Plan & { + planRecommendations: { + recommendation: { estimatedCost: number; sapPoints: number }; + }[]; +}; + +export async function getPlans(propertyId: string): Promise { + const data = await db.query.plan.findMany({ + where: eq(plan.propertyId, BigInt(propertyId)), + with: { + planRecommendations: { + columns: {}, + with: { + recommendation: { + columns: { + estimatedCost: true, + sapPoints: true, + }, + }, + }, + }, + }, + }); + + if (!data) { + throw new Error("Network response was not ok"); + } + + return data as PlanRelation[]; +} + export async function getPropertyMeta( propertyId: string ): Promise {