Skip to content

Commit a246e51

Browse files
Feature/Infinite-scrolling-feature-and-user-search-fix-on-user-management-page (#860)
* resolved the conflicts * fixed the user search feature bugs * refactored constants file * implemented the old changes * resolved the conflicts * fixed the user search feature bugs * refactored constants file * implemented the old changes * added the test fot the empty search after search once * fixed the repeating code --------- Co-authored-by: Yash Raj <[email protected]>
1 parent 367b33a commit a246e51

File tree

5 files changed

+140
-110
lines changed

5 files changed

+140
-110
lines changed

__tests__/users/user-management-home-screen.test.js

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -108,40 +108,46 @@ describe('Tests the User Management User Listing Screen', () => {
108108
expect(liList.length).toBeGreaterThan(0);
109109
});
110110

111-
it('checks the search functionality to display queried user', async () => {
111+
it('Checks the search functionality to display queried user', async () => {
112112
await page.type('input[id="user-search"]', 'randhir');
113113
await page.waitForNetworkIdle();
114114
const userList = await page.$('#user-list');
115115
const userCard = await userList.$$('li');
116116
expect(userCard.length).toBeGreaterThan(0);
117117
});
118118

119-
it('checks the next and previous button functionality', async () => {
120-
await page.goto('http://localhost:8000/users');
121-
await page.waitForNetworkIdle();
119+
it('Checks for empty string input once the user removes their input', async () => {
120+
// Find the user list and the user cards
121+
const userList = await page.$('#head_list');
122+
let userCard = await userList.$$('li');
122123

123-
// Get the "next" button and check if it is enabled
124-
const nextBtn = await page.$('#nextButton');
125-
const isNextButtonDisabled = await page.evaluate(
126-
(button) => button.disabled,
127-
nextBtn,
128-
);
129-
expect(isNextButtonDisabled).toBe(false);
124+
await page.click('input[id="user-search"]');
125+
await page.keyboard.down('Control'); // On Mac, use 'Meta' instead of 'Control'
126+
await page.keyboard.press('A');
127+
await page.keyboard.up('Control');
128+
await page.keyboard.press('Backspace');
130129

131-
// Click the "next" button and wait for the page to load
132-
await nextBtn.click();
133130
await page.waitForNetworkIdle();
134131

135-
// Check that the "next" button is still present and the "previous" button is not disabled
136-
const updatedNextButton = await page.$('#nextButton');
137-
expect(updatedNextButton).toBeTruthy();
132+
userCard = await userList.$$('li');
133+
134+
expect(userCard.length).toBeGreaterThan(0);
135+
});
138136

139-
const prevBtn = await page.$('#prevButton');
140-
const isPrevButtonDisabled = await page.evaluate(
141-
(button) => button.disabled,
142-
prevBtn,
137+
it('checks infinite scroll functionality to load more users', async () => {
138+
await page.goto('http://localhost:8000/users');
139+
await page.waitForNetworkIdle();
140+
const userList = await page.$('#user-list');
141+
let initialUserCount = await userList.$$eval('li', (items) => items.length);
142+
expect(initialUserCount).toBeGreaterThan(0);
143+
await page.evaluate(() => {
144+
window.scrollTo(0, document.body.scrollHeight);
145+
});
146+
const updatedUserCount = await userList.$$eval(
147+
'li',
148+
(items) => items.length,
143149
);
144-
expect(isPrevButtonDisabled).toBe(false);
150+
expect(updatedUserCount).toBeGreaterThanOrEqual(initialUserCount);
145151
});
146152

147153
it('Clicking on filter button should display filter modal', async () => {

users/constants.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
const RDS_API_USERS = `${API_BASE_URL}/users`;
22
const RDS_API_SKILLS = `${API_BASE_URL}/tags`;
33
const USER_LIST_ELEMENT = 'user-list';
4+
const HEAD_LIST_ELEMENT = 'head_list';
45
const LOADER_ELEMENT = 'loader';
6+
const USER_LOADER_ELEMENT = 'loader_tag';
57
const TILE_VIEW_BTN = 'tile-view-btn';
68
const TABLE_VIEW_BTN = 'table-view-btn';
79
const USER_SEARCH_ELEMENT = 'user-search';

users/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ <h2>Skills</h2>
6969
</div>
7070
<div id="user-list">
7171
<div id="loader"></div>
72+
<ul id="head_list"></ul>
7273
</div>
74+
<div id="loader_tag" style="display: none"></div>
7375
<div id="pagination" class="remove-element">
7476
<button class="pagination-btn" id="prevButton">&laquo; Previous</button>
7577
<button class="pagination-btn" id="nextButton">Next &raquo;</button>

users/script.js

Lines changed: 93 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const params = new URLSearchParams(window.location.search);
22
const userListElement = document.getElementById(USER_LIST_ELEMENT);
33
const loaderElement = document.getElementById(LOADER_ELEMENT);
4+
const userloaderElement = document.getElementById(USER_LOADER_ELEMENT);
45
const tileViewBtn = document.getElementById(TILE_VIEW_BTN);
56
const tableViewBtn = document.getElementById(TABLE_VIEW_BTN);
67
const userSearchElement = document.getElementById(USER_SEARCH_ELEMENT);
@@ -12,10 +13,13 @@ const filterButton = document.getElementById(FILTER_BUTTON);
1213
const availabilityFilter = document.getElementById(AVAILABILITY_FILTER);
1314
const applyFilterButton = document.getElementById(APPLY_FILTER_BUTTON);
1415
const clearButton = document.getElementById(CLEAR_BUTTON);
16+
const ulElement = document.getElementById(HEAD_LIST_ELEMENT);
1517

1618
let tileViewActive = false;
1719
let tableViewActive = true;
20+
let isLoading = false;
1821
let page = 0;
22+
let run = true;
1923

2024
const init = (
2125
prevBtn,
@@ -27,26 +31,24 @@ const init = (
2731
paginationElement,
2832
loaderElement,
2933
) => {
30-
prevBtn.addEventListener('click', () => {
31-
showUserDataList(
32-
--page,
33-
userListElement,
34-
paginationElement,
35-
loaderElement,
36-
prevBtn,
37-
nextBtn,
38-
);
39-
});
34+
window.addEventListener('scroll', async () => {
35+
if (
36+
window.innerHeight + window.scrollY >= document.body.offsetHeight - 100 &&
37+
run
38+
) {
39+
if (!page) {
40+
page++;
41+
return;
42+
}
4043

41-
nextBtn.addEventListener('click', () => {
42-
showUserDataList(
43-
++page,
44-
userListElement,
45-
paginationElement,
46-
loaderElement,
47-
prevBtn,
48-
nextBtn,
49-
);
44+
run = false;
45+
showUserDataList(
46+
page++,
47+
userListElement,
48+
paginationElement,
49+
loaderElement,
50+
);
51+
}
5052
});
5153

5254
tileViewBtn.addEventListener('click', () => {
@@ -65,17 +67,9 @@ const init = (
6567
userListElement,
6668
paginationElement,
6769
loaderElement,
68-
prevBtn,
6970
);
7071
}
71-
showUserDataList(
72-
page,
73-
userListElement,
74-
paginationElement,
75-
loaderElement,
76-
prevBtn,
77-
nextBtn,
78-
);
72+
showUserDataList(page, userListElement, paginationElement, loaderElement);
7973
}, 500),
8074
);
8175
};
@@ -86,6 +80,8 @@ function showTileView(userListElement, tableViewBtn, tileViewBtn) {
8680
tableViewBtn.classList.remove('btn-active');
8781
tileViewBtn.classList.add('btn-active');
8882
const listContainerElement = userListElement.lastChild;
83+
const headList = document.getElementById('head_list');
84+
headList.classList.add('tile-webview');
8985
listContainerElement.childNodes.forEach((listElement) => {
9086
const imgElement = listElement.firstChild;
9187
imgElement.classList.add('remove-element');
@@ -99,6 +95,8 @@ function showTableView(userListElement, tableViewBtn, tileViewBtn) {
9995
tileViewBtn.classList.remove('btn-active');
10096
tableViewBtn.classList.add('btn-active');
10197
const listContainerElement = userListElement.lastChild;
98+
const headList = document.getElementById('head_list');
99+
headList.classList.remove('tile-webview');
102100
listContainerElement.childNodes.forEach((listElement) => {
103101
const imgElement = listElement.firstChild;
104102
imgElement.classList.remove('remove-element');
@@ -116,6 +114,7 @@ function showErrorMessage(
116114
const paraELe = document.createElement('p');
117115
const textNode = document.createTextNode(msg);
118116
paraELe.appendChild(textNode);
117+
paraELe.id = 'error_para';
119118
paraELe.classList.add('error-text');
120119
userListElement.appendChild(paraELe);
121120
paginationElement.classList.add('remove-element');
@@ -149,14 +148,7 @@ function generateUserList(
149148
userListElement,
150149
paginationElement,
151150
loaderElement,
152-
prevBtn,
153151
) {
154-
userListElement.innerHTML = '';
155-
if (page <= 0) {
156-
prevBtn.classList.add('btn-disabled');
157-
} else {
158-
prevBtn.classList.remove('btn-disabled');
159-
}
160152
if (!users || !users.length) {
161153
showErrorMessage(
162154
'No data found',
@@ -166,40 +158,49 @@ function generateUserList(
166158
);
167159
return;
168160
}
169-
const ulElement = document.createElement('ul');
170-
users.forEach((userData) => {
171-
const listElement = document.createElement('li');
172-
const imgElement = document.createElement('img');
173-
imgElement.src = userData.picture ? userData.picture : DEFAULT_AVATAR;
174-
imgElement.classList.add('user-img-dimension');
175-
const pElement = document.createElement('p');
176-
const node = document.createTextNode(
177-
`${userData.first_name} ${userData.last_name}`,
178-
);
179-
pElement.appendChild(node);
180-
listElement.appendChild(imgElement);
181-
listElement.appendChild(pElement);
182161

183-
if (tileViewActive) {
184-
let imgElement = listElement.firstChild;
185-
listElement.classList.remove('tile-width');
186-
imgElement.classList.add('remove-element');
162+
const errorTexts = document.getElementById('error_para');
163+
if (errorTexts) {
164+
errorTexts.remove();
165+
}
166+
167+
if (showPagination || page == 0) {
168+
ulElement.innerHTML = '';
169+
}
170+
171+
if (users?.length) {
172+
users?.forEach((userData) => {
173+
const listElement = document.createElement('li');
174+
const imgElement = document.createElement('img');
175+
imgElement.src = userData.picture ? userData.picture : DEFAULT_AVATAR;
176+
imgElement.classList.add('user-img-dimension');
177+
listElement.classList.add('tile-webview');
178+
const pElement = document.createElement('p');
179+
const node = document.createTextNode(
180+
`${userData.first_name} ${userData.last_name}`,
181+
);
182+
pElement.appendChild(node);
183+
listElement.appendChild(imgElement);
184+
listElement.appendChild(pElement);
185+
186+
if (tileViewActive) {
187+
let imgElement = listElement.firstChild;
188+
listElement.classList.add('tile-width');
189+
imgElement.classList.add('remove-element');
190+
}
191+
listElement.onclick = () => {
192+
document.getElementById('user-search').value = '';
193+
window.location.href = `/users/details/index.html?username=${userData.username}`;
194+
};
195+
ulElement.appendChild(listElement);
196+
});
197+
loaderElement.classList.add('remove-element');
198+
userListElement.appendChild(ulElement);
199+
run = true;
200+
if (document.getElementById('loader')) {
201+
document.getElementById('loader').classList.add('remove-element');
187202
}
188-
listElement.onclick = () => {
189-
document.getElementById('user-search').value = '';
190-
window.location.href = `/users/details/index.html?username=${userData.username}`;
191-
};
192-
ulElement.appendChild(listElement);
193-
});
194-
loaderElement.classList.add('remove-element');
195-
if (showPagination) {
196-
paginationElement.classList.remove('remove-element');
197-
paginationElement.classList.add('pagination');
198-
} else {
199-
paginationElement.classList.add('remove-element');
200-
paginationElement.classList.remove('pagination');
201203
}
202-
userListElement.appendChild(ulElement);
203204
}
204205

205206
async function fetchUsersData(searchInput) {
@@ -238,19 +239,28 @@ async function getParticularUserData(
238239
userListElement,
239240
paginationElement,
240241
loaderElement,
241-
prevBtn,
242242
) {
243243
try {
244+
page = 0;
245+
if (!searchInput.length) {
246+
await showUserDataList(
247+
page,
248+
userListElement,
249+
paginationElement,
250+
loaderElement,
251+
);
252+
return;
253+
}
244254
const usersData = await fetchUsersData(searchInput);
245255
if (usersData.users) {
246-
const data = formatUsersData(usersData.users);
256+
const data = formatUsersData(usersData?.users);
257+
247258
generateUserList(
248259
data,
249-
false,
260+
true,
250261
userListElement,
251262
paginationElement,
252263
loaderElement,
253-
prevBtn,
254264
);
255265
} else {
256266
showErrorMessage(
@@ -318,32 +328,24 @@ function displayLoader() {
318328
function clearFilters() {
319329
availabilityFilter.value = 'none';
320330
displayLoader();
321-
showUserDataList(
322-
page,
323-
userListElement,
324-
paginationElement,
325-
loaderElement,
326-
prevBtn,
327-
nextBtn,
328-
);
331+
showUserDataList(page, userListElement, paginationElement, loaderElement);
329332
}
330333

331334
const showUserDataList = async (
332335
page,
333336
userListElement,
334337
paginationElement,
335338
loaderElement,
336-
prevBtn,
337-
nextBtn,
338339
) => {
339340
try {
341+
if (isLoading) return;
342+
if (page != 0) {
343+
isLoading = true;
344+
userloaderElement.style.display = 'block';
345+
}
346+
340347
const userData = await getUsersData(page);
341-
if (userData.length) {
342-
if (userData.length < USER_FETCH_COUNT) {
343-
nextBtn.classList.add('btn-disabled');
344-
} else {
345-
nextBtn.classList.remove('btn-disabled');
346-
}
348+
if (userData && userData.length) {
347349
let usersDataList = userData.filter(
348350
(user) => user.first_name && !user.roles?.archived,
349351
);
@@ -355,11 +357,10 @@ const showUserDataList = async (
355357
}));
356358
generateUserList(
357359
usersDataList,
358-
true,
360+
false,
359361
userListElement,
360362
paginationElement,
361363
loaderElement,
362-
prevBtn,
363364
);
364365
}
365366
} catch (err) {
@@ -370,6 +371,9 @@ const showUserDataList = async (
370371
paginationElement,
371372
loaderElement,
372373
);
374+
} finally {
375+
userloaderElement.style.display = 'none';
376+
isLoading = false;
373377
}
374378
};
375379

@@ -664,6 +668,7 @@ clearButton.addEventListener('click', function () {
664668
clearCheckboxes('availability-filter');
665669
filterModal.classList.toggle('hidden');
666670
displayLoader();
671+
page = 0;
667672
showUserDataList(
668673
page,
669674
userListElement,

0 commit comments

Comments
 (0)