diff --git a/app/lib/yearMonthActions.ts b/app/lib/yearMonthActions.ts new file mode 100644 index 0000000..335012d --- /dev/null +++ b/app/lib/yearMonthActions.ts @@ -0,0 +1,103 @@ +'use server'; + +import { revalidatePath } from 'next/cache'; +import { redirect } from 'next/navigation'; +import clientPromise from './mongodb'; +import { ObjectId } from 'mongodb'; +import { BillingLocation } from './db-types'; + +/** + * Server-side action which adds a new month to the database + * @param locationId location of the bill + * @param billId ID of the bill + * @param prevState previous state of the form + * @param formData form data + * @returns + */ +export async function addYearMonth(yearMonthString: string) { + + // update the bill in the mongodb + const client = await clientPromise; + const db = client.db("rezije"); + const yearMonth = parseInt(yearMonthString); + + const prevYearMonth = (yearMonth - 1) % 100 === 0 ? yearMonth - 89 : yearMonth - 1; + + // find all locations for the previous month + const prevMonthLocations = await db.collection("lokacije").find({ yearMonth: prevYearMonth }); + + const newMonthLocationsCursor = prevMonthLocations.map((prevLocation) => { + return({ + // copy all the properties from the previous location + ...prevLocation, + // assign a new ID + _id: (new ObjectId()).toHexString(), + yearMonth, + // copy bill array, but set all bills to unpaid and remove attachments and notes + bills: prevLocation.bills.map((bill) => { + return { + ...bill, + paid: false, + attachment: null, + notes: null, + } + }) + } as BillingLocation); + }); + + const newMonthLocations = await newMonthLocationsCursor.toArray() + await db.collection("lokacije").insertMany(newMonthLocations); + + // clear the cache for the path + revalidatePath('/'); + // go to the bill list + redirect('/'); +} + +export async function gotoHome() { + redirect('/'); +} + +export const fetchBillById = async (locationID:string, billID:string) => { + const client = await clientPromise; + const db = client.db("rezije"); + + // find a location with the given locationID + const billLocation = await db.collection("lokacije").findOne({ _id: locationID }) + + if(!billLocation) { + console.log(`Location ${locationID} not found`); + return(null); + } + + // find a bill with the given billID + const bill = billLocation?.bills.find(({ _id }) => _id.toString() === billID); + + if(!bill) { + console.log('Bill not found'); + return(null); + } + + return(bill); +} + +export const deleteBillById = async (locationID:string, billID:string) => { + const client = await clientPromise; + const db = client.db("rezije"); + + // find a location with the given locationID + const post = await db.collection("lokacije").updateOne( + { + _id: locationID // find a location with the given locationID + }, + { + // remove the bill with the given billID + $pull: { + bills: { + _id: billID + } + } + }); + + return(post.modifiedCount); +} \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index dad454b..83f5481 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -3,14 +3,18 @@ import { MonthTitle } from './ui/MonthTitle'; import { AddMonthButton } from './ui/AddMonthButton'; import { AddLocationButton } from './ui/AddLocationButton'; import clientPromise from './lib/mongodb'; -import { Location } from './lib/db-types'; +import { BillingLocation } from './lib/db-types'; + +const calcNextYearMonth = (yearMonth: number) => { + return(yearMonth % 100 === 12 ? yearMonth + 89 : yearMonth + 1); +} export const Page = async () => { const client = await clientPromise; const db = client.db("rezije"); - const locations = await db.collection("lokacije") + const locations = await db.collection("lokacije") .find({}) .sort({ yearMonth: -1 }) // sort by yearMonth descending .limit(20) @@ -18,7 +22,7 @@ export const Page = async () => { return (
- + { locations.map((location, ix, array) => { diff --git a/app/ui/AddMonthButton.tsx b/app/ui/AddMonthButton.tsx index 8a14523..cee605f 100644 --- a/app/ui/AddMonthButton.tsx +++ b/app/ui/AddMonthButton.tsx @@ -1,9 +1,11 @@ import { PlusCircleIcon } from "@heroicons/react/24/outline"; +import React from "react"; export interface AddMonthButtonProps { + yearMonth: number; } -export const AddMonthButton:FC = () => - +export const AddMonthButton:React.FC = ({ yearMonth }) => + - + diff --git a/app/year-month/[id]/add/page.tsx b/app/year-month/[id]/add/page.tsx new file mode 100644 index 0000000..b5a43ec --- /dev/null +++ b/app/year-month/[id]/add/page.tsx @@ -0,0 +1,11 @@ +import { addYearMonth } from '@/app/lib/yearMonthActions'; +import { revalidatePath } from 'next/cache'; +import { redirect } from 'next/navigation'; + +export default async function Page({ params:{ id } }: { params: { id:string } }) { + + await addYearMonth(id); + + revalidatePath('/'); + redirect(`/`); +} \ No newline at end of file