Added getproperties api

This commit is contained in:
Khalim Conn-Kowlessar 2023-07-31 17:53:17 +01:00
parent 34b140cf27
commit cc6cdc5d89
7 changed files with 77 additions and 55 deletions

View file

@ -77,7 +77,6 @@ export default function RecommendationModal({
// update the cost sum
setTotalEstimatedCost(sumRecommendationMetricMap(newCostMap));
console.log("title", title);
// Update the sap map
const newSapMap = {
...sapMap,

View file

@ -1,7 +1,8 @@
// db.ts
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
import * as schema from "@/app/db/schema/portfolio";
import * as portfolioSchema from "@/app/db/schema/portfolio";
import * as propertySchema from "@/app/db/schema/property";
export const pool = new Pool({
host: process.env.DB_HOST,
@ -11,4 +12,11 @@ export const pool = new Pool({
database: process.env.DB_NAME,
});
export const db = drizzle(pool, { schema });
const schema = {
...portfolioSchema,
...propertySchema,
};
export const db = drizzle(pool, {
schema: schema,
});

View file

@ -9,7 +9,7 @@ import {
boolean,
} from "drizzle-orm/pg-core";
import { portfolio, PortfolioStatus } from "./portfolio";
import { InferModel } from "drizzle-orm";
import { InferModel, relations } from "drizzle-orm";
// This is a placeholder for the property schema
export interface PropertyMeta {
@ -176,4 +176,25 @@ export const propertyTargets = pgTable("property_targets", {
heatDemand: text("heat_demand"),
});
// one to one relationship between property and propertyTargets
export const propertyTargetRelations = relations(property, ({ one }) => ({
target: one(propertyTargets, {
fields: [property.id],
references: [propertyTargets.propertyId],
}),
}));
// TODO: We'll need a property details buildings materials for verisk data?
export type Property = InferModel<typeof property, "select">;
// This type is used for the getProperties function in src/app/portfolio/[slug]/utils.ts
export interface PropertyWithTarget {
status: string | null;
id: number;
portfolioId: number;
creationStatus: string;
address: string | null;
postcode: string | null;
target: { epc?: string | null; heatDemand?: number | null };
cost?: number | null;
}

View file

@ -22,27 +22,27 @@ import {
} from "@/app/shadcn_components/ui/table";
import { useState } from "react";
import { DataTablePagination } from "./propertyTablePagination";
import { Property } from "./propertyTableColumns";
import React from "react";
import { Input } from "@/app/shadcn_components/ui/input";
import { PropertyWithTarget } from "@/app/db/schema/property";
interface DataTableProps<TData, TValue> {
columns: ColumnDef<Property>[];
data: Property[];
columns: ColumnDef<PropertyWithTarget>[];
data: PropertyWithTarget[];
}
function fetchData(offset: number) {
// Because this is a client component, this will be handled with react query
let properties: Property[] = [];
let properties: PropertyWithTarget[] = [];
for (let i = offset; i <= offset + 20; i++) {
properties.push({
id: i,
portfolioId: 1,
address: `${i}23 Fake Street`,
postcode: `AB${i} 2CD`,
loadingStatus: Math.random() < 0.5 ? "complete" : "loading",
creationStatus: Math.random() < 0.5 ? "complete" : "loading",
status: "assessment",
targetEpc: "C",
target: { epc: "C" },
cost: 1000,
});
}
@ -55,7 +55,7 @@ export default function DataTable<TData, TValue>({
columns,
}: DataTableProps<TData, TValue>) {
const [sorting, setSorting] = useState<SortingState>([]);
const [tableData, setTableData] = useState<Property[]>(data);
const [tableData, setTableData] = useState<PropertyWithTarget[]>(data);
const [offset, setOffset] = useState(0);
const [currentPageIndex, setCurrentPageIndex] = useState(0);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(

View file

@ -17,17 +17,7 @@ import { FunnelIcon } from "@heroicons/react/24/outline";
import { formatNumber } from "@/app/utils";
import { cn } from "@/lib/utils";
import { PortfolioStatus } from "@/app/db/schema/portfolio";
export type Property = {
id: number;
portfolioId: number;
address: string;
postcode: string;
loadingStatus: string;
status: string;
targetEpc: string;
cost: number;
};
import { PropertyWithTarget } from "@/app/db/schema/property";
interface DataTableColumnHeaderProps<TData, TValue>
extends React.HTMLAttributes<HTMLDivElement> {
@ -74,7 +64,7 @@ export function DataTableFilterHeader<TData, TValue>({
);
}
export const columns: ColumnDef<Property>[] = [
export const columns: ColumnDef<PropertyWithTarget>[] = [
{
accessorKey: "address",
header: ({ column }) => {
@ -136,8 +126,8 @@ export const columns: ColumnDef<Property>[] = [
cell: ({ row }) => {
const cost = parseFloat(row.getValue("cost"));
const loadingStatus = row.original.loadingStatus;
if (loadingStatus === "loading") {
const creationStatus = row.original.creationStatus;
if (creationStatus === "LOADING") {
return <div className="font-medium flex justify-center"></div>;
}
@ -156,7 +146,7 @@ export const columns: ColumnDef<Property>[] = [
cell: ({ row }) => {
return (
<div className="text-gray-700 font-medium flex justify-center">
{row.original.targetEpc}
{row.original.target?.epc || ""}
</div>
);
},
@ -168,8 +158,8 @@ export const columns: ColumnDef<Property>[] = [
const propertyId = property.id;
const portfolioId = property.portfolioId;
const loadingStatus = property.loadingStatus;
if (loadingStatus === "loading") {
const creationStatus = property.creationStatus;
if (creationStatus === "LOADING") {
return (
<div className="font-mediutext-gray-800m text-gray-700 flex justify-center">
Loading...

View file

@ -1,11 +1,9 @@
import { HomeIcon } from "@heroicons/react/24/outline";
import { getPortfolio } from "./utils";
import { getPortfolio, getProperties } from "./utils";
import { Toolbar } from "@/app/components/portfolio/Toolbar";
import DataTable from "@/app/portfolio/[slug]/components/propertyTable";
import {
columns,
Property,
} from "@/app/portfolio/[slug]/components/propertyTableColumns";
import { columns } from "@/app/portfolio/[slug]/components/propertyTableColumns";
import { PropertyWithTarget } from "@/app/db/schema/property";
// We enfore caching of data for 60 seconds
export const revalidate = 60;
@ -194,7 +192,6 @@ export default async function Page({
// We explcitly cast the slug to a number since it will be a string
const portfolioId = Number(params.slug);
const pageStatus = searchParams.status || undefined;
const {
name: portfolioName,
budget,
@ -207,23 +204,7 @@ export default async function Page({
energyCostSavings,
} = await getPortfolio(portfolioId);
// TODO: TEMP
// let properties: Property[];
let properties: Property[] = [];
if (pageStatus === "loading") {
for (let i = 1; i <= 20; i++) {
properties.push({
id: i,
portfolioId: 1,
address: `${i}23 Fake Street`,
postcode: `AB${i} 2CD`,
loadingStatus: Math.random() < 0.5 ? "complete" : "loading",
status: "assessment",
targetEpc: "C",
cost: 1000,
});
}
}
const properties: PropertyWithTarget[] = await getProperties(portfolioId);
return (
<>
@ -258,10 +239,6 @@ export default async function Page({
{properties.length === 0 ? (
<EmptyPropertyState />
) : (
// <Propertycards
// properties={properties}
// portfolioId={portfolioId}
// />
<DataTable data={properties} columns={columns} />
)}
</div>

View file

@ -1,7 +1,9 @@
import { eq } from "drizzle-orm";
import { db } from "@/app/db/db";
import { portfolio } from "@/app/db/schema/portfolio";
import { property } from "@/app/db/schema/property";
import type { Portfolio } from "@/app/db/schema/portfolio";
import type { PropertyWithTarget } from "@/app/db/schema/property";
export async function getPortfolio(portfolioId: number): Promise<Portfolio> {
const data = await db
@ -19,3 +21,28 @@ export async function getPortfolio(portfolioId: number): Promise<Portfolio> {
return data[0];
}
export async function getProperties(
portfolioId: number
): Promise<PropertyWithTarget[]> {
const data: PropertyWithTarget[] = await db.query.property.findMany({
columns: {
id: true,
portfolioId: true,
address: true,
postcode: true,
status: true,
creationStatus: true,
},
where: eq(property.portfolioId, portfolioId),
with: {
target: {
columns: {
epc: true,
},
},
},
});
return data;
}