Skip to content

Commit

Permalink
Merge pull request #2 from chrisvel/add_tags
Browse files Browse the repository at this point in the history
Add tags and fix completed
  • Loading branch information
chrisvel authored Nov 15, 2023
2 parents 3e80ff4 + 8ce2538 commit 177ab42
Show file tree
Hide file tree
Showing 21 changed files with 173 additions and 73 deletions.
3 changes: 3 additions & 0 deletions app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
require './app/models/area'
require './app/models/project'
require './app/models/task'
require './app/models/tag'

require './app/helpers/authentication_helper'

Expand Down Expand Up @@ -91,5 +92,7 @@ def nav_link(path, query_params = {}, project_id = nil)
end

get '/inbox' do
@tasks = current_user.tasks.incomplete.where(project_id: nil).order(:name)

erb :inbox
end
3 changes: 3 additions & 0 deletions app/models/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ class Project < ActiveRecord::Base
belongs_to :user
belongs_to :area, optional: true
has_many :tasks, dependent: :destroy

scope :with_incomplete_tasks, -> { joins(:tasks).where(tasks: { completed: false }).distinct }
scope :with_complete_tasks, -> { joins(:tasks).where(tasks: { completed: true }).distinct }
end
4 changes: 4 additions & 0 deletions app/models/tag.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Tag < ActiveRecord::Base
belongs_to :user
has_and_belongs_to_many :tasks
end
4 changes: 3 additions & 1 deletion app/models/task.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
class Task < ActiveRecord::Base
belongs_to :user
belongs_to :project, optional: true
has_and_belongs_to_many :tags

default_scope { where(completed: false) }
scope :complete, -> { where(completed: true) }
scope :incomplete, -> { where(completed: false) }
end
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class User < ActiveRecord::Base
has_many :areas
has_many :projects
has_many :tasks
has_many :tags, dependent: :destroy

validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }, uniqueness: true
end
8 changes: 5 additions & 3 deletions app/routes/projects_routes.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class Sinatra::Application
get '/projects' do
@projects_with_tasks = current_user.projects.includes(:tasks).order(:name)
@projects_with_tasks = current_user.projects.with_incomplete_tasks.order(:name)
@projects_with_tasks_complete = current_user.projects.with_complete_tasks.order(:name)

erb :'projects/index'
end
Expand All @@ -14,9 +15,10 @@ class Sinatra::Application

post '/project/create' do
project = current_user.projects.new(
name: params[:name],
name: params[:name],
description: params[:description],
area_id: params[:area_id].presence)
area_id: params[:area_id].presence
)

if project.save
redirect '/'
Expand Down
43 changes: 32 additions & 11 deletions app/routes/tasks_routes.rb
Original file line number Diff line number Diff line change
@@ -1,26 +1,45 @@
class Sinatra::Application
def update_task_tags(task, tags_json)
return if tags_json.blank?

begin
tag_names = JSON.parse(tags_json).map { |tag| tag['value'] }.uniq
tags = tag_names.map do |name|
current_user.tags.find_or_create_by(name: name)
end
task.tags = tags
rescue JSON::ParserError
puts "Failed to parse JSON for tags: #{tags_json}"
end
end

get '/tasks' do
case params[:due_date]
when 'today'
today = Date.today
@tasks = current_user.tasks.where(due_date: today.beginning_of_day..today.end_of_day, project: nil)
@projects_with_tasks = current_user.projects
.joins(:tasks)
.where(tasks: { due_date: today.beginning_of_day..today.end_of_day })
@tasks = current_user.tasks.incomplete.where('due_date <= ?', today.end_of_day).where(project: nil)

@projects_with_tasks = current_user.projects.with_incomplete_tasks
.where('tasks.due_date <= ?', today.end_of_day)
.distinct.order('projects.name ASC')

