mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
Merge branch 'feature/upload_a_file_to_s3_bucket_via_lambda' of https://github.com/Hestia-Homes/assessment-model into khalim-env-merge
This commit is contained in:
commit
6c08d547b8
33 changed files with 2218 additions and 1499 deletions
42
.devcontainer/Dockerfile
Normal file
42
.devcontainer/Dockerfile
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
FROM library/python:3.12-bullseye
|
||||
|
||||
ARG USER=vscode
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install system dependencies in a single layer
|
||||
RUN apt update && apt install -y --no-install-recommends \
|
||||
sudo jq vim curl\
|
||||
&& apt autoremove -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Create the user and grant sudo privileges
|
||||
RUN useradd -m -s /usr/bin/bash ${USER} \
|
||||
&& echo "${USER} ALL=(ALL) NOPASSWD: ALL" >/etc/sudoers.d/${USER} \
|
||||
&& chmod 0440 /etc/sudoers.d/${USER}
|
||||
|
||||
# Install Node.js 22 (from NodeSource)
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
|
||||
&& apt install -y nodejs \
|
||||
&& node -v \
|
||||
&& npm -v
|
||||
|
||||
# # Install aws
|
||||
# RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
|
||||
# RUN unzip awscliv2.zip
|
||||
# RUN ./aws/install
|
||||
|
||||
# # Install terraform
|
||||
# RUN apt-get update && sudo apt-get install -y gnupg software-properties-common
|
||||
# RUN wget -O- https://apt.releases.hashicorp.com/gpg | \
|
||||
# gpg --dearmor | \
|
||||
# sudo tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null
|
||||
# RUN echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
|
||||
# https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
|
||||
# tee /etc/apt/sources.list.d/hashicorp.list
|
||||
# RUN apt update
|
||||
# RUN apt-get install terraform
|
||||
# RUN terraform -install-autocomplete
|
||||
|
||||
|
||||
# Set the working directory
|
||||
WORKDIR /workspaces/assessment-model
|
||||
22
.devcontainer/devcontainer.json
Normal file
22
.devcontainer/devcontainer.json
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "assessment-model",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "frontend",
|
||||
"remoteUser": "vscode",
|
||||
"workspaceFolder": "/workspaces/assessment-model",
|
||||
"postStartCommand": "bash .devcontainer/post-install.sh",
|
||||
"forwardPorts": [3000],
|
||||
"mounts": [
|
||||
// Optional, just makes getting from Downloads (local env) easier
|
||||
// "source=${localEnv:HOME},target=/workspaces/home,type=bind"
|
||||
],
|
||||
"customizations": {
|
||||
"vscode": {
|
||||
"settings": {
|
||||
"files.defaultWorkspace": "/workspaces/assessment-model"
|
||||
},
|
||||
"extensions": [
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
19
.devcontainer/docker-compose.yml
Normal file
19
.devcontainer/docker-compose.yml
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
frontend:
|
||||
user: "${UID}:${GID}"
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: .devcontainer/Dockerfile
|
||||
command: sleep infinity
|
||||
ports:
|
||||
- "3000:50000"
|
||||
volumes:
|
||||
- ..:/workspaces/assessment-model
|
||||
networks:
|
||||
- frontend-net
|
||||
|
||||
networks:
|
||||
frontend-net:
|
||||
driver: bridge
|
||||
1
.devcontainer/post-install.sh
Normal file
1
.devcontainer/post-install.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
npm install;
|
||||
108
.env.development
Normal file
108
.env.development
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
NEXTAUTH_SECRET=df425f28-06ab-47c2-bb78-7e604387d463
|
||||
NEXTAUTH_URL=http://localhost
|
||||
|
||||
|
||||
GOOGLE_CLIENT_ID=232063354367-ustovlgtk3cmtvohvd6tdlejnj1qjjj0.apps.googleusercontent.com
|
||||
|
||||
GOOGLE_CLIENT_SECRET=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
|
||||
|
||||
EPC_AUTH_TOKEN=a2Nvbm5rb3dsZXNzYXJAZ21haWwuY29tOjY5MGJiMWM0NmIyOGI5ZDUxYzAxMzQzYzNiZGNlZGJjZDNmODQwMzA=
|
||||
|
||||
|
||||
|
||||
AZURE_AD_B2C_TENANT_NAME=DomnaApp
|
||||
|
||||
AZURE_AD_B2C_CLIENT_ID=f0a1f977-ddc4-4037-b129-a310008ee934
|
||||
|
||||
AZURE_AD_B2C_CLIENT_SECRET=6uh8Q~dmZNqQy3ZxM_Ce33fVSeW24K27R~pYYduD
|
||||
|
||||
AZURE_AD_B2C_PRIMARY_USER_FLOW=B2C_1_signupsignin
|
||||
|
||||
|
||||
|
||||
AZURE_AD_CLIENT_ID=069e75ee-ba54-45ff-ba77-a06f29c0e21c
|
||||
|
||||
AZURE_AD_CLIENT_SECRET=x6D8Q~f2roqrnoP1YuomSGN5CvU0HPtIWqqPPaYW
|
||||
|
||||
AZURE_AD_TENANT_ID=4a85e8bb-8b7f-4bbd-adc2-1448bb6a9810
|
||||
|
||||
|
||||
|
||||
DB_HOST=terraform-20230705170609686900000001.cdgzupxvdyp0.eu-west-2.rds.amazonaws.com
|
||||
|
||||
DB_PORT=5432
|
||||
|
||||
DB_NAME=DevAssessmentModelDB
|
||||
|
||||
DB_USERNAME=DevAddessmentModelDB
|
||||
|
||||
DB_PASSWORD=!}-A=3D%(2Awy[Qx
|
||||
|
||||
|
||||
|
||||
URL=http://localhost:3000
|
||||
|
||||
PRSIGN_AWS_ACCESS_KEY=AKIAU5A36PPNMR2G7ZQO
|
||||
|
||||
PRESIGN_AWS_SECRET_KEY=r6UitDtHAB01ZmgSj1+vezg2x2GMzh1oqwwUmexQ
|
||||
|
||||
RETOFIT_PLAN_INPUT_BUCKET_NAME=retrofit-plan-inputs-dev
|
||||
|
||||
PRESIGN_AWS_REGION=eu-west-2
|
||||
|
||||
|
||||
|
||||
DUE_CONSIDERATIONS_BUCKET=retrofit-due-considerations-dev
|
||||
|
||||
DUE_CONSIDERATIONS_AWS_ACCESS_KEY=AKIAU5A36PPNPNFWLJOY
|
||||
|
||||
DUE_CONSIDERATIONS_AWS_SECRET_KEY=tCDIH8WPeiob9eR+81hBT2Bxbd/JN5rUcQsePumR
|
||||
|
||||
DUE_CONSIDERATIONS_AWS_REGION=eu-west-2
|
||||
|
||||
|
||||
|
||||
ECO_SPREADSHEET_BUCKET=retrofit-eco-spreadsheet-dev
|
||||
|
||||
ECO_SPREADSHEET_AWS_ACCESS_KEY=AKIAU5A36PPNPTFDQGOJ
|
||||
|
||||
ECO_SPREADSHEET_AWS_SECRET_KEY=dj7gXLl6xbWuIeVrgwmujla2HMOEUVyiGmrFpZpX
|
||||
|
||||
ECO_SPREADSHEET_AWS_REGION=eu-west-2
|
||||
|
||||
|
||||
|
||||
RETROFIT_ENERGY_ASSESSMENTS_BUCKET=retrofit-energy-assessments-dev
|
||||
|
||||
RETROFIT_ENERGY_ASSESSMENTS_AWS_ACCESS_KEY=AKIAU5A36PPNJMZZ3KRW
|
||||
|
||||
ENERGY_ASSESSMENTS_AWS_SECRET=Pr5uxwh1zOCocKuFDA4DWQX039t0h2mnM7kaxlSt
|
||||
|
||||
|
||||
|
||||
FASTAPI_API_KEY=4QPwbB6hEdUloDVtbBJCUTfGBdBgWwpeavWQ7t5Z
|
||||
|
||||
FASTAPI_API_URL=https://api.dev.hestia.homes
|
||||
|
||||
|
||||
|
||||
DUE_CONSIDERATIONS_API_URL=https://api.dev.hestia.homes
|
||||
|
||||
ECO_SPREADSHEET_API_URL=https://api.dev.hestia.homes
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
DOCUMENTS_DATABASE_URL=postgresql://postgres:makingwarmhomes@terraform-20250331175522503500000002.cdgzupxvdyp0.eu-west-2.rds.amazonaws.com:5432/surveyDB
|
||||
|
||||
DOCUMENTS_DB_HOST=terraform-20250331175522503500000002.cdgzupxvdyp0.eu-west-2.rds.amazonaws.com
|
||||
|
||||
DOCUMENTS_DB_PORT=5432
|
||||
|
||||
DOCUMENTS_DB_NAME=surveyDB
|
||||
|
||||
DOCUMENTS_DB_USERNAME=postgres
|
||||
|
||||
DOCUMENTS_DB_PASSWORD=makingwarmhomes
|
||||
|
||||
|
|
@ -8,6 +8,7 @@ const nextConfig = {
|
|||
},
|
||||
],
|
||||
},
|
||||
allowedDevOrigins: ['local-origin.dev', '*.local-origin.dev'],
|
||||
};
|
||||
|
||||
// use next-axiom for full stack monitoring
|
||||
|
|
|
|||
3213
package-lock.json
generated
3213
package-lock.json
generated
File diff suppressed because it is too large
Load diff
21
package.json
21
package.json
|
|
@ -10,8 +10,8 @@
|
|||
"test:e2e:open": "start-server-and-test dev http://localhost:3000 \"cypress open --e2e\"",
|
||||
"test:e2e:run": "cypress run",
|
||||
"migration:generate": "drizzle-kit generate:pg --config=drizzle.config.ts",
|
||||
"migration:push": "node -r esbuild-register src/app/db/migrate.ts",
|
||||
"create_user": "node -r esbuild-register src/app/db/create_user.ts"
|
||||
"migration:push": "tsx src/app/db/migrate.ts",
|
||||
"create_user": "tsx src/app/db/create_user.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui-float/react": "^0.11.2",
|
||||
|
|
@ -41,34 +41,35 @@
|
|||
"aws-sdk": "^2.1415.0",
|
||||
"class-variance-authority": "^0.6.1",
|
||||
"clsx": "^1.2.1",
|
||||
"drizzle-orm": "^0.27.1",
|
||||
"drizzle-kit": "^0.31.4",
|
||||
"drizzle-orm": "^0.44.3",
|
||||
"esbuild": "^0.25.8",
|
||||
"eslint": "8.41.0",
|
||||
"eslint-config-next": "13.4.3",
|
||||
"lucide-react": "^0.233.0",
|
||||
"next": "13.4.3",
|
||||
"next": "^15.4.2",
|
||||
"next-auth": "^4.22.1",
|
||||
"next-axiom": "^0.17.0",
|
||||
"next-axiom": "^1.9.2",
|
||||
"next-themes": "^0.3.0",
|
||||
"pg": "^8.11.1",
|
||||
"postcss": "8.4.23",
|
||||
"postcss": "^8.5.6",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-hook-form": "^7.53.2",
|
||||
"tailwind-merge": "^1.13.2",
|
||||
"tailwindcss": "^3.4.3",
|
||||
"tailwindcss-animate": "^1.0.6",
|
||||
"tsx": "^4.20.3",
|
||||
"typescript": "5.0.4",
|
||||
"xlsx": "^0.18.5",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/forms": "^0.5.7",
|
||||
"@testing-library/cypress": "^9.0.0",
|
||||
"@testing-library/cypress": "^10.0.3",
|
||||
"@types/pg": "^8.10.2",
|
||||
"cypress": "^12.17.1",
|
||||
"cypress": "^14.5.2",
|
||||
"cypress-social-logins": "^1.14.1",
|
||||
"dotenv": "^16.3.1",
|
||||
"drizzle-kit": "^0.19.3",
|
||||
"start-server-and-test": "^2.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1
run_local.sh
Normal file
1
run_local.sh
Normal file
|
|
@ -0,0 +1 @@
|
|||
npm run dev
|
||||
|
|
@ -9,10 +9,8 @@ const PermissionsBodySchema = z.object({
|
|||
action: z.enum(["delete", "update"]),
|
||||
});
|
||||
|
||||
export async function POST(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { portfolioId: string } }
|
||||
) {
|
||||
export async function POST(request: NextRequest, props: { params: Promise<{ portfolioId: string }> }) {
|
||||
const params = await props.params;
|
||||
// This endpoint lives at portfolio/{portfolioId}/permissions and will return the permissions level for a given portfolio
|
||||
// Call this endpoint with a) userId, b) portfolioId, c) an action and this api will tell you if that person can do that thing
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,8 @@ const UpdateBodySchema = z.object({
|
|||
status: z.optional(z.string()),
|
||||
});
|
||||
|
||||
export async function PUT(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { portfolioId: string } }
|
||||
) {
|
||||
export async function PUT(request: NextRequest, props: { params: Promise<{ portfolioId: string }> }) {
|
||||
const params = await props.params;
|
||||
const body = await request.json();
|
||||
let validatedBody;
|
||||
|
||||
|
|
@ -44,7 +42,7 @@ export async function PUT(
|
|||
const budget = validatedBody.budget;
|
||||
const goal = validatedBody.goal;
|
||||
const status = validatedBody.status;
|
||||
|
||||
|
||||
|
||||
await db
|
||||
.update(portfolio)
|
||||
|
|
@ -57,10 +55,8 @@ export async function PUT(
|
|||
});
|
||||
}
|
||||
|
||||
export async function DELETE(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { portfolioId: string } }
|
||||
) {
|
||||
export async function DELETE(request: NextRequest, props: { params: Promise<{ portfolioId: string }> }) {
|
||||
const params = await props.params;
|
||||
try {
|
||||
const portfolioId = params.portfolioId;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@ import { DataItem, ChartData } from "@/app/portfolio/[slug]/utils";
|
|||
import { eq } from "drizzle-orm";
|
||||
import { scenario } from "@/app/db/schema/recommendations";
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { scenarioId: string } }
|
||||
) {
|
||||
export async function GET(request: NextRequest, props: { params: Promise<{ scenarioId: string }> }) {
|
||||
const params = await props.params;
|
||||
const scenarioId = params.scenarioId;
|
||||
|
||||
const data = await db
|
||||
|
|
|
|||
|
|
@ -4,10 +4,8 @@ import { serializeBigInt } from "@/app/utils";
|
|||
import { eq } from "drizzle-orm";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { propertyId: string } }
|
||||
) {
|
||||
export async function GET(request: NextRequest, props: { params: Promise<{ propertyId: string }> }) {
|
||||
const params = await props.params;
|
||||
const propertyId = params.propertyId;
|
||||
|
||||
const propertyMeta = await db.query.property.findFirst({
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ import EmailSignInButton from "./components/signin/CredentialsButton";
|
|||
import { redirect } from "next/navigation";
|
||||
import Image from "next/image";
|
||||
|
||||
export default async function Home({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { error?: string };
|
||||
}) {
|
||||
export default async function Home(
|
||||
props: {
|
||||
searchParams: Promise<{ error?: string }>;
|
||||
}
|
||||
) {
|
||||
const searchParams = await props.searchParams;
|
||||
const session = await getServerSession(AuthOptions);
|
||||
|
||||
if (session?.user) {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
import { Toolbar } from "@/app/components/portfolio/Toolbar";
|
||||
import { getPortfolio, getPortfolioScenarios } from "../utils";
|
||||
|
||||
export default async function PortfolioLayout({
|
||||
children, // will be a page or nested layout
|
||||
params,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
params: { slug: string; propertyId: string };
|
||||
}) {
|
||||
export default async function PortfolioLayout(
|
||||
props: {
|
||||
children: React.ReactNode;
|
||||
params: Promise<{ slug: string; propertyId: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
|
||||
const {
|
||||
// will be a page or nested layout
|
||||
children
|
||||
} = props;
|
||||
|
||||
const portfolioId = params.slug;
|
||||
const { name: portfolioName } = await getPortfolio(portfolioId);
|
||||
// We retrieve the scenarios associated with the portfolio
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@ import PortfolioPlanTable from "@/app/components/portfolio/measures/PlanTable";
|
|||
import { getPortfolioMeasures } from "../../utils";
|
||||
import { portfolioPlanColumns } from "@/app/components/portfolio/measures/PlanTableColumns";
|
||||
|
||||
export default async function PortfolioPlan({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string };
|
||||
}) {
|
||||
export default async function PortfolioPlan(
|
||||
props: {
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
const portfolioId = params.slug;
|
||||
const portfolioMeasures = await getPortfolioMeasures(portfolioId);
|
||||
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ function EmptyPropertyState() {
|
|||
);
|
||||
}
|
||||
|
||||
export default async function Page({
|
||||
params,
|
||||
searchParams,
|
||||
}: {
|
||||
params: { slug: string };
|
||||
searchParams: { [key: string]: string | string[] | undefined | number };
|
||||
}) {
|
||||
export default async function Page(
|
||||
props: {
|
||||
params: Promise<{ slug: string }>;
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined | number }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
// This page is served from the server so we can make calls to the database
|
||||
|
||||
const portfolioId = params.slug;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { getPortfolioSettings } from "../../utils";
|
||||
import PortfolioSettings from "./PortfolioSettings";
|
||||
|
||||
export default async function PortfolioSettingsPage({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string };
|
||||
}) {
|
||||
export default async function PortfolioSettingsPage(
|
||||
props: {
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
const portfolioId = params.slug;
|
||||
const portfolioSettingsData = await getPortfolioSettings(portfolioId);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,12 @@ import {
|
|||
getOverviewPortfolioData,
|
||||
} from "../../utils";
|
||||
|
||||
export default async function PortfolioSummary({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string };
|
||||
}) {
|
||||
export default async function PortfolioSummary(
|
||||
props: {
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
const portfolioId = params.slug;
|
||||
const data = await getOverviewPortfolioData(portfolioId);
|
||||
|
||||
|
|
|
|||
|
|
@ -38,11 +38,12 @@ async function getDocuments(
|
|||
return result;
|
||||
}
|
||||
|
||||
export default async function DocumentsPage({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string; propertyId: string };
|
||||
}) {
|
||||
export default async function DocumentsPage(
|
||||
props: {
|
||||
params: Promise<{ slug: string; propertyId: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
// Get the property UPRN
|
||||
const propertyId = params.propertyId;
|
||||
if (!propertyId || propertyId === "0") {
|
||||
|
|
|
|||
|
|
@ -63,11 +63,12 @@ const InfoCard: React.FC<InfoCardProps> = ({ title, value, unit }) => {
|
|||
);
|
||||
};
|
||||
|
||||
export default async function EnergyAssessmentsPage({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string; propertyId: string };
|
||||
}) {
|
||||
export default async function EnergyAssessmentsPage(
|
||||
props: {
|
||||
params: Promise<{ slug: string; propertyId: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
const propertyMeta = await getPropertyMeta(params.propertyId);
|
||||
const ea = await getEnergyAssessment(propertyMeta.uprn);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,13 +12,19 @@ function EstimatedDataNotification() {
|
|||
);
|
||||
}
|
||||
|
||||
export default async function DashboardLayout({
|
||||
children, // will be a page or nested layout
|
||||
params,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
params: { slug: string; propertyId: string };
|
||||
}) {
|
||||
export default async function DashboardLayout(
|
||||
props: {
|
||||
children: React.ReactNode;
|
||||
params: Promise<{ slug: string; propertyId: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
|
||||
const {
|
||||
// will be a page or nested layout
|
||||
children
|
||||
} = props;
|
||||
|
||||
const propertyId = params.propertyId ?? "";
|
||||
const portfolioId = params.slug ?? "";
|
||||
|
||||
|
|
|
|||
|
|
@ -12,11 +12,12 @@ import { getPropertyMeta } from "./utils";
|
|||
|
||||
export const revalidate = 1;
|
||||
|
||||
export default async function BuildingPassportHome({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string; propertyId: string };
|
||||
}) {
|
||||
export default async function BuildingPassportHome(
|
||||
props: {
|
||||
params: Promise<{ slug: string; propertyId: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
// This is a server component and because we make the exact same request in the layout,
|
||||
// the response is cached so we just gain access to the data
|
||||
const propertyMeta = await getPropertyMeta(params.propertyId);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import RecommendationContainer from "@/app/components/building-passport/RecommendationContainer";
|
||||
import { getPropertyMeta, getRecommendations, getPlanMeta } from "../../utils";
|
||||
|
||||
export default async function Recommendations({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string; propertyId: string; planId: string };
|
||||
}) {
|
||||
export default async function Recommendations(
|
||||
props: {
|
||||
params: Promise<{ slug: string; propertyId: string; planId: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
const propertyMeta = await getPropertyMeta(params.propertyId);
|
||||
const recommendations = await getRecommendations(params.planId);
|
||||
const planMeta = await getPlanMeta(params.planId);
|
||||
|
|
|
|||
|
|
@ -61,11 +61,12 @@ function PlanCard({
|
|||
);
|
||||
}
|
||||
|
||||
export default async function RecommendationPlans({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string; propertyId: string };
|
||||
}) {
|
||||
export default async function RecommendationPlans(
|
||||
props: {
|
||||
params: Promise<{ slug: string; propertyId: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
const propertyMeta = await getPropertyMeta(params.propertyId);
|
||||
const plans = await getPlans(params.propertyId);
|
||||
|
||||
|
|
|
|||
|
|
@ -128,11 +128,12 @@ const formatDate = (dateString: Date) => {
|
|||
});
|
||||
};
|
||||
|
||||
export default async function PreAssessmentReport({
|
||||
params,
|
||||
}: {
|
||||
params: { slug: string; propertyId: string };
|
||||
}) {
|
||||
export default async function PreAssessmentReport(
|
||||
props: {
|
||||
params: Promise<{ slug: string; propertyId: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
const propertyMeta = await getPropertyMeta(params.propertyId);
|
||||
const conditionReportData = await getConditionReport(params.propertyId);
|
||||
const propertyDetailsSpatial = await getSpatialData(propertyMeta.uprn);
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@ 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,
|
||||
}: {
|
||||
params: { slug: string; propertyId: string };
|
||||
}) {
|
||||
export default async function SolarAnalysisPage(
|
||||
props: {
|
||||
params: Promise<{ slug: string; propertyId: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
const propertyMeta = await getPropertyMeta(params.propertyId);
|
||||
const solarData = await getSolarData(Number(propertyMeta.uprn));
|
||||
// If there's no solar data, we cannot display the page
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
"use client";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useEffect, use } from "react";
|
||||
|
||||
export default function LoadingPage({ params }: { params: { slug: string } }) {
|
||||
export default function LoadingPage(props: { params: Promise<{ slug: string }> }) {
|
||||
const params = use(props.params);
|
||||
const portfolioId = params.slug;
|
||||
const router = useRouter();
|
||||
const [countdown, setCountdown] = useState(10); // Initialize countdown state to 10 seconds
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
import BackToPortfolio from "@/app/components/portfolio/BackToPortfolio";
|
||||
|
||||
export default function Layout({
|
||||
children,
|
||||
params,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
params: { slug: string; lmkKey: string };
|
||||
}) {
|
||||
export default async function Layout(
|
||||
props: {
|
||||
children: React.ReactNode;
|
||||
params: Promise<{ slug: string; lmkKey: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
|
||||
const {
|
||||
children
|
||||
} = props;
|
||||
|
||||
const portfolioId = params.slug;
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useState, use } from "react";
|
||||
import { PencilSquareIcon } from "@heroicons/react/24/outline";
|
||||
import { SearchData, EpcRating, EpcKey } from "@/types/epc";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
|
@ -73,13 +73,14 @@ const partConfig: PartConfig = [
|
|||
},
|
||||
];
|
||||
|
||||
export default function PropertyPage({
|
||||
params,
|
||||
searchParams,
|
||||
}: {
|
||||
params: { slug: string; lmkKey: string };
|
||||
searchParams: { [key: string]: string | string[] | undefined };
|
||||
}) {
|
||||
export default function PropertyPage(
|
||||
props: {
|
||||
params: Promise<{ slug: string; lmkKey: string }>;
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||
}
|
||||
) {
|
||||
const searchParams = use(props.searchParams);
|
||||
const params = use(props.params);
|
||||
const router = useRouter();
|
||||
|
||||
const portfolioId = params.slug;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { EpcRating, SearchData } from "@/types/epc";
|
|||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { fetchData } from "../utils";
|
||||
import { useState } from "react";
|
||||
import { useState, use } from "react";
|
||||
import { PencilSquareIcon } from "@heroicons/react/24/outline";
|
||||
import PlanPart from "@/app/components/plan/PlanPart";
|
||||
import EditEpctargetModal from "@/app/components/property/EditEpcTargetModal";
|
||||
|
|
@ -13,13 +13,14 @@ import BudgetModal from "@/app/components/plan/BudgetModal";
|
|||
import { formatNumber, roundToDecimalPlaces } from "@/app/utils";
|
||||
import { Part } from "@/types/parts";
|
||||
|
||||
export default function Plan({
|
||||
params,
|
||||
searchParams,
|
||||
}: {
|
||||
params: { slug: string; lmkKey: string };
|
||||
searchParams: { [key: string]: string | string[] | undefined };
|
||||
}) {
|
||||
export default function Plan(
|
||||
props: {
|
||||
params: Promise<{ slug: string; lmkKey: string }>;
|
||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||
}
|
||||
) {
|
||||
const searchParams = use(props.searchParams);
|
||||
const params = use(props.params);
|
||||
const router = useRouter();
|
||||
|
||||
const portfolioId = params.slug;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
import BackToPortfolio from "@/app/components/portfolio/BackToPortfolio";
|
||||
|
||||
export default function Layout({
|
||||
children,
|
||||
params,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
params: { slug: string; lmkKey: string };
|
||||
}) {
|
||||
export default async function Layout(
|
||||
props: {
|
||||
children: React.ReactNode;
|
||||
params: Promise<{ slug: string; lmkKey: string }>;
|
||||
}
|
||||
) {
|
||||
const params = await props.params;
|
||||
|
||||
const {
|
||||
children
|
||||
} = props;
|
||||
|
||||
const portfolioId = params.slug;
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useState, use } from "react";
|
||||
import SearchPostcodeButton from "../../../components/search/SearchPostcodeButton";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { SearchData, SearchResult } from "@/types/epc";
|
||||
|
|
@ -13,7 +13,8 @@ const defaultToggleClass =
|
|||
const toggledButtonClass =
|
||||
"text-white mb-1 block max-w-sm rounded-lg border border-gray-200 bg-brandblue p-6 shadow hover:bg-hoverblue dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-700";
|
||||
|
||||
export default function Search({ params }: { params: { slug: string } }) {
|
||||
export default function Search(props: { params: Promise<{ slug: string }> }) {
|
||||
const params = use(props.params);
|
||||
const [postcode, setPostcode] = useState("");
|
||||
const [buttonDisabled, setButtonDisabled] = useState(true);
|
||||
const [data, setData] = useState<null | SearchData>(null);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue