diff --git a/app/Http/Requests/UserListRequest.php b/app/Http/Requests/UserListRequest.php
index e5fee77..6782162 100644
--- a/app/Http/Requests/UserListRequest.php
+++ b/app/Http/Requests/UserListRequest.php
@@ -21,7 +21,8 @@ public function rules()
{
return [
'orderBy' => 'in:first_name,last_name,organisation,industry_type,created_at,last_logged_in_at',
- 'sort' => 'in:asc,desc'
+ 'sort' => 'in:asc,desc',
+ 'filters.search' => 'nullable|string|min:3|max:191'
];
}
@@ -36,8 +37,10 @@ public function getUserQuery(): UserQuery
$userQuery->setOrderBy($orderBy);
$userQuery->setSort($sort);
- foreach ($this->get('filters', []) as $column => $value) {
- $userQuery->addFilter($column, $value);
+ $filters = $this->get('filters', $this->get('filters\\', []));
+
+ foreach ($filters as $column => $value) {
+ $userQuery->addFilter(rtrim($column, '\\'), $value);
}
return $userQuery;
diff --git a/app/Repositories/Access/UserRepository.php b/app/Repositories/Access/UserRepository.php
index d2a57bd..183d956 100644
--- a/app/Repositories/Access/UserRepository.php
+++ b/app/Repositories/Access/UserRepository.php
@@ -186,6 +186,11 @@ public function queryUsers(UserQuery $userQuery): Builder
});
});
+ $search = trim($userQuery->getFilters()->get('search', ''));
+ if (mb_strlen($search) >= 3) {
+ $this->applySearchFilter($builder, $search);
+ }
+
$society = $userQuery->getFilters()->only(['society'])->first();
if ($society) {
$builder->whereHas('organisations', function ($query) use ($society) {
@@ -214,12 +219,25 @@ public function queryUsers(UserQuery $userQuery): Builder
}
if (in_array($userQuery->getOrderBy(), ['first_name', 'last_name', 'organisation', 'industry_type'])) {
- $builder->orderByRaw('(SELECT ' . $userQuery->getOrderBy() . ' FROM user_profiles WHERE user_profiles.user_id = users.id) ' . $userQuery->getSort());
+ $builder->orderByRaw('(SELECT ' . $userQuery->getOrderBy() . ' FROM user_profiles WHERE user_profiles.user_id = users.id AND user_profiles.deleted_at IS NULL ORDER BY user_profiles.id DESC LIMIT 1) ' . $userQuery->getSort());
}
return $builder;
}
+ private function applySearchFilter(Builder $builder, string $search)
+ {
+ $profileMatch = 'MATCH(user_profiles.first_name, user_profiles.last_name) AGAINST (? IN NATURAL LANGUAGE MODE)';
+ $emailMatch = 'MATCH(users.email) AGAINST (? IN NATURAL LANGUAGE MODE)';
+ $profileScore = "(SELECT {$profileMatch} FROM user_profiles WHERE user_profiles.user_id = users.id AND user_profiles.deleted_at IS NULL ORDER BY user_profiles.id DESC LIMIT 1)";
+ $score = "({$emailMatch} + COALESCE({$profileScore}, 0))";
+
+ $builder->select('users.*')
+ ->selectRaw("{$score} as search_score", [$search, $search])
+ ->whereRaw("({$emailMatch} > 0 OR EXISTS (SELECT 1 FROM user_profiles WHERE user_profiles.user_id = users.id AND user_profiles.deleted_at IS NULL AND {$profileMatch} > 0))", [$search, $search])
+ ->orderBy('search_score', 'desc');
+ }
+
public function deactivate(User $user)
{
$user->activated = false;
diff --git a/database/migrations/2026_05_29_000000_add_fulltext_indexes_for_user_search.php b/database/migrations/2026_05_29_000000_add_fulltext_indexes_for_user_search.php
new file mode 100644
index 0000000..1780884
--- /dev/null
+++ b/database/migrations/2026_05_29_000000_add_fulltext_indexes_for_user_search.php
@@ -0,0 +1,51 @@
+indexExists('users', 'users_email_fulltext_search')) {
+ DB::statement('ALTER TABLE users ADD FULLTEXT users_email_fulltext_search(email)');
+ }
+
+ $this->dropIndexIfExists('user_profiles', 'user_profiles_search_fulltext');
+ DB::statement('ALTER TABLE user_profiles ADD FULLTEXT user_profiles_search_fulltext(first_name, last_name)');
+ }
+
+
+ public function down()
+ {
+ if (env('DB_CONNECTION') !== 'mysql') {
+ return;
+ }
+
+ $this->dropIndexIfExists('users', 'users_email_fulltext_search');
+ $this->dropIndexIfExists('user_profiles', 'user_profiles_search_fulltext');
+ }
+
+ private function dropIndexIfExists(string $table, string $index)
+ {
+ if ($this->indexExists($table, $index)) {
+ DB::statement("ALTER TABLE {$table} DROP INDEX {$index}");
+ }
+ }
+
+ private function indexExists(string $table, string $index): bool
+ {
+ return (bool) DB::select(
+ DB::raw(
+ "SHOW KEYS
+ FROM {$table}
+ WHERE Key_name='{$index}'"
+ )
+ );
+ }
+}
diff --git a/resources/assets/js/pages/users/list.vue b/resources/assets/js/pages/users/list.vue
index 7342c94..0f75338 100644
--- a/resources/assets/js/pages/users/list.vue
+++ b/resources/assets/js/pages/users/list.vue
@@ -67,6 +67,16 @@
:staynull="true"
v-if="!apiUsers"/>
+
+
+
+
+
{{ $t('users.list.clear_filters') }}
@@ -226,6 +236,7 @@ export default {
fetchingUsers: false,
roles: null,
locationOptions: null,
+ searchDebounce: null,
countries: require('country-list')()
}
},
@@ -239,6 +250,21 @@ export default {
deep: true
},
activatedFilter: fetchHandler,
+ searchFilter: {
+ handler (val, oldVal) {
+ if (val !== oldVal) {
+ clearTimeout(this.searchDebounce)
+ const search = val ? val.trim() : ''
+ if (search.length > 0 && search.length < 3) {
+ return
+ }
+ this.searchDebounce = setTimeout(() => {
+ this.currentPage = 1
+ this.fetchUsers()
+ }, 350)
+ }
+ }
+ },
roleFilter: fetchHandler,
countryFilter: fetchHandler,
termsFilter: fetchHandler,
@@ -259,6 +285,9 @@ export default {
this.fetchUsers()
this.fetchTerms()
},
+ beforeDestroy () {
+ clearTimeout(this.searchDebounce)
+ },
metaInfo () {
return { title: this.$t('users.list.manage') }
},
@@ -268,6 +297,7 @@ export default {
this.roleFilter = null
this.countryFilter = null
this.selectedSoc = null
+ this.searchFilter = ''
this.termsFilter = termsDefault
},
getSocietyByCode (code) {
@@ -310,12 +340,14 @@ export default {
},
async fetchUsers () {
this.fetchingUsers = true
- await this.fetchRoles()
+ if (this.rolesEmpty) {
+ await this.fetchRoles()
+ }
- let apiUserRole = this.roleOptions.find(role => role.name === 'API User')
+ const apiUserRole = this.roleOptions.find(role => role.name === 'API User')
let filterRoleId = this.roleFilter
if (filterRoleId === null) {
- filterRoleId = this.apiUsers ? apiUserRole.id : null
+ filterRoleId = this.apiUsers && apiUserRole ? apiUserRole.id : null
}
if (!apiUserRole && this.apiUsers) {
@@ -330,6 +362,7 @@ export default {
role: filterRoleId,
society: this.selectedSoc ? this.selectedSoc.countryCode : null,
country_code: this.countryFilter,
+ search: this.searchFilter,
terms_version: this.termsFilter === termsDefault ? null : this.termsFilter
},
admin: !this.apiUsers && filterRoleId === null,
@@ -408,6 +441,14 @@ export default {
return this.$store.state.users.filters.roleFilter
}
},
+ searchFilter: {
+ set: function (newVal) {
+ this.$store.dispatch('users/setFilter', { searchFilter: newVal })
+ },
+ get: function () {
+ return this.$store.state.users.filters.searchFilter
+ }
+ },
countryFilter: {
set: function(newVal) {
this.$store.dispatch('users/setFilter', { countryFilter: newVal })
@@ -451,6 +492,7 @@ export default {
this.roleFilter === null &&
this.countryFilter === null &&
this.selectedSoc === null &&
+ !this.searchFilter &&
this.termsFilter === termsDefault
},
...mapGetters({
@@ -487,5 +529,11 @@ export default {
.text-nowrap {
white-space: nowrap;
}
+ .search-filter-input {
+ background: #E9E9E9;
+ border: none;
+ border-radius: 10px;
+ height: 2.45rem;
+ }
diff --git a/resources/assets/js/plugins/axios.js b/resources/assets/js/plugins/axios.js
index fce96eb..9325132 100644
--- a/resources/assets/js/plugins/axios.js
+++ b/resources/assets/js/plugins/axios.js
@@ -23,6 +23,10 @@ axios.interceptors.request.use(request => {
// Response interceptor
axios.interceptors.response.use(response => response, error => {
+ if (axios.isCancel(error)) {
+ return Promise.reject(error)
+ }
+
if (error.response && error.response.status) {
const { status } = error.response
diff --git a/resources/assets/js/store/modules/users.js b/resources/assets/js/store/modules/users.js
index 57667a1..8f23349 100644
--- a/resources/assets/js/store/modules/users.js
+++ b/resources/assets/js/store/modules/users.js
@@ -2,6 +2,8 @@ import axios from 'axios'
import * as types from '../mutation-types'
import querystring from 'querystring'
+let latestFetchUsersRequest = 0
+
// state
export const state = {
users: {
@@ -24,6 +26,7 @@ export const state = {
roleFilter: null,
countryFilter: null,
selectedSoc: null,
+ searchFilter: '',
termsFilter: 'Terms and Conditions'
}
}
@@ -104,6 +107,7 @@ export const actions = {
roleFilter: null,
countryFilter: null,
selectedSoc: null,
+ searchFilter: '',
termsFilter: 'Terms and Conditions'
})
commit(types.SET_ORDER_BY, null)
@@ -120,6 +124,7 @@ export const actions = {
commit(types.SET_SORT_DESC, sortDesc)
},
async fetchUsers ({ commit }, { page, filters, excludes, admin, orderBy, sort }) {
+ const requestId = ++latestFetchUsersRequest
const queryOptions = { page }
if (orderBy !== null) {
queryOptions.orderBy = orderBy
@@ -131,11 +136,19 @@ export const actions = {
filterString += filters.society !== null ? `&filters[society]=${filters.society}` : ''
filterString += filters.country_code !== null ? `&filters[country_code]=${filters.country_code}` : ''
filterString += filters.terms_version !== null ? `&filters[terms_version]=${filters.terms_version}` : ''
+ const search = filters.search ? filters.search.trim() : ''
+ filterString += search.length >= 3 ? `&filters[search]=${encodeURIComponent(search)}` : ''
const url = admin ? '/api/users/admins' : '/api/users'
const { data } = await axios.get(`${url}?${querystring.stringify(queryOptions)}${filterString}`)
+ if (requestId !== latestFetchUsersRequest) {
+ return
+ }
commit(types.FETCH_USERS_SUCCESS, { users: data })
} catch (e) {
+ if (requestId !== latestFetchUsersRequest) {
+ return
+ }
commit(types.FETCH_USERS_FAILURE, { error: e })
}
},
diff --git a/resources/lang/am.json b/resources/lang/am.json
index 382243a..6847c33 100644
--- a/resources/lang/am.json
+++ b/resources/lang/am.json
@@ -343,6 +343,8 @@
"select_country": "ሀገር ምረጥ",
"select_terms": "የውሎች ስሪት ምረጥ",
"select_society": "የብሔራዊ ማህበር ምረጥ",
+ "search": "ፈልግ",
+ "search_placeholder": "ስም ወይም ኢሜይል (ቢያንስ 3 ቁምፊዎች)",
"create": "አዲስ መጠቀሚያ ይፍጠሩ፤",
"download_report": "ሪፖርት ያውርዱ፤",
"empty": "ምንም መጠቀሚያ ማግኘት አልተቻለም፤",
diff --git a/resources/lang/ar.json b/resources/lang/ar.json
index d370c9d..9a595f5 100644
--- a/resources/lang/ar.json
+++ b/resources/lang/ar.json
@@ -349,6 +349,8 @@
"select_country": "اختر بلدًا",
"select_terms": "اختر إصدار الشروط",
"select_society": "اختر جمعية وطنية",
+ "search": "بحث",
+ "search_placeholder": "الاسم أو البريد الإلكتروني (3 أحرف على الأقل)",
"create": "إنشاء مستخدم جديد",
"download_report": "تنزيل التقرير",
"empty": "لم يتم العثور على أي مستخدمين",
diff --git a/resources/lang/bn.json b/resources/lang/bn.json
index 373b02e..50d42bf 100644
--- a/resources/lang/bn.json
+++ b/resources/lang/bn.json
@@ -343,6 +343,8 @@
"select_country": "একটি দেশ নির্বাচন করুন",
"select_terms": "একটি শর্তাবলী সংস্করণ নির্বাচন করুন",
"select_society": "জাতীয় সমিতি নির্বাচন করুন",
+ "search": "অনুসন্ধান",
+ "search_placeholder": "নাম বা ইমেল (কমপক্ষে ৩ অক্ষর)",
"create": "নতুন ব্যবহারকারী তৈরি করুন",
"download_report": "রিপোর্ট ডাউনলোড করুন",
"empty": "কোন ব্যবহারকারী খুঁজে পাইনি",
diff --git a/resources/lang/de.json b/resources/lang/de.json
index 94d8c85..288973d 100644
--- a/resources/lang/de.json
+++ b/resources/lang/de.json
@@ -343,6 +343,8 @@
"select_country": "Land auswählen",
"select_terms": "Version der Bedingungen auswählen",
"select_society": "Nationale Gesellschaft auswählen",
+ "search": "Suchen",
+ "search_placeholder": "Name oder E-Mail (mind. 3 Zeichen)",
"create": "Neuen Benutzer anlegen",
"download_report": "Bericht herunterladen",
"empty": "Es konnten keine Benutzer gefunden werden",
diff --git a/resources/lang/en.json b/resources/lang/en.json
index ea34e40..4178116 100644
--- a/resources/lang/en.json
+++ b/resources/lang/en.json
@@ -349,6 +349,8 @@
"select_country": "Select a country",
"select_terms": "Select a terms version",
"select_society": "Select a nacional society",
+ "search": "Search",
+ "search_placeholder": "Name or email (min. 3 characters)",
"create": "Create new user",
"download_report": "Download report",
"empty": "Couldn't find any users",
diff --git a/resources/lang/es.json b/resources/lang/es.json
index 8164518..99741e6 100644
--- a/resources/lang/es.json
+++ b/resources/lang/es.json
@@ -349,6 +349,8 @@
"select_country": "Seleccionar un país",
"select_terms": "Seleccionar una versión de términos",
"select_society": "Seleccionar una sociedad nacional",
+ "search": "Buscar",
+ "search_placeholder": "Nombre o correo (mín. 3 caracteres)",
"create": "Crear nuevo usuario",
"download_report": "Descargar informe",
"empty": "No se encontraron usuarios",
diff --git a/resources/lang/fr.json b/resources/lang/fr.json
index f5a4ec8..4de01df 100644
--- a/resources/lang/fr.json
+++ b/resources/lang/fr.json
@@ -349,6 +349,8 @@
"select_country": "Sélectionner un pays",
"select_terms": "Sélectionner une version des conditions",
"select_society": "Sélectionner une société nationale",
+ "search": "Rechercher",
+ "search_placeholder": "Nom ou e-mail (3 caractères min.)",
"create": "Créer un nouvel utilisateur",
"download_report": "Télécharger le rapport",
"empty": "Aucun utilisateur trouvé",
diff --git a/resources/lang/ht.json b/resources/lang/ht.json
index d83355a..f09197f 100644
--- a/resources/lang/ht.json
+++ b/resources/lang/ht.json
@@ -343,6 +343,8 @@
"select_country": "Chwazi yon peyi",
"select_terms": "Chwazi yon vèsyon tèm yo",
"select_society": "Chwazi yon sosyete nasyonal",
+ "search": "Chèche",
+ "search_placeholder": "Non oswa imel (omwen 3 karaktè)",
"create": "Kreye nouvo itilizatè",
"download_report": "Telechaje rapò",
"empty": "Yo pa jwenn itilizatè yo",
diff --git a/resources/lang/id.json b/resources/lang/id.json
index 1ee7201..b1743cc 100644
--- a/resources/lang/id.json
+++ b/resources/lang/id.json
@@ -343,6 +343,8 @@
"select_country": "Select a country",
"select_terms": "Select a terms version",
"select_society": "Select a nacional society",
+ "search": "Cari",
+ "search_placeholder": "Nama atau email (min. 3 karakter)",
"create": "Membuat pengguna baru",
"download_report": "Unduh laporan",
"empty": "Tidak dapat menemukan pengguna",
diff --git a/resources/lang/it.json b/resources/lang/it.json
index da36375..9a49f68 100644
--- a/resources/lang/it.json
+++ b/resources/lang/it.json
@@ -343,6 +343,8 @@
"select_country": "Seleziona un paese",
"select_terms": "Seleziona una versione dei termini",
"select_society": "Seleziona una società nazionale",
+ "search": "Cerca",
+ "search_placeholder": "Nome o email (min. 3 caratteri)",
"create": "Crea nuovo utente",
"download_report": "Scarica il report",
"empty": "Non siamo riusciti a trovare alcun utente",
diff --git a/resources/lang/ja.json b/resources/lang/ja.json
index 527dff9..b1cd646 100644
--- a/resources/lang/ja.json
+++ b/resources/lang/ja.json
@@ -343,6 +343,8 @@
"select_country": "国を選択",
"select_terms": "利用規約のバージョンを選択",
"select_society": "国内協会を選択",
+ "search": "検索",
+ "search_placeholder": "名前またはメール(3文字以上)",
"create": "新規ユーザーの作成",
"download_report": "レポートをダウンロード",
"empty": "ユーザーが見つかりません",
diff --git a/resources/lang/my.json b/resources/lang/my.json
index 7bdf389..a655a06 100644
--- a/resources/lang/my.json
+++ b/resources/lang/my.json
@@ -343,6 +343,8 @@
"select_country": "နိုင်ငံကို ရွေးချယ်ပါ",
"select_terms": "စည်းကမ်းချက်များ ဗားရှင်းကို ရွေးချယ်ပါ",
"select_society": "အမျိုးသားအဖွဲ့အစည်းကို ရွေးချယ်ပါ",
+ "search": "ရှာဖွေရန်",
+ "search_placeholder": "အမည် သို့မဟုတ် အီးမေးလ် (အနည်းဆုံး စာလုံး 3 လုံး)",
"create": "အသုံးပြုသူ အသစ် ဖန်တီးခြင်း",
"download_report": "အစီရင်ခံစာကို ဒေါင်းလုဒ်ဆွဲပါ",
"empty": "မည်သည့်အသုံးပြုသူကိုမှ မတွေ့ရှိရပါ",
diff --git a/resources/lang/ne.json b/resources/lang/ne.json
index 9adbd1b..969378e 100644
--- a/resources/lang/ne.json
+++ b/resources/lang/ne.json
@@ -343,6 +343,8 @@
"select_country": "देश चयन गर्नुहोस्",
"select_terms": "सर्त संस्करण चयन गर्नुहोस्",
"select_society": "राष्ट्रिय समाज चयन गर्नुहोस्",
+ "search": "खोज्नुहोस्",
+ "search_placeholder": "नाम वा इमेल (कम्तीमा ३ अक्षर)",
"create": "नयाँ प्रयोगकर्ता बनाउनुहोस्",
"download_report": "रिपोर्ट डाउनलोड गर्नुहोस",
"empty": "कुनै प्रयोगकर्ता फेला परेन",
diff --git a/resources/lang/pt.json b/resources/lang/pt.json
index 5f05c31..dfcbeca 100644
--- a/resources/lang/pt.json
+++ b/resources/lang/pt.json
@@ -343,6 +343,8 @@
"select_country": "Selecione um país",
"select_terms": "Selecione uma versão dos termos",
"select_society": "Selecione uma sociedade nacional",
+ "search": "Pesquisar",
+ "search_placeholder": "Nome ou email (mín. 3 caracteres)",
"create": "Criar novo utilizador",
"download_report": "Descarregar relatório",
"empty": "Não foi possível encontrar utilizadores",
diff --git a/resources/lang/ru.json b/resources/lang/ru.json
index eafba44..756d848 100644
--- a/resources/lang/ru.json
+++ b/resources/lang/ru.json
@@ -343,6 +343,8 @@
"select_country": "Выберите страну",
"select_terms": "Выберите версию условий",
"select_society": "Выберите национальное общество",
+ "search": "Поиск",
+ "search_placeholder": "Имя или email (мин. 3 символа)",
"create": "Создать нового пользователя",
"download_report": "Скачать отчет",
"empty": "Пользователи не найдены",
diff --git a/resources/lang/rw.json b/resources/lang/rw.json
index 6aa55fa..669a38d 100644
--- a/resources/lang/rw.json
+++ b/resources/lang/rw.json
@@ -343,6 +343,8 @@
"select_country": "Hitamo igihugu",
"select_terms": "Hitamo verisiyo y'amasezerano",
"select_society": "Hitamo umuryango w'igihugu",
+ "search": "Shakisha",
+ "search_placeholder": "Izina cyangwa imeyili (nibura inyuguti 3)",
"create": "Shyiraho ukoresha mushya",
"download_report": "Kurura raporo",
"empty": "Ntubasha kubona umukoresha numwe",
diff --git a/resources/lang/sw.json b/resources/lang/sw.json
index c498aff..4032940 100644
--- a/resources/lang/sw.json
+++ b/resources/lang/sw.json
@@ -343,6 +343,8 @@
"select_country": "Chagua nchi",
"select_terms": "Chagua toleo la masharti",
"select_society": "Chagua jamii ya kitaifa",
+ "search": "Tafuta",
+ "search_placeholder": "Jina au barua pepe (angalau herufi 3)",
"create": "Unda mtumiaji mpya",
"download_report": "Kupakua taarifa",
"empty": "Imeshindwa kupata watumiaji wowote",
diff --git a/resources/lang/th.json b/resources/lang/th.json
index ffd2c6c..d8c0044 100644
--- a/resources/lang/th.json
+++ b/resources/lang/th.json
@@ -343,6 +343,8 @@
"select_country": "เลือกประเทศ",
"select_terms": "เลือกเวอร์ชันข้อกำหนด",
"select_society": "เลือกสมาคมระดับชาติ",
+ "search": "ค้นหา",
+ "search_placeholder": "ชื่อหรืออีเมล (อย่างน้อย 3 ตัวอักษร)",
"create": "สร้างบัญชีผู้ใช้ใหม่",
"download_report": "ดาวน์โหลดรายงาน",
"empty": "ไม่พบบัญชีผู้ใช้ใดๆ",
diff --git a/resources/lang/tr.json b/resources/lang/tr.json
index 2be00a6..556df0e 100644
--- a/resources/lang/tr.json
+++ b/resources/lang/tr.json
@@ -343,6 +343,8 @@
"select_country": "Ülke seçin",
"select_terms": "Şartlar sürümü seçin",
"select_society": "Ulusal topluluk seçin",
+ "search": "Ara",
+ "search_placeholder": "Ad veya e-posta (en az 3 karakter)",
"create": "Yeni kullanıcı oluştur",
"download_report": "Raporu indir",
"empty": "Kullanıcı bulunamadı",
diff --git a/resources/lang/ur.json b/resources/lang/ur.json
index eb56790..08a5cc7 100644
--- a/resources/lang/ur.json
+++ b/resources/lang/ur.json
@@ -343,6 +343,8 @@
"select_country": "ملک منتخب کریں",
"select_terms": "شرائط کا ورژن منتخب کریں",
"select_society": "قومی سوسائٹی منتخب کریں",
+ "search": "تلاش کریں",
+ "search_placeholder": "نام یا ای میل (کم از کم 3 حروف)",
"create": "ایک نیا صارف بنائیں",
"download_report": "رپورٹ ڈاؤن لوڈ کریں",
"empty": "کوئی بھی صارف نہیں ڈھونڈ سکا",
diff --git a/resources/lang/vi.json b/resources/lang/vi.json
index 1f2d23a..269a71b 100644
--- a/resources/lang/vi.json
+++ b/resources/lang/vi.json
@@ -343,6 +343,8 @@
"select_country": "Chọn quốc gia",
"select_terms": "Chọn phiên bản điều khoản",
"select_society": "Chọn hội quốc gia",
+ "search": "Tìm kiếm",
+ "search_placeholder": "Tên hoặc email (tối thiểu 3 ký tự)",
"create": "Tạo người dùng mới",
"download_report": "Tải xuống báo cáo",
"empty": "Không tìm thấy người dùng nào",
diff --git a/resources/lang/zh.json b/resources/lang/zh.json
index 92aec53..cd8ca87 100644
--- a/resources/lang/zh.json
+++ b/resources/lang/zh.json
@@ -343,6 +343,8 @@
"select_country": "选择国家/地区",
"select_terms": "选择条款版本",
"select_society": "选择国家协会",
+ "search": "搜索",
+ "search_placeholder": "姓名或电子邮件(至少 3 个字符)",
"create": "创建新用户",
"download_report": "下载报告",
"empty": "找不到用户",
diff --git a/resources/lang/zh_CN.json b/resources/lang/zh_CN.json
index a435c58..5bacbd3 100644
--- a/resources/lang/zh_CN.json
+++ b/resources/lang/zh_CN.json
@@ -343,6 +343,8 @@
"select_country": "选择国家/地区",
"select_terms": "选择条款版本",
"select_society": "选择国家协会",
+ "search": "搜索",
+ "search_placeholder": "姓名或电子邮件(至少 3 个字符)",
"create": "創建一個新用戶",
"download_report": "下載報告",
"empty": "無法找到任何用戶",
diff --git a/tests/Feature/UserTest.php b/tests/Feature/UserTest.php
index 09e0194..7d52e61 100644
--- a/tests/Feature/UserTest.php
+++ b/tests/Feature/UserTest.php
@@ -179,6 +179,55 @@ public function get_admin_user_list()
]);
}
+ /** @test */
+ public function get_admin_user_list_can_sort_by_profile_last_name()
+ {
+ $adminUser = factory(User::class)->create();
+ $adminUser->userProfile()->save(factory(UserProfile::class)->make([
+ 'first_name' => 'Able',
+ 'last_name' => 'Zed',
+ ]));
+
+ $duplicateProfile = factory(UserProfile::class)->make([
+ 'first_name' => 'Able',
+ 'last_name' => 'Aardvark',
+ ]);
+ $duplicateProfile->user_id = $adminUser->id;
+ $duplicateProfile->save();
+
+ $role = Role::create(['name' => 'Super Admin']);
+ $role->permissions()
+ ->sync([
+ Permission::where('name', '=', 'users-list')->first()->id,
+ ]);
+ $adminUser->roles()->attach($role->id);
+
+ $this->actingAs($adminUser)
+ ->getJson('/api/users/admins?page=1&orderBy=last_name&sort=asc')
+ ->assertSuccessful()
+ ->assertJsonCount(1, 'data')
+ ->assertJsonStructure([
+ 'data' => [
+ '*' => $this->getUserJsonStructure()
+ ],
+ 'links' => [
+ 'first',
+ 'last',
+ 'prev',
+ 'next'
+ ],
+ 'meta' => [
+ 'current_page',
+ 'from',
+ 'last_page',
+ 'path',
+ 'per_page',
+ 'to',
+ 'total'
+ ]
+ ]);
+ }
+
/** @test */
public function get_user_list_with_pagination()
{