Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bring back user profile #599

Merged
merged 80 commits into from
Mar 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
f8a73a1
add first tables to display profile data
RandomTannenbaum Feb 13, 2024
8da7aad
add language and profile pic to view and add a new section in the vie…
RandomTannenbaum Feb 16, 2024
0414a9a
style headers of user profile data table and move edit link
RandomTannenbaum Feb 16, 2024
fd6458b
display languages in a very basic way
RandomTannenbaum Feb 16, 2024
86d149c
make account overview display country name instead of alpha2 code and…
RandomTannenbaum Feb 16, 2024
bdd96ac
fix displaying of values in dropdowns, to represent actual state of o…
RandomTannenbaum Feb 19, 2024
5a90a03
label role form fields and correctly display role in overview
RandomTannenbaum Feb 20, 2024
7d49266
replace @entry with @person after rebase and remove nested_models and…
RandomTannenbaum Feb 20, 2024
6feae9f
move edit form to edit route and add turbo frame that loads edit form…
RandomTannenbaum Feb 20, 2024
a2a154e
fix alignment of tables, set width of input fields to match table wid…
RandomTannenbaum Feb 20, 2024
46055cb
style edit form to use bootstrap form fields
RandomTannenbaum Feb 23, 2024
968d06a
adjust font-weights of edit form
RandomTannenbaum Feb 23, 2024
bee42d0
create controller method to load correct picture path, add uploads to…
RandomTannenbaum Feb 23, 2024
37ba30f
add default avatar to public directory
RandomTannenbaum Feb 23, 2024
d287a2c
make view display nil properties of person as -, create picture contr…
RandomTannenbaum Feb 23, 2024
15c315e
add picture to permitted attrs
RandomTannenbaum Feb 23, 2024
e958f7b
add dummy role adding button in person edit view and make marital sta…
RandomTannenbaum Feb 23, 2024
789f0f9
start working on updating roles by renaming the params in the form an…
RandomTannenbaum Feb 23, 2024
8219d40
rewrite profile to use fields_for instead of a normal for loop, for s…
RandomTannenbaum Feb 26, 2024
a3dfe6b
add person_roles_attributes to permitted attributes
RandomTannenbaum Feb 27, 2024
9daf507
make edit view conditionally display the second nationality dropdown …
RandomTannenbaum Feb 27, 2024
118c9a0
make person overview and edit view responsive
RandomTannenbaum Feb 27, 2024
12ac44a
remove overflow scroll from person overview and edit view
RandomTannenbaum Feb 27, 2024
10928cc
move fields of role form to partial and start writing logic to create…
RandomTannenbaum Feb 27, 2024
f202713
add remove button to roles in edit view and fix rendering of form
RandomTannenbaum Mar 1, 2024
8d9c5f8
add missing class to person role fields partial, add js method to mak…
RandomTannenbaum Mar 1, 2024
a26f027
refactor too long lines, add comments, move whole edit form to form p…
RandomTannenbaum Mar 1, 2024
9e5677c
fix name attribute of contries in form
RandomTannenbaum Mar 1, 2024
743f589
replace pzsh container with div to prevent moving whole page to center
RandomTannenbaum Mar 1, 2024
d659580
style the show view of the person
RandomTannenbaum Mar 1, 2024
ad9afaa
fix styling of edit view
RandomTannenbaum Mar 1, 2024
df96049
change w-100 to mw-100 everywhere in edit view
RandomTannenbaum Mar 1, 2024
0bd65fa
make image instantly update on file upload by using a stimulus contro…
RandomTannenbaum Mar 1, 2024
9e52451
fix nationality2 checkbox
RandomTannenbaum Mar 4, 2024
6490198
add picture cache for profile picture, style picture upload button fi…
RandomTannenbaum Mar 4, 2024
8b6fce7
adjust color of buttons in person edit view
RandomTannenbaum Mar 4, 2024
0c6b0f4
fix loading of profile picture after saving and style profile picture…
RandomTannenbaum Mar 5, 2024
5cb14ff
fix template error in show view of person, when person role level or …
RandomTannenbaum Mar 5, 2024
e1c5105
fix rubocop offenses
RandomTannenbaum Mar 8, 2024
bc470f6
fix last rubocop offenses
RandomTannenbaum Mar 8, 2024
38b38e0
write test that tests if editing a person is possible, assign id to s…
RandomTannenbaum Mar 8, 2024
4b4e4cc
remove unwanted header from person profile
RandomTannenbaum Mar 8, 2024
2850196
change dateformat in equal check of feature spec to make test work ac…
RandomTannenbaum Mar 8, 2024
243278e
change _ to - in ids of save cancel and edit buttons and write test t…
RandomTannenbaum Mar 8, 2024
d393baf
revert formating of date in test
RandomTannenbaum Mar 8, 2024
ef03dfa
bring back formatting of date in test
RandomTannenbaum Mar 8, 2024
bb68559
Change filling of date input in test to default html
RandomTannenbaum Mar 8, 2024
3af92e5
Fix date formating for filling form in test
RandomTannenbaum Mar 8, 2024
0fcc97f
make test also upload new image and check if avatar upload field exists
RandomTannenbaum Mar 8, 2024
89cc571
rename method of has_nationality2 checkbox to checked and start writi…
RandomTannenbaum Mar 8, 2024
0a724e7
Add param converter concerns to check if param is false, use new fals…
RandomTannenbaum Mar 11, 2024
dfca71b
Remove rubocop offense and check if nationality2 is not null initiall…
RandomTannenbaum Mar 11, 2024
c01f61a
style person show view to wrap text and replace some unless statement…
RandomTannenbaum Mar 11, 2024
6dfda1e
reimplement whole picture controller from api namespace, cleanup code
RandomTannenbaum Mar 11, 2024
920eadd
move picture test from api namespace to people namespace and xdescrib…
RandomTannenbaum Mar 11, 2024
f2f07a1
fix rubocop offense
RandomTannenbaum Mar 11, 2024
03879f4
Dont display role percentage if there is no role percentage in person…
RandomTannenbaum Mar 11, 2024
fd9699a
revert unnecessary file change
RandomTannenbaum Mar 11, 2024
10911d4
remove unneeded picture helpers and specs
RandomTannenbaum Mar 11, 2024
bdcd91f
add translations for marital statuses
RandomTannenbaum Mar 11, 2024
7213b45
fix loading of avatar because it vanished in specific cases
RandomTannenbaum Mar 12, 2024
f494fec
fix translation yml files and translate marital status and nationality
RandomTannenbaum Mar 12, 2024
287e1c9
fix tests after localization and test if avatar is saved in feature spec
RandomTannenbaum Mar 12, 2024
2ffd1ec
replace alpha2 code with actual country name in people show view
RandomTannenbaum Mar 12, 2024
51df400
make picture controller inherit from new crud controller instead of a…
RandomTannenbaum Mar 12, 2024
a9cae8a
make people controller test also test if nationality is saved correctly
RandomTannenbaum Mar 12, 2024
eef8242
fix specs after rebase
RandomTannenbaum Mar 12, 2024
dc88a09
move functions to add and remove roles to stimulus controller
RandomTannenbaum Mar 12, 2024
42b8ec9
Fix picture controller spec and rename feature spec
RandomTannenbaum Mar 12, 2024
aebcbd3
make show all link not display in edit view
RandomTannenbaum Mar 12, 2024
a368060
resolve styling conversations
RandomTannenbaum Mar 15, 2024
999499d
Rename ms translations to marital_statuses and refactor all its usage…
RandomTannenbaum Mar 15, 2024
07f24f4
Bring back api route to un-xdescribe api test
RandomTannenbaum Mar 15, 2024
cdf6d6d
move some stuff from view to helper methods in new person_helper
RandomTannenbaum Mar 15, 2024
1b2e35a
make attribute headers in view look like in old skills
RandomTannenbaum Mar 15, 2024
2f76704
fix loading of picture on form validation failure
RandomTannenbaum Mar 15, 2024
4986d9d
Move code to check if picture is cached to helper method
RandomTannenbaum Mar 15, 2024
1cbc937
rename method from avatar_cached to avatar_cached?
RandomTannenbaum Mar 15, 2024
48c2893
add paddings to information of person for improved distinguishability
RandomTannenbaum Mar 15, 2024
efbd837
fix deleting of roles when edit form fails
RandomTannenbaum Mar 15, 2024
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
21 changes: 21 additions & 0 deletions app/assets/stylesheets/styles.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
$skills-blue: #3b7bbe;
$skills-text-gray: #8e8e8e;
$skills-gray: #f5f5f5;

