mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
Adding solar analysis page
This commit is contained in:
parent
b77c45c810
commit
5927a7d2be
4 changed files with 165 additions and 8 deletions
|
|
@ -5,7 +5,7 @@ import {
|
|||
NewspaperIcon,
|
||||
HomeModernIcon,
|
||||
WrenchScrewdriverIcon,
|
||||
LightBulbIcon,
|
||||
SunIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import {
|
||||
NavigationMenu,
|
||||
|
|
@ -29,10 +29,6 @@ export function Toolbar({ propertyId, portfolioId }: ToolbarProps) {
|
|||
console.log("Settings were clicked, implement me");
|
||||
}
|
||||
|
||||
function handleClickPortfolioPlan() {
|
||||
console.log("Opt Plan was clicked, implement me");
|
||||
}
|
||||
|
||||
const preAssessmentReportButton = (
|
||||
<NavigationMenuLink
|
||||
className={navigationMenuTriggerStyle() + " ml-3 mr-2"}
|
||||
|
|
@ -43,6 +39,16 @@ export function Toolbar({ propertyId, portfolioId }: ToolbarProps) {
|
|||
</NavigationMenuLink>
|
||||
);
|
||||
|
||||
const solarAnalysisButton = (
|
||||
<NavigationMenuLink
|
||||
className={navigationMenuTriggerStyle() + " ml-3 mr-2"}
|
||||
href={`/portfolio/${portfolioId}/building-passport/${propertyId}/solar-analysis`}
|
||||
>
|
||||
<SunIcon className="h-4 w-4 mr-2" />
|
||||
Solar Analysis
|
||||
</NavigationMenuLink>
|
||||
);
|
||||
|
||||
const recommendationsButton = (
|
||||
<NavigationMenuLink
|
||||
className={navigationMenuTriggerStyle() + " ml-3 mr-2"}
|
||||
|
|
@ -65,6 +71,7 @@ export function Toolbar({ propertyId, portfolioId }: ToolbarProps) {
|
|||
|
||||
<NavigationMenuList>
|
||||
{preAssessmentReportButton}
|
||||
{solarAnalysisButton}
|
||||
{recommendationsButton}
|
||||
{/* <NavigationMenuLink
|
||||
className={navigationMenuTriggerStyle() + " ml-3 mr-2"}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
} from "drizzle-orm/pg-core";
|
||||
import { InferModel } from "drizzle-orm";
|
||||
|
||||
export const Solar = pgTable("solar", {
|
||||
export const solar = pgTable("solar", {
|
||||
id: bigserial("id", { mode: "bigint" }).primaryKey(),
|
||||
longitude: real("longitude").notNull(),
|
||||
latitude: real("latitude").notNull(),
|
||||
|
|
@ -29,5 +29,63 @@ export const Solar = pgTable("solar", {
|
|||
});
|
||||
|
||||
// Define types for selecting and inserting data
|
||||
export type ApiResponse = InferModel<typeof Solar, "select">;
|
||||
export type NewApiResponse = InferModel<typeof Solar, "insert">;
|
||||
export type Solar = InferModel<typeof solar, "select">;
|
||||
|
||||
interface Center {
|
||||
latitude: number;
|
||||
longitude: number;
|
||||
}
|
||||
|
||||
interface BoundingBox {
|
||||
ne: Center;
|
||||
sw: Center;
|
||||
}
|
||||
|
||||
interface ImageryDate {
|
||||
day: number;
|
||||
year: number;
|
||||
month: number;
|
||||
}
|
||||
|
||||
interface SolarPanelConfig {
|
||||
panelsCount: number;
|
||||
yearlyEnergyDcKwh: number;
|
||||
roofSegmentSummaries: any[];
|
||||
}
|
||||
|
||||
interface SolarPotential {
|
||||
solarPanels: any[];
|
||||
buildingStats: any;
|
||||
wholeRoofStats: any;
|
||||
panelWidthMeters: number;
|
||||
roofSegmentStats: any[];
|
||||
panelHeightMeters: number;
|
||||
solarPanelConfigs: SolarPanelConfig[];
|
||||
panelCapacityWatts: number;
|
||||
panelLifetimeYears: number;
|
||||
maxArrayAreaMeters2: number;
|
||||
maxArrayPanelsCount: number;
|
||||
maxSunshineHoursPerYear: number;
|
||||
carbonOffsetFactorKgPerMwh: number;
|
||||
}
|
||||
|
||||
interface GoogleApiResponse {
|
||||
name: string;
|
||||
center: Center;
|
||||
regionCode: string;
|
||||
boundingBox: BoundingBox;
|
||||
imageryDate: ImageryDate;
|
||||
imageryQuality: string;
|
||||
solarPotential: SolarPotential;
|
||||
imageryProcessedDate: ImageryDate;
|
||||
}
|
||||
|
||||
export interface SolarInterface {
|
||||
id: bigint;
|
||||
longitude: number;
|
||||
latitude: number;
|
||||
uprn: bigint;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
googleApiResponse: GoogleApiResponse;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
import {
|
||||
FlagIcon,
|
||||
LightBulbIcon,
|
||||
SunIcon,
|
||||
InformationCircleIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
import { getPropertyMeta } from "../utils";
|
||||
import { getSolarData } from "./utils";
|
||||
|
||||
export default async function SolarAnalysisPage({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string; propertyId: string };
|
||||
}) {
|
||||
const propertyMeta = await getPropertyMeta(params.propertyId);
|
||||
const solarData = await getSolarData(Number(propertyMeta.uprn));
|
||||
|
||||
if (!solarData) {
|
||||
return (
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<div className="text-center text-gray-500">
|
||||
<div className="text-2xl font-semibold mb-4">
|
||||
No Solar Analysis Data Available
|
||||
</div>
|
||||
<p className="text-lg">Please check back later for updates.</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const {
|
||||
panelWidthMeters,
|
||||
panelHeightMeters,
|
||||
panelCapacityWatts,
|
||||
panelLifetimeYears,
|
||||
} = solarData.googleApiResponse.solarPotential;
|
||||
|
||||
return (
|
||||
<div className="leading-loose tracking-wider">
|
||||
<div className="flex py-8 text-lg">Solar Analysis</div>
|
||||
<div className="py-8 max-w-7xl mx-auto">
|
||||
<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">
|
||||
Simulation Panel Configuration
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
<div className="flex items-center p-4 bg-blue-50 rounded-lg shadow w-full">
|
||||
<InformationCircleIcon className="w-6 h-6 text-blue-500 mr-2" />
|
||||
<p className="text-lg text-gray-700">
|
||||
Dimensions: {panelWidthMeters}m x {panelHeightMeters}m
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center p-4 bg-green-50 rounded-lg shadow w-full">
|
||||
<LightBulbIcon className="w-6 h-6 text-green-500 mr-2" />
|
||||
<p className="text-lg text-gray-700">
|
||||
Wattage: {panelCapacityWatts}W
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center p-4 bg-yellow-50 rounded-lg shadow w-full">
|
||||
<SunIcon className="w-6 h-6 text-yellow-500 mr-2" />
|
||||
<p className="text-lg text-gray-700">
|
||||
Lifetime: {panelLifetimeYears} years
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center p-4 bg-orange-50 rounded-lg shadow w-full">
|
||||
<FlagIcon className="w-6 h-6 text-orange-500 mr-2" />
|
||||
<p className="text-lg text-gray-700">
|
||||
Region: {solarData.googleApiResponse.regionCode}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* Add more sections here as needed */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { db } from "@/app/db/db";
|
||||
import { SolarInterface, solar } from "@/app/db/schema/solar";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
export async function getSolarData(uprn: number): Promise<SolarInterface> {
|
||||
const data = await db.query.solar.findFirst({
|
||||
where: eq(solar.uprn, BigInt(uprn)),
|
||||
});
|
||||
|
||||
if (!data) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
|
||||
return data as SolarInterface;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue