From a3c7e8f4c9dcef13b2a94f8480af54805104931b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Tue, 6 Feb 2024 15:37:37 +0100
Subject: [PATCH 01/12] removing legacy code
---
app/ui/BillEditForm.tsx | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
diff --git a/app/ui/BillEditForm.tsx b/app/ui/BillEditForm.tsx
index 500ca12..b08e84c 100644
--- a/app/ui/BillEditForm.tsx
+++ b/app/ui/BillEditForm.tsx
@@ -6,7 +6,6 @@ import React, { FC } from "react";
import { useFormState } from "react-dom";
import { updateOrAddBill } from "../lib/actions/billActions";
import Link from "next/link";
-import { gotoHome } from "../lib/actions/navigationActions";
import { formatYearMonth } from "../lib/format";
// Next.js does not encode an utf-8 file name correctly when sending a form with a file attachment
@@ -35,12 +34,7 @@ export const BillEditForm:FC = ({ location, bill }) => {
const [ isPaid, setIsPaid ] = React.useState(paid);
- // redirect to the main page
- const handleCancel = () => {
- gotoHome(location.yearMonth);
- };
-
- const billPaid_handleChange = (event: React.ChangeEvent) => {
+ const billPaid_handleChange = (event: React.ChangeEvent) => {
setIsPaid(event.target.checked);
}
From 9a83d48e68c3d166a25b40ecc37fac148752f35c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Tue, 6 Feb 2024 15:42:10 +0100
Subject: [PATCH 02/12] removing legacy code
---
app/ui/LocationEditForm.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/app/ui/LocationEditForm.tsx b/app/ui/LocationEditForm.tsx
index 9b4aa27..97148bd 100644
--- a/app/ui/LocationEditForm.tsx
+++ b/app/ui/LocationEditForm.tsx
@@ -6,7 +6,6 @@ import { BillingLocation, YearMonth } from "../lib/db-types";
import { updateOrAddLocation } from "../lib/actions/locationActions";
import { useFormState } from "react-dom";
import Link from "next/link";
-import { gotoHome } from "../lib/actions/navigationActions";
export type LocationEditFormProps = {
/** location which should be edited */
From 3579bb616ee280dd39da1196215ef90d448dac42 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Thu, 8 Feb 2024 13:22:07 +0100
Subject: [PATCH 03/12] refactoring: renamed a component
---
.../{MonthCardSceleton.tsx => MonthCardSkeleton.tsx} | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
rename app/ui/{MonthCardSceleton.tsx => MonthCardSkeleton.tsx} (77%)
diff --git a/app/ui/MonthCardSceleton.tsx b/app/ui/MonthCardSkeleton.tsx
similarity index 77%
rename from app/ui/MonthCardSceleton.tsx
rename to app/ui/MonthCardSkeleton.tsx
index bc88b4b..d074358 100644
--- a/app/ui/MonthCardSceleton.tsx
+++ b/app/ui/MonthCardSkeleton.tsx
@@ -15,18 +15,9 @@ export interface MonthCardSkeletonProps {
export const MonthCardSkeleton: React.FC = ({checked=false}) =>
;
-
-
-export const HomePageSkeleton: React.FC = () =>
-<>
-
-
-
->;
\ No newline at end of file
From 4633b364749b99ff2b88f4f9d0d5d77c36cebc8e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Thu, 8 Feb 2024 13:22:19 +0100
Subject: [PATCH 04/12] added API routers for locations
---
app/api/all-locations/route.ts | 14 ++++++++++++++
app/api/available-years/route.ts | 9 +++++++++
2 files changed, 23 insertions(+)
create mode 100644 app/api/all-locations/route.ts
create mode 100644 app/api/available-years/route.ts
diff --git a/app/api/all-locations/route.ts b/app/api/all-locations/route.ts
new file mode 100644
index 0000000..21179d9
--- /dev/null
+++ b/app/api/all-locations/route.ts
@@ -0,0 +1,14 @@
+import { fetchAllLocations } from '@/app/lib/actions/locationActions';
+import type { NextApiRequest } from 'next'
+import { NextResponse } from 'next/server';
+
+export const GET = async (
+ req: NextApiRequest,
+) => {
+ // get year from query params
+ const url = new URL(req.url as string);
+ const year = parseInt(url.searchParams.get('year') as string, 10);
+ const locations = await fetchAllLocations(year);
+
+ return NextResponse.json({ locations });
+}
diff --git a/app/api/available-years/route.ts b/app/api/available-years/route.ts
new file mode 100644
index 0000000..310dfed
--- /dev/null
+++ b/app/api/available-years/route.ts
@@ -0,0 +1,9 @@
+import { fetchAvailableYears } from '@/app/lib/actions/monthActions';
+import { NextResponse } from 'next/server';
+
+export async function GET(request: Request) {
+
+ const availableYears = await fetchAvailableYears();
+
+ return NextResponse.json({ availableYears });
+}
\ No newline at end of file
From 8703decb91140eade3b3a1dab06ab750d3b66a19 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Thu, 8 Feb 2024 13:23:23 +0100
Subject: [PATCH 05/12] HomePage: switched to client-side rendering
---
app/lib/actions/monthActions.ts | 2 +-
app/page.tsx | 12 +++--
app/ui/HomePage.tsx | 87 +++++++++++++++++++++++++--------
3 files changed, 74 insertions(+), 27 deletions(-)
diff --git a/app/lib/actions/monthActions.ts b/app/lib/actions/monthActions.ts
index 7b3d843..03dcea8 100644
--- a/app/lib/actions/monthActions.ts
+++ b/app/lib/actions/monthActions.ts
@@ -70,7 +70,7 @@ export const fetchAvailableYears = withUser(async (user:AuthenticatedUser) => {
const dbClient = await getDbClient();
// query mnogodb for all `yearMonth` values
- const years = await dbClient.collection("lokacije")
+ const years:number[] = await dbClient.collection("lokacije")
.distinct("yearMonth.year", { userId })
// sort the years in descending order
diff --git a/app/page.tsx b/app/page.tsx
index d321cd7..01601df 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -1,7 +1,11 @@
import { FC, Suspense } from 'react';
import { Main } from './ui/Main';
-import HomePage from './ui/HomePage';
-import { HomePageSkeleton } from './ui/MonthCardSceleton';
+import dynamic from 'next/dynamic'
+
+const HomePage = dynamic(
+ () => import('./ui/HomePage'),
+ { ssr: false }
+)
export interface PageProps {
searchParams?: {
@@ -14,9 +18,7 @@ const Page:FC = async ({ searchParams }) => {
return (
- }>
-
-
+
);
}
diff --git a/app/ui/HomePage.tsx b/app/ui/HomePage.tsx
index 2f3f59a..821366e 100644
--- a/app/ui/HomePage.tsx
+++ b/app/ui/HomePage.tsx
@@ -1,30 +1,79 @@
-import { fetchAllLocations } from '@/app/lib/actions/locationActions';
-import { fetchAvailableYears } from '@/app/lib/actions/monthActions';
+"use client";
+
import { BillingLocation, YearMonth } from '@/app/lib/db-types';
-import { FC } from 'react';
+import { FC, useEffect, useState } from 'react';
import { MonthLocationList } from '@/app/ui/MonthLocationList';
+import { WithId } from 'mongodb';
+import { MonthCardSkeleton } from './MonthCardSkeleton';
export interface HomePageProps {
- searchParams?: {
- year?: string;
- month?: string;
- };
}
-export const HomePage:FC = async ({ searchParams }) => {
+const fetchAllLocations = async (year: number) => {
+ const response = await fetch(`/api/all-locations/?year=${year}`);
+ const { locations } : { locations: WithId[] } = await response.json();
+ return locations;
+}
- let availableYears: number[];
+const fetchAvailableYears = async () => {
+ const response = await fetch(`/api/available-years/`);
+ const { availableYears }: { availableYears: number[]} = await response.json();
+ return availableYears;
+}
- // const asyncTimout = (ms:number) => new Promise(resolve => setTimeout(resolve, ms));
- // await asyncTimout(5000);
+export const HomePage:FC = () => {
- try {
- availableYears = await fetchAvailableYears();
- } catch (error:any) {
+ const [ homePageStatus, setHomePageStatus ] = useState<{
+ status: "loading" | "loaded" | "error",
+ availableYears: number[],
+ locations: WithId[],
+ error?: string
+ }>({
+ status: "loading",
+ availableYears: [],
+ locations: []
+ });
+
+ const {availableYears, locations, status, error} = homePageStatus;
+
+ const year = new URLSearchParams(window.location.search).get('year');
+ const currentYear = year ? parseInt(year, 10) : new Date().getFullYear();
+
+ useEffect(() => {
+
+ const fetchData = async () => {
+
+ try {
+ setHomePageStatus({
+ availableYears: await fetchAvailableYears(),
+ locations: await fetchAllLocations(currentYear),
+ status: "loaded",
+ });
+ } catch (error: any) {
+ setHomePageStatus({
+ status: "error",
+ availableYears: [],
+ locations: [],
+ error: error.message
+ });
+ }
+ }
+
+ fetchData();
+ }, [currentYear]);
+
+ if(status === "loading") {
return (
-
- {error.message}
- );
+ <>
+
+
+
+ >
+ );
+ }
+
+ if(status === "error") {
+ return({error}
);
}
// if the database is in it's initial state, show the add location button for the current month
@@ -32,10 +81,6 @@ export const HomePage:FC = async ({ searchParams }) => {
return ();
}
- const currentYear = Number(searchParams?.year) || availableYears[0];
-
- const locations = await fetchAllLocations(currentYear);
-
// group locations by month
const months = locations.reduce((acc, location) => {
const {year, month} = location.yearMonth;
From 3bd487d126e7cc6dbdb59a4b08971949c2426ac0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Thu, 8 Feb 2024 13:27:28 +0100
Subject: [PATCH 06/12] refactor: renamed API dirs
---
app/api/{ => locations}/available-years/route.ts | 0
app/api/{all-locations => locations/in-year}/route.ts | 0
app/ui/HomePage.tsx | 4 ++--
3 files changed, 2 insertions(+), 2 deletions(-)
rename app/api/{ => locations}/available-years/route.ts (100%)
rename app/api/{all-locations => locations/in-year}/route.ts (100%)
diff --git a/app/api/available-years/route.ts b/app/api/locations/available-years/route.ts
similarity index 100%
rename from app/api/available-years/route.ts
rename to app/api/locations/available-years/route.ts
diff --git a/app/api/all-locations/route.ts b/app/api/locations/in-year/route.ts
similarity index 100%
rename from app/api/all-locations/route.ts
rename to app/api/locations/in-year/route.ts
diff --git a/app/ui/HomePage.tsx b/app/ui/HomePage.tsx
index 821366e..091af1b 100644
--- a/app/ui/HomePage.tsx
+++ b/app/ui/HomePage.tsx
@@ -10,13 +10,13 @@ export interface HomePageProps {
}
const fetchAllLocations = async (year: number) => {
- const response = await fetch(`/api/all-locations/?year=${year}`);
+ const response = await fetch(`/api/locations/in-year/?year=${year}`);
const { locations } : { locations: WithId[] } = await response.json();
return locations;
}
const fetchAvailableYears = async () => {
- const response = await fetch(`/api/available-years/`);
+ const response = await fetch(`/api/locations/available-years/`);
const { availableYears }: { availableYears: number[]} = await response.json();
return availableYears;
}
From 0bb4c1206197650c6e73002adae9e74a7ccac448 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Thu, 8 Feb 2024 13:50:48 +0100
Subject: [PATCH 07/12] LocationEditForm: migrated to client-side rendering
---
app/api/locations/by-id/route.ts | 13 +++++
app/location/[id]/edit/LocationEditPage.tsx | 57 +++++++++++++++++----
app/location/[id]/edit/page.tsx | 6 +--
app/ui/LocationEditForm.tsx | 17 +++---
4 files changed, 71 insertions(+), 22 deletions(-)
create mode 100644 app/api/locations/by-id/route.ts
diff --git a/app/api/locations/by-id/route.ts b/app/api/locations/by-id/route.ts
new file mode 100644
index 0000000..605b5d6
--- /dev/null
+++ b/app/api/locations/by-id/route.ts
@@ -0,0 +1,13 @@
+import { fetchLocationById } from '@/app/lib/actions/locationActions';
+import type { NextApiRequest } from 'next'
+import { NextResponse } from 'next/server';
+
+export const GET = async (
+ req: NextApiRequest,
+) => {
+ const url = new URL(req.url as string);
+ const locationId = url.searchParams.get('id');
+ const location = await fetchLocationById(locationId as string);
+
+ return NextResponse.json({ location });
+}
diff --git a/app/location/[id]/edit/LocationEditPage.tsx b/app/location/[id]/edit/LocationEditPage.tsx
index 505f634..df97fad 100644
--- a/app/location/[id]/edit/LocationEditPage.tsx
+++ b/app/location/[id]/edit/LocationEditPage.tsx
@@ -1,16 +1,53 @@
+"use client";
+
import { notFound } from 'next/navigation';
-import { LocationEditForm } from '@/app/ui/LocationEditForm';
-import { fetchLocationById } from '@/app/lib/actions/locationActions';
+import { LocationEditForm, LocationEditFormSkeleton } from '@/app/ui/LocationEditForm';
+import { useEffect, useState } from 'react';
+import { WithId } from 'mongodb';
+import { BillingLocation } from '@/app/lib/db-types';
-export default async function LocationEditPage({ locationId }: { locationId:string }) {
- const location = await fetchLocationById(locationId);
+const fetchLocationById = async (locationId: string) => {
+ const response = await fetch(`/api/locations/by-id?id=${locationId}`);
+ const json = await response.json();
+ return json.location as WithId;
+}
- if (!location) {
- return(notFound());
+export default function LocationEditPage({ locationId }: { locationId:string }) {
+
+ const [state, stateSet] = useState<{
+ status: 'loading' | 'error' | 'success';
+ location?: WithId;
+ error?: string;
+ }>({ status: 'loading' });
+
+ useEffect(() => {
+
+ const fetchLocation = async () => {
+ try {
+ const location = await fetchLocationById(locationId);
+ stateSet({ location, status: 'success' });
+ } catch(error:any) {
+ stateSet({ status: 'error', error: error.message });
+ }
+ };
+
+ fetchLocation();
+
+ }, [locationId]);
+
+ switch(state.status) {
+ case "error":
+ return(Error: {state.error}
);
+ case "loading":
+ return();
+ case "success":
+ if (!state.location) {
+ return(notFound());
+ }
+
+ return();
+ default:
+ return(Error: Unknown status
);
}
-
- const result = ;
-
- return (result);
}
\ No newline at end of file
diff --git a/app/location/[id]/edit/page.tsx b/app/location/[id]/edit/page.tsx
index 251f944..7e63bcb 100644
--- a/app/location/[id]/edit/page.tsx
+++ b/app/location/[id]/edit/page.tsx
@@ -1,15 +1,11 @@
-import { Suspense } from 'react';
import LocationEditPage from './LocationEditPage';
import { Main } from '@/app/ui/Main';
-import { LocationEditFormSkeleton } from '@/app/ui/LocationEditForm';
export default async function Page({ params:{ id } }: { params: { id:string } }) {
return (
- }>
-
-
+
);
}
\ No newline at end of file
diff --git a/app/ui/LocationEditForm.tsx b/app/ui/LocationEditForm.tsx
index 97148bd..1c1f86a 100644
--- a/app/ui/LocationEditForm.tsx
+++ b/app/ui/LocationEditForm.tsx
@@ -65,10 +65,9 @@ export const LocationEditForm:FC = ({ location, yearMonth
}
-
-
- Cancel
+
+ Cancel
@@ -79,10 +78,14 @@ export const LocationEditForm:FC = ({ location, yearMonth
export const LocationEditFormSkeleton:FC = () =>
{
return(
-
-
-
-
+
)
From e2f7b21a5e838e55ee3440b9bf144cd85136afb1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Thu, 8 Feb 2024 14:04:48 +0100
Subject: [PATCH 08/12] BugFix: HomePage did not parse URL correctly
---
app/ui/HomePage.tsx | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/app/ui/HomePage.tsx b/app/ui/HomePage.tsx
index 091af1b..095d0dd 100644
--- a/app/ui/HomePage.tsx
+++ b/app/ui/HomePage.tsx
@@ -5,6 +5,7 @@ import { FC, useEffect, useState } from 'react';
import { MonthLocationList } from '@/app/ui/MonthLocationList';
import { WithId } from 'mongodb';
import { MonthCardSkeleton } from './MonthCardSkeleton';
+import { useSearchParams } from 'next/navigation';
export interface HomePageProps {
}
@@ -23,6 +24,8 @@ const fetchAvailableYears = async () => {
export const HomePage:FC = () => {
+ const searchParams = useSearchParams();
+
const [ homePageStatus, setHomePageStatus ] = useState<{
status: "loading" | "loaded" | "error",
availableYears: number[],
@@ -36,7 +39,7 @@ export const HomePage:FC = () => {
const {availableYears, locations, status, error} = homePageStatus;
- const year = new URLSearchParams(window.location.search).get('year');
+ const year = searchParams.get('year');
const currentYear = year ? parseInt(year, 10) : new Date().getFullYear();
useEffect(() => {
From ee02cc4f32b5a4da7fe035bc4f2871acbc1311f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Thu, 8 Feb 2024 14:07:09 +0100
Subject: [PATCH 09/12] LocationAddPage migrated to client-side component
---
app/location/[id]/add/LocationAddPage.tsx | 5 ++---
app/location/[id]/add/page.tsx | 6 +-----
2 files changed, 3 insertions(+), 8 deletions(-)
diff --git a/app/location/[id]/add/LocationAddPage.tsx b/app/location/[id]/add/LocationAddPage.tsx
index ebef49f..a099506 100644
--- a/app/location/[id]/add/LocationAddPage.tsx
+++ b/app/location/[id]/add/LocationAddPage.tsx
@@ -1,8 +1,7 @@
-import { notFound } from 'next/navigation';
+"use client";
+
import { LocationEditForm } from '@/app/ui/LocationEditForm';
-import { fetchLocationById } from '@/app/lib/actions/locationActions';
import { YearMonth } from '@/app/lib/db-types';
-import { Main } from '@/app/ui/Main';
export default async function LocationAddPage({ yearMonth }: { yearMonth:YearMonth }) {
return ();
diff --git a/app/location/[id]/add/page.tsx b/app/location/[id]/add/page.tsx
index fed90e0..3f032fc 100644
--- a/app/location/[id]/add/page.tsx
+++ b/app/location/[id]/add/page.tsx
@@ -1,15 +1,11 @@
import { parseYearMonth } from '@/app/lib/format';
-import { LocationEditFormSkeleton } from '@/app/ui/LocationEditForm';
import LocationAddPage from './LocationAddPage';
import { Main } from '@/app/ui/Main';
-import { Suspense } from 'react';
export default async function Page({ params:{ id } }: { params: { id:string } }) {
return (
- }>
-
-
+
);
}
\ No newline at end of file
From a96998baad5f4f32ee43a2e318a50f53c6c67e32 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Thu, 8 Feb 2024 14:23:01 +0100
Subject: [PATCH 10/12] Location Edit / Add / Delete migrated to client-side
rendering
---
app/location/[id]/add/page.tsx | 7 ++-
.../[id]/delete/LocationDeletePage.tsx | 56 ++++++++++++++++---
app/location/[id]/delete/page.tsx | 16 +++---
app/location/[id]/edit/page.tsx | 8 ++-
app/ui/LocationDeleteForm.tsx | 16 +++++-
app/ui/LocationEditForm.tsx | 12 ++--
6 files changed, 89 insertions(+), 26 deletions(-)
diff --git a/app/location/[id]/add/page.tsx b/app/location/[id]/add/page.tsx
index 3f032fc..87d0ddf 100644
--- a/app/location/[id]/add/page.tsx
+++ b/app/location/[id]/add/page.tsx
@@ -1,6 +1,11 @@
import { parseYearMonth } from '@/app/lib/format';
-import LocationAddPage from './LocationAddPage';
import { Main } from '@/app/ui/Main';
+import dynamic from 'next/dynamic'
+
+const LocationAddPage = dynamic(
+ () => import('./LocationAddPage'),
+ { ssr: false }
+ )
export default async function Page({ params:{ id } }: { params: { id:string } }) {
return (
diff --git a/app/location/[id]/delete/LocationDeletePage.tsx b/app/location/[id]/delete/LocationDeletePage.tsx
index 7377733..ec8663c 100644
--- a/app/location/[id]/delete/LocationDeletePage.tsx
+++ b/app/location/[id]/delete/LocationDeletePage.tsx
@@ -1,14 +1,54 @@
+"use client";
+
import { notFound } from 'next/navigation';
-import { fetchLocationById } from '@/app/lib/actions/locationActions';
-import { LocationDeleteForm } from '@/app/ui/LocationDeleteForm';
+import { LocationDeleteForm, LocationDeleteFormSkeleton } from '@/app/ui/LocationDeleteForm';
+import { WithId } from 'mongodb';
+import { BillingLocation } from '@/app/lib/db-types';
+import { useEffect, useState } from 'react';
-export const LocationDeletePage = async ({ locationId }: { locationId:string }) => {
+const fetchLocationById = async (locationId: string) => {
+ const response = await fetch(`/api/locations/by-id?id=${locationId}`);
+ const json = await response.json();
+ return json.location as WithId;
+}
- const location = await fetchLocationById(locationId);
+const LocationDeletePage = ({ locationId }: { locationId:string }) => {
+
+ const [state, stateSet] = useState<{
+ status: 'loading' | 'error' | 'success';
+ location?: WithId;
+ error?: string;
+ }>({ status: 'loading' });
- if (!location) {
- return(notFound());
+ useEffect(() => {
+
+ const fetchLocation = async () => {
+ try {
+ const location = await fetchLocationById(locationId);
+ stateSet({ location, status: 'success' });
+ } catch(error:any) {
+ stateSet({ status: 'error', error: error.message });
+ }
+ };
+
+ fetchLocation();
+
+ }, [locationId]);
+
+ switch(state.status) {
+ case "error":
+ return(Error: {state.error}
);
+ case "loading":
+ return();
+ case "success":
+ if (!state.location) {
+ return(notFound());
+ }
+
+ return();
+ default:
+ return(Error: Unknown status
);
}
+}
- return ();
-}
\ No newline at end of file
+export default LocationDeletePage;
\ No newline at end of file
diff --git a/app/location/[id]/delete/page.tsx b/app/location/[id]/delete/page.tsx
index 6ae17d5..ca0db96 100644
--- a/app/location/[id]/delete/page.tsx
+++ b/app/location/[id]/delete/page.tsx
@@ -1,17 +1,17 @@
-import { notFound } from 'next/navigation';
-import { fetchLocationById } from '@/app/lib/actions/locationActions';
-import { LocationDeleteForm } from '@/app/ui/LocationDeleteForm';
import { Main } from '@/app/ui/Main';
-import { Suspense } from 'react';
-import { LocationDeletePage } from './LocationDeletePage';
+import dynamic from 'next/dynamic'
+
+const LocationDeletePage = dynamic(
+ () => import('./LocationDeletePage'),
+ { ssr: false }
+ )
+
export default async function Page({ params:{ id } }: { params: { id:string } }) {
return (
- Loading...}>
-
-
+
);
}
\ No newline at end of file
diff --git a/app/location/[id]/edit/page.tsx b/app/location/[id]/edit/page.tsx
index 7e63bcb..0fb2160 100644
--- a/app/location/[id]/edit/page.tsx
+++ b/app/location/[id]/edit/page.tsx
@@ -1,5 +1,11 @@
-import LocationEditPage from './LocationEditPage';
import { Main } from '@/app/ui/Main';
+import dynamic from 'next/dynamic'
+
+const LocationEditPage = dynamic(
+ () => import('./LocationEditPage'),
+ { ssr: false }
+ )
+
export default async function Page({ params:{ id } }: { params: { id:string } }) {
diff --git a/app/ui/LocationDeleteForm.tsx b/app/ui/LocationDeleteForm.tsx
index 35eb104..7f6651d 100644
--- a/app/ui/LocationDeleteForm.tsx
+++ b/app/ui/LocationDeleteForm.tsx
@@ -29,11 +29,23 @@ export const LocationDeleteForm:FC
= ({ location }) =>
Please confirm deletion of location “{location.name}”.
-
- Cancel
+
+ Cancel
);
}
+
+
+export const LocationDeleteFormSkeleton:FC = () =>
+
\ No newline at end of file
diff --git a/app/ui/LocationEditForm.tsx b/app/ui/LocationEditForm.tsx
index 1c1f86a..b1fdc29 100644
--- a/app/ui/LocationEditForm.tsx
+++ b/app/ui/LocationEditForm.tsx
@@ -47,7 +47,7 @@ export const LocationEditForm:FC = ({ location, yearMonth
))}
-
+
{state.errors?.locationNotes &&
state.errors.locationNotes.map((error: string) => (
@@ -79,12 +79,12 @@ export const LocationEditFormSkeleton:FC = () =>
{
return(
-
From 14c043850049aaf9317a60166baea7fe7ddbbf1e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Thu, 8 Feb 2024 14:43:38 +0100
Subject: [PATCH 11/12] HomePage: state optimization
---
app/ui/HomePage.tsx | 84 ++++++++++++++++++++++++---------------------
1 file changed, 44 insertions(+), 40 deletions(-)
diff --git a/app/ui/HomePage.tsx b/app/ui/HomePage.tsx
index 095d0dd..262da6c 100644
--- a/app/ui/HomePage.tsx
+++ b/app/ui/HomePage.tsx
@@ -10,6 +10,14 @@ import { useSearchParams } from 'next/navigation';
export interface HomePageProps {
}
+type MonthsLocations = {
+ [key:string]:{
+ yearMonth: YearMonth,
+ locations: BillingLocation[],
+ monthlyExpense: number
+ }
+}
+
const fetchAllLocations = async (year: number) => {
const response = await fetch(`/api/locations/in-year/?year=${year}`);
const { locations } : { locations: WithId[] } = await response.json();
@@ -25,38 +33,66 @@ const fetchAvailableYears = async () => {
export const HomePage:FC = () => {
const searchParams = useSearchParams();
+ const year = searchParams.get('year');
+ const currentYear = year ? parseInt(year, 10) : new Date().getFullYear();
const [ homePageStatus, setHomePageStatus ] = useState<{
status: "loading" | "loaded" | "error",
availableYears: number[],
- locations: WithId[],
+ months?: MonthsLocations,
error?: string
}>({
status: "loading",
availableYears: [],
- locations: []
});
- const {availableYears, locations, status, error} = homePageStatus;
-
- const year = searchParams.get('year');
- const currentYear = year ? parseInt(year, 10) : new Date().getFullYear();
+ const {availableYears, months, status, error} = homePageStatus;
useEffect(() => {
const fetchData = async () => {
try {
+ const locations = await fetchAllLocations(currentYear);
+
+ // group locations by month
+ const months = locations.reduce((acc, location) => {
+ const {year, month} = location.yearMonth;
+ const key = `${year}-${month}`;
+
+ const locationsInMonth = acc[key];
+
+ if(locationsInMonth) {
+ return({
+ ...acc,
+ [key]: {
+ yearMonth: location.yearMonth,
+ locations: [...locationsInMonth.locations, location],
+ monthlyExpense: locationsInMonth.monthlyExpense + location.bills.reduce((acc, bill) => bill.paid ? acc + (bill.payedAmount ?? 0) : acc, 0)
+ }
+ })
+ }
+
+ return({
+ ...acc,
+ [key]: {
+ yearMonth: location.yearMonth,
+ locations: [location],
+ monthlyExpense: location.bills.reduce((acc, bill) => bill.paid ? acc + (bill.payedAmount ?? 0) : acc, 0)
+ }
+ });
+ }, {} as MonthsLocations);
+
setHomePageStatus({
availableYears: await fetchAvailableYears(),
- locations: await fetchAllLocations(currentYear),
+ months,
status: "loaded",
});
+
} catch (error: any) {
setHomePageStatus({
status: "error",
availableYears: [],
- locations: [],
error: error.message
});
}
@@ -84,38 +120,6 @@ export const HomePage:FC = () => {
return ();
}
- // group locations by month
- const months = locations.reduce((acc, location) => {
- const {year, month} = location.yearMonth;
- const key = `${year}-${month}`;
-
- const locationsInMonth = acc[key];
-
- if(locationsInMonth) {
- return({
- ...acc,
- [key]: {
- yearMonth: location.yearMonth,
- locations: [...locationsInMonth.locations, location],
- monthlyExpense: locationsInMonth.monthlyExpense + location.bills.reduce((acc, bill) => bill.paid ? acc + (bill.payedAmount ?? 0) : acc, 0)
- }
- })
- }
-
- return({
- ...acc,
- [key]: {
- yearMonth: location.yearMonth,
- locations: [location],
- monthlyExpense: location.bills.reduce((acc, bill) => bill.paid ? acc + (bill.payedAmount ?? 0) : acc, 0)
- }
- });
- }, {} as {[key:string]:{
- yearMonth: YearMonth,
- locations: BillingLocation[],
- monthlyExpense: number
- } });
-
return (
);
From ab61657c03a3e74367e1ae66edd91e4405bcc02e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?=
Date: Thu, 8 Feb 2024 14:44:56 +0100
Subject: [PATCH 12/12] updated version in docker-compose
---
docker-compose-deploy.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docker-compose-deploy.yml b/docker-compose-deploy.yml
index a39518f..3dae28e 100644
--- a/docker-compose-deploy.yml
+++ b/docker-compose-deploy.yml
@@ -9,7 +9,7 @@ networks:
services:
web-app:
- image: utility-bills-tracker:1.8.0
+ image: utility-bills-tracker:1.9.0
networks:
- traefik-network
- mongo-network