diff --git a/app/lib/db-types.ts b/app/lib/db-types.ts index c6ebaca..6d83665 100644 --- a/app/lib/db-types.ts +++ b/app/lib/db-types.ts @@ -1,12 +1,16 @@ -export type Location = { - id: number; +import { ObjectId } from "mongodb"; + +export interface Location { + id: ObjectId; name: string; + bills: Bill[]; + /** the value is encoded as yyyymm (i.e. 202301) */ + yearMonth: number; }; -export type Bill = { - id: number; +export interface Bill { + id: ObjectId; name: string; paid: boolean; - amount?: number; - description?: string; + document?: string|null; }; diff --git a/app/lib/format.ts b/app/lib/format.ts new file mode 100644 index 0000000..4be1d36 --- /dev/null +++ b/app/lib/format.ts @@ -0,0 +1,6 @@ + +export const formatYearMonth = (yearMonth: number): string => { + const year = Math.floor(yearMonth / 100); + const month = yearMonth % 100; + return `${year}-${month<10?"0":""}${month}`; +} diff --git a/app/lib/global.d.ts b/app/lib/global.d.ts new file mode 100644 index 0000000..52c4786 --- /dev/null +++ b/app/lib/global.d.ts @@ -0,0 +1,8 @@ +import { MongoClient } from "mongodb"; + +declare global { + namespace globalThis { + /** global Mongo Client used in development */ + var _mongoClientPromise: Promise + } +} \ No newline at end of file diff --git a/app/lib/mongodb.ts b/app/lib/mongodb.ts new file mode 100644 index 0000000..1bcc3cc --- /dev/null +++ b/app/lib/mongodb.ts @@ -0,0 +1,34 @@ +import { MongoClient } from 'mongodb' + +if (!process.env.MONGODB_URI) { + throw new Error('Invalid environment variable: "MONGODB_URI"') +} + +const uri = process.env.MONGODB_URI +const options = { } + +let client +let clientPromise: Promise + + +if (!process.env.MONGODB_URI) { + throw new Error('Please add your Mongo URI to .env.local') +} + +if (process.env.NODE_ENV === 'development') { + // In development mode, use a global variable so that the value + // is preserved across module reloads caused by HMR (Hot Module Replacement). + if (!global._mongoClientPromise) { + client = new MongoClient(uri, options) + global._mongoClientPromise = client.connect() + } + clientPromise = global._mongoClientPromise +} else { + // In production mode, it's best to not use a global variable. + client = new MongoClient(uri, options) + clientPromise = client.connect() +} + +// Export a module-scoped MongoClient promise. By doing this in a +// separate module, the client can be shared across functions. +export default clientPromise \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index 39ac597..22e9c0d 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,67 +1,46 @@ -import Link from 'next/link'; -import styles from '@/app/ui/home.module.css'; -import { lusitana } from './ui/fonts'; -import Image from 'next/image'; - -import { - Cog8ToothIcon, - TrashIcon, - PlusCircleIcon, - DocumentIcon, - MapIcon, - MapPinIcon -} from '@heroicons/react/24/outline'; import { LocationCard } from './ui/LocationCard'; -import { BillEditForm } from './ui/BillEditForm'; -import { LocationEditForm } from './ui/LocationEditForm'; 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'; -export default function Page() { - return ( +export const Page = async () => { + + const client = await clientPromise; + const db = client.db("rezije"); + + const locations = await db.collection("lokacije") + .find({}) + .sort({ yearMonth: -1 }) // sort by yearMonth descending + .limit(20) + .toArray(); + + return (

https://tailwindcss.com/docs/font-weight

https://heroicons.com/

- - - - - - - - - - - - - - - + { + locations.map((location, ix, array) => { + + return ( + <> + { + location.yearMonth !== array[0].yearMonth && location.yearMonth !== array[ix-1].yearMonth ? : null + } + { + // show month title if it's the first location in the month + ix === 0 || location.yearMonth !== array[ix-1].yearMonth ? : null + } + + + ) + }) + }
); } + +export default Page; \ No newline at end of file diff --git a/app/ui/BillBadge.tsx b/app/ui/BillBadge.tsx index c45aa72..dc40be7 100644 --- a/app/ui/BillBadge.tsx +++ b/app/ui/BillBadge.tsx @@ -2,9 +2,8 @@ import { FC } from "react" import { Bill } from "../lib/db-types" export interface BillBadgeProps { - bill: Bill, - // onClick:()=>void, + bill: Bill }; export const BillBadge:FC = ({bill: { name, paid }}) => -
{name}
\ No newline at end of file +
{name}
\ No newline at end of file diff --git a/app/ui/LocationCard.tsx b/app/ui/LocationCard.tsx index a51d7bd..35097d5 100644 --- a/app/ui/LocationCard.tsx +++ b/app/ui/LocationCard.tsx @@ -4,21 +4,20 @@ import { Cog8ToothIcon, PlusCircleIcon } from "@heroicons/react/24/outline"; import { FC } from "react"; import { BillBadge } from "./BillBadge"; import { Bill, Location } from "../lib/db-types"; +import { formatYearMonth } from "../lib/format"; export interface LocationCardProps { - month: Date, - location: Location, - bills: Bill[] + location: Location } -export const LocationCard:FC = ({month, location: { name }, bills}) => +export const LocationCard:FC = ({location: { name, yearMonth, bills }}) =>
-

{month.getFullYear()}-{month.getMonth()+1} {name}

+

{formatYearMonth(yearMonth)} {name}

{ - bills.map(bill => ) + bills.map(bill => ) }
diff --git a/app/ui/MonthTitle.tsx b/app/ui/MonthTitle.tsx index c657302..babe101 100644 --- a/app/ui/MonthTitle.tsx +++ b/app/ui/MonthTitle.tsx @@ -1,8 +1,9 @@ import { FC } from "react"; +import { formatYearMonth } from "../lib/format"; export interface MonthTitleProps { - month: Date; + yearMonth: number; } -export const MonthTitle:FC = ({month}) => -
{`${month.getFullYear()}-${month.getMonth()+1}`}
\ No newline at end of file +export const MonthTitle:FC = ({yearMonth}) => +
{`${formatYearMonth(yearMonth)}`}
\ No newline at end of file