From 195955c2f8f3de166bf4f6a3e6660d173a73ff5a Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Sat, 2 Aug 2025 13:18:15 +0200 Subject: [PATCH] Add range slider --- app/components/dropdown.tsx | 12 ++-- app/profiles/ProfileFilters.tsx | 115 ++++++++++++++++++++++---------- app/profiles/page.tsx | 11 +-- 3 files changed, 91 insertions(+), 47 deletions(-) diff --git a/app/components/dropdown.tsx b/app/components/dropdown.tsx index becae39c..a014e42e 100644 --- a/app/components/dropdown.tsx +++ b/app/components/dropdown.tsx @@ -1,15 +1,15 @@ 'use client'; -import {FilterKey} from "@/app/profiles/page"; +import {DropdownKey} from "@/app/profiles/page"; type DropdownProps = { - id: FilterKey + id: DropdownKey options?: string[] value: string - onChange: (id: FilterKey, value: string) => void - onFocus?: (id: FilterKey) => void - onKeyDown?: (id: FilterKey, key: string) => void - onClick: (id: FilterKey) => void + onChange: (id: DropdownKey, value: string) => void + onFocus?: (id: DropdownKey) => void + onKeyDown?: (id: DropdownKey, key: string) => void + onClick: (id: DropdownKey) => void } export default function Dropdown( diff --git a/app/profiles/ProfileFilters.tsx b/app/profiles/ProfileFilters.tsx index 86e3a499..1e638cb4 100644 --- a/app/profiles/ProfileFilters.tsx +++ b/app/profiles/ProfileFilters.tsx @@ -3,7 +3,8 @@ import {useEffect, useRef, useState} from 'react'; import {Gender} from "@prisma/client"; import Dropdown from "@/app/components/dropdown"; -import {FilterKey} from "@/app/profiles/page"; +import Slider from '@mui/material/Slider'; +import {DropdownKey, RangeKey} from "@/app/profiles/page"; interface FilterProps { filters: { @@ -14,22 +15,28 @@ interface FilterProps { searchQuery: string; minAge?: number | null; maxAge?: number | null; + minIntroversion?: number | null; + maxIntroversion?: number | null; }; onFilterChange: (key: string, value: any) => void; onShowFilters: (value: boolean) => void; - onToggleFilter: (key: FilterKey, value: string) => void; + onToggleFilter: (key: DropdownKey, value: string) => void; onReset: () => void; } -export const dropdownConfig: { id: FilterKey, name: string }[] = [ +export const dropdownConfig: { id: DropdownKey, name: string }[] = [ {id: "connections", name: "Desired Connections"}, {id: "interests", name: "Core Interests"}, {id: "causeAreas", name: "Cause Areas"}, ] +export const rangeConfig: { id: RangeKey, name: string, min: number, max: number }[] = [ + {id: "age", name: "Age Range", min: 15, max: 60}, +] + export function ProfileFilters({filters, onFilterChange, onShowFilters, onToggleFilter, onReset}: FilterProps) { interface Item { - id: FilterKey; + id: DropdownKey; name: string; } @@ -92,7 +99,7 @@ export function ProfileFilters({filters, onFilterChange, onShowFilters, onToggle }, []); - const toggle = (id: FilterKey, optionId: string) => { + const toggle = (id: DropdownKey, optionId: string) => { dropDownStates[id].selected.set(prev => { const newSet = new Set(prev); if (newSet.has(optionId)) { @@ -104,24 +111,24 @@ export function ProfileFilters({filters, onFilterChange, onShowFilters, onToggle }); }; - const handleKeyDown = (id: FilterKey, key: string) => { + const handleKeyDown = (id: DropdownKey, key: string) => { if (key === 'Escape') dropDownStates[id].show.set(false); }; - const handleChange = (id: FilterKey, e: string) => { + const handleChange = (id: DropdownKey, e: string) => { dropDownStates[id].new.set(e); } - const handleFocus = (id: FilterKey) => { + const handleFocus = (id: DropdownKey) => { dropDownStates[id].show.set(true); } - const handleClick = (id: FilterKey) => { + const handleClick = (id: DropdownKey) => { const shown = dropDownStates[id].show.value; dropDownStates[id].show.set(!shown); } - function getDrowDown(id: FilterKey, name: string) { + function getDrowDown(id: DropdownKey, name: string) { return (
@@ -158,7 +165,8 @@ export function ProfileFilters({filters, onFilterChange, onShowFilters, onToggle type="checkbox" className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" checked={dropDownStates[id].selected.value.has(v.id)} - onChange={() => {}} + onChange={() => { + }} onClick={(e) => e.stopPropagation()} /> @@ -203,6 +211,62 @@ export function ProfileFilters({filters, onFilterChange, onShowFilters, onToggle ) } + function getSlider(id: RangeKey, name: string, min: number, max: number) { + + return ( +
+ +
+ + { + let [_min, _max] = newValue as number[]; + onFilterChange('minAge', (_min || min) > min ? _min : undefined); + onFilterChange('maxAge', (_max || max) < max ? _max : undefined); + }} + valueLabelDisplay="auto" + min={min} + max={max} + sx={{ + color: '#3B82F6', + '& .MuiSlider-valueLabel': { + backgroundColor: '#3B82F6', + color: '#fff', + }, + }} + /> +
+
+
+ {/**/} + onFilterChange('minAge', e.target.value ? parseInt(e.target.value) : undefined)} + placeholder="Min" + /> +
+
+ {/**/} + onFilterChange('maxAge', e.target.value ? parseInt(e.target.value) : undefined)} + placeholder="Max" + /> +
+
+
+ ) + } + return (
@@ -264,7 +328,7 @@ export function ProfileFilters({filters, onFilterChange, onShowFilters, onToggle {showFilters && (
-
+
onFilterChange('minAge', e.target.value ? parseInt(e.target.value) : undefined)} - placeholder="Min" - /> -
-
- - onFilterChange('maxAge', e.target.value ? parseInt(e.target.value) : undefined)} - placeholder="Max" - /> -
- {dropdownConfig.map(({ id, name }) => getDrowDown(id, name))} + {rangeConfig.map(({id, name, min, max}) => getSlider(id, name, min, max))} + {dropdownConfig.map(({id, name}) => getDrowDown(id, name))} {/*
*/} {/* */} diff --git a/app/profiles/page.tsx b/app/profiles/page.tsx index d81408ef..516ea204 100644 --- a/app/profiles/page.tsx +++ b/app/profiles/page.tsx @@ -15,14 +15,17 @@ const initialState = { gender: '', minAge: null as number | null, maxAge: null as number | null, + minIntroversion: null as number | null, + maxIntroversion: null as number | null, interests: [] as string[], causeAreas: [] as string[], connections: [] as string[], searchQuery: '', }; -export type FilterKey = 'interests' | 'causeAreas' | 'connections'; -type FilterKeyNonArray = 'gender' | 'minAge' | 'maxAge' | 'searchQuery'; +export type DropdownKey = 'interests' | 'causeAreas' | 'connections'; +export type RangeKey = 'age'; +type OtherKey = 'gender' | 'searchQuery'; export default function ProfilePage() { const [profiles, setProfiles] = useState([]); @@ -56,7 +59,7 @@ export default function ProfilePage() { for (let i = 0; i < dropdownConfig.length; i++) { const v = dropdownConfig[i]; - const filterKey = v.id as FilterKey; + const filterKey = v.id as DropdownKey; if (filters[filterKey] && filters[filterKey].length > 0) { params.append(v.id, filters[filterKey].join(',')); } @@ -119,7 +122,7 @@ export default function ProfilePage() { setShowFilters(value); }; - const toggleFilter = (key: FilterKey, value: string) => { + const toggleFilter = (key: DropdownKey, value: string) => { setFilters(prev => ({ ...prev, [key]: prev[key].includes(value)