diff --git a/web/components/about/box.tsx b/web/components/about/box.tsx deleted file mode 100644 index e01da9db..00000000 --- a/web/components/about/box.tsx +++ /dev/null @@ -1,14 +0,0 @@ -export function AboutBox(props: { - title: string - text: string -}) { - const {title, text} = props - return ( -
-

{title}

-

- {text} -

-
- ) -} diff --git a/web/components/home/home.tsx b/web/components/home/home.tsx new file mode 100644 index 00000000..2efe94cf --- /dev/null +++ b/web/components/home/home.tsx @@ -0,0 +1,79 @@ +import {useEffect} from "react"; +import {Col} from "web/components/layout/col"; +import {Button} from "web/components/buttons/button"; +import {signupRedirect} from "web/lib/util/signup"; + +export function AboutBox(props: { + title: string + text: string +}) { + const {title, text} = props + return ( +
+

{title}

+

+ {text} +

+
+ ) +} + +export function LoggedOutHome() { + useEffect(() => { + const text = "Search."; + const el = document.getElementById("typewriter"); + if (!el) return; + + let i = 0; + let timeoutId: any; + el.textContent = ""; + + function typeWriter() { + if (i < text.length && el) { + el.textContent = text.substring(0, i + 1); + i++; + timeoutId = setTimeout(typeWriter, 150); + } + } + + const startId = setTimeout(typeWriter, 500); + + return () => { + clearTimeout(timeoutId); + clearTimeout(startId); + if (el) el.textContent = text; + }; + }, []); + + return ( + <> + + + {/**/} + +

+ Don't Swipe.
+ + | +

+
+
+
+ + + +
+
+
+ + ); +} + diff --git a/web/components/profiles/profiles-home.tsx b/web/components/profiles/profiles-home.tsx new file mode 100644 index 00000000..4bf48de3 --- /dev/null +++ b/web/components/profiles/profiles-home.tsx @@ -0,0 +1,119 @@ +import {Lover} from 'common/love/lover' +import {removeNullOrUndefinedProps} from 'common/util/object' +import {Search} from 'web/components/filters/search' +import {useLover} from 'web/hooks/use-lover' +import {useCompatibleLovers} from 'web/hooks/use-lovers' +import {getStars} from 'web/lib/supabase/stars' +import Router from 'next/router' +import {useCallback, useEffect, useRef, useState} from 'react' +import {Button} from 'web/components/buttons/button' +import {orderLovers, useFilters} from 'web/components/filters/use-filters' +import {ProfileGrid} from 'web/components/profile-grid' +import {LoadingIndicator} from 'web/components/widgets/loading-indicator' +import {Title} from 'web/components/widgets/title' +import {useGetter} from 'web/hooks/use-getter' +import {usePersistentInMemoryState} from 'web/hooks/use-persistent-in-memory-state' +import {useUser} from 'web/hooks/use-user' +import {api} from 'web/lib/api' +import {debounce, omit} from 'lodash' +import {PREF_AGE_MAX, PREF_AGE_MIN,} from 'web/components/filters/location-filter' + +export function ProfilesHome() { + const user = useUser(); + const lover = useLover(); + const you = lover; + + const { + filters, + updateFilter, + clearFilters, + setYourFilters, + isYourFilters, + locationFilterProps, + } = useFilters(you ?? undefined); + + const [lovers, setLovers] = usePersistentInMemoryState(undefined, 'profile-lovers'); + const [isLoadingMore, setIsLoadingMore] = useState(false); + const [isReloading, setIsReloading] = useState(false); + + const [debouncedAgeRange, setRawAgeRange] = useState({ + min: filters.pref_age_min ?? PREF_AGE_MIN, + max: filters.pref_age_max ?? PREF_AGE_MAX, + }); + + const debouncedSetAge = useCallback(debounce((state) => setRawAgeRange(state), 50), []); + + useEffect(() => { + if (!user) return; + debouncedSetAge({min: filters.pref_age_min ?? PREF_AGE_MIN, max: filters.pref_age_max ?? PREF_AGE_MAX}); + }, [filters.pref_age_min, filters.pref_age_max]); + + const id = useRef(0); + useEffect(() => { + if (!user) return; + setIsReloading(true); + const current = ++id.current; + api('get-lovers', removeNullOrUndefinedProps({limit: 20, compatibleWithUserId: user?.id, ...filters}) as any) + .then(({lovers}) => { + if (current === id.current) setLovers(lovers); + }) + .finally(() => { + if (current === id.current) setIsReloading(false); + }); + }, [JSON.stringify(omit(filters, ['pref_age_min', 'pref_age_max'])), debouncedAgeRange.min, debouncedAgeRange.max]); + + const {data: starredUserIds, refresh: refreshStars} = useGetter('star', user?.id, getStars); + const compatibleLovers = useCompatibleLovers(user?.id); + const displayLovers = lovers && orderLovers(lovers, starredUserIds); + + const loadMore = useCallback(async () => { + if (!lovers || isLoadingMore) return false; + try { + setIsLoadingMore(true); + const lastLover = lovers[lovers.length - 1]; + const result = await api('get-lovers', removeNullOrUndefinedProps({ + limit: 20, + compatibleWithUserId: user?.id, + after: lastLover?.id.toString(), ...filters + }) as any); + if (result.lovers.length === 0) return false; + setLovers((prev) => (prev ? [...prev, ...result.lovers] : result.lovers)); + return true; + } catch (err) { + console.error('Failed to load more lovers', err); + return false; + } finally { + setIsLoadingMore(false); + } + }, [lovers, filters, isLoadingMore, setLovers]); + + return ( + <> + {!lover && } + Profiles + + {displayLovers === undefined || compatibleLovers === undefined ? ( + + ) : ( + + )} + + ); +} diff --git a/web/hooks/use-lovers.ts b/web/hooks/use-lovers.ts index ac5ff3ba..4b4efe5f 100644 --- a/web/hooks/use-lovers.ts +++ b/web/hooks/use-lovers.ts @@ -30,6 +30,7 @@ export const useCompatibleLovers = ( } else if (userId === null) setData(null) }, [userId]) + console.log('debug', data) if (data && lover && options?.sortWithModifiers) { data.compatibleLovers = sortBy(data.compatibleLovers, (l) => { const modifier = !lover ? 1 : getLoversCompatibilityFactor(lover, l) diff --git a/web/pages/index.tsx b/web/pages/index.tsx index 32cd8c12..850b0dbb 100644 --- a/web/pages/index.tsx +++ b/web/pages/index.tsx @@ -1,265 +1,18 @@ -import {Lover} from 'common/love/lover' -import {removeNullOrUndefinedProps} from 'common/util/object' -import {Search} from 'web/components/filters/search' import {LovePage} from 'web/components/love-page' -import {useLover} from 'web/hooks/use-lover' -import {useCompatibleLovers} from 'web/hooks/use-lovers' -import {getStars} from 'web/lib/supabase/stars' -import Router from 'next/router' -import {useCallback, useEffect, useRef, useState} from 'react' -import {Button} from 'web/components/buttons/button' -import {orderLovers, useFilters} from 'web/components/filters/use-filters' import {Col} from 'web/components/layout/col' -import {ProfileGrid} from 'web/components/profile-grid' -import {LoadingIndicator} from 'web/components/widgets/loading-indicator' -import {Title} from 'web/components/widgets/title' -import {useGetter} from 'web/hooks/use-getter' -import {usePersistentInMemoryState} from 'web/hooks/use-persistent-in-memory-state' -import {useSaveReferral} from 'web/hooks/use-save-referral' -import {useTracking} from 'web/hooks/use-tracking' import {useUser} from 'web/hooks/use-user' -import {api} from 'web/lib/api' -import {debounce, omit} from 'lodash' -import {PREF_AGE_MAX, PREF_AGE_MIN,} from 'web/components/filters/location-filter' -import {signupRedirect} from "web/lib/util/signup"; -import {AboutBox} from "web/components/about/box"; +import {LoggedOutHome} from "web/components/home/home"; +import {ProfilesHome} from "web/components/profiles/profiles-home"; export default function ProfilesPage() { - const you = useLover() - - const { - filters, - updateFilter, - clearFilters, - setYourFilters, - isYourFilters, - locationFilterProps, - } = useFilters(you ?? undefined) - - // Store all loaded lovers - const [lovers, setLovers] = usePersistentInMemoryState( - undefined, - 'profile-lovers' - ) - - const [isLoadingMore, setIsLoadingMore] = useState(false) - const [isReloading, setIsReloading] = useState(false) - - // Refresh lovers when filters change - - // debounce age filter - const [debouncedAgeRange, setRawAgeRange] = useState({ - min: filters.pref_age_min ?? PREF_AGE_MIN, - max: filters.pref_age_max ?? PREF_AGE_MAX, - }) - - const debouncedSetAge = useCallback( - debounce( - (state: { min: number; max: number }) => setRawAgeRange(state), - 50 - ), - [] - ) - - const user = useUser() - - useEffect(() => { - if (!user) return - debouncedSetAge({ - min: filters.pref_age_min ?? PREF_AGE_MIN, - max: filters.pref_age_max ?? PREF_AGE_MAX, - }) - }, [filters.pref_age_min, filters.pref_age_max]) - - const id = useRef(0) - useEffect(() => { - if (!user) return - setIsReloading(true) - const current = ++id.current - api( - 'get-lovers', - removeNullOrUndefinedProps({ - limit: 20, - compatibleWithUserId: user?.id, - ...filters, - }) as any - ) - .then(({lovers}) => { - if (current === id.current) { - setLovers(lovers) - } - }) - .finally(() => { - if (current === id.current) { - setIsReloading(false) - } - }) - }, [ - JSON.stringify(omit(filters, ['pref_age_min', 'pref_age_max'])), - debouncedAgeRange.min, - debouncedAgeRange.max, - ]) - - useTracking('view love profiles') - useSaveReferral(user) - const lover = useLover() - const {data: starredUserIds, refresh: refreshStars} = useGetter( - 'star', - user?.id, - getStars - ) - - const compatibleLovers = useCompatibleLovers(user ? user.id : user) - const loadMore = useCallback(async () => { - if (!lovers || isLoadingMore) return false - - try { - setIsLoadingMore(true) - - // Get the last lover's ID as the after parameter - const lastLover = lovers[lovers.length - 1] - - console.log('fetching lovers after', lastLover?.id) - - const result = await api( - 'get-lovers', - removeNullOrUndefinedProps({ - limit: 20, - compatibleWithUserId: user?.id, - after: lastLover?.id.toString(), - ...filters, - } as any) - ) - - if (result.lovers.length === 0) { - return false - } - - // Append new lovers to existing array - setLovers((prevLovers) => { - if (!prevLovers) return result.lovers - - // Create a new array with all existing lovers plus new ones - return [...prevLovers, ...result.lovers] - }) - - return true - } catch (err) { - console.error('Failed to load more lovers', err) - return false - } finally { - setIsLoadingMore(false) - } - }, [lovers, filters, isLoadingMore, setLovers]) - - const displayLovers = lovers && orderLovers(lovers, starredUserIds) - - useEffect(() => { - const text = "Search."; - const typewriter = document.getElementById("typewriter"); - let i = 0; - let timeoutId: any; - if (typewriter) typewriter.textContent = "" - - function typeWriter() { - if (i < text.length && typewriter) { - typewriter.textContent = text.substring(0, i + 1); - i++; - timeoutId = setTimeout(typeWriter, 150); - } - } - - const intervalId = setTimeout(() => typeWriter(), 500); - return () => { - clearTimeout(timeoutId); - clearTimeout(intervalId); - if (typewriter) typewriter.textContent = "Search." - }; - }, []); - - // This makes document.getElementById("typewriter") null and prevents typeWriter from running. - // Should not be needed anyway. - // if (user === undefined) return
+ const user = useUser(); return ( - {user && lovers && !lover && ( - - )} - {user === null && ( - - - {/**/} - - )} - {!user && <> -

- Don't Swipe.
| -

-
-
-
- - - -
-
-
- } - {user && - <> - Profiles - - - {displayLovers === undefined || compatibleLovers === undefined ? ( - - ) : ( - ) - } - - } + {user ? : }