Project initialize
This commit is contained in:
2
app/views/departments/create.html.erb
Normal file
2
app/views/departments/create.html.erb
Normal file
@@ -0,0 +1,2 @@
|
||||
<h1>Departments#create</h1>
|
||||
<p>Find me in app/views/departments/create.html.erb</p>
|
||||
2
app/views/departments/destroy.html.erb
Normal file
2
app/views/departments/destroy.html.erb
Normal file
@@ -0,0 +1,2 @@
|
||||
<h1>Departments#destroy</h1>
|
||||
<p>Find me in app/views/departments/destroy.html.erb</p>
|
||||
31
app/views/departments/edit.html.erb
Normal file
31
app/views/departments/edit.html.erb
Normal file
@@ -0,0 +1,31 @@
|
||||
<h1>Edit Department</h1>
|
||||
|
||||
<%= form_with(model: @department, local: true) do |form| %>
|
||||
<% if @department.errors.any? %>
|
||||
<div id="error_explanation">
|
||||
<h2><%= pluralize(@department.errors.count, "error") %> prohibited this department from being saved:</h2>
|
||||
<ul>
|
||||
<% @department.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="field">
|
||||
<%= form.label :name %>
|
||||
<%= form.text_field :name, placeholder: "Department name..." %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= form.label :description %>
|
||||
<%= form.text_area :description, placeholder: "Department description...", rows: 4 %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= form.submit "Update Department", class: "submit-btn" %>
|
||||
<%= link_to "Cancel", @department, class: "cancel-btn" %>
|
||||
</div>
|
||||
<% end %>
|
||||
36
app/views/departments/index.html.erb
Normal file
36
app/views/departments/index.html.erb
Normal file
@@ -0,0 +1,36 @@
|
||||
<h1>Departments</h1>
|
||||
|
||||
<% if flash[:notice] %>
|
||||
<div class="notice"><%= flash[:notice] %></div>
|
||||
<% end %>
|
||||
|
||||
<div class="departments-grid">
|
||||
<% if @departments.empty? %>
|
||||
<p class="empty-state">No departments found.</p>
|
||||
<% else %>
|
||||
<% @departments.each do |department| %>
|
||||
<div class="department-card">
|
||||
<h3><%= link_to department.name, department_path(department) %></h3>
|
||||
<p><%= department.description %></p>
|
||||
|
||||
<div class="department-stats">
|
||||
<div class="stat">
|
||||
<strong>Users:</strong> <%= department.user_count %>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<strong>Tasks:</strong> <%= department.task_count %>
|
||||
</div>
|
||||
<div class="stat">
|
||||
<strong>Open:</strong> <%= department.incomplete_task_count %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="actions-section">
|
||||
<% if current_user&.admin? %>
|
||||
<%= link_to 'New Department', new_department_path, class: 'action-btn primary' %>
|
||||
<% end %>
|
||||
</div>
|
||||
31
app/views/departments/new.html.erb
Normal file
31
app/views/departments/new.html.erb
Normal file
@@ -0,0 +1,31 @@
|
||||
<h1>New Department</h1>
|
||||
|
||||
<%= form_with(model: @department, local: true) do |form| %>
|
||||
<% if @department.errors.any? %>
|
||||
<div id="error_explanation">
|
||||
<h2><%= pluralize(@department.errors.count, "error") %> prohibited this department from being saved:</h2>
|
||||
<ul>
|
||||
<% @department.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="field">
|
||||
<%= form.label :name %>
|
||||
<%= form.text_field :name, placeholder: "Department name..." %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= form.label :description %>
|
||||
<%= form.text_area :description, placeholder: "Department description...", rows: 4 %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= form.submit "Create Department", class: "submit-btn" %>
|
||||
<%= link_to "Cancel", departments_path, class: "cancel-btn" %>
|
||||
</div>
|
||||
<% end %>
|
||||
40
app/views/departments/show.html.erb
Normal file
40
app/views/departments/show.html.erb
Normal file
@@ -0,0 +1,40 @@
|
||||
<h1><%= @department.name %></h1>
|
||||
|
||||
<div class="department-info">
|
||||
<p><%= @department.description %></p>
|
||||
|
||||
<div class="department-stats">
|
||||
<h3>Department Statistics</h3>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-item">
|
||||
<strong>Total Users:</strong> <%= @department.user_count %>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<strong>Total Tasks:</strong> <%= @department.task_count %>
|
||||
</div>
|
||||
<div class="stat-item">
|
||||
<strong>Open Tasks:</strong> <%= @department.incomplete_task_count %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tasks-section">
|
||||
<h2>Department Tasks</h2>
|
||||
<% if @tasks.empty? %>
|
||||
<p class="empty-state">No tasks in this department yet.</p>
|
||||
<% else %>
|
||||
<div class="tasks-list">
|
||||
<% @tasks.each do |task| %>
|
||||
<%= render 'tasks/task', task: task %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="department-actions">
|
||||
<%= link_to 'Back to All Departments', departments_path, class: 'action-btn secondary' %>
|
||||
<% if current_user&.can_manage_department?(@department) %>
|
||||
<%= link_to 'Edit Department', edit_department_path(@department), class: 'action-btn primary' %>
|
||||
<% end %>
|
||||
</div>
|
||||
2
app/views/departments/update.html.erb
Normal file
2
app/views/departments/update.html.erb
Normal file
@@ -0,0 +1,2 @@
|
||||
<h1>Departments#update</h1>
|
||||
<p>Find me in app/views/departments/update.html.erb</p>
|
||||
16
app/views/devise/confirmations/new.html.erb
Normal file
16
app/views/devise/confirmations/new.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
<h2>Resend confirmation instructions</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :email %><br />
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Resend confirmation instructions" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
@@ -0,0 +1,5 @@
|
||||
<p>Welcome <%= @email %>!</p>
|
||||
|
||||
<p>You can confirm your account email through the link below:</p>
|
||||
|
||||
<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
|
||||
7
app/views/devise/mailer/email_changed.html.erb
Normal file
7
app/views/devise/mailer/email_changed.html.erb
Normal file
@@ -0,0 +1,7 @@
|
||||
<p>Hello <%= @email %>!</p>
|
||||
|
||||
<% if @resource.try(:unconfirmed_email?) %>
|
||||
<p>We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.</p>
|
||||
<% else %>
|
||||
<p>We're contacting you to notify you that your email has been changed to <%= @resource.email %>.</p>
|
||||
<% end %>
|
||||
3
app/views/devise/mailer/password_change.html.erb
Normal file
3
app/views/devise/mailer/password_change.html.erb
Normal file
@@ -0,0 +1,3 @@
|
||||
<p>Hello <%= @resource.email %>!</p>
|
||||
|
||||
<p>We're contacting you to notify you that your password has been changed.</p>
|
||||
@@ -0,0 +1,8 @@
|
||||
<p>Hello <%= @resource.email %>!</p>
|
||||
|
||||
<p>Someone has requested a link to change your password. You can do this through the link below.</p>
|
||||
|
||||
<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>
|
||||
|
||||
<p>If you didn't request this, please ignore this email.</p>
|
||||
<p>Your password won't change until you access the link above and create a new one.</p>
|
||||
7
app/views/devise/mailer/unlock_instructions.html.erb
Normal file
7
app/views/devise/mailer/unlock_instructions.html.erb
Normal file
@@ -0,0 +1,7 @@
|
||||
<p>Hello <%= @resource.email %>!</p>
|
||||
|
||||
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
|
||||
|
||||
<p>Click the link below to unlock your account:</p>
|
||||
|
||||
<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
|
||||
25
app/views/devise/passwords/edit.html.erb
Normal file
25
app/views/devise/passwords/edit.html.erb
Normal file
@@ -0,0 +1,25 @@
|
||||
<h2>Change your password</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
<%= f.hidden_field :reset_password_token %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password, "New password" %><br />
|
||||
<% if @minimum_password_length %>
|
||||
<em>(<%= @minimum_password_length %> characters minimum)</em><br />
|
||||
<% end %>
|
||||
<%= f.password_field :password, autofocus: true, autocomplete: "new-password" %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password_confirmation, "Confirm new password" %><br />
|
||||
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Change my password" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
16
app/views/devise/passwords/new.html.erb
Normal file
16
app/views/devise/passwords/new.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
<h2>Forgot your password?</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :email %><br />
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Send me reset password instructions" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
43
app/views/devise/registrations/edit.html.erb
Normal file
43
app/views/devise/registrations/edit.html.erb
Normal file
@@ -0,0 +1,43 @@
|
||||
<h2>Edit <%= resource_name.to_s.humanize %></h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :email %><br />
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
|
||||
</div>
|
||||
|
||||
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
|
||||
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
|
||||
<% end %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
|
||||
<%= f.password_field :password, autocomplete: "new-password" %>
|
||||
<% if @minimum_password_length %>
|
||||
<br />
|
||||
<em><%= @minimum_password_length %> characters minimum</em>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password_confirmation %><br />
|
||||
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
|
||||
<%= f.password_field :current_password, autocomplete: "current-password" %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Update" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<h3>Cancel my account</h3>
|
||||
|
||||
<div>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %></div>
|
||||
|
||||
<%= link_to "Back", :back %>
|
||||
48
app/views/devise/registrations/new.html.erb
Normal file
48
app/views/devise/registrations/new.html.erb
Normal file
@@ -0,0 +1,48 @@
|
||||
<div class="auth-container">
|
||||
<h2>Register New Account</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { class: "auth-form" }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :name %>
|
||||
<%= f.text_field :name, autofocus: true, autocomplete: "name" %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :email %>
|
||||
<%= f.email_field :email, autocomplete: "email" %>
|
||||
</div>
|
||||
|
||||
<% if current_user&.admin? || !current_user %>
|
||||
<div class="field">
|
||||
<%= f.label :role %>
|
||||
<%= f.select :role, User.roles.keys, { prompt: "Select Role" } %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :department_id %>
|
||||
<%= f.collection_select :department_id, Department.ordered, :id, :name, { prompt: "Select Department" } %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password %>
|
||||
<% if @minimum_password_length %>
|
||||
<em>(<%= @minimum_password_length %> characters minimum)</em>
|
||||
<% end %>
|
||||
<%= f.password_field :password, autocomplete: "new-password" %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password_confirmation %>
|
||||
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Sign up", class: "auth-submit-btn" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
</div>
|
||||
30
app/views/devise/sessions/new.html.erb
Normal file
30
app/views/devise/sessions/new.html.erb
Normal file
@@ -0,0 +1,30 @@
|
||||
<div class="auth-container">
|
||||
<h2>Sign In</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: "auth-form" }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :email %>
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :password %>
|
||||
<%= f.password_field :password, autocomplete: "current-password" %>
|
||||
</div>
|
||||
|
||||
<% if devise_mapping.rememberable? %>
|
||||
<div class="field checkbox-field">
|
||||
<%= f.check_box :remember_me %>
|
||||
<%= f.label :remember_me %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Log in", class: "auth-submit-btn" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
</div>
|
||||
15
app/views/devise/shared/_error_messages.html.erb
Normal file
15
app/views/devise/shared/_error_messages.html.erb
Normal file
@@ -0,0 +1,15 @@
|
||||
<% if resource.errors.any? %>
|
||||
<div id="error_explanation" data-turbo-cache="false">
|
||||
<h2>
|
||||
<%= I18n.t("errors.messages.not_saved",
|
||||
count: resource.errors.count,
|
||||
resource: resource.class.model_name.human.downcase)
|
||||
%>
|
||||
</h2>
|
||||
<ul>
|
||||
<% resource.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
25
app/views/devise/shared/_links.html.erb
Normal file
25
app/views/devise/shared/_links.html.erb
Normal file
@@ -0,0 +1,25 @@
|
||||
<%- if controller_name != 'sessions' %>
|
||||
<%= link_to "Log in", new_session_path(resource_name) %><br />
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.registerable? && controller_name != 'registrations' %>
|
||||
<%= link_to "Sign up", new_registration_path(resource_name) %><br />
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
|
||||
<%= link_to "Forgot your password?", new_password_path(resource_name) %><br />
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
|
||||
<%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %><br />
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %>
|
||||
<%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %><br />
|
||||
<% end %>
|
||||
|
||||
<%- if devise_mapping.omniauthable? %>
|
||||
<%- resource_class.omniauth_providers.each do |provider| %>
|
||||
<%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %><br />
|
||||
<% end %>
|
||||
<% end %>
|
||||
16
app/views/devise/unlocks/new.html.erb
Normal file
16
app/views/devise/unlocks/new.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
<h2>Resend unlock instructions</h2>
|
||||
|
||||
<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
|
||||
<%= render "devise/shared/error_messages", resource: resource %>
|
||||
|
||||
<div class="field">
|
||||
<%= f.label :email %><br />
|
||||
<%= f.email_field :email, autofocus: true, autocomplete: "email" %>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<%= f.submit "Resend unlock instructions" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= render "devise/shared/links" %>
|
||||
49
app/views/layouts/application.html.erb
Normal file
49
app/views/layouts/application.html.erb
Normal file
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Project Management System</title>
|
||||
<%= csrf_meta_tags %>
|
||||
|
||||
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
|
||||
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<% if user_signed_in? %>
|
||||
<nav class="main-nav">
|
||||
<div class="nav-container">
|
||||
<div class="nav-brand">
|
||||
<%= link_to 'Project Manager', root_path, class: 'brand-link' %>
|
||||
</div>
|
||||
|
||||
<div class="nav-menu">
|
||||
<%= link_to 'Dashboard', dashboard_path, class: 'nav-link' %>
|
||||
<%= link_to 'Tasks', tasks_path, class: 'nav-link' %>
|
||||
<% if current_user.admin? || current_user.manager? %>
|
||||
<%= link_to 'Departments', departments_path, class: 'nav-link' %>
|
||||
<% end %>
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to 'Users', new_user_registration_path, class: 'nav-link' %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="nav-user">
|
||||
<span class="user-info">
|
||||
<%= current_user.name %> (<%= current_user.role.humanize %>)
|
||||
</span>
|
||||
<%= link_to 'Sign Out', destroy_user_session_path, method: :delete, class: 'nav-link sign-out' %>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<% end %>
|
||||
|
||||
<% if flash[:notice] %>
|
||||
<div class="notice"><%= flash[:notice] %></div>
|
||||
<% end %>
|
||||
<% if flash[:alert] %>
|
||||
<div class="alert"><%= flash[:alert] %></div>
|
||||
<% end %>
|
||||
|
||||
<%= yield %>
|
||||
</body>
|
||||
</html>
|
||||
13
app/views/layouts/mailer.html.erb
Normal file
13
app/views/layouts/mailer.html.erb
Normal file
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<style>
|
||||
/* Email styles need to be inline */
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<%= yield %>
|
||||
</body>
|
||||
</html>
|
||||
1
app/views/layouts/mailer.text.erb
Normal file
1
app/views/layouts/mailer.text.erb
Normal file
@@ -0,0 +1 @@
|
||||
<%= yield %>
|
||||
71
app/views/tasks/_form.html.erb
Normal file
71
app/views/tasks/_form.html.erb
Normal file
@@ -0,0 +1,71 @@
|
||||
<% if task.errors.any? %>
|
||||
<div id="error_explanation">
|
||||
<h2><%= pluralize(task.errors.count, "error") %> prohibited this task from being saved:</h2>
|
||||
<ul>
|
||||
<% task.errors.full_messages.each do |message| %>
|
||||
<li><%= message %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="field-group">
|
||||
<div class="field">
|
||||
<%= form.label :title %>
|
||||
<%= form.text_field :title, placeholder: "Task title...", class: "title-field" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="field-group">
|
||||
<div class="field">
|
||||
<%= form.label :priority %>
|
||||
<%= form.select :priority, Task.priorities.keys.map { |p| [p.humanize, p] }, { prompt: "Select Priority" }, class: "priority-select" %>
|
||||
</div>
|
||||
|
||||
<% if accessible_departments.count > 1 || current_user&.admin? %>
|
||||
<div class="field">
|
||||
<%= form.label :department_id %>
|
||||
<%= form.collection_select :department_id, accessible_departments, :id, :name, { prompt: "Select Department" }, class: "department-select" %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="field-group">
|
||||
<% if current_user&.admin? || current_user&.manager? %>
|
||||
<div class="field">
|
||||
<%= form.label :assignee_id %>
|
||||
<%= form.collection_select :assignee_id, accessible_users, :id, :name, { prompt: "Select Assignee" }, class: "assignee-select" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="field">
|
||||
<%= form.label :status %>
|
||||
<%= form.select :status, Task.statuses.keys.map { |s| [s.humanize, s] }, { prompt: "Select Status" }, class: "status-select" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="description-section">
|
||||
<div class="description-toggle" onclick="toggleDescription()">
|
||||
<span id="toggle-text">+ Add Description</span>
|
||||
</div>
|
||||
<div id="description-field" class="description-field" style="display: none;">
|
||||
<%= form.text_area :description, placeholder: "Add a detailed description...", rows: 4, class: "description-textarea" %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% if form.object.new_record? %>
|
||||
<div class="actions">
|
||||
<%= form.submit "Create Task", class: "submit-btn" %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="actions">
|
||||
<%= form.submit "Update Task", class: "submit-btn" %>
|
||||
<%= link_to "Cancel", task, class: "cancel-btn" %>
|
||||
</div>
|
||||
<% end %>
|
||||
58
app/views/tasks/_task.html.erb
Normal file
58
app/views/tasks/_task.html.erb
Normal file
@@ -0,0 +1,58 @@
|
||||
<div id="task_<%= task.id %>" class="task <%= 'completed' if task.status == 'completed' %>">
|
||||
<div class="task-header">
|
||||
<div class="task-priority" style="color: <%= task.priority_color %>">
|
||||
<%= task.priority_icon %> <%= task.priority.humanize %>
|
||||
</div>
|
||||
<div class="task-status-badge" style="background-color: <%= task.status_badge[:color] %>">
|
||||
<%= task.status_badge[:text] %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= form_with(model: task, local: false, method: :patch, class: "toggle-form") do |form| %>
|
||||
<div class="task-content">
|
||||
<%= form.check_box :status, { checked: task.status == 'completed', onchange: "this.form.submit();" }, { class: "task-checkbox" } %>
|
||||
|
||||
<div class="task-info">
|
||||
<span class="task-title"
|
||||
title="<%= task.description&.truncate(100) || 'No description' %>"
|
||||
data-description="<%= task.description || '' %>">
|
||||
<%= task.title %>
|
||||
</span>
|
||||
<% if task.description.present? %>
|
||||
<span class="description-indicator">📝</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="task-meta">
|
||||
<% if task.department %>
|
||||
<span class="department-tag">
|
||||
<%= task.department.name %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<% if task.assignee %>
|
||||
<span class="assignee-tag">
|
||||
Assigned to: <%= task.assignee.name %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<span class="created-tag">
|
||||
Created: <%= task.created_at.strftime('%m/%d/%Y') %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="task-actions">
|
||||
<%= link_to 'View', task, class: 'details-btn' %>
|
||||
<% if task.updateable_by?(current_user) %>
|
||||
<%= link_to 'Edit', edit_task_path(task), class: 'edit-btn' %>
|
||||
<% end %>
|
||||
<% if task.assign?(current_user) && !task.assignee %>
|
||||
<%= link_to 'Assign', assign_task_path(task), method: :patch, class: 'assign-btn' %>
|
||||
<% end %>
|
||||
<% if task.updateable_by?(current_user) || current_user.admin? %>
|
||||
<%= link_to 'Delete', task, method: :delete, data: { confirm: 'Are you sure?' }, class: 'delete-btn' %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
2
app/views/tasks/create.html.erb
Normal file
2
app/views/tasks/create.html.erb
Normal file
@@ -0,0 +1,2 @@
|
||||
<h1>Tasks#create</h1>
|
||||
<p>Find me in app/views/tasks/create.html.erb</p>
|
||||
128
app/views/tasks/dashboard.html.erb
Normal file
128
app/views/tasks/dashboard.html.erb
Normal file
@@ -0,0 +1,128 @@
|
||||
<div class="dashboard-container">
|
||||
<div class="dashboard-header">
|
||||
<h1>Company Dashboard</h1>
|
||||
<div class="user-welcome">
|
||||
Welcome back, <%= current_user.name %>!
|
||||
<span class="user-role">(<%= current_user.role.humanize %>)</span>
|
||||
<% if current_user.department %>
|
||||
<span class="user-department">- <%= current_user.department.name %> Department</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-content">
|
||||
<div class="stats-section">
|
||||
<h2>Statistics</h2>
|
||||
|
||||
<% case current_user.role %>
|
||||
<% when 'admin' %>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @total_tasks %></div>
|
||||
<div class="stat-label">Total Tasks</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @open_tasks %></div>
|
||||
<div class="stat-label">Open Tasks</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @urgent_tasks %></div>
|
||||
<div class="stat-label">Urgent Tasks</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @departments.count %></div>
|
||||
<div class="stat-label">Departments</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="departments-overview">
|
||||
<h3>Departments Overview</h3>
|
||||
<% @departments.each do |department| %>
|
||||
<div class="dept-card">
|
||||
<h4><%= department.name %></h4>
|
||||
<div class="dept-stats">
|
||||
<span><strong>Users:</strong> <%= department.users.count %></span>
|
||||
<span><strong>Tasks:</strong> <%= department.tasks.count %></span>
|
||||
<span><strong>Open:</strong> <%= department.tasks.open.count %></span>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% when 'manager' %>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @dept_tasks.count %></div>
|
||||
<div class="stat-label">Department Tasks</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @open_tasks %></div>
|
||||
<div class="stat-label">Open Tasks</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @urgent_tasks %></div>
|
||||
<div class="stat-label">Urgent Tasks</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @team_members.count %></div>
|
||||
<div class="stat-label">Team Members</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="team-overview">
|
||||
<h3>Team Overview - <%= current_user.department.name %></h3>
|
||||
<% @team_members.each do |member| %>
|
||||
<div class="member-card">
|
||||
<div class="member-name"><%= member.name %></div>
|
||||
<div class="member-stats">
|
||||
<span><strong>Assigned:</strong> <%= member.assigned_tasks.count %></span>
|
||||
<span><strong>Open:</strong> <%= member.assigned_tasks.open.count %></span>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% when 'employee' %>
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @my_tasks.count %></div>
|
||||
<div class="stat-label">My Tasks</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @open_tasks %></div>
|
||||
<div class="stat-label">Open Tasks</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @urgent_tasks %></div>
|
||||
<div class="stat-label">Urgent Tasks</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number"><%= @my_tasks.complete.count %></div>
|
||||
<div class="stat-label">Completed</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="recent-tasks-section">
|
||||
<h2>Recent Tasks</h2>
|
||||
<% if @recent_tasks.empty? %>
|
||||
<p class="empty-state">No recent tasks found.</p>
|
||||
<% else %>
|
||||
<div class="tasks-list">
|
||||
<% @recent_tasks.each do |task| %>
|
||||
<%= render 'task', task: task %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-actions">
|
||||
<%= link_to 'View All Tasks', tasks_path, class: 'action-btn primary' %>
|
||||
<%= link_to 'Create New Task', new_task_path, class: 'action-btn success' %>
|
||||
<% if current_user.admin? || current_user.manager? %>
|
||||
<%= link_to 'Manage Departments', departments_path, class: 'action-btn secondary' %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
2
app/views/tasks/destroy.html.erb
Normal file
2
app/views/tasks/destroy.html.erb
Normal file
@@ -0,0 +1,2 @@
|
||||
<h1>Tasks#destroy</h1>
|
||||
<p>Find me in app/views/tasks/destroy.html.erb</p>
|
||||
16
app/views/tasks/edit.html.erb
Normal file
16
app/views/tasks/edit.html.erb
Normal file
@@ -0,0 +1,16 @@
|
||||
<h1>Edit Task</h1>
|
||||
|
||||
<% if flash[:notice] %>
|
||||
<div class="notice"><%= flash[:notice] %></div>
|
||||
<% end %>
|
||||
|
||||
<div class="edit-task">
|
||||
<%= form_with(model: @task, local: true, class: "task-form edit-form") do |form| %>
|
||||
<%= render 'form', task: @task, form: form %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="back-link">
|
||||
<%= link_to '← Back to Task', @task %> |
|
||||
<%= link_to '← Back to List', tasks_path %>
|
||||
</div>
|
||||
94
app/views/tasks/index.html.erb
Normal file
94
app/views/tasks/index.html.erb
Normal file
@@ -0,0 +1,94 @@
|
||||
<div class="dashboard-header">
|
||||
<h1>Task Management</h1>
|
||||
|
||||
<% if current_user %>
|
||||
<div class="user-info">
|
||||
<span class="user-role">
|
||||
<%= current_user.name %> - <%= current_user.role.humanize %>
|
||||
<% if current_user.department %>
|
||||
( <%= current_user.department.name %> )
|
||||
<% end %>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if flash[:notice] %>
|
||||
<div class="notice"><%= flash[:notice] %></div>
|
||||
<% end %>
|
||||
|
||||
<div class="content-layout">
|
||||
<div class="sidebar">
|
||||
<div class="filter-section">
|
||||
<h3>Filters</h3>
|
||||
|
||||
<% if accessible_departments.count > 1 %>
|
||||
<div class="filter-group">
|
||||
<label>Department</label>
|
||||
<%= form_with(url: tasks_path, method: :get, local: true, class: "filter-form") do |f| %>
|
||||
<%= f.select :department_id,
|
||||
options_for_select([[ "All Departments", "" ]] + accessible_departments.map { |d| [d.name, d.id] },
|
||||
params[:department_id]),
|
||||
{ onchange: "this.form.submit();" },
|
||||
{ class: "filter-select" } %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="filter-group">
|
||||
<label>Priority</label>
|
||||
<%= form_with(url: tasks_path, method: :get, local: true, class: "filter-form") do |f| %>
|
||||
<%= f.select :priority,
|
||||
options_for_select([[ "All Priorities", "" ]] + Task.priorities.keys.map { |p| [p.humanize, p] },
|
||||
params[:priority]),
|
||||
{ onchange: "this.form.submit();" },
|
||||
{ class: "filter-select" } %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label>Status</label>
|
||||
<%= form_with(url: tasks_path, method: :get, local: true, class: "filter-form") do |f| %>
|
||||
<%= f.select :status,
|
||||
options_for_select([[ "All Statuses", "" ]] + Task.statuses.keys.map { |s| [s.humanize, s] },
|
||||
params[:status]),
|
||||
{ onchange: "this.form.submit();" },
|
||||
{ class: "filter-select" } %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions-section">
|
||||
<h3>Actions</h3>
|
||||
<%= link_to 'Dashboard', dashboard_path, class: 'action-btn' %>
|
||||
<%= link_to 'My Tasks', my_tasks_path, class: 'action-btn' if current_user.employee? %>
|
||||
<%= link_to 'Departments', departments_path, class: 'action-btn' if current_user.admin? || current_user.manager? %>
|
||||
<% if current_user.admin? %>
|
||||
<%= link_to 'New User', new_user_registration_path, class: 'action-btn' %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<div class="new-task-section">
|
||||
<h2>Create New Task</h2>
|
||||
<%= form_with(model: @task, local: true, class: "task-form") do |form| %>
|
||||
<%= render 'form', task: @task, form: form %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="tasks-section">
|
||||
<h2>Tasks (<%= @tasks.count %>)</h2>
|
||||
|
||||
<% if @tasks.empty? %>
|
||||
<p class="empty-state">No tasks found with current filters.</p>
|
||||
<% else %>
|
||||
<div class="tasks-list">
|
||||
<% @tasks.each do |task| %>
|
||||
<%= render 'task', task: task %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
41
app/views/tasks/show.html.erb
Normal file
41
app/views/tasks/show.html.erb
Normal file
@@ -0,0 +1,41 @@
|
||||
<div class="task-detail" id="task_detail_<%= @task.id %>">
|
||||
<div class="task-header">
|
||||
<h1 class="task-title <%= 'completed' if @task.completed %>">
|
||||
<%= @task.title %>
|
||||
</h1>
|
||||
<div class="task-meta">
|
||||
<span class="status-badge <%= @task.completed ? 'completed' : 'pending' %>">
|
||||
<%= @task.completed ? '✓ Completed' : '○ Pending' %>
|
||||
</span>
|
||||
<span class="created-date">
|
||||
Created: <%= @task.created_at.strftime('%B %d, %Y at %I:%M %p') %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="task-description">
|
||||
<h2>Description</h2>
|
||||
<% if @task.description.present? %>
|
||||
<div class="description-content">
|
||||
<%= simple_format(@task.description) %>
|
||||
</div>
|
||||
<% else %>
|
||||
<p class="no-description">No description provided.</p>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="task-actions">
|
||||
<%= form_with(model: @task, local: false, method: :patch, class: "toggle-status-form") do |form| %>
|
||||
<%= form.hidden_field :completed, value: !@task.completed %>
|
||||
<%= form.submit @task.completed ? 'Mark as Pending' : 'Mark as Completed',
|
||||
class: "status-toggle-btn #{@task.completed ? 'pending' : 'completed'}" %>
|
||||
<% end %>
|
||||
|
||||
<%= link_to 'Edit Task', edit_task_path(@task), class: 'edit-btn' %>
|
||||
<%= link_to 'Back to List', tasks_path, class: 'back-btn' %>
|
||||
|
||||
<%= link_to 'Delete', @task, method: :delete,
|
||||
data: { confirm: 'Are you sure you want to delete this task?' },
|
||||
class: 'delete-btn' %>
|
||||
</div>
|
||||
</div>
|
||||
2
app/views/tasks/update.html.erb
Normal file
2
app/views/tasks/update.html.erb
Normal file
@@ -0,0 +1,2 @@
|
||||
<h1>Tasks#update</h1>
|
||||
<p>Find me in app/views/tasks/update.html.erb</p>
|
||||
22
app/views/tasks/update.js.erb
Normal file
22
app/views/tasks/update.js.erb
Normal file
@@ -0,0 +1,22 @@
|
||||
// Update task list if on index page to preserve sorting
|
||||
var tasksList = document.querySelector('.tasks-list');
|
||||
if (tasksList) {
|
||||
<% @tasks = Task.ordered %>
|
||||
tasksList.innerHTML = '<%= j render partial: "task", collection: @tasks, as: :task %>';
|
||||
|
||||
// Handle empty state if necessary
|
||||
var emptyState = document.querySelector('.empty-state');
|
||||
if (emptyState) {
|
||||
if (<%= @tasks.any? %>) {
|
||||
emptyState.style.display = 'none';
|
||||
} else {
|
||||
emptyState.style.display = 'block';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update task detail page if present
|
||||
var taskDetail = document.getElementById('task_detail_<%= @task.id %>');
|
||||
if (taskDetail) {
|
||||
taskDetail.outerHTML = '<%= j render template: "tasks/show", formats: [:html], layout: false %>';
|
||||
}
|
||||
Reference in New Issue
Block a user