Skip to content

Commit 26f28d5

Browse files
committed
Add filters for drinks
1 parent cb66688 commit 26f28d5

File tree

10 files changed

+209
-12
lines changed

10 files changed

+209
-12
lines changed

backend/api/src/get-profiles.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ export type profileQueryType = {
1616
pref_gender?: String[] | undefined,
1717
pref_age_min?: number | undefined,
1818
pref_age_max?: number | undefined,
19+
drinks_min?: number | undefined,
20+
drinks_max?: number | undefined,
1921
pref_relation_styles?: String[] | undefined,
2022
pref_romantic_styles?: String[] | undefined,
2123
diet?: String[] | undefined,
@@ -49,6 +51,8 @@ export const loadProfiles = async (props: profileQueryType) => {
4951
pref_gender,
5052
pref_age_min,
5153
pref_age_max,
54+
drinks_min,
55+
drinks_max,
5256
pref_relation_styles,
5357
pref_romantic_styles,
5458
diet,
@@ -88,6 +92,8 @@ export const loadProfiles = async (props: profileQueryType) => {
8892
(!pref_gender || intersection(pref_gender, l.pref_gender).length) &&
8993
(!pref_age_min || (l.age ?? MAX_INT) >= pref_age_min) &&
9094
(!pref_age_max || (l.age ?? MIN_INT) <= pref_age_max) &&
95+
(!drinks_min || (l.drinks_per_month ?? MAX_INT) >= drinks_min) &&
96+
(!drinks_max || (l.drinks_per_month ?? MIN_INT) <= drinks_max) &&
9197
(!pref_relation_styles ||
9298
intersection(pref_relation_styles, l.pref_relation_styles).length) &&
9399
(!pref_romantic_styles ||
@@ -163,6 +169,12 @@ export const loadProfiles = async (props: profileQueryType) => {
163169
pref_age_max &&
164170
where(`age <= $(pref_age_max) or age is null`, {pref_age_max}),
165171

172+
drinks_min &&
173+
where(`drinks_per_month >= $(drinks_min) or drinks_per_month is null`, {drinks_min}),
174+
175+
drinks_max &&
176+
where(`drinks_per_month <= $(drinks_max) or drinks_per_month is null`, {drinks_max}),
177+
166178
pref_relation_styles?.length &&
167179
where(
168180
`pref_relation_styles IS NULL OR pref_relation_styles = '{}' OR pref_relation_styles && $(pref_relation_styles)`,

common/src/api/schema.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,8 @@ export const API = (_apiTypeCheck = {
349349
pref_gender: arraybeSchema.optional(),
350350
pref_age_min: z.coerce.number().optional(),
351351
pref_age_max: z.coerce.number().optional(),
352+
drinks_min: z.coerce.number().optional(),
353+
drinks_max: z.coerce.number().optional(),
352354
pref_relation_styles: arraybeSchema.optional(),
353355
pref_romantic_styles: arraybeSchema.optional(),
354356
diet: arraybeSchema.optional(),

common/src/api/zod-types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ const optionalProfilesSchema = z.object({
9292
twitter: z.string().optional(),
9393
avatar_url: z.string().optional(),
9494
pref_romantic_styles: z.array(z.string()),
95+
drinks_min: z.number().min(0).optional(),
96+
drinks_max: z.number().min(0).optional(),
9597
})
9698

9799
export const combinedProfileSchema =

common/src/filters.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ export type FilterFields = {
1818
education_levels: string[]
1919
name: string | undefined
2020
shortBio: boolean | undefined
21+
drinks_min: number | undefined
22+
drinks_max: number | undefined
2123
} & Pick<
2224
ProfileRow,
2325
| 'wants_kids_strength'
@@ -70,6 +72,8 @@ export const initialFilters: Partial<FilterFields> = {
7072
political_beliefs: undefined,
7173
pref_gender: undefined,
7274
shortBio: undefined,
75+
drinks_min: undefined,
76+
drinks_max: undefined,
7377
orderBy: 'created_time',
7478
}
7579

common/src/searches.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const filterLabels: Record<string, string> = {
1111
education_levels: "Education",
1212
pref_age_max: "Max age",
1313
pref_age_min: "Min age",
14+
drinks_max: "Max drinks",
15+
drinks_min: "Min drinks",
1416
has_kids: "",
1517
wants_kids_strength: "Kids",
1618
is_smoker: "",

web/components/filters/desktop-filters.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import {GiFruitBowl} from "react-icons/gi";
2727
import {RiScales3Line} from "react-icons/ri";
2828
import {EducationFilter, EducationFilterText} from "web/components/filters/education-filter";
2929
import {LuGraduationCap} from "react-icons/lu";
30+
import {DrinksFilter, DrinksFilterText} from "web/components/filters/drinks-filter";
31+
import {MdLocalBar} from 'react-icons/md'
3032

3133
export function DesktopFilters(props: {
3234
filters: Partial<FilterFields>
@@ -324,6 +326,32 @@ export function DesktopFilters(props: {
324326
menuWidth="w-50"
325327
/>
326328

329+
{/* DRINKS PER MONTH */}
330+
<CustomizeableDropdown
331+
buttonContent={(open) => (
332+
<DropdownButton
333+
open={open}
334+
content={
335+
<Row className="items-center gap-1">
336+
<MdLocalBar className="h-4 w-4"/>
337+
<DrinksFilterText
338+
drinks_min={filters.drinks_min}
339+
drinks_max={filters.drinks_max}
340+
highlightedClass={open ? 'text-primary-500' : undefined}
341+
/>
342+
</Row>
343+
}
344+
/>
345+
)}
346+
dropdownMenuContent={
347+
<Col className="mx-2 mb-4">
348+
<DrinksFilter filters={filters} updateFilter={updateFilter}/>
349+
</Col>
350+
}
351+
popoverClassName="bg-canvas-50"
352+
menuWidth="w-80"
353+
/>
354+
327355
{/* POLITICS */}
328356
<CustomizeableDropdown
329357
buttonContent={(open) => (
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import clsx from 'clsx'
2+
import {RangeSlider} from 'web/components/widgets/slider'
3+
import {FilterFields} from 'common/filters'
4+
5+
export const DRINKS_MIN = 0
6+
export const DRINKS_MAX = 30
7+
8+
export function getNoMinMaxDrinks(
9+
drinks_min: number | null | undefined,
10+
drinks_max: number | null | undefined
11+
) {
12+
const noMin = drinks_min == null || drinks_min <= DRINKS_MIN
13+
const noMax = drinks_max == null || drinks_max >= DRINKS_MAX
14+
// console.log('drinks min max', drinks_min, drinks_max)
15+
return [noMin, noMax]
16+
}
17+
18+
export function DrinksFilterText(props: {
19+
drinks_min: number | null | undefined
20+
drinks_max: number | null | undefined
21+
highlightedClass?: string
22+
}) {
23+
const {drinks_min, drinks_max, highlightedClass} = props
24+
const [noMin, noMax] = getNoMinMaxDrinks(drinks_min, drinks_max)
25+
26+
27+
if (drinks_max === DRINKS_MIN) {
28+
return (
29+
<span className="font-semibold">
30+
<span className={clsx(highlightedClass)}>{drinks_max}</span> / mo
31+
</span>
32+
)
33+
}
34+
35+
if (noMin && noMax) {
36+
return (
37+
<span>
38+
<span className={clsx('text-semibold', highlightedClass)}>Any</span>{' '}
39+
<span className="hidden sm:inline">drinks</span>
40+
</span>
41+
)
42+
}
43+
if (noMin) {
44+
return (
45+
<span className="font-semibold">
46+
<span className={clsx(highlightedClass)}>
47+
{' < '}
48+
{drinks_max}
49+
</span>{' '}
50+
/ mo
51+
</span>
52+
)
53+
}
54+
if (noMax) {
55+
return (
56+
<span className="font-semibold">
57+
<span className={clsx(highlightedClass)}>
58+
{' > '}
59+
{drinks_min}
60+
</span>{' '}
61+
/ mo
62+
</span>
63+
)
64+
}
65+
if (drinks_min === drinks_max) {
66+
return (
67+
<span className="font-semibold">
68+
<span className={clsx(highlightedClass)}>{drinks_min}</span> / mo
69+
</span>
70+
)
71+
}
72+
return (
73+
<span className="font-semibold">
74+
<span className={clsx(highlightedClass)}>
75+
{drinks_min}
76+
{' - '}
77+
{drinks_max}
78+
</span>{' '}
79+
/mo
80+
</span>
81+
)
82+
}
83+
84+
export function DrinksFilter(props: {
85+
filters: Partial<FilterFields>
86+
updateFilter: (newState: Partial<FilterFields>) => void
87+
}) {
88+
const {filters, updateFilter} = props
89+
return (
90+
<RangeSlider
91+
lowValue={filters.drinks_min ?? DRINKS_MIN}
92+
highValue={filters.drinks_max ?? DRINKS_MAX}
93+
setValues={(low: number, high: number) => {
94+
console.log('setValues', low, high)
95+
updateFilter({
96+
drinks_min: Number(low),
97+
drinks_max: Number(high),
98+
})
99+
}}
100+
min={DRINKS_MIN}
101+
max={DRINKS_MAX}
102+
marks={[
103+
{ value: 0, label: `${DRINKS_MIN}` },
104+
{
105+
value: ((5 - DRINKS_MIN) / (DRINKS_MAX - DRINKS_MIN)) * 100,
106+
label: `5`,
107+
},
108+
{
109+
value: ((10 - DRINKS_MIN) / (DRINKS_MAX - DRINKS_MIN)) * 100,
110+
label: `10`,
111+
},
112+
{
113+
value: ((20 - DRINKS_MIN) / (DRINKS_MAX - DRINKS_MIN)) * 100,
114+
label: `20`,
115+
},
116+
{ value: 100, label: `${DRINKS_MAX}+` },
117+
]}
118+
/>
119+
)
120+
}

web/components/filters/mobile-filters.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {RomanticFilter, RomanticFilterText} from "web/components/filters/romanti
2222
import {DietFilter, DietFilterText} from "web/components/filters/diet-filter";
2323
import {PoliticalFilter, PoliticalFilterText} from "web/components/filters/political-filter";
2424
import {EducationFilter, EducationFilterText} from "web/components/filters/education-filter";
25+
import {DrinksFilter, DrinksFilterText, getNoMinMaxDrinks} from "./drinks-filter";
2526

2627
function MobileFilters(props: {
2728
filters: Partial<FilterFields>
@@ -259,6 +260,23 @@ function MobileFilters(props: {
259260
<DietFilter filters={filters} updateFilter={updateFilter}/>
260261
</MobileFilterSection>
261262

263+
{/* DRINKS PER MONTH */}
264+
<MobileFilterSection
265+
title="Drinks"
266+
openFilter={openFilter}
267+
setOpenFilter={setOpenFilter}
268+
isActive={(() => { const [noMin, noMax] = getNoMinMaxDrinks(filters.drinks_min, filters.drinks_max); return !noMin || !noMax })()}
269+
selection={
270+
<DrinksFilterText
271+
drinks_min={filters.drinks_min}
272+
drinks_max={filters.drinks_max}
273+
highlightedClass={(() => { const [noMin, noMax] = getNoMinMaxDrinks(filters.drinks_min, filters.drinks_max); return (noMin && noMax) ? 'text-ink-900' : 'text-primary-600' })()}
274+
/>
275+
}
276+
>
277+
<DrinksFilter filters={filters} updateFilter={updateFilter} />
278+
</MobileFilterSection>
279+
262280
{/* POLITICS */}
263281
<MobileFilterSection
264282
title="Politics"

web/components/filters/use-filters.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import {debounce, isEqual} from "lodash";
66
import {wantsKidsDatabase, wantsKidsDatabaseToWantsKidsFilter, wantsKidsToHasKidsFilter} from "common/wants-kids";
77
import {FilterFields, initialFilters, OriginLocation} from "common/filters";
88
import {MAX_INT, MIN_INT} from "common/constants";
9+
import {DRINKS_MAX, DRINKS_MIN} from "web/components/filters/drinks-filter";
10+
import {PREF_AGE_MAX, PREF_AGE_MIN} from "web/components/filters/age-filter";
911

1012
export const useFilters = (you: Profile | undefined) => {
1113
const isLooking = useIsLooking()
@@ -19,17 +21,11 @@ export const useFilters = (you: Profile | undefined) => {
1921
const updateFilter = (newState: Partial<FilterFields>) => {
2022
const updatedState = {...newState}
2123

22-
if ('pref_age_min' in updatedState && updatedState.pref_age_min !== undefined) {
23-
if (updatedState.pref_age_min != null && updatedState.pref_age_min <= 18) {
24-
updatedState.pref_age_min = undefined
25-
}
26-
}
24+
if ((updatedState?.pref_age_min ?? MAX_INT) <= PREF_AGE_MIN) updatedState.pref_age_min = undefined
25+
if ((updatedState?.pref_age_max ?? MIN_INT) >= PREF_AGE_MAX) updatedState.pref_age_max = undefined
2726

28-
if ('pref_age_max' in updatedState && updatedState.pref_age_max !== undefined) {
29-
if (updatedState.pref_age_max != null && updatedState.pref_age_max >= 100) {
30-
updatedState.pref_age_max = undefined
31-
}
32-
}
27+
if ((updatedState?.drinks_min ?? DRINKS_MIN) <= DRINKS_MIN) updatedState.drinks_min = undefined
28+
if ((updatedState?.drinks_max ?? DRINKS_MIN) >= DRINKS_MAX) updatedState.drinks_max = undefined
3329

3430
// console.log('updating filters', updatedState)
3531

web/components/widgets/slider.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import clsx from 'clsx'
22
import * as RxSlider from '@radix-ui/react-slider'
3-
import {ReactNode, useState} from 'react'
3+
import {ReactNode, useEffect, useState} from 'react'
44

55
const colors = {
66
green: ['bg-teal-400', 'focus:outline-teal-600/30 bg-teal-600'],
@@ -111,6 +111,20 @@ export function RangeSlider(props: {
111111
const [trackClasses, thumbClasses] = colors[color]
112112
const [dragValues, setDragValues] = useState<[number, number]>([lowValue, highValue])
113113

114+
// keep local drag state in sync with external values
115+
useEffect(() => {
116+
setDragValues([lowValue, highValue])
117+
}, [lowValue, highValue])
118+
119+
// debounce parent updates while dragging to avoid excessive re-renders/queries
120+
useEffect(() => {
121+
const [low, high] = dragValues
122+
const t = setTimeout(() => {
123+
setValues(low, high)
124+
}, 200)
125+
return () => clearTimeout(t)
126+
}, [dragValues])
127+
114128
return (
115129
<RxSlider.Root
116130
className={clsx(
@@ -120,7 +134,6 @@ export function RangeSlider(props: {
120134
value={dragValues}
121135
step={step ?? 1}
122136
onValueChange={(vals: number[]) => setDragValues([vals[0], vals[1]])} // update continuously for UI feedback
123-
onValueCommit={([low, high]) => setValues(low, high)} // update only on release
124137
min={min}
125138
max={max}
126139
disabled={disabled}

0 commit comments

Comments
 (0)