Loading src/components/ExpanseHistory/ExpanseHistory.tsx +10 −8 Original line number Diff line number Diff line import { useReportPage } from "@/hooks"; import InputSearchField from "../Input/InputSearchField"; import { ExpensesDataType } from "@/models/ExpensesDataType"; type ExpanseHistoryProps = { expensesData: ExpensesDataType[]; filter: string; setFilter: (value: string) => void; }; export const ExpanseHistory = ({ expensesData }: ExpanseHistoryProps) => { const { filter, setFilter, filteredExpenses } = useReportPage({ export const ExpanseHistory: React.FC<ExpanseHistoryProps> = ({ expensesData, }); filter, setFilter, }) => { return ( <> <h3 className="font-bold text-xl text-center lg:text-left mb-5"> <h3 className="font-bold text-xl text-center lg:text-left my-10"> História výdavkov </h3> <InputSearchField Loading @@ -21,8 +23,8 @@ export const ExpanseHistory = ({ expensesData }: ExpanseHistoryProps) => { placeholder="Vyhľadať výdavky..." /> <div className="mt-5 sm:grid grid-cols-2"> {filteredExpenses.length > 0 ? ( filteredExpenses.map((expense, index) => ( {expensesData.length > 0 ? ( expensesData.map((expense, index) => ( <div key={index} className="p-3 border-b"> <p className="text-sm"> {expense.date} - {expense.category} Loading src/components/HouseholdPage/AddExpense.tsx +18 −17 Original line number Diff line number Diff line Loading @@ -3,32 +3,33 @@ import Modal from "@/components/Modal/Modal"; import CustomButton from "@/components/Button/CustomButton"; import InputField from "@/components/Input/InputField"; import { Form } from "@/components/ui/form"; import { useHouseholdPage } from "@/hooks"; import { ExpensesDataType } from "@/models/ExpensesDataType"; import { Plus } from "lucide-react"; import { useAddExpense } from "@/hooks/useAddExpense"; type AddExpenseProps = { buttomClassName: string; onAddExpense: (expense: ExpensesDataType) => void; buttonClassName?: string; }; const AddExpense: React.FC<AddExpenseProps> = ({ buttomClassName }) => { const { onAddExpenseSubmit, expenseForm, createModalOpen, setCreateModalOpen, } = useHouseholdPage(); const AddExpense: React.FC<AddExpenseProps> = ({ onAddExpense, buttonClassName, }) => { const { modalOpen, setModalOpen, expenseForm, onSubmit } = useAddExpense({ onAddExpense, }); return ( <Modal dialogDescription="Pridať nový výdavok" open={createModalOpen} onOpenChange={setCreateModalOpen} open={modalOpen} onOpenChange={setModalOpen} trigger={ <CustomButton onClick={() => setCreateModalOpen(true)} className={buttomClassName} onClick={() => setModalOpen(true)} className={buttonClassName} tooltip="Pridať výdavok" leftIcon={<Plus className="w-4 h-4 mr-2 sm:w-6 sm:h-6" />} leftIcon={<Plus className="w-4 h-4 sm:w-6 sm:h-6 mr-2" />} > Pridať výdavok </CustomButton> Loading @@ -36,7 +37,7 @@ const AddExpense: React.FC<AddExpenseProps> = ({ buttomClassName }) => { > <Form {...expenseForm}> <form onSubmit={expenseForm.handleSubmit(onAddExpenseSubmit)} onSubmit={expenseForm.handleSubmit(onSubmit)} className="flex flex-col gap-5 mt-5" > <InputField Loading Loading @@ -64,7 +65,7 @@ const AddExpense: React.FC<AddExpenseProps> = ({ buttomClassName }) => { label="Popis" placeholder="Zara nohavice" /> <CustomButton>Pridať výdavok</CustomButton> <CustomButton>Potvrdiť pridanie výdavku</CustomButton> </form> </Form> </Modal> Loading src/hooks/useAddExpense.tsx 0 → 100644 +33 −0 Original line number Diff line number Diff line import { ExpensesDataType } from "@/models/ExpensesDataType"; import { AddExpenseSchema } from "@/validationSchemas"; import { zodResolver } from "@hookform/resolvers/zod"; import { useState } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; type AddExpenseProps = { onAddExpense: (expense: ExpensesDataType) => void; }; export const useAddExpense = ({ onAddExpense }: AddExpenseProps) => { const [modalOpen, setModalOpen] = useState(false); type AddExpenseFormData = z.infer<typeof AddExpenseSchema>; const expenseForm = useForm<ExpensesDataType>({ resolver: zodResolver(AddExpenseSchema), defaultValues: { date: "", category: "", amount: 0, description: "", }, }); const onSubmit = (data: AddExpenseFormData) => { onAddExpense(data); setModalOpen(false); expenseForm.reset(); }; return { modalOpen, setModalOpen, expenseForm, onSubmit }; }; src/hooks/useReportPage.tsx +20 −8 Original line number Diff line number Diff line import { monthlySpendingData } from "@/mockData/reportData"; import { useState, useEffect } from "react"; import { ExpensesDataType } from "@/models/ExpensesDataType"; import { useEffect, useState } from "react"; type ReportPageProps = { expensesData: ExpensesDataType[]; initialExpensesData: ExpensesDataType[]; }; export const useReportPage = ({ expensesData }: ReportPageProps) => { export const useReportPage = ({ initialExpensesData }: ReportPageProps) => { const [filter, setFilter] = useState(""); const [expensesData, setExpensesData] = useState(initialExpensesData); const [filteredExpenses, setFilteredExpenses] = useState(expensesData); const currentMonth = monthlySpendingData.find((data) => data.month === "August")?.amount || 0; const currentMonth = expensesData.reduce( (total, expense) => total + expense.amount, 0 ); useEffect(() => { const handler = setTimeout(() => { Loading @@ -24,7 +26,17 @@ export const useReportPage = ({ expensesData }: ReportPageProps) => { return () => { clearTimeout(handler); }; }, [filter]); }, [filter, expensesData]); const addExpense = (newExpense: ExpensesDataType) => { setExpensesData((prevExpenses) => [newExpense, ...prevExpenses]); }; return { filter, setFilter, filteredExpenses, currentMonth }; return { filter, setFilter, filteredExpenses, currentMonth, addExpense, }; }; src/pages/HouseholdPage.tsx +12 −5 Original line number Diff line number Diff line import React from "react"; import { ExpanseBar } from "@/components/ExpanseBar/ExpanseBar"; import { ExpanseHistory } from "@/components/ExpanseHistory/ExpanseHistory"; import MainContainer from "@/components/Layout/MainContainer"; Loading @@ -7,7 +8,7 @@ import { weeklyTotalHousehold, yearlyTotalHouseHold, } from "@/mockData/expenseBarHouseholdData"; import { expensesData } from "@/mockData/reportData"; import { expensesData as initialExpensesData } from "@/mockData/reportData"; import { Accordion, AccordionContent, Loading @@ -17,7 +18,9 @@ import { import AddExpense from "@/components/HouseholdPage/AddExpense"; const HouseholdPage: React.FC = () => { const { currentMonth } = useReportPage({ expensesData }); const { currentMonth, filteredExpenses, addExpense, filter, setFilter } = useReportPage({ initialExpensesData }); return ( <MainContainer> <ExpanseBar Loading @@ -26,12 +29,12 @@ const HouseholdPage: React.FC = () => { yearlyTotal={yearlyTotalHouseHold} currentMonth={currentMonth} /> <div className="flex items-center justify-between"> <div className="flex items-center justify-between mb-5"> <h3 className="text-lg my-10"> Domácnosť: <span className="text-2xl font-bold">Schodová 5</span> </h3> <AddExpense buttomClassName="p-6 sm:p-10" /> <AddExpense onAddExpense={addExpense} buttonClassName="p-6 sm:p-10" /> </div> <Accordion type="single" collapsible className="mb-15"> <AccordionItem value="household-members"> Loading @@ -43,7 +46,11 @@ const HouseholdPage: React.FC = () => { </AccordionContent> </AccordionItem> </Accordion> <ExpanseHistory expensesData={expensesData} /> <ExpanseHistory expensesData={filteredExpenses} filter={filter} setFilter={setFilter} /> </MainContainer> ); }; Loading Loading
src/components/ExpanseHistory/ExpanseHistory.tsx +10 −8 Original line number Diff line number Diff line import { useReportPage } from "@/hooks"; import InputSearchField from "../Input/InputSearchField"; import { ExpensesDataType } from "@/models/ExpensesDataType"; type ExpanseHistoryProps = { expensesData: ExpensesDataType[]; filter: string; setFilter: (value: string) => void; }; export const ExpanseHistory = ({ expensesData }: ExpanseHistoryProps) => { const { filter, setFilter, filteredExpenses } = useReportPage({ export const ExpanseHistory: React.FC<ExpanseHistoryProps> = ({ expensesData, }); filter, setFilter, }) => { return ( <> <h3 className="font-bold text-xl text-center lg:text-left mb-5"> <h3 className="font-bold text-xl text-center lg:text-left my-10"> História výdavkov </h3> <InputSearchField Loading @@ -21,8 +23,8 @@ export const ExpanseHistory = ({ expensesData }: ExpanseHistoryProps) => { placeholder="Vyhľadať výdavky..." /> <div className="mt-5 sm:grid grid-cols-2"> {filteredExpenses.length > 0 ? ( filteredExpenses.map((expense, index) => ( {expensesData.length > 0 ? ( expensesData.map((expense, index) => ( <div key={index} className="p-3 border-b"> <p className="text-sm"> {expense.date} - {expense.category} Loading
src/components/HouseholdPage/AddExpense.tsx +18 −17 Original line number Diff line number Diff line Loading @@ -3,32 +3,33 @@ import Modal from "@/components/Modal/Modal"; import CustomButton from "@/components/Button/CustomButton"; import InputField from "@/components/Input/InputField"; import { Form } from "@/components/ui/form"; import { useHouseholdPage } from "@/hooks"; import { ExpensesDataType } from "@/models/ExpensesDataType"; import { Plus } from "lucide-react"; import { useAddExpense } from "@/hooks/useAddExpense"; type AddExpenseProps = { buttomClassName: string; onAddExpense: (expense: ExpensesDataType) => void; buttonClassName?: string; }; const AddExpense: React.FC<AddExpenseProps> = ({ buttomClassName }) => { const { onAddExpenseSubmit, expenseForm, createModalOpen, setCreateModalOpen, } = useHouseholdPage(); const AddExpense: React.FC<AddExpenseProps> = ({ onAddExpense, buttonClassName, }) => { const { modalOpen, setModalOpen, expenseForm, onSubmit } = useAddExpense({ onAddExpense, }); return ( <Modal dialogDescription="Pridať nový výdavok" open={createModalOpen} onOpenChange={setCreateModalOpen} open={modalOpen} onOpenChange={setModalOpen} trigger={ <CustomButton onClick={() => setCreateModalOpen(true)} className={buttomClassName} onClick={() => setModalOpen(true)} className={buttonClassName} tooltip="Pridať výdavok" leftIcon={<Plus className="w-4 h-4 mr-2 sm:w-6 sm:h-6" />} leftIcon={<Plus className="w-4 h-4 sm:w-6 sm:h-6 mr-2" />} > Pridať výdavok </CustomButton> Loading @@ -36,7 +37,7 @@ const AddExpense: React.FC<AddExpenseProps> = ({ buttomClassName }) => { > <Form {...expenseForm}> <form onSubmit={expenseForm.handleSubmit(onAddExpenseSubmit)} onSubmit={expenseForm.handleSubmit(onSubmit)} className="flex flex-col gap-5 mt-5" > <InputField Loading Loading @@ -64,7 +65,7 @@ const AddExpense: React.FC<AddExpenseProps> = ({ buttomClassName }) => { label="Popis" placeholder="Zara nohavice" /> <CustomButton>Pridať výdavok</CustomButton> <CustomButton>Potvrdiť pridanie výdavku</CustomButton> </form> </Form> </Modal> Loading
src/hooks/useAddExpense.tsx 0 → 100644 +33 −0 Original line number Diff line number Diff line import { ExpensesDataType } from "@/models/ExpensesDataType"; import { AddExpenseSchema } from "@/validationSchemas"; import { zodResolver } from "@hookform/resolvers/zod"; import { useState } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; type AddExpenseProps = { onAddExpense: (expense: ExpensesDataType) => void; }; export const useAddExpense = ({ onAddExpense }: AddExpenseProps) => { const [modalOpen, setModalOpen] = useState(false); type AddExpenseFormData = z.infer<typeof AddExpenseSchema>; const expenseForm = useForm<ExpensesDataType>({ resolver: zodResolver(AddExpenseSchema), defaultValues: { date: "", category: "", amount: 0, description: "", }, }); const onSubmit = (data: AddExpenseFormData) => { onAddExpense(data); setModalOpen(false); expenseForm.reset(); }; return { modalOpen, setModalOpen, expenseForm, onSubmit }; };
src/hooks/useReportPage.tsx +20 −8 Original line number Diff line number Diff line import { monthlySpendingData } from "@/mockData/reportData"; import { useState, useEffect } from "react"; import { ExpensesDataType } from "@/models/ExpensesDataType"; import { useEffect, useState } from "react"; type ReportPageProps = { expensesData: ExpensesDataType[]; initialExpensesData: ExpensesDataType[]; }; export const useReportPage = ({ expensesData }: ReportPageProps) => { export const useReportPage = ({ initialExpensesData }: ReportPageProps) => { const [filter, setFilter] = useState(""); const [expensesData, setExpensesData] = useState(initialExpensesData); const [filteredExpenses, setFilteredExpenses] = useState(expensesData); const currentMonth = monthlySpendingData.find((data) => data.month === "August")?.amount || 0; const currentMonth = expensesData.reduce( (total, expense) => total + expense.amount, 0 ); useEffect(() => { const handler = setTimeout(() => { Loading @@ -24,7 +26,17 @@ export const useReportPage = ({ expensesData }: ReportPageProps) => { return () => { clearTimeout(handler); }; }, [filter]); }, [filter, expensesData]); const addExpense = (newExpense: ExpensesDataType) => { setExpensesData((prevExpenses) => [newExpense, ...prevExpenses]); }; return { filter, setFilter, filteredExpenses, currentMonth }; return { filter, setFilter, filteredExpenses, currentMonth, addExpense, }; };
src/pages/HouseholdPage.tsx +12 −5 Original line number Diff line number Diff line import React from "react"; import { ExpanseBar } from "@/components/ExpanseBar/ExpanseBar"; import { ExpanseHistory } from "@/components/ExpanseHistory/ExpanseHistory"; import MainContainer from "@/components/Layout/MainContainer"; Loading @@ -7,7 +8,7 @@ import { weeklyTotalHousehold, yearlyTotalHouseHold, } from "@/mockData/expenseBarHouseholdData"; import { expensesData } from "@/mockData/reportData"; import { expensesData as initialExpensesData } from "@/mockData/reportData"; import { Accordion, AccordionContent, Loading @@ -17,7 +18,9 @@ import { import AddExpense from "@/components/HouseholdPage/AddExpense"; const HouseholdPage: React.FC = () => { const { currentMonth } = useReportPage({ expensesData }); const { currentMonth, filteredExpenses, addExpense, filter, setFilter } = useReportPage({ initialExpensesData }); return ( <MainContainer> <ExpanseBar Loading @@ -26,12 +29,12 @@ const HouseholdPage: React.FC = () => { yearlyTotal={yearlyTotalHouseHold} currentMonth={currentMonth} /> <div className="flex items-center justify-between"> <div className="flex items-center justify-between mb-5"> <h3 className="text-lg my-10"> Domácnosť: <span className="text-2xl font-bold">Schodová 5</span> </h3> <AddExpense buttomClassName="p-6 sm:p-10" /> <AddExpense onAddExpense={addExpense} buttonClassName="p-6 sm:p-10" /> </div> <Accordion type="single" collapsible className="mb-15"> <AccordionItem value="household-members"> Loading @@ -43,7 +46,11 @@ const HouseholdPage: React.FC = () => { </AccordionContent> </AccordionItem> </Accordion> <ExpanseHistory expensesData={expensesData} /> <ExpanseHistory expensesData={filteredExpenses} filter={filter} setFilter={setFilter} /> </MainContainer> ); }; Loading