Skip to content

Commit

Permalink
Merge pull request #15 from jhancock532/search-groups
Browse files Browse the repository at this point in the history
Add search with fuse.js
  • Loading branch information
jhancock532 authored Dec 19, 2024
2 parents d96efa9 + 8e3ba6e commit e8ca5ed
Show file tree
Hide file tree
Showing 19 changed files with 143 additions and 48 deletions.
4 changes: 2 additions & 2 deletions data/groups/bristol-ultimate-development/details.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
},
"location": {
"address": "Shine Sports Hall, Brecon Road, Henleaze, BS9 4DT",
"latitude": "51.4847",
"longitude": "-2.6066",
"latitude": "51.486401",
"longitude": "-2.6140988",
"googleMapsLink": "https://maps.app.goo.gl/EA2VJFazA1jL9VAe9"
},
"cost": {
Expand Down
2 changes: 1 addition & 1 deletion data/groups/west-country-leders/details.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"links": [
{
"type": "Discord",
"url": "https://discord.com/invite/BUGXEyvwTc"
"url": "https://discord.gg/yP55Z56E"
}
]
}
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"dotenv": "16.4.5",
"eslint": "8.56.0",
"eslint-config-next": "14.2.3",
"fuse.js": "7.0.0",
"leaflet": "1.9.4",
"next": "14.2.13",
"prettier": "3.2.4",
Expand Down
10 changes: 8 additions & 2 deletions src/components/Footer/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@ export const Footer = () => {
<p>
This website is a non-profit, volunteer run initiative.
<br />
If you&apos;d like to leave feedback,{' '}
<Link url="/feedback" className={styles.link}>
please use this form
Leave feedback here
</Link>{' '}
or send an email to{' '}
<Link
url="mailto:[email protected]"
className={styles.link}
>
[email protected]
</Link>
.
</p>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion src/components/GroupListingMap/GroupListingMap.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
}

@include media-query(large) {
margin-bottom: $grid * 3;
margin-bottom: $grid * 4;
}
}

.toggleButton {
@include focus-outline;
@include font-size(sm);

padding: $grid;
display: flex;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 changes: 42 additions & 10 deletions src/pages/Index.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,6 @@

.hero {
margin-bottom: 0;

@include media-query(medium) {
margin-bottom: $grid * 2;
}

@include media-query(large) {
margin-bottom: $grid * 2;
}
}

.title {
Expand Down Expand Up @@ -109,7 +101,7 @@
}

.filterAccordion {
margin-bottom: $grid * 2;
margin-bottom: $grid * 1;
max-width: $max-content-width;
}

Expand All @@ -130,6 +122,7 @@

width: 290px;
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: space-between;
padding: $grid * 0.5;
Expand Down Expand Up @@ -159,7 +152,20 @@
padding: $grid 0;

@include media-query(medium) {
padding: $grid * 2 0 0 0;
padding: $grid * 2 0 $grid * 1 0;
}
}

.filterActionsContainer {
display: flex;
flex-direction: column;
gap: $grid;
margin-bottom: $grid;

@include media-query(medium) {
align-items: center;
flex-direction: row;
margin-bottom: $grid * 2;
}
}

Expand All @@ -180,3 +186,29 @@
margin-top: $grid * 4;
}
}

.searchAndFilterContainer {
display: flex;
flex-direction: column;
gap: $grid;
margin-top: $grid * 2;

@include media-query(medium) {
flex-direction: row;
}
}

.searchInput {
@include focus-outline;
@include font-size(sm);

width: 290px;
padding: $grid * 0.5;
border: 1px solid var(--color--black);
border-radius: 4px;

@include media-query(medium) {
width: 100%;
max-width: 40ch;
}
}
87 changes: 63 additions & 24 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useState, useMemo } from 'react';
import fs from 'fs';
import Fuse from 'fuse.js';
import { join } from 'path';
import GroupListingFeed from '@/components/GroupListingFeed';
import GroupListingMap from '@/components/GroupListingMap';
Expand All @@ -23,11 +24,11 @@ const generateListOfGroupTags = (events: any) => {
}, {});
};

export default function Home({ groups }: any) {
export default function Home({ groups }: { groups: Group[] }) {
const [selectedGroupTags, setSelectedGroupTags] = useState<string[]>([]);
const [selectedWeekday, setSelectedWeekday] = useState<string>('All');
const [filterIsOpen, setFilterIsOpen] = useState(false);

const [searchQuery, setSearchQuery] = useState<string>('');
const groupTags = useMemo(() => generateListOfGroupTags(groups), [groups]);

const handleGroupFilterClicked = (tag: string) => {
Expand All @@ -43,15 +44,43 @@ export default function Home({ groups }: any) {
const clearAllFilters = () => {
setSelectedGroupTags([]);
setSelectedWeekday('All');
setSearchQuery('');
};

const toggleFilter = () => {
setFilterIsOpen(!filterIsOpen);
};

const handleSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchQuery(event.target.value);
};

const searchOptions = {
includeScore: true,
minMatchCharLength: 3,
useAnd: false,
threshold: 0.2,
matchAllTokens: false,
tokenize: true,
keys: ['name', 'description', 'tags', 'details'],
};

const fuse = new Fuse(groups, searchOptions);

const filteredGroups = useMemo(() => {
if (searchQuery.length > 2) {
const searchResults = fuse.search(searchQuery);
const searchResultGroups = searchResults.map(
(result: any) => result.item,
);
return filterGroups(
searchResultGroups,
selectedGroupTags,
selectedWeekday,
);
}
return filterGroups(groups, selectedGroupTags, selectedWeekday);
}, [groups, selectedGroupTags, selectedWeekday]);
}, [groups, selectedGroupTags, selectedWeekday, searchQuery]);

const filteredGroupsContainRegularLocation =
filteredGroups.regularGroups.some((group: Group) => {
Expand All @@ -73,7 +102,14 @@ export default function Home({ groups }: any) {
A collection of local groups that meet up regularly and are
open to newcomers.
</p>
<div className={styles.filterAccordion}>
<div className={styles.searchAndFilterContainer}>
<input
className={styles.searchInput}
type="text"
placeholder="Search"
onChange={handleSearch}
value={searchQuery}
/>
<button
className={styles.filterAccordionToggle}
onClick={toggleFilter}
Expand All @@ -84,6 +120,8 @@ export default function Home({ groups }: any) {
pointDownwards={!filterIsOpen}
/>
</button>
</div>
<div className={styles.filterAccordion}>
{filterIsOpen && (
<div className={styles.filterContent}>
<div className={styles.groupFilterOptionsContainer}>
Expand Down Expand Up @@ -167,29 +205,30 @@ export default function Home({ groups }: any) {
))}
</div>
</div>

<FilteredGroupsShownMessage
filteredGroups={filteredGroups}
numberOfPossibleGroups={groups.length}
/>

{(selectedGroupTags.length !== 0 ||
selectedWeekday !== 'All') && (
<button
className={
styles.clearSelectedTagsButton
}
onClick={clearAllFilters}
>
Clear all filters
</button>
)}
</div>
</div>
)}
</div>
</div>

<div className={styles.filterActionsContainer}>
<FilteredGroupsShownMessage
filteredGroups={filteredGroups}
numberOfPossibleGroups={groups.length}
/>

{(selectedGroupTags.length !== 0 ||
selectedWeekday !== 'All' ||
searchQuery !== '') && (
<button
className={styles.clearSelectedTagsButton}
onClick={clearAllFilters}
>
Clear all filters
</button>
)}
</div>

{filteredGroupsContainRegularLocation && (
<GroupListingMap
groups={filteredGroups.regularGroups}
Expand All @@ -209,9 +248,9 @@ export default function Home({ groups }: any) {
<h2>Ad-hoc groups</h2>
<p className={styles.description}>
These groups may host an event on the day
you&apos;ve specified. Please check the groups
website, social media page or group chat for
more information.{' '}
you&apos;ve specified, on an ad-hoc basis.
Please check the groups website, social media
page or group chat for more information.{' '}
</p>
</div>
<GroupListingFeed
Expand Down
17 changes: 9 additions & 8 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ export const filterGroups = (
selectedGroupTags: string[],
selectedWeekday: string,
) => {
const regularGroups = groups.filter((event: any) => {
const regularGroups = groups.filter((group: Group) => {
// Find the groups that have a matching tag
let matchingTagFound = event.tags?.some((tag: string) =>
let matchingTagFound = group.tags?.some((tag: string) =>
selectedGroupTags.includes(tag),
);

Expand All @@ -63,15 +63,16 @@ export const filterGroups = (
// If no weekday is selected, all groups will be shown
if (selectedWeekday === 'All') {
matchingWeekdaySelected = true;
} else if (event.events) {
} else if (group.events) {
// If the group has event information,
// check if it has an event on the selected weekday
matchingWeekdaySelected = event.events.some(
matchingWeekdaySelected = group.events.some(
(e: any) => e.time.weekday === selectedWeekday,
);
}

const adHocGroup = event.type === 'Discord' || event.type === 'Ad-hoc';
// If a group doesn't have any regular events, assume it is ad-hoc
const adHocGroup = group.events === undefined;

if (adHocGroup) {
return false;
Expand All @@ -80,16 +81,16 @@ export const filterGroups = (
return matchingTagFound && matchingWeekdaySelected;
});

const adHocGroups = groups.filter((event: any) => {
const adHocGroups = groups.filter((group: Group) => {
// Find the groups that have a matching tag
let matchingTagFound = event.tags?.some((tag: string) =>
let matchingTagFound = group.tags?.some((tag: string) =>
selectedGroupTags.includes(tag),
);

// If no tags are filtered by, all ad-hoc groups will be shown
if (selectedGroupTags.length === 0) matchingTagFound = true;

const adHocGroup = event.type === 'Discord' || event.type === 'Ad-hoc';
const adHocGroup = group.events === undefined;

return matchingTagFound && adHocGroup;
});
Expand Down

0 comments on commit e8ca5ed

Please sign in to comment.