Skip to content

Commit 912007d

Browse files
committed
Enhance person blocking functionality: add search by name and slug, update UI components, and improve localization across multiple languages
1 parent 927fa15 commit 912007d

File tree

11 files changed

+234
-97
lines changed

11 files changed

+234
-97
lines changed

app/controllers/better_together/person_blocks_controller.rb

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,26 @@ class PersonBlocksController < ApplicationController # rubocop:todo Style/Docume
99
def index # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
1010
authorize PersonBlock
1111

12-
# AC-2.11: I can search through my blocked users by name
12+
# AC-2.11: I can search through my blocked users by name and slug
1313
@blocked_people = helpers.current_person.blocked_people
1414
if params[:search].present?
15-
# Search by translated name using includes and references
15+
# Search by translated name and slug using includes and references
1616
# Apply policy scope to ensure only authorized people are searchable
1717
search_term = params[:search].strip
1818
authorized_person_ids = policy_scope(BetterTogether::Person).pluck(:id)
1919

2020
@blocked_people = @blocked_people.where(id: authorized_person_ids)
2121
.includes(:string_translations)
2222
.references(:string_translations)
23-
.where(string_translations: { key: 'name' })
23+
.where(string_translations: { key: ['name', 'slug'] })
2424
.where('string_translations.value ILIKE ?', "%#{search_term}%")
2525
.distinct
2626
end
2727

2828
# AC-2.12: I can see when I blocked each user (provide person_blocks for timestamp info)
2929
@person_blocks = helpers.current_person.person_blocks.includes(:blocked)
3030
if params[:search].present?
31-
# Filter person_blocks by matching blocked person names
31+
# Filter person_blocks by matching blocked person names and slugs
3232
# Apply policy scope to ensure only authorized people are searchable
3333
search_term = params[:search].strip
3434
authorized_person_ids = policy_scope(BetterTogether::Person).pluck(:id)
@@ -37,7 +37,7 @@ def index # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
3737
.where(better_together_people: { id: authorized_person_ids })
3838
.includes(blocked: :string_translations)
3939
.references(:string_translations)
40-
.where(string_translations: { key: 'name' })
40+
.where(string_translations: { key: ['name', 'slug'] })
4141
.where('string_translations.value ILIKE ?', "%#{search_term}%")
4242
.distinct
4343
end
@@ -56,15 +56,6 @@ def create # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
5656
@person_block = helpers.current_person.person_blocks.new(person_block_params)
5757
# rubocop:enable Layout/IndentationWidth
5858

59-
# AC-2.13: I can block a user by entering their username or email
60-
if params[:person_block][:blocked_identifier].present? # rubocop:todo Layout/IndentationConsistency
61-
target_person = BetterTogether::Person.find_by(identifier: params[:person_block][:blocked_identifier]) ||
62-
# rubocop:todo Layout/LineLength
63-
BetterTogether::Person.joins(:user).find_by(better_together_users: { email: params[:person_block][:blocked_identifier] })
64-
# rubocop:enable Layout/LineLength
65-
@person_block.blocked = target_person if target_person
66-
end
67-
6859
authorize @person_block # rubocop:todo Layout/IndentationConsistency
6960

7061
respond_to do |format| # rubocop:todo Layout/IndentationConsistency
@@ -85,6 +76,44 @@ def create # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
8576
end
8677
end
8778

79+
def search
80+
authorize PersonBlock
81+
82+
search_term = params[:q].to_s.strip
83+
current_person = helpers.current_person
84+
85+
# Get all people that could potentially be blocked (policy scoped)
86+
blockable_people = policy_scope(BetterTogether::Person)
87+
.where.not(id: current_person.id) # Can't block yourself
88+
.where.not(id: current_person.blocked_people.select(:id)) # Already blocked
89+
90+
if search_term.present?
91+
# Use Mobility's i18n scope to search across translations for name and slug
92+
search_pattern = "%#{search_term}%"
93+
blockable_people = blockable_people.i18n.where(
94+
'mobility_string_translations.value ILIKE ?',
95+
search_pattern
96+
).where(
97+
mobility_string_translations: { key: ['name', 'slug'] }
98+
)
99+
end
100+
101+
# Limit results and format for slim-select
102+
people_data = blockable_people
103+
.limit(20)
104+
.map do |person|
105+
{
106+
text: person.name, # This will be the display text
107+
value: person.id.to_s,
108+
data: {
109+
slug: person.slug
110+
}
111+
}
112+
end
113+
114+
render json: people_data
115+
end
116+
88117
def destroy
89118
authorize @person_block
90119
@person_block.destroy

