From 119d64344f0b4ea1d21da29289e626b51aaeddcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?= Date: Tue, 16 Jan 2024 17:13:58 +0100 Subject: [PATCH 1/8] added ToDo u Readme --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 7efaefe..9aac028 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,13 @@ +# ToDo +* zeleni outline dodati na račune koji imaju attachment čak i ako nisu plaćeni +* Bug: kod kopiranja računa u idući mjesec prenosi se i uplaćeni iznos +* Bug: kod sumiranja dodati provjeru je li račun plaćen - to je ispravka i za prethodni bug +* Forma za editiranje računa: + * dodati na vrh naziv lokacije + * forma se razvali (input za unos iznosa) kada je postavljen PDF +* Popis lokacija: + * omogućiti collapse za pojedine mjesece + # Authentication Authentication consists of the following parts: * `next-auth` boilerplate From 0eb11e7d02ee1dd2eb1b0681129be55a07dd8f61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?= Date: Wed, 17 Jan 2024 15:47:55 +0100 Subject: [PATCH 2/8] form action redirects user to tjhe appropriate year --- app/attachment/[id]/route.tsx | 2 +- app/bill/[id]/add/page.tsx | 1 + app/bill/[id]/delete/page.tsx | 15 ++++++---- app/bill/[id]/edit/page.tsx | 4 +-- app/lib/actions/billActions.ts | 25 ++++++----------- app/lib/actions/locationActions.ts | 17 ++++------- app/lib/actions/monthActions.ts | 19 +++---------- app/lib/actions/navigationActions.ts | 9 ++++++ app/location/[id]/delete/page.tsx | 15 +++++----- app/location/[id]/edit/page.tsx | 2 +- app/page.tsx | 12 ++++---- app/ui/BillDeleteForm.tsx | 42 ++++++++++++++++++++++++++++ app/ui/BillEditForm.tsx | 17 +++++------ app/ui/LocationCard.tsx | 6 ++-- app/ui/LocationDeleteForm.tsx | 41 +++++++++++++++++++++++++++ app/ui/LocationEditForm.tsx | 4 +-- app/ui/Pagination.tsx | 2 +- app/year-month/[id]/add/page.tsx | 11 ++++---- 18 files changed, 158 insertions(+), 86 deletions(-) create mode 100644 app/lib/actions/navigationActions.ts create mode 100644 app/ui/BillDeleteForm.tsx create mode 100644 app/ui/LocationDeleteForm.tsx diff --git a/app/attachment/[id]/route.tsx b/app/attachment/[id]/route.tsx index 258957c..4bb82d2 100644 --- a/app/attachment/[id]/route.tsx +++ b/app/attachment/[id]/route.tsx @@ -4,7 +4,7 @@ import { notFound } from 'next/navigation'; export async function GET(request: Request, { params:{ id } }: { params: { id:string } }) { const [locationID, billID] = id.split('-'); - const bill = await fetchBillById(locationID, billID); + const [location, bill] = await fetchBillById(locationID, billID) ? []; if(!bill?.attachment) { notFound(); diff --git a/app/bill/[id]/add/page.tsx b/app/bill/[id]/add/page.tsx index 5549d24..fbb92da 100644 --- a/app/bill/[id]/add/page.tsx +++ b/app/bill/[id]/add/page.tsx @@ -1,3 +1,4 @@ +import { fetchLocationById } from '@/app/lib/actions/locationActions'; import { BillEditForm } from '@/app/ui/BillEditForm'; import { Main } from '@/app/ui/Main'; diff --git a/app/bill/[id]/delete/page.tsx b/app/bill/[id]/delete/page.tsx index 3d41f02..6b9d211 100644 --- a/app/bill/[id]/delete/page.tsx +++ b/app/bill/[id]/delete/page.tsx @@ -1,14 +1,17 @@ -import { deleteBillById } from '@/app/lib/actions/billActions'; -import { revalidatePath } from 'next/cache'; -import { notFound, redirect } from 'next/navigation'; +import { notFound } from 'next/navigation'; +import { fetchLocationById } from '@/app/lib/actions/locationActions'; +import { LocationDeleteForm } from '@/app/ui/LocationDeleteForm'; +import { BillDeleteForm } from '@/app/ui/BillDeleteForm'; +import { fetchBillById } from '@/app/lib/actions/billActions'; export default async function Page({ params:{ id } }: { params: { id:string } }) { const [locationID, billID] = id.split('-'); - if(await deleteBillById(locationID, billID) === 0) { + const [location, bill] = await fetchBillById(locationID, billID) ?? []; + + if (!location || !bill) { return(notFound()); } - revalidatePath('/'); - redirect(`/`); + return (); } \ No newline at end of file diff --git a/app/bill/[id]/edit/page.tsx b/app/bill/[id]/edit/page.tsx index c1184b6..1d97ce4 100644 --- a/app/bill/[id]/edit/page.tsx +++ b/app/bill/[id]/edit/page.tsx @@ -7,14 +7,14 @@ export default async function Page({ params:{ id } }: { params: { id:string } }) const [locationID, billID] = id.split('-'); - const bill = await fetchBillById(locationID, billID); + const [location, bill] = await fetchBillById(locationID, billID) ?? []; if (!bill) { return(notFound()); } return (
- +
); } \ No newline at end of file diff --git a/app/lib/actions/billActions.ts b/app/lib/actions/billActions.ts index 18dd7fd..cb84856 100644 --- a/app/lib/actions/billActions.ts +++ b/app/lib/actions/billActions.ts @@ -1,13 +1,12 @@ 'use server'; import { z } from 'zod'; -import { revalidatePath } from 'next/cache'; -import { redirect } from 'next/navigation'; -import clientPromise, { getDbClient } from '../dbClient'; -import { BillAttachment, BillingLocation } from '../db-types'; +import { getDbClient } from '../dbClient'; +import { Bill, BillAttachment, BillingLocation, YearMonth } from '../db-types'; import { ObjectId } from 'mongodb'; import { withUser } from '@/app/lib/auth'; import { AuthenticatedUser } from '../types/next-auth'; +import { gotoHome } from './navigationActions'; export type State = { errors?: { @@ -110,7 +109,7 @@ const serializeAttachment = async (billAttachment: File | null) => { * @param formData form data * @returns */ -export const updateOrAddBill = withUser(async (user:AuthenticatedUser, locationId: string, billId:string|undefined, prevState:State, formData: FormData) => { +export const updateOrAddBill = withUser(async (user:AuthenticatedUser, locationId: string, billId:string|undefined, billYear:number|undefined, prevState:State, formData: FormData) => { const { id: userId } = user; @@ -192,18 +191,9 @@ export const updateOrAddBill = withUser(async (user:AuthenticatedUser, locationI } }); } - - // clear the cache for the path - revalidatePath('/'); - // go to the bill list - redirect('/'); + await gotoHome(billYear ? `/?year=${billYear}` : undefined); }) -export async function gotoHome() { - revalidatePath('/'); - redirect('/'); -} - export const fetchBillById = withUser(async (user:AuthenticatedUser, locationID:string, billID:string) => { const { id: userId } = user; @@ -226,10 +216,10 @@ export const fetchBillById = withUser(async (user:AuthenticatedUser, locationID: return(null); } - return(bill); + return([billLocation, bill] as [BillingLocation, Bill]); }) -export const deleteBillById = withUser(async (user:AuthenticatedUser, locationID:string, billID:string) => { +export const deleteBillById = withUser(async (user:AuthenticatedUser, locationID:string, billID:string, year:number) => { const { id: userId } = user; @@ -250,5 +240,6 @@ export const deleteBillById = withUser(async (user:AuthenticatedUser, locationID } }); + await gotoHome(`/?year=${year}`); return(post.modifiedCount); }); \ No newline at end of file diff --git a/app/lib/actions/locationActions.ts b/app/lib/actions/locationActions.ts index 91c2dbb..a928f1e 100644 --- a/app/lib/actions/locationActions.ts +++ b/app/lib/actions/locationActions.ts @@ -1,14 +1,12 @@ 'use server'; import { z } from 'zod'; -import { revalidatePath } from 'next/cache'; -import { redirect } from 'next/navigation'; -import clientPromise, { getDbClient } from '../dbClient'; +import { getDbClient } from '../dbClient'; import { BillingLocation, YearMonth } from '../db-types'; import { ObjectId } from 'mongodb'; -import { auth, withUser } from '@/app/lib/auth'; +import { withUser } from '@/app/lib/auth'; import { AuthenticatedUser } from '../types/next-auth'; -import { NormalizedRouteManifest } from 'next/dist/server/base-server'; +import { gotoHome } from './navigationActions'; export type State = { errors?: { @@ -82,10 +80,7 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat }); } - // clear the cache for the path - revalidatePath('/'); - // go to the bill list - redirect('/'); + await gotoHome(yearMonth ? `/?year=${yearMonth?.year}` : undefined) }); @@ -128,7 +123,7 @@ export const fetchLocationById = withUser(async (user:AuthenticatedUser, locatio return(billLocation); }) -export const deleteLocationById = withUser(async (user:AuthenticatedUser, locationID:string) => { +export const deleteLocationById = withUser(async (user:AuthenticatedUser, locationID:string, yearMonth:YearMonth) => { const dbClient = await getDbClient(); @@ -137,5 +132,5 @@ export const deleteLocationById = withUser(async (user:AuthenticatedUser, locati // find a location with the given locationID const post = await dbClient.collection("lokacije").deleteOne({ _id: locationID, userId }); - return(post.deletedCount); + await gotoHome(`/?year=${yearMonth?.year}`) }) \ No newline at end of file diff --git a/app/lib/actions/monthActions.ts b/app/lib/actions/monthActions.ts index 1a234a0..3e7948a 100644 --- a/app/lib/actions/monthActions.ts +++ b/app/lib/actions/monthActions.ts @@ -1,10 +1,8 @@ 'use server'; -import { revalidatePath } from 'next/cache'; -import { redirect } from 'next/navigation'; -import clientPromise, { getDbClient } from '../dbClient'; +import { getDbClient } from '../dbClient'; import { ObjectId } from 'mongodb'; -import { BillingLocation, YearMonth } from '../db-types'; +import { Bill, BillingLocation, YearMonth } from '../db-types'; import { AuthenticatedUser } from '../types/next-auth'; import { withUser } from '../auth'; @@ -22,7 +20,6 @@ export const addMonth = withUser(async (user:AuthenticatedUser, { year, month }: // update the bill in the mongodb const dbClient = await getDbClient(); - const prevYear = month === 1 ? year - 1 : year; const prevMonth = month === 1 ? 12 : month - 1; @@ -52,24 +49,16 @@ export const addMonth = withUser(async (user:AuthenticatedUser, { year, month }: paid: false, attachment: null, notes: null, - } + payedAmount: null + } as Bill }) } as BillingLocation); }); const newMonthLocations = await newMonthLocationsCursor.toArray() await dbClient.collection("lokacije").insertMany(newMonthLocations); - - // clear the cache for the path - revalidatePath('/'); - // go to the bill list - redirect('/'); }); -export async function gotoHome() { - redirect('/'); -} - export const fetchAvailableYears = withUser(async (user:AuthenticatedUser) => { const { id: userId } = user; diff --git a/app/lib/actions/navigationActions.ts b/app/lib/actions/navigationActions.ts new file mode 100644 index 0000000..444c801 --- /dev/null +++ b/app/lib/actions/navigationActions.ts @@ -0,0 +1,9 @@ +'use server'; + +import { revalidatePath } from "next/cache"; +import { redirect } from 'next/navigation'; + +export async function gotoHome(path: string = '/') { + revalidatePath(path, "page"); + redirect(path); +} diff --git a/app/location/[id]/delete/page.tsx b/app/location/[id]/delete/page.tsx index 687570b..f4d8d44 100644 --- a/app/location/[id]/delete/page.tsx +++ b/app/location/[id]/delete/page.tsx @@ -1,15 +1,14 @@ -import { deleteBillById } from '@/app/lib/actions/billActions'; -import { deleteLocationById } from '@/app/lib/actions/locationActions'; -import { revalidatePath } from 'next/cache'; -import { notFound, redirect } from 'next/navigation'; +import { notFound } from 'next/navigation'; +import { fetchLocationById } from '@/app/lib/actions/locationActions'; +import { LocationDeleteForm } from '@/app/ui/LocationDeleteForm'; export default async function Page({ params:{ id } }: { params: { id:string } }) { - const locationID = id; - if(await deleteLocationById(locationID) === 0) { + const location = await fetchLocationById(id); + + if (!location) { return(notFound()); } - revalidatePath('/'); - redirect(`/`); + return (); } \ No newline at end of file diff --git a/app/location/[id]/edit/page.tsx b/app/location/[id]/edit/page.tsx index b991b72..b28cd30 100644 --- a/app/location/[id]/edit/page.tsx +++ b/app/location/[id]/edit/page.tsx @@ -9,5 +9,5 @@ export default async function Page({ params:{ id } }: { params: { id:string } }) if (!location) { return(notFound()); } - return (); + return (); } \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index 5568288..c325365 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -8,7 +8,7 @@ import { formatCurrency } from './lib/formatStrings'; import { fetchAvailableYears } from './lib/actions/monthActions'; import { YearMonth } from './lib/db-types'; import { formatYearMonth } from './lib/format'; -import { FC } from 'react'; +import { FC, Fragment } from 'react'; import Pagination from './ui/Pagination'; import { PageHeader } from './ui/PageHeader'; import { Main } from './ui/Main'; @@ -89,17 +89,17 @@ const Page:FC = async ({ searchParams }) => { monthlyExpense += location.bills.reduce((acc, bill) => acc + (bill.payedAmount ?? 0), 0); return ( - <> + { // show month title above the first LocationCard in the month isFirstLocationInMonth ? - : null + : null } - + { // show AddLocationButton as a last item in the first month isLastLocationOfLatestMonth && isLatestYear ? - : null + : null } { isLastLocationInMonth && monthlyExpense>0 ? @@ -111,7 +111,7 @@ const Page:FC = async ({ searchParams }) => { : null } - + ) }) } diff --git a/app/ui/BillDeleteForm.tsx b/app/ui/BillDeleteForm.tsx new file mode 100644 index 0000000..1427625 --- /dev/null +++ b/app/ui/BillDeleteForm.tsx @@ -0,0 +1,42 @@ +"use client"; + +import { FC } from "react"; +import { Bill, BillingLocation } from "../lib/db-types"; +import { deleteLocationById } from "../lib/actions/locationActions"; +import { useFormState } from "react-dom"; +import { Main } from "./Main"; +import { gotoHome } from "../lib/actions/navigationActions"; +import { deleteBillById } from "../lib/actions/billActions"; + +export interface BillDeleteFormProps { + bill: Bill, + location: BillingLocation +} + +export const BillDeleteForm:FC = ({ bill, location }) => +{ + const handleAction = deleteBillById.bind(null, location._id, bill._id, location.yearMonth.year); + const [ state, dispatch ] = useFormState(handleAction, null); + + const handleCancel = () => { + gotoHome(`/?year=${location.yearMonth.year}`); + }; + + return( +
+
+
+
+

+ Please confirm deletion of bill “{bill.name}” at “{location.name}”. +

+
+ + +
+
+
+
+
+ ) +} diff --git a/app/ui/BillEditForm.tsx b/app/ui/BillEditForm.tsx index e3ddf50..9d25dba 100644 --- a/app/ui/BillEditForm.tsx +++ b/app/ui/BillEditForm.tsx @@ -4,37 +4,38 @@ import { DocumentIcon, TrashIcon } from "@heroicons/react/24/outline"; import { Bill } from "../lib/db-types"; import React, { FC } from "react"; import { useFormState } from "react-dom"; -import { gotoHome, updateOrAddBill } from "../lib/actions/billActions"; +import { updateOrAddBill } from "../lib/actions/billActions"; import Link from "next/link"; +import { gotoHome } from "../lib/actions/navigationActions"; // Next.js does not encode an utf-8 file name correctly when sending a form with a file attachment // This is a workaround for that -const updateOrAddBillMiddleware = (locationId: string, billId:string|undefined, prevState:any, formData: FormData) => { +const updateOrAddBillMiddleware = (locationId: string, billId:string|undefined, billYear:number|undefined, prevState:any, formData: FormData) => { // URL encode the file name of the attachment so it is correctly sent to the server const billAttachment = formData.get('billAttachment') as File; formData.set('billAttachment', billAttachment, encodeURIComponent(billAttachment.name)); - return updateOrAddBill(locationId, billId, prevState, formData); + return updateOrAddBill(locationId, billId, billYear, prevState, formData); } export interface BillEditFormProps { locationID: string, - bill?: Bill + bill?: Bill, + billYear?: number } -export const BillEditForm:FC = ({ locationID, bill }) => { +export const BillEditForm:FC = ({ locationID, bill, billYear }) => { const { _id: billID, name, paid, attachment, notes, payedAmount } = bill ?? { _id:undefined, name:"", paid:false, notes:"" }; const initialState = { message: null, errors: {} }; - const handleAction = updateOrAddBillMiddleware.bind(null, locationID, billID); + const handleAction = updateOrAddBillMiddleware.bind(null, locationID, billID, billYear); const [ state, dispatch ] = useFormState(handleAction, initialState); const [ isPaid, setIsPaid ] = React.useState(paid); // redirect to the main page const handleCancel = () => { - console.log('handleCancel'); - gotoHome(); + gotoHome(billYear ? `/?year=${billYear}` : undefined); }; const billPaid_handleChange = (event: React.ChangeEvent) => { diff --git a/app/ui/LocationCard.tsx b/app/ui/LocationCard.tsx index 1fec078..68a207c 100644 --- a/app/ui/LocationCard.tsx +++ b/app/ui/LocationCard.tsx @@ -16,9 +16,9 @@ export const LocationCard:FC = ({location: { _id, name, yearM // sum all the billAmounts const monthlyExpense = bills.reduce((acc, bill) => acc + (bill.payedAmount ?? 0), 0); - + return( -
+
@@ -26,7 +26,7 @@ export const LocationCard:FC = ({location: { _id, name, yearM

{formatYearMonth(yearMonth)} {name}

{ - bills.map(bill => ) + bills.map(bill => ) } diff --git a/app/ui/LocationDeleteForm.tsx b/app/ui/LocationDeleteForm.tsx new file mode 100644 index 0000000..47737d9 --- /dev/null +++ b/app/ui/LocationDeleteForm.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { FC } from "react"; +import { BillingLocation } from "../lib/db-types"; +import { deleteLocationById } from "../lib/actions/locationActions"; +import { useFormState } from "react-dom"; +import { Main } from "./Main"; +import { gotoHome } from "../lib/actions/navigationActions"; + +export interface LocationDeleteFormProps { + /** location which should be deleted */ + location: BillingLocation +} + +export const LocationDeleteForm:FC = ({ location }) => +{ + const handleAction = deleteLocationById.bind(null, location._id, location.yearMonth); + const [ state, dispatch ] = useFormState(handleAction, null); + + const handleCancel = () => { + gotoHome(`/location/${location._id}/edit/`); + }; + + return( +
+
+
+
+

+ Please confirm deletion of location “{location.name}”. +

+
+ + +
+
+
+
+
+ ) +} diff --git a/app/ui/LocationEditForm.tsx b/app/ui/LocationEditForm.tsx index da81eb1..1f236cd 100644 --- a/app/ui/LocationEditForm.tsx +++ b/app/ui/LocationEditForm.tsx @@ -5,9 +5,9 @@ import { FC } from "react"; import { BillingLocation, YearMonth } from "../lib/db-types"; import { updateOrAddLocation } from "../lib/actions/locationActions"; import { useFormState } from "react-dom"; -import { gotoHome } from "../lib/actions/billActions"; import { Main } from "./Main"; import Link from "next/link"; +import { gotoHome } from "../lib/actions/navigationActions"; export interface LocationEditFormProps { /** location which should be edited */ @@ -25,7 +25,7 @@ export const LocationEditForm:FC = ({ location, yearMonth // redirect to the main page const handleCancel = () => { console.log('handleCancel'); - gotoHome(); + gotoHome(location ? `/?year=${location?.yearMonth?.year}` : undefined); }; return( diff --git a/app/ui/Pagination.tsx b/app/ui/Pagination.tsx index 66b0e06..8316aa2 100644 --- a/app/ui/Pagination.tsx +++ b/app/ui/Pagination.tsx @@ -83,7 +83,7 @@ export default function Pagination({ availableYears } : { availableYears: number return ( Date: Wed, 17 Jan 2024 15:52:38 +0100 Subject: [PATCH 3/8] BugFix: monthly expenses calculaton not taking into account unpaied bills --- app/page.tsx | 13 ++++--------- app/ui/MonthlyExpensesCard.tsx | 12 ++++++++++++ 2 files changed, 16 insertions(+), 9 deletions(-) create mode 100644 app/ui/MonthlyExpensesCard.tsx diff --git a/app/page.tsx b/app/page.tsx index c325365..79d745c 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -12,6 +12,7 @@ import { FC, Fragment } from 'react'; import Pagination from './ui/Pagination'; import { PageHeader } from './ui/PageHeader'; import { Main } from './ui/Main'; +import { MontlyExpensesCard } from './ui/MonthlyExpensesCard'; const getNextYearMonth = (yearMonth:YearMonth) => { const {year, month} = yearMonth; @@ -86,7 +87,7 @@ const Page:FC = async ({ searchParams }) => { monthlyExpense = 0; } - monthlyExpense += location.bills.reduce((acc, bill) => acc + (bill.payedAmount ?? 0), 0); + monthlyExpense += location.bills.reduce((acc, bill) => bill.paid ? acc + (bill.payedAmount ?? 0) : acc, 0); return ( @@ -102,14 +103,8 @@ const Page:FC = async ({ searchParams }) => { : null } { - isLastLocationInMonth && monthlyExpense>0 ? -
- -

- Total monthly expenditure: { formatCurrency(monthlyExpense) } -

-
-
: null + isLastLocationInMonth ? + : null }
) diff --git a/app/ui/MonthlyExpensesCard.tsx b/app/ui/MonthlyExpensesCard.tsx new file mode 100644 index 0000000..40db12f --- /dev/null +++ b/app/ui/MonthlyExpensesCard.tsx @@ -0,0 +1,12 @@ +import { FC } from "react"; +import { formatCurrency } from "../lib/formatStrings"; + +export const MontlyExpensesCard:FC<{monthlyExpense:number}> = ({ monthlyExpense }) => + monthlyExpense>0 ? +
+ +

+ Total monthly expenditure: { formatCurrency(monthlyExpense) } +

+
+
: null \ No newline at end of file From bdf9c10303cd427f27cac1f736fdcb0b35837866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?= Date: Wed, 17 Jan 2024 15:55:33 +0100 Subject: [PATCH 4/8] bills with attachment marked with green outline --- app/ui/BillBadge.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/ui/BillBadge.tsx b/app/ui/BillBadge.tsx index fb1f093..f0e3eda 100644 --- a/app/ui/BillBadge.tsx +++ b/app/ui/BillBadge.tsx @@ -7,7 +7,7 @@ export interface BillBadgeProps { bill: Bill }; -export const BillBadge:FC = ({ locationId, bill: { _id: billId, name, paid }}) => - +export const BillBadge:FC = ({ locationId, bill: { _id: billId, name, paid, attachment }}) => + {name} ; \ No newline at end of file From c7c7bf2924b4c42de763685be58c422ff79a9be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?= Date: Wed, 17 Jan 2024 16:06:54 +0100 Subject: [PATCH 5/8] BillEditForm: added location title @ top --- app/bill/[id]/add/not-found.tsx | 6 ++++++ app/bill/[id]/add/page.tsx | 9 ++++++++- app/bill/[id]/edit/page.tsx | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 app/bill/[id]/add/not-found.tsx diff --git a/app/bill/[id]/add/not-found.tsx b/app/bill/[id]/add/not-found.tsx new file mode 100644 index 0000000..d9d84b1 --- /dev/null +++ b/app/bill/[id]/add/not-found.tsx @@ -0,0 +1,6 @@ +import { NotFoundPage } from '@/app/ui/NotFoundPage'; + +const BillNotFound = () => +; + +export default BillNotFound; diff --git a/app/bill/[id]/add/page.tsx b/app/bill/[id]/add/page.tsx index fbb92da..bae6db8 100644 --- a/app/bill/[id]/add/page.tsx +++ b/app/bill/[id]/add/page.tsx @@ -1,12 +1,19 @@ import { fetchLocationById } from '@/app/lib/actions/locationActions'; import { BillEditForm } from '@/app/ui/BillEditForm'; import { Main } from '@/app/ui/Main'; +import { notFound } from 'next/navigation'; export default async function Page({ params:{ id:locationID } }: { params: { id:string } }) { + const location = await fetchLocationById(locationID); + + if (!location) { + return(notFound()); + } + return (
- +
); } \ No newline at end of file diff --git a/app/bill/[id]/edit/page.tsx b/app/bill/[id]/edit/page.tsx index 1d97ce4..eda8bea 100644 --- a/app/bill/[id]/edit/page.tsx +++ b/app/bill/[id]/edit/page.tsx @@ -9,12 +9,12 @@ export default async function Page({ params:{ id } }: { params: { id:string } }) const [location, bill] = await fetchBillById(locationID, billID) ?? []; - if (!bill) { + if (!bill || !location) { return(notFound()); } return (
- +
); } \ No newline at end of file From 9deec817b1d2b77902538927e210f0d849b2971a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?= Date: Wed, 17 Jan 2024 16:07:12 +0100 Subject: [PATCH 6/8] fix: bill edit form formatting was falling apart --- app/ui/BillEditForm.tsx | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/ui/BillEditForm.tsx b/app/ui/BillEditForm.tsx index 9d25dba..a7739ac 100644 --- a/app/ui/BillEditForm.tsx +++ b/app/ui/BillEditForm.tsx @@ -1,12 +1,13 @@ "use client"; import { DocumentIcon, TrashIcon } from "@heroicons/react/24/outline"; -import { Bill } from "../lib/db-types"; +import { Bill, BillingLocation } from "../lib/db-types"; 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 // This is a workaround for that @@ -18,15 +19,16 @@ const updateOrAddBillMiddleware = (locationId: string, billId:string|undefined, } export interface BillEditFormProps { - locationID: string, + location: BillingLocation, bill?: Bill, - billYear?: number } -export const BillEditForm:FC = ({ locationID, bill, billYear }) => { +export const BillEditForm:FC = ({ location, bill }) => { const { _id: billID, name, paid, attachment, notes, payedAmount } = bill ?? { _id:undefined, name:"", paid:false, notes:"" }; + const { yearMonth:{year: billYear}, _id: locationID } = location; + const initialState = { message: null, errors: {} }; const handleAction = updateOrAddBillMiddleware.bind(null, locationID, billID, billYear); const [ state, dispatch ] = useFormState(handleAction, initialState); @@ -45,6 +47,7 @@ export const BillEditForm:FC = ({ locationID, bill, billYear return(
+

{`${formatYearMonth(location.yearMonth)} ${location.name}`}

{ // don't show the delete button if we are adding a new bill @@ -67,13 +70,13 @@ export const BillEditForm:FC = ({ locationID, bill, billYear // attachment ? - + {decodeURIComponent(attachment.fileName)} : null } - +
{state.errors?.billAttachment && state.errors.billAttachment.map((error: string) => ( @@ -111,7 +114,7 @@ export const BillEditForm:FC = ({ locationID, bill, billYear } - +
{state.errors?.billNotes && state.errors.billNotes.map((error: string) => ( From 9b7e21b2683e29e0c622633f74e2d6880890c449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?= Date: Wed, 17 Jan 2024 16:07:19 +0100 Subject: [PATCH 7/8] upadted todo in readme --- README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/README.md b/README.md index 9aac028..d1d4c4b 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,4 @@ # ToDo -* zeleni outline dodati na račune koji imaju attachment čak i ako nisu plaćeni -* Bug: kod kopiranja računa u idući mjesec prenosi se i uplaćeni iznos -* Bug: kod sumiranja dodati provjeru je li račun plaćen - to je ispravka i za prethodni bug -* Forma za editiranje računa: - * dodati na vrh naziv lokacije - * forma se razvali (input za unos iznosa) kada je postavljen PDF * Popis lokacija: * omogućiti collapse za pojedine mjesece From 6b55597ddc98f0b2ff3357726dd057e042cc7bba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nikola=20Dere=C5=BEi=C4=87?= Date: Wed, 17 Jan 2024 16:08:17 +0100 Subject: [PATCH 8/8] updated image version --- 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 ab03916..8dbc123 100644 --- a/docker-compose-deploy.yml +++ b/docker-compose-deploy.yml @@ -9,7 +9,7 @@ networks: services: web-app: - image: utility-bills-tracker:1.2.0 + image: utility-bills-tracker:1.3.0 networks: - traefik-network - mongo-network