diff --git a/.env.example b/.env.example index 5e08ea24..b144a286 100644 --- a/.env.example +++ b/.env.example @@ -12,4 +12,9 @@ SMTP_ADDRESS= SMTP_PORT=465 SMTP_USERNAME= SMTP_PASSWORD= -TLS=true \ No newline at end of file +TLS=true + +# Database Configuration +DB_HOST=localhost +POSTGRES_PASSWORD=postgres +POSTGRES_USER=postgres \ No newline at end of file diff --git a/.gitignore b/.gitignore index 763dc3f6..7d98173a 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,10 @@ # Ignore Jetbrains IDEs .idea + +# Ignore macOS specific files +*/.DS_Store +.DS_Store + +# Ignore .devcontainer files +compose-dev.yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 61209a3d..aab5f572 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,12 +2,39 @@ It means so much that you're interested in contributing to Maybe! Seriously. Thank you. The entire community benefits from these contributions! -Before submitting a new issue or PR, check if it already exists in [issues](https://github.com/maybe-finance/maybe/issues) or [PRs](https://github.com/maybe-finance/maybe/pulls) so you have an idea of where things stand. +## House Rules -Then, once you're ready to begin work, submit a draft PR with your high-level plan (or the full solution). +- Before contributing, please check if it already exists in [issues](https://github.com/maybe-finance/maybe/issues) or [PRs](https://github.com/maybe-finance/maybe/pulls) +- Given the speed at which we're moving on the codebase, we don't assign issues or "give" issues to anyone. +- When multiple PRs are submitted for the same issue, we take the one that most succinctly & efficiently solves a given problem and stays within the scope of work. +- Priority is generally given to previous committers as they've proven familiarity with the codebase and product. -Given the speed at which we're moving on the codebase, we don't assign issues or "give" issues to anyone. +## What should I contribute? -When multiple PRs are submitted for the same issue, we take the one that most succinctly & efficiently solves a given problem and stays within the scope of work. +As we are still in the early days of this project, we recommend [heading over to the Wiki](https://github.com/maybe-finance/maybe/wiki) to get a better idea of _what_ to contribute. -Priority is also generally given to previous committers as they've proven familiarity with the codebase and product. +In general, _full features_ that get us closer to [our Vision](https://github.com/maybe-finance/maybe/wiki/Vision) are the most valuable contributions at this stage. + +## Development + +### Setup + +To get setup for local development, you have two options: + +1. [Dev Containers](https://code.visualstudio.com/docs/devcontainers/containers) with VSCode (see the `.devcontainer` folder) +2. Local Development + - [Mac Setup Guide](https://github.com/maybe-finance/maybe/wiki/Mac-Dev-Setup-Guide) + - [Linux Setup Guide](https://github.com/maybe-finance/maybe/wiki/Linux-Dev-Setup-Guide) + - [Windows Setup Guide](https://github.com/maybe-finance/maybe/wiki/Windows-Dev-Setup-Guide) + +### Making a Pull Request + +1. Fork the repo +2. Create your feature branch (`git checkout -b my-new-feature`) +3. Commit your changes (`git commit -am 'Add some feature'`) +4. Push to the branch (`git push origin my-new-feature`) +5. Create new Pull Request, and be sure to check the [Allow edits from maintainers](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) option while creating your PR. This allows maintainers to collaborate with you on your PR if needed. +6. If possible, [link your pull request to an issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword) by adding the appropriate keyword (e.g. `fixes issue #XXX`) +7. Before requesting a review, please make sure that all [Github Checks](https://docs.github.com/en/rest/checks?apiVersion=2022-11-28) have passed and your branch is up-to-date with the `main` branch. After doing so, request a review and wait for a maintainer's approval. + +All PRs should target the `main` branch. diff --git a/Gemfile b/Gemfile index f6e21c12..42d78dd4 100644 --- a/Gemfile +++ b/Gemfile @@ -20,7 +20,7 @@ gem "tailwindcss-rails" # Hotwire gem "stimulus-rails" -gem "turbo-rails", github: "hotwired/turbo-rails", branch: "main" +gem "turbo-rails" # Other gem "bcrypt", "~> 3.1.7" @@ -33,7 +33,7 @@ group :development, :test do gem "debug", platforms: %i[ mri windows ] gem "brakeman", require: false gem "rubocop-rails-omakase", require: false - gem "dotenv" + gem "dotenv-rails" gem "letter_opener" gem "i18n-tasks" end diff --git a/Gemfile.lock b/Gemfile.lock index 6efd9773..e3bf36b1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,16 +1,6 @@ -GIT - remote: https://github.com/hotwired/turbo-rails.git - revision: 3748512710a29b541a1f2b3863cc6fb2422fb7e2 - branch: main - specs: - turbo-rails (2.0.0.pre.rc.2) - actionpack (>= 6.0.0) - activejob (>= 6.0.0) - railties (>= 6.0.0) - GIT remote: https://github.com/rails/rails.git - revision: 554e5c2d8e8dd9f9e302a2d11c775f14c512d957 + revision: f0d433bb46ac233ec7fd7fae48f458978908d905 branch: main specs: actioncable (7.2.0.alpha) @@ -143,6 +133,9 @@ GEM irb (~> 1.10) reline (>= 0.3.8) dotenv (2.8.1) + dotenv-rails (2.8.1) + dotenv (= 2.8.1) + railties (>= 3.2) drb (2.2.0) ruby2_keywords erubi (1.12.0) @@ -352,6 +345,10 @@ GEM unicode-display_width (>= 1.1.1, < 3) thor (1.3.0) timeout (0.4.1) + turbo-rails (2.0.0) + actionpack (>= 6.0.0) + activejob (>= 6.0.0) + railties (>= 6.0.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) @@ -384,7 +381,7 @@ DEPENDENCIES brakeman capybara debug - dotenv + dotenv-rails hotwire-livereload i18n-tasks importmap-rails @@ -402,7 +399,7 @@ DEPENDENCIES selenium-webdriver stimulus-rails tailwindcss-rails - turbo-rails! + turbo-rails tzinfo-data web-console diff --git a/Procfile.dev b/Procfile.dev index da151fee..7410150c 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,2 +1,2 @@ -web: bin/rails server +web: bin/rails server -b 0.0.0.0 css: bin/rails tailwindcss:watch diff --git a/README.md b/README.md index 769396dd..57e654e3 100644 --- a/README.md +++ b/README.md @@ -26,22 +26,16 @@ We're now building the app in Ruby on Rails. We realize that's a controversial c From the start our focus with this is to make it as easy as possible for you to both contribute to and deploy the app, and this move to Rails is a big part of that. -## Codebase +## Local Development Setup -The codebase is vanilla [Rails](https://rubyonrails.org/) and [Postgres](https://www.postgresql.org/). Quite a simple setup. +### Requirements -## Setup +- Ruby >3 (see `Gemfile`) +- PostgreSQL >9.3 (ideally, latest stable version) -You'll need: +After cloning the repo, the basic setup commands are: -- ruby >3 (specific version is in `Gemfile`) -- postgresql (if using stock `config/database.yml`) - -If you prefer devcontainer, this project supports it (entirely optional). - -Run the following commands after cloning the repo: - -```shell +```sh cd maybe cp .env.example .env bundle install @@ -49,33 +43,48 @@ rails db:setup bin/dev ``` -And visit [http://localhost:3000](http://localhost:3000) +And visit http://localhost:3000 to see the app. You can use the following credentials to log in (generated by DB seed): -### Email +Email: user@maybe.local +Password: password -In development, we use `letter_opener` to automatically open emails in your browser. However, if you self-host, you'll likely want some basic email sending abilities. +For further instructions, see guides below. -You can use any SMTP-based mail service and then simply drop in your SMTP credentials in the `.env` file. +### Setup Guides -[Resend](https://resend.com) is a great option for personal use as they have a very generous free plan. +#### Dev Container (optional) + +This is 100% optional and meant for devs who don't want to worry about installing requirements manually for their platform. You can follow [this guide](https://code.visualstudio.com/docs/devcontainers/containers) to learn more about Dev Containers. + +#### Mac + +Please visit our [Mac dev setup guide](https://github.com/maybe-finance/maybe/wiki/Mac-Dev-Setup-Guide). + +#### Linux + +Please visit our [Linux dev setup guide](https://github.com/maybe-finance/maybe/wiki/Linux-Dev-Setup-Guide). + +#### Windows + +Please visit our [Windows dev setup guide](https://github.com/maybe-finance/maybe/wiki/Windows-Dev-Setup-Guide). + +### Testing Emails + +In development, we use `letter_opener` to automatically open emails in your browser. When an email sends locally, a new browser tab will open with a preview. ## Contributing Before contributing, you'll likely find it helpful to [understand context and general vision/direction](https://github.com/maybe-finance/maybe/wiki). -It's still very early days for this so your mileage will vary here and lots of things will break. +Once you've done that, please visit our [contributing guide](https://github.com/maybe-finance/maybe/blob/main/CONTRIBUTING.md) to get started! -But almost any contribution will be beneficial at this point. Check the [current Issues](https://github.com/maybe-finance/maybe/issues) to see where you can jump in! +## Self Hosting -If you've got an improvement, just send in a pull request! +Our long term goal is to make self-hosting as easy as possible. That said, during these early stages of building the product, we are focusing our efforts on development. -1. Fork it -2. Create your feature branch (`git checkout -b my-new-feature`) -3. Commit your changes (`git commit -am 'Add some feature'`) -4. Push to the branch (`git push origin my-new-feature`) -5. Create new Pull Request +We will update this section as we get closer to an initial release. -If you've got feature ideas, simply [open a new issue](https://github.com/maybe-finance/maybe/issues/new)! +Please see our [guide on self hosting here](https://github.com/maybe-finance/maybe/wiki/Self-Hosting-Setup-Guide). ## Repo Activity diff --git a/app/helpers/accounts_helper.rb b/app/helpers/accounts_helper.rb index 17850b4b..0673bf2a 100644 --- a/app/helpers/accounts_helper.rb +++ b/app/helpers/accounts_helper.rb @@ -1,2 +1,5 @@ module AccountsHelper + def to_accountable_title(accountable) + accountable.model_name.human + end end diff --git a/app/models/account/investment.rb b/app/models/account/investment.rb index 57bdfcf8..87675da6 100644 --- a/app/models/account/investment.rb +++ b/app/models/account/investment.rb @@ -1,3 +1,15 @@ class Account::Investment < ApplicationRecord include Accountable + + SUBTYPES = [ + [ "Brokerage", "brokerage" ], + [ "Pension", "pension" ], + [ "Retirement", "retirement" ], + [ "401(k)", "401k" ], + [ "529 plan", "529_plan" ], + [ "Health Savings Account", "hsa" ], + [ "Mutual Fund", "mutual_fund" ], + [ "Roth IRA", "roth_ira" ], + [ "Roth 401k", "roth_401k" ] + ].freeze end diff --git a/app/views/accounts/account/_investment.html.erb b/app/views/accounts/account/_investment.html.erb index e69de29b..6310d930 100644 --- a/app/views/accounts/account/_investment.html.erb +++ b/app/views/accounts/account/_investment.html.erb @@ -0,0 +1,4 @@ +
+ + <%= f.select :subtype, options_for_select(Account::Investment::SUBTYPES, selected: ""), {}, class: "block w-full p-0 mt-1 bg-transparent border-none focus:outline-none focus:ring-0" %> +
diff --git a/app/views/accounts/index.html.erb b/app/views/accounts/index.html.erb index ef727457..34bc5672 100644 --- a/app/views/accounts/index.html.erb +++ b/app/views/accounts/index.html.erb @@ -3,14 +3,14 @@