app/javascript/controllers/better_together/slim_select_controller.js

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,56 @@ export default class extends Controller {
77
}
88

99
connect() {
10+
const defaultOptions = {
11+
settings: {
12+
allowDeselect: true,
13+
searchPlaceholder: 'Search...',
14+
searchHighlight: true,
15+
closeOnSelect: true
16+
}
17+
};
18+
19+
// Merge with custom options from the element
20+
const options = { ...defaultOptions, ...this.optionsValue };
21+
22+
// Handle AJAX configuration if present
23+
if (options.ajax) {
24+
options.events = {
25+
search: (search, currentData) => {
26+
if (search.length < 2) {
27+
return new Promise((resolve) => {
28+
resolve([]);
29+
});
30+
}
31+
32+
return new Promise((resolve, reject) => {
33+
const url = new URL(options.ajax.url, window.location.origin);
34+
url.searchParams.append('q', search);
35+
36+
fetch(url.toString(), {
37+
method: 'GET',
38+
headers: {
39+
'Accept': 'application/json',
40+
'Content-Type': 'application/json',
41+
'X-Requested-With': 'XMLHttpRequest'
42+
}
43+
})
44+
.then(response => response.json())
45+
.then(data => {
46+
resolve(data);
47+
})
48+
.catch(error => {
49+
console.error('SlimSelect AJAX error:', error);
50+
reject(error);
51+
});
52+
});
53+
}
54+
};
55+
}
56+
1057
this.slimSelect = new SlimSelect({
1158
select: this.element,
12-
settings: {
13-
allowDeselect: true
14-
},
15-
...this.optionsValue
59+
...options
1660
});
1761
}
1862

app/policies/better_together/person_block_policy.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ def index?
66
user.present?
77
end
88

9+
def search?
10+
user.present?
11+
end
12+
913
def new?
1014
user.present?
1115
end

app/views/better_together/person_blocks/_index_content.html.erb

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,9 @@
44
<div class="list-group-item d-flex justify-content-between align-items-center" id="<%= dom_id(person_block) %>">
55
<div class="d-flex align-items-center">
66
<div class="me-3">
7-
<% if person_block.blocked.profile_image.attached? %>
8-
<%= image_tag person_block.blocked.profile_image,
9-
class: 'rounded-circle',
10-
size: '40x40',
11-
alt: person_block.blocked.name %>
12-
<% else %>
13-
<div class="bg-secondary rounded-circle d-flex align-items-center justify-content-center"
14-
style="width: 40px; height: 40px;">
15-
<i class="fas fa-user text-white" aria-hidden="true"></i>
16-
</div>
17-
<% end %>
7+
<%= profile_image_tag(person_block.blocked,
8+
size: 50,
9+
class: 'rounded-circle') %>
1810
</div>
1911
<div>
2012
<h6 class="mb-0"><%= person_block.blocked.name %></h6>

app/views/better_together/person_blocks/index.html.erb

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,40 @@
66
<div class="col-12">
77
<div class="d-flex justify-content-between align-items-center mb-3">
88
<h2 class="h4 mb-0"><%= t('better_together.person_blocks.index.title') %></h2>
9-
<%= link_to t('better_together.person_blocks.index.block_user'),
10-
new_person_block_path(locale: locale),
9+
<%= link_to t('better_together.person_blocks.index.block_person'),
10+
new_person_block_path(locale: locale),
1111
class: 'btn btn-primary btn-sm' %>
1212
</div>
1313

