diff --git a/src/app/components/building-passport/EpcCard.tsx b/src/app/components/building-passport/EpcCard.tsx new file mode 100644 index 0000000..ef0f0aa --- /dev/null +++ b/src/app/components/building-passport/EpcCard.tsx @@ -0,0 +1,19 @@ +export default function EpcCard({ + epcRating, + fullMargin = true, +}: { + epcRating: string; + fullMargin: boolean; +}) { + let marginClass = ""; + if (fullMargin) { + marginClass = "mx-auto"; + } + + return ( +
+
Energy Rating
+
{epcRating}
+
+ ); +} diff --git a/src/app/components/building-passport/FeatureTable.tsx b/src/app/components/building-passport/FeatureTable.tsx new file mode 100644 index 0000000..a7ec59d --- /dev/null +++ b/src/app/components/building-passport/FeatureTable.tsx @@ -0,0 +1,113 @@ +"use client"; + +import { + flexRender, + getCoreRowModel, + useReactTable, + ColumnDef, +} from "@tanstack/react-table"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/app/shadcn_components/ui/table"; + +import { Badge } from "@/app/shadcn_components/ui/badge"; +import { Feature, Rating } from "@/app/db/schema/property"; + +function RatingBadge({ rating }: { rating: Rating }) { + const colourMap = { + "Very good": "bg-green-500", + Good: "bg-green-300", + Poor: "bg-yellow-300", + "Very poor": "bg-red-500", + }; + const ratingConfig = colourMap[rating]; + return {rating}; +} + +export const columns: ColumnDef[] = [ + { + accessorKey: "feature", + header: "Feature", + }, + { + accessorKey: "description", + header: "Description", + }, + { + accessorKey: "rating", + header: "Rating", + cell: ({ row }) => { + return ( +
+ +
+ ); + }, + }, +]; + +interface DataTableProps { + data: Feature[]; +} + +export default function FeatureTable({ data }: DataTableProps) { + // Initialise the table + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + }); + + return ( +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ); + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+ ); +} diff --git a/src/app/db/schema/property.ts b/src/app/db/schema/property.ts index 121d7c4..8b07f89 100644 --- a/src/app/db/schema/property.ts +++ b/src/app/db/schema/property.ts @@ -15,3 +15,26 @@ export interface PropertyMeta { tenure: string; currentEpcRating: string; } + +export type Rating = "Very good" | "Good" | "Poor" | "Very poor"; + +export interface Feature { + feature: string; + description: string; + rating: Rating; +} + +export interface ConditionReportData { + id: number; + lastUpdated: string; + fullAddress: string; + postcode: string; + currentEpcRating: string; + inConservationArea: "Yes" | "No" | "Unknown"; + propertyType: string; + builtForm: string; + totalFloorArea: number; + tenure: string; + features: Feature[]; + yearBuilt: string; +} diff --git a/src/app/portfolio/[slug]/building-passport/[propertyId]/page.tsx b/src/app/portfolio/[slug]/building-passport/[propertyId]/page.tsx index 1923538..f435b4c 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/page.tsx +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/page.tsx @@ -1,4 +1,6 @@ +import EpcCard from "@/app/components/building-passport/EpcCard"; import { PropertyMeta } from "@/app/db/schema/property"; +import { formatDateTime } from "@/app/utils"; import { HomeIcon, BuildingOfficeIcon, @@ -8,30 +10,6 @@ import { UserGroupIcon, } from "@heroicons/react/24/solid"; -function formatDateTime(dateTimeString: string): string { - // Create a new Date object - const dateTime = new Date(dateTimeString); - - // Get the various parts of the date - const options: Intl.DateTimeFormatOptions = { - year: "numeric", - month: "long", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - }; - return dateTime.toLocaleDateString("en-GB", options); -} - -function EpcCard({ epcRating }: { epcRating: string }) { - return ( -
-
Energy Rating
-
{epcRating}
-
- ); -} - export default function BuildingPassportHome() { const propertyMeta: PropertyMeta = { id: 1, @@ -53,7 +31,7 @@ export default function BuildingPassportHome() { return (
- +
Your property
diff --git a/src/app/portfolio/[slug]/building-passport/[propertyId]/pre-assessment-report/page.tsx b/src/app/portfolio/[slug]/building-passport/[propertyId]/pre-assessment-report/page.tsx index 5a6928e..5a70d6e 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/pre-assessment-report/page.tsx +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/pre-assessment-report/page.tsx @@ -1,7 +1,178 @@ -export default function PreAssessmentReport() { +import EpcCard from "@/app/components/building-passport/EpcCard"; +import FeatureTable from "@/app/components/building-passport/FeatureTable"; +import { ConditionReportData, PropertyMeta } from "@/app/db/schema/property"; +import { formatDateTime } from "@/app/utils"; + +function AddressCard({ address }: { address: string }) { + // In the future, we might want to use react-wrap-balancer for some of this text return ( -
-
Pre Assessment Report
+
+
{address}
+
+ ); +} + +interface PropertyDetailsCardProps { + conditionReportData: ConditionReportData; + propertyMeta: PropertyMeta; +} + +function PropertyDetailsCard({ + conditionReportData, + propertyMeta, +}: PropertyDetailsCardProps) { + return ( +
+
+
+ + + + + + + + + + + + + + + + + + + +
Year built: + {conditionReportData.yearBuilt} +
Property Type:{`${conditionReportData.builtForm} ${conditionReportData.propertyType}`}
Total floor area:{`${conditionReportData.totalFloorArea} square meters`}
In conservation area: + {conditionReportData.inConservationArea} +
+
+ + + + + + + + + + + + + + + + + + + +
Local Authority: + {propertyMeta.localAuthority} +
Constituency: + {propertyMeta.constituency} +
Tenure + {propertyMeta.tenure} +
Number of rooms: + {propertyMeta.numberOfRooms} +
+
+
+ ); +} + +// This type is used to define the shape of our data. +// You can use a Zod schema here if you want. + +export default async function PreAssessmentReport() { + const propertyMeta: PropertyMeta = { + id: 1, + address: "123 Fake Street", + postcode: "AB1 2CD", + hasPreConditionReport: true, + hasRecommendations: true, + createdAt: "2023-07-12 11:51:31.000 +0100", + propertyType: "House", + builtForm: "Detached", + localAuthority: "Birmingham", + constituency: "Birmingham", + numberOfRooms: 5, + yearBuilt: 1990, + tenure: "Rented (social)", + currentEpcRating: "C", + }; + + const conditionReportData: ConditionReportData = { + id: 1, + lastUpdated: "2023-07-12 11:51:31.000 +0100", + fullAddress: "123 Fake Street, Fake Town", + postcode: "AB1 2CD", + currentEpcRating: "C", + inConservationArea: "Yes", + propertyType: "House", + builtForm: "Detached", + totalFloorArea: 60, + tenure: "Rented (social)", + yearBuilt: "1990", + features: [ + { feature: "Wall", description: "Cavity wall", rating: "Poor" }, + { + feature: "Roof", + description: "Flat, limited insulation (assumed)", + rating: "Very poor", + }, + { feature: "Windows", description: "Double glazing", rating: "Good" }, + { feature: "Heating", description: "Gas boiler", rating: "Good" }, + { + feature: "Heating Control", + description: "Programmer and appliance thermostats", + rating: "Good", + }, + { + feature: "Hot Water", + description: "Electric immersion, standard tariff", + rating: "Good", + }, + { + feature: "Lighting", + description: "Low energy lighting in all fixed outlets", + rating: "Very good", + }, + { + feature: "Floor", + description: "Suspended timber", + rating: "Poor", + }, + ], + }; + + const features = conditionReportData.features; + + return ( +
+
Pre Assessment Report
+
+ Last updated: {formatDateTime(conditionReportData.lastUpdated)} +
+
+
+ + + + +
+
+
Property Features
+ +
Heating Demand
); } diff --git a/src/app/utils.ts b/src/app/utils.ts index 4cd6704..7c71075 100644 --- a/src/app/utils.ts +++ b/src/app/utils.ts @@ -1,3 +1,18 @@ +export function formatDateTime(dateTimeString: string): string { + // Create a new Date object + const dateTime = new Date(dateTimeString); + + // Get the various parts of the date + const options: Intl.DateTimeFormatOptions = { + year: "numeric", + month: "long", + day: "numeric", + hour: "2-digit", + minute: "2-digit", + }; + return dateTime.toLocaleDateString("en-GB", options); +} + export function formatNumber(number: number): string { const suffixes: string[] = ["", "k", "m", "b", "t"]; const suffixIndex: number = Math.floor(Math.log10(Math.abs(number)) / 3);