<%#= number_to_currency Current.family.cash_balance %>

<% Current.family.accounts.each do |account| %> -
-
+
+
<%= account.name %>
-
- <%= account.accountable.model_name.human %> +
+ <%= to_accountable_title(account.accountable) %>
-

+

<%= humanized_money_with_symbol account.balance %>

diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 80628e29..fd46221a 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -56,8 +56,10 @@
- <%= t('.accounts') %> - <%= link_to new_account_path, class: 'block hover:bg-gray-100 p-2 text-sm font-semibold text-gray-900 flex items-center rounded', title: t('.new_accoount') do %> + <%= link_to accounts_path, class: 'text-xs' do%> + <%= t('.accounts') %> + <% end %> + <%= link_to new_account_path, class: 'block hover:bg-gray-100 p-2 text-sm font-semibold text-gray-900 flex items-center rounded', title: t('.new_account') do %> <%= inline_svg_tag('icon-add.svg', class: 'text-gray-500 fill-current') %> <% end %>
diff --git a/app/views/settings/edit.html.erb b/app/views/settings/edit.html.erb index 145ec171..14a5e9d4 100644 --- a/app/views/settings/edit.html.erb +++ b/app/views/settings/edit.html.erb @@ -3,34 +3,34 @@ <%= form_with model: Current.user, url: settings_path, html: { class: "space-y-4" } do |form| %> <%= form.fields_for :family_attributes do |family_fields| %>
- <%= family_fields.label :name, "Family name", class: "block text-sm font-medium opacity-50 focus-within:opacity-100" %> + <%= family_fields.label :name, "Family name", class: "block text-sm font-medium opacity-75 focus-within:opacity-100" %> <%= family_fields.text_field :name, placeholder: "Family name", value: Current.family.name, class: "p-0 mt-1 bg-transparent border-none opacity-50 focus:outline-none focus:ring-0 focus-within:opacity-100" %>
<% end %>
- <%= form.label :first_name, class: "block text-sm font-medium opacity-50 focus-within:opacity-100" %> + <%= form.label :first_name, class: "block text-sm font-medium opacity-75 focus-within:opacity-100" %> <%= form.text_field :first_name, placeholder: "First name", value: Current.user.first_name, class: "w-full p-0 mt-1 bg-transparent border-none opacity-50 focus:outline-none focus:ring-0 focus-within:opacity-100" %>
- <%= form.label :last_name, class: "block text-sm font-medium opacity-50 focus-within:opacity-100" %> + <%= form.label :last_name, class: "block text-sm font-medium opacity-75 focus-within:opacity-100" %> <%= form.text_field :last_name, placeholder: "Last name", value: Current.user.last_name, class: "w-full p-0 mt-1 bg-transparent border-none opacity-50 focus:outline-none focus:ring-0 focus-within:opacity-100" %>
- <%= form.label :email, class: "block text-sm font-medium opacity-50 focus-within:opacity-100" %> + <%= form.label :email, class: "block text-sm font-medium opacity-75 focus-within:opacity-100" %> <%= form.email_field :email, placeholder: "Email", value: Current.user.email, class: "w-full p-0 mt-1 bg-transparent border-none opacity-50 focus:outline-none focus:ring-0 focus-within:opacity-100" %>
- <%= form.label :password, class: "block text-sm font-medium opacity-50 focus-within:opacity-100" %> + <%= form.label :password, class: "block text-sm font-medium opacity-75 focus-within:opacity-100" %> <%= form.password_field :password, class: "w-full p-0 mt-1 bg-transparent border-none opacity-50 focus:outline-none focus:ring-0 focus-within:opacity-100" %>
- <%= form.label :password_confirmation, class: "block text-sm font-medium opacity-50 focus-within:opacity-100" %> + <%= form.label :password_confirmation, class: "block text-sm font-medium opacity-75 focus-within:opacity-100" %> <%= form.password_field :password_confirmation, class: "w-full p-0 mt-1 bg-transparent border-none opacity-50 focus:outline-none focus:ring-0 focus-within:opacity-100" %>
diff --git a/config/locales/views/layout/en.yml b/config/locales/views/layout/en.yml index 85310a0f..780891a5 100644 --- a/config/locales/views/layout/en.yml +++ b/config/locales/views/layout/en.yml @@ -5,7 +5,7 @@ en: accounts: Accounts cash: Cash dashboard: Dashboard - new_accoount: New Account + new_account: New Account auth: or: or privacy_policy: Privacy Policy diff --git a/db/migrate/20240206031739_replace_money_field.rb b/db/migrate/20240206031739_replace_money_field.rb index dfe2b732..4c5ef9db 100644 --- a/db/migrate/20240206031739_replace_money_field.rb +++ b/db/migrate/20240206031739_replace_money_field.rb @@ -6,7 +6,7 @@ class ReplaceMoneyField < ActiveRecord::Migration[7.2] Account.reset_column_information Account.find_each do |account| - account.update_columns(balance_cents: Money.from_amount(account.balance, account.currency).cents) + account.update_columns(balance_cents: Money.from_amount(account.balance_in_database, account.currency).cents) end remove_column :accounts, :balance diff --git a/db/seeds.rb b/db/seeds.rb index 4fbd6ed9..396593bd 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -7,3 +7,11 @@ # ["Action", "Comedy", "Drama", "Horror"].each do |genre_name| # MovieGenre.find_or_create_by!(name: genre_name) # end + +# Create the default user +family = Family.create_or_find_by!(name: "The Maybe Family") +puts "Family created: #{family.name}" +user = User.create_or_find_by!( + first_name: "Josh", last_name: "Maybe", email: "user@maybe.local", + password: "password", password_confirmation: "password", family_id: family.id) +puts "User created: #{user.email} for family: #{family.name}" diff --git a/test/helpers/application_helper_test.rb b/test/helpers/application_helper_test.rb new file mode 100644 index 00000000..14fafe8e --- /dev/null +++ b/test/helpers/application_helper_test.rb @@ -0,0 +1,19 @@ +require "test_helper" + +class ApplicationHelperTest < ActionView::TestCase + test "#title(page_title)" do + title("Test Title") + assert_equal "Test Title", content_for(:title) + end + + test "#header_title(page_title)" do + header_title("Test Header Title") + assert_equal "Test Header Title", content_for(:header_title) + end + + test "#permitted_accountable_partial(accountable_type)" do + assert_equal "account", permitted_accountable_partial("Account") + assert_equal "user", permitted_accountable_partial("User") + assert_equal "admin_user", permitted_accountable_partial("AdminUser") + end +end diff --git a/test/system/accounts_test.rb b/test/system/accounts_test.rb index 030cb87d..9c4401fe 100644 --- a/test/system/accounts_test.rb +++ b/test/system/accounts_test.rb @@ -5,14 +5,16 @@ class AccountsTest < ApplicationSystemTestCase sign_in @user = users(:bob) end - # test "should create account" do - # click_on "New account" - # click_on "Credit Card" - # within "form" do - # fill_in "Name", with: "VISA" - # fill_in "Balance", with: "1000" - # click_on "Submit" - # end - # assert_text "$1,000" - # end + test "should create account" do + skip("Disabling this test for now, UI is changing to quickly to do systems testing") + + click_on "New account" + click_on "Credit Card" + within "form" do + fill_in "Name", with: "VISA" + fill_in "Balance", with: "1000" + click_on "Submit" + end + assert_text "$1,000" + end end