Skip to content

Commit

Permalink
Add sorting/filtering features
Browse files Browse the repository at this point in the history
  • Loading branch information
AhmedHHamdy committed Oct 31, 2023
1 parent 0840e41 commit dfbfbfa
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 9 deletions.
61 changes: 58 additions & 3 deletions client/app/home/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,30 +11,85 @@ import { fetchClients } from '@utils/client'
const Home = () => {
const auth = useAuthContext()
const [clients, setClients] = useState(null)
const [filteringOptions, setFilteringOptions] = useState([]); // Add state for filtering options

useEffect(() => {
fetchClients().then(data => setClients(data))
fetchClients().then(data => {
setClients(data)
setFilteringOptions(data); // Initialize filteringOptions with the fetched data
})
}, [auth?.user])

if (!auth?.checkAuth) return <Spinner />
if (auth?.isAuthenticated === "unauthenticated") return redirect('/')

function sortClients(sortingFunction) {
// Clone the clients array and sort it using the provided sorting function.
const sortedClients = [...clients].sort(sortingFunction);
setClients(sortedClients); // We set the clients state variable with sorted array
};

function filterClients(data) {
setClients(data) // We set the clients state variable with the filtered array coming from action menu component
}

function clearFilter() {
setClients(filteringOptions); // We reset the clients state variable with the original data from the server
};

return (
<>
<div className="px-8 pb-4">
<ActionMenu />
<ActionMenu
sortClients={sortClients}
filterClients={filterClients}
filteringOptions={filteringOptions}
clearFilter={clearFilter}
/>
</div>

<div className="flex flex-wrap gap-x-[2%] gap-y-4 justify-center">
{clients === null && <Spinner />}
{clients && clients.length > 0
&& clients.map((client, index) => {
return <ClientCard client={client} key={index} />
})
}

{clients && clients.length === 0 && <p>You have not added any clients!</p>}
</div>
</>
)
}

export default Home
export default Home


// <section className="flex">
// <ArrowsUpDownIcon className="action-icon" title="Sort By" />
// <FunnelIcon className="action-icon" title="Filter By" />
// <ListBulletIcon className="action-icon" title="List View" />
// </section>