when 'upcoming'
one_week_from_today = Date.today + 7.days
@tasks = current_user.tasks.where(due_date: Date.today..one_week_from_today, project: nil)
@projects_with_tasks = current_user.projects.includes(:tasks).where(tasks: { due_date: Date.today..one_week_from_today }).order('projects.name ASC')
@tasks = current_user.tasks.incomplete.where(due_date: Date.today..one_week_from_today, project: nil)
@projects_with_tasks = current_user.projects.with_incomplete_tasks.includes(:tasks).where(tasks: { due_date: Date.today..one_week_from_today }).order('projects.name ASC')

when 'never'
@tasks = current_user.tasks.where(due_date: nil, project: nil)
@projects_with_tasks = current_user.projects.includes(:tasks).where(tasks: { due_date: nil }).order('projects.name ASC')
@tasks = current_user.tasks.incomplete.where(due_date: nil, project: nil)
@projects_with_tasks = current_user.projects.with_incomplete_tasks.includes(:tasks).where(tasks: { due_date: nil }).order('projects.name ASC')

else
@tasks = current_user.tasks.where(project: nil)
@projects_with_tasks = current_user.projects.includes(:tasks).order('projects.name ASC')
if params[:status] == 'completed'
@tasks = current_user.tasks.complete.where(project: nil)
@projects_with_tasks = current_user.projects.with_complete_tasks.includes(:tasks).order('projects.name ASC')
else
@tasks = current_user.tasks.incomplete.where(project: nil)
@projects_with_tasks = current_user.projects.with_incomplete_tasks.includes(:tasks).order('projects.name ASC')
end
end

@tasks ||= []
Expand All @@ -46,6 +65,7 @@ class Sinatra::Application
end

if task.save
update_task_tags(task, params[:tags])
redirect request.referrer || '/'
else
halt 400, 'There was a problem creating the task.'
Expand All @@ -72,6 +92,7 @@ class Sinatra::Application
end

if task.update(task_attributes)
update_task_tags(task, params[:tags])
redirect request.referrer || '/'
else
halt 400, 'There was a problem updating the task.'
Expand All @@ -80,7 +101,7 @@ class Sinatra::Application

