diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json
index 4439651822..8cda295760 100644
--- a/services/web/frontend/extracted-translations.json
+++ b/services/web/frontend/extracted-translations.json
@@ -1442,6 +1442,7 @@
"per_license": "",
"per_month": "",
"per_month_x_annually": "",
+ "per_page": "",
"per_year": "",
"percent_is_the_percentage_of_the_line_width": "",
"permanently_delete_accounts": "",
@@ -1840,7 +1841,6 @@
"sharing_permissions": "",
"shortcut_to_open_advanced_reference_search": "",
"show_all_projects": "",
- "show_all_users": "",
"show_breadcrumbs": "",
"show_document_preamble": "",
"show_equation_preview": "",
@@ -1854,7 +1854,6 @@
"show_outline": "",
"show_version_history": "",
"show_x_more_projects": "",
- "show_x_more_users": "",
"showing_1_result": "",
"showing_1_result_of_total": "",
"showing_pdf_preview_with_inverted_colors": "",
diff --git a/services/web/frontend/js/shared/components/pagination-cep.tsx b/services/web/frontend/js/shared/components/pagination-cep.tsx
new file mode 100644
index 0000000000..86521b2f99
--- /dev/null
+++ b/services/web/frontend/js/shared/components/pagination-cep.tsx
@@ -0,0 +1,90 @@
+import { useTranslation } from 'react-i18next'
+
+interface PaginationProps {
+ currentPage: number
+ totalPages: number
+ onPageChange: (page: number) => void
+}
+
+export default function Pagination({
+ currentPage,
+ totalPages,
+ onPageChange,
+}: PaginationProps) {
+ const { t } = useTranslation()
+ if (totalPages <= 1) return null
+
+ const pageNumbers: (number | "...")[] = []
+ let startPage = Math.max(1, currentPage - 4)
+ let endPage = Math.min(totalPages, currentPage + 4)
+
+ if (startPage > 1) {
+ pageNumbers.push(1)
+ if (startPage > 2) {
+ pageNumbers.push("...")
+ }
+ }
+
+ for (let i = startPage; i <= endPage; i++) {
+ pageNumbers.push(i)
+ }
+
+ if (endPage < totalPages) {
+ if (endPage < totalPages - 1) {
+ pageNumbers.push("...")
+ }
+ pageNumbers.push(totalPages)
+ }
+
+ return (
+
+ )
+}
diff --git a/services/web/locales/de.json b/services/web/locales/de.json
index 1e6860cbaa..7ed4436cc9 100644
--- a/services/web/locales/de.json
+++ b/services/web/locales/de.json
@@ -1159,6 +1159,7 @@
"pending": "Ausstehend",
"pending_additional_licenses": "Dein Abonnement wird geändert, um <0>__pendingAdditionalLicenses__0> zusätzliche Lizenz(en) für insgesamt <1>__pendingTotalLicenses__1> Lizenzen einzuschließen.",
"per_month": "pro Monat",
+ "per_page": "pro Seite",
"per_user_year": "pro Nutzer / Jahr",
"per_year": "pro Jahr",
"permanently_delete_accounts": "Konten endgültig löschen",
@@ -1401,14 +1402,12 @@
"shared_with_you": "Mit dir geteilt",
"sharelatex_beta_program": "__appName__ Beta-Programm",
"show_all_projects": "Alle Projekte anzeigen",
- "show_all_users": "Alle Benutzer anzeigen",
"show_in_code": "Im Code anzeigen",
"show_in_pdf": "Im PDF anzeigen",
"show_less": "Weniger anzeigen",
"show_live_equation_previews_while_typing": "Live-Gleichungsvorschau beim Tippen anzeigen",
"show_outline": "Dateigliederung anzeigen",
"show_x_more_projects": "__x__ weitere Projekte anzeigen",
- "show_x_more_users": "__x__ weitere Benutzer anzeigen",
"showing_1_result": "1 Ergebnis wird angezeigt",
"showing_1_result_of_total": "Zeige 1 Ergebnis von __total__",
"showing_x_out_of_n_projects": "Es werden __x__ von __n__ Projekten angezeigt.",
diff --git a/services/web/locales/en.json b/services/web/locales/en.json
index 6fb43afd73..61ca041b13 100644
--- a/services/web/locales/en.json
+++ b/services/web/locales/en.json
@@ -1893,6 +1893,7 @@
"per_month": "per month",
"per_month_billed_annually": "per month, billed annually",
"per_month_x_annually": "per month, __price__ annually",
+ "per_page": "per page",
"per_user_year": "per user / year",
"per_year": "per year",
"percent_is_the_percentage_of_the_line_width": "% is the percentage of the line width",
@@ -2382,7 +2383,6 @@
"sharing_permissions": "Sharing permissions",
"shortcut_to_open_advanced_reference_search": "(__ctrlSpace__ or __altSpace__)",
"show_all_projects": "Show all projects",
- "show_all_users": "Show all users",
"show_breadcrumbs": "Show breadcrumbs",
"show_document_preamble": "Show document preamble",
"show_equation_preview": "Show equation preview",
@@ -2396,7 +2396,6 @@
"show_outline": "Show File outline",
"show_version_history": "Show version history",
"show_x_more_projects": "Show __x__ more projects",
- "show_x_more_users": "Show __x__ more users",
"showing_1_result": "Showing 1 result",
"showing_1_result_of_total": "Showing 1 result of __total__",
"showing_pdf_preview_with_inverted_colors": "Showing PDF preview with inverted colors",
diff --git a/services/web/locales/ru.json b/services/web/locales/ru.json
index 04373b1214..e94c4c7f31 100644
--- a/services/web/locales/ru.json
+++ b/services/web/locales/ru.json
@@ -325,6 +325,7 @@
"password_reset_token_expired": "Ваш код восстановления пароля истёк. Пожалуйста, запросите восстановление пароля по почте ещё раз и перейдите по ссылке в письме.",
"pdf_viewer": "Просмотрщик PDF",
"pending": "В ожидании",
+ "per_page": "на страницу",
"permanently_delete_accounts": "Окончательно удалить аккаунты",
"permanently_delete_projects": "Окончательно удалить проекты",
"personal": "Личный",
@@ -434,9 +435,7 @@
"share_project": "Открыть доступ к проекту",
"shared_with_you": "Доступные мне",
"show_all_projects": "Показать все проекты",
- "show_all_users": "Показать всех пользователей",
"show_x_more_projects": "Показать ещё __x__ проектов",
- "show_x_more_users": "Показать ещё __x__ пользователей",
"showing_x_out_of_n_projects": "Показано __x__ из __n__ проектов",
"showing_x_out_of_n_users": "Показано __x__ из __n__ пользователей",
"signed_up": "Зарегистрирован",
diff --git a/services/web/modules/admin-tools/app/src/UserListController.mjs b/services/web/modules/admin-tools/app/src/UserListController.mjs
index 0805d3480b..7b70dc217a 100644
--- a/services/web/modules/admin-tools/app/src/UserListController.mjs
+++ b/services/web/modules/admin-tools/app/src/UserListController.mjs
@@ -323,8 +323,8 @@ function _matchesFilters(user, filters) {
if (
filters.search?.length &&
user.email.toLowerCase().indexOf(filters.search.toLowerCase()) === -1 &&
- user.first_name.toLowerCase().indexOf(filters.search.toLowerCase()) === -1 &&
- user.last_name.toLowerCase().indexOf(filters.search.toLowerCase()) === -1
+ user.firstName?.toLowerCase().indexOf(filters.search.toLowerCase()) === -1 &&
+ user.lastName?.toLowerCase().indexOf(filters.search.toLowerCase()) === -1
) { return false }
// Deleted users only match the 'deleted' filter
if (user.deleted) return Boolean(filters.deleted)
diff --git a/services/web/modules/admin-tools/frontend/js/project-list/components/load-more.tsx b/services/web/modules/admin-tools/frontend/js/project-list/components/load-more.tsx
deleted file mode 100644
index 3843a89a19..0000000000
--- a/services/web/modules/admin-tools/frontend/js/project-list/components/load-more.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import { useTranslation } from 'react-i18next'
-import { useProjectListContext } from '../context/project-list-context'
-import OLButton from '@/shared/components/ol/ol-button'
-
-export default function LoadMore() {
- const {
- visibleProjects,
- hiddenProjectsCount,
- loadMoreCount,
- showAllProjects,
- loadMoreProjects,
- } = useProjectListContext()
- const { t } = useTranslation()
-
- return (
-
- {hiddenProjectsCount > 0 ? (
- <>
-
loadMoreProjects()}
- >
- {t('show_x_more_projects', { x: loadMoreCount })}
-
- >
- ) : null}
-
- {hiddenProjectsCount > 0 ? (
- <>
-
- {t('showing_x_out_of_n_projects', {
- x: visibleProjects.length,
- n: visibleProjects.length + hiddenProjectsCount,
- })}
- {' '}
- showAllProjects()}
- className="btn-inline-link"
- >
- {t('show_all_projects')}
-
- >
- ) : (
-
- {t('showing_x_out_of_n_projects', {
- x: visibleProjects.length,
- n: visibleProjects.length,
- })}
-
- )}
-
-
- )
-}
diff --git a/services/web/modules/admin-tools/frontend/js/project-list/components/modals/transfer-project-modal.tsx b/services/web/modules/admin-tools/frontend/js/project-list/components/modals/transfer-project-modal.tsx
index 3602d06664..384ac88442 100644
--- a/services/web/modules/admin-tools/frontend/js/project-list/components/modals/transfer-project-modal.tsx
+++ b/services/web/modules/admin-tools/frontend/js/project-list/components/modals/transfer-project-modal.tsx
@@ -13,7 +13,6 @@ import OLFormGroup from '@/shared/components/ol/ol-form-group'
import OLFormLabel from '@/shared/components/ol/ol-form-label'
import OLFormCheckbox from '@/shared/components/ol/ol-form-checkbox'
import OLSpinner from '@/shared/components/ol/ol-spinner'
-import sortUsers from '../../../user-list/util/sort-users'
type TransferProjectModalProps = Pick<
React.ComponentProps,
@@ -35,9 +34,8 @@ function TransferProjectModal({
const potentialOwners = useMemo(() => {
if (!loadedUsers) return null;
- const sortedUsers = sortUsers(loadedUsers, { by: 'name', order: 'asc' })
const result: UserRef[] = []
- for (const user of sortedUsers) {
+ for (const user of loadedUsers) {
if (!user.deleted && user.id !== projectsOwnerId) {
result.push({
id: user.id,
diff --git a/services/web/modules/admin-tools/frontend/js/project-list/components/project-list-ds-nav.tsx b/services/web/modules/admin-tools/frontend/js/project-list/components/project-list-ds-nav.tsx
index e6f0a7e0c7..6b3e84c128 100644
--- a/services/web/modules/admin-tools/frontend/js/project-list/components/project-list-ds-nav.tsx
+++ b/services/web/modules/admin-tools/frontend/js/project-list/components/project-list-ds-nav.tsx
@@ -18,6 +18,8 @@ import overleafLogo from '@/shared/svgs/overleaf-a-ds-solution-mallard.svg'
import { getUserName } from '../util/user'
import { useProjectListContext } from '../context/project-list-context'
import { useUserIdentityContext } from '../../user-list/context/user-identity-context'
+import Pagination from '@/shared/components/pagination-cep'
+import ProjectListSummary from './project-list-summary'
export function ProjectListDsNav() {
@@ -32,6 +34,9 @@ export function ProjectListDsNav() {
selectedProjects,
filter,
projectsOwnerId,
+ currentPage,
+ setCurrentPage,
+ totalPages,
} = useProjectListContext()
const { getUserNameById } = useUserIdentityContext()
@@ -100,7 +105,10 @@ export function ProjectListDsNav() {
+
diff --git a/services/web/modules/admin-tools/frontend/js/project-list/components/project-list-summary.tsx b/services/web/modules/admin-tools/frontend/js/project-list/components/project-list-summary.tsx
new file mode 100644
index 0000000000..156e5a2059
--- /dev/null
+++ b/services/web/modules/admin-tools/frontend/js/project-list/components/project-list-summary.tsx
@@ -0,0 +1,50 @@
+import { useTranslation } from 'react-i18next'
+import OLFormSelect from '@/shared/components/ol/ol-form-select'
+import { useProjectListContext } from '../context/project-list-context'
+
+export default function ProjectListSummary() {
+ const {
+ visibleProjects,
+ hiddenProjectsCount,
+ projectsPerPage,
+ setProjectsPerPage,
+ } = useProjectListContext()
+
+ const { t } = useTranslation()
+
+ return (
+
+
+
+ {t('showing_x_out_of_n_projects', {
+ x: visibleProjects.length,
+ n: visibleProjects.length + hiddenProjectsCount,
+ })}
+
+ ·
+
+ setProjectsPerPage(Number(e.target.value))}
+ style={{
+ width: 'auto',
+ border: '1px solid #ccc',
+ background: 'var(--green-10)',
+ padding: '0 0.2rem',
+ boxShadow: 'none',
+ cursor: 'pointer',
+ }}
+ >
+
+
+
+
+
+ {t('per_page')}
+
+
+
+
+ )
+}
diff --git a/services/web/modules/admin-tools/frontend/js/project-list/components/search-form.tsx b/services/web/modules/admin-tools/frontend/js/project-list/components/search-form.tsx
index 5eaddcd26c..085a77203a 100644
--- a/services/web/modules/admin-tools/frontend/js/project-list/components/search-form.tsx
+++ b/services/web/modules/admin-tools/frontend/js/project-list/components/search-form.tsx
@@ -1,13 +1,14 @@
+import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import * as eventTracking from '@/infrastructure/event-tracking'
import classnames from 'classnames'
-import { MergeAndOverride } from '../../../../../../types/utils'
+import * as eventTracking from '@/infrastructure/event-tracking'
import { isSmallDevice } from '@/infrastructure/event-tracking'
+import OLCol from '@/shared/components/ol/ol-col'
import OLForm from '@/shared/components/ol/ol-form'
import OLFormGroup from '@/shared/components/ol/ol-form-group'
-import OLCol from '@/shared/components/ol/ol-col'
import OLFormControl from '@/shared/components/ol/ol-form-control'
import MaterialIcon from '@/shared/components/material-icon'
+import { MergeAndOverride } from '../../../../../../types/utils'
type SearchFormOwnProps = {
inputValue: string
@@ -26,20 +27,39 @@ function SearchForm({
...props
}: SearchFormProps) {
const { t } = useTranslation()
- const placeholderMessage = t('search_projects')
- const placeholder = `${placeholderMessage}…`
+ const placeholder = t('search_projects')+'…'
+
+ const [localValue, setLocalValue] = useState(inputValue)
+ const debounceRef = useRef | null>(null)
+
+ useEffect(() => {
+ setLocalValue(inputValue)
+ }, [inputValue])
const handleChange: React.ComponentProps<
typeof OLFormControl
>['onChange'] = e => {
- eventTracking.sendMB('admin-user-project-list-page-interaction', {
+ eventTracking.sendMB('admin-project-list-page-interaction', {
action: 'search',
isSmallDevice,
})
- setInputValue(e.target.value)
+
+ const value = e.target.value
+ setLocalValue(value)
+
+ if (debounceRef.current) {
+ clearTimeout(debounceRef.current)
+ }
+
+ debounceRef.current = setTimeout(() => {
+ setInputValue(value)
+ }, 300)
}
- const handleClear = () => setInputValue('')
+ const handleClear = () => {
+ setLocalValue('')
+ setInputValue('')
+ }
return (
}
append={
- inputValue.length > 0 && (
+ localValue.length > 0 && (
@@ -98,7 +101,10 @@ export function UserListDsNav() {
-
+
+
+
diff --git a/services/web/modules/admin-tools/frontend/js/user-list/components/user-list-summary.tsx b/services/web/modules/admin-tools/frontend/js/user-list/components/user-list-summary.tsx
new file mode 100644
index 0000000000..d6743f86a9
--- /dev/null
+++ b/services/web/modules/admin-tools/frontend/js/user-list/components/user-list-summary.tsx
@@ -0,0 +1,50 @@
+import { useTranslation } from 'react-i18next'
+import OLFormSelect from '@/shared/components/ol/ol-form-select'
+import { useUserListContext } from '../context/user-list-context'
+
+export default function UserListSummary() {
+ const {
+ visibleUsers,
+ hiddenUsersCount,
+ usersPerPage,
+ setUsersPerPage,
+ } = useUserListContext()
+
+ const { t } = useTranslation()
+
+ return (
+
+
+
+ {t('showing_x_out_of_n_users', {
+ x: visibleUsers.length,
+ n: visibleUsers.length + hiddenUsersCount,
+ })}
+
+ ·
+
+ setUsersPerPage(Number(e.target.value))}
+ style={{
+ width: 'auto',
+ border: '1px solid #ccc',
+ background: 'var(--green-10)',
+ padding: '0 0.2rem',
+ boxShadow: 'none',
+ cursor: 'pointer',
+ }}
+ >
+
+
+
+
+
+ {t('per_page')}
+
+
+
+
+ )
+}
diff --git a/services/web/modules/admin-tools/frontend/js/user-list/context/user-list-context.tsx b/services/web/modules/admin-tools/frontend/js/user-list/context/user-list-context.tsx
index f256a94c53..251b124150 100644
--- a/services/web/modules/admin-tools/frontend/js/user-list/context/user-list-context.tsx
+++ b/services/web/modules/admin-tools/frontend/js/user-list/context/user-list-context.tsx
@@ -6,6 +6,7 @@ import {
useEffect,
useMemo,
useState,
+ useRef,
} from 'react'
import {
filter as arrayFilter,
@@ -25,8 +26,6 @@ import sortUsers from '../util/sort-users'
import { UserIdentityProvider } from './user-identity-context'
-const MAX_USER_PER_PAGE = 10
-
type AuthMethods = 'local' | 'ldap' | 'saml' | 'oidc'
export type Filter = 'all' | 'admin' | 'suspended' | 'inactive' | AuthMethods | 'deleted'
@@ -68,8 +67,6 @@ export type UserListContextValue = {
filterTranslations: Map
hiddenUsersCount: number
isLoading: ReturnType['isLoading']
- loadMoreCount: number
- loadMoreUsers: () => void
loadProgress: number
removeUserFromView: (user: User) => void
searchText: string
@@ -81,13 +78,17 @@ export type UserListContextValue = {
setSearchText: React.Dispatch>
setSelectedUserIds: React.Dispatch>>
setSort: React.Dispatch>
- showAllUsers: () => void
sort: Sort
toggleSelectedUser: (userId: string, selected?: boolean) => void
totalUsersCount: number
updateUserViewData: (newUserData: User) => void
loadedUsers: User[]
visibleUsers: User[]
+ currentPage: number
+ setCurrentPage: React.Dispatch>
+ totalPages: number
+ usersPerPage: number,
+ setUsersPerPage: React.Dispatch>,
}
export const UserListContext = createContext<
@@ -104,9 +105,6 @@ export function UserListProvider({ children }: UserListProviderProps) {
prefetchedUsersBlob?.users ?? []
)
- const [maxVisibleUsers, setMaxVisibleUsers] =
- useState(MAX_USER_PER_PAGE)
-
const [loadProgress, setLoadProgress] = useState(
prefetchedUsersBlob ? 100 : 20
)
@@ -130,7 +128,31 @@ export function UserListProvider({ children }: UserListProviderProps) {
'all'
)
- const [searchText, setSearchText] = useState('')
+ const [currentPage, setCurrentPage] = useState(1)
+ const [searchText, setSearchTextState] = useState('')
+ const lastNonSearchPageRef = useRef(1)
+ const isSearchingRef = useRef(false)
+
+ const setSearchText: React.Dispatch> = value => {
+ setSearchTextState(prev => {
+ const nextValue =
+ typeof value === 'function' ? value(prev) : value
+
+ const wasSearching = isSearchingRef.current
+ const willSearch = nextValue.length > 0
+
+ if (!wasSearching && willSearch) {
+ lastNonSearchPageRef.current = currentPage
+ isSearchingRef.current = true
+ setCurrentPage(1)
+ } else if (wasSearching && !willSearch) {
+ isSearchingRef.current = false
+ setCurrentPage(lastNonSearchPageRef.current)
+ }
+
+ return nextValue
+ })
+ }
const {
isLoading: loading,
@@ -143,10 +165,11 @@ export function UserListProvider({ children }: UserListProviderProps) {
})
const isLoading = isIdle ? true : loading
+
useEffect(() => {
if (prefetchedUsersBlob) return
setLoadProgress(40)
- runAsync(getUsers({ by: 'signUpDate', order: 'desc' }))
+ runAsync(getUsers({ by: 'name', order: 'asc' }))
.then(data => {
setLoadedUsers(data.users)
setTotalUsersCount(data.totalSize)
@@ -161,7 +184,10 @@ export function UserListProvider({ children }: UserListProviderProps) {
setLoadedUsers(prev => [newUser as User, ...prev])
}, [])
- const processedUsers = useMemo(() => {
+ const isDefaultSort =
+ sort.by === 'name' && sort.order === 'asc'
+
+ const filteredUsers = useMemo(() => {
let users = loadedUsers
if (searchText.length) {
@@ -175,35 +201,50 @@ export function UserListProvider({ children }: UserListProviderProps) {
users = arrayFilter(users, filters[filter])
- return sortUsers(users, sort)
- }, [loadedUsers, searchText, filter, sort])
+ return users
+ }, [loadedUsers, searchText, filter])
+
+ const processedUsers = useMemo(() => {
+ if (isDefaultSort) {
+ return filteredUsers
+ }
+
+ return sortUsers(filteredUsers, sort)
+ }, [filteredUsers, sort, isDefaultSort])
+
+ const [usersPerPage, setUsersPerPage] = useState(20)
+ const previousUsersPerPageRef = useRef(usersPerPage)
+
+ useEffect(() => {
+ const previousUsersPerPage = previousUsersPerPageRef.current
+
+ if (previousUsersPerPage !== usersPerPage) {
+ const oldStartIndex = (currentPage - 1) * previousUsersPerPage
+ const newPage = Math.floor(oldStartIndex / usersPerPage) + 1
+ setCurrentPage(newPage)
+ previousUsersPerPageRef.current = usersPerPage
+ }
+ }, [usersPerPage])
+
+ const totalPages = useMemo(
+ () => Math.ceil(processedUsers.length / usersPerPage),
+ [processedUsers.length, usersPerPage]
+ )
+ const startIndex = (currentPage - 1) * usersPerPage
const visibleUsers = useMemo(() => {
- return processedUsers.slice(0, maxVisibleUsers)
- }, [processedUsers, maxVisibleUsers])
+ return processedUsers.slice(startIndex, startIndex + usersPerPage)
+ }, [processedUsers, startIndex, usersPerPage])
const hiddenUsersCount = Math.max(
processedUsers.length - visibleUsers.length,
0
)
- const loadMoreCount = Math.min(
- hiddenUsersCount,
- MAX_USER_PER_PAGE
- )
-
const selfVisibleCount = useMemo(() => {
return visibleUsers.some(u => u.id === selfId) ? 1 : 0
}, [visibleUsers])
- const showAllUsers = useCallback(() => {
- setMaxVisibleUsers(maxVisibleUsers + hiddenUsersCount)
- }, [hiddenUsersCount, maxVisibleUsers])
-
- const loadMoreUsers = useCallback(() => {
- setMaxVisibleUsers(maxVisibleUsers + loadMoreCount)
- }, [maxVisibleUsers, loadMoreCount])
-
const [selectedUserIds, setSelectedUserIds] = useState(
() => new Set()
)
@@ -266,10 +307,10 @@ export function UserListProvider({ children }: UserListProviderProps) {
return prev
})
- const selected = false
- selectOrUnselectAllUsers(selected)
+ selectOrUnselectAllUsers(false)
+ setCurrentPage(1)
},
- [selectOrUnselectAllUsers, setFilter]
+ [selectOrUnselectAllUsers]
)
const updateUserViewData = useCallback((newUserData: User) => {
@@ -294,8 +335,6 @@ export function UserListProvider({ children }: UserListProviderProps) {
filterTranslations,
hiddenUsersCount,
isLoading,
- loadMoreCount,
- loadMoreUsers,
loadProgress,
removeUserFromView,
searchText,
@@ -307,13 +346,17 @@ export function UserListProvider({ children }: UserListProviderProps) {
setSearchText,
setSelectedUserIds,
setSort,
- showAllUsers,
sort,
toggleSelectedUser,
totalUsersCount,
updateUserViewData,
loadedUsers,
visibleUsers,
+ currentPage,
+ setCurrentPage,
+ totalPages,
+ usersPerPage,
+ setUsersPerPage,
}),
[
addUserToView,
@@ -322,8 +365,6 @@ export function UserListProvider({ children }: UserListProviderProps) {
filterTranslations,
hiddenUsersCount,
isLoading,
- loadMoreCount,
- loadMoreUsers,
loadProgress,
removeUserFromView,
searchText,
@@ -335,19 +376,21 @@ export function UserListProvider({ children }: UserListProviderProps) {
setSearchText,
setSelectedUserIds,
setSort,
- showAllUsers,
sort,
toggleSelectedUser,
totalUsersCount,
updateUserViewData,
loadedUsers,
visibleUsers,
+ currentPage,
+ setCurrentPage,
+ totalPages,
+ usersPerPage,
+ setUsersPerPage,
]
)
- if (!loadedUsers || loadedUsers.length === 0) {
- return null
- }
+ if (isLoading) return null
return (
diff --git a/services/web/modules/admin-tools/frontend/js/user-list/hooks/use-sort.ts b/services/web/modules/admin-tools/frontend/js/user-list/hooks/use-sort.ts
index 07472eec69..876e9fdeb1 100644
--- a/services/web/modules/admin-tools/frontend/js/user-list/hooks/use-sort.ts
+++ b/services/web/modules/admin-tools/frontend/js/user-list/hooks/use-sort.ts
@@ -8,9 +8,10 @@ const toggleSort = (order: SortingOrder): SortingOrder => {
}
function useSort() {
- const { filter, sort, setSort } = useUserListContext()
+ const { filter, sort, setSort, setCurrentPage } = useUserListContext()
const handleSort = (by: Sort['by']) => {
+ setCurrentPage(1)
setSort(prev => ({
by,
order: prev.by === by ? toggleSort(sort.order) : sort.order,
@@ -19,13 +20,15 @@ function useSort() {
useEffect(() => {
if (filter === 'deleted' && sort.by === 'signUpDate') {
+ setCurrentPage(1)
setSort(prev => ({ ...prev, by: 'deletedAt' }))
}
if (filter !== 'deleted' && sort.by === 'deletedAt') {
+ setCurrentPage(1)
setSort(prev => ({ ...prev, by: 'signUpDate' }))
}
- }, [filter, sort.by, setSort])
+ }, [filter, sort.by, setSort, setCurrentPage])
return { handleSort }
}