{/* <div className="">
<div className="dropdown dropdown-end text-secondary">
<ul tabIndex="0" className="mt-3 z-[1] p-2 shadow menu menu-sm dropdown-content bg-primary border border-secondary rounded-box w-52">
<li><Link href=''>Home</Link></li>
<li>
<Link href={'/profile'} className="justify-between">
Profile
<span className="badge">New</span>
</Link>
</li>
<li><Link href="/client/add">+ Client</Link></li>
<li><Link href="/outreach/add">+ Outreach</Link></li>
<li><Link href={'/settings'}>Settings</Link></li>
<li><span className="pointer" onClick={logOut}>Logout</span></li>
<li><div className="form-control flex flex-row gap-1 mr-2">
<ThemeToggle />
</div></li>
</ul>
</div>
</div>
</div>
*/}
2 changes: 1 addition & 1 deletion client/components/client/ClientCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import { EllipsisHorizontalIcon, PhoneIcon, EnvelopeIcon, MapPinIcon } from '@heroicons/react/24/outline'
const ClientCard = ({ client }) => {
return (
<section className="client-card">
<section className="client-card mb-8">
<div>
<div className="flex justify-between">
<h3 className="">{client.businessName}</h3>
Expand Down
92 changes: 87 additions & 5 deletions client/components/ui/ActionMenu.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,94 @@
import Link from 'next/link'
import { FunnelIcon, ArrowsUpDownIcon, ListBulletIcon } from '@heroicons/react/20/solid'
import { FunnelIcon, ArrowsUpDownIcon, ListBulletIcon, ArrowRightIcon } from '@heroicons/react/20/solid'
import { useState } from 'react';

const ActionMenu = ({ sortClients, filterClients, clearFilter, filteringOptions }) => {
const [currentSort, setCurrentSort] = useState('');
const [currentFilter, setCurrentFilter] = useState([]);

function handleSortAZ() {
sortClients((a, b) => a['businessType'].localeCompare(b['businessType'], "en", { sensitivity: 'base' })); // We provide the function that is used for sorting from A to Z, case-insensitive comparison
setCurrentSort('Sorted AZ')
};

function handleSortZA() {
sortClients((a, b) => b['businessType'].localeCompare(a['businessType'], "en", { sensitivity: 'base' })); // We provide the function that is used for sorting from Z to A, case-insensitive comparison
setCurrentSort('Sorted ZA')
}


function handleFiltering(event) {
const filteringValue = event.target.value || event.target.innerHTML // We get filtering value ['clinic'] for example when you click on the checkbox input and if you're clicking on the current filter badge you get the filtering value from it to through event target inner html
const updateFilters = [...currentFilter]

if (updateFilters.includes(filteringValue)) { // We check the if the updatedFilter array if it has any filtering values
updateFilters.splice(updateFilters.indexOf(filteringValue), 1) // if it has any filtering values, it deletes it
} else {
updateFilters.push(filteringValue) // if it hasn't, we push the filtering value to the updatedFilters
}

let filteredData = filteringOptions.filter((option) =>
updateFilters.includes(option.businessType) // We get an array of filteredData based on the filtering values
);


if (filteredData.length == 0) { // if the filteredData is empty array we reassign the filteredData with filteringOptions (Original Data from the server)
filteredData = filteringOptions // this necessary because when we clear all filters the array we need ti reset to the original data
}

filterClients(filteredData) // we call the filterClients function from the home page with filteredData
setCurrentFilter(updateFilters) // We set the currentFilter array with updatedFilters
}

function removeFilter () {
setCurrentFilter([]) // We set the currentFilter state variable to an empty array
clearFilter() // We call the clearFilter function from the home page to reset the clients state variable to the original data from the server
}

const filterOptionElements = filteringOptions?.map((option, i) => {
return (
<label key={i} className='label '>
<span className="label-text">{option.businessType}</span>
<input
type='checkbox'
value={option.businessType}
checked={currentFilter.includes(option.businessType)}
onChange={handleFiltering}
className='checkbox'
/>
</label>
)

})


const ActionMenu = () => {
return (
<section className="flex">
<ArrowsUpDownIcon className="action-icon" title="Sort By" />
<FunnelIcon className="action-icon" title="Filter By" />
<section className="flex pl-8">
{/* <ArrowsUpDownIcon onClick={clickHandle} className="action-icon" title="Sort By" /> */}
<div className="dropdown dropdown-bottom text-secondary">
<label tabIndex={0} className=""><ArrowsUpDownIcon className="action-icon" title="Sort By" /></label>
<ul tabIndex={0} className="mt-3 z-[1] p-2 shadow menu menu-sm dropdown-content bg-primary border border-secondary rounded-box w-16 ">
<li className='cursor-pointer btn-ghost text-sm text-center' onClick={handleSortAZ}>A Z</li>
<li className='cursor-pointer btn-ghost text-sm text-center' onClick={handleSortZA}>Z A</li>
</ul>
</div>
{/* <FunnelIcon className="action-icon" title="Filter By" /> */}
<div className="dropdown dropdown-bottom text-secondary">
<label tabIndex={0} className=""><FunnelIcon className="action-icon" title="Filter By" /></label>
<ul tabIndex={0} className="mt-3 z-[1] p-2 shadow menu menu-sm dropdown-content bg-primary border border-secondary rounded-box w-52 ">
{filterOptionElements}
</ul>
</div>
<ListBulletIcon className="action-icon" title="List View" />
{currentSort && <div className="badge badge-primary self-center flex justify-center items-center leading-none mx-1">{currentSort}</div>

} {currentFilter &&
<section className='flex justify-center items-center'>
{currentFilter.map((filter, i) =>
(<div key={i} className="badge badge-primary self-center flex justify-center items-center leading-none cursor-pointer mx-1" onClick={handleFiltering}>{filter}</div>))
}
{currentFilter.length > 0 && <div className='border-b-2 text-sm cursor-pointer ml-1' onClick={removeFilter}>Clear</div>}
</section>}
</section>
)
}
Expand Down

0 comments on commit dfbfbfa

Please sign in to comment.