patch '/task/:id/toggle_completion' do
content_type :json
task = current_user.tasks.find(params[:id])
task = current_user.tasks.find_by(id: params[:id])
if task
task.completed = !task.completed
if task.save
Expand Down
7 changes: 3 additions & 4 deletions app/views/inbox.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
<%= partial :'tasks/_form', locals: { task: Task.new } %>
</div>
</div>
<div class="mx-3 my-2">
<% standalone_tasks = current_user.tasks.where(project_id: nil) %>
<% if standalone_tasks.any? %>
<% standalone_tasks.each do |task| %>
<div class="mx-3 mt-4 mb-2">
<% if @tasks %>
<% @tasks.each do |task| %>
<div id="edit_task_form_<%= task.id %>" class="d-none">
<%= partial :'tasks/_form', locals: { task: task } %>
</div>
Expand Down
8 changes: 5 additions & 3 deletions app/views/layout.erb
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.css">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.css" rel="stylesheet">
<link rel="stylesheet" href="/css/app.css">
</head>
<body class="container-fluid bg-light">
<body class="container-fluid" style="background: #fcfcfc">
<div class="row flex-nowrap">
<% if current_user %>
<%= partial :'sidebar' %>
<%= partial :'projects/_new_project_modal' %>
<div class="px-md-4 pt-4 mb-3 main-content col-md-9 col-lg-10" style="background: #fbfbfb">
<div class="px-md-4 pt-4 mb-3 main-content col-md-9 col-lg-10">
<%= yield %>
</div>
<% else %>
<div class="px-md-4 pt-4 mb-3 col-md-12" style="background: #fbfbfb">
<div class="px-md-4 pt-4 mb-3 col-md-12">
<%= yield %>
</div>
<% end %>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script> </body>
<script src="https://cdn.jsdelivr.net/npm/@yaireo/tagify@latest/dist/tagify.min.js"></script>
<script src="/js/app.js"></script>
</html>
2 changes: 1 addition & 1 deletion app/views/projects/index.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<% if @projects_with_tasks.any? %>
<% @projects_with_tasks.each do |project| %>
<% if project.tasks.any? %>
<h5 class="mt-4 ms-4 mb-2">
<h5 class="mt-4 mb-2">
<div class="px-2 py-1 mb-1 border border-dark d-inline-block"><%= project.name.upcase %></div>
</h5>
<% project.tasks.each do |task| %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/projects/show.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<%= @project.description %>
</div>
<% end %>
<div class="bg-light py-2 px-3 mx-3 d-flex align-items-center border" data-bs-toggle="collapse" data-bs-target="#newTaskForm" aria-expanded="false" aria-controls="newTaskForm" style="cursor: pointer;">
<div class="bg-light py-2 mb-4 px-3 mx-3 d-flex align-items-center border" data-bs-toggle="collapse" data-bs-target="#newTaskForm" aria-expanded="false" aria-controls="newTaskForm" style="cursor: pointer;">
<i class="fs-4 bi bi-plus-circle-fill text-primary me-2"></i> <span class="fs-6">New task</span>
</div>
<div class="collapse" id="newTaskForm">
Expand Down
8 changes: 4 additions & 4 deletions app/views/sidebar.erb
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
</a>
</li>
<li>
<a href="/tasks?due_date=anytime" class="<%= nav_link('/tasks', 'due_date' => 'anytime') %>">
<i class="bi bi-sun-fill me-1"></i> Anytime
<a href="/tasks?due_date=never" class="<%= nav_link('/tasks', 'due_date' => 'never') %>">
<i class="bi bi-moon-stars-fill me-1"></i> Someday
</a>
</li>
<li>
<a href="/tasks?due_date=never" class="<%= nav_link('/tasks', 'due_date' => 'never') %>">
<i class="bi bi-moon-stars-fill me-1"></i> Someday
<a href="/tasks?status=completed" class="<%= nav_link('/tasks', 'status' => 'completed') %>">
<i class="bi bi-check-circle me-1"></i> Completed
</a>
</li>
<li class="border-top my-3"></li>
Expand Down
75 changes: 39 additions & 36 deletions app/views/tasks/_form.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<% action_url = task.new_record? ? '/task/create' : "/task/#{task.id}" %>
<% method = task.new_record? ? 'post' : 'patch' %>

<form action="<%= action_url %>" method="post" class="">
<% unless task.new_record? %>
<input type="hidden" name="_method" value="<%= method %>">
Expand All @@ -19,46 +18,50 @@
<option value="">No Project</option>
<% current_user.projects.each do |project| %>
<option value="<%= project.id %>" <%= 'selected' if task.project_id == project.id %>><%= project.name %></option>
<% end %>
</select>
</div>
<div class="col-md-4">
<label for="task_priority" class="form-label">Priority:</label>
<select id="task_priority" name="priority" class="form-select">
<option value="Low" <%= 'selected' if task.priority == 'Low' %>>Low</option>
<% end %>
</select>
</div>
<div class="col-md-4">
<label for="task_priority" class="form-label">Priority:</label>
<select id="task_priority" name="priority" class="form-select">
<option value="Low" <%= 'selected' if task.priority == 'Low' %>>Low</option>
<option value="Medium" <%= 'selected' if task.priority == 'Medium' %>>Medium</option>
<option value="High" <%= 'selected' if task.priority == 'High' %>>High</option>
</select>
</div>
<div class="col-md-4">
<label for="task_due_date" class="form-label">Due Date:</label>
<input type="date" id="task_due_date" name="due_date" value="<%= task.due_date.strftime('%Y-%m-%d') if task.due_date %>" class="form-control">
</div>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary">
<%= task.new_record? ? 'Create Task' : 'Update Task' %>
</button>
<% unless task.new_record? %>
<button type="button" class="btn btn-outline-danger" onclick="deleteTask('<%= task.id %>')">
<i class="bi bi-trash"></i>
</button>
</div>
</div>
<div class="row mb-3">
<div class="col-md-12">
<label for="task_tags" class="form-label">Tags:</label>
<input name="tags" id="task_tags" class="form-control" value="<%= task.tags&.map(&:name)&.join(',') %>">
</div>
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary">
<%= task.new_record? ? 'Create Task' : 'Update Task' %>
</button>
<% unless task.new_record? %>
<button type="button" class="btn btn-outline-danger" onclick="deleteTask('<%= task.id %>')">
<i class="bi bi-trash"></i>
</button>
<% end %>
</div>
</fieldset>
</form>
<% if !task.new_record? %>
<form id="delete_task_<%= task.id %>" action="/task/<%= task.id %>" method="post" class="d-none">
<input type="hidden" name="_method" value="delete">
</form>
<% end %>
</div>
</fieldset>
</form>

<% if !task.new_record? %>
<form id="delete_task_<%= task.id %>" action="/task/<%= task.id %>" method="post" class="d-none">
<input type="hidden" name="_method" value="delete">
</form>
<% end %>

<script>
function deleteTask(taskId) {
if (confirm('Are you sure you want to delete this task?')) {
var form = document.getElementById('delete_task_' + taskId);
form.submit();
}
}
</script>
<script>
function deleteTask(taskId) {
if (confirm('Are you sure you want to delete this task?')) {
var form = document.getElementById('delete_task_' + taskId);
form.submit();
}
}
</script>
4 changes: 2 additions & 2 deletions app/views/tasks/_header.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
<h2 class="mb-5"><i class="bi bi-calendar3 ms-3 me-2"></i> Upcoming</h2>
<% elsif params[:due_date] == 'never' %>
<h2 class="mb-5"><i class="bi bi-moon-stars-fill ms-3 me-2"></i> Someday</h2>
<% elsif params[:due_date] == 'anytime' %>
<h2 class="mb-5"><i class="bi bi-sun-fill ms-3 me-2"></i> Anytime</h2>
<% elsif params[:status] == 'completed' %>
<h2 class="mb-5"><i class="bi bi-check-circle ms-3 me-2"></i> Completed</h2>
<% end %>
7 changes: 7 additions & 0 deletions app/views/tasks/_task.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
<div class="col-md-5">
<%= task.name %>
</div>
<div class="col-md-3">
<% task.tags.each do |tag| %>
<span class="badge bg-primary-subtle text-primary rounded">
<%= tag.name %>
</span>
<% end %>
</div>
<div class="col-md-3">
<% if task.due_date %>
<% if task.due_date.to_date == Date.today %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/tasks/index.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<%= partial :'tasks/_form', locals: { task: Task.new } %>
</div>
</div>
<div class="mx-3 my-2">
<div class="mx-3 mt-4 mb-4">
<% if @tasks.any? %>
<% @tasks.each do |task| %>
<div id="edit_task_form_<%= task.id %>" class="d-none">
Expand Down
10 changes: 10 additions & 0 deletions db/migrate/20231114203847_add_tags.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class AddTags < ActiveRecord::Migration[7.1]
def change
create_table :tags do |t|
t.string :name
t.references :user, null: false, foreign_key: { on_delete: :cascade }

t.timestamps
end
end
end
8 changes: 8 additions & 0 deletions db/migrate/20231114210336_create_tasks_tags.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class CreateTasksTags < ActiveRecord::Migration[7.1]
def change
create_table :tasks_tags, id: false do |t|
t.belongs_to :task, null: false, foreign_key: true
t.belongs_to :tag, null: false, foreign_key: true
end
end
end
5 changes: 5 additions & 0 deletions db/migrate/20231115092055_rename_tasks_tags_to_tags_tasks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class RenameTasksTagsToTagsTasks < ActiveRecord::Migration[7.1]
def change
rename_table :tasks_tags, :tags_tasks
end
end
Loading

0 comments on commit 177ab42

Please sign in to comment.