Skip to content

Commit

Permalink
feat: implement filter functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
zerinoid committed Jul 6, 2023
1 parent cea2918 commit 5c71eba
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 46 deletions.
28 changes: 1 addition & 27 deletions src/components/sections/filter/Filter.module.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.nav {
.container {
display: flex;
position: fixed;
width: 250px;
Expand All @@ -15,32 +15,6 @@
}
}

.nav>a {
margin: 8px 0;
text-decoration: none;
background: white;
border-radius: 4px;
font-size: 14px;
padding: 12px 16px;
text-transform: uppercase;
font-weight: 600;
letter-spacing: 0.025em;
color: #333;
border: 1px solid #eaeaea;
transition: all 0.125s ease;
}

.nav>a:hover {
background-color: #eaeaea;
}

.input {
margin: 32px 0;
text-decoration: none;
background: white;
border-radius: 4px;
border: 1px solid #eaeaea;
font-size: 14px;
padding: 8px 16px;
height: 28px;
}
48 changes: 40 additions & 8 deletions src/components/sections/filter/Filter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,60 @@ import Link from 'next/link';
import styles from './Filter.module.css';
import { SetStateAction, Dispatch } from 'react';
import SearchBox from '@/components/inputs/search-box/SearchBox';
import CheckboxToggle from '@/components/inputs/checkbox-toggle/CheckboxToggle';

export interface IFilter {
isOpen: boolean;
setIsOpen?: Dispatch<SetStateAction<boolean>>;
searchText: string;
handleSearchTextChange: (text: string) => void;
handleCheckboxChange: (
filterName: string,
value: string,
checked: boolean
) => void;
filters: Record<string, Set<string | number>>;
}

const Filter: React.FC<IFilter> = ({
isOpen,
setIsOpen,
searchText,
handleSearchTextChange
handleSearchTextChange,
handleCheckboxChange,
filters
}) => {
return (
<nav className={styles.nav} style={{ left: isOpen ? '0' : '-100%' }}>
<SearchBox value={searchText} onChange={handleSearchTextChange} />
<input className={styles.input} placeholder="Search..." />
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/contact">Contact</Link>
</nav>
<div className={styles.container} style={{ left: isOpen ? '0' : '-100%' }}>
<div className={styles.input}>
<SearchBox value={searchText} onChange={handleSearchTextChange} />
</div>

<CheckboxToggle
value="planning"
label="Planning"
checked={filters.status.has('planning')}
onChange={checked =>
handleCheckboxChange('status', 'planning', checked)
}
/>

<CheckboxToggle
value="inprogress"
label="In Progress"
checked={filters.status.has('inprogress')}
onChange={checked =>
handleCheckboxChange('status', 'inprogress', checked)
}
/>

<CheckboxToggle
value="done"
label="Done"
checked={filters.status.has('done')}
onChange={checked => handleCheckboxChange('status', 'done', checked)}
/>
</div>
);
};

