mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-02-24 02:46:11 -05:00
Refactor measurement system imports and enhance filter formatting
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import {MeasurementSystem} from 'web/hooks/use-measurement-system'
|
||||
|
||||
// Conversion factors
|
||||
const INCHES_TO_CM = 2.54
|
||||
const MILES_TO_KM = 1.60934
|
||||
|
||||
export type MeasurementSystem = 'metric' | 'imperial'
|
||||
|
||||
/**
|
||||
* Format height in inches according to the specified measurement system
|
||||
*/
|
||||
@@ -1,33 +1,34 @@
|
||||
// Define nice labels for each key
|
||||
import {FilterFields, initialFilters} from "common/filters";
|
||||
import {wantsKidsNames} from "common/wants-kids";
|
||||
import {hasKidsNames} from "common/has-kids";
|
||||
import {FilterFields, initialFilters} from 'common/filters'
|
||||
import {wantsKidsNames} from 'common/wants-kids'
|
||||
import {hasKidsNames} from 'common/has-kids'
|
||||
import {milesToKm} from "common/measurement-utils";
|
||||
|
||||
const filterLabels: Record<string, string> = {
|
||||
geodbCityIds: "",
|
||||
location: "",
|
||||
name: "Searching",
|
||||
genders: "",
|
||||
education_levels: "Education",
|
||||
pref_age_max: "Max age",
|
||||
pref_age_min: "Min age",
|
||||
drinks_max: "Max drinks",
|
||||
drinks_min: "Min drinks",
|
||||
relationship_status: "",
|
||||
has_kids: "",
|
||||
wants_kids_strength: "Kids",
|
||||
is_smoker: "",
|
||||
pref_relation_styles: "Seeking",
|
||||
interests: "",
|
||||
causes: "",
|
||||
work: "",
|
||||
religion: "",
|
||||
pref_gender: "",
|
||||
orderBy: "",
|
||||
diet: "Diet",
|
||||
political_beliefs: "Political views",
|
||||
languages: "",
|
||||
mbti: "MBTI",
|
||||
geodbCityIds: '',
|
||||
location: '',
|
||||
name: 'Searching',
|
||||
genders: '',
|
||||
education_levels: 'Education',
|
||||
pref_age_max: 'Max age',
|
||||
pref_age_min: 'Min age',
|
||||
drinks_max: 'Max drinks',
|
||||
drinks_min: 'Min drinks',
|
||||
relationship_status: '',
|
||||
has_kids: '',
|
||||
wants_kids_strength: 'Kids',
|
||||
is_smoker: '',
|
||||
pref_relation_styles: 'Seeking',
|
||||
interests: '',
|
||||
causes: '',
|
||||
work: '',
|
||||
religion: '',
|
||||
pref_gender: '',
|
||||
orderBy: '',
|
||||
diet: 'Diet',
|
||||
political_beliefs: 'Political views',
|
||||
languages: '',
|
||||
mbti: 'MBTI',
|
||||
}
|
||||
|
||||
export type locationType = {
|
||||
@@ -49,18 +50,18 @@ const skippedKeys = [
|
||||
'radius',
|
||||
]
|
||||
|
||||
|
||||
export function formatFilters(
|
||||
filters: Partial<FilterFields>,
|
||||
location: locationType | null,
|
||||
choicesIdsToLabels: Record<string, any>
|
||||
choicesIdsToLabels: Record<string, any>,
|
||||
measurementSystem?: 'metric' | 'imperial'
|
||||
): String[] | null {
|
||||
const entries: String[] = []
|
||||
|
||||
let ageEntry = null
|
||||
let ageMin: number | undefined | null = filters.pref_age_min
|
||||
if (ageMin == 18) ageMin = undefined
|
||||
let ageMax = filters.pref_age_max;
|
||||
let ageMax = filters.pref_age_max
|
||||
if (ageMax == 100) ageMax = undefined
|
||||
if (ageMin || ageMax) {
|
||||
let text: string = 'Age: '
|
||||
@@ -89,7 +90,8 @@ export function formatFilters(
|
||||
|
||||
let stringValue = value
|
||||
if (key === 'has_kids') stringValue = hasKidsNames[value as number]
|
||||
if (key === 'wants_kids_strength') stringValue = wantsKidsNames[value as number]
|
||||
if (key === 'wants_kids_strength')
|
||||
stringValue = wantsKidsNames[value as number]
|
||||
if (Array.isArray(value)) {
|
||||
if (choicesIdsToLabels[key]) {
|
||||
value = value.map((id) => choicesIdsToLabels[key][id])
|
||||
@@ -110,11 +112,18 @@ export function formatFilters(
|
||||
if (ageEntry) entries.push(ageEntry)
|
||||
|
||||
if (location?.location?.name) {
|
||||
const locString = `${location?.location?.name} (${location?.radius}mi)`
|
||||
const radius = location?.radius || 0
|
||||
let formattedRadius: string
|
||||
if (measurementSystem === 'metric') {
|
||||
formattedRadius = `${Math.round(milesToKm(radius))} km`
|
||||
} else {
|
||||
formattedRadius = `${Math.round(radius)}mi`
|
||||
}
|
||||
const locString = `${location?.location?.name} (${formattedRadius})`
|
||||
entries.push(locString)
|
||||
}
|
||||
|
||||
if (entries.length === 0) return ['Anyone']
|
||||
|
||||
return entries
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {uniqBy} from 'lodash'
|
||||
import {buildArray} from 'common/util/array'
|
||||
import {OriginLocation} from 'common/filters'
|
||||
import {useMeasurementSystem} from 'web/hooks/use-measurement-system'
|
||||
import {formatDistance, kmToMiles, milesToKm} from 'web/lib/measurement-utils'
|
||||
import {formatDistance, kmToMiles, milesToKm} from 'common/measurement-utils'
|
||||
|
||||
export function LocationFilterText(props: {
|
||||
location: OriginLocation | undefined | null
|
||||
|
||||
@@ -28,8 +28,7 @@ import {UserHandles} from 'web/components/user/user-handles'
|
||||
import {Profile} from 'common/profiles/profile'
|
||||
import {UserActivity} from 'common/user'
|
||||
import {ClockIcon} from '@heroicons/react/solid'
|
||||
import {MeasurementSystem} from 'web/hooks/use-measurement-system'
|
||||
import {formatHeight} from 'web/lib/measurement-utils'
|
||||
import {formatHeight, MeasurementSystem} from 'common/measurement-utils'
|
||||
import {MAX_INT, MIN_INT} from 'common/constants'
|
||||
import {GiFruitBowl} from 'react-icons/gi'
|
||||
import {FaBriefcase, FaHandsHelping, FaHeart, FaStar} from 'react-icons/fa'
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
import {User} from "common/user";
|
||||
import {Button} from "web/components/buttons/button";
|
||||
import {Modal, MODAL_CLASS, SCROLLABLE_MODAL_CLASS} from "web/components/layout/modal";
|
||||
import {Col} from "web/components/layout/col";
|
||||
import {BookmarkedSearchesType} from "web/hooks/use-bookmarked-searches";
|
||||
import {useUser} from "web/hooks/use-user";
|
||||
import {deleteBookmarkedSearch} from "web/lib/supabase/searches";
|
||||
import {formatFilters, locationType} from "common/searches";
|
||||
import {FilterFields} from "common/filters";
|
||||
import {api} from "web/lib/api";
|
||||
import {XIcon} from "@heroicons/react/outline";
|
||||
import {DisplayUser} from "common/api/user-types";
|
||||
import {useState} from "react";
|
||||
import {useT} from "web/lib/locale";
|
||||
import toast from "react-hot-toast";
|
||||
import Link from "next/link";
|
||||
import {useAllChoices} from "web/hooks/use-choices";
|
||||
import clsx from "clsx";
|
||||
import {Row} from "web/components/layout/row";
|
||||
import {Avatar} from "web/components/widgets/avatar";
|
||||
import {User} from 'common/user'
|
||||
import {Button} from 'web/components/buttons/button'
|
||||
import {Modal, MODAL_CLASS, SCROLLABLE_MODAL_CLASS,} from 'web/components/layout/modal'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {BookmarkedSearchesType} from 'web/hooks/use-bookmarked-searches'
|
||||
import {useUser} from 'web/hooks/use-user'
|
||||
import {deleteBookmarkedSearch} from 'web/lib/supabase/searches'
|
||||
import {formatFilters, locationType} from 'common/searches'
|
||||
import {FilterFields} from 'common/filters'
|
||||
import {api} from 'web/lib/api'
|
||||
import {XIcon} from '@heroicons/react/outline'
|
||||
import {DisplayUser} from 'common/api/user-types'
|
||||
import {useState} from 'react'
|
||||
import {useT} from 'web/lib/locale'
|
||||
import toast from 'react-hot-toast'
|
||||
import Link from 'next/link'
|
||||
import {useAllChoices} from 'web/hooks/use-choices'
|
||||
import clsx from 'clsx'
|
||||
import {Row} from 'web/components/layout/row'
|
||||
import {Avatar} from 'web/components/widgets/avatar'
|
||||
import {useMeasurementSystem} from 'web/hooks/use-measurement-system'
|
||||
|
||||
export function BookmarkSearchButton(props: {
|
||||
bookmarkedSearches: BookmarkedSearchesType[]
|
||||
@@ -25,12 +26,7 @@ export function BookmarkSearchButton(props: {
|
||||
open: boolean
|
||||
setOpen: (checked: boolean) => void
|
||||
}) {
|
||||
const {
|
||||
bookmarkedSearches,
|
||||
refreshBookmarkedSearches,
|
||||
open,
|
||||
setOpen,
|
||||
} = props
|
||||
const {bookmarkedSearches, refreshBookmarkedSearches, open, setOpen} = props
|
||||
const user = useUser()
|
||||
|
||||
const t = useT()
|
||||
@@ -51,9 +47,7 @@ export function BookmarkSearchButton(props: {
|
||||
)
|
||||
}
|
||||
|
||||
export function ResetFiltersButton(props: {
|
||||
clearFilters: () => void
|
||||
}) {
|
||||
export function ResetFiltersButton(props: { clearFilters: () => void }) {
|
||||
const {clearFilters} = props
|
||||
const t = useT()
|
||||
return (
|
||||
@@ -65,7 +59,6 @@ export function ResetFiltersButton(props: {
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function ButtonModal(props: {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
@@ -76,6 +69,7 @@ function ButtonModal(props: {
|
||||
const {open, setOpen, bookmarkedSearches, refreshBookmarkedSearches} = props
|
||||
const t = useT()
|
||||
const choicesIdsToLabels = useAllChoices()
|
||||
const {measurementSystem} = useMeasurementSystem()
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
@@ -86,35 +80,53 @@ function ButtonModal(props: {
|
||||
>
|
||||
<Col className={MODAL_CLASS}>
|
||||
<h3>{t('saved_searches.title', 'Saved Searches')}</h3>
|
||||
{bookmarkedSearches?.length ? (<>
|
||||
<p>{t('saved_searches.notification_note', "We'll notify you daily when new people match your searches below.")}</p>
|
||||
<Col
|
||||
className={
|
||||
'border-ink-300bg-canvas-0 inline-flex flex-col gap-2 rounded-md border p-1 shadow-sm'
|
||||
}
|
||||
>
|
||||
<ol className="list-decimal list-inside space-y-2">
|
||||
{(bookmarkedSearches || []).map((search) => (
|
||||
<li key={search.id}
|
||||
className="items-center justify-between gap-2 list-item marker:text-ink-500 marker:font-bold">
|
||||
{formatFilters(search.search_filters as Partial<FilterFields>, search.location as locationType, choicesIdsToLabels)?.join(" • ")}
|
||||
<button
|
||||
onClick={async () => {
|
||||
await deleteBookmarkedSearch(search.id)
|
||||
refreshBookmarkedSearches()
|
||||
}}
|
||||
className="inline-flex text-xl h-5 w-5 items-center justify-center rounded-full text-red-600 hover:bg-red-200 focus:outline-none focus:ring-2 focus:ring-red-400"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
|
||||
</Col>
|
||||
</>
|
||||
) :
|
||||
<p>{t('saved_searches.empty_state', "You haven't saved any search. To save one, click on Get Notified and we'll notify you daily when new people match it.")}</p>}
|
||||
{bookmarkedSearches?.length ? (
|
||||
<>
|
||||
<p>
|
||||
{t(
|
||||
'saved_searches.notification_note',
|
||||
"We'll notify you daily when new people match your searches below."
|
||||
)}
|
||||
</p>
|
||||
<Col
|
||||
className={
|
||||
'border-ink-300bg-canvas-0 inline-flex flex-col gap-2 rounded-md border p-1 shadow-sm'
|
||||
}
|
||||
>
|
||||
<ol className="list-decimal list-inside space-y-2">
|
||||
{(bookmarkedSearches || []).map((search) => (
|
||||
<li
|
||||
key={search.id}
|
||||
className="items-center justify-between gap-2 list-item marker:text-ink-500 marker:font-bold"
|
||||
>
|
||||
{formatFilters(
|
||||
search.search_filters as Partial<FilterFields>,
|
||||
search.location as locationType,
|
||||
choicesIdsToLabels,
|
||||
measurementSystem
|
||||
)?.join(' • ')}
|
||||
<button
|
||||
onClick={async () => {
|
||||
await deleteBookmarkedSearch(search.id)
|
||||
refreshBookmarkedSearches()
|
||||
}}
|
||||
className="inline-flex text-xl h-5 w-5 items-center justify-center rounded-full text-red-600 hover:bg-red-200 focus:outline-none focus:ring-2 focus:ring-red-400"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</Col>
|
||||
</>
|
||||
) : (
|
||||
<p>
|
||||
{t(
|
||||
'saved_searches.empty_state',
|
||||
"You haven't saved any search. To save one, click on Get Notified and we'll notify you daily when new people match it."
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
{/*<BookmarkSearchContent*/}
|
||||
{/* total={bookmarkedSearches.length}*/}
|
||||
{/* compatibilityQuestion={bookmarkedSearches[questionIndex]}*/}
|
||||
@@ -142,12 +154,7 @@ export function BookmarkStarButton(props: {
|
||||
open: boolean
|
||||
setOpen: (checked: boolean) => void
|
||||
}) {
|
||||
const {
|
||||
starredUsers,
|
||||
refreshStars,
|
||||
open,
|
||||
setOpen,
|
||||
} = props
|
||||
const {starredUsers, refreshStars, open, setOpen} = props
|
||||
const user = useUser()
|
||||
|
||||
const t = useT()
|
||||
@@ -168,7 +175,6 @@ export function BookmarkStarButton(props: {
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
function StarModal(props: {
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
@@ -181,7 +187,9 @@ function StarModal(props: {
|
||||
const [removingIds, setRemovingIds] = useState<Set<string>>(new Set())
|
||||
|
||||
const t = useT()
|
||||
const visibleUsers = (starredUsers || []).filter((u) => !removingIds.has(u.id))
|
||||
const visibleUsers = (starredUsers || []).filter(
|
||||
(u) => !removingIds.has(u.id)
|
||||
)
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -193,20 +201,37 @@ function StarModal(props: {
|
||||
>
|
||||
<Col className={MODAL_CLASS}>
|
||||
<h3>{t('saved_people.title', 'Saved People')}</h3>
|
||||
{visibleUsers?.length ? (<>
|
||||
<p>{t('saved_people.list_header', 'Here are the people you saved:')}</p>
|
||||
<Col className={clsx("divide-y divide-canvas-300 w-full pr-4", SCROLLABLE_MODAL_CLASS)}>
|
||||
{visibleUsers?.length ? (
|
||||
<>
|
||||
<p>
|
||||
{t('saved_people.list_header', 'Here are the people you saved:')}
|
||||
</p>
|
||||
<Col
|
||||
className={clsx(
|
||||
'divide-y divide-canvas-300 w-full pr-4',
|
||||
SCROLLABLE_MODAL_CLASS
|
||||
)}
|
||||
>
|
||||
{visibleUsers.map((u) => (
|
||||
<Row key={u.id} className="items-center justify-between py-2 gap-2">
|
||||
<Row
|
||||
key={u.id}
|
||||
className="items-center justify-between py-2 gap-2"
|
||||
>
|
||||
<Link
|
||||
className="w-full rounded-md hover:bg-canvas-100 p-2"
|
||||
href={'/' + u.username}
|
||||
>
|
||||
<Row className="items-center gap-3">
|
||||
<Avatar size="md" username={u.username} avatarUrl={u.avatarUrl ?? undefined}/>
|
||||
<Avatar
|
||||
size="md"
|
||||
username={u.username}
|
||||
avatarUrl={u.avatarUrl ?? undefined}
|
||||
/>
|
||||
<Col>
|
||||
<div className="font-medium">{u.name}</div>
|
||||
<div className="text-ink-500 text-sm">@{u.username}</div>
|
||||
<div className="text-ink-500 text-sm">
|
||||
@{u.username}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Link>
|
||||
@@ -224,7 +249,9 @@ function StarModal(props: {
|
||||
refreshStars()
|
||||
})
|
||||
.catch(() => {
|
||||
toast.error("Couldn't remove saved profile. Please try again.")
|
||||
toast.error(
|
||||
"Couldn't remove saved profile. Please try again."
|
||||
)
|
||||
// Revert optimistic removal on failure
|
||||
setRemovingIds((prev) => {
|
||||
const next = new Set(prev)
|
||||
@@ -241,7 +268,12 @@ function StarModal(props: {
|
||||
))}
|
||||
</Col>
|
||||
</>
|
||||
) : <p>You haven't saved any profile. To save one, click on the star on their profile page.</p>}
|
||||
) : (
|
||||
<p>
|
||||
You haven't saved any profile. To save one, click on the star on
|
||||
their profile page.
|
||||
</p>
|
||||
)}
|
||||
{/*<BookmarkSearchContent*/}
|
||||
{/* total={bookmarkedSearches.length}*/}
|
||||
{/* compatibilityQuestion={bookmarkedSearches[questionIndex]}*/}
|
||||
@@ -261,4 +293,4 @@ function StarModal(props: {
|
||||
</Col>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {usePersistentLocalState} from 'web/hooks/use-persistent-local-state'
|
||||
import {getLocale} from "web/lib/locale-cookie";
|
||||
|
||||
export type MeasurementSystem = 'metric' | 'imperial'
|
||||
import {MeasurementSystem} from "common/measurement-utils";
|
||||
|
||||
export const useMeasurementSystem = () => {
|
||||
// Get default based on locale
|
||||
|
||||
Reference in New Issue
Block a user