diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 1f46a9bd810..2f33493ba31 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -13,6 +13,8 @@ def index else user_scope.where(retired_on: nil) end + @job = params[:job] + user_scope = user_scope.users_job(@job) if @job.present? @users = user_scope.with_attached_avatar .preload(:company, :course) .order_by_counts(params[:order_by] || 'id', @direction) diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index dbb26cfde55..d6f1a661ba6 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -70,4 +70,14 @@ def all_countries_with_subdivisions .to_h .to_json end + + def roles_for_select + roles = %w[all student_and_trainee inactive hibernated retired graduate adviser mentor trainee year_end_party campaign] + roles.map { |role| [t("target.#{role}"), role] } + end + + def jobs_for_select + user_jobs = User.jobs.keys.map { |job| [t("activerecord.enums.user.job.#{job}"), job] } + user_jobs.prepend(%w[全員 all]) + end end diff --git a/app/javascript/stylesheets/application.sass b/app/javascript/stylesheets/application.sass index 5f16ddb56f3..0881c4c2c1a 100644 --- a/app/javascript/stylesheets/application.sass +++ b/app/javascript/stylesheets/application.sass @@ -79,6 +79,7 @@ @import application/blocks/page/page-tabs @import application/blocks/page/page @import application/blocks/page/page-filter +@import application/blocks/page/page-main-filter @import application/blocks/page-content/page-content @import application/blocks/page-content/page-content-header-actions diff --git a/app/javascript/stylesheets/application/blocks/page/_page-main-filter.sass b/app/javascript/stylesheets/application/blocks/page/_page-main-filter.sass new file mode 100644 index 00000000000..d722439fca7 --- /dev/null +++ b/app/javascript/stylesheets/application/blocks/page/_page-main-filter.sass @@ -0,0 +1,11 @@ +.page-main-filter__inner + display: block + padding-block: .75rem + +.page-main-filter__row + display: flex + gap: 1rem + align-items: center + flex-wrap: wrap + .page-main-filter__row + gap: .5rem diff --git a/app/javascript/stylesheets/atoms/_a-form-label.sass b/app/javascript/stylesheets/atoms/_a-form-label.sass index 4d587547451..54dcb09b6bb 100644 --- a/app/javascript/stylesheets/atoms/_a-form-label.sass +++ b/app/javascript/stylesheets/atoms/_a-form-label.sass @@ -1,5 +1,7 @@ .a-form-label +text-block(.875rem 1.5 0 .5rem, block 600) + &:last-child + margin-bottom: 0 &.is-required &::after +fa(fas '\f069') diff --git a/app/models/user.rb b/app/models/user.rb index f008366dad8..939862fd7a9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -428,6 +428,14 @@ def users_role(target, allowed_targets: [], default_target: :none) send(scope_name) end + # User::users_roleと同じく安全性確保のため、以下の条件を指定している。 + # allowed_job.include?(job): 存在する職業を過不足なく指定した配列の中に、jobが存在するかどうかチェック。 + def users_job(job) + allowed_jobs = User.jobs.keys.freeze + scope_name = allowed_jobs.include?(job) ? "job_#{job}" : 'all' + send(scope_name) + end + def tags unretired.unhibernated.all_tag_counts(order: 'count desc, name asc') end diff --git a/app/views/admin/users/_filter.html.slim b/app/views/admin/users/_filter.html.slim new file mode 100644 index 00000000000..1f2b1526d6a --- /dev/null +++ b/app/views/admin/users/_filter.html.slim @@ -0,0 +1,24 @@ +.page-main-filter + .container + = form_with url: admin_users_path(target: @target, job: @job), local: true, method: 'get', class: 'page-main-filter__inner' do + .page-main-filter__row + .page-main-filter__column + .page-main-filter__row + .page-main-filter__column + label.a-form-label.is-sm + | ロール + .page-main-filter__column + .a-button.is-sm.is-secondary.is-select.is-block + = select_tag 'target', options_for_select(roles_for_select, params[:target]) + .page-main-filter__column + .page-main-filter__row + .page-main-filter__column + label.a-form-label.is-sm + | 職業 + .page-main-filter__column + .a-button.is-sm.is-secondary.is-select.is-block + = select_tag 'job', options_for_select(jobs_for_select, params[:job]) + .page-main-filter__column + button.a-button.is-sm.is-primary.is-block + span + | この条件で絞り込む diff --git a/app/views/admin/users/_nav.html.slim b/app/views/admin/users/_nav.html.slim deleted file mode 100644 index 786468d4a38..00000000000 --- a/app/views/admin/users/_nav.html.slim +++ /dev/null @@ -1,6 +0,0 @@ -nav.tab-nav.is-in-tab - .container - ul.tab-nav__items - - %w[all student_and_trainee inactive hibernated retired graduate adviser mentor trainee year_end_party campaign].each do |target| - li.tab-nav__item - = link_to t("target.#{target}"), admin_users_path(target:), class: (@target == target ? ['is-active'] : []) << 'tab-nav__item-link' diff --git a/app/views/admin/users/_sort_column.html.slim b/app/views/admin/users/_sort_column.html.slim index 44ab475aad7..94b66082196 100644 --- a/app/views/admin/users/_sort_column.html.slim +++ b/app/views/admin/users/_sort_column.html.slim @@ -1,6 +1,6 @@ - direction = params[:order_by] == order_by && direction == 'asc' ? 'desc' : 'asc' -= link_to admin_users_path(order_by:, direction:, target:), class: 'a-button is-xs is-secondary is-icon' do += link_to admin_users_path(order_by:, direction:, target:, job:), class: 'a-button is-xs is-secondary is-icon' do - if direction == 'asc' i.fa-solid.fa-caret-up - else diff --git a/app/views/admin/users/_table.html.slim b/app/views/admin/users/_table.html.slim index 3894e8fff83..f4770f939ed 100644 --- a/app/views/admin/users/_table.html.slim +++ b/app/views/admin/users/_table.html.slim @@ -5,21 +5,21 @@ th.admin-table__label ステータス th.admin-table__label | ユーザー名 - = render 'sort_column', order_by: 'login_name', direction: direction, target: @target + = render 'sort_column', order_by: 'login_name', direction: direction, target: @target, job: @job th.admin-table__label | メールアドレス th.admin-table__label | 企業 - = render 'sort_column', order_by: 'company_id', direction: direction, target: @target + = render 'sort_column', order_by: 'company_id', direction: direction, target: @target, job: @job th.admin-table__label 職業 th.admin-table__label Discord th.admin-table__label | = User.human_attribute_name :last_activity_at - = render 'sort_column', order_by: 'last_activity_at', direction: direction, target: @target + = render 'sort_column', order_by: 'last_activity_at', direction: direction, target: @target, job: @job th.admin-table__label | 登録日時 - = render 'sort_column', order_by: 'created_at', direction: direction, target: @target + = render 'sort_column', order_by: 'created_at', direction: direction, target: @target, job: @job th.admin-table__label 相談部屋 th.admin-table__label カード登録 th.admin-table__label サブスク diff --git a/app/views/admin/users/index.html.slim b/app/views/admin/users/index.html.slim index d4e23272081..b47473c93cb 100644 --- a/app/views/admin/users/index.html.slim +++ b/app/views/admin/users/index.html.slim @@ -7,8 +7,16 @@ header.page-header = title = render 'admin/admin_page_tabs' -= render 'nav' - -.page-body - .container - = render 'table', users: @users, direction: @direction +main.page-main + header.page-main-header + .container + .page-main-header__inner + .page-main-header__start + h1.page-main-header__title + | ユーザー一覧 + hr.a-border + = render 'filter' + hr.a-border + .page-body + .container + = render 'table', users: @users, direction: @direction diff --git a/test/helpers/users_helper.rb b/test/helpers/users_helper.rb index d719e5aab93..c60e920bd10 100644 --- a/test/helpers/users_helper.rb +++ b/test/helpers/users_helper.rb @@ -8,4 +8,33 @@ class UsersHelperTest < ActionView::TestCase assert_includes countries['JP'], %w[北海道 01] assert_includes countries['US'], %w[アラスカ州 AK] end + + test '#roles_for_select' do + user_roles = [ + %w[全員 all], + %w[現役生 student_and_trainee], + %w[非アクティブ inactive], + %w[休会 hibernated], + %w[退会 retired], + %w[卒業 graduate], + %w[アドバイザー adviser], + %w[メンター mentor], + %w[研修生 trainee], + %w[忘年会 year_end_party], + %w[お試し延長 campaign] + ] + assert roles_for_select, user_roles + end + + test '#jobs_for_select' do + user_jobs = [ + %w[全員 all], + %w[学生 student], + %w[会社員 office_worker], + %w[フリーター part_time_worker], + %w[休職中 vacation], + %w[働いていない unemployed] + ] + assert jobs_for_select, user_jobs + end end diff --git a/test/models/user_test.rb b/test/models/user_test.rb index bc80a913e23..2c640305142 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -724,4 +724,16 @@ class UserTest < ActiveSupport::TestCase assert_equal '2020-07-01 09:00:00 +0900', users(:kyuukai).scheduled_retire_at.to_s assert_nil users(:hatsuno).scheduled_retire_at end + + test '.users_job' do + assert_equal User.job_student, User.users_job('student') + assert_equal User.job_office_worker, User.users_job('office_worker') + assert_equal User.job_part_time_worker, User.users_job('part_time_worker') + assert_equal User.job_vacation, User.users_job('vacation') + assert_equal User.job_unemployed, User.users_job('unemployed') + end + + test '.users_job returns all users when invalid job is passed' do + assert_equal User.all, User.users_job('destroy_all') + end end diff --git a/test/system/admin/users_test.rb b/test/system/admin/users_test.rb index 1e0e7138552..944c51bff95 100644 --- a/test/system/admin/users_test.rb +++ b/test/system/admin/users_test.rb @@ -44,6 +44,13 @@ class Admin::UsersTest < ApplicationSystemTestCase assert_text 'kensyu(Kensyu Seiko)' end + test 'show listing graduated and office_worker' do + visit_with_auth '/admin/users?target=graduate&job=office_worker', 'komagata' + assert_equal '管理ページ | FBC', title + assert_text 'sotugyou-with-job(卒業 就職済美)' + assert_no_text 'sotugyou(卒業 太郎)' + end + test 'exclude hibernated and retired users from year-end-party email list' do visit_with_auth '/admin/users?target=year_end_party', 'komagata' assert_equal '管理ページ | FBC', title