@import "bootstrap";

Expand Down Expand Up @@ -42,4 +43,24 @@ pzsh-topbar {

.text-gray {
color: $skills-text-gray;
}

.person-profile-header {
background: $skills-gray;
height: 3.25rem;
padding: 12px 20px 12px 20px;
RandomTannenbaum marked this conversation as resolved.
Show resolved Hide resolved
font-size: 18px;
RandomTannenbaum marked this conversation as resolved.
Show resolved Hide resolved
}

.bg-skills-blue {
background-color: $skills-blue;
}

.bg-skills-blue:hover {
background-color: #3268a1;
}

.fixed-table {
table-layout: fixed;
RandomTannenbaum marked this conversation as resolved.
Show resolved Hide resolved
width: 100%;
}
18 changes: 18 additions & 0 deletions app/controllers/concerns/param_converters.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# frozen_string_literal: true

module ParamConverters

private

def true?(value)
%w[1 yes true].include?(value.to_s.downcase)
end

def false?(value)
%w[0 no false].include?(value.to_s.downcase)
end

def nil_param?(value)
value == 'null' ? nil : value
end
end
9 changes: 9 additions & 0 deletions app/controllers/crud_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,15 @@ def error_messages
# rubocop:enable Rails/OutputSafety
end

def get_asset_path(filename)
manifest_file = Rails.application.assets_manifest.assets[filename]
if manifest_file
File.join(Rails.application.assets_manifest.directory, manifest_file)
else
Rails.application.assets&.[](filename)&.filename
end
end

# Class methods for CrudActions.
class << self
# Convenience callback to apply a callback on both form actions
Expand Down
32 changes: 32 additions & 0 deletions app/controllers/people/picture_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

module People
class PictureController < CrudController

self.permitted_attrs = %i[picture]

def update
person.update!(picture: params[:picture])
RandomTannenbaum marked this conversation as resolved.
Show resolved Hide resolved
render json: { data: { picture_path: picture_person_path(params[:id]) } }
end

def show
picture_url = person.picture.file.nil? ? default_avatar_path : person.picture.url
send_file(picture_url, disposition: 'inline')
end

private

def model_class
Person
end

def person
@person ||= Person.find(params[:id])
end

def default_avatar_path
get_asset_path 'default_avatar.png'
end
end
end
20 changes: 12 additions & 8 deletions app/controllers/people_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@

class PeopleController < CrudController
include ExportController
include ParamConverters

# self.permitted_attrs = %i[birthdate location
# marital_status updated_by name nationality nationality2 title
# competence_notes company_id email department_id shortname]
self.permitted_attrs = [:birthdate, :location, :marital_status, :updated_by, :name, :nationality,
:nationality2, :title, :competence_notes, :company_id, :email,
:department_id, :shortname, :picture, :picture_cache,
{ person_roles_attributes: [:role_id, :person_role_level_id,
:percent, :id, :_destroy] }]

# self.nested_models = %i[advanced_trainings activities projects
# educations language_skills person_roles
# people_skills categories]

# self.permitted_relationships = %i[person_roles people_skills]
def update
if false?(params['has_nationality2']['checked'])
params['person']['nationality2'] = nil
end
super
end

def show
if format_odt?
Expand Down
35 changes: 35 additions & 0 deletions app/helpers/person_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# frozen_string_literal: true

module PersonHelper
def nationality_string(nationality, nationality2)
if nationality2.blank?
ISO3166::Country[nationality].translations[I18n.locale]
else
"#{ISO3166::Country[nationality].translations[I18n.locale]},
#{ISO3166::Country[nationality2].translations[I18n.locale]}"
end
end

def person_role_string(person_role)
"#{person_role.role.name} #{person_role.person_role_level&.level}
#{person_role.percent.nil? ? '' : "#{person_role.percent.to_i}%"}"
end

def marital_status_translation_map
Person.marital_statuses.keys.map do |marital_status|
[marital_status, t("marital_statuses.#{marital_status}")]
end
end

def country_alpha2_translation_map
ISO3166::Country.all.sort.map do |country|
[country.alpha2, country.translations[I18n.locale]]
end
end

# If the path of the avatar includes tmp, the picture is cached
# and we can load it directly without the picture controller
def avatar_cached?(picture)
picture&.file&.file&.include? 'tmp'
end
end
29 changes: 29 additions & 0 deletions app/helpers/role_form_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

module RoleFormHelper
# This method creates a link with `data-id` `data-fields` attributes. These attributes are used
# to create new instances of the nested fields through Javascript.
def link_to_add_role(name, form, association)
RandomTannenbaum marked this conversation as resolved.
Show resolved Hide resolved
# Takes an object and creates a new instance of its associated model
new_role = form.object.send(association).klass.new
# Saves the unique ID of the object into a variable.
# This is needed to ensure the key of the associated array is unique. This makes parsing the
# content in the `data-fields` attribute easier through Javascript.
id = new_role.object_id
# child_index` is used to ensure the key of the associated array is unique, and that it matched
# the value in the `data-id` attribute.
fields = form.fields_for(association, new_role, child_index: id) do |builder|
render("#{association.to_s.singularize}_fields", person_role: builder)
end


# This renders a simple link, but passes information into `data` attributes.
# This info can be named anything we want, but in this case
# we chose `data-id:` and `data-fields:`.
# We use `gsub("\n", "")` to remove anywhite space from the rendered partial.
# The `id:` value needs to match the value used in `child_index: id`.
link_to(name, '#',
{ class: 'add_fields', 'data-action' => 'person-roles#addField',
data: { id: id, fields: fields.gsub("\n", '') } })
end
end
9 changes: 9 additions & 0 deletions app/javascript/controllers/image_upload_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
changeImage() {
const avatarUploader = document.getElementById("avatar-uploader");
const avatar = document.getElementById("avatar");
avatar.src = URL.createObjectURL(avatarUploader.files[0])
}
}
13 changes: 11 additions & 2 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@

