kreirane komponente
This commit is contained in:
@@ -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
12
app/lib/db-types.ts
Normal 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;
|
||||
};
|
||||
136
app/page.tsx
136
app/page.tsx
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
14
app/ui/AddLocationButton.tsx
Normal file
14
app/ui/AddLocationButton.tsx
Normal 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>;
|
||||
9
app/ui/AddMonthButton.tsx
Normal file
9
app/ui/AddMonthButton.tsx
Normal 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
10
app/ui/BillBadge.tsx
Normal 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>
|
||||
32
app/ui/BillPaymentForm.tsx
Normal file
32
app/ui/BillPaymentForm.tsx
Normal 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>
|
||||
16
app/ui/BillTemplateForm.tsx
Normal file
16
app/ui/BillTemplateForm.tsx
Normal 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
28
app/ui/LocationCard.tsx
Normal 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>;
|
||||
16
app/ui/LocationEditForm.tsx
Normal file
16
app/ui/LocationEditForm.tsx
Normal 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
8
app/ui/MonthTitle.tsx
Normal 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>
|
||||
Reference in New Issue
Block a user