kreirane komponente

This commit is contained in:
2024-01-04 10:30:43 +01:00
parent e1a225b91b
commit b653ce40bc
11 changed files with 191 additions and 99 deletions

View File

@@ -4,9 +4,6 @@ This is the starter template for the Next.js App Router Course. It contains the
For more information, see the [course curriculum](https://nextjs.org/learn) on the Next.js Website.
## ToDo
Zadnje sam stao na koraku 12 (nisam ga dovršio): https://nextjs.org/learn/dashboard-app/mutating-data
# Authentication
Authentication consists of the following parts:
* `next-auth` boilerplate
@@ -18,3 +15,9 @@ Authentication consists of the following parts:
* `sidenav.tsx` = implements logout action - calls `signOut` from `auth.ts`
* `login-form.tsx` = implements login form
* `actions.ts` = handles login-form validation and submition - calls `signIn` from `auth.ts`
# Database structure
* month
* location
* bill
* attachment

12
app/lib/db-types.ts Normal file
View File

@@ -0,0 +1,12 @@
export type Location = {
id: number;
name: string;
};
export type Bill = {
id: number;
name: string;
paid: boolean;
amount?: number;
description?: string;
};

View File

@@ -11,6 +11,13 @@ import {
MapIcon,
MapPinIcon
} from '@heroicons/react/24/outline';
import { LocationCard } from './ui/LocationCard';
import { BillPaymentForm } from './ui/BillPaymentForm';
import { LocationEditForm } from './ui/LocationEditForm';
import { BillTemplateForm } from './ui/BillTemplateForm';
import { MonthTitle } from './ui/MonthTitle';
import { AddMonthButton } from './ui/AddMonthButton';
import { AddLocationButton } from './ui/AddLocationButton';
export default function Page() {
return (
@@ -18,108 +25,45 @@ export default function Page() {
<p>https://tailwindcss.com/docs/font-weight</p>
<p>https://heroicons.com/</p>
<span className='grid self-center' data-tip="Dodaj novi mjesec">
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-4xl" />
</span>
<AddMonthButton />
<div className="divider text-2xl">2023-05</div>
<MonthTitle month={new Date(2023, 4)} />
<div className="card card-compact card-bordered max-w-[36em] bg-base-100 shadow-s my-1">
<div className="card-body">
<Cog8ToothIcon className="h-[1em] w-[1em] absolute cursor-pointer top-3 right-3 text-2xl" />
<h2 className="card-title">2023-05 Budakova</h2>
<div className="card-actions">
<div className="badge badge-lg badge-success cursor-pointer">GSKG</div>
<div className="badge badge-lg badge-neutral cursor-pointer">HEP Elektra</div>
<div className="badge badge-lg badge-neutral cursor-pointer">Iskon</div>
<div className="badge badge-lg badge-neutral cursor-pointer">Plinara</div>
<div className="tooltip" data-tip="Dodaj novi tip računa">
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-2xl" />
</div>
</div>
</div>
</div>
<LocationCard
month={new Date(2023, 4)}
location={{id: 1, name: 'Budakova'}}
bills={[
{id: 1, name: 'GSKG', paid: true},
{id: 2, name: 'HEP Elektra', paid: false},
{id: 3, name: 'Iskon', paid: false},
{id: 4, name: 'Plinara', paid: false},
]} />
<div className="card card-compact card-bordered max-w-[36em] bg-base-100 shadow-s my-1">
<div className="card-body">
<Cog8ToothIcon className="h-[1em] w-[1em] absolute cursor-pointer top-3 right-3 text-2xl" />
<h2 className="card-title">2023-05 Kopernikova</h2>
<div className="card-actions">
<div className="badge badge-lg badge-success cursor-pointer">GSKG</div>
<div className="badge badge-lg badge-neutral cursor-pointer">HEP Elektra</div>
<div className="badge badge-lg badge-neutral cursor-pointer">Iskon</div>
<div className="badge badge-lg badge-neutral cursor-pointer">Plinara</div>
<div className="tooltip" data-tip="Dodaj novi tip računa">
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-2xl" />
</div>
</div>
</div>
</div>
<LocationCard
month={new Date(2023, 4)}
location={{id: 1, name: 'Kopernikova'}}
bills={[
{id: 1, name: 'Toplana', paid: true},
{id: 2, name: 'HEP Elektra', paid: true},
{id: 3, name: 'GSKG', paid: true},
]} />
<div className="card card-compact card-bordered max-w-[36em] bg-base-100 shadow-s my-1">
<div className="card-body">
<span className='grid self-center' data-tip="Dodaj novu lokaciju">
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-4xl" />
</span>
</div>
</div>
<AddLocationButton />
<div className="divider text-2xl">2023-06</div>
<MonthTitle month={new Date(2023, 5)} />
<div className="card card-compact card-bordered max-w-[36em] bg-base-100 shadow-s my-1">
<div className="card-body">
<Cog8ToothIcon className="h-[1em] w-[1em] absolute cursor-pointer top-3 right-3 text-2xl" />
<h2 className="card-title">2023-05 Šišićeva</h2>
<div className="card-actions">
<div className="badge badge-lg badge-success cursor-pointer">GSKG</div>
<div className="badge badge-lg badge-neutral cursor-pointer">HEP Elektra</div>
<div className="badge badge-lg badge-neutral cursor-pointer">Iskon</div>
<div className="badge badge-lg badge-neutral cursor-pointer">Plinara</div>
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-2xl" />
</div>
</div>
</div>
<div className="card card-compact card-bordered max-w-sm bg-base-100 shadow-s my-1">
<div className="card-body">
<form>
<Cog8ToothIcon className="h-[1em] w-[1em] absolute cursor-pointer top-4 right-4 text-2xl" />
<TrashIcon className="h-[1em] w-[1em] absolute cursor-pointer text-error bottom-5 right-4 text-2xl" />
<h1 className="text-2xl">GSKG</h1>
<p className="my-2">Pričuva, Voda, Smeće</p>
<a href="#document.pdf" className='text-center block max-w-[24em] text-nowrap truncate inline-block'>
<DocumentIcon className="h-[1em] w-[1em] text-2xl inline-block mr-1" />
2023-22-12 document GSKG račun za 2023.pdf
</a>
<input type="file" className="file-input file-input-bordered w-full max-w-sm file-input-xs my-2" />
<div className="form-control w-32 p-1">
<label className="cursor-pointer label p-0">
<span className="label-text">Plaćeno</span>
<input type="checkbox" className="toggle toggle-success" checked={false} />
</label>
</div>
<textarea className="textarea textarea-bordered my-2 w-full max-w-sm block" placeholder="Napomena"></textarea>
<button className="btn btn-primary">Spremi</button>
</form>
</div>
</div>
<div className="card card-compact card-bordered max-w-sm bg-base-100 shadow-s my-1">
<div className="card-body">
<form>
<input type="text" placeholder="Naziv računa" className="input input-bordered w-full" value="GSKG" />
<textarea className="textarea textarea-bordered my-1 w-full max-w-sm block" placeholder="Opis" value="Pričuva, Voda, Smeće"></textarea>
<button className="btn btn-primary">Spremi</button>
</form>
</div>
</div>
<div className="card card-compact card-bordered max-w-sm bg-base-100 shadow-s my-1">
<div className="card-body">
<form>
<input type="text" placeholder="Naziv lokacije" className="input input-bordered w-full" defaultValue="Budakova" />
<textarea className="textarea textarea-bordered my-1 w-full max-w-sm block" placeholder="Opis" value="Stan u Budakovoj"></textarea>
<button className="btn btn-primary">Spremi</button>
</form>
</div>
</div>
<LocationCard
month={new Date(2023, 5)}
location={{id: 1, name: 'Šišićeva'}}
bills={[
{id: 1, name: 'Toplana', paid: true},
{id: 2, name: 'HEP Elektra', paid: true},
{id: 3, name: 'GSKG', paid: true},
]} />
<BillPaymentForm bill={{id: 1, name: 'GSKG', description: 'Pričuva, Voda, Smeće', paid: true}} />
<LocationEditForm />
<BillTemplateForm />
</main>
);
}

View File

@@ -0,0 +1,14 @@
import { PlusCircleIcon } from "@heroicons/react/24/outline";
export interface AddLocationButtonProps {
}
export const AddLocationButton:React.FC<AddLocationButtonProps> = () =>
<div className="card card-compact card-bordered max-w-[36em] bg-base-100 shadow-s my-1">
<div className="card-body">
<span className='grid self-center' data-tip="Dodaj novu lokaciju">
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-4xl" />
</span>
</div>
</div>;

View File

@@ -0,0 +1,9 @@
import { PlusCircleIcon } from "@heroicons/react/24/outline";
export interface AddMonthButtonProps {
}
export const AddMonthButton:FC<AddMonthButtonProps> = () =>
<span className='grid self-center' data-tip="Dodaj novi mjesec">
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-4xl" />
</span>

10
app/ui/BillBadge.tsx Normal file
View File

@@ -0,0 +1,10 @@
import { FC } from "react"
import { Bill } from "../lib/db-types"
export interface BillBadgeProps {
bill: Bill,
// onClick:()=>void,
};
export const BillBadge:FC<BillBadgeProps> = ({bill: { name, paid }}) =>
<div className={`badge badge-lg badge-${paid?"success":"neutral"} cursor-pointer`}>{name}</div>

View File

@@ -0,0 +1,32 @@
import { Cog8ToothIcon, DocumentIcon, TrashIcon } from "@heroicons/react/24/outline";
import { Bill } from "../lib/db-types";
import { FC } from "react";
export interface BillPaymentFormProps {
bill: Bill
}
export const BillPaymentForm:FC<BillPaymentFormProps> = ({ bill: { name, description, paid } }) =>
<div className="card card-compact card-bordered max-w-sm bg-base-100 shadow-s my-1">
<div className="card-body">
<form>
<Cog8ToothIcon className="h-[1em] w-[1em] absolute cursor-pointer top-4 right-4 text-2xl" />
<TrashIcon className="h-[1em] w-[1em] absolute cursor-pointer text-error bottom-5 right-4 text-2xl" />
<h1 className="text-2xl">{name}</h1>
<p className="my-2">{description}</p>
<a href="#document.pdf" className='text-center block max-w-[24em] text-nowrap truncate inline-block'>
<DocumentIcon className="h-[1em] w-[1em] text-2xl inline-block mr-1" />
2023-22-12 document GSKG račun za 2023.pdf
</a>
<input type="file" className="file-input file-input-bordered w-full max-w-sm file-input-xs my-2" />
<div className="form-control w-32 p-1">
<label className="cursor-pointer label p-0">
<span className="label-text">Plaćeno</span>
<input type="checkbox" className="toggle toggle-success" checked={paid} />
</label>
</div>
<textarea className="textarea textarea-bordered my-2 w-full max-w-sm block" placeholder="Napomena"></textarea>
<button className="btn btn-primary">Spremi</button>
</form>
</div>
</div>

View File

@@ -0,0 +1,16 @@
import { FC } from "react";
export interface BillTemplateFormProps {
}
export const BillTemplateForm:FC<BillTemplateFormProps> = () =>
<div className="card card-compact card-bordered max-w-sm bg-base-100 shadow-s my-1">
<div className="card-body">
<form>
<input type="text" placeholder="Naziv računa" className="input input-bordered w-full" value="GSKG" />
<textarea className="textarea textarea-bordered my-1 w-full max-w-sm block" placeholder="Opis" value="Pričuva, Voda, Smeće"></textarea>
<button className="btn btn-primary">Spremi</button>
</form>
</div>
</div>;

28
app/ui/LocationCard.tsx Normal file
View File

@@ -0,0 +1,28 @@
'client only';
import { Cog8ToothIcon, PlusCircleIcon } from "@heroicons/react/24/outline";
import { FC } from "react";
import { BillBadge } from "./BillBadge";
import { Bill, Location } from "../lib/db-types";
export interface LocationCardProps {
month: Date,
location: Location,
bills: Bill[]
}
export const LocationCard:FC<LocationCardProps> = ({month, location: { name }, bills}) =>
<div className="card card-compact card-bordered max-w-[36em] bg-base-100 shadow-s my-1">
<div className="card-body">
<Cog8ToothIcon className="h-[1em] w-[1em] absolute cursor-pointer top-3 right-3 text-2xl" />
<h2 className="card-title">{month.getFullYear()}-{month.getMonth()+1} {name}</h2>
<div className="card-actions">
{
bills.map(bill => <BillBadge key={bill.id} bill={bill} />)
}
<div className="tooltip" data-tip="Dodaj novi tip računa">
<PlusCircleIcon className="h-[1em] w-[1em] cursor-pointer text-2xl" />
</div>
</div>
</div>
</div>;

View File

@@ -0,0 +1,16 @@
import { FC } from "react";
export interface LocationEditFormProps {
}
export const LocationEditForm:FC<LocationEditFormProps> = () =>
<div className="card card-compact card-bordered max-w-sm bg-base-100 shadow-s my-1">
<div className="card-body">
<form>
<input type="text" placeholder="Naziv lokacije" className="input input-bordered w-full" defaultValue="Budakova" />
<textarea className="textarea textarea-bordered my-1 w-full max-w-sm block" placeholder="Opis" value="Stan u Budakovoj"></textarea>
<button className="btn btn-primary">Spremi</button>
</form>
</div>
</div>

8
app/ui/MonthTitle.tsx Normal file
View File

@@ -0,0 +1,8 @@
import { FC } from "react";
export interface MonthTitleProps {
month: Date;
}
export const MonthTitle:FC<MonthTitleProps> = ({month}) =>
<div className="divider text-2xl">{`${month.getFullYear()}-${month.getMonth()+1}`}</div>