diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs index d6c9537..81b15e1 100644 --- a/frontend/.eslintrc.cjs +++ b/frontend/.eslintrc.cjs @@ -9,10 +9,5 @@ module.exports = { ignorePatterns: ['dist', '.eslintrc.cjs'], parser: '@typescript-eslint/parser', plugins: ['react-refresh'], - rules: { - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true }, - ], - }, + rules: {}, } diff --git a/frontend/package.json b/frontend/package.json index f7a5d08..907f85d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,6 +12,7 @@ "dependencies": { "@headlessui/react": "^1.7.19", "@hookform/resolvers": "^3.3.4", + "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-icons": "^1.3.0", "@tanstack/react-query": "^5.29.0", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 43f341a..52de582 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -21,7 +21,7 @@ export function App() { - + ); } diff --git a/frontend/src/view/components/DropdownMenu.tsx b/frontend/src/view/components/DropdownMenu.tsx index 19623ca..7c897d4 100644 --- a/frontend/src/view/components/DropdownMenu.tsx +++ b/frontend/src/view/components/DropdownMenu.tsx @@ -11,7 +11,7 @@ export function DropdownMenuRoot({ children }: { children: React.ReactNode }) { export function DropdownMenuTrigger({ children }: { children: React.ReactNode }) { return ( - + {children} ); @@ -27,7 +27,9 @@ export function DropdownMenuContent({ children, className }: DropdownMenuContent diff --git a/frontend/src/view/components/Modal.tsx b/frontend/src/view/components/Modal.tsx new file mode 100644 index 0000000..5bb8ae4 --- /dev/null +++ b/frontend/src/view/components/Modal.tsx @@ -0,0 +1,57 @@ +import * as Dialog from '@radix-ui/react-dialog'; +import { cn } from '../../app/utils/cn'; +import { Cross2Icon } from '@radix-ui/react-icons'; + +interface ModalProps { + open: boolean; + children: React.ReactNode; + title: string; + rightAction?: React.ReactNode; + onClose?(): void; +} + +export function Modal({ open, title, children, rightAction, onClose }: ModalProps) { + return ( + + + + + +
+ + + + + {title} + + +
+ {rightAction} +
+ +
+ +
+ {children} +
+
+
+
+ ); +} + diff --git a/frontend/src/view/pages/Dashboard/components/Fab/index.tsx b/frontend/src/view/pages/Dashboard/components/Fab/index.tsx index 37366d7..86d3d14 100644 --- a/frontend/src/view/pages/Dashboard/components/Fab/index.tsx +++ b/frontend/src/view/pages/Dashboard/components/Fab/index.tsx @@ -1,5 +1,7 @@ import { PlusIcon } from "@radix-ui/react-icons"; import { DropdownMenu, DropdownMenuItem } from "../../../../components/DropdownMenu"; +import { CategoryIcon } from "../../../../components/icons/categories/CategoryIcon"; +import { BankAccountIcon } from "../../../../components/icons/BankAccountIcon"; export function Fab() { return ( @@ -14,15 +16,18 @@ export function Fab() { - + + Nova Despesa - + + Nova Receita - + + Nova Conta diff --git a/frontend/src/view/pages/Dashboard/components/Transactions/FiltersModal/index.tsx b/frontend/src/view/pages/Dashboard/components/Transactions/FiltersModal/index.tsx new file mode 100644 index 0000000..9011a2a --- /dev/null +++ b/frontend/src/view/pages/Dashboard/components/Transactions/FiltersModal/index.tsx @@ -0,0 +1,89 @@ +import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons"; +import { Modal } from "../../../../../components/Modal"; +import { Button } from "../../../../../components/Button"; +import { useFiltersModal } from "./useFiltersModal"; +import { cn } from "../../../../../../app/utils/cn"; + +interface FiltersModalProps { + open: boolean; + onClose(): void; +} + +const mockedAccounts = [ + { + id: '123', + name: 'Nubank', + }, + { + id: '456', + name: 'XP Investimentos', + }, + { + id: '789', + name: 'Dinheiro', + }, +]; + +export function FiltersModal({ open, onClose }: FiltersModalProps) { + const { + selectedBankAccountId, + handleSelectBankAccount, + selectedYear, + handleChangeYear, + } = useFiltersModal(); + + return ( + +
+ + Conta + +
+ {mockedAccounts.map(account => ( + + ))} +
+
+ +
+ + Ano + +
+ +
+ + {selectedYear} + +
+ + +
+
+ + +
+ ); +} diff --git a/frontend/src/view/pages/Dashboard/components/Transactions/FiltersModal/useFiltersModal.ts b/frontend/src/view/pages/Dashboard/components/Transactions/FiltersModal/useFiltersModal.ts new file mode 100644 index 0000000..e88027a --- /dev/null +++ b/frontend/src/view/pages/Dashboard/components/Transactions/FiltersModal/useFiltersModal.ts @@ -0,0 +1,25 @@ +import { useState } from "react"; + +export function useFiltersModal() { + const [selectedBankAccountId, setSelectedBankAccountId] = useState(null); + const [selectedYear, setSelectedYear] = useState(new Date().getFullYear()); + + function handleSelectBankAccount(bankAccountId: string) { + setSelectedBankAccountId(prevState => ( + prevState === bankAccountId + ? null + : bankAccountId + )); + } + + function handleChangeYear(step: number) { + setSelectedYear(prevState => prevState + step); + } + + return { + handleSelectBankAccount, + selectedBankAccountId, + selectedYear, + handleChangeYear, + }; +} diff --git a/frontend/src/view/pages/Dashboard/components/Transactions/index.tsx b/frontend/src/view/pages/Dashboard/components/Transactions/index.tsx index ed18cfe..43f92ed 100644 --- a/frontend/src/view/pages/Dashboard/components/Transactions/index.tsx +++ b/frontend/src/view/pages/Dashboard/components/Transactions/index.tsx @@ -10,9 +10,18 @@ import { cn } from "../../../../../app/utils/cn"; import Spinner from "../../../../components/Spinner"; import emptyStateImage from "../../../../../assets/empty-state.svg"; import { TransactionTypeDropdown } from "./TransactionTypeDropdown"; +import { FiltersModal } from "./FiltersModal"; export function Transactions() { - const { areValuesVisible, isInitialLoading, isLoading, transactions } = useTransactionsController(); + const { + areValuesVisible, + isInitialLoading, + isLoading, + transactions, + isFiltersModalOpen, + handleOpenFiltersModal, + handleCloseFiltersModal, + } = useTransactionsController(); const hasTransactions = transactions.length > 0; @@ -26,10 +35,15 @@ export function Transactions() { {!isInitialLoading && ( <> +
-
diff --git a/frontend/src/view/pages/Dashboard/components/Transactions/useTransactionsController.ts b/frontend/src/view/pages/Dashboard/components/Transactions/useTransactionsController.ts index 48d9443..760050a 100644 --- a/frontend/src/view/pages/Dashboard/components/Transactions/useTransactionsController.ts +++ b/frontend/src/view/pages/Dashboard/components/Transactions/useTransactionsController.ts @@ -1,12 +1,26 @@ +import { useState } from "react"; import { useDashboard } from "../DashboardContext/useDashboard"; export function useTransactionsController() { const { areValuesVisible } = useDashboard(); + const [isFiltersModalOpen, setIsFiltersModalOpen] = useState(true); + + function handleOpenFiltersModal() { + setIsFiltersModalOpen(true); + } + + function handleCloseFiltersModal() { + setIsFiltersModalOpen(false); + } + return { areValuesVisible, transactions: [], isInitialLoading: false, isLoading: false, + handleOpenFiltersModal, + handleCloseFiltersModal, + isFiltersModalOpen, }; } diff --git a/frontend/src/view/pages/Dashboard/index.tsx b/frontend/src/view/pages/Dashboard/index.tsx index d8aad5a..5ac7feb 100644 --- a/frontend/src/view/pages/Dashboard/index.tsx +++ b/frontend/src/view/pages/Dashboard/index.tsx @@ -25,6 +25,7 @@ export function Dashboard() { + ); diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index b295c24..d44dcd4 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -181,9 +181,24 @@ export default { from: { opacity: '0', transform: 'translateY(2px)' }, to: { opacity: '1', transform: 'translateY(0)' }, }, + slideDownAndFade: { + from: { opacity: '0', transform: 'translateY(-2px)' }, + to: { opacity: '1', transform: 'translateY(0)' }, + }, + overlayShow: { + from: { opacity: '0' }, + to: { opacity: '1' }, + }, + contentShow: { + from: { opacity: '0', transform: 'translate(-50%, -48%) scale(0.96)' }, + to: { opacity: '1', transform: 'translate(-50%, -50%) scale(1)' }, + }, }, animation: { 'slide-up-and-fade': 'slideUpAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', + 'slide-down-and-fade': 'slideDownAndFade 400ms cubic-bezier(0.16, 1, 0.3, 1)', + 'overlay-show': 'overlayShow 150ms cubic-bezier(0.16, 1, 0.3, 1)', + 'content-show': 'contentShow 150ms cubic-bezier(0.16, 1, 0.3, 1)', }, }, }, diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 0821d9b..114aa59 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -335,6 +335,27 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-dialog@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz#71657b1b116de6c7a0b03242d7d43e01062c7300" + integrity sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.5" + "@radix-ui/react-focus-guards" "1.0.1" + "@radix-ui/react-focus-scope" "1.0.4" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-portal" "1.0.4" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-controllable-state" "1.0.1" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + "@radix-ui/react-direction@1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b"