Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FE - Display chart- and table view for Annual project cash flow #131

4 changes: 2 additions & 2 deletions api/src/modules/calculations/cost.calculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import {
CostPlanMap,
CustomProjectCostDetails,
CustomProjectSummary,
OutputCostNames,
YearlyBreakdown,
YearlyBreakdownCostName,
} from '@shared/dtos/custom-projects/custom-project-output.dto';

export type CostPlans = Record<
Expand Down Expand Up @@ -410,7 +410,7 @@ export class CostCalculator {
const totalCost = sum(Object.values(costValues));
const totalNPV = this.calculateNpv(costValues, discountRate);
yearlyBreakdown.push({
costName: costName as keyof OverridableCostInputs & OutputCostNames,
costName: costName as YearlyBreakdownCostName,
totalCost,
totalNPV,
costValues,
Expand Down
2 changes: 2 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@ts-rest/react-query": "3.51.0",
"class-variance-authority": "0.7.0",
"clsx": "2.1.1",
"country-iso-3-to-2": "^1.1.1",
"d3": "7.9.0",
"framer-motion": "11.11.9",
"jotai": "2.10.1",
Expand All @@ -52,6 +53,7 @@
"react-dropzone": "^14.3.5",
"react-map-gl": "7.1.7",
"react-resizable-panels": "2.1.6",
"recharts": "^2.13.3",
"rooks": "7.14.1",
"tailwind-merge": "2.5.3",
"tailwindcss-animate": "1.0.7",
Expand Down
39 changes: 32 additions & 7 deletions client/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
@tailwind components;
@tailwind utilities;


body {
font-family: Arial, Helvetica, sans-serif;
}
Expand Down Expand Up @@ -50,6 +49,11 @@ body {
--sidebar-accent-foreground: 192, 86%, 69%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 212, 57%, 24%;
--chart-1: 150 43% 61%;
--chart-2: 191 87% 82%;
--chart-3: 194 88% 43%;
--chart-4: 213 73% 97%;
--chart-5: 50 80% 58%;
}
}

Expand All @@ -65,31 +69,52 @@ body {
/* mapbox styles */
.mapboxgl-popup-anchor-top {
.mapboxgl-popup-tip {
@apply !border-b-popover !z-10 relative;
@apply relative !z-10 !border-b-popover;
}
}

.mapboxgl-popup-anchor-bottom {
.mapboxgl-popup-tip {
@apply !border-t-popover !z-10 relative;
@apply relative !z-10 !border-t-popover;
}
}

.mapboxgl-popup-anchor-left {
.mapboxgl-popup-tip {
@apply !border-r-popover !z-10 relative;
@apply relative !z-10 !border-r-popover;
}
}

.mapboxgl-popup-anchor-right {
.mapboxgl-popup-tip {
@apply !border-l-popover !z-10 relative;
@apply relative !z-10 !border-l-popover;
}
}

.mapboxgl-popup-content {
@apply !bg-popover !rounded-md border border-border text-big-stone-50 shadow-md;
@apply !rounded-md border border-border !bg-popover text-big-stone-50 shadow-md;
}
.mapboxgl-popup-close-button {
@apply hidden;
}
}

/* cashflow chart */
.cashflow-chart {
.recharts-cartesian-grid-vertical line {
stroke-dasharray: 3, 3;

&:nth-last-child(1),
&:nth-last-child(2) {
stroke: transparent;
}
}

.recharts-cartesian-grid-horizontal line {
stroke-dasharray: 0;

&:first-of-type,
&:last-of-type {
stroke: transparent;
}
}
}
64 changes: 62 additions & 2 deletions client/src/app/projects/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,65 @@
import { notFound } from "next/navigation";

import {
dehydrate,
HydrationBoundary,
QueryClient,
} from "@tanstack/react-query";

import { client } from "@/lib/query-client";
import { queryKeys } from "@/lib/query-keys";
import { getAuthHeader } from "@/lib/utils";

import { auth } from "@/app/auth/api/[...nextauth]/config";

import CustomProject from "@/containers/projects/custom-project";

export default function CustomProjectPage() {
return <CustomProject />;
async function getCustomProject(id: string, accessToken: string) {
const response = await client.customProjects.getCustomProject.query({
params: { id },
query: {
include: ["country"],
},
extraHeaders: {
...getAuthHeader(accessToken),
},
});

if (response.status !== 200) {
throw new Error(`Failed to fetch project: ${response.status}`);
}

return response;
}

export default async function CustomProjectPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const queryClient = new QueryClient();

try {
const id = (await params).id;
const session = await auth();

if (!session?.accessToken) {
throw new Error("Unauthorized");
}

// Using fetchQuery because prefetchQuery will not throw or return any data
// https://tanstack.com/query/latest/docs/reference/QueryClient#queryclientprefetchquery
await queryClient.fetchQuery({
queryKey: queryKeys.customProjects.one(id).queryKey,
queryFn: async () => getCustomProject(id, session.accessToken),
});

return (
<HydrationBoundary state={dehydrate(queryClient)}>
<CustomProject id={id} />
</HydrationBoundary>
);
} catch (e) {
notFound();
}
}
Loading
Loading