import { application } from "./application"

import DropdownLinksController from "./dropdown_controller"
application.register("dropdown", DropdownLinksController)
import DropdownController from "./dropdown_controller"
application.register("dropdown", DropdownController)

import ImageUploadController from "./image_upload_controller"
application.register("image-upload", ImageUploadController)

import NationalityTwoController from "./nationality_two_controller"
application.register("nationality-two", NationalityTwoController)

import PersonRolesController from "./person_roles_controller"
application.register("person-roles", PersonRolesController)

import RemoteModalController from "./remote_modal_controller"
application.register("remote-modal", RemoteModalController)
18 changes: 18 additions & 0 deletions app/javascript/controllers/nationality_two_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
setVisibility() {
const natTwoElements = document.getElementsByClassName('nationality-two')
const natTwoCheckbox = document.getElementById('nat-two-checkbox')
for(const element of natTwoElements) {
!natTwoCheckbox.checked ? element.classList.add('d-none') : element.classList.remove('d-none')
}
}

connect() {
this.setVisibility();
}
nationalityTwoVisible() {
this.setVisibility()
}
}
47 changes: 47 additions & 0 deletions app/javascript/controllers/person_roles_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
connect() {
for(let nested_field of document.getElementsByClassName("nested-fields")) {
if(nested_field.querySelector('input[type="hidden"]').value === "true") {
nested_field.style.display = "none";
}
}
}
addField(e) {
let link = e.target
// Stop the function from executing if a link or event were not passed into the function.
if (!link || !e) return;
// Prevent the browser from following the URL.
e.preventDefault();
// Save a unique timestamp to ensure the key of the associated array is unique.
let time = new Date().getTime();
// Save the data id attribute into a variable. This corresponds to `new_object.object_id`.
let linkId = link.dataset.id;
// Create a new regular expression needed to find any instance of the `new_object.object_id` used in the fields data attribute if there's a value in `linkId`.
let regexp = linkId ? new RegExp(linkId, "g") : null;
// Replace all instances of the `new_object.object_id` with `time`, and save markup into a variable if there's a value in `regexp`.
let newFields = regexp ? link.dataset.fields.replace(regexp, time) : null;
// Add the new markup to the form if there are fields to add.
newFields ? link.insertAdjacentHTML("beforebegin", newFields) : null;
}

