Skip to content

Commit

Permalink
Merge pull request #2 from deyemiobaa/dev
Browse files Browse the repository at this point in the history
Rails budget app
  • Loading branch information
deyemiobaa authored Aug 14, 2022
2 parents 396acfa + 58c2f7d commit a5b127e
Show file tree
Hide file tree
Showing 68 changed files with 2,081 additions and 957 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,6 @@
!/app/assets/builds/.keep

/node_modules

# Ignore application configuration
/config/application.yml
6 changes: 6 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ gem 'cssbundling-rails', '~> 1.1'

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"
gem 'aws-sdk-s3', require: false

# Store encrypted credentials
gem 'figaro'

group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
Expand Down Expand Up @@ -82,3 +86,5 @@ group :test do
gem 'selenium-webdriver'
gem 'webdrivers'
end

gem 'pry-rails', group: :development
28 changes: 28 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,22 @@ GEM
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
ast (2.4.2)
aws-eventstream (1.2.0)
aws-partitions (1.616.0)
aws-sdk-core (3.132.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.525.0)
aws-sigv4 (~> 1.1)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.58.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.114.0)
aws-sdk-core (~> 3, >= 3.127.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.1)
aws-eventstream (~> 1, >= 1.0.2)
bcrypt (3.1.18)
bindex (0.8.1)
bootsnap (1.13.0)
Expand All @@ -84,6 +100,7 @@ GEM
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
childprocess (4.1.0)
coderay (1.1.3)
concurrent-ruby (1.1.10)
crass (1.0.6)
cssbundling-rails (1.1.1)
Expand All @@ -110,6 +127,8 @@ GEM
factory_bot (~> 6.2.0)
railties (>= 5.0.0)
ffi (1.15.5-x64-mingw-ucrt)
figaro (1.2.0)
thor (>= 0.14.0, < 2)
globalid (1.0.0)
activesupport (>= 5.0)
i18n (1.12.0)
Expand All @@ -123,6 +142,7 @@ GEM
jbuilder (2.11.5)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
jmespath (1.6.1)
json (2.6.2)
loofah (2.18.0)
crass (~> 1.0.2)
Expand Down Expand Up @@ -157,6 +177,11 @@ GEM
parser (3.1.2.0)
ast (~> 2.4.1)
pg (1.4.2-x64-mingw-ucrt)
pry (0.14.1)
coderay (~> 1.1)
method_source (~> 1.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
public_suffix (4.0.7)
puma (5.6.4)
nio4r (~> 2.0)
Expand Down Expand Up @@ -283,6 +308,7 @@ PLATFORMS
x64-mingw-ucrt

DEPENDENCIES
aws-sdk-s3
bootsnap
capybara
cssbundling-rails (~> 1.1)
Expand All @@ -291,9 +317,11 @@ DEPENDENCIES
devise
factory_bot_rails
ffi (~> 1.15, >= 1.15.5)
figaro
importmap-rails
jbuilder
pg (~> 1.1)
pry-rails
puma (~> 5.0)
rails (~> 7.0.3, >= 7.0.3.1)
rails-controller-testing
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

A web application where you can manage your budget: you have a list of transactions associated with a category, so that you can see how much money you spent and on what.

![image](https://user-images.githubusercontent.com/55185309/184540699-4353c054-c3e5-49e9-9b55-ece9ea3f6721.png)



### Live demo: [Budgit](https://my-budgit-app.herokuapp.com/)

## Built With

Expand Down
2 changes: 2 additions & 0 deletions app/assets/javascript/activestorage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
//= require activestorage

40 changes: 40 additions & 0 deletions app/assets/javascript/direct_uploads.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

// direct_uploads.js

addEventListener("direct-upload:initialize", event => {
const { target, detail } = event
const { id, file } = detail
target.insertAdjacentHTML("beforebegin", `
<div id="direct-upload-${id}" class="direct-upload direct-upload--pending">
<div id="direct-upload-progress-${id}" class="direct-upload__progress" style="width: 0%"></div>
<span class="direct-upload__filename"></span>
</div>
`)
target.previousElementSibling.querySelector(`.direct-upload__filename`).textContent = file.name
})

addEventListener("direct-upload:start", event => {
const { id } = event.detail
const element = document.getElementById(`direct-upload-${id}`)
element.classList.remove("direct-upload--pending")
})

addEventListener("direct-upload:progress", event => {
const { id, progress } = event.detail
const progressElement = document.getElementById(`direct-upload-progress-${id}`)
progressElement.style.width = `${progress}%`
})

addEventListener("direct-upload:error", event => {
event.preventDefault()
const { id, error } = event.detail
const element = document.getElementById(`direct-upload-${id}`)
element.classList.add("direct-upload--error")
element.setAttribute("title", error)
})

addEventListener("direct-upload:end", event => {
const { id } = event.detail
const element = document.getElementById(`direct-upload-${id}`)
element.classList.add("direct-upload--complete")
})
40 changes: 40 additions & 0 deletions app/assets/stylesheets/application.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,43 @@
*= require_tree .
*= require_self
*/

/* direct_uploads.css */

.direct-upload {
display: inline-block;
position: relative;
padding: 2px 4px;
margin: 0 3px 3px 0;
border: 1px solid rgba(0, 0, 0, 0.3);
border-radius: 3px;
font-size: 11px;
line-height: 13px;
}

.direct-upload--pending {
opacity: 0.6;
}

.direct-upload__progress {
position: absolute;
top: 0;
left: 0;
bottom: 0;
opacity: 0.2;
background: #0076ff;
transition: width 120ms ease-out, opacity 60ms 60ms ease-in;
transform: translate3d(0, 0, 0);
}

.direct-upload--complete .direct-upload__progress {
opacity: 0.4;
}

.direct-upload--error {
border-color: red;
}

input[type=file][data-direct-upload-url][disabled] {
display: none;
}
5 changes: 4 additions & 1 deletion app/assets/stylesheets/application.tailwind.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
/* stylelint-disable */

@tailwind base;
@tailwind components;
@tailwind utilities;
@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@300;700&display=swap');

@import url('https://fonts.googleapis.com/css2?family=Raleway:wght@300;700&display=swap');
9 changes: 9 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :authenticate_user!

protected

def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up) { |u| u.permit(:name, :email, :password, :password_confirmation) }
end
end
27 changes: 7 additions & 20 deletions app/controllers/categories_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,39 @@ class CategoriesController < ApplicationController

# GET /categories or /categories.json
def index
@categories = Category.all
@categories = Category.includes(:user).where(user: current_user)
end

# GET /categories/1 or /categories/1.json
def show; end
def show
@payments = @category.sorted_payments(current_user)
end

# GET /categories/new
def new
@category = Category.new
end

# GET /categories/1/edit
def edit; end

# POST /categories or /categories.json
def create
@category = Category.new(category_params)
@category.user = current_user

respond_to do |format|
if @category.save
format.html { redirect_to category_url(@category), notice: 'Category was successfully created.' }
format.html { redirect_to categories_path, notice: 'Category was successfully created.' }
else
format.html { render :new, status: :unprocessable_entity }
end
end
end

# PATCH/PUT /categories/1 or /categories/1.json
def update
respond_to do |format|
if @category.update(category_params)
format.html { redirect_to category_url(@category), notice: 'Category was successfully updated.' }
format.json { render :show, status: :ok, location: @category }
else
format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @category.errors, status: :unprocessable_entity }
end
end
end