14-
<!-- Search Form -->
15-
<div class="row mb-3">
16-
<div class="col-md-6">
17-
<%= form_with url: person_blocks_path(locale: locale), method: :get, local: true, class: 'd-flex' do |form| %>
18-
<%= form.text_field :search,
19-
value: params[:search],
20-
placeholder: t('better_together.person_blocks.index.search_placeholder'),
21-
class: 'form-control me-2' %>
22-
<%= form.submit t('better_together.person_blocks.index.search'),
23-
class: 'btn btn-outline-secondary btn-sm' %>
24-
<% end %>
14+
<% if @blocked_count > 5 %>
15+
<!-- Search Form -->
16+
<div class="row mb-3">
17+
<div class="col-md-6">
18+
<%= form_with url: person_blocks_path(locale: locale), method: :get, local: true, class: 'd-flex' do |form| %>
19+
<%= form.text_field :search,
20+
value: params[:search],
21+
placeholder: t('better_together.person_blocks.index.search_placeholder'),
22+
class: 'form-control me-2' %>
23+
<%= form.submit t('better_together.person_blocks.index.search'),
24+
class: 'btn btn-outline-secondary btn-sm' %>
25+
<% end %>
26+
</div>
27+
<div class="col-md-6 text-end">
28+
<small class="text-muted">
29+
<%= t('better_together.person_blocks.index.blocked_count', count: @blocked_count) %>
30+
</small>
31+
</div>
2532
</div>
26-
<div class="col-md-6 text-end">
27-
<small class="text-muted">
28-
<%= t('better_together.person_blocks.index.blocked_count', count: @blocked_count) %>
29-
</small>
33+
<% else %>
34+
<!-- Just show the count when there are 5 or fewer blocked people -->
35+
<div class="row mb-3">
36+
<div class="col-12 text-end">
37+
<small class="text-muted">
38+
<%= t('better_together.person_blocks.index.blocked_count', count: @blocked_count) %>
39+
</small>
40+
</div>
3041
</div>
31-
</div>
42+
<% end %>
3243

3344
<!-- Blocked People List -->
3445
<div id="blocked_people_list">

app/views/better_together/person_blocks/new.html.erb

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,32 @@
1616
local: true,
1717
data: { turbo_frame: "blocked-people-settings" } do |form| %>
1818
<div class="mb-3">
19-
<%= form.label :blocked_identifier,
20-
t('better_together.person_blocks.new.blocked_identifier_label'),
19+
<%= form.label :blocked_id,
20+
t('better_together.person_blocks.new.blocked_person_label'),
2121
class: 'form-label' %>
22-
<%= form.text_field :blocked_identifier,
23-
class: 'form-control',
24-
placeholder: t('better_together.person_blocks.new.blocked_identifier_placeholder'),
25-
required: true %>
22+
<%= form.select :blocked_id,
23+
options_for_select([]),
24+
{ prompt: t('better_together.person_blocks.new.blocked_person_prompt') },
25+
{
26+
class: 'form-select',
27+
required: true,
28+
data: {
29+
controller: "better-together--slim-select",
30+
"better-together--slim-select-options-value": {
31+
ajax: {
32+
url: search_person_blocks_path(locale: locale),
33+
fetch: true,
34+
delay: 300
35+
},
36+
searchPlaceholder: t('better_together.person_blocks.new.blocked_person_placeholder'),
37+
searchHighlight: true,
38+
closeOnSelect: true,
39+
allowDeselect: true
40+
}.to_json
41+
}
42+
} %>
2643
<div class="form-text">
27-
<%= t('better_together.person_blocks.new.blocked_identifier_help') %>
44+
<%= t('better_together.person_blocks.new.blocked_person_help') %>
2845
</div>
2946
</div>
3047

app/views/better_together/settings/index.html.erb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525
<i class="fa-solid fa-user me-2" aria-hidden="true"></i>
2626
<%= t('.tabs.personal') %>
2727
</button> -->
28-
<button class="nav-link active" id="account-tab" data-bs-toggle="pill" data-bs-target="#account" type="button" role="tab" aria-controls="account" aria-selected="false" data-better_together--tabs-target="tab">
28+
<button class="nav-link text-start active" id="account-tab" data-bs-toggle="pill" data-bs-target="#account" type="button" role="tab" aria-controls="account" aria-selected="false" data-better_together--tabs-target="tab">
2929
<i class="fa-solid fa-key me-2" aria-hidden="true"></i>
3030
<%= t('.tabs.account') %>
3131
</button>
32-
<button class="nav-link" id="blocked-people-tab" data-bs-toggle="pill" data-bs-target="#blocked-people" type="button" role="tab" aria-controls="blocked-people" aria-selected="false" data-better_together--tabs-target="tab">
32+
<button class="nav-link text-start" id="blocked-people-tab" data-bs-toggle="pill" data-bs-target="#blocked-people" type="button" role="tab" aria-controls="blocked-people" aria-selected="false" data-better_together--tabs-target="tab">
3333
<i class="fa-solid fa-user-slash me-2" aria-hidden="true"></i>
3434
<%= t('.tabs.blocked_people') %>
3535
</button>
@@ -139,7 +139,7 @@
139139
<%= t('.privacy.title') %>
140140
</h3>
141141
<p class="text-muted mb-4"><%= t('.privacy.description') %></p>
142-
142+
143143
<!-- Privacy settings content will go here -->
144144
<div class="alert alert-info" role="status">
145145
<i class="fa-solid fa-info-circle me-2" aria-hidden="true"></i>

