Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
@import "./components/ranks.css";
@import "./components/ranking.css";
@import "./components/teachers.css";
@import "./components/organizations.css";
@import "./components/badges.css";
@import "./components/items.css";
@import "./components/shop.css";
Expand Down
170 changes: 170 additions & 0 deletions app/assets/stylesheets/components/organizations.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
@layer components {

.gh-organizations-panel {
margin-top: 22px;
padding: 6px 8px;
}

.gh-organizations-panel-title {
padding: 12px 12px 6px;
}

.gh-organizations-panel > .gh-explainer-note {
margin: 0;
padding: 6px 12px 14px;
}

.gh-organization-row,
.gh-organization-member-row {
display: grid;
gap: 12px;
align-items: center;
padding: 12px;
border-top: 1px solid var(--gh-line);
}

.gh-organization-row {
grid-template-columns: minmax(0, 2fr) 120px 120px;
}

.gh-organization-member-row {
grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr) 140px 96px;
}

.gh-organizations-panel-title + .gh-organization-member-row {
border-top: 0;
}

.gh-organization-row--link {
color: inherit;
text-decoration: none;
}

.gh-organization-row--link:hover {
background: color-mix(in srgb, var(--gh-ink) 5%, transparent);
}

.gh-organization-name {
font: 650 15px var(--gh-f-ui);
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

.gh-organization-member-actions {
display: flex;
justify-content: flex-end;
gap: 6px;
}

/* Admin start screens */

.gh-stat-row--numeric .gh-stat-tile:last-child dd {
font-size: 26px;
line-height: 1;
}

.gh-start-org-list {
margin-top: 10px;
}

.gh-start-org-row {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(140px, 220px);
gap: 16px;
align-items: center;
padding: 12px 4px;
border-top: 1px solid var(--gh-line);
color: inherit;
text-decoration: none;
}

a.gh-start-org-row:hover b {
text-decoration: underline;
}

.gh-capacity-bar {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 10px;
align-items: center;
margin: 10px 0;
}

.gh-capacity-bar .gh-small {
font-variant-numeric: tabular-nums;
}

.gh-progress-bar--full > i {
background: var(--gh-heart);
}

.gh-start-more {
margin-top: 14px;
}

.gh-start-attention-list {
list-style: none;
margin: 10px 0 0;
padding: 0;
}

.gh-start-attention-list li {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 2px 12px;
align-items: center;
padding: 10px 0;
border-top: 1px solid var(--gh-line);
}

.gh-start-attention-list li > :first-child {
font-weight: 650;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
}

.gh-start-attention-list small {
grid-column: 1;
color: var(--gh-ink-3);
}

.gh-start-attention-list .gh-btn {
grid-column: 2;
grid-row: 1 / 3;
}

@media (width <= theme(--breakpoint-mobile)) {
.gh-start-org-row {
grid-template-columns: minmax(0, 1fr);
gap: 4px;
}

.gh-organization-row,
.gh-organization-member-row {
grid-template-columns: minmax(0, 1fr) auto;
gap: 6px 12px;
}

.gh-organization-row--header,
.gh-organization-member-row--header {
display: none;
}

.gh-organization-row > :not(:first-child) {
grid-column: 1;
}

.gh-organization-member-row > :not(:last-child) {
grid-column: 1;
}

.gh-organization-member-row > :last-child {
grid-column: 2;
grid-row: 1 / 4;
align-self: center;
}
}
}
4 changes: 3 additions & 1 deletion app/assets/stylesheets/components/table.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
.gh-invite-row--header,
.gh-ledger-row--header,
.gh-ranking-row--header,
.gh-student-row--header {
.gh-student-row--header,
.gh-organization-row--header,
.gh-organization-member-row--header {
border-top: 0;
font: 680 12.5px var(--gh-f-ui);
color: var(--gh-ink-3);
Expand Down
9 changes: 7 additions & 2 deletions app/components/shared/sidebar_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ def nav_items
end

# `all_story_groups` already unions owned, taught and joined groups and
# uniques them, which is exactly the mockup's "Twoje grupy" list.
# uniques them, which is exactly the mockup's "Twoje grupy" list. Global
# admins manage organizations only, so they get no group list.
def groups
@groups ||= user.all_story_groups.sort_by { |group| group.name.to_s.downcase }
@groups ||= if user.global_admin?
[]
else
user.all_story_groups.sort_by { |group| group.name.to_s.downcase }
end
end

# "Prowadzisz" for a group you own, "Wspierasz" for one you co-teach,
Expand Down
35 changes: 35 additions & 0 deletions app/controllers/account_setups_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

class AccountSetupsController < ApplicationController
skip_before_action :require_account_setup!
before_action :redirect_configured_user
before_action -> { @chrome = false }

def edit; end

def update
@current_user.assign_attributes(account_setup_params)
@current_user.first_login = false

if @current_user.save(context: :account_setup)
redirect_to home_path, notice: 'Pomyślnie skonfigurowano konto.'
else
@current_user.first_login = true
render :edit, status: :unprocessable_content
end
end

private

def redirect_configured_user
redirect_to home_path unless @current_user.needs_account_setup?
end

def account_setup_params
params.expect(
user: %i[
full_name
],
)
end
end
4 changes: 4 additions & 0 deletions app/controllers/auth/usos_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ def create
redirect_to root_path, alert: 'Nieprawidłowy dostawca logowania.'
rescue Providers::InvalidAuthError
redirect_to root_path, alert: 'Nieprawidłowa próba autoryzacji.'
rescue SessionUserBuilder::OrganizationNotFoundError
redirect_to root_path, alert: 'Twoja uczelnia nie jest zarejestrowana jako organizacja.'
rescue SessionUserBuilder::OrganizationFullError
redirect_to root_path, alert: 'Organizacja Twojej uczelni osiągnęła limit członków.'
end

private
Expand Down
5 changes: 5 additions & 0 deletions app/controllers/concerns/authentication.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module ::Authentication
included do
before_action :set_current_user
before_action :authenticate!
before_action :require_account_setup!
end

protected
Expand All @@ -30,4 +31,8 @@ def store_return_path
def full_page_navigation?
request.get? && !request.xhr? && !turbo_frame_request?
end

def require_account_setup!
redirect_to edit_account_setup_path if @current_user&.needs_account_setup?
end
end
10 changes: 8 additions & 2 deletions app/controllers/home_controller.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
# frozen_string_literal: true

class HomeController < ApplicationController
# The landing screen after login. Two different screens behind one route,
helper OrganizationsHelper

# The landing screen after login. One screen per role behind one route,
# mirroring StoryGroupsController#show: the view dispatches on the role, the
# controller loads the matching dashboard.
def index
@dashboard =
if current_user.teacher?
if current_user.global_admin?
GlobalAdminStartDashboard.new.load
elsif current_user.organization_admin?
OrganizationAdminStartDashboard.new(user: current_user).load
elsif current_user.teacher?
TeacherStartDashboard.new(user: current_user, filter: params[:group]).load
else
StudentStartDashboard.new(user: current_user).load
Expand Down
64 changes: 64 additions & 0 deletions app/controllers/organizations/users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

class Organizations::UsersController < ApplicationController
helper OrganizationsHelper

before_action :set_presentation
before_action :set_organization
before_action :set_user

def edit; end

def update
@user.assign_attributes(user_params)

if @user.save(context: :user_invitation)
redirect_after_save notice: "Zapisano zmiany: #{@user.full_name}."
else
render :edit, status: :unprocessable_content
end
end

def confirm_destroy; end

def destroy
name = @user.full_name
@user.destroy!

redirect_after_save notice: "Usunięto użytkownika: #{name}."
end

private

def set_presentation
@in_modal = turbo_frame_request_id == 'modal'
end

def redirect_after_save(notice:)
path = organization_path(@organization)
return redirect_outside_turbo_frame(path, notice: notice) if @in_modal

redirect_to path, notice: notice, status: :see_other
end

def set_organization
@organization = Organization.find(params.expect(:organization_id))
authorize @organization, :manage_users?
end

def set_user
@user = @organization.users.where(role: User::INVITABLE_ROLES).find(params.expect(:id))
end

def user_params
params.expect(
user: %i[
email
full_name
university_number
usos_id
role
],
)
end
end
Loading
Loading