removeField(e) {
let link = e.target
// Stop the function from executing if a link or event were not passed into the function.
if (!link || !e) return;
// Prevent the browser from following the URL.
e.preventDefault();
// Find the parent wrapper for the set of nested fields.
let fieldParent = link.closest(".nested-fields");
// If there is a parent wrapper, find the hidden delete field.
let deleteField = fieldParent
? fieldParent.querySelector('input[type="hidden"]')
: null;
// If there is a delete field, update the value to `1` and hide the corresponding nested fields.
if (deleteField) {
deleteField.value = 1;
fieldParent.style.display = "none";
}
}
}
1 change: 1 addition & 0 deletions app/models/person.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Person < ApplicationRecord
has_many :expertise_topics, through: :expertise_topic_skill_values
has_many :language_skills, dependent: :delete_all
has_many :person_roles, dependent: :destroy
accepts_nested_attributes_for :person_roles, allow_destroy: true
has_many :people_skills, dependent: :destroy
has_many :skills, through: :people_skills
has_many :roles, through: :person_roles
Expand Down
2 changes: 1 addition & 1 deletion app/views/layouts/application.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
= javascript_include_tag "application", "data-turbo-track": "reload", type: "module"
= favicon_link_tag "favicon.png"
%body.d-flex.justify-content-center
%pzsh-container.content
%div.content
%div.position-sticky.top-0.z-3
%div.d-flex.justify-content-between.bg-white
%div.d-flex
Expand Down
70 changes: 70 additions & 0 deletions app/views/people/_form.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
= form_with model: @person do |form|
%div.d-flex.flex-xl-row.flex-column
%div.col-xl-3.col-12
- if avatar_cached?(@person.picture)
%img.rounded-circle#avatar{src: "#{@person.picture}?#{Time.now.to_f}", width: '141', height: '141'}
- else
%img.rounded-circle#avatar{src: "#{@person.id}/picture?#{Time.now.to_f}", width: '141', height: '141'}
%br
%label.btn.btn-link{for: "avatar-uploader"} Bild ändern
%div.visually-hidden{"data-controller"=>"image-upload"}= form.file_field :picture, { accept: "image/", "data-action" => "image-upload#changeImage", id: "avatar-uploader" }
= form.hidden_field :picture_cache
%div.pe-5.col-xl-3.col-12
%table
%tbody
%th.fw-normal Name
%tr
%td= form.text_field :name, class: "mw-100 form-control"
%th.fw-normal Email
%tr
%td= form.text_field :email, class: "mw-100, form-control"
%th.fw-normal Abschluss
%tr
%td= form.text_field :title, class: "mw-100, form-control"
%th.fw-normal Funktionen
%div
= form.fields_for :person_roles do |person_role|
%tr
%td= render "person_role_fields", person_role: person_role
%tr
%td{"data-controller"=>"person-roles"}
= link_to_add_role "Neue Funktion", form, :person_roles
%th.fw-normal Organisationseinheit
%tr
%td= form.collection_select :department_id, Department.order(:name), :id, :name, {}, class: "form-select mw-100"
%th.fw-normal Firma
%tr
%td= form.collection_select :company_id, Company.order(:name), :id, :name, {}, class: "form-select mw-100"
%th.fw-normal Wohnort (Stadt)
%tr
%td= form.text_field :location, class: "form-control mw-100"