config/locales/en.yml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,7 +1141,7 @@ en:
11411141
person_blocks:
11421142
index:
11431143
actions: Actions
1144-
block_user: Block User
1144+
block_person: Block Person
11451145
blocked_at: Blocked
11461146
blocked_count:
11471147
one: 1 person blocked
@@ -1157,20 +1157,20 @@ en:
11571157
unblock_confirmation: Are you sure you want to unblock this person?
11581158
new:
11591159
back_to_list: Back to Blocked People
1160-
blocked_identifier_help: Enter the username or email address of the person
1161-
you want to block.
1162-
blocked_identifier_label: Username or Email
1163-
blocked_identifier_placeholder: Enter username or email address
1160+
blocked_person_help: Select a person you want to block from the search results.
1161+
blocked_person_label: Person to Block
1162+
blocked_person_placeholder: Search for a person to block...
1163+
blocked_person_prompt: Select a person to block
11641164
cancel: Cancel
1165-
submit: Block User
1166-
title: Block User
1165+
submit: Block Person
1166+
title: Block Person
11671167
notices:
1168-
already_blocked: This user is already blocked.
1169-
blocked: User has been blocked successfully.
1170-
not_found: User not found.
1168+
already_blocked: This person is already blocked.
1169+
blocked: Person has been blocked successfully.
1170+
not_found: Person not found.
11711171
platform_manager_error: Platform managers cannot be blocked.
11721172
self_block_error: You cannot block yourself.
1173-
unblocked: User has been unblocked successfully.
1173+
unblocked: Person has been unblocked successfully.
11741174
phone_numbers:
11751175
add: Add Phone Number
11761176
label: Label

config/locales/es.yml

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,7 +1143,7 @@ es:
11431143
person_blocks:
11441144
index:
11451145
actions: Acciones
1146-
block_user: Bloquear Usuario
1146+
block_person: Bloquear Persona
11471147
blocked_at: Bloqueado
11481148
blocked_count:
11491149
one: 1 persona bloqueada
@@ -1159,21 +1159,20 @@ es:
11591159
unblock_confirmation: "¿Estás seguro de que quieres desbloquear a esta persona?"
11601160
new:
11611161
back_to_list: Volver a Personas Bloqueadas
1162-
blocked_identifier_help: Introduce el nombre de usuario o dirección de email
1163-
de la persona que quieres bloquear.
1164-
blocked_identifier_label: Nombre de usuario o Email
1165-
blocked_identifier_placeholder: Introduce nombre de usuario o dirección de
1166-
email
1162+
blocked_person_help: Selecciona a una persona que quieras bloquear de los resultados de búsqueda.
1163+
blocked_person_label: Persona a Bloquear
1164+
blocked_person_placeholder: Buscar una persona para bloquear...
1165+
blocked_person_prompt: Selecciona una persona para bloquear
11671166
cancel: Cancelar
1168-
submit: Bloquear Usuario
1169-
title: Bloquear Usuario
1167+
submit: Bloquear Persona
1168+
title: Bloquear Persona
11701169
notices:
1171-
already_blocked: Este usuario ya está bloqueado.
1172-
blocked: Usuario ha sido bloqueado exitosamente.
1173-
not_found: Usuario no encontrado.
1170+
already_blocked: Este persona ya está bloqueado.
1171+
blocked: Persona ha sido bloqueado exitosamente.
1172+
not_found: Persona no encontrado.
11741173
platform_manager_error: Los administradores de plataforma no pueden ser bloqueados.
11751174
self_block_error: No puedes bloquearte a ti mismo.
1176-
unblocked: Usuario ha sido desbloqueado exitosamente.
1175+
unblocked: Persona ha sido desbloqueado exitosamente.
11771176
phone_numbers:
11781177
add: Agregar Número de Teléfono
11791178
label: Etiqueta

0 commit comments

Comments
 (0)