├── .dockerignore ├── .github └── workflows │ ├── docker-image-dev.yml │ └── docker-image.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── back ├── .editorconfig ├── .env.example ├── .gitattributes ├── .gitignore ├── README.md ├── app │ ├── Authorizations │ │ └── TransactionTemplateAuthorization.php │ ├── Console │ │ ├── Commands │ │ │ └── CreateFakeTransactions.php │ │ └── Kernel.php │ ├── Exceptions │ │ ├── FireflyException.php │ │ ├── GeneralException.php │ │ └── Handler.php │ ├── Helpers │ │ └── Helpers.php │ ├── Http │ │ ├── Controllers │ │ │ ├── AccountController.php │ │ │ ├── Base │ │ │ │ ├── BaseController.php │ │ │ │ └── BaseControllerFirefly.php │ │ │ ├── BudgetController.php │ │ │ ├── CategoryController.php │ │ │ ├── CurrencyController.php │ │ │ ├── ProfileController.php │ │ │ ├── TagController.php │ │ │ ├── TransactionController.php │ │ │ ├── TransactionTemplateController.php │ │ │ ├── UserController.php │ │ │ └── VersionController.php │ │ ├── Kernel.php │ │ └── Middleware │ │ │ ├── Authenticate.php │ │ │ ├── EncryptCookies.php │ │ │ ├── PreventRequestsDuringMaintenance.php │ │ │ ├── RedirectIfAuthenticated.php │ │ │ ├── TrimStrings.php │ │ │ ├── TrustHosts.php │ │ │ ├── TrustProxies.php │ │ │ ├── ValidateSignature.php │ │ │ └── VerifyCsrfToken.php │ ├── Models │ │ ├── Account.php │ │ ├── BaseModel.php │ │ ├── Budget.php │ │ ├── Category.php │ │ ├── Currency.php │ │ ├── Icon.php │ │ ├── Profile.php │ │ ├── Tag.php │ │ ├── Transaction.php │ │ ├── TransactionTemplate.php │ │ ├── TransactionTemplateExtraName.php │ │ ├── TransactionTemplateTag.php │ │ └── User.php │ ├── Providers │ │ ├── AppServiceProvider.php │ │ ├── AuthServiceProvider.php │ │ ├── BroadcastServiceProvider.php │ │ ├── EventServiceProvider.php │ │ └── RouteServiceProvider.php │ ├── Repositories │ │ ├── BaseRepository.php │ │ └── TransactionTemplateRepository.php │ ├── Utils │ │ ├── CurrencyUtils.php │ │ └── RouteUtils.php │ └── Validations │ │ └── TransactionTemplateValidation.php ├── artisan ├── bootstrap │ ├── app.php │ └── cache │ │ └── .gitignore ├── composer.json ├── composer.lock ├── config │ ├── app.php │ ├── auth.php │ ├── broadcasting.php │ ├── cache.php │ ├── cors.php │ ├── database.php │ ├── filesystems.php │ ├── hashing.php │ ├── logging.php │ ├── mail.php │ ├── queue.php │ ├── services.php │ ├── session.php │ └── view.php ├── database │ ├── .gitignore │ ├── factories │ │ └── UserFactory.php │ ├── migrations │ │ ├── 2014_10_12_000000_create_users_table.php │ │ ├── 2014_10_12_100000_create_password_reset_tokens_table.php │ │ ├── 2019_08_19_000000_create_failed_jobs_table.php │ │ ├── 2019_12_14_000001_create_personal_access_tokens_table.php │ │ ├── 2023_10_02_124513_create_transaction_templates.php │ │ ├── 2024_02_22_131702_create_transaction_template_audio_names_table.php │ │ ├── 2024_03_10_084308_create_tags_table.php │ │ ├── 2024_03_27_130655_add_icon_to_accounts_and_categories.php │ │ ├── 2024_04_01_121800_add_is_todo_to_tags.php │ │ ├── 2024_04_23_155844_rename_transaction_templates_audio_names.php │ │ ├── 2024_05_14_054224_add_is_visible_on_dashboard_to_accounts.php │ │ ├── 2024_06_25_000000_create_profiles_table.php │ │ └── 2024_09_13_152958_create_budgets_table.php │ └── seeders │ │ └── DatabaseSeeder.php ├── package-lock.json ├── package.json ├── phpunit.xml ├── public │ ├── .htaccess │ ├── favicon.ico │ ├── index.php │ └── robots.txt ├── resources │ ├── css │ │ └── app.css │ ├── js │ │ ├── app.js │ │ └── bootstrap.js │ └── views │ │ └── welcome.blade.php ├── routes │ ├── api.php │ ├── channels.php │ ├── console.php │ └── web.php ├── storage │ ├── app │ │ ├── .gitignore │ │ └── public │ │ │ └── .gitignore │ ├── framework │ │ ├── .gitignore │ │ ├── cache │ │ │ ├── .gitignore │ │ │ └── data │ │ │ │ └── .gitignore │ │ ├── sessions │ │ │ └── .gitignore │ │ ├── testing │ │ │ └── .gitignore │ │ └── views │ │ │ └── .gitignore │ └── logs │ │ └── .gitignore ├── tests │ ├── CreatesApplication.php │ ├── Feature │ │ └── ExampleTest.php │ ├── TestCase.php │ └── Unit │ │ └── ExampleTest.php └── vite.config.js ├── docker-compose.pico+firefly+importer.yml ├── docker-compose.pico+firefly.yml ├── docker-compose.pico.yml ├── docker ├── conf │ ├── nginx │ │ ├── http.d │ │ │ └── default.conf │ │ └── nginx.conf │ ├── php-fpm │ │ ├── php-fpm.conf │ │ └── php-fpm.d │ │ │ └── www.conf │ └── supervisor │ │ ├── cron.ini │ │ ├── nginx.ini │ │ ├── node.ini │ │ ├── php-fpm.ini │ │ └── supervisord.conf └── docker-entrypoint.d │ └── start.sh ├── docs ├── architecture.md ├── assistant.md ├── attribution.md ├── contribute.md ├── images │ ├── architecture.png │ ├── demo.gif │ ├── logo.png │ ├── logo2.png │ └── presentation.png └── installation.md ├── front ├── .gitignore ├── .npmrc ├── .prettierrc ├── README.md ├── app.vue ├── assets │ ├── icons │ │ ├── avatar │ │ │ ├── actor-chaplin-comedy-svgrepo-com.svg │ │ │ ├── addicted-draw-love-svgrepo-com.svg │ │ │ ├── afro-avatar-male-2-svgrepo-com.svg │ │ │ ├── afro-avatar-male-svgrepo-com.svg │ │ │ ├── afro-boy-child-svgrepo-com.svg │ │ │ ├── afro-female-person-svgrepo-com.svg │ │ │ ├── alien-avatar-space-svgrepo-com.svg │ │ │ ├── animal-avatar-bear-svgrepo-com.svg │ │ │ ├── animal-avatar-mutton-svgrepo-com.svg │ │ │ ├── animal-deer.svg │ │ │ ├── animal-deer2.svg │ │ │ ├── animal-dog.svg │ │ │ ├── animal-elephant.svg │ │ │ ├── animal-fox.svg │ │ │ ├── animal-giraffe.svg │ │ │ ├── animal-koala.svg │ │ │ ├── animal-lion.svg │ │ │ ├── animal-monkey.svg │ │ │ ├── animal-monkey2.svg │ │ │ ├── animal-owl.svg │ │ │ ├── animal-racoon.svg │ │ │ ├── animal-rhino.svg │ │ │ ├── anime-away-face-svgrepo-com.svg │ │ │ ├── apple-avatar-illness-svgrepo-com.svg │ │ │ ├── artist-avatar-marilyn-svgrepo-com.svg │ │ │ ├── atm.svg │ │ │ ├── atm2.svg │ │ │ ├── avatar-avocado-food-svgrepo-com.svg │ │ │ ├── avatar-bad-breaking-svgrepo-com.svg │ │ │ ├── avatar-batman-comics-svgrepo-com.svg │ │ │ ├── avatar-boy-kid-svgrepo-com.svg │ │ │ ├── avatar-boy-male-svgrepo-com.svg │ │ │ ├── avatar-bug-insect-svgrepo-com.svg │ │ │ ├── avatar-cacti-cactus-svgrepo-com.svg │ │ │ ├── avatar-child-girl-svgrepo-com.svg │ │ │ ├── avatar-cloud-crying-svgrepo-com.svg │ │ │ ├── avatar-coffee-cup-svgrepo-com.svg │ │ │ ├── avatar-dead-monster-svgrepo-com.svg │ │ │ ├── avatar-einstein-professor-svgrepo-com.svg │ │ │ ├── avatar-elderly-grandma-svgrepo-com.svg │ │ │ ├── avatar-female-girl-svgrepo-com.svg │ │ │ ├── avatar-female-portrait-2-svgrepo-com.svg │ │ │ ├── avatar-female-portrait-svgrepo-com.svg │ │ │ ├── avatar-geisha-japanese-svgrepo-com.svg │ │ │ ├── avatar-hindi-indian-svgrepo-com.svg │ │ │ ├── avatar-joker-squad-svgrepo-com.svg │ │ │ ├── avatar-lazybones-sloth-svgrepo-com.svg │ │ │ ├── avatar-male-man-svgrepo-com.svg │ │ │ ├── avatar-male-ozzy-svgrepo-com.svg │ │ │ ├── avatar-male-president-svgrepo-com.svg │ │ │ ├── avatar-man-muslim-svgrepo-com.svg │ │ │ ├── avatar-man-person-svgrepo-com.svg │ │ │ ├── avatar-muslim-paranja-svgrepo-com.svg │ │ │ ├── avatar-nun-sister-svgrepo-com.svg │ │ │ ├── avatar-person-pilot-svgrepo-com.svg │ │ │ ├── baby-child-kid-svgrepo-com.svg │ │ │ ├── bag.svg │ │ │ ├── bag2.svg │ │ │ ├── bag3.svg │ │ │ ├── bag4.svg │ │ │ ├── bag5.svg │ │ │ ├── bank-card-svgrepo-com.svg │ │ │ ├── bank-finance-business-money-card-svgrepo-com.svg │ │ │ ├── bank-svgrepo-com.svg │ │ │ ├── bank.svg │ │ │ ├── bank2.svg │ │ │ ├── bar-chart-bars-chart-svgrepo-com.svg │ │ │ ├── bar-chart-graph-svgrepo-com.svg │ │ │ ├── bear-svgrepo-com.svg │ │ │ ├── beard-hipster-male-svgrepo-com.svg │ │ │ ├── bitcoin-svgrepo-com.svg │ │ │ ├── box.svg │ │ │ ├── boy-indian-kid-svgrepo-com.svg │ │ │ ├── briefcase.svg │ │ │ ├── briefcase2.svg │ │ │ ├── browser-analytics-svgrepo-com.svg │ │ │ ├── builder-helmet-worker-svgrepo-com.svg │ │ │ ├── calculator.svg │ │ │ ├── calendar-svgrepo-com.svg │ │ │ ├── card.svg │ │ │ ├── card2.svg │ │ │ ├── chart-bar-chart-svgrepo-com.svg │ │ │ ├── chart-decreasing-svgrepo-com.svg │ │ │ ├── chart-graphic-svgrepo-com.svg │ │ │ ├── child-girl-kid-svgrepo-com.svg │ │ │ ├── christmas-clous-santa-svgrepo-com.svg │ │ │ ├── coin-svgrepo-com.svg │ │ │ ├── coin.svg │ │ │ ├── coin2.svg │ │ │ ├── coordinate-svgrepo-com.svg │ │ │ ├── credit-card-svgrepo-com.svg │ │ │ ├── diamond-ring-diamond-svgrepo-com.svg │ │ │ ├── diamond.svg │ │ │ ├── discount-sign-money-svgrepo-com.svg │ │ │ ├── education.svg │ │ │ ├── exchange.svg │ │ │ ├── femal12.svg │ │ │ ├── female.svg │ │ │ ├── female10.svg │ │ │ ├── female11.svg │ │ │ ├── female13.svg │ │ │ ├── female2.svg │ │ │ ├── female3.svg │ │ │ ├── female4.svg │ │ │ ├── female5.svg │ │ │ ├── female6.svg │ │ │ ├── female7.svg │ │ │ ├── female8.svg │ │ │ ├── female9.svg │ │ │ ├── fighter-luchador-man-svgrepo-com.svg │ │ │ ├── football-svgrepo-com.svg │ │ │ ├── friday-halloween-jason-svgrepo-com.svg │ │ │ ├── globe-svgrepo-com.svg │ │ │ ├── graph.svg │ │ │ ├── heart-red-svgrepo-com.svg │ │ │ ├── help-desk-svgrepo-com.svg │ │ │ ├── indian-male-man-svgrepo-com.svg │ │ │ ├── indian-man-sikh-svgrepo-com.svg │ │ │ ├── light-bulb-idea-svgrepo-com.svg │ │ │ ├── line-chart-svgrepo-com.svg │ │ │ ├── male-man-old-svgrepo-com.svg │ │ │ ├── male.svg │ │ │ ├── male10.svg │ │ │ ├── male11.svg │ │ │ ├── male12.svg │ │ │ ├── male13.svg │ │ │ ├── male2.svg │ │ │ ├── male3.svg │ │ │ ├── male4.svg │ │ │ ├── male5.svg │ │ │ ├── male6.svg │ │ │ ├── male7.svg │ │ │ ├── male8.svg │ │ │ ├── male9.svg │ │ │ ├── medal-gold-svgrepo-com.svg │ │ │ ├── money-cog.svg │ │ │ ├── money-pile.svg │ │ │ ├── money.svg │ │ │ ├── money2.svg │ │ │ ├── money3.svg │ │ │ ├── money4.svg │ │ │ ├── money5.svg │ │ │ ├── payment-cards-money-svgrepo-com.svg │ │ │ ├── phone.svg │ │ │ ├── pie-chart-svgrepo-com.svg │ │ │ ├── piggy-bank-svgrepo-com.svg │ │ │ ├── piggy.svg │ │ │ ├── piggy2.svg │ │ │ ├── piggy3.svg │ │ │ ├── piggy4.svg │ │ │ ├── pot.svg │ │ │ ├── pouch.svg │ │ │ ├── pyramid-chart-graph-svgrepo-com.svg │ │ │ ├── rainbow.svg │ │ │ ├── safe.svg │ │ │ ├── safe2.svg │ │ │ ├── safebox-bank-svgrepo-com.svg │ │ │ ├── shopping-bag-svgrepo-com.svg │ │ │ ├── shopping-basket-svgrepo-com.svg │ │ │ ├── star-gold-orange-svgrepo-com.svg │ │ │ ├── statistics-graph-svgrepo-com.svg │ │ │ ├── stats-line-chart-svgrepo-com.svg │ │ │ ├── tag-price-label-svgrepo-com.svg │ │ │ ├── target-hit-aim-svgrepo-com.svg │ │ │ ├── umbrella.svg │ │ │ ├── wallet-money-business-svgrepo-com.svg │ │ │ ├── wallet-svgrepo-com-2.svg │ │ │ ├── wallet-svgrepo-com.svg │ │ │ ├── wallet.svg │ │ │ └── wallet2.svg │ │ ├── custom │ │ │ └── exchange.svg │ │ ├── duo │ │ │ ├── adhesive-plaster-2.svg │ │ │ ├── adhesive-plaster.svg │ │ │ ├── airbuds-case.svg │ │ │ ├── airbuds.svg │ │ │ ├── alarm.svg │ │ │ ├── album.svg │ │ │ ├── archive-up-minimlistic.svg │ │ │ ├── archive.svg │ │ │ ├── armchair-2.svg │ │ │ ├── armchair.svg │ │ │ ├── asteroid.svg │ │ │ ├── atom.svg │ │ │ ├── backpack.svg │ │ │ ├── bacteria.svg │ │ │ ├── bag-2.svg │ │ │ ├── bag-3.svg │ │ │ ├── bag-4.svg │ │ │ ├── bag-5.svg │ │ │ ├── bag-heart.svg │ │ │ ├── bag.svg │ │ │ ├── balloon.svg │ │ │ ├── balls.svg │ │ │ ├── banknote-2.svg │ │ │ ├── banknote.svg │ │ │ ├── bar-chair.svg │ │ │ ├── basketball.svg │ │ │ ├── bath.svg │ │ │ ├── battery-charge.svg │ │ │ ├── bed.svg │ │ │ ├── bedside-table-2.svg │ │ │ ├── bedside-table-3.svg │ │ │ ├── bedside-table-4.svg │ │ │ ├── bedside-table.svg │ │ │ ├── body.svg │ │ │ ├── bolt-circle.svg │ │ │ ├── bone.svg │ │ │ ├── bonfire.svg │ │ │ ├── book-bookmark-minimalistic.svg │ │ │ ├── bookmark-square.svg │ │ │ ├── bottle.svg │ │ │ ├── bowling.svg │ │ │ ├── box.svg │ │ │ ├── calculator.svg │ │ │ ├── calendar-add.svg │ │ │ ├── calendar.svg │ │ │ ├── camera-minimalistic.svg │ │ │ ├── camera.svg │ │ │ ├── card-2.svg │ │ │ ├── card-recive.svg │ │ │ ├── card-search.svg │ │ │ ├── card-send.svg │ │ │ ├── card-transfer.svg │ │ │ ├── card.svg │ │ │ ├── cardholder.svg │ │ │ ├── cart-3.svg │ │ │ ├── cart-check.svg │ │ │ ├── cart.svg │ │ │ ├── case-minimalistic.svg │ │ │ ├── case-round.svg │ │ │ ├── cash-out.svg │ │ │ ├── cassette-2.svg │ │ │ ├── chair-2.svg │ │ │ ├── chair.svg │ │ │ ├── chandelier.svg │ │ │ ├── chart-2.svg │ │ │ ├── chat--square-call.svg │ │ │ ├── chat--square-like.svg │ │ │ ├── chat--square.svg │ │ │ ├── chef-hat-heart.svg │ │ │ ├── chef-hat-minimalistic.svg │ │ │ ├── clapperboard-edit.svg │ │ │ ├── clapperboard-open-play.svg │ │ │ ├── clapperboard-text.svg │ │ │ ├── clipboard-heart.svg │ │ │ ├── clipboard-list.svg │ │ │ ├── closet-2.svg │ │ │ ├── closet.svg │ │ │ ├── cloud-bolt-minimalistic.svg │ │ │ ├── cloud-rain.svg │ │ │ ├── code.svg │ │ │ ├── colour-tuneing.svg │ │ │ ├── condicioner.svg │ │ │ ├── confetti-minimalistic.svg │ │ │ ├── corkscrew.svg │ │ │ ├── cosmetic.svg │ │ │ ├── cpu.svg │ │ │ ├── crown-line.svg │ │ │ ├── cup-first.svg │ │ │ ├── cup-hot.svg │ │ │ ├── cup-paper.svg │ │ │ ├── cup.svg │ │ │ ├── database.svg │ │ │ ├── delivery.svg │ │ │ ├── devices.svg │ │ │ ├── diagram-down.svg │ │ │ ├── diploma.svg │ │ │ ├── diskette.svg │ │ │ ├── display.svg │ │ │ ├── dna.svg │ │ │ ├── document-add.svg │ │ │ ├── documents-minimalistic.svg │ │ │ ├── dollar.svg │ │ │ ├── donut-bitten.svg │ │ │ ├── dumbbell-large.svg │ │ │ ├── dumbbell-small.svg │ │ │ ├── earth.svg │ │ │ ├── emoji-funny-square.svg │ │ │ ├── end-call-rounded.svg │ │ │ ├── eraser.svg │ │ │ ├── euro.svg │ │ │ ├── eye.svg │ │ │ ├── face-scan-square.svg │ │ │ ├── filter.svg │ │ │ ├── fire.svg │ │ │ ├── flag.svg │ │ │ ├── flame.svg │ │ │ ├── flash-drive.svg │ │ │ ├── flashlight-on.svg │ │ │ ├── floor-lamp-minimalistic.svg │ │ │ ├── floor-lamp.svg │ │ │ ├── football.svg │ │ │ ├── fridge.svg │ │ │ ├── fuel.svg │ │ │ ├── gallery-edit.svg │ │ │ ├── gameboy.svg │ │ │ ├── gamepad-charge.svg │ │ │ ├── ghost-smile.svg │ │ │ ├── gift.svg │ │ │ ├── glasses.svg │ │ │ ├── global.svg │ │ │ ├── globus.svg │ │ │ ├── golf.svg │ │ │ ├── gps.svg │ │ │ ├── hanger-2.svg │ │ │ ├── hanger.svg │ │ │ ├── headphones-round-sound.svg │ │ │ ├── headphones-square.svg │ │ │ ├── health.svg │ │ │ ├── heart.svg │ │ │ ├── hiking.svg │ │ │ ├── history-3.svg │ │ │ ├── home-angle-2.svg │ │ │ ├── hourglass-line.svg │ │ │ ├── inbox-archive.svg │ │ │ ├── inbox-in.svg │ │ │ ├── incognito.svg │ │ │ ├── iphone.svg │ │ │ ├── jar-of-pills-2.svg │ │ │ ├── jar-of-pills.svg │ │ │ ├── key.svg │ │ │ ├── keyboard.svg │ │ │ ├── ladle.svg │ │ │ ├── lamp.svg │ │ │ ├── laptop.svg │ │ │ ├── layers-minimalistic.svg │ │ │ ├── leaf.svg │ │ │ ├── lightbulb.svg │ │ │ ├── lightning.svg │ │ │ ├── like.svg │ │ │ ├── lock-keyhole.svg │ │ │ ├── magic-stick-2.svg │ │ │ ├── magic-stick-3.svg │ │ │ ├── magic-stick.svg │ │ │ ├── magnet.svg │ │ │ ├── magnifer.svg │ │ │ ├── mailbox.svg │ │ │ ├── map-arrow-up.svg │ │ │ ├── map-point-wave.svg │ │ │ ├── map.svg │ │ │ ├── masks.svg │ │ │ ├── medal-ribbon-star.svg │ │ │ ├── medal-star-circle.svg │ │ │ ├── medal-star-square.svg │ │ │ ├── medical-kit.svg │ │ │ ├── meditation-round.svg │ │ │ ├── men.svg │ │ │ ├── microphone-large.svg │ │ │ ├── microphone.svg │ │ │ ├── money-bag.svg │ │ │ ├── monitor-camera.svg │ │ │ ├── moon-fog.svg │ │ │ ├── moon.svg │ │ │ ├── mouse.svg │ │ │ ├── music-note-2.svg │ │ │ ├── music-note-3.svg │ │ │ ├── notebook.svg │ │ │ ├── notes-minimalistic.svg │ │ │ ├── notification-unread-lines.svg │ │ │ ├── oven-mitts.svg │ │ │ ├── paint-roller.svg │ │ │ ├── palette-round.svg │ │ │ ├── pallete-2.svg │ │ │ ├── panorama.svg │ │ │ ├── paper-bin.svg │ │ │ ├── paperclip.svg │ │ │ ├── passport.svg │ │ │ ├── paw.svg │ │ │ ├── pen.svg │ │ │ ├── perfume.svg │ │ │ ├── pill.svg │ │ │ ├── pin-list.svg │ │ │ ├── pin.svg │ │ │ ├── pipette.svg │ │ │ ├── plain-2.svg │ │ │ ├── planet-2.svg │ │ │ ├── planet-3.svg │ │ │ ├── plug-circle.svg │ │ │ ├── presentation-graph.svg │ │ │ ├── printer-2.svg │ │ │ ├── printer.svg │ │ │ ├── projector.svg │ │ │ ├── pulse-2.svg │ │ │ ├── qr-code.svg │ │ │ ├── radar-2.svg │ │ │ ├── radio-minimalistic.svg │ │ │ ├── radio.svg │ │ │ ├── ranking.svg │ │ │ ├── reel.svg │ │ │ ├── remote-controller.svg │ │ │ ├── rocket-2.svg │ │ │ ├── rugby.svg │ │ │ ├── ruler-angular.svg │ │ │ ├── ruler-pen.svg │ │ │ ├── ruler.svg │ │ │ ├── running-2.svg │ │ │ ├── scissors.svg │ │ │ ├── server-path.svg │ │ │ ├── server.svg │ │ │ ├── settings.svg │ │ │ ├── shop-2.svg │ │ │ ├── sim-card-minimalistic.svg │ │ │ ├── siren-rounded.svg │ │ │ ├── skateboarding-round.svg │ │ │ ├── skirt.svg │ │ │ ├── sledgehammer.svg │ │ │ ├── sleeping.svg │ │ │ ├── smart-speaker-minimalistic.svg │ │ │ ├── smart-vacuum-cleaner.svg │ │ │ ├── snowflake.svg │ │ │ ├── sofa-3.svg │ │ │ ├── sofa.svg │ │ │ ├── speaker.svg │ │ │ ├── square-academic-cap.svg │ │ │ ├── star.svg │ │ │ ├── stars-line.svg │ │ │ ├── station-minimalistic.svg │ │ │ ├── stethoscope.svg │ │ │ ├── stream.svg │ │ │ ├── streets-map-point.svg │ │ │ ├── stretching-round.svg │ │ │ ├── suitcase-lines.svg │ │ │ ├── suitcase-tag.svg │ │ │ ├── suitcase.svg │ │ │ ├── sun-2.svg │ │ │ ├── swimming.svg │ │ │ ├── syringe.svg │ │ │ ├── t-shirt.svg │ │ │ ├── tag.svg │ │ │ ├── target.svg │ │ │ ├── tea-cup.svg │ │ │ ├── telescope.svg │ │ │ ├── temperature.svg │ │ │ ├── tennis-2.svg │ │ │ ├── tennis.svg │ │ │ ├── test-tube-minimalistic.svg │ │ │ ├── thermometer.svg │ │ │ ├── ticker-star.svg │ │ │ ├── tornado-small.svg │ │ │ ├── trash-bin-trash.svg │ │ │ ├── treadmill.svg │ │ │ ├── turntable.svg │ │ │ ├── tv.svg │ │ │ ├── ufo.svg │ │ │ ├── umbrella.svg │ │ │ ├── user.svg │ │ │ ├── videocamera-record.svg │ │ │ ├── volleyball.svg │ │ │ ├── walking.svg │ │ │ ├── wallet-money.svg │ │ │ ├── wallet.svg │ │ │ ├── wallpaper.svg │ │ │ ├── washing-machine-minimalistic.svg │ │ │ ├── washing-machine.svg │ │ │ ├── watch-square.svg │ │ │ ├── water-sun.svg │ │ │ ├── water.svg │ │ │ ├── waterdrop.svg │ │ │ ├── waterdrops.svg │ │ │ ├── weigher.svg │ │ │ ├── whisk.svg │ │ │ ├── wi-fi-router.svg │ │ │ ├── wineglass-triangle.svg │ │ │ ├── wineglass.svg │ │ │ ├── wireless-charge.svg │ │ │ └── women.svg │ │ ├── flags │ │ │ ├── cn.svg │ │ │ ├── en.svg │ │ │ ├── it.svg │ │ │ └── ro.svg │ │ ├── fluent │ │ │ ├── bike.svg │ │ │ ├── building_24_regular.svg │ │ │ ├── building_bank_20_regular.svg │ │ │ ├── building_home_16_regular.svg │ │ │ ├── building_mosque_20_regular.svg │ │ │ ├── building_multiple_20_regular.svg │ │ │ ├── building_townhouse_20_regular.svg │ │ │ ├── chick.svg │ │ │ ├── crown_20_regular.svg │ │ │ ├── dentist_20_regular.svg │ │ │ ├── desktop_sync_24_regular.svg │ │ │ ├── dishwasher_20_regular.svg │ │ │ ├── dress.svg │ │ │ ├── emoji_24_regular.svg │ │ │ ├── food_24_regular.svg │ │ │ ├── food_apple_20_regular.svg │ │ │ ├── food_chicken_leg_16_regular.svg │ │ │ ├── food_egg_20_regular.svg │ │ │ ├── food_fish_20_regular.svg │ │ │ ├── food_pizza_20_regular.svg │ │ │ ├── food_toast_20_regular.svg │ │ │ ├── glasses.svg │ │ │ ├── hat.svg │ │ │ ├── home_garage_20_regular.svg │ │ │ ├── ice-cream.svg │ │ │ ├── kid1.svg │ │ │ ├── kid2.svg │ │ │ ├── kid3.svg │ │ │ ├── motorbike.svg │ │ │ ├── pants.svg │ │ │ ├── rocket_24_regular.svg │ │ │ ├── savings_24_regular.svg │ │ │ ├── school.svg │ │ │ ├── scooter.svg │ │ │ ├── scooter2.svg │ │ │ ├── shifts_20_regular.svg │ │ │ ├── shoe.svg │ │ │ ├── spatula_spoon_24_regular.svg │ │ │ ├── stack_star_20_regular.svg │ │ │ ├── underwear.svg │ │ │ ├── vehicle_bicycle_20_regular.svg │ │ │ ├── vehicle_car_profile_24_regular.svg │ │ │ ├── wallet_20_regular.svg │ │ │ └── wifi.svg │ │ └── speed1.svg │ ├── styles │ │ ├── animations.css │ │ ├── bootstrap.min.css │ │ ├── bootstrap.min.css.map │ │ ├── helper.css │ │ ├── theme-dark.css │ │ ├── theme.css │ │ └── variables.css │ └── svg │ │ ├── empty.svg │ │ └── empty2.svg ├── components │ ├── account │ │ └── account-adjust-balance.vue │ ├── budget │ │ └── budget-icon.vue │ ├── charts │ │ ├── bar-chart-item-horizontal.vue │ │ └── bar-chart-item-vertical.vue │ ├── dashboard │ │ ├── dashboard-accounts │ │ │ └── dashboard-accounts.vue │ │ ├── dashboard-budgets │ │ │ ├── dashboard-budget-item.vue │ │ │ └── dashboard-budgets.vue │ │ ├── dashboard-calendar │ │ │ ├── dashboard-calendar-month-day.vue │ │ │ ├── dashboard-calendar-month.vue │ │ │ └── dashboard-calendar.vue │ │ ├── dashboard-category-totals │ │ │ └── dashboard-category-totals.vue │ │ ├── dashboard-controls │ │ │ ├── dashboard-control-buttons.vue │ │ │ └── dashboard-control.vue │ │ ├── dashboard-summary │ │ │ ├── dashboard-summary-card.vue │ │ │ └── dashboard-summary.vue │ │ ├── dashboard-tag-totals │ │ │ └── dashboard-tag-totals.vue │ │ ├── dashboard-todo-transactions │ │ │ └── dashboard-todo-transactions.vue │ │ └── dashboard-week-bars │ │ │ └── dashboard-week-bars.vue │ ├── general │ │ └── empty-list.vue │ ├── global │ │ └── svg │ │ │ ├── SvgAccountIcon.vue │ │ │ ├── SvgAccountTransfer.vue │ │ │ ├── SvgAddIcon.vue │ │ │ ├── SvgCategoryIcon.vue │ │ │ ├── SvgEmptyList.vue │ │ │ ├── SvgEmptyList2.vue │ │ │ ├── SvgExtrasIcon.vue │ │ │ ├── SvgSettingIcon.vue │ │ │ ├── SvgTagIcon.vue │ │ │ ├── SvgTransactionIcon.vue │ │ │ └── SvgTransactionTemplateIcon.vue │ ├── list-items │ │ ├── account-list-item.vue │ │ ├── app-list-item.vue │ │ ├── budget-list-item.vue │ │ ├── category-list-item.vue │ │ ├── currency-list-item.vue │ │ ├── tag-list-item.vue │ │ ├── transaction-list-item-hero-icon.vue │ │ ├── transaction-list-item.vue │ │ └── transaction-template-list-item.vue │ ├── select │ │ ├── account │ │ │ ├── account-liability-direction-select.vue │ │ │ ├── account-liability-type-select.vue │ │ │ ├── account-role-select.vue │ │ │ ├── account-select.vue │ │ │ └── account-type-select.vue │ │ ├── budget-select.vue │ │ ├── budget │ │ │ ├── budget-period-select.vue │ │ │ └── budget-type-select.vue │ │ ├── category-select.vue │ │ ├── currency-dropdown.vue │ │ ├── currency-select.vue │ │ ├── date-format-select.vue │ │ ├── general │ │ │ ├── day-select.vue │ │ │ └── language-select.vue │ │ ├── icon-select.vue │ │ ├── page-select.vue │ │ ├── tag-select.vue │ │ ├── transaction-template-popup.vue │ │ └── transaction-type-select.vue │ ├── settings │ │ ├── app-config-stat.vue │ │ └── settings-token-field.vue │ ├── transaction │ │ ├── transaction-amount-field-operations.vue │ │ ├── transaction-amount-field-success-animation.vue │ │ ├── transaction-amount-field.vue │ │ ├── transaction-assistant.vue │ │ ├── transaction-filters.vue │ │ ├── transaction-split-badge.vue │ │ ├── transaction-type-dot.vue │ │ └── transaction-type-tabs.vue │ └── ui-kit │ │ ├── app-action-sheet.vue │ │ ├── app-boolean-old.vue │ │ ├── app-boolean.vue │ │ ├── app-checkbox.vue │ │ ├── app-chip.vue │ │ ├── app-circle.vue │ │ ├── app-date-time-grid.vue │ │ ├── app-date-time.vue │ │ ├── app-date.vue │ │ ├── app-field-link.vue │ │ ├── app-field.vue │ │ ├── app-icon.vue │ │ ├── app-loading.vue │ │ ├── app-month-year.vue │ │ ├── app-repeater.vue │ │ ├── app-select-option.vue │ │ ├── app-select.vue │ │ ├── app-tab-bar-item.vue │ │ ├── app-time.vue │ │ ├── app-tutorial.vue │ │ └── theme │ │ ├── app-bottom-loading.vue │ │ ├── app-bottom-toolbar.vue │ │ ├── app-button-form-delete.vue │ │ ├── app-button-form-save.vue │ │ ├── app-button-list-add.vue │ │ ├── app-card-info.vue │ │ ├── app-list-search.vue │ │ └── app-top-toolbar.vue ├── composables │ ├── directives │ │ └── swipe-fix.js │ ├── useActionSheet.js │ ├── useClickWithoutSwipe.js │ ├── useForm.js │ ├── useFormAttributes.js │ ├── useKeyboard.js │ ├── useList.js │ ├── useSpeechRecognition.js │ ├── useSwipeToDismiss.js │ └── useToolbar.js ├── constants │ ├── Constants.js │ ├── DashboardConstants.js │ ├── LanguageConstants.js │ ├── RouteConstants.js │ ├── SvgConstants.js │ ├── TablerIconConstants.js │ ├── TransactionConstants.js │ └── TutorialConstants.js ├── eslint.config.mjs ├── global.d.ts ├── i18n │ ├── i18n.config.js │ ├── index.js │ └── locales │ │ ├── en.json │ │ ├── it.json │ │ ├── ro.json │ │ └── zh-CN.json ├── layouts │ ├── default.vue │ └── empty.vue ├── models │ ├── Account.js │ ├── BaseModel.js │ ├── Budget.js │ ├── BudgetLimit.js │ ├── Category.js │ ├── Currency.js │ ├── Icon.js │ ├── Page.js │ ├── Profile.js │ ├── Tag.js │ ├── Transaction.js │ └── TransactionTemplate.js ├── modules │ └── register-components.js ├── nuxt.config.ts ├── package-lock.json ├── package.json ├── pages │ ├── accounts │ │ ├── [[id]].vue │ │ └── list.vue │ ├── budgets │ │ ├── [[id]].vue │ │ └── list.vue │ ├── categories │ │ ├── [[id]].vue │ │ └── list.vue │ ├── currencies │ │ ├── [[id]].vue │ │ └── list.vue │ ├── dashboard.vue │ ├── exchange-rates │ │ └── index.vue │ ├── extras.vue │ ├── index.vue │ ├── mihai.vue │ ├── settings │ │ ├── about.vue │ │ ├── assistant.vue │ │ ├── dashboard │ │ │ ├── cards.vue │ │ │ └── index.vue │ │ ├── formatting.vue │ │ ├── index.vue │ │ ├── setup.vue │ │ ├── transactions │ │ │ ├── default-form-values.vue │ │ │ ├── default-list-filters.vue │ │ │ ├── form-fields.vue │ │ │ ├── index.vue │ │ │ ├── list-fields.vue │ │ │ └── quick-amounts.vue │ │ └── ui.vue │ ├── tags │ │ ├── [[id]].vue │ │ └── list.vue │ ├── transaction-templates │ │ ├── [[id]].vue │ │ └── list.vue │ └── transactions │ │ ├── [[id]].vue │ │ └── list.vue ├── plugins │ ├── array-extension.js │ ├── axios.js │ ├── plugin-date-fns.js │ ├── plugin-i18n.js │ ├── plugin-register-tabler-icons.js │ └── plugin-vant.js ├── public │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── mstile-150x150.png │ ├── safari-pinned-tab.svg │ └── site.webmanifest ├── repository │ ├── AccountRepository.js │ ├── BaseRepository.js │ ├── BudgetRepository.js │ ├── CategoryRepository.js │ ├── CurrencyRepository.js │ ├── InfoRepository.js │ ├── ProfileRepository.js │ ├── TagRepository.js │ ├── TransactionRepository.js │ ├── TransactionTemplateRepository.js │ └── UserRepository.js ├── stores │ ├── appStore.js │ ├── dataStore.js │ └── profileStore.js ├── transformers │ ├── AccountTransformer.js │ ├── ApiTransformer.js │ ├── BudgetLimitTransformer.js │ ├── BudgetTransformer.js │ ├── CategoryTransformer.js │ ├── CurrencyTransformer.js │ ├── ProfileTransformer.js │ ├── TagTransformer.js │ ├── TransactionTemplateTransformer.js │ └── TransactionTransformer.js ├── tsconfig.json └── utils │ ├── AnimationUtils.js │ ├── CurrencyUtils.js │ ├── DashboardUtils.js │ ├── DataUtils.js │ ├── DateUtils.js │ ├── FilterUtils.js │ ├── LanguageUtils.js │ ├── MathUtils.js │ ├── MigrateUtils.js │ ├── NumberUtils.js │ ├── ResponseUtils.js │ ├── RomanianLanguageUtils.js │ ├── SettingUtils.js │ ├── TransactionFilterUtils.js │ ├── UIUtils.js │ ├── Utils.js │ ├── ValidationUtils.js │ └── VueUtils.js └── readme.md /.dockerignore: -------------------------------------------------------------------------------- 1 | back/vendor -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log* 3 | .nuxt 4 | .nitro 5 | .cache 6 | .output 7 | .env 8 | dist 9 | .idea 10 | .vscode 11 | -------------------------------------------------------------------------------- /back/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | indent_size = 4 7 | indent_style = space 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | 17 | [docker-compose.yml] 18 | indent_size = 4 19 | -------------------------------------------------------------------------------- /back/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | *.blade.php diff=html 4 | *.css diff=css 5 | *.html diff=html 6 | *.md diff=markdown 7 | *.php diff=php 8 | 9 | /.github export-ignore 10 | CHANGELOG.md export-ignore 11 | .styleci.yml export-ignore 12 | -------------------------------------------------------------------------------- /back/.gitignore: -------------------------------------------------------------------------------- 1 | /.phpunit.cache 2 | /node_modules 3 | /public/build 4 | /public/hot 5 | /public/storage 6 | /storage/*.key 7 | /vendor 8 | .env 9 | .env.backup 10 | .env.production 11 | .phpunit.result.cache 12 | Homestead.json 13 | Homestead.yaml 14 | auth.json 15 | npm-debug.log 16 | yarn-error.log 17 | /.fleet 18 | /.idea 19 | /.vscode 20 | -------------------------------------------------------------------------------- /back/README.md: -------------------------------------------------------------------------------- 1 | ## Structure -------------------------------------------------------------------------------- /back/app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | command('inspire')->hourly(); 16 | } 17 | 18 | /** 19 | * Register the commands for the application. 20 | */ 21 | protected function commands(): void 22 | { 23 | $this->load(__DIR__.'/Commands'); 24 | 25 | require base_path('routes/console.php'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /back/app/Http/Controllers/AccountController.php: -------------------------------------------------------------------------------- 1 | getFullUrl(); 21 | $response = $this->getHttpClient()->get($url); 22 | 23 | if ($response->status() !== self::HTTP_CODE_OK) { 24 | throw new FireflyException($response); 25 | } 26 | $data = $response->json(); 27 | $data = $this->onPostGet($data); 28 | return $data; 29 | } 30 | 31 | // --------------------------- 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /back/app/Http/Controllers/UserController.php: -------------------------------------------------------------------------------- 1 | expectsJson() ? null : route('login'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /back/app/Http/Middleware/EncryptCookies.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /back/app/Http/Middleware/PreventRequestsDuringMaintenance.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /back/app/Http/Middleware/RedirectIfAuthenticated.php: -------------------------------------------------------------------------------- 1 | check()) { 24 | return redirect(RouteServiceProvider::HOME); 25 | } 26 | } 27 | 28 | return $next($request); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /back/app/Http/Middleware/TrimStrings.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | 'current_password', 16 | 'password', 17 | 'password_confirmation', 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /back/app/Http/Middleware/TrustHosts.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | public function hosts(): array 15 | { 16 | return [ 17 | $this->allSubdomainsOfApplicationUrl(), 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /back/app/Http/Middleware/TrustProxies.php: -------------------------------------------------------------------------------- 1 | |string|null 14 | */ 15 | protected $proxies; 16 | 17 | /** 18 | * The headers that should be used to detect proxies. 19 | * 20 | * @var int 21 | */ 22 | protected $headers = 23 | Request::HEADER_X_FORWARDED_FOR | 24 | Request::HEADER_X_FORWARDED_HOST | 25 | Request::HEADER_X_FORWARDED_PORT | 26 | Request::HEADER_X_FORWARDED_PROTO | 27 | Request::HEADER_X_FORWARDED_AWS_ELB; 28 | } 29 | -------------------------------------------------------------------------------- /back/app/Http/Middleware/ValidateSignature.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 'fbclid', 16 | // 'utm_campaign', 17 | // 'utm_content', 18 | // 'utm_medium', 19 | // 'utm_source', 20 | // 'utm_term', 21 | ]; 22 | } 23 | -------------------------------------------------------------------------------- /back/app/Http/Middleware/VerifyCsrfToken.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /back/app/Models/Account.php: -------------------------------------------------------------------------------- 1 | 'array' 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /back/app/Models/Tag.php: -------------------------------------------------------------------------------- 1 | hasMany(TransactionTemplateTag::class); 25 | } 26 | 27 | // ------------------------------ Scopes --------------------------------- 28 | 29 | public function scopeSearch(Builder $query, $search = null) 30 | { 31 | if (!$search) 32 | return $query; 33 | 34 | return applyWhereLike($query, 'name', $search); 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /back/app/Models/TransactionTemplateExtraName.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | protected $policies = [ 16 | // 17 | ]; 18 | 19 | /** 20 | * Register any authentication / authorization services. 21 | */ 22 | public function boot(): void 23 | { 24 | // 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /back/app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | where('id', '[0-9]+'); 12 | Route::get($routeName, [$controller, 'getAll']); 13 | 14 | Route::post("$routeName", [$controller, 'create']); 15 | Route::patch("$routeName/{id}", [$controller, 'update'])->where('id', '[0-9]+'); 16 | Route::put("$routeName/{id}", [$controller, 'update'])->where('id', '[0-9]+'); 17 | Route::delete("$routeName/{id}", [$controller, 'delete'])->where('id', '[0-9]+'); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /back/app/Validations/TransactionTemplateValidation.php: -------------------------------------------------------------------------------- 1 | validate([ 28 | 'name' => 'required|max:1000', 29 | // 'description' => 'nullable|max:10000', 30 | ]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /back/bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /back/database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite* 2 | -------------------------------------------------------------------------------- /back/database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->string('name'); 17 | $table->string('email')->unique(); 18 | $table->timestamp('email_verified_at')->nullable(); 19 | $table->string('password'); 20 | $table->rememberToken(); 21 | $table->timestamps(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | */ 28 | public function down(): void 29 | { 30 | Schema::dropIfExists('users'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /back/database/migrations/2014_10_12_100000_create_password_reset_tokens_table.php: -------------------------------------------------------------------------------- 1 | string('email')->primary(); 16 | $table->string('token'); 17 | $table->timestamp('created_at')->nullable(); 18 | }); 19 | } 20 | 21 | /** 22 | * Reverse the migrations. 23 | */ 24 | public function down(): void 25 | { 26 | Schema::dropIfExists('password_reset_tokens'); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /back/database/migrations/2019_08_19_000000_create_failed_jobs_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->string('uuid')->unique(); 17 | $table->text('connection'); 18 | $table->text('queue'); 19 | $table->longText('payload'); 20 | $table->longText('exception'); 21 | $table->timestamp('failed_at')->useCurrent(); 22 | }); 23 | } 24 | 25 | /** 26 | * Reverse the migrations. 27 | */ 28 | public function down(): void 29 | { 30 | Schema::dropIfExists('failed_jobs'); 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /back/database/migrations/2024_02_22_131702_create_transaction_template_audio_names_table.php: -------------------------------------------------------------------------------- 1 | id(); 14 | $table->timestamps(); 15 | $table->unsignedBigInteger("transaction_template_id"); 16 | $table->string("name", 1000); 17 | $table->foreign('transaction_template_id')->references('id')->on('transaction_templates')->onDelete('cascade'); 18 | }); 19 | } 20 | 21 | 22 | public function down(): void 23 | { 24 | Schema::dropIfExists('transaction_template_audio_names'); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /back/database/migrations/2024_03_10_084308_create_tags_table.php: -------------------------------------------------------------------------------- 1 | id(); 16 | $table->timestamps(); 17 | $table->string("icon", 1000)->nullable(); 18 | $table->integer("parent_id")->nullable(); 19 | }); 20 | } 21 | 22 | /** 23 | * Reverse the migrations. 24 | */ 25 | public function down(): void 26 | { 27 | Schema::dropIfExists('tags'); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /back/database/migrations/2024_04_01_121800_add_is_todo_to_tags.php: -------------------------------------------------------------------------------- 1 | boolean("is_todo")->default(false); 13 | }); 14 | } 15 | 16 | 17 | public function down(): void 18 | { 19 | Schema::table('tags', function (Blueprint $table) { 20 | $table->dropColumn("is_todo"); 21 | }); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /back/database/migrations/2024_04_23_155844_rename_transaction_templates_audio_names.php: -------------------------------------------------------------------------------- 1 | boolean("is_dashboard_visible")->default(true); 14 | }); 15 | } 16 | 17 | 18 | public function down(): void 19 | { 20 | Schema::table('accounts', function (Blueprint $table) { 21 | $table->dropColumn("is_dashboard_visible"); 22 | }); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /back/database/migrations/2024_06_25_000000_create_profiles_table.php: -------------------------------------------------------------------------------- 1 | id(); 13 | $table->string("auth_token_hash")->unique(); 14 | $table->jsonb('settings')->nullable(); 15 | $table->timestamps(); 16 | }); 17 | } 18 | 19 | 20 | public function down(): void 21 | { 22 | Schema::dropIfExists('profiles'); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /back/database/migrations/2024_09_13_152958_create_budgets_table.php: -------------------------------------------------------------------------------- 1 | id(); 14 | $table->timestamps(); 15 | $table->string("icon", 1000)->nullable(); 16 | }); 17 | } 18 | 19 | 20 | public function down(): void 21 | { 22 | Schema::dropIfExists('budgets'); 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /back/database/seeders/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | create(); 16 | 17 | // \App\Models\User::factory()->create([ 18 | // 'name' => 'Test User', 19 | // 'email' => 'test@example.com', 20 | // ]); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /back/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "type": "module", 4 | "scripts": { 5 | "dev": "vite", 6 | "build": "vite build" 7 | }, 8 | "devDependencies": { 9 | "axios": "^1.1.2", 10 | "laravel-vite-plugin": "^0.8.0", 11 | "vite": "^4.0.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /back/public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Send Requests To Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /back/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/back/public/favicon.ico -------------------------------------------------------------------------------- /back/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /back/resources/css/app.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/back/resources/css/app.css -------------------------------------------------------------------------------- /back/resources/js/app.js: -------------------------------------------------------------------------------- 1 | import './bootstrap'; 2 | -------------------------------------------------------------------------------- /back/routes/channels.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 18 | }); 19 | -------------------------------------------------------------------------------- /back/routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 19 | })->purpose('Display an inspiring quote'); 20 | -------------------------------------------------------------------------------- /back/routes/web.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class)->bootstrap(); 18 | 19 | return $app; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /back/tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | get('/'); 16 | 17 | $response->assertStatus(200); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /back/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /back/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import laravel from 'laravel-vite-plugin'; 3 | 4 | export default defineConfig({ 5 | plugins: [ 6 | laravel({ 7 | input: ['resources/css/app.css', 'resources/js/app.js'], 8 | refresh: true, 9 | }), 10 | ], 11 | }); 12 | -------------------------------------------------------------------------------- /docker/conf/supervisor/cron.ini: -------------------------------------------------------------------------------- 1 | [program:cron] 2 | process_name=%(program_name)s_%(process_num)02d 3 | command=crond -f 4 | autostart=true 5 | autorestart=true 6 | user=root 7 | numprocs=1 8 | redirect_stderr=true 9 | stdout_logfile=/dev/stdout 10 | stdout_logfile_maxbytes=0 11 | stopwaitsecs=10 -------------------------------------------------------------------------------- /docker/conf/supervisor/nginx.ini: -------------------------------------------------------------------------------- 1 | [program:nginx] 2 | process_name=%(program_name)s_%(process_num)02d 3 | command=/usr/sbin/nginx -g "daemon off;" 4 | autostart=true 5 | autorestart=true 6 | user=root 7 | redirect_stderr=true 8 | stdout_logfile=/dev/stdout 9 | stdout_logfile_maxbytes=0 10 | stopwaitsecs=10 -------------------------------------------------------------------------------- /docker/conf/supervisor/node.ini: -------------------------------------------------------------------------------- 1 | [program:node] 2 | process_name=%(program_name)s_%(process_num)02d 3 | directory=/var/www/html/front 4 | command=npm run prod 5 | autostart=true 6 | autorestart=true 7 | redirect_stderr=true 8 | stdout_logfile=/dev/stdout 9 | stdout_logfile_maxbytes=0 10 | stopwaitsecs=10 -------------------------------------------------------------------------------- /docker/conf/supervisor/php-fpm.ini: -------------------------------------------------------------------------------- 1 | [program:php-fpm] 2 | process_name=%(program_name)s_%(process_num)02d 3 | command=/usr/sbin/php-fpm82 --nodaemonize 4 | autostart=true 5 | autorestart=true 6 | user=root 7 | redirect_stderr=true 8 | stdout_logfile=/dev/stdout 9 | stdout_logfile_maxbytes=0 10 | stopwaitsecs=10 -------------------------------------------------------------------------------- /docker/conf/supervisor/supervisord.conf: -------------------------------------------------------------------------------- 1 | [unix_http_server] 2 | file=/run/supervisord.sock ; the path to the socket file 3 | [supervisord] 4 | logfile=/var/log/supervisord.log ; main log file; default $CWD/supervisord.log 5 | pidfile=/run/supervisord.pid ; supervisord pidfile; default supervisord.pid 6 | nodaemon=true ; start in foreground if true; default false 7 | user=root ; setuid to this UNIX account at startup; recommended if root 8 | [rpcinterface:supervisor] 9 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface 10 | [supervisorctl] 11 | serverurl=unix:///run/supervisord.sock ; use a unix:// URL for a unix socket 12 | [include] 13 | files = /etc/supervisor.d/*.ini -------------------------------------------------------------------------------- /docs/attribution.md: -------------------------------------------------------------------------------- 1 | ## Credits 2 | 3 | - Developed by Mihai Cioraneanu 4 | - Using [Laravel](https://laravel.com/) and [Nuxt](https://nuxt.com/) 5 | - Consuming the [Firefly III](https://www.firefly-iii.org) REST API 6 | - With a UI theme based on [Vant](https://vant-ui.github.io) 7 | - Exchange rate by [Exchange Rate API](https://www.exchangerate-api.com) 8 | 9 | 10 | - IconPacks: [Tablr Icons](https://tabler.io/icons) 11 | - IconPacks: [Fluent UI System Icons](https://github.com/microsoft/fluentui) 12 | - IconPacks: [Circle Avatar Vectors by Laura Reen](https://www.svgrepo.com/author/Laura%20Reen) 13 | - IconPacks: [SVG Repo](https://www.svgrepo.com/) 14 | - Illustrations: [unDraw](https://undraw.co) 15 | 16 | If you enjoy Firefly-Pico please ⭐️ it on [GitHub](https://github.com/cioraneanu/firefly-pico). -------------------------------------------------------------------------------- /docs/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/docs/images/architecture.png -------------------------------------------------------------------------------- /docs/images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/docs/images/demo.gif -------------------------------------------------------------------------------- /docs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/docs/images/logo.png -------------------------------------------------------------------------------- /docs/images/logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/docs/images/logo2.png -------------------------------------------------------------------------------- /docs/images/presentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/docs/images/presentation.png -------------------------------------------------------------------------------- /front/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log* 3 | .nuxt 4 | .nitro 5 | .cache 6 | .output 7 | .env 8 | dist 9 | .idea 10 | -------------------------------------------------------------------------------- /front/.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | strict-peer-dependencies=false 3 | -------------------------------------------------------------------------------- /front/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": false, 4 | "bracketSpacing": true, 5 | "arrowParens": "always", 6 | "trailingComma": "all", 7 | "tabWidth": 2, 8 | "printWidth": 200, 9 | "endOfLine": "lf", 10 | "vueIndentScriptAndStyle": false 11 | } 12 | -------------------------------------------------------------------------------- /front/README.md: -------------------------------------------------------------------------------- 1 | ## Structure 2 | -------------------------------------------------------------------------------- /front/assets/icons/avatar/statistics-graph-svgrepo-com.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 10 | 11 | -------------------------------------------------------------------------------- /front/assets/icons/avatar/wallet-svgrepo-com.svg: -------------------------------------------------------------------------------- 1 | 2 | 70 Basic icons by Xicons.co -------------------------------------------------------------------------------- /front/assets/icons/custom/exchange.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/adhesive-plaster-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /front/assets/icons/duo/airbuds-case.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/alarm.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/archive-up-minimlistic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/atom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/bag-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/bag-5.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/bag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/balloon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/banknote.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/bar-chair.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/basketball.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/battery-charge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/bedside-table-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/bedside-table-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/bedside-table-4.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/bonfire.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/bowling.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/box.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/calendar-add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/card-recive.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/card-search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/card-send.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/card-transfer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/card.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/cardholder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/cash-out.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/chair.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/chandelier.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/clapperboard-text.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/closet-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/cloud-bolt-minimalistic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/code.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/colour-tuneing.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/cup.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/database.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/diagram-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/diskette.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/display.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/documents-minimalistic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /front/assets/icons/duo/dollar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/earth.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/end-call-rounded.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/euro.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/eye.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/fire.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/flag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/flame.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/fridge.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/ghost-smile.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/glasses.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/golf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/gps.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /front/assets/icons/duo/hanger-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/hanger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /front/assets/icons/duo/heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/history-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/home-angle-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/hourglass-line.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/incognito.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/iphone.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/ladle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/leaf.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/lock-keyhole.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/magnet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/magnifer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/map-arrow-up.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/map-point-wave.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/medical-kit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/men.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/microphone-large.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/microphone.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/money-bag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/mouse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/music-note-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/notification-unread-lines.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/oven-mitts.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/palette-round.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/paper-bin.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/pill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/planet-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/planet-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/presentation-graph.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/pulse-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/radio-minimalistic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /front/assets/icons/duo/scissors.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/sleeping.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/smart-speaker-minimalistic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/smart-vacuum-cleaner.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/snowflake.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/sofa-3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/sofa.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/speaker.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/square-academic-cap.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/stethoscope.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/stretching-round.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/suitcase-lines.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/suitcase.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/tag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/target.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /front/assets/icons/duo/temperature.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/tennis-2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/tennis.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/test-tube-minimalistic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/thermometer.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/tornado-small.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/tv.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /front/assets/icons/duo/user.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/washing-machine-minimalistic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /front/assets/icons/duo/waterdrop.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/duo/waterdrops.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/whisk.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/wineglass-triangle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /front/assets/icons/duo/women.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /front/assets/icons/flags/it.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/flags/ro.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/bike.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/building_24_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/building_bank_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/building_home_16_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/building_mosque_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/building_multiple_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/building_townhouse_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/chick.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/crown_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/desktop_sync_24_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/dishwasher_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/emoji_24_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/food_24_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/food_chicken_leg_16_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/food_pizza_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/glasses.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/home_garage_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/ice-cream.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/kid1.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/kid2.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/kid3.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/motorbike.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/pants.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/school.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/scooter.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/scooter2.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/shifts_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/shoe.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/stack_star_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/underwear.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/vehicle_bicycle_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/vehicle_car_profile_24_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/wallet_20_regular.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /front/assets/icons/fluent/wifi.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /front/components/charts/bar-chart-item-horizontal.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 27 | -------------------------------------------------------------------------------- /front/components/charts/bar-chart-item-vertical.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 22 | -------------------------------------------------------------------------------- /front/components/dashboard/dashboard-calendar/dashboard-calendar.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /front/components/dashboard/dashboard-summary/dashboard-summary-card.vue: -------------------------------------------------------------------------------- 1 | 14 | 26 | -------------------------------------------------------------------------------- /front/components/general/empty-list.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 13 | -------------------------------------------------------------------------------- /front/components/list-items/app-list-item.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 32 | -------------------------------------------------------------------------------- /front/components/select/budget/budget-period-select.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /front/components/select/budget/budget-type-select.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 22 | -------------------------------------------------------------------------------- /front/components/select/date-format-select.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | -------------------------------------------------------------------------------- /front/components/select/page-select.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 31 | -------------------------------------------------------------------------------- /front/components/settings/app-config-stat.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | -------------------------------------------------------------------------------- /front/components/transaction/transaction-split-badge.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | -------------------------------------------------------------------------------- /front/components/transaction/transaction-type-dot.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 27 | 28 | -------------------------------------------------------------------------------- /front/components/transaction/transaction-type-tabs.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 29 | -------------------------------------------------------------------------------- /front/components/ui-kit/app-checkbox.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 20 | 21 | 26 | -------------------------------------------------------------------------------- /front/components/ui-kit/app-chip.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 24 | -------------------------------------------------------------------------------- /front/components/ui-kit/app-field-link.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /front/components/ui-kit/app-icon.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 31 | 32 | -------------------------------------------------------------------------------- /front/components/ui-kit/app-loading.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /front/components/ui-kit/app-select-option.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /front/components/ui-kit/app-tab-bar-item.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /front/components/ui-kit/theme/app-button-form-delete.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /front/components/ui-kit/theme/app-button-list-add.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /front/components/ui-kit/theme/app-card-info.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /front/components/ui-kit/theme/app-list-search.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /front/composables/useFormAttributes.js: -------------------------------------------------------------------------------- 1 | export function useFormAttributes(attributes, customAttributes = {}) { 2 | const dynamicAttrs = computed(() => { 3 | let defaultAttributes = { 4 | 'label-align': 'top', 5 | 'placeholder': attributes?.label 6 | } 7 | return { ...defaultAttributes, ...attributes, ...customAttributes } 8 | }) 9 | 10 | return { 11 | dynamicAttrs, 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /front/constants/Constants.js: -------------------------------------------------------------------------------- 1 | export const REPO_URL = 'https://github.com/cioraneanu/firefly-pico/tags' 2 | -------------------------------------------------------------------------------- /front/constants/DashboardConstants.js: -------------------------------------------------------------------------------- 1 | export const dashboardCard = { 2 | calendar: { t: 'calendar', code: 'calendar', isVisible: true }, 3 | accounts: { t: 'settings.dashboard.cards.accounts_summary', code: 'accounts', isVisible: true }, 4 | expensesLastWeek: { t: 'settings.dashboard.cards.expenses_this_week', code: 'expensesLastWeek', isVisible: true }, 5 | transactionsSummary: { t: 'settings.dashboard.cards.transactions_summary', code: 'transactionSummary', isVisible: true }, 6 | budgets: { t: 'budgets', code: 'budgets', isVisible: true }, 7 | expensesByTag: { t: 'settings.dashboard.cards.expenses_by_tag', code: 'expensesByTag', isVisible: true }, 8 | expensesByCategory: { t: 'settings.dashboard.cards.expenses_by_category', code: 'expensesByCategory', isVisible: true }, 9 | todoTransactions: { t: 'settings.dashboard.cards.todo_transactions', code: 'todoTransactions', isVisible: true }, 10 | } 11 | 12 | export const dashboardCardList = Object.values(dashboardCard) 13 | -------------------------------------------------------------------------------- /front/constants/LanguageConstants.js: -------------------------------------------------------------------------------- 1 | export const LANGUAGE_ENGLISH = 'en-US' 2 | export const LANGUAGE_ROMANIAN = 'ro-RO' 3 | export const LANGUAGE_FRENCH = 'fr-FR' 4 | 5 | export const OPTION_ENGLISH = { code: LANGUAGE_ENGLISH, name: 'English', flag: 'en' } 6 | export const OPTION_ROMANIAN = { code: LANGUAGE_ROMANIAN, name: 'Romanian', flag: 'ro' } 7 | export const OPTION_FRENCH = { code: LANGUAGE_FRENCH, name: 'French', flag: 'fr' } 8 | 9 | export const OPTIONS_LIST = [OPTION_ENGLISH, OPTION_ROMANIAN, OPTION_FRENCH] 10 | -------------------------------------------------------------------------------- /front/constants/TutorialConstants.js: -------------------------------------------------------------------------------- 1 | export const TUTORIAL_CONSTANTS = { 2 | 3 | todoTag: { 4 | title: 'Todo Tag', 5 | body: ` 6 |

One of your Tags can be marked as your "todo". This is useful for knowing which transactions require some later edits and you easily keep an eye on them straight from the dashboard

7 |

Ex. If you're buying multiple items with the intent to keep only some of them and return the rest.

8 |

There can only be one "todo" tag so setting a second one will clear it from the first one.

9 | `, 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /front/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | import withNuxt from './.nuxt/eslint.config.mjs' 3 | 4 | export default withNuxt({ 5 | // rules: { 6 | // 'no-console': 'off', // allow console.log in TypeScript files 7 | // }, 8 | }) 9 | -------------------------------------------------------------------------------- /front/global.d.ts: -------------------------------------------------------------------------------- 1 | interface Array { 2 | uniqBy(field): T[]; 3 | } -------------------------------------------------------------------------------- /front/i18n/i18n.config.js: -------------------------------------------------------------------------------- 1 | export default defineI18nConfig(() => ({ 2 | legacy: false, 3 | locale: 'en', 4 | fallbackLocale: 'en', 5 | fallbackWarn: true, 6 | missingWarn: true, 7 | })) 8 | 9 | -------------------------------------------------------------------------------- /front/i18n/index.js: -------------------------------------------------------------------------------- 1 | // import { flags } from '~/constants/SvgConstants.js' 2 | 3 | export const languageCode = { 4 | english: 'en', 5 | romanian: 'ro', 6 | chinese: 'zh-CN', 7 | italian: 'it' 8 | } 9 | 10 | export const supportedLanguages = [ 11 | { 12 | code: languageCode.english, 13 | file: 'en.json', 14 | displayName: 'English', 15 | icon: 'svgo-flags-en', 16 | }, 17 | { 18 | code: languageCode.romanian, 19 | file: 'ro.json', 20 | displayName: 'Română', 21 | icon: 'svgo-flags-ro', 22 | }, 23 | { 24 | code: languageCode.chinese, 25 | file: 'zh-CN.json', 26 | displayName: '简体中文', 27 | icon: 'svgo-flags-cn', 28 | }, 29 | { 30 | code: languageCode.italian, 31 | file: 'it.json', 32 | displayName: 'Italiano', 33 | icon: 'svgo-flags-it', 34 | }, 35 | ] 36 | -------------------------------------------------------------------------------- /front/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | import { ref } from 'vue'; 10 | 11 | 22 | -------------------------------------------------------------------------------- /front/layouts/empty.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | import { ref } from 'vue'; 10 | 11 | 12 | -------------------------------------------------------------------------------- /front/models/BaseModel.js: -------------------------------------------------------------------------------- 1 | import _, { get } from 'lodash' 2 | 3 | export default class BaseModel { 4 | constructor() {} 5 | 6 | getEmpty() { 7 | throw 'Implement me' 8 | } 9 | 10 | getFake(id) { 11 | throw 'Implement me' 12 | } 13 | 14 | getFakeList() { 15 | let list = [] 16 | for (let i = 1; i <= 50; i++) { 17 | list.push(this.getFake(i)) 18 | } 19 | return { 20 | data: list, 21 | } 22 | } 23 | 24 | static getIcon(item) { 25 | return get(item, 'attributes.icon.icon') 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /front/models/Profile.js: -------------------------------------------------------------------------------- 1 | import BaseModel from '~/models/BaseModel' 2 | import ProfileTransformer from '~/transformers/ProfileTransformer' 3 | import ProfileRepository from '~/repository/ProfileRepository' 4 | 5 | class Profile extends BaseModel { 6 | getTransformer() { 7 | return ProfileTransformer 8 | } 9 | 10 | getRepository() { 11 | return new ProfileRepository() 12 | } 13 | 14 | getEmpty() { 15 | return {} 16 | } 17 | 18 | // ------------ 19 | 20 | getFake() { 21 | return {} 22 | } 23 | } 24 | 25 | export default Profile 26 | -------------------------------------------------------------------------------- /front/modules/register-components.js: -------------------------------------------------------------------------------- 1 | import { addComponent, defineNuxtModule } from '@nuxt/kit' 2 | // import icons from '../constants/TablerIconConstants' 3 | // import {IconPhone} from '@tabler/icons-vue' 4 | 5 | export default defineNuxtModule({ 6 | setup() { 7 | // addImports({ name: 'IconAngle', as: 'IconAngle', from: "@tabler/icons-vue" }) 8 | // addComponent({ 9 | // name: 'MyTest', 10 | // export: 'IconAngle', 11 | // filePath: '@tabler/icons-vue', 12 | // global: false 13 | // }) 14 | // addComponent({ 15 | // name: 'IconAnalyze', 16 | // export: 'IconAnalyze', 17 | // filePath: '@tabler/icons-vue', 18 | // global: true 19 | // }) 20 | // for (let icon of Object.values(icons)) { 21 | // 22 | // addComponent({ 23 | // name: icon, 24 | // export: icon, 25 | // filePath: '@tabler/icons-vue', 26 | // // global: true 27 | // }) 28 | // } 29 | }, 30 | }) 31 | -------------------------------------------------------------------------------- /front/pages/index.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 26 | -------------------------------------------------------------------------------- /front/pages/mihai.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /front/plugins/array-extension.js: -------------------------------------------------------------------------------- 1 | export default defineNuxtPlugin((nuxtApp) => { 2 | Array.prototype.uniqBy = function (field) { 3 | return [...new Map(this.map((item) => [item[field], item])).values()] 4 | } 5 | }) 6 | -------------------------------------------------------------------------------- /front/plugins/plugin-date-fns.js: -------------------------------------------------------------------------------- 1 | import { setDefaultOptions } from 'date-fns' 2 | import { ro, enUS, zhCN, it } from 'date-fns/locale' 3 | import { languageCode } from '~/i18n/index.js' 4 | 5 | export default defineNuxtPlugin((nuxtApp) => { 6 | watch( 7 | () => useProfileStore().weekStartsOn, 8 | (newValue) => { 9 | setDefaultOptions({ weekStartsOn: newValue }) 10 | }, 11 | { immediate: true }, 12 | ) 13 | 14 | watch( 15 | () => useProfileStore().language, 16 | (newValue) => { 17 | const dateFnsLocaleDictionary = { 18 | [languageCode.english]: enUS, 19 | [languageCode.romanian]: ro, 20 | [languageCode.chinese]: zhCN, 21 | [languageCode.italian]: it, 22 | } 23 | let dateFnsLocale = dateFnsLocaleDictionary[newValue] || enUS 24 | 25 | setDefaultOptions({ locale: dateFnsLocale }) 26 | }, 27 | { immediate: true }, 28 | ) 29 | }) 30 | -------------------------------------------------------------------------------- /front/plugins/plugin-i18n.js: -------------------------------------------------------------------------------- 1 | import { useI18n } from '#imports' 2 | import { useNuxtApp } from '#app' 3 | 4 | export default defineNuxtPlugin((nuxtApp) => { 5 | // const { setLocale } = useI18n() 6 | 7 | watch( 8 | () => useProfileStore().language, 9 | (newValue) => { 10 | nuxtApp.$i18n.setLocale(newValue) 11 | }, 12 | { immediate: true }, 13 | ) 14 | }) 15 | 16 | 17 | // Useful if we need translations in plain JS files (no components or composables) 18 | export const translate = (key) => useNuxtApp()?.$i18n?.t(key) 19 | -------------------------------------------------------------------------------- /front/plugins/plugin-vant.js: -------------------------------------------------------------------------------- 1 | // Vant theme related 2 | import '@vant/touch-emulator' 3 | 4 | // Vant locale related 5 | import { Locale } from 'vant' 6 | import enUS from 'vant/es/locale/lang/en-US' 7 | import ro from 'vant/es/locale/lang/ro-RO' 8 | import zhCN from 'vant/es/locale/lang/zh-CN' 9 | import italian from 'vant/es/locale/lang/it-IT' 10 | 11 | import { languageCode } from '~/i18n/index.js' 12 | 13 | export default defineNuxtPlugin((nuxtApp) => { 14 | watch( 15 | () => useProfileStore().language, 16 | (newValue) => { 17 | const localeDictionary = { 18 | [languageCode.english]: enUS, 19 | [languageCode.romanian]: ro, 20 | [languageCode.chinese]: zhCN, 21 | [languageCode.italian]: italian, 22 | } 23 | let locale = localeDictionary[newValue] || enUS 24 | Locale.use(newValue, locale) 25 | }, 26 | { immediate: true }, 27 | ) 28 | }) 29 | -------------------------------------------------------------------------------- /front/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/front/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /front/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/front/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /front/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/front/public/apple-touch-icon.png -------------------------------------------------------------------------------- /front/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /front/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/front/public/favicon-16x16.png -------------------------------------------------------------------------------- /front/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/front/public/favicon-32x32.png -------------------------------------------------------------------------------- /front/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/front/public/favicon.ico -------------------------------------------------------------------------------- /front/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cioraneanu/firefly-pico/3f97e0b24ecf642cb4835bee62a01c062e36db0c/front/public/mstile-150x150.png -------------------------------------------------------------------------------- /front/public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /front/repository/AccountRepository.js: -------------------------------------------------------------------------------- 1 | import BaseRepository from '~/repository/BaseRepository' 2 | import axios from 'axios' 3 | import _ from 'lodash' 4 | import { useProfileStore } from '~/stores/profileStore' 5 | import { useDataStore } from '~/stores/dataStore' 6 | 7 | class AccountRepository extends BaseRepository { 8 | constructor() { 9 | super('api/accounts') 10 | } 11 | } 12 | 13 | export default AccountRepository 14 | -------------------------------------------------------------------------------- /front/repository/BudgetRepository.js: -------------------------------------------------------------------------------- 1 | import BaseRepository from '~/repository/BaseRepository' 2 | import axios from 'axios' 3 | import _ from 'lodash' 4 | 5 | export default class BudgetRepository extends BaseRepository { 6 | constructor() { 7 | super(`api/budgets`) 8 | } 9 | 10 | async getBudgetLimits() { 11 | const appStore = useAppStore() 12 | let response = await axios.get(`${appStore.picoBackendURL}/api/budget-limits`) 13 | return _.get(response, 'data', {}) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /front/repository/CategoryRepository.js: -------------------------------------------------------------------------------- 1 | import BaseRepository from '~/repository/BaseRepository' 2 | 3 | class CategoryRepository extends BaseRepository { 4 | constructor() { 5 | super(`api/categories`) 6 | } 7 | } 8 | 9 | export default CategoryRepository 10 | -------------------------------------------------------------------------------- /front/repository/CurrencyRepository.js: -------------------------------------------------------------------------------- 1 | import BaseRepository from '~/repository/BaseRepository' 2 | import axios from 'axios' 3 | import _, { get } from 'lodash' 4 | 5 | class CurrencyRepository extends BaseRepository { 6 | constructor() { 7 | super(`api/currencies`) 8 | } 9 | 10 | async update(id, data) { 11 | return await axios.put(`${this.getUrl()}/${data.code}`, data) 12 | } 13 | 14 | async delete(id) { 15 | let dataStore = useDataStore() 16 | let currencyCode = dataStore.currencyDictionary[id]?.attributes?.code 17 | return await axios.delete(`${this.getUrl()}/${currencyCode}`) 18 | } 19 | 20 | async getCurrencyExchange() { 21 | const appStore = useAppStore() 22 | const url = `${appStore.picoBackendURL}/api/currencies/exchange` 23 | let response = await axios.get(url) 24 | return _.get(response, 'data', {}) 25 | } 26 | } 27 | 28 | export default CurrencyRepository 29 | -------------------------------------------------------------------------------- /front/repository/InfoRepository.js: -------------------------------------------------------------------------------- 1 | import BaseRepository from '~/repository/BaseRepository' 2 | import axios from 'axios' 3 | 4 | export default class InfoRepository extends BaseRepository { 5 | constructor() { 6 | super('api/latest-version') 7 | } 8 | 9 | async getLatestVersion() { 10 | return await axios.get(`${this.getUrl()}`) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /front/repository/ProfileRepository.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import BaseRepository from '~/repository/BaseRepository' 3 | import _ from 'lodash' 4 | 5 | class ProfileRepository extends BaseRepository { 6 | constructor() { 7 | super('api/profile') 8 | } 9 | 10 | async getProfile() { 11 | let result = await axios.get(`${this.getUrl()}`) 12 | return _.get(result, 'data', {}) 13 | } 14 | 15 | async writeProfile(data) { 16 | let result = await axios.put(`${this.getUrl()}`, data) 17 | return result 18 | } 19 | } 20 | 21 | export default ProfileRepository 22 | -------------------------------------------------------------------------------- /front/repository/TagRepository.js: -------------------------------------------------------------------------------- 1 | import BaseRepository from '~/repository/BaseRepository' 2 | 3 | class CategoryRepository extends BaseRepository { 4 | constructor() { 5 | super('api/tags') 6 | } 7 | } 8 | 9 | export default CategoryRepository 10 | -------------------------------------------------------------------------------- /front/repository/TransactionRepository.js: -------------------------------------------------------------------------------- 1 | import BaseRepository from '~/repository/BaseRepository' 2 | import axios from 'axios' 3 | import _ from 'lodash' 4 | 5 | class TransactionRepository extends BaseRepository { 6 | constructor() { 7 | super(`api/transactions`) 8 | this.searchTransaction = this.searchTransaction.bind(this) 9 | } 10 | 11 | 12 | async searchTransaction({ filters = [], page = 1, pageSize = 50 } = {}) { 13 | const appStore = useAppStore() 14 | const url = `${appStore.picoBackendURL}/api/search/transactions` 15 | let searchUrl = this.getUrlForRequest({ filters, page, pageSize, url }) 16 | let response = await axios.get(searchUrl) 17 | return _.get(response, 'data', {}) 18 | } 19 | } 20 | 21 | export default TransactionRepository 22 | -------------------------------------------------------------------------------- /front/repository/TransactionTemplateRepository.js: -------------------------------------------------------------------------------- 1 | import BaseRepository from '~/repository/BaseRepository' 2 | import axios from 'axios' 3 | import _ from 'lodash' 4 | 5 | class TransactionTemplateRepository extends BaseRepository { 6 | constructor() { 7 | super(`api/transaction-templates`) 8 | } 9 | 10 | // async getOne (id) { 11 | // // const baseURL = this.getBaseUrl() 12 | // let result = await axios.get(`${this.endpoint}/${id}`) 13 | // return _.get(result, 'data', {}) 14 | // } 15 | // 16 | // async getAll ({ filters = [], page = 1, pageSize = 10 } = {}) { 17 | // let url = this.getUrlForRequest({ filters, page, pageSize }) 18 | // let response = await axios.get(url) 19 | // return _.get(response, 'data', {}) 20 | // } 21 | } 22 | 23 | export default TransactionTemplateRepository 24 | -------------------------------------------------------------------------------- /front/repository/UserRepository.js: -------------------------------------------------------------------------------- 1 | import BaseRepository from '~/repository/BaseRepository' 2 | import axios from 'axios' 3 | 4 | export default class UserRepository extends BaseRepository { 5 | constructor() { 6 | super('api/user') 7 | } 8 | 9 | async getUser() { 10 | return await axios.get(`${this.getUrl()}`) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /front/transformers/CurrencyTransformer.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import DateUtils from '~/utils/DateUtils' 3 | import Account from '~/models/Account' 4 | import Utils from '~/utils/Utils' 5 | import ApiTransformer from '~/transformers/ApiTransformer' 6 | 7 | export default class CurrencyTransformer extends ApiTransformer { 8 | static transformFromApi(item) { 9 | if (!item) { 10 | return null 11 | } 12 | return item 13 | } 14 | 15 | static transformToApi(item) { 16 | if (!item) { 17 | return null 18 | } 19 | 20 | let data = _.get(item, 'attributes') 21 | let result = _.pick(data, ['name', 'code', 'symbol', 'decimal_places', 'enabled', 'default']) 22 | 23 | return result 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /front/transformers/ProfileTransformer.js: -------------------------------------------------------------------------------- 1 | import ApiTransformer from '~/transformers/ApiTransformer' 2 | 3 | export default class ProfileTransformer extends ApiTransformer { 4 | static transformFromApi(item) { 5 | if (!item) { 6 | return null 7 | } 8 | 9 | return item.settings 10 | } 11 | 12 | static transformToApi(item) { 13 | if (!item) { 14 | return null 15 | } 16 | 17 | return { 18 | settings: item, 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /front/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /front/utils/LanguageUtils.js: -------------------------------------------------------------------------------- 1 | export default class LanguageUtils { 2 | static removeAccents(text) { 3 | if (!text) { 4 | return '' 5 | } 6 | return text 7 | .normalize('NFD') 8 | .replace(/[\u0300-\u036f]/g, '') 9 | } 10 | 11 | static removeAccentsAndLowerCase(text) { 12 | text = LanguageUtils.removeAccents(text) 13 | text = LanguageUtils.lowercase(text) 14 | return text 15 | } 16 | 17 | static lowercase(text) { 18 | if (!text) { 19 | return '' 20 | } 21 | return text.toLowerCase() 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /front/utils/NumberUtils.js: -------------------------------------------------------------------------------- 1 | export const NUMBER_FORMAT = { 2 | eu: { name: '1234.56 -> 1.234,56', code: 'de-DE' }, 3 | international: { name: '1234.56 -> 1,234.56', code: 'en-EN' }, 4 | } 5 | 6 | export const formatNumber = (value, digits) => { 7 | const profileStore = useProfileStore() 8 | let numberFormatCode = profileStore.numberFormat.code ?? NUMBER_FORMAT.eu.code 9 | 10 | return new Intl.NumberFormat(numberFormatCode, { 11 | minimumFractionDigits: digits, 12 | maximumFractionDigits: digits, 13 | }).format(value) 14 | } 15 | 16 | export const formatNumberForDashboard = (value) => { 17 | const profileStore = useProfileStore() 18 | if (!profileStore.dashboard.showAccountAmounts) { 19 | return '******' 20 | } 21 | let digits = profileStore.dashboard.showDecimal ? 2 : 0 22 | return formatNumber(value, digits) 23 | } 24 | -------------------------------------------------------------------------------- /front/utils/ResponseUtils.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | const STATUS_CODE_SUCCESS = 200 3 | const STATUS_CODE_SUCCESS_DELETE = 204 4 | 5 | export default class ResponseUtils { 6 | static isSuccess(response) { 7 | const responseStatus = _.get(response, 'status', ' - ') 8 | const successCodesList = [STATUS_CODE_SUCCESS, STATUS_CODE_SUCCESS_DELETE] 9 | return successCodesList.includes(responseStatus) 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /front/utils/SettingUtils.js: -------------------------------------------------------------------------------- 1 | import { set, get } from 'lodash' 2 | import { watch } from 'vue' 3 | 4 | export function saveSettingsToStore(settingsList) { 5 | for (let setting of settingsList) { 6 | let { store, path, ref } = setting 7 | set(store, path, ref.value) 8 | } 9 | } 10 | 11 | export function saveSettingsToLocal(settingsList) { 12 | for (let setting of settingsList) { 13 | let { store, path, ref } = setting 14 | ref.value = get(store, path) 15 | } 16 | } 17 | 18 | export function watchSettingsStore(settingsList) { 19 | let watchList = () => 20 | settingsList.reduce((result, setting) => { 21 | let { store, path, ref } = setting 22 | result = [...result, get(store, path)] 23 | return result 24 | }, []) 25 | 26 | watch(watchList, () => saveSettingsToLocal(settingsList), { immediate: true }) 27 | } 28 | -------------------------------------------------------------------------------- /front/utils/Utils.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | export default class UIUtils { 4 | static getGUID() { 5 | return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) => (c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)) 6 | } 7 | 8 | static updateListWithNewItems(list, newItems) { 9 | newItems = _.isArray(newItems) ? newItems : [newItems] 10 | let newItemIds = newItems.map((item) => item.id) 11 | let initialListFiltered = list.filter((item) => !newItemIds.includes(item.id)) 12 | return [...newItems, ...initialListFiltered] 13 | } 14 | 15 | static stringToData(item, path, list) { 16 | const type = _.get(item, path) 17 | const convertedType = list.find((accountType) => accountType.code === type) 18 | _.set(item, path, convertedType) 19 | } 20 | } 21 | 22 | export function ellipsizeText(text = '', maxLength = 100) { 23 | return text.length > maxLength ? `${text.slice(0, maxLength)}...` : text 24 | } 25 | -------------------------------------------------------------------------------- /front/utils/ValidationUtils.js: -------------------------------------------------------------------------------- 1 | export const rule = { 2 | 3 | // TODO: Interpolate fieldName into the message. The field name should be translated as well. Ex. The "description" field is required. 4 | required: (fieldName) => { 5 | const { t } = useI18n() 6 | return { required: true, message: t('validation.required') } 7 | }, 8 | 9 | } 10 | --------------------------------------------------------------------------------