Added basic structure for building passport, optimised layout

This commit is contained in:
Khalim Conn-Kowlessar 2023-07-25 12:01:14 +01:00
parent 6f8e7b256e
commit 97158d3dde
15 changed files with 239 additions and 26 deletions

View file

@ -1,5 +1,14 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "lh3.googleusercontent.com",
},
],
},
};
// use next-axiom for full stack monitoring
const { withAxiom } = require("next-axiom");

View file

@ -1,10 +1,11 @@
"use client";
import React, { use, useState } from "react";
import React, { useState } from "react";
import { Transition } from "@headlessui/react";
import ProfileDropDown from "./ProfileDropDown";
import { signOut } from "next-auth/react";
import { usePathname } from "next/navigation";
import Image from "next/image";
function makeLink(href: string, label: string) {
return (
@ -17,7 +18,7 @@ function makeLink(href: string, label: string) {
);
}
function Nav() {
function Nav({ userImage }: { userImage: string }) {
const [isOpen, setIsOpen] = useState(false);
const pathname = usePathname();
@ -46,7 +47,7 @@ function Nav() {
</div>
</div>
<div className="flex-grow"></div>
<ProfileDropDown />
<ProfileDropDown userImage={userImage} />
<div className="-mr-2 flex md:hidden">
<button
onClick={() => setIsOpen(!isOpen)}

View file

@ -1,22 +1,16 @@
"use client";
import { Menu } from "@headlessui/react";
import { signOut, useSession } from "next-auth/react";
import { signOut } from "next-auth/react";
import Link from "next/link";
function ProfileDropDown() {
const { data: session, status } = useSession();
if (status !== "authenticated" || !session || !session.user) {
return null;
}
function ProfileDropDown({ userImage }: { userImage: string }) {
return (
<Menu as="div" className="relative">
<Menu.Button className="rounded-full">
{session.user.image ? (
{userImage ? (
<img
src={session.user.image}
src={userImage}
alt={"Profile"}
className="inline h-12 w-12 rounded-full text-white"
/>

View file

@ -17,9 +17,6 @@ export default function StatusBadge({
}) {
const statusConfig = statusColor[status];
console.log("status");
console.log(status);
return (
<HoverCard>
<HoverCardTrigger>

View file

@ -0,0 +1,88 @@
"use client";
import {
Cog6ToothIcon,
NewspaperIcon,
HomeModernIcon,
LightBulbIcon,
} from "@heroicons/react/24/outline";
import {
NavigationMenu,
NavigationMenuItem,
NavigationMenuList,
NavigationMenuLink,
} from "@/app/shadcn_components/ui/navigation-menu";
import { cva } from "class-variance-authority";
import type { PropertyMeta } from "@/app/db/schema/property";
interface ToolbarProps {
propertyMeta: PropertyMeta;
portfolioId: number;
}
const navigationMenuTriggerStyle = cva(
"bg-gray-50 cursor-pointer group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-gray-200 hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-gray-200"
);
export function Toolbar({ propertyMeta, portfolioId }: ToolbarProps) {
function handleClickSettings() {
console.log("Settings were clicked, implement me");
}
function handleClickPortfolioPlan() {
console.log("Opt Plan was clicked, implement me");
}
const propertyId = propertyMeta.id;
const preAssessmentReportButton = propertyMeta.hasPreConditionReport && (
<NavigationMenuLink
className={navigationMenuTriggerStyle() + " ml-3 mr-2"}
href={`/portfolio/${portfolioId}/building-passport/${propertyId}/pre-assessment-report`}
>
<NewspaperIcon className="h-4 w-4 mr-2" />
Pre-assessment Condition Report
</NavigationMenuLink>
);
const recommendationsButton = propertyMeta.hasPreConditionReport && (
<NavigationMenuLink
className={navigationMenuTriggerStyle() + " ml-3 mr-2"}
href={`/portfolio/${portfolioId}/building-passport/${propertyId}/recommendations`}
>
<HomeModernIcon className="h-4 w-4 mr-2" />
Retrofit Recommendations
</NavigationMenuLink>
);
return (
<NavigationMenu>
<NavigationMenuLink
className={navigationMenuTriggerStyle() + " ml-3 mr-2"}
href={`/portfolio/${portfolioId}/building-passport/${propertyId}`}
>
<HomeModernIcon className="h-4 w-4 mr-2" />
Property Information
</NavigationMenuLink>
<NavigationMenuList>
{preAssessmentReportButton}
{recommendationsButton}
<NavigationMenuLink
className={navigationMenuTriggerStyle() + " ml-3 mr-2"}
href={`/portfolio/${portfolioId}/building-passport/${propertyId}/plan-optimiser`}
>
<LightBulbIcon className="h-4 w-4 mr-2" />
Plan optimiser
</NavigationMenuLink>
<NavigationMenuItem
className={navigationMenuTriggerStyle() + " ml-3 mr-2"}
onClick={handleClickSettings}
>
<Cog6ToothIcon className="h-4 w-4 mr-2" />
Settings
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
);
}

View file

@ -0,0 +1,8 @@
// This is a placeholder for the property schema
export interface PropertyMeta {
id: number;
address: string;
postcode: string;
hasPreConditionReport: boolean;
hasRecommendations: boolean;
}

View file

@ -2,6 +2,9 @@ import "./globals.css";
import Provider from "./components/Provider";
import Nav from "./components/Navbar";
import { ReactQueryProvider } from "./ReactQueryProvider";
import { AuthOptions } from "@/app/api/auth/[...nextauth]/route";
import { getServerSession } from "next-auth/next";
import { cache } from "react";
import { Inter } from "next/font/google";
@ -16,7 +19,12 @@ export const metadata = {
description: "Start your retrofit journey today",
};
export default function RootLayout({
const getSession = cache(async () => {
const session = await getServerSession(AuthOptions);
return session;
});
export default async function RootLayout({
children,
}: {
children: React.ReactNode;
@ -25,12 +33,15 @@ export default function RootLayout({
// possibly don't want, or at least don't want it to look exactly like this, with the same links and ability to sign out
// on small screens.
const session = await getSession();
const userImage = session?.user?.image;
return (
<html lang="en" className={inter.className}>
<body>
<Provider>
<ReactQueryProvider>
<Nav />
<Nav userImage={userImage} />
{children}
</ReactQueryProvider>
</Provider>

View file

@ -0,0 +1,48 @@
import { Toolbar } from "@/app/components/building-passport/Toolbar";
export default function DashboardLayout({
children, // will be a page or nested layout
params,
}: {
children: React.ReactNode;
params: { slug: string; propertyId: string };
}) {
const propertyId = Number(params.propertyId) ?? null;
const portfolioId = Number(params.slug) ?? null;
// The layout is a server component by default so we can fetch meta data here
// TODO: Implement get api
const propertyMeta = {
id: 1,
address: "123 Fake Street",
postcode: "AB1 2CD",
hasPreConditionReport: true,
hasRecommendations: true,
};
if (!propertyId && propertyId !== 0) {
throw Error("Invalid propertyId");
}
if (!portfolioId && portfolioId !== 0) {
throw Error("Invalid portfolioId");
}
return (
<section>
<div className="mx-auto w-full max-w-screen-2xl">
<div className="flex justify-start items-end p-8">
<h1 className="text-3xl font-bold mr-3 text-gray-900">
{propertyMeta.address}
</h1>
<p className="text-xl text-gray-700">{propertyMeta.postcode}</p>
</div>
<div className="col-span-12 justify-center bg-gray-50 py-2 rounded-md">
<Toolbar propertyMeta={propertyMeta} portfolioId={portfolioId} />
</div>
{children}
</div>
</section>
);
}

View file

@ -0,0 +1,10 @@
import { Button } from "@/app/shadcn_components/ui/button";
import { Toolbar } from "@/app/components/building-passport/Toolbar";
export default function BuildingPassportHome() {
return (
<div>
<div className="flex p-8">Basic information</div>
</div>
);
}

View file

@ -0,0 +1,7 @@
export default function PlanOptimiser() {
return (
<div>
<div className="flex p-8">Plan optimiser</div>
</div>
);
}

View file

@ -0,0 +1,7 @@
export default function PreAssessmentReport() {
return (
<div>
<div className="flex p-8">Pre Assessment Report</div>
</div>
);
}

View file

@ -0,0 +1,7 @@
export default function Recommendations() {
return (
<div>
<div className="flex p-8">Recommendations</div>
</div>
);
}

View file

@ -0,0 +1,25 @@
"use client";
export default function Error() {
return (
<div className="grid h-screen px-4 bg-white pt-32">
<div className="text-center">
<h1 className="font-black text-gray-200 text-9xl">404</h1>
<p className="text-2xl font-bold tracking-tight text-gray-900 sm:text-4xl">
Something went wrong!
</p>
<p className="mt-4 text-gray-500">Please try again or return to home</p>
<a
type="button"
className="inline-block px-5 py-3 mt-6 text-sm font-medium text-white bg-brandblue rounded hover:bg-hoverblue focus:outline-none focus:ring"
href="/home"
>
Home
</a>
</div>
</div>
);
}

View file

@ -99,7 +99,7 @@ export const columns: ColumnDef<Property>[] = [
<HomeIcon className="h-8 w-8 text-gray-200" />
<div className="flex flex-col">
<a
href={`portfolio/${portfolioId}/building-passport/${propertyId}`}
href={`${portfolioId}/building-passport/${propertyId}`}
className="font-medium underline text-gray-800 cursor-pointer"
>
{address}
@ -166,7 +166,7 @@ export const columns: ColumnDef<Property>[] = [
cell: ({ row }) => {
const property = row.original;
const propertyId = property.id;
const porfolioId = property.portfolioId;
const portfolioId = property.portfolioId;
const loadingStatus = property.loadingStatus;
if (loadingStatus === "loading") {
@ -192,9 +192,7 @@ export const columns: ColumnDef<Property>[] = [
// onClick={() => navigator.clipboard.writeText(payment.id)}
className="text-gray-700 cursor-pointer"
>
<a
href={`porfolio/${porfolioId}/building-passport/${propertyId}`}
>
<a href={`${portfolioId}/building-passport/${propertyId}`}>
Building Passport
</a>
</DropdownMenuItem>

View file

@ -45,8 +45,11 @@ export function DataTablePagination<TData>({
<div className="flex items-center justify-end px-2">
<div className="flex items-center space-x-6 lg:space-x-8">
<div className="flex w-[100px] items-center justify-center text-sm font-medium">
Page {table.getState().pagination.pageIndex + 1} of{" "}
{table.getPageCount()}
Page{" "}
{table.getPageCount() === 0
? 0
: table.getState().pagination.pageIndex + 1}{" "}
of {table.getPageCount()}
</div>
<div className="flex items-center space-x-2">
<Button