Creating plans UI (WIP)

This commit is contained in:
Khalim Conn-Kowlessar 2023-08-16 14:33:14 +01:00
parent 9fd9d0641e
commit 5e70c072a5
3 changed files with 176 additions and 75 deletions

View file

@ -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<typeof plan, "select">;
export type Recommendation = InferModel<typeof recommendation, "select">;
export type PlanRecommendations = InferModel<
typeof planRecommendations,
"select"
>;

View file

@ -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 (
<div className="leading-loose tracking-wider">
<div className="flex py-8 text-lg">Recommendations</div>
<RecommendationContainer
recommendations={recommendations}
propertyMeta={propertyMeta}
/>
<div className="flex py-8 text-lg">Retrofit Plans</div>
<div>
{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 (
<div key={index}>
<div>Created At: {plan.createdAt.toISOString()}</div>
<div>Is Default: {plan.isDefault ? "Yes" : "No"}</div>
<div>Total Estimated Cost: £{totalEstimatedCost}</div>
<div>Total SAP Points: {totalSapPoints}</div>
</div>
);
})}
</div>
</div>
);
// 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 (
// <div className="leading-loose tracking-wider">
// <div className="flex py-8 text-lg">Recommendations</div>
// <RecommendationContainer
// recommendations={recommendations}
// propertyMeta={propertyMeta}
// />
// </div>
// );
}

View file

@ -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<PlanRelation[]> {
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<PropertyMeta> {