Expand Down
12 changes: 6 additions & 6 deletions src/components/sections/gallery/Gallery.data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const projects: IProject[] = [
responsible: 'Sophia Davis',
manager: 'Ethan Thompson',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
status: 'running',
status: 'inprogress',
year: 2020,
rating: 2,
area: 'Painting',
Expand Down Expand Up @@ -67,7 +67,7 @@ const projects: IProject[] = [
responsible: 'James Martinez',
manager: 'Sofia Lewis',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
status: 'running',
status: 'inprogress',
year: 2022,
rating: 3,
area: 'Architecture',
Expand Down Expand Up @@ -103,7 +103,7 @@ const projects: IProject[] = [
responsible: 'Amelia Baker',
manager: 'Liam Lee',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
status: 'running',
status: 'inprogress',
year: 2019,
rating: 3,
area: 'Poetry',
Expand Down Expand Up @@ -139,7 +139,7 @@ const projects: IProject[] = [
responsible: 'Logan Cook',
manager: 'Abigail Reed',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
status: 'running',
status: 'inprogress',
year: 2023,
rating: 4,
area: 'Music',
Expand Down Expand Up @@ -175,7 +175,7 @@ const projects: IProject[] = [
responsible: 'Nora Evans',
manager: 'William Campbell',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
status: 'running',
status: 'inprogress',
year: 2019,
rating: 2,
area: 'Poetry',
Expand Down Expand Up @@ -211,7 +211,7 @@ const projects: IProject[] = [
responsible: 'Mia Collins',
manager: 'Jacob Scott',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
status: 'running',
status: 'inprogress',
year: 2021,
rating: 4,
area: 'Architecture',
Expand Down
9 changes: 5 additions & 4 deletions src/components/sections/gallery/Gallery.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import Image, { ImageLoaderProps } from 'next/image';
import { galleryData } from './Gallery.data';
import styles from './Gallery.module.css';

export type statuses = 'done' | 'planning' | 'running';
export type statuses = 'done' | 'planning' | 'inprogress';
type areas = 'Architecture' | 'Music' | 'Painting' | 'Poetry' | 'Cinema';
type programs = 'Endorsement' | 'Internship' | 'Scholarship' | 'Integration';

Expand All @@ -19,9 +18,11 @@ export interface IProject {
program: programs;
}

const Gallery: React.FC = () => {
const projects = galleryData.projects;
export interface IGallery {
projects: IProject[];
}

const Gallery: React.FC<IGallery> = ({ projects }) => {
const imageLoader = ({ src, width }: ImageLoaderProps) => {
return `https://via.placeholder.com/${width}x${width / 1.777}?text=${src}`;
};
Expand Down
70 changes: 69 additions & 1 deletion src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,90 @@ import Filter from '../components/sections/filter/Filter';
import { useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faXmark, faBars } from '@fortawesome/free-solid-svg-icons';
import { galleryData } from '@/components/sections/gallery/Gallery.data';

const Home: NextPageWithLayout = () => {
const [filters, setFilters] = useState<Record<string, Set<string | number>>>({
status: new Set(),
approvalYear: new Set(),
enterprise: new Set(),
areas: new Set(),
programs: new Set()
});
const [isFilterOpen, setIsFilterOpen] = useState<boolean>(false);
const [searchText, setSearchText] = useState<string>('');
const icon = isFilterOpen ? faXmark : faBars;
const projects = galleryData.projects;

const handleSearchTextChange = (text: string) => {
setSearchText(text);
};

const handleCheckboxChange = (
filterName: string,
value: string | number,
checked: boolean
) => {
setFilters(prevFilters => {
const newSet = new Set(prevFilters[filterName]);
if (checked) {
newSet.add(value);
} else {
newSet.delete(value);
}
return {
...prevFilters,
[filterName]: newSet
};
});
};

const filteredItems = projects.filter(project => {
// Filter by category values
if (filters.status.size > 0 && !filters.status.has(project.status)) {
return false;
}
if (
filters.approvalYear.size > 0 &&
!filters.approvalYear.has(project.year)
) {
return false;
}
if (
filters.enterprise.size > 0 &&
!filters.enterprise.has(project.rating)
) {
return false;
}
if (filters.areas.size > 0 && !filters.areas.has(project.area)) {
return false;
}
if (filters.programs.size > 0 && !filters.programs.has(project.program)) {
return false;
}
// Filter by search text
if (searchText.length > 0) {
const searchRegex = new RegExp(searchText, 'i');
if (
!searchRegex.test(project.title) &&
!searchRegex.test(project.responsible) &&
!searchRegex.test(project.manager) &&
!searchRegex.test(project.description)
) {
return false;
}
}
return true;
});

return (
<>
<Filter
isOpen={isFilterOpen}
searchText={searchText}
handleSearchTextChange={handleSearchTextChange}
handleCheckboxChange={handleCheckboxChange}
filters={filters}
/>
<section className={styles.main}>
<button
Expand All @@ -31,7 +99,7 @@ const Home: NextPageWithLayout = () => {
<FontAwesomeIcon icon={icon} size="xl" />
</button>
<h1 className={styles.title}>Search and Filter</h1>
<Gallery />
<Gallery projects={filteredItems} />
</section>
</>
);
Expand Down

0 comments on commit 5c71eba

Please sign in to comment.