%div.pe-5.col-xl-3.col-12
%table
%tbody
%th.fw-normal Geburtsdatum
%tr
%td= form.date_field :birthdate, class: "form-control mw-100"
%th.fw-normal Doppelbürger
%tr
%td{"data-controller"=>"nationality-two"}= check_box :has_nationality2, "checked", {"checked" => @person.nationality2?, "data-action" => "nationality-two#nationalityTwoVisible", "id" => "nat-two-checkbox"}
%th.fw-normal Erste Nationalität
%tr
%td= form.collection_select :nationality, country_alpha2_translation_map, :first, :last, {}, class: "form-select mw-100"
%th.fw-normal.nationality-two Zweite Nationalität
%tr.nationality-two
%td= form.collection_select :nationality2, country_alpha2_translation_map, :first, :last, {}, class: "form-select mw-100"
%th.fw-normal Zivilstand
%tr
%td= form.collection_select :marital_status, marital_status_translation_map, :first, :last, { selected: @person.marital_status }, class: "form-select mw-100"
%th.fw-normal Kürzel
%tr
%td= form.text_field :shortname, class: "mw-100 form-control"
%div.col-xl-3.col-12.mw-100
%div.fw-normal Sprachen
%div.border.border-dark-subtle.mt-1.p-2.rounded
- @person.language_skills.each do |language|
%div.mb-1= "#{language.language}: #{language.level} - #{language.certificate}"
%div.mt-3
= form.submit :Speichern, { class: "btn btn-primary me-3 bg-skills-blue", id: "save-button" }
= link_to "Abbrechen", person_path, { id: "cancel-button" }
10 changes: 10 additions & 0 deletions app/views/people/_person_role_fields.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
%div.border.border-dark-subtle.rounded.p-1.fw-light.nested-fields
= person_role.hidden_field :_destroy
Rolle
= person_role.collection_select :role_id, Role.order(:name), :id, :name, {}, class: "form-select w-100 role-select"
%div
Stufe
%div.d-flex.fw-light
= person_role.collection_select :person_role_level_id, PersonRoleLevel.order(:level), :id, :level, {}, class: "form-select w-50 me-1 role-level-select"
= person_role.number_field :percent, in: 0..200, step: 1, class: "form-control w-50 person-role-percent"
%div{"data-controller"=>"person-roles"}= link_to "Remove", "#", { class: "remove_fields", 'data-action' => 'person-roles#removeField' }
Loading