mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-30 12:55:02 +00:00
Adding in new solar visuals wip
This commit is contained in:
parent
e933feb764
commit
b622ec3250
5 changed files with 1929 additions and 21 deletions
27
src/app/db/migrations/0074_regular_blonde_phantom.sql
Normal file
27
src/app/db/migrations/0074_regular_blonde_phantom.sql
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
DO $$ BEGIN
|
||||
CREATE TYPE "scenario_type" AS ENUM('unit', 'building');
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "solar_scenario" (
|
||||
"id" bigserial PRIMARY KEY NOT NULL,
|
||||
"solar_id" bigint NOT NULL,
|
||||
"scenario_type" "scenario_type" NOT NULL,
|
||||
"number_panels" integer NOT NULL,
|
||||
"array_kwhp" integer NOT NULL,
|
||||
"lifetime_dc_kwh" real NOT NULL,
|
||||
"yearly_dc_kwh" real NOT NULL,
|
||||
"lifetime_ac_kwh" real,
|
||||
"yearly_ac_kwh" real,
|
||||
"cost" real NOT NULL,
|
||||
"expected_payback_years" real,
|
||||
"panelled_roof_area" real NOT NULL,
|
||||
"is_default" boolean NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "solar_scenario" ADD CONSTRAINT "solar_scenario_solar_id_solar_id_fk" FOREIGN KEY ("solar_id") REFERENCES "solar"("id") ON DELETE no action ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
1823
src/app/db/migrations/meta/0074_snapshot.json
Normal file
1823
src/app/db/migrations/meta/0074_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -36,9 +36,9 @@ export const solar = pgTable("solar", {
|
|||
export const scenarioType: [string, ...string[]] = ["unit", "building"];
|
||||
export const scenarioTypeEnum = pgEnum("scenario_type", scenarioType);
|
||||
|
||||
export const solarSenario = pgTable("solar_scenario", {
|
||||
export const solarScenario = pgTable("solar_scenario", {
|
||||
id: bigserial("id", { mode: "bigint" }).primaryKey(),
|
||||
solar_id: bigint("solar_id", { mode: "bigint" })
|
||||
solarId: bigint("solar_id", { mode: "bigint" })
|
||||
.notNull()
|
||||
.references(() => solar.id),
|
||||
scenrioType: scenarioTypeEnum("scenario_type").notNull(),
|
||||
|
|
@ -56,7 +56,7 @@ export const solarSenario = pgTable("solar_scenario", {
|
|||
|
||||
// Define types for selecting and inserting data
|
||||
export type Solar = InferModel<typeof solar, "select">;
|
||||
export type SolarScenario = InferModel<typeof solarSenario, "select">;
|
||||
export type SolarScenario = InferModel<typeof solarScenario, "select">;
|
||||
|
||||
interface Center {
|
||||
latitude: number;
|
||||
|
|
|
|||
|
|
@ -5,11 +5,17 @@ import {
|
|||
InformationCircleIcon,
|
||||
CloudIcon,
|
||||
SparklesIcon,
|
||||
BoltIcon,
|
||||
CurrencyDollarIcon,
|
||||
ArrowTrendingUpIcon,
|
||||
CalendarIcon,
|
||||
HomeIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { getPropertyMeta } from "../utils";
|
||||
import { getSolarData, getSolarScenarioData } from "./utils";
|
||||
import FeatureTable from "@/app/components/building-passport/FeatureTable";
|
||||
import { roofSegmentsColumns } from "./roof-segments-table";
|
||||
import { formatNumber } from "@/app/utils";
|
||||
|
||||
export default async function SolarAnalysisPage({
|
||||
params,
|
||||
|
|
@ -138,21 +144,69 @@ export default async function SolarAnalysisPage({
|
|||
|
||||
<div className="bg-white shadow-md rounded-lg p-6 mb-8 w-full">
|
||||
<h2 className="text-l font-semibold text-gray-800 mb-4">
|
||||
Recommended Solar Configuration
|
||||
Solar PV Simulation
|
||||
</h2>
|
||||
{/*
|
||||
We want to show:
|
||||
- Number of panels
|
||||
- Array ouput
|
||||
- lifetime dc energy
|
||||
- yearly dc energy
|
||||
- lifetime ac energy
|
||||
- yearly ac energy
|
||||
- cost
|
||||
- roi
|
||||
- expected payback years
|
||||
- pannelled roof area
|
||||
*/}
|
||||
<div className="flex">
|
||||
<div className="flex flex-col space-y-4 w-1/2">
|
||||
<ul className="list-none pl-5 text-gray-700">
|
||||
<li className="flex items-center">
|
||||
<HomeIcon className="w-5 h-5 text-blue-500 mr-2" />
|
||||
Number of panels: {solarScenarioData.numberPanels}
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<BoltIcon className="w-5 h-5 text-yellow-500 mr-2" />
|
||||
Array output: {solarScenarioData.arrayKwhp} kWp
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<SunIcon className="w-5 h-5 text-orange-500 mr-2" />
|
||||
Lifetime DC energy:{" "}
|
||||
{Math.round(solarScenarioData.lifetimeDcKwh)} kWh
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<SunIcon className="w-5 h-5 text-orange-500 mr-2" />
|
||||
Yearly DC energy: {Math.round(
|
||||
solarScenarioData.yearlyDcKwh
|
||||
)}{" "}
|
||||
kWh
|
||||
</li>
|
||||
{solarScenarioData.lifetimeAcKwh !== null && (
|
||||
<li className="flex items-center">
|
||||
<SunIcon className="w-5 h-5 text-orange-500 mr-2" />
|
||||
Lifetime AC energy:{" "}
|
||||
{Math.round(solarScenarioData.lifetimeAcKwh)} kWh
|
||||
</li>
|
||||
)}
|
||||
{solarScenarioData.yearlyAcKwh !== null && (
|
||||
<li className="flex items-center">
|
||||
<SunIcon className="w-5 h-5 text-orange-500 mr-2" />
|
||||
Yearly AC energy:{" "}
|
||||
{Math.round(solarScenarioData.yearlyAcKwh)} kWh
|
||||
</li>
|
||||
)}
|
||||
<li className="flex items-center">
|
||||
<CurrencyDollarIcon className="w-5 h-5 text-green-500 mr-2" />
|
||||
Cost: £{formatNumber(solarScenarioData.cost)}
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<ArrowTrendingUpIcon className="w-5 h-5 text-purple-500 mr-2" />
|
||||
Expected payback years:{" "}
|
||||
{solarScenarioData.expectedPaybackYears}
|
||||
</li>
|
||||
<li className="flex items-center">
|
||||
<HomeIcon className="w-5 h-5 text-blue-500 mr-2" />
|
||||
Panelled roof area:{" "}
|
||||
{solarScenarioData.panelledRoofArea.toFixed(1)} m²
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="w-1/2 flex items-center justify-center">
|
||||
<img
|
||||
src="/static/solar_image.png"
|
||||
alt="Solar Image"
|
||||
className="w-3/4 h-auto"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import {
|
|||
SolarInterface,
|
||||
solar,
|
||||
SolarScenario,
|
||||
solarSenario,
|
||||
solarScenario,
|
||||
} from "@/app/db/schema/solar";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
|
||||
export async function getSolarData(uprn: number): Promise<SolarInterface> {
|
||||
const data = await db.query.solar.findFirst({
|
||||
|
|
@ -22,8 +22,12 @@ export async function getSolarData(uprn: number): Promise<SolarInterface> {
|
|||
export async function getSolarScenarioData(
|
||||
solarId: string
|
||||
): Promise<SolarScenario> {
|
||||
const data = await db.query.solarSenario.findFirst({
|
||||
where: eq(solarSenario.solar_id, BigInt(solarId)),
|
||||
const data = await db.query.solarScenario.findFirst({
|
||||
where: (solarScenario, { eq, and }) =>
|
||||
and(
|
||||
eq(solarScenario.solarId, BigInt(solarId)),
|
||||
eq(solarScenario.isDefault, true)
|
||||
),
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue