mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-03-25 01:51:37 -04:00
Improve wants kids and has kids filters
This commit is contained in:
@@ -340,7 +340,8 @@
|
||||
"filter.label.pref_age_min": "Âge min",
|
||||
"filter.label.pref_gender": "Genre recherché",
|
||||
"filter.label.pref_relation_styles": "Recherche",
|
||||
"filter.label.wants_kids_strength": "Enfants",
|
||||
"filter.label.wants_kids_strength": "Désir d'enfants",
|
||||
"filter.label.has_kids": "Enfants",
|
||||
"filter.location": "Habite",
|
||||
"filter.location.any": "n'importe où",
|
||||
"filter.location.search_city": "Rechercher une ville...",
|
||||
@@ -360,9 +361,9 @@
|
||||
"filter.last_active.3months": "3 derniers mois",
|
||||
"filter.reset": "Réinitialiser",
|
||||
"filter.short_bio_toggle": "Inclure les profils incomplets",
|
||||
"filter.wants_kids.any_preference": "Toutes préférences",
|
||||
"filter.wants_kids.any_preference": "N'importe",
|
||||
"filter.wants_kids.doesnt_want_kids": "Ne veut pas d'enfants",
|
||||
"filter.wants_kids.either": "Tout désir d'enfants",
|
||||
"filter.wants_kids.either": "N'importe",
|
||||
"filter.wants_kids.wants_kids": "Veut des enfants",
|
||||
"font.atkinson": "Atkinson Hyperlegible",
|
||||
"font.classic-serif": "Serif classique",
|
||||
@@ -679,12 +680,12 @@
|
||||
"profile.gender.plural.male": "Hommes",
|
||||
"profile.gender.plural.other": "Autres",
|
||||
"profile.has_kids": "A des enfants",
|
||||
"profile.has_kids.-1": "Tout enfant",
|
||||
"profile.has_kids.-1": "N'importe",
|
||||
"profile.has_kids.0": "N'a pas d'enfants",
|
||||
"profile.has_kids.1": "A des enfants",
|
||||
"profile.has_kids.doesnt_have_kids": "N'a pas d'enfants",
|
||||
"profile.has_kids.has_kids": "A des enfants",
|
||||
"profile.has_kids.no_preference": "Tout enfant",
|
||||
"profile.has_kids.no_preference": "N'importe",
|
||||
"profile.has_kids_many": "A {count} enfants",
|
||||
"profile.has_kids_one": "A {count} enfant",
|
||||
"profile.header.age": "{age} ans",
|
||||
|
||||
@@ -10,7 +10,7 @@ export interface HasKidsLabelsMap {
|
||||
|
||||
export const hasKidsLabels: HasKidsLabelsMap = {
|
||||
no_preference: {
|
||||
name: 'Any kids',
|
||||
name: 'Either way',
|
||||
shortName: 'Either',
|
||||
value: -1,
|
||||
},
|
||||
|
||||
@@ -31,3 +31,8 @@ export function groupConsecutive<T, U>(xs: T[], key: (x: T) => U) {
|
||||
result.push(curr)
|
||||
return result
|
||||
}
|
||||
|
||||
export function nullifyEmpty<T>(array: T[]) {
|
||||
if (!Array.isArray(array)) return null
|
||||
return array.length > 0 ? array : null
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export type KidsLabelsMap = Record<string, KidLabel>
|
||||
|
||||
export const wantsKidsLabels: KidsLabelsMap = {
|
||||
no_preference: {
|
||||
name: 'Any preference',
|
||||
name: 'Either',
|
||||
shortName: 'Either',
|
||||
strength: -1,
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@ import {buildArray} from 'common/util/array'
|
||||
import {keyBy, partition, sortBy} from 'lodash'
|
||||
import {useEffect, useState} from 'react'
|
||||
import toast from 'react-hot-toast'
|
||||
import DropdownMenu from 'web/components/comments/dropdown-menu'
|
||||
import DropdownMenu, {DropdownButton} from 'web/components/comments/dropdown-menu'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {Modal, MODAL_CLASS, SCROLLABLE_MODAL_CLASS} from 'web/components/layout/modal'
|
||||
import {Row} from 'web/components/layout/row'
|
||||
@@ -32,7 +32,6 @@ import {useUser} from 'web/hooks/use-user'
|
||||
import {useT} from 'web/lib/locale'
|
||||
import {db} from 'web/lib/supabase/db'
|
||||
|
||||
import {DropdownButton} from '../filters/desktop-filters'
|
||||
import {Subtitle} from '../widgets/profile-subtitle'
|
||||
import {AddCompatibilityQuestionButton} from './add-compatibility-question-button'
|
||||
import {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import {Popover, Transition} from '@headlessui/react'
|
||||
import {DotsHorizontalIcon} from '@heroicons/react/solid'
|
||||
import {ChevronDownIcon, ChevronUpIcon, DotsHorizontalIcon} from '@heroicons/react/solid'
|
||||
import clsx from 'clsx'
|
||||
import {toKey} from 'common/parsing'
|
||||
import {Fragment, ReactNode, useState} from 'react'
|
||||
import {usePopper} from 'react-popper'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {Row} from 'web/components/layout/row'
|
||||
import {useT} from 'web/lib/locale'
|
||||
|
||||
export type DropdownItem = {
|
||||
@@ -165,3 +166,15 @@ export function DropdownOptions(props: {
|
||||
</Col>
|
||||
)
|
||||
}
|
||||
|
||||
export function DropdownButton(props: {open: boolean; content: ReactNode}) {
|
||||
const {open, content} = props
|
||||
return (
|
||||
<Row className="hover:text-ink-700 items-center gap-0.5 transition-all">
|
||||
{content}
|
||||
<span className="text-ink-400">
|
||||
{open ? <ChevronUpIcon className="h-4 w-4" /> : <ChevronDownIcon className="h-4 w-4" />}
|
||||
</span>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -51,12 +51,14 @@ function countActiveFilters(
|
||||
locationFilterProps: LocationFilterProps,
|
||||
raisedInLocationFilterProps: LocationFilterProps,
|
||||
) {
|
||||
let count = Object.keys(removeNullOrUndefinedProps({...filters, orderBy: undefined})).length
|
||||
let parsedFilters = Object.keys(removeNullOrUndefinedProps({...filters, orderBy: undefined}))
|
||||
parsedFilters = parsedFilters.filter((key) => !key.startsWith('big5_'))
|
||||
let count = parsedFilters.length
|
||||
if (locationFilterProps.location) count = count - 2
|
||||
if (raisedInLocationFilterProps.location) count = count - 2
|
||||
if (filters.pref_age_min && filters.pref_age_max) count--
|
||||
const big5Count = countBig5Filters(filters)
|
||||
if (big5Count > 1) count = count - (big5Count - 1)
|
||||
if (big5Count > 0) count++
|
||||
return count
|
||||
}
|
||||
|
||||
@@ -344,26 +346,6 @@ function Filters(props: {
|
||||
<RomanticFilter filters={filters} updateFilter={updateFilter} />
|
||||
</FilterSection>
|
||||
|
||||
{/* Wants Kids */}
|
||||
<FilterSection
|
||||
title={t('filter.wants_kids.wants_kids', 'Wants kids')}
|
||||
openFilter={openFilter}
|
||||
setOpenFilter={setOpenFilter}
|
||||
isActive={filters.wants_kids_strength != null && filters.wants_kids_strength !== -1}
|
||||
selection={
|
||||
<KidsLabel
|
||||
strength={filters.wants_kids_strength ?? -1}
|
||||
highlightedClass={
|
||||
filters.wants_kids_strength != null && filters.wants_kids_strength !== -1
|
||||
? 'text-primary-600'
|
||||
: 'text-ink-900'
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<WantsKidsFilter filters={filters} updateFilter={updateFilter} />
|
||||
</FilterSection>
|
||||
|
||||
{/* Has Kids */}
|
||||
<FilterSection
|
||||
title={t('profile.optional.has_kids', 'Has kids')}
|
||||
@@ -383,6 +365,26 @@ function Filters(props: {
|
||||
>
|
||||
<HasKidsFilter filters={filters} updateFilter={updateFilter} />
|
||||
</FilterSection>
|
||||
|
||||
{/* Wants Kids */}
|
||||
<FilterSection
|
||||
title={t('filter.wants_kids.wants_kids', 'Wants kids')}
|
||||
openFilter={openFilter}
|
||||
setOpenFilter={setOpenFilter}
|
||||
isActive={filters.wants_kids_strength != null && filters.wants_kids_strength !== -1}
|
||||
selection={
|
||||
<KidsLabel
|
||||
strength={filters.wants_kids_strength ?? -1}
|
||||
highlightedClass={
|
||||
filters.wants_kids_strength != null && filters.wants_kids_strength !== -1
|
||||
? 'text-primary-600'
|
||||
: 'text-ink-900'
|
||||
}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<WantsKidsFilter filters={filters} updateFilter={updateFilter} />
|
||||
</FilterSection>
|
||||
</FilterGroup>
|
||||
)}
|
||||
|
||||
@@ -726,7 +728,7 @@ export function FilterSection(props: {
|
||||
<Col className={clsx(className)}>
|
||||
<button
|
||||
className={clsx(
|
||||
'text-ink-600 flex w-full flex-row justify-between px-4 pt-4 relative',
|
||||
'text-ink-600 flex w-full flex-row justify-between px-4 pt-4 relative hover-bold',
|
||||
isOpen ? 'pb-2' : 'pb-4',
|
||||
)}
|
||||
onClick={() => (isOpen ? setOpenFilter(undefined) : setOpenFilter(title))}
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
import clsx from 'clsx'
|
||||
import {FilterFields} from 'common/filters'
|
||||
import {generateChoicesMap, hasKidsLabels} from 'common/has-kids'
|
||||
import {FaChild} from 'react-icons/fa6'
|
||||
import {invert} from 'lodash'
|
||||
import {DropdownOptions} from 'web/components/comments/dropdown-menu'
|
||||
import {Row} from 'web/components/layout/row'
|
||||
import {ChoicesToggleGroup} from 'web/components/widgets/choices-toggle-group'
|
||||
import {useT} from 'web/lib/locale'
|
||||
|
||||
const DEFAULT_KEY = -1
|
||||
|
||||
export function HasKidsLabel(props: {
|
||||
has_kids: number
|
||||
highlightedClass?: string
|
||||
mobile?: boolean
|
||||
}) {
|
||||
const {has_kids, highlightedClass} = props
|
||||
const {highlightedClass} = props
|
||||
const t = useT()
|
||||
|
||||
const has_kids = Number(props.has_kids)
|
||||
|
||||
// Get the appropriate label based on has_kids value
|
||||
let labelKey = 'no_preference'
|
||||
let labelValue = hasKidsLabels.no_preference.name
|
||||
@@ -27,8 +31,9 @@ export function HasKidsLabel(props: {
|
||||
}
|
||||
return (
|
||||
<Row className="items-center gap-0.5">
|
||||
<FaChild className="h-4 w-4" />
|
||||
<span className={clsx(highlightedClass, has_kids !== -1 && 'font-semibold')}>
|
||||
{/*<FaChild className="h-4 w-4" />*/}
|
||||
<span className={clsx(highlightedClass, has_kids !== DEFAULT_KEY && 'font-semibold')}>
|
||||
{has_kids === DEFAULT_KEY && t('filter.label.has_kids', 'Kids') + ': '}
|
||||
{t(`profile.has_kids.${labelKey}`, labelValue)}
|
||||
</span>
|
||||
</Row>
|
||||
@@ -41,12 +46,13 @@ export function HasKidsFilter(props: {
|
||||
}) {
|
||||
const {filters, updateFilter} = props
|
||||
return (
|
||||
<ChoicesToggleGroup
|
||||
currentChoice={filters.has_kids ?? 0}
|
||||
choicesMap={generateChoicesMap(hasKidsLabels)}
|
||||
<DropdownOptions
|
||||
items={invert(generateChoicesMap(hasKidsLabels))}
|
||||
activeKey={String(filters.has_kids ?? DEFAULT_KEY)}
|
||||
translationPrefix="profile.has_kids"
|
||||
setChoice={(c) => updateFilter({has_kids: Number(c) >= 0 ? Number(c) : undefined})}
|
||||
toggleClassName="w-1/3 justify-center"
|
||||
onClick={(key) => {
|
||||
updateFilter({has_kids: Number(key) === DEFAULT_KEY ? undefined : key})
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import clsx from 'clsx'
|
||||
import {RELATIONSHIP_CHOICES} from 'common/choices'
|
||||
import {FilterFields} from 'common/filters'
|
||||
import {nullifyEmpty} from 'common/util/array'
|
||||
import {MultiCheckbox} from 'web/components/multi-checkbox'
|
||||
import {useT} from 'web/lib/locale'
|
||||
import {convertRelationshipType, RelationshipType} from 'web/lib/util/convert-types'
|
||||
@@ -59,7 +60,7 @@ export function RelationshipFilter(props: {
|
||||
choices={RELATIONSHIP_CHOICES as any}
|
||||
translationPrefix={'profile.relationship'}
|
||||
onChange={(c) => {
|
||||
updateFilter({pref_relation_styles: c})
|
||||
updateFilter({pref_relation_styles: nullifyEmpty(c)})
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import clsx from 'clsx'
|
||||
import {FilterFields} from 'common/filters'
|
||||
import {generateChoicesMap, KidLabel, wantsKidsLabels} from 'common/wants-kids'
|
||||
import {invert} from 'lodash'
|
||||
import {ReactNode} from 'react'
|
||||
import {MdNoStroller, MdOutlineStroller, MdStroller} from 'react-icons/md'
|
||||
import {DropdownOptions} from 'web/components/comments/dropdown-menu'
|
||||
import {Row} from 'web/components/layout/row'
|
||||
import {ChoicesToggleGroup} from 'web/components/widgets/choices-toggle-group'
|
||||
import {useT} from 'web/lib/locale'
|
||||
|
||||
interface KidLabelWithIcon extends KidLabel {
|
||||
@@ -15,12 +16,14 @@ interface KidsLabelsMapWithIcon {
|
||||
[key: string]: KidLabelWithIcon
|
||||
}
|
||||
|
||||
const DEFAULT_KEY = -1
|
||||
|
||||
export const useWantsKidsLabelsWithIcon = () => {
|
||||
const t = useT()
|
||||
return {
|
||||
no_preference: {
|
||||
...wantsKidsLabels.no_preference,
|
||||
name: t('filter.wants_kids.any_preference', 'Any preference'),
|
||||
name: t('filter.wants_kids.any_preference', 'Either'),
|
||||
shortName: t('filter.wants_kids.either', 'Either'),
|
||||
icon: <MdOutlineStroller className="h-4 w-4" />,
|
||||
},
|
||||
@@ -55,18 +58,22 @@ export function WantsKidsIcon(props: {strength: number; className?: string}) {
|
||||
}
|
||||
|
||||
export function KidsLabel(props: {strength: number; highlightedClass?: string; mobile?: boolean}) {
|
||||
const {strength, highlightedClass} = props
|
||||
const {highlightedClass} = props
|
||||
const wantsKidsLabelsWithIcon = useWantsKidsLabelsWithIcon()
|
||||
const t = useT()
|
||||
|
||||
const strength = props.strength ? Number(props.strength) : DEFAULT_KEY
|
||||
|
||||
return (
|
||||
<Row className="items-center gap-0.5">
|
||||
<WantsKidsIcon strength={strength} className={clsx('')} />
|
||||
{/*<WantsKidsIcon strength={strength} className={clsx('')} />*/}
|
||||
<span
|
||||
className={clsx(
|
||||
strength != wantsKidsLabelsWithIcon.no_preference.strength && 'font-semibold',
|
||||
highlightedClass,
|
||||
)}
|
||||
>
|
||||
{strength === DEFAULT_KEY && t('filter.label.wants_kids_strength', 'Wants Kids') + ': '}
|
||||
{strength == wantsKidsLabelsWithIcon.no_preference.strength
|
||||
? wantsKidsLabelsWithIcon.no_preference.name
|
||||
: strength == wantsKidsLabelsWithIcon.wants_kids.strength
|
||||
@@ -85,11 +92,13 @@ export function WantsKidsFilter(props: {
|
||||
const wantsKidsLabelsWithIcon = useWantsKidsLabelsWithIcon()
|
||||
|
||||
return (
|
||||
<ChoicesToggleGroup
|
||||
currentChoice={filters.wants_kids_strength ?? 0}
|
||||
choicesMap={generateChoicesMap(wantsKidsLabelsWithIcon)}
|
||||
setChoice={(c) => updateFilter({wants_kids_strength: Number(c) >= 0 ? Number(c) : undefined})}
|
||||
toggleClassName="w-1/3 justify-center"
|
||||
<DropdownOptions
|
||||
items={invert(generateChoicesMap(wantsKidsLabelsWithIcon))}
|
||||
activeKey={String(filters.wants_kids_strength ?? DEFAULT_KEY)}
|
||||
translationPrefix="profile.wants_kids"
|
||||
onClick={(key) => {
|
||||
updateFilter({wants_kids_strength: Number(key) === DEFAULT_KEY ? undefined : key})
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import clsx from 'clsx'
|
||||
import {toKey} from 'common/parsing'
|
||||
import {nullifyEmpty} from 'common/util/array'
|
||||
import {useEffect, useMemo, useState} from 'react'
|
||||
import {Button} from 'web/components/buttons/button'
|
||||
import {Row} from 'web/components/layout/row'
|
||||
@@ -12,7 +13,7 @@ export const MultiCheckbox = (props: {
|
||||
choices: {[key: string]: string}
|
||||
// Selected values (should match the "value" side of choices)
|
||||
selected: string[]
|
||||
onChange: (selected: string[]) => void
|
||||
onChange: (selected: string[] | null) => void
|
||||
className?: string
|
||||
optionsClassName?: string
|
||||
// If provided, enables adding a new option and should persist it (e.g. to DB)
|
||||
@@ -146,7 +147,7 @@ export const MultiCheckbox = (props: {
|
||||
if (checked) {
|
||||
onChange([...selected, value])
|
||||
} else {
|
||||
onChange(selected.filter((s) => s !== value))
|
||||
onChange(nullifyEmpty(selected.filter((s) => s !== value)))
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user