From cf843f66c41a64187250a4f468ca47fe14d4c99c Mon Sep 17 00:00:00 2001 From: MartinBraquet Date: Thu, 19 Feb 2026 01:30:59 +0100 Subject: [PATCH] Refactor measurement system imports and enhance filter formatting --- {web/lib => common/src}/measurement-utils.ts | 4 +- common/src/searches.ts | 75 ++++---- web/components/filters/location-filter.tsx | 2 +- web/components/profile-about.tsx | 3 +- web/components/searches/button.tsx | 184 +++++++++++-------- web/hooks/use-measurement-system.ts | 3 +- 6 files changed, 155 insertions(+), 116 deletions(-) rename {web/lib => common/src}/measurement-utils.ts (95%) diff --git a/web/lib/measurement-utils.ts b/common/src/measurement-utils.ts similarity index 95% rename from web/lib/measurement-utils.ts rename to common/src/measurement-utils.ts index a1429033..0d56934e 100644 --- a/web/lib/measurement-utils.ts +++ b/common/src/measurement-utils.ts @@ -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 */ diff --git a/common/src/searches.ts b/common/src/searches.ts index 0d054a8b..ae59b2ab 100644 --- a/common/src/searches.ts +++ b/common/src/searches.ts @@ -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 = { - 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, location: locationType | null, - choicesIdsToLabels: Record + choicesIdsToLabels: Record, + 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 -} \ No newline at end of file +} diff --git a/web/components/filters/location-filter.tsx b/web/components/filters/location-filter.tsx index cfd9e3fd..810c2068 100644 --- a/web/components/filters/location-filter.tsx +++ b/web/components/filters/location-filter.tsx @@ -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 diff --git a/web/components/profile-about.tsx b/web/components/profile-about.tsx index 0b90a414..b5824e32 100644 --- a/web/components/profile-about.tsx +++ b/web/components/profile-about.tsx @@ -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' diff --git a/web/components/searches/button.tsx b/web/components/searches/button.tsx index 6aeffd45..bacbe974 100644 --- a/web/components/searches/button.tsx +++ b/web/components/searches/button.tsx @@ -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 (

{t('saved_searches.title', 'Saved Searches')}

- {bookmarkedSearches?.length ? (<> -

{t('saved_searches.notification_note', "We'll notify you daily when new people match your searches below.")}

- -
    - {(bookmarkedSearches || []).map((search) => ( -
  1. - {formatFilters(search.search_filters as Partial, search.location as locationType, choicesIdsToLabels)?.join(" • ")} - -
  2. - ))} -
- - - - ) : -

{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.")}

} + {bookmarkedSearches?.length ? ( + <> +

+ {t( + 'saved_searches.notification_note', + "We'll notify you daily when new people match your searches below." + )} +

+ +
    + {(bookmarkedSearches || []).map((search) => ( +
  1. + {formatFilters( + search.search_filters as Partial, + search.location as locationType, + choicesIdsToLabels, + measurementSystem + )?.join(' • ')} + +
  2. + ))} +
+ + + ) : ( +

+ {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." + )} +

+ )} {/* 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>(new Set()) const t = useT() - const visibleUsers = (starredUsers || []).filter((u) => !removingIds.has(u.id)) + const visibleUsers = (starredUsers || []).filter( + (u) => !removingIds.has(u.id) + ) return (

{t('saved_people.title', 'Saved People')}

- {visibleUsers?.length ? (<> -

{t('saved_people.list_header', 'Here are the people you saved:')}

- + {visibleUsers?.length ? ( + <> +

+ {t('saved_people.list_header', 'Here are the people you saved:')} +

+ {visibleUsers.map((u) => ( - + - +
{u.name}
-
@{u.username}
+
+ @{u.username} +
@@ -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: { ))} - ) :

You haven't saved any profile. To save one, click on the star on their profile page.

} + ) : ( +

+ You haven't saved any profile. To save one, click on the star on + their profile page. +

+ )} {/*
) -} \ No newline at end of file +} diff --git a/web/hooks/use-measurement-system.ts b/web/hooks/use-measurement-system.ts index 48677fe0..35c7af52 100644 --- a/web/hooks/use-measurement-system.ts +++ b/web/hooks/use-measurement-system.ts @@ -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