Skip to content

PR3: Add debounce logic to user search#1742

Merged
adarshm11 merged 3 commits intodevfrom
devTA_searching_debounce_logic
Jul 19, 2025
Merged

PR3: Add debounce logic to user search#1742
adarshm11 merged 3 commits intodevfrom
devTA_searching_debounce_logic

Conversation

@Pikalot
Copy link
Copy Markdown
Collaborator

@Pikalot Pikalot commented Jul 1, 2025

Merge #1748 first.
This PR builds on top of PR2 (search UI) and introduces debounce logic to reduce API calls during user input.
Officer and Admin can search for users.
UI screenshots:

  • Light mode:
    image

  • Dark mode:
    image

@Pikalot Pikalot requested review from evanugarte and weslayer July 1, 2025 20:13
Copy link
Copy Markdown
Collaborator

@weslayer weslayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

boing boing

Base automatically changed from devTA_search_ui to devTA_shortcut_key July 3, 2025 20:54
Base automatically changed from devTA_shortcut_key to dev July 5, 2025 05:30
@Pikalot Pikalot changed the base branch from dev to devTA_search_ui July 5, 2025 07:50
@Pikalot Pikalot force-pushed the devTA_searching_debounce_logic branch 2 times, most recently from 1d1df62 to 99399bc Compare July 5, 2025 11:16
Base automatically changed from devTA_search_ui to dev July 7, 2025 04:40
@Pikalot Pikalot force-pushed the devTA_searching_debounce_logic branch 15 times, most recently from eb64d34 to 391560a Compare July 9, 2025 06:05
Comment thread api/main_endpoints/routes/UserSearch.js Outdated
.then(items => {
res.status(OK).send({ items, total, rowsPerPage: ROWS_PER_PAGE, });
})
.catch((e) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can remove the "e" in the catch, since you're not using it

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! Removed!

Comment thread src/Components/ShortcutKeyModal/SearchModal.js Outdated
@Pikalot Pikalot force-pushed the devTA_searching_debounce_logic branch 3 times, most recently from 7fb53f2 to abef8fd Compare July 13, 2025 19:40
Comment thread api/main_endpoints/routes/UserSearch.js Outdated
const parts = query.trim().split(/\s+/);
const first = parts[0];
const last = parts[parts.length - 1];
const nameRegex = new RegExp(`^${first}.*${last}`, 'i');
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if we do a match using whatever the user typed

so if i was searching for person one, i could match it by typing pone

Suggested change
const nameRegex = new RegExp(`^${first}.*${last}`, 'i');
const query = req.body.query.replace(/\s/g, '');
const pattern = new RegExp(`.*${query}.*`);

another example the above would match on would be person o, as right now the pr's logic is expecting the entire first and last name to by typed out to do a match

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New suggestion: Instead of matching the first and last name, the backend will match the record using the input sequence:

const query = req.body.query.replace(/\s/g, '');
const fuzzyPattern = query.split('').join('.*');
const pattern = new RegExp(fuzzyPattern, 'i');

This trades off O(n) performance for maximum flexibility. Note: this approach does not ignore discrepancies in middle names.

Comment thread api/main_endpoints/routes/UserSearch.js Outdated
{
$expr: {
$regexMatch: {
input: { $concat: ['$firstName', ' ', '$lastName'] },
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see other comment about regex change, we can just do

Suggested change
input: { $concat: ['$firstName', ' ', '$lastName'] },
input: { $concat: ['$firstName', '$lastName'] },

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment thread api/main_endpoints/routes/UserSearch.js Outdated
const limit = Math.min(Number(req.body.limit) || ROWS_PER_PAGE, ROWS_PER_PAGE);
let maybeOr = {};
const query = req.body.query;
if (query) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the user didnt pass a query in should we even bother displaying suggestions?

if (!req.body.query) {
  return res.status(OK).send({ items: [] });
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment thread api/main_endpoints/routes/UserSearch.js Outdated
};
}

const sortColumn = req.query.sort || 'joinDate';
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a way to have mongodb return the result based on best match? https://stackoverflow.com/a/27224578

Copy link
Copy Markdown
Collaborator Author

@Pikalot Pikalot Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Implement scoring approach:

        const aScore = Math.min(tokenScores(aName, input), tokenScores(aEmail, input));
        const bScore = Math.min(tokenScores(bName, input), tokenScores(bEmail, input));

        return aScore - bScore; 

Comment thread api/main_endpoints/routes/UserSearch.js Outdated
User.find(maybeOr, { password: 0, }, { skip, limit })
.sort({ [sortColumn] : sortOrder })
.then(items => {
res.status(OK).send({ items, total, rowsPerPage: ROWS_PER_PAGE, });
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

total and rowsPerPage are unused in the frontend, can we remove it

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment thread api/main_endpoints/routes/UserSearch.js Outdated
res.status(OK).send({ items, total, rowsPerPage: ROWS_PER_PAGE, });
})
.catch(() => {
res.sendStatus(BAD_REQUEST);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import logger and log the error, would be good for debugging

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment thread api/main_endpoints/routes/UserSearch.js Outdated
const ROWS_PER_PAGE = 20;

// Search for all members using either first name, last name or email
router.post('/shortcutsearchusers', async function(req, res) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this api can go in User.js instead of a new file

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! Migrated codes to user.js

@Pikalot Pikalot force-pushed the devTA_searching_debounce_logic branch 4 times, most recently from c13cf4c to cc96df4 Compare July 17, 2025 07:43
@Pikalot Pikalot force-pushed the devTA_searching_debounce_logic branch from cc96df4 to b568e60 Compare July 17, 2025 07:58
Comment thread test/api/User.js Outdated

it('Should return status code 401 if access level is invalid', async () => {
accessLevel = MEMBERSHIP_STATE.MEMBER;
setTokenStatus(accessLevel >= requiredLevel, {accessLevel});
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

each line with accessLevel >= requiredLevel, please hardcode it to true/false, it will read much easier

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Comment thread api/main_endpoints/routes/User.js Outdated
Comment on lines +554 to +556
if (str.startsWith(token)) return score + 0; // highest score for exact match
else if (str.includes(token)) return score + 1; // lower score for partial match
else return score + 2; // lowest score for no match
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (str.startsWith(token)) return score + 0; // highest score for exact match
else if (str.includes(token)) return score + 1; // lower score for partial match
else return score + 2; // lowest score for no match
if (str.startsWith(token)) return score + 0; // highest score for exact match
if (str.includes(token)) return score + 1; // lower score for partial match
return score + 2; // lowest score for no match

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Pikalot and others added 2 commits July 17, 2025 11:31
Co-authored-by: Evan Ugarte <36345325+evanugarte@users.noreply.github.com>
@adarshm11 adarshm11 merged commit 1de82d2 into dev Jul 19, 2025
4 checks passed
@adarshm11 adarshm11 deleted the devTA_searching_debounce_logic branch July 19, 2025 05:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants