Skip to content

Commit 5194b5f

Browse files
committed
Clean home and fix profiles not loading
1 parent d7c49fe commit 5194b5f

File tree

5 files changed

+203
-265
lines changed

5 files changed

+203
-265
lines changed

web/components/about/box.tsx

Lines changed: 0 additions & 14 deletions
This file was deleted.

web/components/home/home.tsx

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import {useEffect} from "react";
2+
import {Col} from "web/components/layout/col";
3+
import {Button} from "web/components/buttons/button";
4+
import {signupRedirect} from "web/lib/util/signup";
5+
6+
export function AboutBox(props: {
7+
title: string
8+
text: string
9+
}) {
10+
const {title, text} = props
11+
return (
12+
<div className="space-y-2">
13+
<h3 className="text-lg font-bold">{title}</h3>
14+
<p className="text-gray-600 dark:text-gray-400">
15+
{text}
16+
</p>
17+
</div>
18+
)
19+
}
20+
21+
export function LoggedOutHome() {
22+
useEffect(() => {
23+
const text = "Search.";
24+
const el = document.getElementById("typewriter");
25+
if (!el) return;
26+
27+
let i = 0;
28+
let timeoutId: any;
29+
el.textContent = "";
30+
31+
function typeWriter() {
32+
if (i < text.length && el) {
33+
el.textContent = text.substring(0, i + 1);
34+
i++;
35+
timeoutId = setTimeout(typeWriter, 150);
36+
}
37+
}
38+
39+
const startId = setTimeout(typeWriter, 500);
40+
41+
return () => {
42+
clearTimeout(timeoutId);
43+
clearTimeout(startId);
44+
if (el) el.textContent = text;
45+
};
46+
}, []);
47+
48+
return (
49+
<>
50+
<Col className="mb-4 gap-2 lg:hidden">
51+
<Button
52+
className="flex-1"
53+
color="gradient"
54+
size="xl"
55+
onClick={signupRedirect}
56+
>
57+
Sign up
58+
</Button>
59+
{/*<SignUpAsMatchmaker className="flex-1"/>*/}
60+
</Col>
61+
<h1
62+
className="pt-12 pb-2 text-7xl md:text-8xl xs:text-6xl font-extrabold max-w-4xl leading-tight xl:whitespace-nowrap md:whitespace-nowrap">
63+
Don't Swipe.<br/>
64+
<span id="typewriter"></span>
65+
<span id="cursor" className="animate-pulse">|</span>
66+
</h1>
67+
<div className="w-full bg-gray-50 dark:bg-gray-900 py-8 mt-20">
68+
<div className="max-w-6xl mx-auto px-4">
69+
<div className="grid md:grid-cols-3 gap-8 text-center">
70+
<AboutBox title="Radically Transparent" text="No algorithms. Every profile searchable."/>
71+
<AboutBox title="Built for Depth" text="Filter by any keyword and what matters most."/>
72+
<AboutBox title="Community Owned" text="Free forever. Built by users, for users."/>
73+
</div>
74+
</div>
75+
</div>
76+
</>
77+
);
78+
}
79+
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import {Lover} from 'common/love/lover'
2+
import {removeNullOrUndefinedProps} from 'common/util/object'
3+
import {Search} from 'web/components/filters/search'
4+
import {useLover} from 'web/hooks/use-lover'
5+
import {useCompatibleLovers} from 'web/hooks/use-lovers'
6+
import {getStars} from 'web/lib/supabase/stars'
7+
import Router from 'next/router'
8+
import {useCallback, useEffect, useRef, useState} from 'react'
9+
import {Button} from 'web/components/buttons/button'
10+
import {orderLovers, useFilters} from 'web/components/filters/use-filters'
11+
import {ProfileGrid} from 'web/components/profile-grid'
12+
import {LoadingIndicator} from 'web/components/widgets/loading-indicator'
13+
import {Title} from 'web/components/widgets/title'
14+
import {useGetter} from 'web/hooks/use-getter'
15+
import {usePersistentInMemoryState} from 'web/hooks/use-persistent-in-memory-state'
16+
import {useUser} from 'web/hooks/use-user'
17+
import {api} from 'web/lib/api'
18+
import {debounce, omit} from 'lodash'
19+
import {PREF_AGE_MAX, PREF_AGE_MIN,} from 'web/components/filters/location-filter'
20+
21+
export function ProfilesHome() {
22+
const user = useUser();
23+
const lover = useLover();
24+
const you = lover;
25+
26+
const {
27+
filters,
28+
updateFilter,
29+
clearFilters,
30+
setYourFilters,
31+
isYourFilters,
32+
locationFilterProps,
33+
} = useFilters(you ?? undefined);
34+
35+
const [lovers, setLovers] = usePersistentInMemoryState<Lover[] | undefined>(undefined, 'profile-lovers');
36+
const [isLoadingMore, setIsLoadingMore] = useState(false);
37+
const [isReloading, setIsReloading] = useState(false);
38+
39+
const [debouncedAgeRange, setRawAgeRange] = useState({
40+
min: filters.pref_age_min ?? PREF_AGE_MIN,
41+
max: filters.pref_age_max ?? PREF_AGE_MAX,
42+
});
43+
44+
const debouncedSetAge = useCallback(debounce((state) => setRawAgeRange(state), 50), []);
45+
46+
useEffect(() => {
47+
if (!user) return;
48+
debouncedSetAge({min: filters.pref_age_min ?? PREF_AGE_MIN, max: filters.pref_age_max ?? PREF_AGE_MAX});
49+
}, [filters.pref_age_min, filters.pref_age_max]);
50+
51+
const id = useRef(0);
52+
useEffect(() => {
53+
if (!user) return;
54+
setIsReloading(true);
55+
const current = ++id.current;
56+
api('get-lovers', removeNullOrUndefinedProps({limit: 20, compatibleWithUserId: user?.id, ...filters}) as any)
57+
.then(({lovers}) => {
58+
if (current === id.current) setLovers(lovers);
59+
})
60+
.finally(() => {
61+
if (current === id.current) setIsReloading(false);
62+
});
63+
}, [JSON.stringify(omit(filters, ['pref_age_min', 'pref_age_max'])), debouncedAgeRange.min, debouncedAgeRange.max]);
64+
65+
const {data: starredUserIds, refresh: refreshStars} = useGetter('star', user?.id, getStars);
66+
const compatibleLovers = useCompatibleLovers(user?.id);
67+
const displayLovers = lovers && orderLovers(lovers, starredUserIds);
68+
69+
const loadMore = useCallback(async () => {
70+
if (!lovers || isLoadingMore) return false;
71+
try {
72+
setIsLoadingMore(true);
73+
const lastLover = lovers[lovers.length - 1];
74+
const result = await api('get-lovers', removeNullOrUndefinedProps({
75+
limit: 20,
76+
compatibleWithUserId: user?.id,
77+
after: lastLover?.id.toString(), ...filters
78+
}) as any);
79+
if (result.lovers.length === 0) return false;
80+
setLovers((prev) => (prev ? [...prev, ...result.lovers] : result.lovers));
81+
return true;
82+
} catch (err) {
83+
console.error('Failed to load more lovers', err);
84+
return false;
85+
} finally {
86+
setIsLoadingMore(false);
87+
}
88+
}, [lovers, filters, isLoadingMore, setLovers]);
89+
90+
return (
91+
<>
92+
{!lover && <Button className="mb-4 lg:hidden" onClick={() => Router.push('signup')}>Create a profile</Button>}
93+
<Title className="!mb-2 text-3xl">Profiles</Title>
94+
<Search
95+
youLover={you}
96+
starredUserIds={starredUserIds ?? []}
97+
filters={filters}
98+
updateFilter={updateFilter}
99+
clearFilters={clearFilters}
100+
setYourFilters={setYourFilters}
101+
isYourFilters={isYourFilters}
102+
locationFilterProps={locationFilterProps}
103+
/>
104+
{displayLovers === undefined || compatibleLovers === undefined ? (
105+
<LoadingIndicator/>
106+
) : (
107+
<ProfileGrid
108+
lovers={displayLovers}
109+
loadMore={loadMore}
110+
isLoadingMore={isLoadingMore}
111+
isReloading={isReloading}
112+
compatibilityScores={compatibleLovers?.loverCompatibilityScores}
113+
starredUserIds={starredUserIds}
114+
refreshStars={refreshStars}
115+
/>
116+
)}
117+
</>
118+
);
119+
}

web/hooks/use-lovers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export const useCompatibleLovers = (
3030
} else if (userId === null) setData(null)
3131
}, [userId])
3232

33+
console.log('debug', data)
3334
if (data && lover && options?.sortWithModifiers) {
3435
data.compatibleLovers = sortBy(data.compatibleLovers, (l) => {
3536
const modifier = !lover ? 1 : getLoversCompatibilityFactor(lover, l)

0 commit comments

Comments
 (0)