diff --git a/app/assets/stylesheets/_variables.scss b/app/assets/stylesheets/_variables.scss index b9be833..55f8aca 100644 --- a/app/assets/stylesheets/_variables.scss +++ b/app/assets/stylesheets/_variables.scss @@ -2,6 +2,7 @@ $header-color: #000103; $background-color: #333138; $line-color: #515052; $font-color: #fffffa; +$font-secondary-color: #878787; $highlight-color: #00538F; $link-hover-color: #cccccc; $font-size: 20px; diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 2f4d66a..c4acf7a 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -20,3 +20,5 @@ @import "header"; @import "pagination"; @import "buttons"; + @import "form"; + @import "progress_bar"; diff --git a/app/assets/stylesheets/buttons.scss b/app/assets/stylesheets/buttons.scss index bcf0445..1e52d3f 100644 --- a/app/assets/stylesheets/buttons.scss +++ b/app/assets/stylesheets/buttons.scss @@ -24,4 +24,22 @@ display: flex; align-items: center; gap: 1rem; +} + +.card-button { + color: $font-secondary-color; + text-align: center; + padding: $roundness; + border-radius: $roundness; + background-color: inherit; + border: 1px solid $line-color; + margin: 0 0 10px; + max-width: 100%; + text-decoration: none; + font-size: 0.8em; + + &:hover { + box-shadow: 0 0 5px rgba(0, 0, 0, 0.4); + color: lighten($line-color, 20%); + } } \ No newline at end of file diff --git a/app/assets/stylesheets/form.scss b/app/assets/stylesheets/form.scss new file mode 100644 index 0000000..ddb53df --- /dev/null +++ b/app/assets/stylesheets/form.scss @@ -0,0 +1,45 @@ +@import "variables"; + +.form-heading { + display: flex; + align-items: center; + gap: 0.5rem; + + margin-bottom: 0.5rem; + + h1 { + margin: 0; + } +} + +.gt-form { + input, select { + height: 34px; + width: 100%; + padding: 0 5px; + outline: none; + border-radius: 5px; + background-color: $line-color; + color: $font-color; + border: 2px solid $background-color; + margin-bottom: 4px; + } + + input[type="submit"] { + background-color: $highlight-color; + border: none; + padding: 2px 10px; + border-radius: 5px; + margin-top: 4px; + + &:hover{ + box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); + } + } +} + +.form-card-container { + width: 100%; + max-width: 600px; + margin: 0 auto; +} \ No newline at end of file diff --git a/app/assets/stylesheets/home.scss b/app/assets/stylesheets/home.scss index 8506116..2bd5aed 100644 --- a/app/assets/stylesheets/home.scss +++ b/app/assets/stylesheets/home.scss @@ -56,28 +56,6 @@ main { box-sizing: border-box; } -.gt-form { - input { - padding: 0 5px; - outline: none; - border-radius: 5px; - background-color: $line-color; - color: $font-color; - border: 2px solid $background-color; - } - - input[type="submit"] { - background-color: $highlight-color; - border: none; - padding: 2px 10px; - border-radius: 5px; - - &:hover{ - box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); - } - } -} - .quicklog { /*Can probably switch to gt-form once polished (TODO)*/ //width: 400px; margin-top: 0; @@ -220,8 +198,7 @@ main { } .due-date { - color: $line-color; - font-size: 0.9em; + color: $font-secondary-color; font-style: italic; } @@ -233,20 +210,13 @@ main { } } -.form-heading { - display: flex; - align-items: center; - gap: 0.5rem; - - margin-bottom: 0.5rem; - - h1 { - margin: 0; - } -} - .col.mod-code { width: 100px !important; flex: 0 0 100px; max-width: 100px; +} + +.font-secondary { + color: $font-secondary-color; + font-size: 0.8em; } \ No newline at end of file diff --git a/app/assets/stylesheets/progress_bar.scss b/app/assets/stylesheets/progress_bar.scss index 97d76e9..fd41103 100644 --- a/app/assets/stylesheets/progress_bar.scss +++ b/app/assets/stylesheets/progress_bar.scss @@ -1,6 +1,9 @@ @import "variables"; .progress-bar { + margin: 0; + padding: 0; + border-radius: 1px; background-color: $line-color; height: 3px; @@ -16,4 +19,9 @@ .px-12px { padding-left: 12px; padding-right: 12px; +} + +.mx-12px { + margin-left: 12px; + margin-right: 12px; } \ No newline at end of file diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index f44934d..d649f33 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -10,7 +10,7 @@ def home .where(years: { user_id: current_user.id }) .includes(:uni_modules) - @years = Year.where(user_id: current_user.id).includes(:semesters) + @years = Year.where(user_id: current_user.id).includes(:semesters).order(weighting: :desc) # Get the cumulative time logged for each module @module_data = @uni_modules.map do |mod| @@ -27,6 +27,20 @@ def home } end + @assessment_data = current_user.exam_results + .includes(:exam) + .map { |res| [res.exam.due, res.score] } + + @exam_data = current_user.exam_results + .includes(:exam) + .select { |res| res.exam&.due.present? && res.score.present? } + .map do |res| + { + name: res.exam.name, + data: [[res.exam.due.to_date, res.score.to_f]] + } + end + @exam_type_data = Exam.joins(:uni_module) .where(uni_modules: { id: @uni_modules.map(&:id) }) .group(:type) diff --git a/app/controllers/uni_modules_controller.rb b/app/controllers/uni_modules_controller.rb index e296e15..32a0799 100644 --- a/app/controllers/uni_modules_controller.rb +++ b/app/controllers/uni_modules_controller.rb @@ -6,6 +6,11 @@ class UniModulesController < ApplicationController # GET /uni_modules or /uni_modules.json def index @uni_modules = UniModule.joins(semester: :year).where(years: { user_id: current_user.id }) + + if params[:search].present? + query = "%#{params[:search]}%" + @uni_modules = @uni_modules.where("LOWER(uni_modules.code) LIKE ? OR LOWER(uni_modules.name) LIKE ?", query.downcase, query.downcase) + end end # GET /uni_modules/1 or /uni_modules/1.json diff --git a/app/controllers/years_controller.rb b/app/controllers/years_controller.rb index 5111804..ff18752 100644 --- a/app/controllers/years_controller.rb +++ b/app/controllers/years_controller.rb @@ -69,6 +69,6 @@ def set_year # Only allow a list of trusted parameters through. def year_params - params.require(:year).permit(:name) + params.require(:year).permit(:name, :weighting) end end diff --git a/app/models/semester.rb b/app/models/semester.rb index 37c3fd6..f5f9a71 100644 --- a/app/models/semester.rb +++ b/app/models/semester.rb @@ -23,6 +23,12 @@ def achieved_score(user) total_weight.zero? ? 0 : (weighted_sum / total_weight) end + def progress(user) + total_credits = uni_modules.sum(:credits) + completed_credits = uni_modules.sum { |m| m.completion_percentage(user) * m.credits } + total_credits.zero? ? 0 : (completed_credits / total_credits) + end + private def generate_share_token diff --git a/app/models/user.rb b/app/models/user.rb index f9e6efb..b11db8d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -7,6 +7,7 @@ class User < ApplicationRecord :recoverable, :rememberable, :validatable has_many :years, dependent: :destroy + has_many :exam_results, dependent: :destroy has_many :exams, through: :exam_results has_many :uni_modules, through: :uni_module_targets has_many :timelogs, dependent: :destroy diff --git a/app/models/year.rb b/app/models/year.rb index 609020b..b934d82 100644 --- a/app/models/year.rb +++ b/app/models/year.rb @@ -8,6 +8,7 @@ def credits semesters.includes(:uni_modules).sum { |s| s.credits } end + # The average of all the grades of the semesters in this year def weighted_average(user) return 0 if semesters.empty? total_weight = semesters.sum { |s| s.credits } @@ -15,6 +16,14 @@ def weighted_average(user) total_weight.zero? ? 0 : (weighted_sum / total_weight) end + # The percentage of credits completed by the user in this year + def progress(user) + return 0 if semesters.empty? + completed_credits = semesters.sum { |s| s.progress(user) } + completed_credits / semesters.count + end + + # The accumulated score of all the completed exams in this year def achieved_score(user) return 0 if semesters.empty? semesters.sum { |semester| semester.achieved_score(user) } / semesters.size diff --git a/app/views/devise/registrations/edit.html.haml b/app/views/devise/registrations/edit.html.haml index 40b0c3b..8f8ac43 100644 --- a/app/views/devise/registrations/edit.html.haml +++ b/app/views/devise/registrations/edit.html.haml @@ -1,38 +1,37 @@ -.container - .gt-card.gt-form - %h2 - Edit #{resource_name.to_s.humanize} - = form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| - = render "devise/shared/error_messages", resource: resource - .field - = f.label :email +.gt-card.gt-form + %h2 + Edit #{resource_name.to_s.humanize} + = form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| + = render "devise/shared/error_messages", resource: resource + .field + = f.label :email + %br/ + = f.email_field :email, autofocus: true, autocomplete: "email" + - if devise_mapping.confirmable? && resource.pending_reconfirmation? + %div + Currently waiting confirmation for: #{resource.unconfirmed_email} + .field + = f.label :password + %i (leave blank if you don't want to change it) + %br/ + = f.password_field :password, autocomplete: "new-password" + - if @minimum_password_length %br/ - = f.email_field :email, autofocus: true, autocomplete: "email" - - if devise_mapping.confirmable? && resource.pending_reconfirmation? - %div - Currently waiting confirmation for: #{resource.unconfirmed_email} - .field - = f.label :password - %i (leave blank if you don't want to change it) - %br/ - = f.password_field :password, autocomplete: "new-password" - - if @minimum_password_length - %br/ - %em - = @minimum_password_length - characters minimum - .field - = f.label :password_confirmation - %br/ - = f.password_field :password_confirmation, autocomplete: "new-password" - .field - = f.label :current_password - %i (we need your current password to confirm your changes) - %br/ - = f.password_field :current_password, autocomplete: "current-password" - .actions - = f.submit "Update" - %h3 Cancel my account - %div - Unhappy? #{button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete} - = link_to "Back", :back + %em + = @minimum_password_length + characters minimum + .field + = f.label :password_confirmation + %br/ + = f.password_field :password_confirmation, autocomplete: "new-password" + .field + = f.label :current_password + %i (we need your current password to confirm your changes) + %br/ + = f.password_field :current_password, autocomplete: "current-password" + .actions + = f.submit "Update" + %h3 Cancel my account + %div + Unhappy? #{button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete} + = link_to "Back", :back diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index 0598458..24a9e55 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -1,23 +1,22 @@ -.container - .gt-card.gt-form - %h2 Sign up - = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| - = render "devise/shared/error_messages", resource: resource - .field - = f.label :email - %br/ - = f.email_field :email, autofocus: true, autocomplete: "email" - .field - = f.label :password - - if @minimum_password_length - %em - (#{@minimum_password_length} characters minimum) - %br/ - = f.password_field :password, autocomplete: "new-password" - .field - = f.label :password_confirmation - %br/ - = f.password_field :password_confirmation, autocomplete: "new-password" - .actions - = f.submit "Sign up" - = render "devise/shared/links" +.gt-card.gt-form + %h2 Sign up + = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| + = render "devise/shared/error_messages", resource: resource + .field + = f.label :email + %br/ + = f.email_field :email, autofocus: true, autocomplete: "email" + .field + = f.label :password + - if @minimum_password_length + %em + (#{@minimum_password_length} characters minimum) + %br/ + = f.password_field :password, autocomplete: "new-password" + .field + = f.label :password_confirmation + %br/ + = f.password_field :password_confirmation, autocomplete: "new-password" + .actions + = f.submit "Sign up" + = render "devise/shared/links" diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 9c68451..9ab646e 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -1,19 +1,18 @@ -.container - .gt-card.gt-form - %h2 Log in - = form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| +.gt-card.gt-form + %h2 Log in + = form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| + .field + = f.label :email + %br/ + = f.email_field :email, autofocus: true, autocomplete: "email" + .field + = f.label :password + %br/ + = f.password_field :password, autocomplete: "current-password" + - if devise_mapping.rememberable? .field - = f.label :email - %br/ - = f.email_field :email, autofocus: true, autocomplete: "email" - .field - = f.label :password - %br/ - = f.password_field :password, autocomplete: "current-password" - - if devise_mapping.rememberable? - .field - = f.check_box :remember_me - = f.label :remember_me - .actions - = f.submit "Log in" - = render "devise/shared/links" + = f.check_box :remember_me + = f.label :remember_me + .actions + = f.submit "Log in" + = render "devise/shared/links" diff --git a/app/views/layouts/_sidebar.html.haml b/app/views/layouts/_sidebar.html.haml index c7d307a..4bda920 100644 --- a/app/views/layouts/_sidebar.html.haml +++ b/app/views/layouts/_sidebar.html.haml @@ -22,7 +22,7 @@ .col.mod-code= m.code .col.text-truncate= m.name -#.col-2.text-end= "#{number_with_precision(m.weighted_average(current_user), precision: 0)}%" - .row.progress-bar.px-12px + .row.progress-bar .progress{style: "width: #{m.completion_percentage(current_user)}%"} .gt-card @@ -38,7 +38,7 @@ .col-1.text-end.icon-button.pe-3 %i.fa-solid.fa-arrow-right .row - .col.due-date + .col.due-date.font-secondary Due: = exam.due.strftime("%d %b %Y, %H:%M") - else diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 73e7e66..d4a3c13 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -46,7 +46,7 @@ - else 'alert alert-warning' %p{class: bootstrap_class}= message - = yield + = yield %footer = link_to "GradeTracker", root_path diff --git a/app/views/pages/home.html.haml b/app/views/pages/home.html.haml index d89d52f..72e290a 100644 --- a/app/views/pages/home.html.haml +++ b/app/views/pages/home.html.haml @@ -20,19 +20,49 @@ %span.stat= number_with_precision(current_user.achieved_score, precision: 2) + '%' - @years.each do |year| + -# .gt-card + -# .row + -# %h2.col= year.name + -# %h2.col-3.text-end= "#{number_with_precision(year.achieved_score(current_user), precision: 0)}%" + -# - year.semesters.each do |semester| + -# .row + -# .col= semester.name + -# .col-2.text-end= "#{number_with_precision(semester.weighted_average(current_user), precision: 0)}%" + -# .text-end.icon-button + -# = link_to year_path(year) do + -# %i.fa-solid.fa-arrow-right + .gt-card - .row - %h2.col= year.name - %h2.col-3.text-end= "#{number_with_precision(year.achieved_score(current_user), precision: 0)}%" - - year.semesters.each do |semester| + .card-heading + %h2= year.name + .icon-button + = link_to year_path(year) do + %i.fa-solid.fa-arrow-right + .container-flex + .row.font-secondary + .col Weighting + .col Progress + .col Achieved + .row + .col + - if year.weighting.present? + = "#{number_with_precision(year.weighting, precision: 0)}%" + - else + = "N/A" + .col= "#{number_with_precision(year.progress(current_user), precision: 0)}%" + .col= "#{number_with_precision(year.achieved_score(current_user), precision: 0)}%" .row - .col= semester.name - .col-2.text-end= "#{number_with_precision(semester.weighted_average(current_user), precision: 0)}%" - .text-end.icon-button - = link_to year_path(year) do - %i.fa-solid.fa-arrow-right + .col.progress-bar.mx-12px + - if year.weighting.present? + .progress{style: "width: #{year.weighting}%"} + - else + .progress{style: "width: 0%"} + .col.progress-bar.mx-12px + .progress{style: "width: #{year.progress(current_user)}%"} + .col.progress-bar.mx-12px + .progress{style: "width: #{year.achieved_score(current_user)}%"} -= link_to '+ New Year', new_year_path, class: 'link-button' += link_to '+ New Year', new_year_path, class: 'card-button' %h1.section-heading Statistics -# Graph on left @@ -45,16 +75,11 @@ .row .col .gt-card - %h2 Upcoming Assessments - - if @next_exam - = link_to @next_exam.name, uni_module_exam_path(@next_exam.uni_module, @next_exam) - %span.d-block - %b Due: - = @next_exam.due.strftime("%d %b %Y, %H:%M") - - else - %span No upcoming assessments. + %h2 All Assessments + .chart-container + = line_chart @exam_data, legend: false, width: "100%", height:"300px", points: true, curve: false .col .gt-card %h2 Assessment Type .chart-container - = pie_chart @exam_type_data, legend: false, width: "100%" #, height:"100%" \ No newline at end of file + = pie_chart @exam_type_data, legend: false, width: "100%", height:"300px" \ No newline at end of file diff --git a/app/views/semesters/_form.html.haml b/app/views/semesters/_form.html.haml index 547e357..afdddfb 100644 --- a/app/views/semesters/_form.html.haml +++ b/app/views/semesters/_form.html.haml @@ -1,18 +1,19 @@ -= form_for @semester do |f| - - if @semester.errors.any? - #error_explanation - %h2= "#{pluralize(@semester.errors.count, "error")} prohibited this semester from being saved:" - %ul - - @semester.errors.full_messages.each do |message| - %li= message +.gt-form + = form_for @semester do |f| + - if @semester.errors.any? + #error_explanation + %h2= "#{pluralize(@semester.errors.count, "error")} prohibited this semester from being saved:" + %ul + - @semester.errors.full_messages.each do |message| + %li= message - .field - = f.label :name - = f.text_field :name - - .field - = f.label :year_id, "Year" - = f.collection_select :year_id, current_user.years, :id, :name, prompt: "Select Year" + .field + = f.label :year_id, "Year" + = f.collection_select :year_id, current_user.years, :id, :name, prompt: "Select Year" + + .field + = f.label :name + = f.text_field :name - .actions - = f.submit 'Save' + .actions + = f.submit 'Save' diff --git a/app/views/semesters/edit.html.haml b/app/views/semesters/edit.html.haml index cecd356..4977142 100644 --- a/app/views/semesters/edit.html.haml +++ b/app/views/semesters/edit.html.haml @@ -1,7 +1,9 @@ -%h1 Editing semester +.form-card-container + .gt-card + .form-heading + .icon-button + = link_to @semester do + %i.fa-solid.fa-arrow-left + %h1 Editing Semester -= render 'form' - -= link_to 'Show', @semester -\| -= link_to 'Back', semesters_path + = render 'form' diff --git a/app/views/semesters/new.html.haml b/app/views/semesters/new.html.haml index 88aa789..2dadef4 100644 --- a/app/views/semesters/new.html.haml +++ b/app/views/semesters/new.html.haml @@ -1,8 +1,6 @@ -%h1 New semester +.form-card-container + .gt-card + .card-heading + %h1 New Semester -= render 'form' - -- if @semester.year_id - = link_to 'Back to Year', year_path(@semester.year_id), class: 'link-button' -- else - = link_to 'Back to Semesters', semesters_path, class: 'link-button' + = render 'form' diff --git a/app/views/uni_modules/_form.html.haml b/app/views/uni_modules/_form.html.haml index a65d7ad..1638c6a 100644 --- a/app/views/uni_modules/_form.html.haml +++ b/app/views/uni_modules/_form.html.haml @@ -6,7 +6,9 @@ %ul - @uni_module.errors.full_messages.each do |message| %li= message - + .field + = f.label :semester_id, "Semester" + = f.collection_select :semester_id, Semester.all, :id, :name, prompt: "Select a Semester" .field = f.label :code = f.text_field :code @@ -16,9 +18,6 @@ .field = f.label :credits = f.number_field :credits - .field - = f.label :semester_id, "Semester" - = f.collection_select :semester_id, Semester.all, :id, :name, prompt: "Select a Semester" .actions = f.submit 'Save' diff --git a/app/views/uni_modules/edit.html.haml b/app/views/uni_modules/edit.html.haml index cfbe6db..3b92c5b 100644 --- a/app/views/uni_modules/edit.html.haml +++ b/app/views/uni_modules/edit.html.haml @@ -1,4 +1,4 @@ -.container +.form-card-container .gt-card .card-heading %h1 Editing Module diff --git a/app/views/uni_modules/index.html.haml b/app/views/uni_modules/index.html.haml index e24b3c6..7340639 100644 --- a/app/views/uni_modules/index.html.haml +++ b/app/views/uni_modules/index.html.haml @@ -1,12 +1,18 @@ -%h1 Listing uni_modules +%h1 All Modules + +.gt-form + = form_with url: uni_modules_path, method: :get, local: true do + = label_tag :search, "Search Modules:" + = text_field_tag :search, params[:search] + = submit_tag "Search" %table %thead %tr %th Code %th Name - %th - %th + %th Credits + %th Achieved Score %th %tbody @@ -14,10 +20,12 @@ %tr %td= uni_module.code %td= uni_module.name - %td= link_to 'Show', uni_module - %td= link_to 'Edit', edit_uni_module_path(uni_module) - %td= link_to 'Destroy', uni_module, method: :delete, data: { confirm: 'Are you sure?' } + %td= uni_module.credits + %td= number_with_precision(uni_module.achieved_score(current_user), precision: 2) + '%' + %td.icon-button + = link_to uni_module do + %i.fa-solid.fa-arrow-right %br -= link_to 'New Uni module', new_uni_module_path += link_to 'New Uni module', new_uni_module_path, class: 'link-button' diff --git a/app/views/uni_modules/new.html.haml b/app/views/uni_modules/new.html.haml index 7792f55..61fc6b1 100644 --- a/app/views/uni_modules/new.html.haml +++ b/app/views/uni_modules/new.html.haml @@ -1,7 +1,6 @@ -.container +.form-card-container .gt-card - .card-heading + .form-heading %h1 New Module - = link_to 'All Modules', uni_modules_path = render 'form' diff --git a/app/views/years/_form.html.haml b/app/views/years/_form.html.haml index d9ef953..3fdcc25 100644 --- a/app/views/years/_form.html.haml +++ b/app/views/years/_form.html.haml @@ -1,14 +1,19 @@ -= form_for @year do |f| - - if @year.errors.any? - #error_explanation - %h2= "#{pluralize(@year.errors.count, "error")} prohibited this year from being saved:" - %ul - - @year.errors.full_messages.each do |message| - %li= message +.gt-form + = form_for @year do |f| + - if @year.errors.any? + #error_explanation + %h2= "#{pluralize(@year.errors.count, "error")} prohibited this year from being saved:" + %ul + - @year.errors.full_messages.each do |message| + %li= message - .field - = f.label :name - = f.text_field :name + .field + = f.label :name + = f.text_field :name - .actions - = f.submit 'Save' + .field + = f.label :weighting + = f.number_field :weighting, step: 0.01, min: 0, max: 100 + + .actions + = f.submit 'Save' diff --git a/app/views/years/edit.html.haml b/app/views/years/edit.html.haml index f7e910c..0e2976a 100644 --- a/app/views/years/edit.html.haml +++ b/app/views/years/edit.html.haml @@ -1,8 +1,9 @@ -.gt-card.gt-form - .form-heading - .icon-button - = link_to @year do - %i.fa-solid.fa-arrow-left - %h1 Editing year +.form-card-container + .gt-card.gt-form + .form-heading + .icon-button + = link_to @year do + %i.fa-solid.fa-arrow-left + %h1 Editing Year - = render 'form' + = render 'form' diff --git a/app/views/years/new.html.haml b/app/views/years/new.html.haml index ad40b89..2bc8416 100644 --- a/app/views/years/new.html.haml +++ b/app/views/years/new.html.haml @@ -1,5 +1,6 @@ -%h1 New year - -= render 'form' - -= link_to 'Back', years_path +.form-card-container + .gt-card + .form-heading + %h1 New year + + = render 'form' diff --git a/app/views/years/show.html.haml b/app/views/years/show.html.haml index a1762d2..34c8020 100644 --- a/app/views/years/show.html.haml +++ b/app/views/years/show.html.haml @@ -35,6 +35,4 @@ %i.fa-solid.fa-arrow-right -= link_to '+ New Semester', new_semester_path(year_id: @year.id), class: 'link-button' - -= link_to 'Back', root_path += link_to '+ New Semester', new_semester_path(year_id: @year.id), class: 'card-button' diff --git a/db/migrate/20250718211949_add_weighting_to_years.rb b/db/migrate/20250718211949_add_weighting_to_years.rb new file mode 100644 index 0000000..20ffa29 --- /dev/null +++ b/db/migrate/20250718211949_add_weighting_to_years.rb @@ -0,0 +1,5 @@ +class AddWeightingToYears < ActiveRecord::Migration[7.1] + def change + add_column :years, :weighting, :float + end +end diff --git a/db/schema.rb b/db/schema.rb index 8943e54..13327a6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2025_07_03_120000) do +ActiveRecord::Schema[7.1].define(version: 2025_07_18_211949) do create_table "exam_results", force: :cascade do |t| t.integer "user_id", null: false t.integer "exam_id", null: false @@ -102,6 +102,7 @@ t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "user_id", null: false + t.float "weighting" t.index ["user_id"], name: "index_years_on_user_id" end diff --git a/spec/factories/exam_results.rb b/spec/factories/exam_results.rb new file mode 100644 index 0000000..064a9e6 --- /dev/null +++ b/spec/factories/exam_results.rb @@ -0,0 +1,7 @@ +FactoryBot.define do + factory :exam_result do + association :user + association :exam + score { 75.5 } + end +end diff --git a/spec/factories/exams.rb b/spec/factories/exams.rb new file mode 100644 index 0000000..6d9a0a9 --- /dev/null +++ b/spec/factories/exams.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :exam do + name { "Easy Exam" } + weight { 1.0 } + end +end diff --git a/spec/system/dashboard_spec.rb b/spec/system/dashboard_spec.rb new file mode 100644 index 0000000..261fb44 --- /dev/null +++ b/spec/system/dashboard_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Visiting the homepage', type: :system do + let(:user) { create(:user) } + + it 'shows the welcome text' do + login_as user + visit '/' + expect(page).to have_content 'Dashboard' + end + + it 'shows year progress' do + login_as user + create(:year, user: user, name: 'Year 1', weighting: 25) + create(:year, user: user, name: 'Year 2', weighting: 75) + visit '/' + expect(page).to have_content 'Year 1' + expect(page).to have_content 'Year 2' + expect(page).to have_content '25%' + expect(page).to have_content '75%' + end + + it 'shows the achieved score' do + login_as user + year = create(:year, user: user, name: 'Year 1', weighting: 50) + semester = create(:semester, year: year, name: 'Semester 1') + uni_module = create(:uni_module, semester: semester, credits: 30) + create(:uni_module, semester: semester, credits: 30) # Another module to ensure calculation is correct + exam = create(:exam, uni_module: uni_module) + create(:exam_result, user: user, exam: exam, score: 80) + + visit '/' + expect(page).to have_content 'Achieved' + expect(page).to have_content '40%' + end +end diff --git a/spec/system/homepage_spec.rb b/spec/system/homepage_spec.rb deleted file mode 100644 index 42d2666..0000000 --- a/spec/system/homepage_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -RSpec.describe 'Visiting the homepage', type: :system do - let(:user) { create(:user) } - - it 'shows the welcome text' do - login_as user - visit '/' - expect(page).to have_content 'Dashboard' - end -end