Skip to content

Commit

Permalink
Improve search functionality (#558)
Browse files Browse the repository at this point in the history
  • Loading branch information
antoinejaussoin authored Jul 18, 2023
1 parent 5220124 commit be4ae89
Show file tree
Hide file tree
Showing 11 changed files with 345 additions and 144 deletions.
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"util": "0.12.5",
"uuid": "9.0.0",
"vite": "4.3.8",
"vite-plugin-checker": "^0.6.1",
"vite-plugin-ejs": "1.6.4",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-svgr": "3.2.0",
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/Game.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Dashboard, List, CloudOff } from '@mui/icons-material';
import { useTranslation } from 'react-i18next';
import useGame from './game/useGame';
import Board from './game/board/Board';
import SummaryMode from './game/summary/SummaryMode';
import { SummaryMode } from './game/summary/SummaryMode';
import useColumns from './game/useColumns';
import NoContent from '../components/NoContent';
import useCrypto from '../crypto/useCrypto';
Expand Down
37 changes: 17 additions & 20 deletions frontend/src/views/game/__tests__/is-search-match.test.ts
Original file line number Diff line number Diff line change
@@ -1,61 +1,58 @@
import isSearchMatch from '../is-search-match';
import { searchLogic } from '../is-search-match';

describe('Search Match logic', () => {
it('Should be a match if there is no search (as everything matches)', () => {
expect(isSearchMatch('One little piggy', 'Bob Dylan', '', false)).toBe(
true
);
expect(searchLogic('One little piggy', 'Bob Dylan', '', false)).toBe(true);
});

it('Should not be a match if the post is blurred', () => {
expect(isSearchMatch('One little piggy', 'Bob Dylan', 'little', true)).toBe(
expect(searchLogic('One little piggy', 'Bob Dylan', 'little', true)).toBe(
false
);
});

it('Should be a match if the search matches the content', () => {
expect(
isSearchMatch('One little piggy', 'Bob Dylan', 'little', false)
).toBe(true);
expect(searchLogic('One little piggy', 'Bob Dylan', 'little', false)).toBe(
true
);

expect(
isSearchMatch('One little piggy', 'Bob Dylan', 'LITTLE', false)
).toBe(true);
expect(searchLogic('One little piggy', 'Bob Dylan', 'LITTLE', false)).toBe(
true
);
});

it('Should NOT be a match if the search does not matches the content', () => {
expect(isSearchMatch('One little piggy', 'Bob Dylan', 'big', false)).toBe(
expect(searchLogic('One little piggy', 'Bob Dylan', 'big', false)).toBe(
false
);

expect(isSearchMatch('One little piggy', 'Bob Dylan', 'litle', false)).toBe(
expect(searchLogic('One little piggy', 'Bob Dylan', 'litle', false)).toBe(
false
);
});

it('Should be a match if the search matches the author', () => {
expect(isSearchMatch('One little piggy', 'Bob Dylan', 'dyl', false)).toBe(
expect(searchLogic('One little piggy', 'Bob Dylan', 'dyl', false)).toBe(
true
);

expect(isSearchMatch('One little piggy', 'Bob Dylan', 'bob d', false)).toBe(
expect(searchLogic('One little piggy', 'Bob Dylan', 'bob d', false)).toBe(
true
);
});

it('Should NOT be a match if the search does not matches the author', () => {
expect(isSearchMatch('One little piggy', 'Bob Dylan', 'John', false)).toBe(
expect(searchLogic('One little piggy', 'Bob Dylan', 'John', false)).toBe(
false
);

expect(isSearchMatch('One little piggy', 'Bob Dylan', 'Lenon', false)).toBe(
expect(searchLogic('One little piggy', 'Bob Dylan', 'Lenon', false)).toBe(
false
);
});

it('Should NOT be a match if the author is null', () => {
expect(isSearchMatch('One little piggy', null, 'John', false)).toBe(false);

expect(isSearchMatch('One little piggy', null, 'Lenon', false)).toBe(false);
expect(searchLogic('One little piggy', null, 'John', false)).toBe(false);
expect(searchLogic('One little piggy', null, 'Lenon', false)).toBe(false);
});
});
102 changes: 54 additions & 48 deletions frontend/src/views/game/board/Column.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ColumnContent } from '../types';
import useCrypto from '../../../crypto/useCrypto';
import useQuota from '../../../hooks/useQuota';
import useSessionUserPermissions from './useSessionUserPermissions';
import { useSearch } from '../is-search-match';

interface ColumnProps {
column: ColumnContent;
Expand Down Expand Up @@ -62,6 +63,7 @@ const Column: React.FC<ColumnProps> = ({
const { encrypt } = useCrypto();
const permissions = useSessionUserPermissions();
const { increment } = useQuota();
const searchPredicate = useSearch(search);
const onContentChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => setContent(e.target.value),
[setContent]
Expand Down Expand Up @@ -124,52 +126,57 @@ const Column: React.FC<ColumnProps> = ({
) : null}
</Add>
<Groups>
{groups.map((group) => (
<Group
key={group.id}
group={group}
readonly={false}
onEditLabel={(label) =>
onEditGroup({
...group,
label,
})
}
onDelete={() => onDeleteGroup(group)}
>
{group.posts.map((post, index) => (
<PostItem
index={index}
key={post.id}
post={post}
search={search}
color={color}
onLike={() => onLike(post)}
onDislike={() => onDislike(post)}
onDelete={() => onDelete(post)}
onCancelVotes={() => onCancelVotes(post)}
onEdit={(content) =>
onEdit({
...post,
content,
})
}
onEditAction={(action) =>
onEdit({
...post,
action,
})
}
onEditGiphy={(giphy) =>
onEdit({
...post,
giphy,
})
}
/>
))}
</Group>
))}
{groups.map((group) => {
const posts = group.posts.filter(searchPredicate);
if (posts.length === 0) {
return null;
}
return (
<Group
key={group.id}
group={group}
readonly={false}
onEditLabel={(label) =>
onEditGroup({
...group,
label,
})
}
onDelete={() => onDeleteGroup(group)}
>
{posts.map((post, index) => (
<PostItem
index={index}
key={post.id}
post={post}
color={color}
onLike={() => onLike(post)}
onDislike={() => onDislike(post)}
onDelete={() => onDelete(post)}
onCancelVotes={() => onCancelVotes(post)}
onEdit={(content) =>
onEdit({
...post,
content,
})
}
onEditAction={(action) =>
onEdit({
...post,
action,
})
}
onEditGiphy={(giphy) =>
onEdit({
...post,
giphy,
})
}
/>
))}
</Group>
);
})}
</Groups>
<Droppable
droppableId={'column#' + column.index}
Expand All @@ -186,12 +193,11 @@ const Column: React.FC<ColumnProps> = ({
draggingOver={dropSnapshot.isDraggingOver}
draggingColor={column.color}
>
{posts.map((post, index) => (
{posts.filter(searchPredicate).map((post, index) => (
<PostItem
index={index}
key={post.id}
post={post}
search={search}
color={color}
onLike={() => onLike(post)}
onDislike={() => onDislike(post)}
Expand Down
18 changes: 2 additions & 16 deletions frontend/src/views/game/board/post/Post.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,12 @@ import { trackEvent } from '../../../../track';
import useCrypto from '../../../../crypto/useCrypto';
import { getLorem } from './lorem';
import useCanDecrypt from '../../../../crypto/useCanDecrypt';
import isSearchMatch from '../../is-search-match';
import { useConfirm } from 'material-ui-confirm';

interface PostItemProps {
index: number;
post: Post;
color: string;
search: string;
onLike: () => void;
onDislike: () => void;
onCancelVotes: () => void;
Expand Down Expand Up @@ -72,7 +70,6 @@ const PostItem = ({
index,
post,
color,
search,
onLike,
onDislike,
onCancelVotes,
Expand Down Expand Up @@ -162,13 +159,6 @@ const PostItem = ({
return isBlurred ? generateLoremIpsum(post.content) : decrypt(post.content);
}, [decrypt, isBlurred, post.content]);

const faded = !isSearchMatch(
post.content,
canShowAuthor ? post.user.name : null,
search,
isBlurred
);

return (
<>
<Draggable
Expand All @@ -177,11 +167,7 @@ const PostItem = ({
isDragDisabled={!canReorder}
>
{(provided: DraggableProvided) => (
<PostCard
elevation={search ? (faded ? 0 : 3) : 2}
ref={provided.innerRef}
{...provided.draggableProps}
>
<PostCard ref={provided.innerRef} {...provided.draggableProps}>
{isBlurred ? (
<Tooltip title="Cards from other people will be shown when the moderator chooses to reveal them.">
<BlurOverlay />
Expand Down Expand Up @@ -248,7 +234,7 @@ const PostItem = ({
</CardContent>
)}
<ActionsBar
color={faded ? colors.grey[100] : color}
color={color}
rightActions={
<>
{giphyImageUrl && (
Expand Down
5 changes: 0 additions & 5 deletions frontend/src/views/game/board/post/__tests__/Post.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ describe('Post', () => {
onEditAction={noop}
onCancelVotes={noop}
color="#123456"
search=""
/>
);
});
Expand All @@ -92,7 +91,6 @@ describe('Post', () => {
onEditAction={noop}
onCancelVotes={noop}
color="#123456"
search=""
/>
);
const display = getByLabelText(/post content/i);
Expand All @@ -115,7 +113,6 @@ describe('Post', () => {
onEditAction={noop}
onCancelVotes={noop}
color="#123456"
search=""
/>
);
const deleteButton = queryByText(/delete/i);
Expand Down Expand Up @@ -158,7 +155,6 @@ describe('Post', () => {
onLike={noop}
onCancelVotes={noop}
color="#123456"
search=""
/>
);
const editableLabel = getByLabelText(/Post content/i);
Expand Down Expand Up @@ -193,7 +189,6 @@ describe('Post', () => {
onLike={noop}
onCancelVotes={noop}
color="#123456"
search=""
/>
);
const editableLabel = getByLabelText(/post content/i);
Expand Down
51 changes: 44 additions & 7 deletions frontend/src/views/game/is-search-match.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
export default function isSearchMatch(
import { Post } from 'common';
import { postPermissionLogic } from './board/permissions-logic';
import { useCallback } from 'react';
import useBackendCapabilities from 'global/useBackendCapabilities';
import useUser from 'state/user/useUser';
import useSession from './useSession';

type SearchPredicate = (post: Post) => boolean;

function match(value: string, search: string) {
return value.toLocaleLowerCase().includes(search.toLocaleLowerCase());
}

export function searchLogic(
content: string,
userName: string | null,
user: string | null,
search: string,
blurred: boolean
) {
Expand All @@ -10,11 +23,35 @@ export default function isSearchMatch(
if (blurred) {
return false;
}
return match(content, search) || match(user || '', search);
}

export function useSearch(search: string): SearchPredicate {
const capabilities = useBackendCapabilities();
const user = useUser();
const { session } = useSession();

return (
content.toLocaleLowerCase().includes(search.toLocaleLowerCase()) ||
(userName
? userName.toLocaleLowerCase().includes(search.toLocaleLowerCase())
: false)
const predicate = useCallback(
(post: Post) => {
if (!search) {
return true;
}
const permissions = postPermissionLogic(
post,
session,
capabilities,
user,
false
);
return searchLogic(
post.content,
post.user.name,
search,
permissions.isBlurred
);
},
[capabilities, user, session, search]
);

return predicate;
}
Loading

0 comments on commit be4ae89

Please sign in to comment.