Move interestChoices to app context to fix db blast

This commit is contained in:
MartinBraquet
2026-03-13 14:35:20 +01:00
parent cdbba244d0
commit d3634d8b1c
8 changed files with 59 additions and 42 deletions

View File

@@ -37,7 +37,7 @@ import {Col} from 'web/components/layout/col'
import {Row} from 'web/components/layout/row'
import {NewBadge} from 'web/components/new-badge'
import {ResetFiltersButton} from 'web/components/searches/button'
import {useAllChoices, useChoices} from 'web/hooks/use-choices'
import {useChoicesContext} from 'web/hooks/use-choices'
import {useMeasurementSystem} from 'web/hooks/use-measurement-system'
import {useT} from 'web/lib/locale'
import {DietType, RelationshipType, RomanticType} from 'web/lib/util/convert-types'
@@ -76,7 +76,7 @@ function SelectedFiltersSummary(props: {
}) {
const {locationFilterProps, raisedInLocationFilterProps, updateFilter, clearFilters} = props
const t = useT()
const choicesIdsToLabels = useAllChoices()
const choicesIdsToLabels = useChoicesContext()
const {measurementSystem} = useMeasurementSystem()
const filters = removeNullOrUndefinedProps({...props.filters, orderBy: undefined})
@@ -870,14 +870,8 @@ export function FiltersElement(props: {
updateDisplayOptions,
} = props
const youSeekingRelationship = youProfile?.pref_relation_styles?.includes('relationship')
const {choices: interestChoices} = useChoices('interests')
const {choices: causeChoices} = useChoices('causes')
const {choices: workChoices} = useChoices('work')
const choices = {
interests: interestChoices,
causes: causeChoices,
work: workChoices,
}
const _choices = useChoicesContext()
const choices = {interests: _choices.interests, causes: _choices.causes, work: _choices.work}
return (
<Filters
filters={filters}

View File

@@ -3,7 +3,7 @@ import {FilterFields} from 'common/filters'
import {OptionTableKey} from 'common/profiles/constants'
import {invert} from 'lodash'
import {MultiCheckbox} from 'web/components/multi-checkbox'
import {useChoices} from 'web/hooks/use-choices'
import {useChoicesContext} from 'web/hooks/use-choices'
import {useLocale, useT} from 'web/lib/locale'
import stringOrStringArrayToText from 'web/lib/util/string-or-string-array-to-text'
@@ -15,7 +15,7 @@ export function InterestFilterText(props: {
const {options, highlightedClass, label} = props
const t = useT()
const length = (options ?? []).length
const {choices} = useChoices(label)
const choices = useChoicesContext()?.[label]
if (!options || length < 1) {
return (

View File

@@ -15,7 +15,7 @@ import {Input} from 'web/components/widgets/input'
import {Select} from 'web/components/widgets/select'
import {Tooltip} from 'web/components/widgets/tooltip'
import {BookmarkedSearchesType} from 'web/hooks/use-bookmarked-searches'
import {useChoices} from 'web/hooks/use-choices'
import {useChoicesContext} from 'web/hooks/use-choices'
import {useIsClearedFilters} from 'web/hooks/use-is-cleared-filters'
import {useUser} from 'web/hooks/use-user'
import {useT} from 'web/lib/locale'
@@ -179,7 +179,7 @@ export const Search = forwardRef<
const [openStarBookmarks, setOpenStarBookmarks] = useState(false)
const user = useUser()
const isClearedFilters = useIsClearedFilters(filters)
const {choices: interestChoices} = useChoices('interests')
const choices = useChoicesContext()
useEffect(() => {
if (isHolding) return
@@ -195,7 +195,7 @@ export const Search = forwardRef<
setTimeout(() => {
setPlaceholder('')
setCharIndex(0)
setTextToType(getRandomPair(Object.values(interestChoices))) // pick new pair
setTextToType(getRandomPair(Object.values(choices?.['interests']))) // pick new pair
setIsHolding(false)
}, HOLD_TIME)
return prev

View File

@@ -33,7 +33,7 @@ import {TbBulb, TbCheck, TbMoodSad, TbUsers} from 'react-icons/tb'
import {Col} from 'web/components/layout/col'
import {Row} from 'web/components/layout/row'
import {UserHandles} from 'web/components/user/user-handles'
import {useChoices} from 'web/hooks/use-choices'
import {useChoicesContext} from 'web/hooks/use-choices'
import {useLocale, useT} from 'web/lib/locale'
import {getSeekingConnectionText} from 'web/lib/profile/seeking'
import {convertRace} from 'web/lib/util/convert-types'
@@ -83,9 +83,7 @@ export default function ProfileAbout(props: {
}) {
const {profile, userActivity, isCurrentUser} = props
const t = useT()
const {choices: interestsById} = useChoices('interests')
const {choices: causesById} = useChoices('causes')
const {choices: workById} = useChoices('work')
const choices = useChoicesContext()
const {locale} = useLocale()
return (
@@ -98,7 +96,7 @@ export default function ProfileAbout(props: {
icon={<FaBriefcase className="h-5 w-5" />}
text={
profile.work
?.map((id) => workById[id])
?.map((id) => choices?.['work']?.[id])
.filter(Boolean)
.sort((a, b) => a.localeCompare(b, locale)) as string[]
}
@@ -124,7 +122,7 @@ export default function ProfileAbout(props: {
icon={<FaStar className="h-5 w-5" />}
text={
profile.interests
?.map((id) => interestsById[id])
?.map((id) => choices?.['interests']?.[id])
.filter(Boolean)
.sort((a, b) => a.localeCompare(b, locale)) as string[]
}
@@ -134,7 +132,7 @@ export default function ProfileAbout(props: {
icon={<FaHandsHelping className="h-5 w-5" />}
text={
profile.causes
?.map((id) => causesById[id])
?.map((id) => choices?.['causes']?.[id])
.filter(Boolean)
.sort((a, b) => a.localeCompare(b, locale)) as string[]
}

View File

@@ -31,7 +31,7 @@ import {Content} from 'web/components/widgets/editor'
import HideProfileButton from 'web/components/widgets/hide-profile-button'
import {CompassLoadingIndicator} from 'web/components/widgets/loading-indicator'
import {LoadMoreUntilNotVisible} from 'web/components/widgets/visibility-observer'
import {useAllChoices} from 'web/hooks/use-choices'
import {useChoicesContext} from 'web/hooks/use-choices'
import {useUser} from 'web/hooks/use-user'
import {useT} from 'web/lib/locale'
import {getSeekingConnectionText} from 'web/lib/profile/seeking'
@@ -157,7 +157,7 @@ function ProfilePreview(props: {
cardSize,
} = displayOptions ?? {}
const {user} = profile
const choicesIdsToLabels = useAllChoices()
const choicesIdsToLabels = useChoicesContext()
const t = useT()
// const currentUser = useUser()

View File

@@ -13,7 +13,7 @@ import {Modal, MODAL_CLASS, SCROLLABLE_MODAL_CLASS} from 'web/components/layout/
import {Row} from 'web/components/layout/row'
import {Avatar} from 'web/components/widgets/avatar'
import {BookmarkedSearchesType} from 'web/hooks/use-bookmarked-searches'
import {useAllChoices} from 'web/hooks/use-choices'
import {useChoicesContext} from 'web/hooks/use-choices'
import {useMeasurementSystem} from 'web/hooks/use-measurement-system'
import {useUser} from 'web/hooks/use-user'
import {api} from 'web/lib/api'
@@ -68,7 +68,7 @@ function ButtonModal(props: {
}) {
const {open, setOpen, bookmarkedSearches, refreshBookmarkedSearches} = props
const t = useT()
const choicesIdsToLabels = useAllChoices()
const choicesIdsToLabels = useChoicesContext()
const {measurementSystem} = useMeasurementSystem()
return (
<Modal

View File

@@ -1,11 +1,26 @@
import {debug} from 'common/logger'
import {OptionTableKey} from 'common/profiles/constants'
import {run} from 'common/supabase/utils'
import {useEffect} from 'react'
import {createContext, ReactNode, useContext, useEffect} from 'react'
import {usePersistentInMemoryState} from 'web/hooks/use-persistent-in-memory-state'
import {useLocale} from 'web/lib/locale'
import {db} from 'web/lib/supabase/db'
const ChoicesContext = createContext<UseAllChoices | null>(null)
export const ChoicesProvider = ({children}: {children: ReactNode}) => {
const choices = useAllChoices()
return <ChoicesContext.Provider value={choices}>{children}</ChoicesContext.Provider>
}
export const useChoicesContext = () => {
const ctx = useContext(ChoicesContext)
if (!ctx) throw new Error('useChoicesContext must be used within a ChoicesProvider')
return ctx
}
export async function fetchChoices(label: OptionTableKey, locale: string) {
debug('Fetching choices for', label)
const choicesById: Record<string, string> = {}
const {data} = await run(
db
@@ -32,7 +47,7 @@ export async function fetchChoices(label: OptionTableKey, locale: string) {
return choicesById
}
export const useChoices = (label: OptionTableKey) => {
const useChoices = (label: OptionTableKey) => {
const [choices, setChoices] = usePersistentInMemoryState<Record<string, string>>(
{},
`${label}-choices`,
@@ -40,24 +55,31 @@ export const useChoices = (label: OptionTableKey) => {
const {locale} = useLocale()
const refreshChoices = async () => {
try {
const results = await fetchChoices(label, locale)
setChoices(results)
} catch (err) {
console.error('Error fetching choices:', err)
return {}
}
fetchChoices(label, locale)
.then(setChoices)
.catch((err) => {
console.error('Error fetching choices:', err?.message ?? err)
return {}
})
}
useEffect(() => {
// debug('Fetching choices in use effect...')
refreshChoices()
}, [locale])
return {choices, refreshChoices}
}
export const useAllChoices = () => {
export type UseAllChoices = {
interests: Record<string, string>
causes: Record<string, string>
work: Record<string, string>
refreshInterests: () => void
refreshCauses: () => void
refreshWork: () => void
}
const useAllChoices = () => {
const {choices: interests, refreshChoices: refreshInterests} = useChoices('interests')
const {choices: causes, refreshChoices: refreshCauses} = useChoices('causes')
const {choices: work, refreshChoices: refreshWork} = useChoices('work')

View File

@@ -20,6 +20,7 @@ import {useEffect, useState} from 'react'
import {AuthProvider, AuthUser} from 'web/components/auth-context'
import {ErrorBoundary} from 'web/components/error-boundary'
import {LiveRegionProvider} from 'web/components/live-region'
import {ChoicesProvider} from 'web/hooks/use-choices'
import {useFontPreferenceManager} from 'web/hooks/use-font-preference'
import {useHasLoaded} from 'web/hooks/use-has-loaded'
import {HiddenProfilesProvider} from 'web/hooks/use-hidden-profiles'
@@ -196,11 +197,13 @@ function MyApp(props: AppProps<PageProps>) {
<I18nContext.Provider value={{locale, setLocale}}>
<ErrorBoundary>
<AuthProvider serverUser={pageProps.auth}>
<HiddenProfilesProvider>
<WebPush />
<AndroidPush />
<Component {...pageProps} />
</HiddenProfilesProvider>
<ChoicesProvider>
<HiddenProfilesProvider>
<WebPush />
<AndroidPush />
<Component {...pageProps} />
</HiddenProfilesProvider>
</ChoicesProvider>
</AuthProvider>
</ErrorBoundary>
</I18nContext.Provider>