diff --git a/.gitignore b/.gitignore index 388fdca..3e13ae4 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ # Ignore master key for decrypting credentials and more. /config/master.key + +/config/application.yml diff --git a/Gemfile b/Gemfile index ecea4a7..2bab722 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,6 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } ruby '2.5.1' -gem 'will_paginate' gem 'jquery-rails' gem 'bootstrap', '~> 4.1.3' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' @@ -63,3 +62,8 @@ end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] +gem 'wice_grid', git: 'https://github.com/patricklindsay/wice_grid.git' +gem "figaro" +gem 'bootstrap-datepicker-rails' +gem 'jquery-ui-rails' + diff --git a/Gemfile.lock b/Gemfile.lock index ee73330..d2f9269 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,12 @@ +GIT + remote: https://github.com/patricklindsay/wice_grid.git + revision: fbce87432eec24c9e9bec05d6698f150cfb17329 + specs: + wice_grid (4.0.1) + coffee-rails (> 3.2) + kaminari (~> 0.16) + rails (~> 5.0, < 5.3) + GEM remote: https://rubygems.org/ specs: @@ -57,6 +66,8 @@ GEM autoprefixer-rails (>= 6.0.3) popper_js (>= 1.12.9, < 2) sass (>= 3.5.2) + bootstrap-datepicker-rails (1.8.0.1) + railties (>= 3.0) builder (3.2.3) byebug (10.0.2) capybara (3.10.1) @@ -84,6 +95,8 @@ GEM erubi (1.7.1) execjs (2.7.0) ffi (1.9.25) + figaro (1.1.1) + thor (~> 0.14) globalid (0.4.1) activesupport (>= 4.2.0) i18n (1.1.1) @@ -96,6 +109,11 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) + jquery-ui-rails (6.0.1) + railties (>= 3.2.16) + kaminari (0.17.0) + actionpack (>= 3.0.0) + activesupport (>= 3.0.0) listen (3.1.5) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) @@ -199,7 +217,6 @@ GEM websocket-driver (0.7.0) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.3) - will_paginate (3.1.6) xpath (3.2.0) nokogiri (~> 1.8) @@ -210,12 +227,15 @@ DEPENDENCIES bcrypt (~> 3.1.7) bootsnap (>= 1.1.0) bootstrap (~> 4.1.3) + bootstrap-datepicker-rails byebug capybara (>= 2.15) chromedriver-helper coffee-rails (~> 4.2) + figaro jbuilder (~> 2.5) jquery-rails + jquery-ui-rails listen (>= 3.0.5, < 3.2) puma (~> 3.11) rails (~> 5.2.1) @@ -228,7 +248,7 @@ DEPENDENCIES tzinfo-data uglifier (>= 1.3.0) web-console (>= 3.3.0) - will_paginate + wice_grid! RUBY VERSION ruby 2.5.1p57 diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 7631c6d..2755cc7 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -10,22 +10,16 @@ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // -//= require jquery //= require rails-ujs //= require activestorage //= require turbolinks //= require_tree . - -function openPopup () { - $('.modal').show(500, function () { - $(this).addClass('active') - }) -} - -function closePopup () { - $('.modal').removeClass('active') - $('.modal').hide(500) -} +//= require jquery3 +//= require bootstrap +//= require jquery_ujs +//= require jquery-ui +//= require wice_grid +//= require bootstrap-datepicker function handleCheckbox (event) { if (event.target.id === 'task_status') { diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 567f715..1189ca4 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -33,13 +33,10 @@ body { min-width: 100vw; padding: 100px 0; width: 100%; - z-index: -10; - overflow-x: hidden; - color: white; font-size: 1.3rem; } .hero { - //background-color: rgba(31, 34, 118, 0.5); + color: white; .container { text-align: center; button.open { @@ -74,6 +71,7 @@ body { display: flex; flex-direction: column; align-items: center; + padding-top: 20px; } h1 { margin: 0; @@ -147,65 +145,3 @@ body { background-color: #343a4069; } } - -.navbar { - .container { - display: flex; - justify-content: space-between; - } - .user-data-container { - display: flex; - align-items: center; - p { - margin: 0 10px 0 0; - font-size: 14px; - } - } -} - -.modal { - justify-content: center; - align-items: center; - transition: background 0.1s ease; - &.active { - display: flex; - background: rgba(0, 0, 0, 0.6); - } - .modal-dialog { - height: 100%; - display: flex; - align-items: center; - } - .modal-content { - position: relative; - display: flex; - flex-direction: column; - align-items: center; - padding: 50px 50px 25px; - .close { - position: absolute; - top: 5px; - right: 5px; - width: 25px; - outline: none; - } - button.save { - margin-top: 20px; - } - } - form.new_task { - display: flex; - width: 100%; - flex-direction: column; - align-items: center; - .input-group, .form-group, .field_with_errors, input { - width: 100%; - } - button { - width: 100px; - } - } - .error { - color: red; - } -} \ No newline at end of file diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index edf9cc1..953f3be 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,25 +1,57 @@ class SessionsController < ApplicationController before_action :require_guest, only: [:new, :create] + def new @user = User.new end def create - @user = User.find_by(name: user_params[:name]) - @user ||= User.create(user_params) + @existed_user = User.find_by(name: user_params[:name]) + @user = @existed_user ? @existed_user : User.create(user_params) + + if (user_params[:email] && !@existed_user) + UserMailer.welcome_email(@user).deliver_later + end + if @user.valid? && @user.authenticate(user_params[:password]) session[:user_id] = @user.id redirect_to tasks_path end end + def find + @user = User.find_by(name: params[:user][:name]) + + return share_error('No such user') unless @user + + if @user.id != current_user.id + current_user.users.push(@user) + flash[:success] = 'Successful shared' + redirect_to root_path + else + share_error('U cant do it with yourself ;)') + end + end + + def share + @user = User.new + end + def destroy session[:user_id] = nil redirect_to new_session_path end private + + def share_error(error) + flash[:error] = error + + @user = User.new + render 'share' + end + def user_params - params.require(:user).permit(:name, :password) + params.require(:user).permit(:name, :password, :email) end end diff --git a/app/controllers/tasks_controller.rb b/app/controllers/tasks_controller.rb index fe8a15d..6424027 100644 --- a/app/controllers/tasks_controller.rb +++ b/app/controllers/tasks_controller.rb @@ -3,7 +3,12 @@ class TasksController < ApplicationController def index @task = Task.new - @tasks = Task.for_dashboard(params).where(user_id: params[:user_id] || current_user) + @tasks = Task.for_dashboard(params, current_user) + @tasks_grid = initialize_grid(@tasks) + end + + def new + @task = Task.new end def create diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index de6be79..bd6f680 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,2 +1,20 @@ module ApplicationHelper + + def bootstrap_class_for flash_type + { + success: "alert-success", + error: "alert-danger", + alert: "alert-warning", + notice: "alert-info"}.stringify_keys[flash_type.to_s] || flash_type.to_s + end + + def flash_messages(opts = {}) + flash.each do |msg_type, message| + concat(content_tag(:div, message, class: "alert #{bootstrap_class_for(msg_type)}", role: "alert") do + concat content_tag(:button, 'x', class: "close", data: {dismiss: 'alert'}) + concat message + end) + end + nil + end end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb new file mode 100644 index 0000000..a17c53a --- /dev/null +++ b/app/mailers/user_mailer.rb @@ -0,0 +1,9 @@ +class UserMailer < ApplicationMailer + default from: 'notifications@example.com' + + def welcome_email(user) + @user = user + + mail(to: @user.email, subject: "Wellcome, #{@user.name}#") + end +end \ No newline at end of file diff --git a/app/models/task.rb b/app/models/task.rb index 2a43fea..9093cb2 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -4,12 +4,20 @@ class Task < ApplicationRecord validates :title, presence: true validates :description, presence: true validates_length_of :description, minimum: 5 - validates :expire_at, inclusion: { in: (Date.today..Date.today+5.years) } + validates :expire_at, inclusion: {in: (Date.today..Date.today + 5.years)} enum status: %i[todo done] scope :q, ->(q) { where("title LIKE '%#{q}%'") unless q.blank? } scope :status, ->(status) { where(status: status) unless status.blank? } - scope :expired, ->(val) { where("expire_at #{val == 'Expired' ? '<' : '>'} ?", Time.now) unless val.blank?} - scope :for_dashboard, ->(params) { q(params[:q]).status(params[:status]).expired(params[:expired]).paginate(page: params[:page], per_page: 5) } + scope :expired, ->(val) { where("expire_at #{val == 'Expired' ? '<' : '>'} ?", Time.now) unless val.blank? } + scope :for_dashboard, ->(params, current_user) do + users_tasks(current_user).q(params[:q]).status(params[:status]).expired(params[:expired]) + end + + scope :users_tasks, ->(current_user) { + id = current_user.id + friends = UserConnection.find_by_user_b_id(id) + where(user_id: friends ? [id, friends.user_a_id] : id) + } end diff --git a/app/models/user.rb b/app/models/user.rb index 30a97a4..711b2be 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -4,5 +4,8 @@ class User < ApplicationRecord has_secure_password validations: false - has_many :tasks + has_many :user_connections, :foreign_key => :user_a_id, :dependent => :destroy + has_many :users, :through => :user_connections, :source => :user_b + has_many(:reverse_user_connections, :class_name => :UserConnection, + :foreign_key => :user_b_id, :dependent => :destroy) end diff --git a/app/models/user_connection.rb b/app/models/user_connection.rb new file mode 100644 index 0000000..f5eaf66 --- /dev/null +++ b/app/models/user_connection.rb @@ -0,0 +1,4 @@ +class UserConnection < ApplicationRecord + belongs_to :user_a, :class_name => :User + belongs_to :user_b, :class_name => :User +end diff --git a/app/views/layouts/_header.html.erb b/app/views/layouts/_header.html.erb index 105fc3e..cca0409 100644 --- a/app/views/layouts/_header.html.erb +++ b/app/views/layouts/_header.html.erb @@ -1,12 +1,15 @@ -