# DELETE /categories/1 or /categories/1.json
def destroy
@category.destroy

respond_to do |format|
format.html { redirect_to categories_url, notice: 'Category was successfully deleted.' }
format.html { redirect_to categories_path, notice: 'Category was successfully deleted.' }
end
end

Expand Down
19 changes: 4 additions & 15 deletions app/controllers/payments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def show; end
# GET /payments/new
def new
@payment = Payment.new
@categories = Category.includes(:user).where(user: current_user)
end

# GET /payments/1/edit
Expand All @@ -20,25 +21,13 @@ def edit; end
# POST /payments or /payments.json
def create
@payment = Payment.new(payment_params)
@payment.user = current_user

respond_to do |format|
if @payment.save
format.html { redirect_to payment_url(@payment), notice: 'Payment was successfully created.' }
format.json { render :show, status: :created, location: @payment }
format.html { redirect_to category_path(@payment.category), notice: 'Payment was successfully created.' }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @payment.errors, status: :unprocessable_entity }
end
end
end

# PATCH/PUT /payments/1 or /payments/1.json
def update
respond_to do |format|
if @payment.update(payment_params)
format.html { redirect_to payment_url(@payment), notice: 'Payment was successfully updated.' }
else
format.html { render :edit, status: :unprocessable_entity }
end
end
end
Expand All @@ -62,6 +51,6 @@ def set_payment

# Only allow a list of trusted parameters through.
def payment_params
params.require(:payment).permit(:name, :amount)
params.require(:payment).permit(:name, :amount, :category_id)
end
end
4 changes: 1 addition & 3 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@ def create

respond_to do |format|
if @user.save
format.html { redirect_to user_url(@user), notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: @user }
format.html { redirect_to categories_path, notice: 'Account successfully created.' }
else
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end
Expand Down
1 change: 1 addition & 0 deletions app/controllers/welcome_controller.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
class WelcomeController < ApplicationController
skip_before_action :authenticate_user!
def index; end
end
13 changes: 13 additions & 0 deletions app/models/category.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
class Category < ApplicationRecord
has_one_attached :icon
has_many :payments, dependent: :destroy
belongs_to :user
validates :name, presence: true
validates :icon, presence: true
validates :user_id, presence: true

def total_amount(user)
payments.includes(:user).where(user:).sum(:amount)
end

def sorted_payments(user)
payments.includes(:user).where(user:).order(created_at: :desc)
end
end
10 changes: 10 additions & 0 deletions app/models/payment.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
class Payment < ApplicationRecord
belongs_to :user
belongs_to :category
validates :amount, presence: true
validates :amount, numericality: { greater_than: 0 }
validates :category_id, presence: true
validates :name, presence: true

def payment_date
created_at.strftime('%d %b %Y')
end
end
9 changes: 5 additions & 4 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :categories, dependent: :destroy
has_many :payments, dependent: :destroy
validates :name, presence: true, length: { minimum: 3, maximum: 25 }

devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable
end
Loading

0 comments on commit a5b127e

Please sign in to comment.