mirror of
https://github.com/CompassConnections/Compass.git
synced 2025-12-23 22:18:43 -05:00
Rename lover -> profile
This commit is contained in:
@@ -12,11 +12,11 @@ import {blockUser, unblockUser} from './block-user'
|
||||
import {getCompatibleProfilesHandler} from './compatible-profiles'
|
||||
import {createComment} from './create-comment'
|
||||
import {createCompatibilityQuestion} from './create-compatibility-question'
|
||||
import {createProfile} from './create-lover'
|
||||
import {createProfile} from './create-profile'
|
||||
import {createUser} from './create-user'
|
||||
import {getCompatibilityQuestions} from './get-compatibililty-questions'
|
||||
import {getLikesAndShips} from './get-likes-and-ships'
|
||||
import {getProfileAnswers} from './get-lover-answers'
|
||||
import {getProfileAnswers} from './get-profile-answers'
|
||||
import {getProfiles} from './get-profiles'
|
||||
import {getSupabaseToken} from './get-supabase-token'
|
||||
import {getDisplayUser, getUser} from './get-user'
|
||||
@@ -25,15 +25,15 @@ import {hasFreeLike} from './has-free-like'
|
||||
import {health} from './health'
|
||||
import {type APIHandler, typedEndpoint} from './helpers/endpoint'
|
||||
import {hideComment} from './hide-comment'
|
||||
import {likeProfile} from './like-lover'
|
||||
import {likeProfile} from './like-profile'
|
||||
import {markAllNotifsRead} from './mark-all-notifications-read'
|
||||
import {removePinnedPhoto} from './remove-pinned-photo'
|
||||
import {report} from './report'
|
||||
import {searchLocation} from './search-location'
|
||||
import {searchNearCity} from './search-near-city'
|
||||
import {shipProfiles} from './ship-profiles'
|
||||
import {starProfile} from './star-lover'
|
||||
import {updateProfile} from './update-lover'
|
||||
import {starProfile} from './star-profile'
|
||||
import {updateProfile} from './update-profile'
|
||||
import {updateMe} from './update-me'
|
||||
import {deleteMe} from './delete-me'
|
||||
import {getCurrentPrivateUser} from './get-current-private-user'
|
||||
@@ -134,20 +134,20 @@ const handlers: { [k in APIPath]: APIHandler<k> } = {
|
||||
'ban-user': banUser,
|
||||
report: report,
|
||||
'create-user': createUser,
|
||||
'create-lover': createProfile,
|
||||
'create-profile': createProfile,
|
||||
me: getMe,
|
||||
'me/private': getCurrentPrivateUser,
|
||||
'me/update': updateMe,
|
||||
'update-notif-settings': updateNotifSettings,
|
||||
'me/delete': deleteMe,
|
||||
'update-lover': updateProfile,
|
||||
'like-lover': likeProfile,
|
||||
'update-profile': updateProfile,
|
||||
'like-profile': likeProfile,
|
||||
'ship-profiles': shipProfiles,
|
||||
'get-likes-and-ships': getLikesAndShips,
|
||||
'has-free-like': hasFreeLike,
|
||||
'star-lover': starProfile,
|
||||
'star-profile': starProfile,
|
||||
'get-profiles': getProfiles,
|
||||
'get-lover-answers': getProfileAnswers,
|
||||
'get-profile-answers': getProfileAnswers,
|
||||
'get-compatibility-questions': getCompatibilityQuestions,
|
||||
'remove-pinned-photo': removePinnedPhoto,
|
||||
'create-comment': createComment,
|
||||
|
||||
@@ -15,32 +15,32 @@ export const getCompatibleProfilesHandler: APIHandler<
|
||||
}
|
||||
|
||||
export const getCompatibleProfiles = async (userId: string) => {
|
||||
const lover = await getProfile(userId)
|
||||
const profile = await getProfile(userId)
|
||||
|
||||
log('got lover', {
|
||||
id: lover?.id,
|
||||
userId: lover?.user_id,
|
||||
username: lover?.user?.username,
|
||||
log('got profile', {
|
||||
id: profile?.id,
|
||||
userId: profile?.user_id,
|
||||
username: profile?.user?.username,
|
||||
})
|
||||
|
||||
if (!lover) throw new APIError(404, 'Profile not found')
|
||||
if (!profile) throw new APIError(404, 'Profile not found')
|
||||
|
||||
const profiles = await getGenderCompatibleProfiles(lover)
|
||||
const profiles = await getGenderCompatibleProfiles(profile)
|
||||
|
||||
const loverAnswers = await getCompatibilityAnswers([
|
||||
const profileAnswers = await getCompatibilityAnswers([
|
||||
userId,
|
||||
...profiles.map((l) => l.user_id),
|
||||
])
|
||||
log('got lover answers ' + loverAnswers.length)
|
||||
log('got profile answers ' + profileAnswers.length)
|
||||
|
||||
const answersByUserId = groupBy(loverAnswers, 'creator_id')
|
||||
const loverCompatibilityScores = Object.fromEntries(
|
||||
const answersByUserId = groupBy(profileAnswers, 'creator_id')
|
||||
const profileCompatibilityScores = Object.fromEntries(
|
||||
profiles.map(
|
||||
(l) =>
|
||||
[
|
||||
l.user_id,
|
||||
getCompatibilityScore(
|
||||
answersByUserId[lover.user_id] ?? [],
|
||||
answersByUserId[profile.user_id] ?? [],
|
||||
answersByUserId[l.user_id] ?? []
|
||||
),
|
||||
] as const
|
||||
@@ -49,13 +49,13 @@ export const getCompatibleProfiles = async (userId: string) => {
|
||||
|
||||
const sortedCompatibleProfiles = sortBy(
|
||||
profiles,
|
||||
(l) => loverCompatibilityScores[l.user_id].score
|
||||
(l) => profileCompatibilityScores[l.user_id].score
|
||||
).reverse()
|
||||
|
||||
return {
|
||||
status: 'success',
|
||||
lover,
|
||||
profile,
|
||||
compatibleProfiles: sortedCompatibleProfiles,
|
||||
loverCompatibilityScores,
|
||||
profileCompatibilityScores,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ export const createComment: APIHandler<'create-comment'> = async (
|
||||
if (!onUser) throw new APIError(404, 'User not found')
|
||||
|
||||
const pg = createSupabaseDirectClient()
|
||||
const comment = await pg.one<Row<'lover_comments'>>(
|
||||
`insert into lover_comments (user_id, user_name, user_username, user_avatar_url, on_user_id, content, reply_to_comment_id)
|
||||
const comment = await pg.one<Row<'profile_comments'>>(
|
||||
`insert into profile_comments (user_id, user_name, user_username, user_avatar_url, on_user_id, content, reply_to_comment_id)
|
||||
values ($1, $2, $3, $4, $5, $6, $7) returning *`,
|
||||
[
|
||||
creator.id,
|
||||
@@ -104,7 +104,7 @@ const createNewCommentOnProfileNotification = async (
|
||||
createdTime: Date.now(),
|
||||
isSeen: false,
|
||||
sourceId: commentId.toString(),
|
||||
sourceType: 'comment_on_lover',
|
||||
sourceType: 'comment_on_profile',
|
||||
sourceUpdateType: 'created',
|
||||
sourceUserName: creator.name,
|
||||
sourceUserUsername: creator.username,
|
||||
|
||||
@@ -8,7 +8,7 @@ import { updateUser } from 'shared/supabase/users'
|
||||
import { tryCatch } from 'common/util/try-catch'
|
||||
import { insert } from 'shared/supabase/utils'
|
||||
|
||||
export const createProfile: APIHandler<'create-lover'> = async (body, auth) => {
|
||||
export const createProfile: APIHandler<'create-profile'> = async (body, auth) => {
|
||||
const pg = createSupabaseDirectClient()
|
||||
|
||||
const { data: existingUser } = await tryCatch(
|
||||
@@ -40,7 +40,7 @@ export const createProfile: APIHandler<'create-lover'> = async (body, auth) => {
|
||||
}
|
||||
|
||||
log('Created user', data)
|
||||
await track(user.id, 'create lover', { username: user.username })
|
||||
await track(user.id, 'create profile', { username: user.username })
|
||||
|
||||
return data
|
||||
}
|
||||
@@ -123,7 +123,7 @@ export const createUser: APIHandler<'create-user'> = async (
|
||||
log('created user ', { username: user.username, firebaseId: auth.uid })
|
||||
|
||||
const continuation = async () => {
|
||||
await track(auth.uid, 'create lover', { username: user.username })
|
||||
await track(auth.uid, 'create profile', { username: user.username })
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { type APIHandler } from 'api/helpers/endpoint'
|
||||
import { createSupabaseDirectClient } from 'shared/supabase/init'
|
||||
import { Row } from 'common/supabase/utils'
|
||||
|
||||
export const getProfileAnswers: APIHandler<'get-lover-answers'> = async (
|
||||
export const getProfileAnswers: APIHandler<'get-profile-answers'> = async (
|
||||
props,
|
||||
_auth
|
||||
) => {
|
||||
@@ -10,8 +10,8 @@ export const hideComment: APIHandler<'hide-comment'> = async (
|
||||
auth
|
||||
) => {
|
||||
const pg = createSupabaseDirectClient()
|
||||
const comment = await pg.oneOrNone<Row<'lover_comments'>>(
|
||||
`select * from lover_comments where id = $1`,
|
||||
const comment = await pg.oneOrNone<Row<'profile_comments'>>(
|
||||
`select * from profile_comments where id = $1`,
|
||||
[commentId]
|
||||
)
|
||||
if (!comment) {
|
||||
@@ -26,7 +26,7 @@ export const hideComment: APIHandler<'hide-comment'> = async (
|
||||
throw new APIError(403, 'You are not allowed to hide this comment')
|
||||
}
|
||||
|
||||
await pg.none(`update lover_comments set hidden = $2 where id = $1`, [
|
||||
await pg.none(`update profile_comments set hidden = $2 where id = $1`, [
|
||||
commentId,
|
||||
hide,
|
||||
])
|
||||
|
||||
@@ -6,7 +6,7 @@ import { log } from 'shared/utils'
|
||||
import { tryCatch } from 'common/util/try-catch'
|
||||
import { Row } from 'common/supabase/utils'
|
||||
|
||||
export const likeProfile: APIHandler<'like-lover'> = async (props, auth) => {
|
||||
export const likeProfile: APIHandler<'like-profile'> = async (props, auth) => {
|
||||
const { targetUserId, remove } = props
|
||||
const creatorId = auth.uid
|
||||
|
||||
@@ -5,7 +5,7 @@ import { tryCatch } from 'common/util/try-catch'
|
||||
import { Row } from 'common/supabase/utils'
|
||||
import { insert } from 'shared/supabase/utils'
|
||||
|
||||
export const starProfile: APIHandler<'star-lover'> = async (props, auth) => {
|
||||
export const starProfile: APIHandler<'star-profile'> = async (props, auth) => {
|
||||
const { targetUserId, remove } = props
|
||||
const creatorId = auth.uid
|
||||
|
||||
@@ -7,7 +7,7 @@ import { tryCatch } from 'common/util/try-catch'
|
||||
import { update } from 'shared/supabase/utils'
|
||||
import { type Row } from 'common/supabase/utils'
|
||||
|
||||
export const updateProfile: APIHandler<'update-lover'> = async (
|
||||
export const updateProfile: APIHandler<'update-profile'> = async (
|
||||
parsedBody,
|
||||
auth
|
||||
) => {
|
||||
@@ -25,7 +25,7 @@ export const updateProfile: APIHandler<'update-lover'> = async (
|
||||
}
|
||||
|
||||
!parsedBody.last_online_time &&
|
||||
log('Updating lover', { userId: auth.uid, parsedBody })
|
||||
log('Updating profile', { userId: auth.uid, parsedBody })
|
||||
|
||||
await removePinnedUrlFromPhotoUrls(parsedBody)
|
||||
if (parsedBody.avatar_url) {
|
||||
@@ -37,8 +37,8 @@ export const updateProfile: APIHandler<'update-lover'> = async (
|
||||
)
|
||||
|
||||
if (error) {
|
||||
log('Error updating lover', error)
|
||||
throw new APIError(500, 'Error updating lover')
|
||||
log('Error updating profile', error)
|
||||
throw new APIError(500, 'Error updating profile')
|
||||
}
|
||||
|
||||
return data
|
||||
@@ -20,8 +20,8 @@ const from = 'Compass <no-reply@compassmeet.com>'
|
||||
// 'new_match'
|
||||
// )
|
||||
// if (!privateUser.email || !sendToEmail) return
|
||||
// const lover = await getProfile(privateUser.id)
|
||||
// if (!lover) return
|
||||
// const profile = await getProfile(privateUser.id)
|
||||
// if (!profile) return
|
||||
//
|
||||
// return await sendEmail({
|
||||
// from,
|
||||
@@ -29,10 +29,10 @@ const from = 'Compass <no-reply@compassmeet.com>'
|
||||
// to: privateUser.email,
|
||||
// react: (
|
||||
// <NewMatchEmail
|
||||
// onUser={lover.user}
|
||||
// onUser={profile.user}
|
||||
// email={privateUser.email}
|
||||
// matchedWithUser={matchedWithUser}
|
||||
// matchedProfile={lover}
|
||||
// matchedProfile={profile}
|
||||
// unsubscribeUrl={unsubscribeUrl}
|
||||
// />
|
||||
// ),
|
||||
@@ -51,9 +51,9 @@ export const sendNewMessageEmail = async (
|
||||
)
|
||||
if (!privateUser.email || !sendToEmail) return
|
||||
|
||||
const lover = await getProfile(fromUser.id)
|
||||
const profile = await getProfile(fromUser.id)
|
||||
|
||||
if (!lover) {
|
||||
if (!profile) {
|
||||
console.error('Could not send email notification: User not found')
|
||||
return
|
||||
}
|
||||
@@ -65,7 +65,7 @@ export const sendNewMessageEmail = async (
|
||||
html: await render(
|
||||
<NewMessageEmail
|
||||
fromUser={fromUser}
|
||||
fromUserProfile={lover}
|
||||
fromUserProfile={profile}
|
||||
toUser={toUser}
|
||||
channelId={channelId}
|
||||
unsubscribeUrl={unsubscribeUrl}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ProfileRow } from 'common/love/lover'
|
||||
import { ProfileRow } from 'common/love/profile'
|
||||
import type { User } from 'common/user'
|
||||
|
||||
// for email template testing
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Body, Button, Container, Head, Html, Preview, Section, Text,} from '@react-email/components'
|
||||
import {DOMAIN} from 'common/envs/constants'
|
||||
import {type ProfileRow} from 'common/love/lover'
|
||||
import {type ProfileRow} from 'common/love/profile'
|
||||
import {type User} from 'common/user'
|
||||
import {jamesProfile, jamesUser, sinclairUser} from './functions/mock'
|
||||
import {Footer} from "email/utils";
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
Text,
|
||||
} from '@react-email/components'
|
||||
import { type User } from 'common/user'
|
||||
import { type ProfileRow } from 'common/love/lover'
|
||||
import { type ProfileRow } from 'common/love/profile'
|
||||
import {
|
||||
jamesProfile,
|
||||
jamesUser,
|
||||
|
||||
@@ -27,7 +27,7 @@ const getNodes = async (pg: SupabaseDirectClient, nodeName: string) => {
|
||||
console.log(`\nSearching comments for ${nodeName}...`)
|
||||
const commentQuery = renderSql(
|
||||
select('id, user_id, on_user_id, content'),
|
||||
from('lover_comments'),
|
||||
from('profile_comments'),
|
||||
where(`jsonb_path_exists(content, '$.**.type ? (@ == "${nodeName}")')`)
|
||||
)
|
||||
const comments = await pg.manyOrNone(commentQuery)
|
||||
|
||||
@@ -33,7 +33,7 @@ runScript(async ({ pg }) => {
|
||||
console.log('\nSearching comments for linkPreviews...')
|
||||
const commentQuery = renderSql(
|
||||
select('id, content'),
|
||||
from('lover_comments'),
|
||||
from('profile_comments'),
|
||||
where(`jsonb_path_exists(content, '$.**.type ? (@ == "${nodeType}")')`)
|
||||
)
|
||||
const comments = await pg.manyOrNone(commentQuery)
|
||||
@@ -45,7 +45,7 @@ runScript(async ({ pg }) => {
|
||||
console.log('before', comment.content)
|
||||
console.log('after', newContent)
|
||||
|
||||
await pg.none('update lover_comments set content = $1 where id = $2', [
|
||||
await pg.none('update profile_comments set content = $1 where id = $2', [
|
||||
newContent,
|
||||
comment.id,
|
||||
])
|
||||
|
||||
@@ -10,9 +10,9 @@ export const createLoveLikeNotification = async (like: Row<'love_likes'>) => {
|
||||
const { creator_id, target_id, like_id } = like
|
||||
|
||||
const targetPrivateUser = await getPrivateUser(target_id)
|
||||
const lover = await getProfile(creator_id)
|
||||
const profile = await getProfile(creator_id)
|
||||
|
||||
if (!targetPrivateUser || !lover) return
|
||||
if (!targetPrivateUser || !profile) return
|
||||
|
||||
const { sendToBrowser } = getNotificationDestinationsForUser(
|
||||
targetPrivateUser,
|
||||
@@ -30,9 +30,9 @@ export const createLoveLikeNotification = async (like: Row<'love_likes'>) => {
|
||||
sourceId: like_id,
|
||||
sourceType: 'love_like',
|
||||
sourceUpdateType: 'created',
|
||||
sourceUserName: lover.user.name,
|
||||
sourceUserUsername: lover.user.username,
|
||||
sourceUserAvatarUrl: lover.pinned_url ?? lover.user.avatarUrl,
|
||||
sourceUserName: profile.user.name,
|
||||
sourceUserUsername: profile.user.username,
|
||||
sourceUserAvatarUrl: profile.pinned_url ?? profile.user.avatarUrl,
|
||||
sourceText: '',
|
||||
}
|
||||
const pg = createSupabaseDirectClient()
|
||||
@@ -48,13 +48,13 @@ export const createLoveShipNotification = async (
|
||||
|
||||
const creator = await getUser(creator_id)
|
||||
const targetPrivateUser = await getPrivateUser(recipientId)
|
||||
const lover = await getProfile(otherTargetId)
|
||||
const profile = await getProfile(otherTargetId)
|
||||
|
||||
if (!creator || !targetPrivateUser || !lover) {
|
||||
if (!creator || !targetPrivateUser || !profile) {
|
||||
console.error('Could not load user object', {
|
||||
creator,
|
||||
targetPrivateUser,
|
||||
lover,
|
||||
profile,
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -75,9 +75,9 @@ export const createLoveShipNotification = async (
|
||||
sourceId: ship_id,
|
||||
sourceType: 'love_ship',
|
||||
sourceUpdateType: 'created',
|
||||
sourceUserName: lover.user.name,
|
||||
sourceUserUsername: lover.user.username,
|
||||
sourceUserAvatarUrl: lover.pinned_url ?? lover.user.avatarUrl,
|
||||
sourceUserName: profile.user.name,
|
||||
sourceUserUsername: profile.user.username,
|
||||
sourceUserAvatarUrl: profile.pinned_url ?? profile.user.avatarUrl,
|
||||
sourceText: '',
|
||||
data: {
|
||||
creatorId: creator_id,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { areGenderCompatible } from 'common/love/compatibility-util'
|
||||
import { type Profile, type ProfileRow } from 'common/love/lover'
|
||||
import { type Profile, type ProfileRow } from 'common/love/profile'
|
||||
import { type User } from 'common/user'
|
||||
import { Row } from 'common/supabase/utils'
|
||||
import { createSupabaseDirectClient } from 'shared/supabase/init'
|
||||
@@ -58,7 +58,7 @@ export const getProfiles = async (userIds: string[]) => {
|
||||
)
|
||||
}
|
||||
|
||||
export const getGenderCompatibleProfiles = async (lover: ProfileRow) => {
|
||||
export const getGenderCompatibleProfiles = async (profile: ProfileRow) => {
|
||||
const pg = createSupabaseDirectClient()
|
||||
const profiles = await pg.map(
|
||||
`
|
||||
@@ -74,14 +74,14 @@ export const getGenderCompatibleProfiles = async (lover: ProfileRow) => {
|
||||
and (data->>'userDeleted' != 'true' or data->>'userDeleted' is null)
|
||||
and profiles.pinned_url is not null
|
||||
`,
|
||||
{ ...lover },
|
||||
{ ...profile },
|
||||
convertRow
|
||||
)
|
||||
return profiles.filter((l: Profile) => areGenderCompatible(lover, l))
|
||||
return profiles.filter((l: Profile) => areGenderCompatible(profile, l))
|
||||
}
|
||||
|
||||
export const getCompatibleProfiles = async (
|
||||
lover: ProfileRow,
|
||||
profile: ProfileRow,
|
||||
radiusKm: number | undefined
|
||||
) => {
|
||||
const pg = createSupabaseDirectClient()
|
||||
@@ -111,7 +111,7 @@ export const getCompatibleProfiles = async (
|
||||
-- Location
|
||||
and calculate_earth_distance_km($(city_latitude), $(city_longitude), profiles.city_latitude, profiles.city_longitude) < $(radiusKm)
|
||||
`,
|
||||
{ ...lover, radiusKm: radiusKm ?? 40_000 },
|
||||
{ ...profile, radiusKm: radiusKm ?? 40_000 },
|
||||
convertRow
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ BEGIN;
|
||||
\i backend/supabase/private_user_messages.sql
|
||||
\i backend/supabase/private_user_seen_message_channels.sql
|
||||
\i backend/supabase/love_answers.sql
|
||||
\i backend/supabase/lover_comments.sql
|
||||
\i backend/supabase/profile_comments.sql
|
||||
\i backend/supabase/love_compatibility_answers.sql
|
||||
\i backend/supabase/love_likes.sql
|
||||
\i backend/supabase/love_questions.sql
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CREATE TABLE IF NOT EXISTS lover_comments (
|
||||
CREATE TABLE IF NOT EXISTS profile_comments (
|
||||
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
||||
content JSONB NOT NULL,
|
||||
created_time TIMESTAMPTZ DEFAULT now() NOT NULL,
|
||||
@@ -12,12 +12,12 @@ CREATE TABLE IF NOT EXISTS lover_comments (
|
||||
);
|
||||
|
||||
-- Row Level Security
|
||||
ALTER TABLE lover_comments ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE profile_comments ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Policies
|
||||
DROP POLICY IF EXISTS "public read" ON lover_comments;
|
||||
CREATE POLICY "public read" ON lover_comments FOR ALL USING (true);
|
||||
DROP POLICY IF EXISTS "public read" ON profile_comments;
|
||||
CREATE POLICY "public read" ON profile_comments FOR ALL USING (true);
|
||||
|
||||
-- Indexes
|
||||
CREATE INDEX IF NOT EXISTS lover_comments_user_id_idx
|
||||
ON public.lover_comments USING btree (on_user_id);
|
||||
CREATE INDEX IF NOT EXISTS profile_comments_user_id_idx
|
||||
ON public.profile_comments USING btree (on_user_id);
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'lover_visibility') THEN
|
||||
CREATE TYPE lover_visibility AS ENUM ('public', 'member');
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'profile_visibility') THEN
|
||||
CREATE TYPE profile_visibility AS ENUM ('public', 'member');
|
||||
END IF;
|
||||
END$$;
|
||||
|
||||
@@ -47,7 +47,7 @@ CREATE TABLE IF NOT EXISTS profiles (
|
||||
twitter TEXT,
|
||||
university TEXT,
|
||||
user_id TEXT NOT NULL,
|
||||
visibility lover_visibility DEFAULT 'member'::lover_visibility NOT NULL,
|
||||
visibility profile_visibility DEFAULT 'member'::profile_visibility NOT NULL,
|
||||
wants_kids_strength INTEGER DEFAULT 0 NOT NULL,
|
||||
website TEXT,
|
||||
CONSTRAINT profiles_pkey PRIMARY KEY (id)
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
import { PrivateChatMessage } from 'common/chat-message'
|
||||
import { CompatibilityScore } from 'common/love/compatibility-score'
|
||||
import { MAX_COMPATIBILITY_QUESTION_LENGTH } from 'common/love/constants'
|
||||
import { Profile, ProfileRow } from 'common/love/lover'
|
||||
import { Profile, ProfileRow } from 'common/love/profile'
|
||||
import { Row } from 'common/supabase/utils'
|
||||
import { PrivateUser, User } from 'common/user'
|
||||
import { z } from 'zod'
|
||||
@@ -88,7 +88,7 @@ export const API = (_apiTypeCheck = {
|
||||
})
|
||||
.strict(),
|
||||
},
|
||||
'create-lover': {
|
||||
'create-profile': {
|
||||
method: 'POST',
|
||||
authed: true,
|
||||
returns: {} as Row<'profiles'>,
|
||||
@@ -143,7 +143,7 @@ export const API = (_apiTypeCheck = {
|
||||
}),
|
||||
returns: {} as FullUser,
|
||||
},
|
||||
'update-lover': {
|
||||
'update-profile': {
|
||||
method: 'POST',
|
||||
authed: true,
|
||||
props: combinedLoveUsersSchema.partial(),
|
||||
@@ -217,9 +217,9 @@ export const API = (_apiTypeCheck = {
|
||||
authed: false,
|
||||
props: z.object({ userId: z.string() }),
|
||||
returns: {} as {
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
compatibleProfiles: Profile[]
|
||||
loverCompatibilityScores: {
|
||||
profileCompatibilityScores: {
|
||||
[userId: string]: CompatibilityScore
|
||||
}
|
||||
},
|
||||
@@ -246,7 +246,7 @@ export const API = (_apiTypeCheck = {
|
||||
})[]
|
||||
},
|
||||
},
|
||||
'like-lover': {
|
||||
'like-profile': {
|
||||
method: 'POST',
|
||||
authed: true,
|
||||
props: z.object({
|
||||
@@ -293,7 +293,7 @@ export const API = (_apiTypeCheck = {
|
||||
hasFreeLike: boolean
|
||||
},
|
||||
},
|
||||
'star-lover': {
|
||||
'star-profile': {
|
||||
method: 'POST',
|
||||
authed: true,
|
||||
props: z.object({
|
||||
@@ -334,7 +334,7 @@ export const API = (_apiTypeCheck = {
|
||||
profiles: Profile[]
|
||||
},
|
||||
},
|
||||
'get-lover-answers': {
|
||||
'get-profile-answers': {
|
||||
method: 'GET',
|
||||
authed: false,
|
||||
props: z.object({ userId: z.string() }).strict(),
|
||||
|
||||
@@ -11,8 +11,8 @@ export type Comment = {
|
||||
replyToCommentId?: string
|
||||
userId: string
|
||||
|
||||
// lover
|
||||
commentType: 'lover'
|
||||
// profile
|
||||
commentType: 'profile'
|
||||
onUserId: string
|
||||
|
||||
/** @deprecated - content now stored as JSON in content*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Profile, ProfileRow} from "common/love/lover";
|
||||
import {Profile, ProfileRow} from "common/love/profile";
|
||||
import {cloneDeep} from "lodash";
|
||||
import {filterDefined} from "common/util/array";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { keyBy, sumBy } from 'lodash'
|
||||
import { ProfileRow } from 'common/love/lover'
|
||||
import { ProfileRow } from 'common/love/profile'
|
||||
import { Row as rowFor } from 'common/supabase/utils'
|
||||
import {
|
||||
areAgeCompatible,
|
||||
@@ -133,13 +133,13 @@ export function getScoredAnswerCompatibility(
|
||||
}
|
||||
|
||||
export const getProfilesCompatibilityFactor = (
|
||||
lover1: ProfileRow,
|
||||
lover2: ProfileRow
|
||||
profile1: ProfileRow,
|
||||
profile2: ProfileRow
|
||||
) => {
|
||||
let multiplier = 1
|
||||
multiplier *= areAgeCompatible(lover1, lover2) ? 1 : 0.5
|
||||
multiplier *= areRelationshipStyleCompatible(lover1, lover2) ? 1 : 0.5
|
||||
multiplier *= areWantKidsCompatible(lover1, lover2) ? 1 : 0.5
|
||||
multiplier *= areLocationCompatible(lover1, lover2) ? 1 : 0.1
|
||||
multiplier *= areAgeCompatible(profile1, profile2) ? 1 : 0.5
|
||||
multiplier *= areRelationshipStyleCompatible(profile1, profile2) ? 1 : 0.5
|
||||
multiplier *= areWantKidsCompatible(profile1, profile2) ? 1 : 0.5
|
||||
multiplier *= areLocationCompatible(profile1, profile2) ? 1 : 0.1
|
||||
return multiplier
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ProfileRow } from 'common/love/lover'
|
||||
import { ProfileRow } from 'common/love/profile'
|
||||
import {MAX_INT, MIN_INT} from "common/constants";
|
||||
|
||||
const isPreferredGender = (
|
||||
@@ -18,53 +18,53 @@ const isPreferredGender = (
|
||||
return preferredGenders.includes(gender) || gender === 'non-binary'
|
||||
}
|
||||
|
||||
export const areGenderCompatible = (lover1: ProfileRow, lover2: ProfileRow) => {
|
||||
// console.log('areGenderCompatible', isPreferredGender(lover1.pref_gender, lover2.gender), isPreferredGender(lover2.pref_gender, lover1.gender))
|
||||
export const areGenderCompatible = (profile1: ProfileRow, profile2: ProfileRow) => {
|
||||
// console.log('areGenderCompatible', isPreferredGender(profile1.pref_gender, profile2.gender), isPreferredGender(profile2.pref_gender, profile1.gender))
|
||||
return (
|
||||
isPreferredGender(lover1.pref_gender, lover2.gender) &&
|
||||
isPreferredGender(lover2.pref_gender, lover1.gender)
|
||||
isPreferredGender(profile1.pref_gender, profile2.gender) &&
|
||||
isPreferredGender(profile2.pref_gender, profile1.gender)
|
||||
)
|
||||
}
|
||||
|
||||
const satisfiesAgeRange = (lover: ProfileRow, age: number | null | undefined) => {
|
||||
return (age ?? MAX_INT) >= (lover.pref_age_min ?? MIN_INT) && (age ?? MIN_INT) <= (lover.pref_age_max ?? MAX_INT)
|
||||
const satisfiesAgeRange = (profile: ProfileRow, age: number | null | undefined) => {
|
||||
return (age ?? MAX_INT) >= (profile.pref_age_min ?? MIN_INT) && (age ?? MIN_INT) <= (profile.pref_age_max ?? MAX_INT)
|
||||
}
|
||||
|
||||
export const areAgeCompatible = (lover1: ProfileRow, lover2: ProfileRow) => {
|
||||
export const areAgeCompatible = (profile1: ProfileRow, profile2: ProfileRow) => {
|
||||
return (
|
||||
satisfiesAgeRange(lover1, lover2.age) &&
|
||||
satisfiesAgeRange(lover2, lover1.age)
|
||||
satisfiesAgeRange(profile1, profile2.age) &&
|
||||
satisfiesAgeRange(profile2, profile1.age)
|
||||
)
|
||||
}
|
||||
|
||||
export const areLocationCompatible = (lover1: ProfileRow, lover2: ProfileRow) => {
|
||||
export const areLocationCompatible = (profile1: ProfileRow, profile2: ProfileRow) => {
|
||||
if (
|
||||
!lover1.city_latitude ||
|
||||
!lover2.city_latitude ||
|
||||
!lover1.city_longitude ||
|
||||
!lover2.city_longitude
|
||||
!profile1.city_latitude ||
|
||||
!profile2.city_latitude ||
|
||||
!profile1.city_longitude ||
|
||||
!profile2.city_longitude
|
||||
)
|
||||
return lover1.city.trim().toLowerCase() === lover2.city.trim().toLowerCase()
|
||||
return profile1.city.trim().toLowerCase() === profile2.city.trim().toLowerCase()
|
||||
|
||||
const latitudeDiff = Math.abs(lover1.city_latitude - lover2.city_latitude)
|
||||
const longigudeDiff = Math.abs(lover1.city_longitude - lover2.city_longitude)
|
||||
const latitudeDiff = Math.abs(profile1.city_latitude - profile2.city_latitude)
|
||||
const longigudeDiff = Math.abs(profile1.city_longitude - profile2.city_longitude)
|
||||
|
||||
const root = (latitudeDiff ** 2 + longigudeDiff ** 2) ** 0.5
|
||||
return root < 2.5
|
||||
}
|
||||
|
||||
export const areRelationshipStyleCompatible = (
|
||||
lover1: ProfileRow,
|
||||
lover2: ProfileRow
|
||||
profile1: ProfileRow,
|
||||
profile2: ProfileRow
|
||||
) => {
|
||||
return lover1.pref_relation_styles.some((style) =>
|
||||
lover2.pref_relation_styles.includes(style)
|
||||
return profile1.pref_relation_styles.some((style) =>
|
||||
profile2.pref_relation_styles.includes(style)
|
||||
)
|
||||
}
|
||||
|
||||
export const areWantKidsCompatible = (lover1: ProfileRow, lover2: ProfileRow) => {
|
||||
const { wants_kids_strength: kids1 } = lover1
|
||||
const { wants_kids_strength: kids2 } = lover2
|
||||
export const areWantKidsCompatible = (profile1: ProfileRow, profile2: ProfileRow) => {
|
||||
const { wants_kids_strength: kids1 } = profile1
|
||||
const { wants_kids_strength: kids2 } = profile2
|
||||
|
||||
if (kids1 === undefined || kids2 === undefined) return true
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { User } from 'common/user'
|
||||
import { ProfileRow } from 'common/love/lover'
|
||||
import { ProfileRow } from 'common/love/profile'
|
||||
import { buildOgUrl } from 'common/util/og'
|
||||
|
||||
// TODO: handle age, gender undefined better
|
||||
@@ -8,21 +8,21 @@ export type LoveOgProps = {
|
||||
avatarUrl: string
|
||||
username: string
|
||||
name: string
|
||||
// lover props
|
||||
// profile props
|
||||
age: string
|
||||
city: string
|
||||
gender: string
|
||||
}
|
||||
|
||||
export function getLoveOgImageUrl(user: User, lover?: ProfileRow | null) {
|
||||
export function getLoveOgImageUrl(user: User, profile?: ProfileRow | null) {
|
||||
const loveProps = {
|
||||
avatarUrl: lover?.pinned_url,
|
||||
avatarUrl: profile?.pinned_url,
|
||||
username: user.username,
|
||||
name: user.name,
|
||||
age: lover?.age?.toString() ?? '25',
|
||||
city: lover?.city ?? 'Internet',
|
||||
gender: lover?.gender ?? '???',
|
||||
age: profile?.age?.toString() ?? '25',
|
||||
city: profile?.city ?? 'Internet',
|
||||
gender: profile?.gender ?? '???',
|
||||
} as LoveOgProps
|
||||
|
||||
return buildOgUrl(loveProps, 'lover')
|
||||
return buildOgUrl(loveProps, 'profile')
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export type Notification = {
|
||||
|
||||
export const NOTIFICATION_TYPES_TO_SELECT = [
|
||||
'new_match', // new match markets
|
||||
'comment_on_lover', // endorsements
|
||||
'comment_on_profile', // endorsements
|
||||
'love_like',
|
||||
'love_ship',
|
||||
]
|
||||
|
||||
@@ -2,10 +2,10 @@ import { type JSONContent } from '@tiptap/core'
|
||||
import { type Row, tsToMillis } from './utils'
|
||||
import { type Comment } from 'common/comment'
|
||||
|
||||
export const convertComment = (row: Row<'lover_comments'>): Comment => ({
|
||||
export const convertComment = (row: Row<'profile_comments'>): Comment => ({
|
||||
id: row.id + '',
|
||||
userId: row.user_id,
|
||||
commentType: 'lover',
|
||||
commentType: 'profile',
|
||||
onUserId: row.on_user_id,
|
||||
createdTime: tsToMillis(row.created_time),
|
||||
userName: row.user_name,
|
||||
|
||||
@@ -221,7 +221,7 @@ export type Database = {
|
||||
}
|
||||
Relationships: []
|
||||
}
|
||||
lover_comments: {
|
||||
profile_comments: {
|
||||
Row: {
|
||||
content: Json
|
||||
created_time: string
|
||||
@@ -260,147 +260,6 @@ export type Database = {
|
||||
}
|
||||
Relationships: []
|
||||
}
|
||||
lovers: {
|
||||
Row: {
|
||||
age: number | null
|
||||
bio: Json | null
|
||||
bio_text: unknown | null
|
||||
born_in_location: string | null
|
||||
city: string
|
||||
city_latitude: number | null
|
||||
city_longitude: number | null
|
||||
comments_enabled: boolean
|
||||
company: string | null
|
||||
country: string | null
|
||||
created_time: string
|
||||
drinks_per_month: number | null
|
||||
education_level: string | null
|
||||
ethnicity: string[] | null
|
||||
gender: string
|
||||
geodb_city_id: string | null
|
||||
has_kids: number | null
|
||||
height_in_inches: number | null
|
||||
id: number
|
||||
is_smoker: boolean | null
|
||||
is_vegetarian_or_vegan: boolean | null
|
||||
last_modification_time: string
|
||||
last_online_time: string
|
||||
looking_for_matches: boolean
|
||||
messaging_status: string
|
||||
occupation: string | null
|
||||
occupation_title: string | null
|
||||
photo_urls: string[] | null
|
||||
pinned_url: string | null
|
||||
political_beliefs: string[] | null
|
||||
pref_age_max: number | null
|
||||
pref_age_min: number | null
|
||||
pref_gender: string[]
|
||||
pref_relation_styles: string[]
|
||||
referred_by_username: string | null
|
||||
region_code: string | null
|
||||
religious_belief_strength: number | null
|
||||
religious_beliefs: string | null
|
||||
twitter: string | null
|
||||
university: string | null
|
||||
user_id: string
|
||||
visibility: Database['public']['Enums']['lover_visibility']
|
||||
wants_kids_strength: number
|
||||
website: string | null
|
||||
}
|
||||
Insert: {
|
||||
age?: number | null
|
||||
bio?: Json | null
|
||||
bio_text?: unknown | null
|
||||
born_in_location?: string | null
|
||||
city: string
|
||||
city_latitude?: number | null
|
||||
city_longitude?: number | null
|
||||
comments_enabled?: boolean
|
||||
company?: string | null
|
||||
country?: string | null
|
||||
created_time?: string
|
||||
drinks_per_month?: number | null
|
||||
education_level?: string | null
|
||||
ethnicity?: string[] | null
|
||||
gender: string
|
||||
geodb_city_id?: string | null
|
||||
has_kids?: number | null
|
||||
height_in_inches?: number | null
|
||||
id?: never
|
||||
is_smoker?: boolean | null
|
||||
is_vegetarian_or_vegan?: boolean | null
|
||||
last_modification_time?: string
|
||||
last_online_time?: string
|
||||
looking_for_matches?: boolean
|
||||
messaging_status?: string
|
||||
occupation?: string | null
|
||||
occupation_title?: string | null
|
||||
photo_urls?: string[] | null
|
||||
pinned_url?: string | null
|
||||
political_beliefs?: string[] | null
|
||||
pref_age_max?: number | null
|
||||
pref_age_min?: number | null
|
||||
pref_gender: string[]
|
||||
pref_relation_styles: string[]
|
||||
referred_by_username?: string | null
|
||||
region_code?: string | null
|
||||
religious_belief_strength?: number | null
|
||||
religious_beliefs?: string | null
|
||||
twitter?: string | null
|
||||
university?: string | null
|
||||
user_id: string
|
||||
visibility?: Database['public']['Enums']['lover_visibility']
|
||||
wants_kids_strength?: number
|
||||
website?: string | null
|
||||
}
|
||||
Update: {
|
||||
age?: number | null
|
||||
bio?: Json | null
|
||||
bio_text?: unknown | null
|
||||
born_in_location?: string | null
|
||||
city?: string
|
||||
city_latitude?: number | null
|
||||
city_longitude?: number | null
|
||||
comments_enabled?: boolean
|
||||
company?: string | null
|
||||
country?: string | null
|
||||
created_time?: string
|
||||
drinks_per_month?: number | null
|
||||
education_level?: string | null
|
||||
ethnicity?: string[] | null
|
||||
gender?: string
|
||||
geodb_city_id?: string | null
|
||||
has_kids?: number | null
|
||||
height_in_inches?: number | null
|
||||
id?: never
|
||||
is_smoker?: boolean | null
|
||||
is_vegetarian_or_vegan?: boolean | null
|
||||
last_modification_time?: string
|
||||
last_online_time?: string
|
||||
looking_for_matches?: boolean
|
||||
messaging_status?: string
|
||||
occupation?: string | null
|
||||
occupation_title?: string | null
|
||||
photo_urls?: string[] | null
|
||||
pinned_url?: string | null
|
||||
political_beliefs?: string[] | null
|
||||
pref_age_max?: number | null
|
||||
pref_age_min?: number | null
|
||||
pref_gender?: string[]
|
||||
pref_relation_styles?: string[]
|
||||
referred_by_username?: string | null
|
||||
region_code?: string | null
|
||||
religious_belief_strength?: number | null
|
||||
religious_beliefs?: string | null
|
||||
twitter?: string | null
|
||||
university?: string | null
|
||||
user_id?: string
|
||||
visibility?: Database['public']['Enums']['lover_visibility']
|
||||
wants_kids_strength?: number
|
||||
website?: string | null
|
||||
}
|
||||
Relationships: []
|
||||
}
|
||||
private_user_message_channel_members: {
|
||||
Row: {
|
||||
channel_id: number
|
||||
@@ -584,7 +443,7 @@ export type Database = {
|
||||
twitter: string | null
|
||||
university: string | null
|
||||
user_id: string
|
||||
visibility: Database['public']['Enums']['lover_visibility']
|
||||
visibility: Database['public']['Enums']['profile_visibility']
|
||||
wants_kids_strength: number
|
||||
website: string | null
|
||||
}
|
||||
@@ -629,7 +488,7 @@ export type Database = {
|
||||
twitter?: string | null
|
||||
university?: string | null
|
||||
user_id: string
|
||||
visibility?: Database['public']['Enums']['lover_visibility']
|
||||
visibility?: Database['public']['Enums']['profile_visibility']
|
||||
wants_kids_strength?: number
|
||||
website?: string | null
|
||||
}
|
||||
@@ -674,7 +533,7 @@ export type Database = {
|
||||
twitter?: string | null
|
||||
university?: string | null
|
||||
user_id?: string
|
||||
visibility?: Database['public']['Enums']['lover_visibility']
|
||||
visibility?: Database['public']['Enums']['profile_visibility']
|
||||
wants_kids_strength?: number
|
||||
website?: string | null
|
||||
}
|
||||
@@ -834,10 +693,6 @@ export type Database = {
|
||||
Args: Record<PropertyKey, never>
|
||||
Returns: Record<string, unknown>[]
|
||||
}
|
||||
get_love_question_answers_and_lovers: {
|
||||
Args: { p_question_id: number }
|
||||
Returns: Record<string, unknown>[]
|
||||
}
|
||||
get_love_question_answers_and_profiles: {
|
||||
Args: { p_question_id: number }
|
||||
Returns: Record<string, unknown>[]
|
||||
@@ -900,7 +755,7 @@ export type Database = {
|
||||
}
|
||||
}
|
||||
Enums: {
|
||||
lover_visibility: 'public' | 'member'
|
||||
profile_visibility: 'public' | 'member'
|
||||
}
|
||||
CompositeTypes: {
|
||||
[_ in never]: never
|
||||
@@ -1028,7 +883,7 @@ export type CompositeTypes<
|
||||
export const Constants = {
|
||||
public: {
|
||||
Enums: {
|
||||
lover_visibility: ['public', 'member'],
|
||||
profile_visibility: ['public', 'member'],
|
||||
},
|
||||
},
|
||||
} as const
|
||||
|
||||
@@ -400,7 +400,7 @@ const { data, error } = await tryCatch(
|
||||
insert(pg, 'profiles', { user_id: auth.uid, ...body })
|
||||
)
|
||||
|
||||
if (error) throw APIError(500, 'Error creating lover: ' + error.message)
|
||||
if (error) throw APIError(500, 'Error creating profile: ' + error.message)
|
||||
|
||||
await update(pg, 'profiles', 'user_id', { user_id: auth.uid, age: 99 })
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ import {
|
||||
getAnswerCompatibility,
|
||||
getScoredAnswerCompatibility,
|
||||
} from 'common/love/compatibility-score'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import { Row as rowFor } from 'common/supabase/utils'
|
||||
import { User } from 'common/user'
|
||||
import { partition, sortBy, keyBy } from 'lodash'
|
||||
import { useProfile } from 'web/hooks/use-lover'
|
||||
import { useProfile } from 'web/hooks/use-profile'
|
||||
import {
|
||||
QuestionWithCountType,
|
||||
useCompatibilityQuestionsWithAnswerCount,
|
||||
@@ -25,7 +25,7 @@ import { Row } from 'web/components/layout/row'
|
||||
import { Linkify } from 'web/components/widgets/linkify'
|
||||
import { Pagination } from 'web/components/widgets/pagination'
|
||||
import { db } from 'web/lib/supabase/db'
|
||||
import { Subtitle } from '../widgets/lover-subtitle'
|
||||
import { Subtitle } from '../widgets/profile-subtitle'
|
||||
import { AddCompatibilityQuestionButton } from './add-compatibility-question-button'
|
||||
import {
|
||||
AnswerCompatibilityQuestionButton,
|
||||
@@ -81,11 +81,11 @@ type CompatibilitySort =
|
||||
export function CompatibilityQuestionsDisplay(props: {
|
||||
isCurrentUser: boolean
|
||||
user: User
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
fromSignup?: boolean
|
||||
fromProfilePage?: Profile
|
||||
}) {
|
||||
const { isCurrentUser, user, fromSignup, fromProfilePage, lover } = props
|
||||
const { isCurrentUser, user, fromSignup, fromProfilePage, profile } = props
|
||||
|
||||
const { refreshCompatibilityQuestions, compatibilityQuestions } =
|
||||
useCompatibilityQuestionsWithAnswerCount()
|
||||
@@ -223,7 +223,7 @@ export function CompatibilityQuestionsDisplay(props: {
|
||||
user={user}
|
||||
isCurrentUser={isCurrentUser}
|
||||
refreshCompatibilityAll={refreshCompatibilityAll}
|
||||
lover={lover}
|
||||
profile={profile}
|
||||
fromProfilePage={fromProfilePage}
|
||||
/>
|
||||
)
|
||||
@@ -314,7 +314,7 @@ function CompatibilityAnswerBlock(props: {
|
||||
yourQuestions: QuestionWithCountType[]
|
||||
user: User
|
||||
isCurrentUser: boolean
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
refreshCompatibilityAll: () => void
|
||||
fromProfilePage?: Profile
|
||||
}) {
|
||||
@@ -322,7 +322,7 @@ function CompatibilityAnswerBlock(props: {
|
||||
answer,
|
||||
yourQuestions,
|
||||
user,
|
||||
lover,
|
||||
profile,
|
||||
isCurrentUser,
|
||||
refreshCompatibilityAll,
|
||||
fromProfilePage,
|
||||
@@ -374,9 +374,9 @@ function CompatibilityAnswerBlock(props: {
|
||||
<div className="hidden sm:block">
|
||||
<CompatibilityDisplay
|
||||
question={question}
|
||||
lover1={lover}
|
||||
profile1={profile}
|
||||
answer1={answer}
|
||||
lover2={comparedProfile as Profile}
|
||||
profile2={comparedProfile as Profile}
|
||||
currentUserIsComparedProfile={!fromProfilePage}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
@@ -437,9 +437,9 @@ function CompatibilityAnswerBlock(props: {
|
||||
<Row className="w-full justify-end sm:hidden">
|
||||
<CompatibilityDisplay
|
||||
question={question}
|
||||
lover1={lover}
|
||||
profile1={profile}
|
||||
answer1={answer}
|
||||
lover2={comparedProfile as Profile}
|
||||
profile2={comparedProfile as Profile}
|
||||
currentUserIsComparedProfile={!fromProfilePage}
|
||||
currentUser={currentUser}
|
||||
/>
|
||||
@@ -476,8 +476,8 @@ function CompatibilityAnswerBlock(props: {
|
||||
|
||||
function CompatibilityDisplay(props: {
|
||||
question: QuestionWithCountType
|
||||
lover1: Profile
|
||||
lover2: Profile
|
||||
profile1: Profile
|
||||
profile2: Profile
|
||||
answer1: rowFor<'love_compatibility_answers'>
|
||||
currentUserIsComparedProfile: boolean
|
||||
currentUser: User | null | undefined
|
||||
@@ -485,8 +485,8 @@ function CompatibilityDisplay(props: {
|
||||
}) {
|
||||
const {
|
||||
question,
|
||||
lover1,
|
||||
lover2,
|
||||
profile1,
|
||||
profile2,
|
||||
answer1,
|
||||
currentUserIsComparedProfile,
|
||||
currentUser,
|
||||
@@ -499,7 +499,7 @@ function CompatibilityDisplay(props: {
|
||||
async function getComparedProfileAnswer() {
|
||||
db.from('love_compatibility_answers')
|
||||
.select()
|
||||
.eq('creator_id', lover2.user_id)
|
||||
.eq('creator_id', profile2.user_id)
|
||||
.eq('question_id', question.id)
|
||||
.then((res) => {
|
||||
if (res.error) {
|
||||
@@ -515,21 +515,21 @@ function CompatibilityDisplay(props: {
|
||||
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
if (lover1.id === lover2.id) return null
|
||||
if (profile1.id === profile2.id) return null
|
||||
|
||||
const showCreateAnswer =
|
||||
(!answer2 || answer2.importance == -1) &&
|
||||
currentUserIsComparedProfile &&
|
||||
!!currentUser
|
||||
|
||||
const isCurrentUser = currentUser?.id === lover2.user_id
|
||||
const isCurrentUser = currentUser?.id === profile2.user_id
|
||||
|
||||
const answerCompatibility = answer2
|
||||
? getAnswerCompatibility(answer1, answer2)
|
||||
: //getScoredAnswerCompatibility(answer1, answer2)
|
||||
undefined
|
||||
const user1 = lover1.user
|
||||
const user2 = lover2.user
|
||||
const user1 = profile1.user
|
||||
const user2 = profile2.user
|
||||
|
||||
const importanceScore = answer1.importance
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { IndividualQuestionRow } from '../questions-form'
|
||||
import { TbMessage } from 'react-icons/tb'
|
||||
import { OtherProfileAnswers } from './other-lover-answers'
|
||||
import { OtherProfileAnswers } from './other-profile-answers'
|
||||
import { ArrowLeftIcon } from '@heroicons/react/outline'
|
||||
import { usePersistentInMemoryState } from 'web/hooks/use-persistent-in-memory-state'
|
||||
|
||||
|
||||
@@ -10,14 +10,14 @@ import { Col } from 'web/components/layout/col'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { Linkify } from 'web/components/widgets/linkify'
|
||||
import { IndividualQuestionRow } from '../questions-form'
|
||||
import { Subtitle } from '../widgets/lover-subtitle'
|
||||
import { Subtitle } from '../widgets/profile-subtitle'
|
||||
import {
|
||||
QuestionWithCountType,
|
||||
useFRQuestionsWithAnswerCount,
|
||||
useUserAnswers,
|
||||
} from 'web/hooks/use-questions'
|
||||
import { TbMessage } from 'react-icons/tb'
|
||||
import { OtherProfileAnswers } from './other-lover-answers'
|
||||
import { OtherProfileAnswers } from './other-profile-answers'
|
||||
import {
|
||||
MODAL_CLASS,
|
||||
Modal,
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
import { partition } from 'lodash'
|
||||
import { shortenName } from 'web/components/widgets/user-link'
|
||||
import { AddQuestionButton } from './free-response-add-question'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
|
||||
export function FreeResponseDisplay(props: {
|
||||
isCurrentUser: boolean
|
||||
|
||||
@@ -8,7 +8,7 @@ import { capitalize, orderBy } from 'lodash'
|
||||
import { Button } from 'web/components/buttons/button'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { Subtitle } from '../widgets/lover-subtitle'
|
||||
import { Subtitle } from '../widgets/profile-subtitle'
|
||||
import { BiTachometer } from 'react-icons/bi'
|
||||
|
||||
export function OpinionScale(props: {
|
||||
|
||||
@@ -2,23 +2,23 @@ import { User } from 'common/user'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { CompatibilityQuestionsDisplay } from './compatibility-questions-display'
|
||||
import { FreeResponseDisplay } from './free-response-display'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
|
||||
export function ProfileAnswers(props: {
|
||||
isCurrentUser: boolean
|
||||
user: User
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
fromSignup?: boolean
|
||||
fromProfilePage?: Profile
|
||||
}) {
|
||||
const { isCurrentUser, user, fromSignup, fromProfilePage, lover } = props
|
||||
const { isCurrentUser, user, fromSignup, fromProfilePage, profile } = props
|
||||
|
||||
return (
|
||||
<Col className={'mt-2 gap-5'}>
|
||||
<CompatibilityQuestionsDisplay
|
||||
isCurrentUser={isCurrentUser}
|
||||
user={user}
|
||||
lover={lover}
|
||||
profile={profile}
|
||||
fromSignup={fromSignup}
|
||||
fromProfilePage={fromProfilePage}
|
||||
/>
|
||||
@@ -1,6 +1,6 @@
|
||||
import { JSONContent } from '@tiptap/core'
|
||||
import { MAX_DESCRIPTION_LENGTH } from 'common/envs/constants'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import { tryCatch } from 'common/util/try-catch'
|
||||
import { Button } from 'web/components/buttons/button'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
@@ -10,18 +10,18 @@ import { updateProfile } from 'web/lib/api'
|
||||
import { track } from 'web/lib/service/analytics'
|
||||
|
||||
export function EditableBio(props: {
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
onSave: () => void
|
||||
onCancel?: () => void
|
||||
}) {
|
||||
const { lover, onCancel, onSave } = props
|
||||
const { profile, onCancel, onSave } = props
|
||||
const editor = useTextEditor({
|
||||
max: MAX_DESCRIPTION_LENGTH,
|
||||
defaultValue: (lover.bio as JSONContent) ?? '',
|
||||
defaultValue: (profile.bio as JSONContent) ?? '',
|
||||
placeholder: "Tell us about yourself — and what you're looking for!",
|
||||
})
|
||||
|
||||
const hideButtons = editor?.getText().length === 0 && !lover.bio
|
||||
const hideButtons = editor?.getText().length === 0 && !profile.bio
|
||||
|
||||
const saveBio = async () => {
|
||||
if (!editor) return
|
||||
@@ -32,7 +32,7 @@ export function EditableBio(props: {
|
||||
return
|
||||
}
|
||||
|
||||
track('edited lover bio')
|
||||
track('edited profile bio')
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,7 +2,7 @@ import { PencilIcon, XIcon } from '@heroicons/react/outline'
|
||||
import { JSONContent } from '@tiptap/core'
|
||||
import clsx from 'clsx'
|
||||
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import DropdownMenu from 'web/components/comments/dropdown-menu'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
@@ -13,12 +13,12 @@ import { tryCatch } from 'common/util/try-catch'
|
||||
|
||||
export function BioBlock(props: {
|
||||
isCurrentUser: boolean
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
refreshProfile: () => void
|
||||
edit: boolean
|
||||
setEdit: (edit: boolean) => void
|
||||
}) {
|
||||
const { isCurrentUser, refreshProfile, lover, edit, setEdit } = props
|
||||
const { isCurrentUser, refreshProfile, profile, edit, setEdit } = props
|
||||
|
||||
return (
|
||||
<Col
|
||||
@@ -28,15 +28,15 @@ export function BioBlock(props: {
|
||||
)}
|
||||
>
|
||||
<Row className="w-full">
|
||||
{!edit && lover.bio && (
|
||||
{!edit && profile.bio && (
|
||||
<Col className="flex w-full flex-grow">
|
||||
<Content className="w-full" content={lover.bio as JSONContent} />
|
||||
<Content className="w-full" content={profile.bio as JSONContent} />
|
||||
</Col>
|
||||
)}
|
||||
{edit && (
|
||||
<EditableBio
|
||||
lover={lover}
|
||||
onCancel={lover.bio ? () => setEdit(false) : undefined}
|
||||
profile={profile}
|
||||
onCancel={profile.bio ? () => setEdit(false) : undefined}
|
||||
onSave={() => {
|
||||
refreshProfile()
|
||||
setEdit(false)
|
||||
@@ -1,29 +1,29 @@
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import { useState } from 'react'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { Subtitle } from '../widgets/lover-subtitle'
|
||||
import { BioBlock } from './lover-bio-block'
|
||||
import { Subtitle } from '../widgets/profile-subtitle'
|
||||
import { BioBlock } from './profile-bio-block'
|
||||
|
||||
export function ProfileBio(props: {
|
||||
isCurrentUser: boolean
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
refreshProfile: () => void
|
||||
fromProfilePage?: Profile
|
||||
}) {
|
||||
const { isCurrentUser, lover, refreshProfile, fromProfilePage } = props
|
||||
const { isCurrentUser, profile, refreshProfile, fromProfilePage } = props
|
||||
const [edit, setEdit] = useState(false)
|
||||
|
||||
if (!isCurrentUser && !lover.bio) return null
|
||||
if (fromProfilePage && !lover.bio) return null
|
||||
if (!isCurrentUser && !profile.bio) return null
|
||||
if (fromProfilePage && !profile.bio) return null
|
||||
|
||||
return (
|
||||
<Col>
|
||||
<Subtitle className="mb-4">About Me</Subtitle>
|
||||
<BioBlock
|
||||
isCurrentUser={isCurrentUser}
|
||||
lover={lover}
|
||||
profile={profile}
|
||||
refreshProfile={refreshProfile}
|
||||
edit={edit || (isCurrentUser && !lover.bio)}
|
||||
edit={edit || (isCurrentUser && !profile.bio)}
|
||||
setEdit={setEdit}
|
||||
/>
|
||||
</Col>
|
||||
@@ -4,7 +4,7 @@ import { useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
|
||||
import { MAX_COMMENT_LENGTH } from 'common/comment'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import { Button } from 'web/components/buttons/button'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { Modal, SCROLLABLE_MODAL_CLASS } from 'web/components/layout/modal'
|
||||
@@ -13,21 +13,21 @@ import { useTextEditor } from 'web/components/widgets/editor'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
import { CompatibilityScore } from 'common/love/compatibility-score'
|
||||
import { CompatibleBadge } from './widgets/compatible-badge'
|
||||
import { ProfileProfile } from './profile/lover-profile'
|
||||
import { ProfileProfile } from './profile/profile-profile'
|
||||
import { Pagination } from 'web/components/widgets/pagination'
|
||||
import { Title } from 'web/components/widgets/title'
|
||||
import { Input } from 'web/components/widgets/input'
|
||||
|
||||
export const BrowseMatchesButton = (props: {
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
potentialProfiles: Profile[]
|
||||
compatibilityScores: Record<string, CompatibilityScore>
|
||||
className?: string
|
||||
}) => {
|
||||
const { lover, potentialProfiles, compatibilityScores, className } = props
|
||||
const { profile, potentialProfiles, compatibilityScores, className } = props
|
||||
|
||||
const currentUser = useUser()
|
||||
const isCurrentUser = currentUser?.id === lover.user_id
|
||||
const isCurrentUser = currentUser?.id === profile.user_id
|
||||
|
||||
const [dialogOpen, setDialogOpen] = useState(false)
|
||||
const key = `comment ${potentialProfiles.map((l) => l.id).join(',')}`
|
||||
@@ -46,7 +46,7 @@ export const BrowseMatchesButton = (props: {
|
||||
|
||||
// setIsSubmitting(true)
|
||||
// const result = await createMatch({
|
||||
// userId1: lover.user_id,
|
||||
// userId1: profile.user_id,
|
||||
// userId2: selectedMatchId,
|
||||
// betAmount,
|
||||
// introduction,
|
||||
@@ -61,7 +61,7 @@ export const BrowseMatchesButton = (props: {
|
||||
// window.location.reload()
|
||||
// }
|
||||
}
|
||||
if (!lover.looking_for_matches)
|
||||
if (!profile.looking_for_matches)
|
||||
return (
|
||||
<div className="text-ink-500 text-sm">
|
||||
Not looking for more matches right now
|
||||
@@ -77,11 +77,11 @@ export const BrowseMatchesButton = (props: {
|
||||
disabled={isSubmitting}
|
||||
loading={isSubmitting}
|
||||
>
|
||||
Browse {isCurrentUser ? 'your compatible' : `for ${lover.user.name}`}
|
||||
Browse {isCurrentUser ? 'your compatible' : `for ${profile.user.name}`}
|
||||
</Button>
|
||||
{dialogOpen && (
|
||||
<BrowseMatchesDialog
|
||||
lover={lover}
|
||||
profile={profile}
|
||||
potentialProfiles={potentialProfiles}
|
||||
compatibilityScores={compatibilityScores}
|
||||
isSubmitting={isSubmitting}
|
||||
@@ -95,7 +95,7 @@ export const BrowseMatchesButton = (props: {
|
||||
}
|
||||
|
||||
const BrowseMatchesDialog = (props: {
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
potentialProfiles: Profile[]
|
||||
compatibilityScores: Record<string, CompatibilityScore>
|
||||
isSubmitting: boolean
|
||||
@@ -104,7 +104,7 @@ const BrowseMatchesDialog = (props: {
|
||||
editor: Editor | null
|
||||
}) => {
|
||||
const {
|
||||
lover,
|
||||
profile,
|
||||
potentialProfiles,
|
||||
compatibilityScores,
|
||||
isSubmitting,
|
||||
@@ -117,10 +117,10 @@ const BrowseMatchesDialog = (props: {
|
||||
const [error, setError] = useState<string | undefined>(undefined)
|
||||
|
||||
const currentUser = useUser()
|
||||
const isCurrentUser = currentUser?.id === lover.user_id
|
||||
const isCurrentUser = currentUser?.id === profile.user_id
|
||||
|
||||
const filteredProfiles = potentialProfiles.filter((lover) =>
|
||||
lover.user.name.toLowerCase().includes(query.toLowerCase())
|
||||
const filteredProfiles = potentialProfiles.filter((profile) =>
|
||||
profile.user.name.toLowerCase().includes(query.toLowerCase())
|
||||
)
|
||||
const [potentialIndex, setPotentialIndex] = useState(0)
|
||||
const index = Math.min(potentialIndex, filteredProfiles.length - 1)
|
||||
@@ -140,7 +140,7 @@ const BrowseMatchesDialog = (props: {
|
||||
<Col className="bg-canvas-0 min-h-full gap-2 rounded p-4 pb-8">
|
||||
<Row className="justify-between">
|
||||
<Title className="!mb-0">
|
||||
Browse {!isCurrentUser && `for ${lover.user.name}`}
|
||||
Browse {!isCurrentUser && `for ${profile.user.name}`}
|
||||
</Title>
|
||||
<Input
|
||||
className={'!h-10 max-w-[200px] self-end text-sm'}
|
||||
@@ -172,13 +172,13 @@ const BrowseMatchesDialog = (props: {
|
||||
<>
|
||||
<CompatibilityScoreDisplay compatibility={compatibility} />
|
||||
<ProfileProfile
|
||||
lover={potentialProfile}
|
||||
profile={potentialProfile}
|
||||
user={potentialProfile.user}
|
||||
refreshProfile={() => window.location.reload()}
|
||||
fromProfilePage={lover}
|
||||
fromProfilePage={profile}
|
||||
/>
|
||||
|
||||
{/* <Col key={lover.id} className={clsx('gap-4 px-3 py-2')}>
|
||||
{/* <Col key={profile.id} className={clsx('gap-4 px-3 py-2')}>
|
||||
<CommentInputTextArea
|
||||
isSubmitting={isSubmitting}
|
||||
editor={editor}
|
||||
|
||||
@@ -640,7 +640,7 @@
|
||||
"fountain": "26F2",
|
||||
"fountain_pen": "1F58B",
|
||||
"four": "0034 20E3",
|
||||
"four_leaf_clover": "1F340",
|
||||
"four_leaf_cprofile": "1F340",
|
||||
"fox_face": "1F98A",
|
||||
"fr": "1F1EB 1F1F7",
|
||||
"framed_picture": "1F5BC",
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
import { KidsLabel, wantsKidsLabelsWithIcon } from './wants-kids-filter'
|
||||
import { HasKidsLabel } from './has-kids-filter'
|
||||
import { MyMatchesToggle } from './my-matches-toggle'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import {FilterFields} from "common/filters";
|
||||
import {hasKidsLabels} from "common/has-kids";
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ import {Col} from 'web/components/layout/col'
|
||||
import {Slider} from 'web/components/widgets/slider'
|
||||
import {usePersistentInMemoryState} from 'web/hooks/use-persistent-in-memory-state'
|
||||
import {Row} from 'web/components/layout/row'
|
||||
import {City, CityRow, loverToCity, originToCity, useCitySearch,} from '../search-location'
|
||||
import {Profile} from 'common/love/lover'
|
||||
import {City, CityRow, profileToCity, originToCity, useCitySearch,} from '../search-location'
|
||||
import {Profile} from 'common/love/profile'
|
||||
import {useEffect, useState} from 'react'
|
||||
import {Input} from 'web/components/widgets/input'
|
||||
import {XIcon} from '@heroicons/react/solid'
|
||||
@@ -64,7 +64,7 @@ export function LocationFilter(props: {
|
||||
|
||||
const { location, setLocation, radius, setRadius } = props.locationFilterProps
|
||||
|
||||
const youCity = youProfile && loverToCity(youProfile)
|
||||
const youCity = youProfile && profileToCity(youProfile)
|
||||
|
||||
const [lastCity, setLastCity] = usePersistentInMemoryState<City>(
|
||||
location ? originToCity(location) : youCity || DEFAULT_LAST_CITY,
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
} from './wants-kids-filter'
|
||||
import { FaChild } from 'react-icons/fa6'
|
||||
import { MyMatchesToggle } from './my-matches-toggle'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import { Gender } from 'common/gender'
|
||||
import { RelationshipType } from 'web/lib/util/convert-relationship-type'
|
||||
import {FilterFields} from "common/filters";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import clsx from 'clsx'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
|
||||
export function MyMatchesToggle(props: {
|
||||
setYourFilters: (checked: boolean) => void
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Profile} from 'common/love/lover'
|
||||
import {Profile} from 'common/love/profile'
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {IoFilterSharp} from 'react-icons/io5'
|
||||
import {Button} from 'web/components/buttons/button'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Profile} from "common/love/lover";
|
||||
import {Profile} from "common/love/profile";
|
||||
import {useIsLooking} from "web/hooks/use-is-looking";
|
||||
import {usePersistentLocalState} from "web/hooks/use-persistent-local-state";
|
||||
import {useCallback} from "react";
|
||||
|
||||
@@ -18,8 +18,8 @@ import {useTracking} from 'web/hooks/use-tracking'
|
||||
import {useUser} from 'web/hooks/use-user'
|
||||
import {GoogleOneTapLogin} from 'web/lib/firebase/google-onetap-login'
|
||||
import Sidebar from './nav/love-sidebar'
|
||||
import {useProfile} from 'web/hooks/use-lover'
|
||||
import {Profile} from 'common/love/lover'
|
||||
import {useProfile} from 'web/hooks/use-profile'
|
||||
import {Profile} from 'common/love/profile'
|
||||
import {NotificationsIcon, SolidNotificationsIcon} from './notifications-icon'
|
||||
|
||||
export function LovePage(props: {
|
||||
@@ -40,9 +40,9 @@ export function LovePage(props: {
|
||||
} = props
|
||||
const user = useUser()
|
||||
const isMobile = useIsMobile()
|
||||
const lover = useProfile()
|
||||
const profile = useProfile()
|
||||
const bottomNavOptions = user
|
||||
? getBottomNavigation(user, lover)
|
||||
? getBottomNavigation(user, profile)
|
||||
: signedOutNavigation()
|
||||
// const [isModalOpen, setIsModalOpen] = useState(false)
|
||||
const desktopSidebarOptions = getDesktopNav(user)
|
||||
@@ -106,13 +106,13 @@ const Notifs = {name: 'Notifs', href: `/notifications`, icon: NotificationsIcon}
|
||||
const NotifsSolid = {name: 'Notifs', href: `/notifications`, icon: SolidNotificationsIcon};
|
||||
const Messages = {name: 'Messages', href: '/messages', icon: PrivateMessagesIcon};
|
||||
|
||||
function getBottomNavigation(user: User, lover: Profile | null | undefined) {
|
||||
function getBottomNavigation(user: User, profile: Profile | null | undefined) {
|
||||
return buildArray(
|
||||
Profiles,
|
||||
NotifsSolid,
|
||||
{
|
||||
name: 'Profile',
|
||||
href: lover === null ? '/signup' : `/${user.username}`,
|
||||
href: profile === null ? '/signup' : `/${user.username}`,
|
||||
icon: SolidHomeIcon,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { HeartIcon } from '@heroicons/react/solid'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import Image from 'next/image'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { UserIcon } from '@heroicons/react/solid'
|
||||
|
||||
@@ -12,7 +12,7 @@ import { useIsIframe } from 'web/hooks/use-is-iframe'
|
||||
import { trackCallback } from 'web/lib/service/analytics'
|
||||
import { User } from 'common/user'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { useProfile } from 'web/hooks/use-lover'
|
||||
import { useProfile } from 'web/hooks/use-profile'
|
||||
|
||||
const itemClass =
|
||||
'sm:hover:bg-ink-200 block w-full py-1 px-3 text-center sm:hover:text-primary-700 transition-colors'
|
||||
@@ -80,7 +80,7 @@ function ProfileItem(props: {
|
||||
track: () => void
|
||||
}) {
|
||||
const { user, item, touched, setTouched, currentPage, track } = props
|
||||
const lover = useProfile()
|
||||
const profile = useProfile()
|
||||
return (
|
||||
<Link
|
||||
href={item.href ?? '#'}
|
||||
@@ -98,7 +98,7 @@ function ProfileItem(props: {
|
||||
<Avatar
|
||||
size={'md'}
|
||||
username={user.username}
|
||||
avatarUrl={lover?.pinned_url ?? user.avatarUrl}
|
||||
avatarUrl={profile?.pinned_url ?? user.avatarUrl}
|
||||
noLink
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import clsx from 'clsx'
|
||||
import { useProfile } from 'web/hooks/use-lover'
|
||||
import { useProfile } from 'web/hooks/use-profile'
|
||||
import Link from 'next/link'
|
||||
import { Avatar } from 'web/components/widgets/avatar'
|
||||
import { User } from 'web/lib/firebase/users'
|
||||
@@ -8,11 +8,11 @@ import { trackCallback } from 'web/lib/service/analytics'
|
||||
export function ProfileSummary(props: { user: User; className?: string }) {
|
||||
const { user, className } = props
|
||||
|
||||
const lover = useProfile()
|
||||
const profile = useProfile()
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={lover === null ? '/signup' : `/${user.username}`}
|
||||
href={profile === null ? '/signup' : `/${user.username}`}
|
||||
onClick={trackCallback('sidebar: profile')}
|
||||
className={clsx(
|
||||
'hover:bg-ink-100 text-ink-700 group flex w-full shrink-0 flex-row items-center truncate rounded-md py-3',
|
||||
@@ -21,7 +21,7 @@ export function ProfileSummary(props: { user: User; className?: string }) {
|
||||
>
|
||||
<div className="w-2 shrink" />
|
||||
<Avatar
|
||||
avatarUrl={lover?.pinned_url ?? ''}
|
||||
avatarUrl={profile?.pinned_url ?? ''}
|
||||
username={user.username}
|
||||
noLink
|
||||
/>
|
||||
|
||||
@@ -15,7 +15,7 @@ import { Item, SidebarItem } from './love-sidebar-item'
|
||||
import SiteLogo from '../site-logo'
|
||||
import { Button, ColorType, SizeType } from 'web/components/buttons/button'
|
||||
import {signupRedirect} from 'web/lib/util/signup'
|
||||
import { useProfile } from 'web/hooks/use-lover'
|
||||
import { useProfile } from 'web/hooks/use-profile'
|
||||
import { useTheme } from 'web/hooks/use-theme'
|
||||
|
||||
export default function Sidebar(props: {
|
||||
@@ -28,7 +28,7 @@ export default function Sidebar(props: {
|
||||
const currentPage = router.pathname
|
||||
|
||||
const user = useUser()
|
||||
const lover = useProfile()
|
||||
const profile = useProfile()
|
||||
|
||||
const { theme, setTheme } = useTheme()
|
||||
|
||||
@@ -58,7 +58,7 @@ export default function Sidebar(props: {
|
||||
{user === null && <SignUpButton className="mt-4" text="Sign up" />}
|
||||
{/*{user === null && <SignUpAsMatchmaker className="mt-2" />}*/}
|
||||
|
||||
{user && lover === null && (
|
||||
{user && profile === null && (
|
||||
<Button className="mt-2" onClick={() => router.push('signup')}>
|
||||
Create a profile
|
||||
</Button>
|
||||
|
||||
@@ -26,7 +26,7 @@ export function NotificationItem(props: { notification: Notification }) {
|
||||
setHighlighted,
|
||||
}
|
||||
|
||||
if (sourceType === 'comment_on_lover') {
|
||||
if (sourceType === 'comment_on_profile') {
|
||||
return <CommentOnProfileNotification {...params} />
|
||||
} else if (sourceType === 'new_match') {
|
||||
return <NewMatchNotification {...params} />
|
||||
|
||||
@@ -16,7 +16,7 @@ import {track} from 'web/lib/service/analytics'
|
||||
import {Races} from './race'
|
||||
import {Carousel} from 'web/components/widgets/carousel'
|
||||
import {tryCatch} from 'common/util/try-catch'
|
||||
import {ProfileRow} from 'common/love/lover'
|
||||
import {ProfileRow} from 'common/love/profile'
|
||||
import {removeNullOrUndefinedProps} from 'common/util/object'
|
||||
import {isEqual, range} from 'lodash'
|
||||
import {PlatformSelect} from 'web/components/widgets/platform-select'
|
||||
@@ -24,7 +24,7 @@ import {PLATFORM_LABELS, type Site, SITE_ORDER} from 'common/socials'
|
||||
import {PlusIcon, XIcon} from '@heroicons/react/solid'
|
||||
import {SocialIcon} from './user/social'
|
||||
import {Select} from 'web/components/widgets/select'
|
||||
import {City, CityRow, loverToCity, useCitySearch} from "web/components/search-location";
|
||||
import {City, CityRow, profileToCity, useCitySearch} from "web/components/search-location";
|
||||
import {AddPhotosWidget} from './widgets/add-photos'
|
||||
import {RadioToggleGroup} from "web/components/widgets/radio-toggle-group";
|
||||
import {MultipleChoiceOptions} from "common/love/multiple-choice";
|
||||
@@ -32,26 +32,26 @@ import {RELATIONSHIP_CHOICES} from "web/components/filters/choices";
|
||||
import toast from "react-hot-toast";
|
||||
|
||||
export const OptionalLoveUserForm = (props: {
|
||||
lover: ProfileRow
|
||||
profile: ProfileRow
|
||||
setProfile: <K extends Column<'profiles'>>(key: K, value: ProfileRow[K]) => void
|
||||
user: User
|
||||
buttonLabel?: string
|
||||
fromSignup?: boolean
|
||||
onSubmit?: () => Promise<void>
|
||||
}) => {
|
||||
const {lover, user, buttonLabel, setProfile, fromSignup, onSubmit} = props
|
||||
const {profile, user, buttonLabel, setProfile, fromSignup, onSubmit} = props
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
||||
const [lookingRelationship, setLookingRelationship] = useState(false)
|
||||
const router = useRouter()
|
||||
const [heightFeet, setHeightFeet] = useState<number | undefined>(
|
||||
lover.height_in_inches
|
||||
? Math.floor((lover['height_in_inches'] ?? 0) / 12)
|
||||
profile.height_in_inches
|
||||
? Math.floor((profile['height_in_inches'] ?? 0) / 12)
|
||||
: undefined
|
||||
)
|
||||
const [heightInches, setHeightInches] = useState<number | undefined>(
|
||||
lover.height_in_inches
|
||||
? Math.floor((lover['height_in_inches'] ?? 0) % 12)
|
||||
profile.height_in_inches
|
||||
? Math.floor((profile['height_in_inches'] ?? 0) % 12)
|
||||
: undefined
|
||||
)
|
||||
|
||||
@@ -64,7 +64,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
|
||||
const handleSubmit = async () => {
|
||||
setIsSubmitting(true)
|
||||
const {bio: _, ...otherProfileProps} = lover
|
||||
const {bio: _, ...otherProfileProps} = profile
|
||||
const {error} = await tryCatch(
|
||||
updateProfile(removeNullOrUndefinedProps(otherProfileProps) as any)
|
||||
)
|
||||
@@ -105,7 +105,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
}
|
||||
|
||||
const [trans, setTrans] = useState<boolean | undefined>(
|
||||
lover['gender'].includes('trans')
|
||||
profile['gender'].includes('trans')
|
||||
)
|
||||
|
||||
function setProfileCity(inputCity: City | undefined) {
|
||||
@@ -135,7 +135,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const currentState = lover['gender']
|
||||
const currentState = profile['gender']
|
||||
if (currentState === 'non-binary') {
|
||||
setTrans(undefined)
|
||||
} else if (trans && !currentState.includes('trans-')) {
|
||||
@@ -143,7 +143,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
} else if (!trans && currentState.includes('trans-')) {
|
||||
setProfile('gender', currentState.replace('trans-', ''))
|
||||
}
|
||||
}, [trans, lover['gender']])
|
||||
}, [trans, profile['gender']])
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -164,10 +164,10 @@ export const OptionalLoveUserForm = (props: {
|
||||
|
||||
<Col className={clsx(colClassName)}>
|
||||
<label className={clsx(labelClassName)}>Location</label>
|
||||
{lover.city ? (
|
||||
{profile.city ? (
|
||||
<Row className="border-primary-500 w-full justify-between rounded border px-4 py-2">
|
||||
<CityRow
|
||||
city={loverToCity(lover)}
|
||||
city={profileToCity(profile)}
|
||||
onSelect={() => {
|
||||
}}
|
||||
className="pointer-events-none"
|
||||
@@ -195,7 +195,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="Age"
|
||||
value={lover['age'] ?? undefined}
|
||||
value={profile['age'] ?? undefined}
|
||||
min={18}
|
||||
max={100}
|
||||
onChange={(e) => setProfile('age', Number(e.target.value))}
|
||||
@@ -206,7 +206,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
<Col className={'gap-1'}>
|
||||
<label className={clsx(labelClassName)}>Gender</label>
|
||||
<ChoicesToggleGroup
|
||||
currentChoice={lover['gender'].replace('trans-', '')}
|
||||
currentChoice={profile['gender'].replace('trans-', '')}
|
||||
choicesMap={{
|
||||
Woman: 'female',
|
||||
Man: 'male',
|
||||
@@ -225,7 +225,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
Men: 'male',
|
||||
Other: 'other',
|
||||
}}
|
||||
selected={lover['pref_gender']}
|
||||
selected={profile['pref_gender']}
|
||||
onChange={(selected) => setProfile('pref_gender', selected)}
|
||||
/>
|
||||
</Col>
|
||||
@@ -236,7 +236,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
<Col>
|
||||
<span>Min</span>
|
||||
<Select
|
||||
value={lover['pref_age_min'] ?? ''}
|
||||
value={profile['pref_age_min'] ?? ''}
|
||||
onChange={(e) =>
|
||||
setProfile('pref_age_min', Number(e.target.value))
|
||||
}
|
||||
@@ -253,7 +253,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
<Col>
|
||||
<span>Max</span>
|
||||
<Select
|
||||
value={lover['pref_age_max'] ?? ''}
|
||||
value={profile['pref_age_max'] ?? ''}
|
||||
onChange={(e) =>
|
||||
setProfile('pref_age_max', Number(e.target.value))
|
||||
}
|
||||
@@ -274,7 +274,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
<label className={clsx(labelClassName)}>Connection type</label>
|
||||
<MultiCheckbox
|
||||
choices={RELATIONSHIP_CHOICES}
|
||||
selected={lover['pref_relation_styles']}
|
||||
selected={profile['pref_relation_styles']}
|
||||
onChange={(selected) =>
|
||||
setProfile('pref_relation_styles', selected)
|
||||
}
|
||||
@@ -359,7 +359,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
'Pause AI': 'pause ai',
|
||||
Other: 'other',
|
||||
}}
|
||||
selected={lover['political_beliefs'] ?? []}
|
||||
selected={profile['political_beliefs'] ?? []}
|
||||
onChange={(selected) => setProfile('political_beliefs', selected)}
|
||||
/>
|
||||
</Col>
|
||||
@@ -370,14 +370,14 @@ export const OptionalLoveUserForm = (props: {
|
||||
type="text"
|
||||
onChange={(e) => setProfile('religious_beliefs', e.target.value)}
|
||||
className={'w-full sm:w-96'}
|
||||
value={lover['religious_beliefs'] ?? undefined}
|
||||
value={profile['religious_beliefs'] ?? undefined}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
<Col className={clsx(colClassName)}>
|
||||
<label className={clsx(labelClassName)}>Do you smoke?</label>
|
||||
<ChoicesToggleGroup
|
||||
currentChoice={lover['is_smoker'] ?? undefined}
|
||||
currentChoice={profile['is_smoker'] ?? undefined}
|
||||
choicesMap={{
|
||||
Yes: true,
|
||||
No: false,
|
||||
@@ -399,7 +399,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
}}
|
||||
className={'w-20'}
|
||||
min={0}
|
||||
value={lover['drinks_per_month'] ?? undefined}
|
||||
value={profile['drinks_per_month'] ?? undefined}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
@@ -451,7 +451,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
type="text"
|
||||
onChange={(e) => setProfileState('born_in_location', e.target.value)}
|
||||
className={'w-52'}
|
||||
value={lover['born_in_location'] ?? undefined}
|
||||
value={profile['born_in_location'] ?? undefined}
|
||||
/>
|
||||
</Col> */}
|
||||
|
||||
@@ -459,7 +459,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
<label className={clsx(labelClassName)}>Ethnicity/origin</label>
|
||||
<MultiCheckbox
|
||||
choices={Races}
|
||||
selected={lover['ethnicity'] ?? []}
|
||||
selected={profile['ethnicity'] ?? []}
|
||||
onChange={(selected) => setProfile('ethnicity', selected)}
|
||||
/>
|
||||
</Col>
|
||||
@@ -470,7 +470,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
</label>
|
||||
<Carousel className="max-w-full">
|
||||
<ChoicesToggleGroup
|
||||
currentChoice={lover['education_level'] ?? ''}
|
||||
currentChoice={profile['education_level'] ?? ''}
|
||||
choicesMap={{
|
||||
None: 'none',
|
||||
'High school': 'high-school',
|
||||
@@ -489,7 +489,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
type="text"
|
||||
onChange={(e) => setProfile('university', e.target.value)}
|
||||
className={'w-52'}
|
||||
value={lover['university'] ?? undefined}
|
||||
value={profile['university'] ?? undefined}
|
||||
/>
|
||||
</Col>
|
||||
<Col className={clsx(colClassName)}>
|
||||
@@ -498,19 +498,19 @@ export const OptionalLoveUserForm = (props: {
|
||||
type="text"
|
||||
onChange={(e) => setProfile('company', e.target.value)}
|
||||
className={'w-52'}
|
||||
value={lover['company'] ?? undefined}
|
||||
value={profile['company'] ?? undefined}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
<Col className={clsx(colClassName)}>
|
||||
<label className={clsx(labelClassName)}>
|
||||
Job title {lover['company'] ? 'at ' + lover['company'] : ''}
|
||||
Job title {profile['company'] ? 'at ' + profile['company'] : ''}
|
||||
</label>
|
||||
<Input
|
||||
type="text"
|
||||
onChange={(e) => setProfile('occupation_title', e.target.value)}
|
||||
className={'w-52'}
|
||||
value={lover['occupation_title'] ?? undefined}
|
||||
value={profile['occupation_title'] ?? undefined}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
@@ -525,7 +525,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
}}
|
||||
className={'w-20'}
|
||||
min={0}
|
||||
value={lover['has_kids'] ?? undefined}
|
||||
value={profile['has_kids'] ?? undefined}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
@@ -549,7 +549,7 @@ export const OptionalLoveUserForm = (props: {
|
||||
setChoice={(choice) => {
|
||||
setProfile('wants_kids_strength', choice)
|
||||
}}
|
||||
currentChoice={lover.wants_kids_strength ?? -1}
|
||||
currentChoice={profile.wants_kids_strength ?? -1}
|
||||
/>
|
||||
</Col>
|
||||
</>}
|
||||
@@ -563,8 +563,8 @@ export const OptionalLoveUserForm = (props: {
|
||||
|
||||
<AddPhotosWidget
|
||||
user={user}
|
||||
photo_urls={lover.photo_urls}
|
||||
pinned_url={lover.pinned_url}
|
||||
photo_urls={profile.photo_urls}
|
||||
pinned_url={profile.pinned_url}
|
||||
setPhotoUrls={(urls) => setProfile('photo_urls', urls)}
|
||||
setPinnedUrl={(url) => setProfile('pinned_url', url)}
|
||||
/>
|
||||
@@ -28,7 +28,7 @@ import { Gender, convertGenderPlural } from 'common/gender'
|
||||
import { HiOutlineGlobe } from 'react-icons/hi'
|
||||
import { UserHandles } from 'web/components/user/user-handles'
|
||||
import { convertRace } from './race'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
|
||||
export function AboutRow(props: {
|
||||
icon: ReactNode
|
||||
@@ -54,48 +54,48 @@ export function AboutRow(props: {
|
||||
)
|
||||
}
|
||||
|
||||
export default function ProfileAbout(props: { lover: Profile }) {
|
||||
const { lover } = props
|
||||
export default function ProfileAbout(props: { profile: Profile }) {
|
||||
const { profile } = props
|
||||
return (
|
||||
<Col
|
||||
className={clsx('bg-canvas-0 relative gap-3 overflow-hidden rounded p-4')}
|
||||
>
|
||||
<Seeking lover={lover} />
|
||||
<RelationshipType lover={lover} />
|
||||
<HasKids lover={lover} />
|
||||
<Seeking profile={profile} />
|
||||
<RelationshipType profile={profile} />
|
||||
<HasKids profile={profile} />
|
||||
<AboutRow
|
||||
icon={<RiScales3Line className="h-5 w-5" />}
|
||||
text={lover.political_beliefs}
|
||||
text={profile.political_beliefs}
|
||||
/>
|
||||
<Education lover={lover} />
|
||||
<Occupation lover={lover} />
|
||||
<Education profile={profile} />
|
||||
<Occupation profile={profile} />
|
||||
<AboutRow
|
||||
icon={<PiHandsPrayingBold className="h-5 w-5" />}
|
||||
text={lover.religious_beliefs}
|
||||
text={profile.religious_beliefs}
|
||||
/>
|
||||
<AboutRow
|
||||
icon={<HiOutlineGlobe className="h-5 w-5" />}
|
||||
text={lover.ethnicity
|
||||
text={profile.ethnicity
|
||||
?.filter((r) => r !== 'other')
|
||||
?.map((r: any) => convertRace(r))}
|
||||
/>
|
||||
<Smoker lover={lover} />
|
||||
<Drinks lover={lover} />
|
||||
<Smoker profile={profile} />
|
||||
<Drinks profile={profile} />
|
||||
<AboutRow
|
||||
icon={<PiPlantBold className="h-5 w-5" />}
|
||||
text={lover.is_vegetarian_or_vegan ? 'Vegetarian/Vegan' : null}
|
||||
text={profile.is_vegetarian_or_vegan ? 'Vegetarian/Vegan' : null}
|
||||
/>
|
||||
<WantsKids lover={lover} />
|
||||
<UserHandles links={lover.user.link} />
|
||||
<WantsKids profile={profile} />
|
||||
<UserHandles links={profile.user.link} />
|
||||
</Col>
|
||||
)
|
||||
}
|
||||
|
||||
function Seeking(props: { lover: Profile }) {
|
||||
const { lover } = props
|
||||
const prefGender = lover.pref_gender
|
||||
const min = lover.pref_age_min
|
||||
const max = lover.pref_age_max
|
||||
function Seeking(props: { profile: Profile }) {
|
||||
const { profile } = props
|
||||
const prefGender = profile.pref_gender
|
||||
const min = profile.pref_age_min
|
||||
const max = profile.pref_age_max
|
||||
const seekingGenderText = stringOrStringArrayToText({
|
||||
text:
|
||||
prefGender.length == 5
|
||||
@@ -126,9 +126,9 @@ function Seeking(props: { lover: Profile }) {
|
||||
)
|
||||
}
|
||||
|
||||
function RelationshipType(props: { lover: Profile }) {
|
||||
const { lover } = props
|
||||
const relationshipTypes = lover.pref_relation_styles
|
||||
function RelationshipType(props: { profile: Profile }) {
|
||||
const { profile } = props
|
||||
const relationshipTypes = profile.pref_relation_styles
|
||||
const seekingGenderText = stringOrStringArrayToText({
|
||||
text: relationshipTypes.map((rel) =>
|
||||
convertRelationshipType(rel as RelationshipType).toLowerCase()
|
||||
@@ -149,10 +149,10 @@ function RelationshipType(props: { lover: Profile }) {
|
||||
)
|
||||
}
|
||||
|
||||
function Education(props: { lover: Profile }) {
|
||||
const { lover } = props
|
||||
const educationLevel = lover.education_level
|
||||
const university = lover.university
|
||||
function Education(props: { profile: Profile }) {
|
||||
const { profile } = props
|
||||
const educationLevel = profile.education_level
|
||||
const university = profile.university
|
||||
|
||||
const noUniversity =
|
||||
!educationLevel ||
|
||||
@@ -173,10 +173,10 @@ function Education(props: { lover: Profile }) {
|
||||
)
|
||||
}
|
||||
|
||||
function Occupation(props: { lover: Profile }) {
|
||||
const { lover } = props
|
||||
const occupation_title = lover.occupation_title
|
||||
const company = lover.company
|
||||
function Occupation(props: { profile: Profile }) {
|
||||
const { profile } = props
|
||||
const occupation_title = profile.occupation_title
|
||||
const company = profile.company
|
||||
|
||||
if (!company && !occupation_title) {
|
||||
return <></>
|
||||
@@ -194,9 +194,9 @@ function Occupation(props: { lover: Profile }) {
|
||||
)
|
||||
}
|
||||
|
||||
function Smoker(props: { lover: Profile }) {
|
||||
const { lover } = props
|
||||
const isSmoker = lover.is_smoker
|
||||
function Smoker(props: { profile: Profile }) {
|
||||
const { profile } = props
|
||||
const isSmoker = profile.is_smoker
|
||||
if (isSmoker == null) return null
|
||||
if (isSmoker) {
|
||||
return (
|
||||
@@ -211,9 +211,9 @@ function Smoker(props: { lover: Profile }) {
|
||||
)
|
||||
}
|
||||
|
||||
function Drinks(props: { lover: Profile }) {
|
||||
const { lover } = props
|
||||
const drinksPerMonth = lover.drinks_per_month
|
||||
function Drinks(props: { profile: Profile }) {
|
||||
const { profile } = props
|
||||
const drinksPerMonth = profile.drinks_per_month
|
||||
if (drinksPerMonth == null) return null
|
||||
if (drinksPerMonth === 0) {
|
||||
return (
|
||||
@@ -233,9 +233,9 @@ function Drinks(props: { lover: Profile }) {
|
||||
)
|
||||
}
|
||||
|
||||
function WantsKids(props: { lover: Profile }) {
|
||||
const { lover } = props
|
||||
const wantsKidsStrength = lover.wants_kids_strength
|
||||
function WantsKids(props: { profile: Profile }) {
|
||||
const { profile } = props
|
||||
const wantsKidsStrength = profile.wants_kids_strength
|
||||
if (wantsKidsStrength == null || wantsKidsStrength < 0) return null
|
||||
const wantsKidsText =
|
||||
wantsKidsStrength == 0
|
||||
@@ -256,11 +256,11 @@ function WantsKids(props: { lover: Profile }) {
|
||||
)
|
||||
}
|
||||
|
||||
function HasKids(props: { lover: Profile }) {
|
||||
const { lover } = props
|
||||
function HasKids(props: { profile: Profile }) {
|
||||
const { profile } = props
|
||||
const hasKidsText =
|
||||
lover.has_kids && lover.has_kids > 0
|
||||
? `Has ${lover.has_kids} ${lover.has_kids > 1 ? 'kids' : 'kid'}`
|
||||
profile.has_kids && profile.has_kids > 0
|
||||
? `Has ${profile.has_kids} ${profile.has_kids > 1 ? 'kids' : 'kid'}`
|
||||
: null
|
||||
return <AboutRow icon={<FaChild className="h-5 w-5" />} text={hasKidsText} />
|
||||
}
|
||||
@@ -7,7 +7,7 @@ import { Carousel } from 'web/components/widgets/carousel'
|
||||
import { MODAL_CLASS, Modal } from 'web/components/layout/modal'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { SignUpButton } from './nav/love-sidebar'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import { useAdmin } from 'web/hooks/use-admin'
|
||||
import { Button } from 'web/components/buttons/button'
|
||||
import { updateProfile } from 'web/lib/api'
|
||||
@@ -18,21 +18,21 @@ import { api } from 'web/lib/api'
|
||||
import { EditablePhotoGrid } from './widgets/editable-photo-grid'
|
||||
import { AddPhotosWidget } from './widgets/add-photos'
|
||||
|
||||
export default function ProfileCarousel(props: { lover: Profile }) {
|
||||
const { lover } = props
|
||||
const photoNums = lover.photo_urls ? lover.photo_urls.length : 0
|
||||
export default function ProfileCarousel(props: { profile: Profile }) {
|
||||
const { profile } = props
|
||||
const photoNums = profile.photo_urls ? profile.photo_urls.length : 0
|
||||
|
||||
const [lightboxUrl, setLightboxUrl] = useState('')
|
||||
const [lightboxOpen, setLightboxOpen] = useState(false)
|
||||
const [isEditMode, setIsEditMode] = useState(false)
|
||||
const [addPhotosOpen, setAddPhotosOpen] = useState(false)
|
||||
|
||||
const [pinnedUrl, setPinnedUrl] = useState<string | null>(lover.pinned_url)
|
||||
const [photoUrls, setPhotoUrls] = useState<string[]>(lover.photo_urls ?? [])
|
||||
const [pinnedUrl, setPinnedUrl] = useState<string | null>(profile.pinned_url)
|
||||
const [photoUrls, setPhotoUrls] = useState<string[]>(profile.photo_urls ?? [])
|
||||
|
||||
const isAdmin = useAdmin()
|
||||
const currentUser = useUser()
|
||||
const isCurrentUser = currentUser?.id === lover.user_id
|
||||
const isCurrentUser = currentUser?.id === profile.user_id
|
||||
|
||||
const handleSaveChanges = async () => {
|
||||
await updateProfile({
|
||||
@@ -42,14 +42,14 @@ export default function ProfileCarousel(props: { lover: Profile }) {
|
||||
setIsEditMode(false)
|
||||
}
|
||||
|
||||
if (!currentUser && lover.visibility !== 'public') {
|
||||
if (!currentUser && profile.visibility !== 'public') {
|
||||
return (
|
||||
<Carousel>
|
||||
{lover.pinned_url && (
|
||||
{profile.pinned_url && (
|
||||
<div className="h-80 w-[250px] flex-none snap-start">
|
||||
<Image
|
||||
priority={true}
|
||||
src={lover.pinned_url}
|
||||
src={profile.pinned_url}
|
||||
height={360}
|
||||
width={240}
|
||||
sizes="(max-width: 640px) 100vw, 240px"
|
||||
@@ -83,7 +83,7 @@ export default function ProfileCarousel(props: { lover: Profile }) {
|
||||
size="sm"
|
||||
color="red"
|
||||
onClick={() => {
|
||||
api('remove-pinned-photo', { userId: lover.user_id }).then(() =>
|
||||
api('remove-pinned-photo', { userId: profile.user_id }).then(() =>
|
||||
Router.back()
|
||||
)
|
||||
}}
|
||||
@@ -105,8 +105,8 @@ export default function ProfileCarousel(props: { lover: Profile }) {
|
||||
<Button
|
||||
onClick={() => {
|
||||
// TODO this is stale if you've saved
|
||||
setPhotoUrls(lover.photo_urls ?? [])
|
||||
setPinnedUrl(lover.pinned_url)
|
||||
setPhotoUrls(profile.photo_urls ?? [])
|
||||
setPinnedUrl(profile.pinned_url)
|
||||
setIsEditMode(false)
|
||||
}}
|
||||
color="gray-outline"
|
||||
@@ -164,7 +164,7 @@ export default function ProfileCarousel(props: { lover: Profile }) {
|
||||
</Col>
|
||||
) : (
|
||||
<Carousel>
|
||||
{buildArray(lover.pinned_url, lover.photo_urls).map((url, i) => (
|
||||
{buildArray(profile.pinned_url, profile.photo_urls).map((url, i) => (
|
||||
<div key={url} className="h-80 w-[250px] flex-none snap-start">
|
||||
<Image
|
||||
priority={i < 3}
|
||||
@@ -181,7 +181,7 @@ export default function ProfileCarousel(props: { lover: Profile }) {
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
{isCurrentUser && (lover.photo_urls?.length ?? 0) > 1 && (
|
||||
{isCurrentUser && (profile.photo_urls?.length ?? 0) > 1 && (
|
||||
<button
|
||||
className="bg-ink-200 text-ink-0 group flex h-80 w-[250px] flex-none cursor-pointer snap-start items-center justify-center rounded ease-in-out"
|
||||
onClick={() => setAddPhotosOpen(true)}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { groupBy, orderBy } from 'lodash'
|
||||
import { useLiveCommentsOnProfile } from 'web/hooks/use-comments-on-lover'
|
||||
import { useLiveCommentsOnProfile } from 'web/hooks/use-comments-on-profile'
|
||||
import {
|
||||
ProfileCommentInput,
|
||||
ProfileProfileCommentThread,
|
||||
} from 'web/components/lover-comments'
|
||||
} from 'web/components/profile-comments'
|
||||
import { User } from 'common/user'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import ShortToggle from 'web/components/widgets/short-toggle'
|
||||
@@ -12,12 +12,12 @@ import { useState } from 'react'
|
||||
import { updateProfile } from 'web/lib/api'
|
||||
import { Tooltip } from 'web/components/widgets/tooltip'
|
||||
import { toast } from 'react-hot-toast'
|
||||
import { Subtitle } from './widgets/lover-subtitle'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Subtitle } from './widgets/profile-subtitle'
|
||||
import { Profile } from 'common/love/profile'
|
||||
|
||||
export const ProfileCommentSection = (props: {
|
||||
onUser: User
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
currentUser: User | null | undefined
|
||||
simpleView?: boolean
|
||||
}) => {
|
||||
@@ -25,10 +25,10 @@ export const ProfileCommentSection = (props: {
|
||||
const comments = useLiveCommentsOnProfile(onUser.id).filter((c) => !c.hidden)
|
||||
const parentComments = comments.filter((c) => !c.replyToCommentId)
|
||||
const commentsByParent = groupBy(comments, (c) => c.replyToCommentId ?? '_')
|
||||
const [lover, setProfile] = useState<Profile>(props.lover)
|
||||
const [profile, setProfile] = useState<Profile>(props.profile)
|
||||
const isCurrentUser = currentUser?.id === onUser.id
|
||||
|
||||
if (simpleView && (!lover.comments_enabled || parentComments.length == 0))
|
||||
if (simpleView && (!profile.comments_enabled || parentComments.length == 0))
|
||||
return null
|
||||
|
||||
return (
|
||||
@@ -38,12 +38,12 @@ export const ProfileCommentSection = (props: {
|
||||
{isCurrentUser && !simpleView && (
|
||||
<Tooltip
|
||||
text={
|
||||
(lover.comments_enabled ? 'Disable' : 'Enable') +
|
||||
(profile.comments_enabled ? 'Disable' : 'Enable') +
|
||||
' endorsements from others'
|
||||
}
|
||||
>
|
||||
<ShortToggle
|
||||
on={lover.comments_enabled}
|
||||
on={profile.comments_enabled}
|
||||
setOn={(on) => {
|
||||
const update = { comments_enabled: on }
|
||||
setProfile((l) => ({ ...l, ...update }))
|
||||
@@ -63,7 +63,7 @@ export const ProfileCommentSection = (props: {
|
||||
</Row>
|
||||
{!simpleView && (
|
||||
<>
|
||||
{lover.comments_enabled && (
|
||||
{profile.comments_enabled && (
|
||||
<>
|
||||
<div className="mb-4">
|
||||
{isCurrentUser ? (
|
||||
@@ -84,7 +84,7 @@ export const ProfileCommentSection = (props: {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{!lover.comments_enabled &&
|
||||
{!profile.comments_enabled &&
|
||||
(isCurrentUser ? (
|
||||
<span className={'text-ink-500 text-sm'}>
|
||||
This feature is disabled
|
||||
@@ -96,7 +96,7 @@ export const ProfileCommentSection = (props: {
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{lover.comments_enabled &&
|
||||
{profile.comments_enabled &&
|
||||
orderBy(parentComments, 'createdTime', 'desc').map((c) => (
|
||||
<ProfileProfileCommentThread
|
||||
key={c.id + 'thread'}
|
||||
@@ -29,7 +29,7 @@ import { api } from 'web/lib/api'
|
||||
import { RelativeTimestamp } from 'web/components/relative-timestamp'
|
||||
import { useAdmin } from 'web/hooks/use-admin'
|
||||
import { EyeOffIcon } from '@heroicons/react/outline'
|
||||
import { useProfileByUserId } from 'web/hooks/use-lover'
|
||||
import { useProfileByUserId } from 'web/hooks/use-profile'
|
||||
import { MAX_COMMENT_LENGTH, ReplyToUserInfo } from 'common/comment'
|
||||
import { safeLocalStorage } from 'web/lib/util/local'
|
||||
|
||||
@@ -158,7 +158,7 @@ const ProfileComment = memo(function FeedComment(props: {
|
||||
const [comment, setComment] = useState(props.comment)
|
||||
const { userUsername, userAvatarUrl, userId, hidden } = comment
|
||||
const isOwner = onUser.id === userId
|
||||
const lover = useProfileByUserId(userId)
|
||||
const profile = useProfileByUserId(userId)
|
||||
|
||||
useEffect(() => {
|
||||
if (highlighted && ref.current) {
|
||||
@@ -176,7 +176,7 @@ const ProfileComment = memo(function FeedComment(props: {
|
||||
<Avatar
|
||||
username={userUsername}
|
||||
size={isParent ? 'sm' : '2xs'}
|
||||
avatarUrl={lover?.pinned_url ?? userAvatarUrl}
|
||||
avatarUrl={profile?.pinned_url ?? userAvatarUrl}
|
||||
className={clsx(isOwner && 'shadow shadow-amber-300', 'z-10')}
|
||||
/>
|
||||
<div
|
||||
@@ -1,4 +1,4 @@
|
||||
import {Profile} from 'common/love/lover'
|
||||
import {Profile} from 'common/love/profile'
|
||||
import {CompatibilityScore} from 'common/love/compatibility-score'
|
||||
import {LoadingIndicator} from 'web/components/widgets/loading-indicator'
|
||||
import {LoadMoreUntilNotVisible} from 'web/components/widgets/visibility-observer'
|
||||
@@ -34,7 +34,7 @@ export const ProfileGrid = (props: {
|
||||
|
||||
const user = useUser()
|
||||
|
||||
const other_profiles = profiles.filter((lover) => lover.user_id !== user?.id);
|
||||
const other_profiles = profiles.filter((profile) => profile.user_id !== user?.id);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
@@ -45,12 +45,12 @@ export const ProfileGrid = (props: {
|
||||
)}
|
||||
>
|
||||
{other_profiles
|
||||
.map((lover) => (
|
||||
.map((profile) => (
|
||||
<ProfilePreview
|
||||
key={lover.id}
|
||||
lover={lover}
|
||||
compatibilityScore={compatibilityScores?.[lover.user_id]}
|
||||
hasStar={starredUserIds?.includes(lover.user_id) ?? false}
|
||||
key={profile.id}
|
||||
profile={profile}
|
||||
compatibilityScore={compatibilityScores?.[profile.user_id]}
|
||||
hasStar={starredUserIds?.includes(profile.user_id) ?? false}
|
||||
refreshStars={refreshStars}
|
||||
/>
|
||||
))}
|
||||
@@ -75,13 +75,13 @@ export const ProfileGrid = (props: {
|
||||
}
|
||||
|
||||
function ProfilePreview(props: {
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
compatibilityScore: CompatibilityScore | undefined
|
||||
hasStar: boolean
|
||||
refreshStars: () => Promise<void>
|
||||
}) {
|
||||
const {lover, compatibilityScore} = props
|
||||
const {user} = lover
|
||||
const {profile, compatibilityScore} = props
|
||||
const {user} = profile
|
||||
// const currentUser = useUser()
|
||||
|
||||
return (
|
||||
@@ -115,7 +115,7 @@ function ProfilePreview(props: {
|
||||
{/* className="!pt-0"*/}
|
||||
{/* isStarred={hasStar}*/}
|
||||
{/* refresh={refreshStars}*/}
|
||||
{/* targetProfile={lover}*/}
|
||||
{/* targetProfile={profile}*/}
|
||||
{/* hideTooltip*/}
|
||||
{/* />*/}
|
||||
{/* ) : (*/}
|
||||
@@ -135,7 +135,7 @@ function ProfilePreview(props: {
|
||||
</h3>
|
||||
<div className="text-sm text-gray-500 dark:text-gray-400">
|
||||
{/*TODO: fix nested <a> links warning (one from Link above, one from link in bio below)*/}
|
||||
<Content className="w-full line-clamp-4" content={lover.bio as JSONContent}/>
|
||||
<Content className="w-full line-clamp-4" content={profile.bio as JSONContent}/>
|
||||
</div>
|
||||
{/*{age}*/}
|
||||
</div>
|
||||
|
||||
@@ -6,30 +6,30 @@ import { MdHeight } from 'react-icons/md'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import GenderIcon from '../gender-icon'
|
||||
import { Gender, convertGender } from 'common/gender'
|
||||
import { formatProfileValue } from '../lover-about'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { formatProfileValue } from '../profile-about'
|
||||
import { Profile } from 'common/love/profile'
|
||||
|
||||
export default function ProfilePrimaryInfo(props: { lover: Profile }) {
|
||||
const { lover } = props
|
||||
export default function ProfilePrimaryInfo(props: { profile: Profile }) {
|
||||
const { profile } = props
|
||||
const stateOrCountry =
|
||||
lover.country === 'United States of America'
|
||||
? lover.region_code
|
||||
: lover.country
|
||||
profile.country === 'United States of America'
|
||||
? profile.region_code
|
||||
: profile.country
|
||||
return (
|
||||
<Row className="text-ink-700 gap-4 text-sm">
|
||||
<IconWithInfo
|
||||
text={`${lover.city ?? ''}, ${stateOrCountry ?? ''}`}
|
||||
text={`${profile.city ?? ''}, ${stateOrCountry ?? ''}`}
|
||||
icon={<IoLocationOutline className="h-4 w-4" />}
|
||||
/>
|
||||
<IconWithInfo
|
||||
text={capitalize(convertGender(lover.gender as Gender))}
|
||||
text={capitalize(convertGender(profile.gender as Gender))}
|
||||
icon={
|
||||
<GenderIcon gender={lover.gender as Gender} className="h-4 w-4 " />
|
||||
<GenderIcon gender={profile.gender as Gender} className="h-4 w-4 " />
|
||||
}
|
||||
/>
|
||||
{lover.height_in_inches != null && (
|
||||
{profile.height_in_inches != null && (
|
||||
<IconWithInfo
|
||||
text={formatProfileValue('height_in_inches', lover.height_in_inches)}
|
||||
text={formatProfileValue('height_in_inches', profile.height_in_inches)}
|
||||
icon={<MdHeight className="h-4 w-4 " />}
|
||||
/>
|
||||
)}
|
||||
@@ -8,12 +8,12 @@ import {MoreOptionsUserButton} from 'web/components/buttons/more-options-user-bu
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {Row} from 'web/components/layout/row'
|
||||
import {SendMessageButton} from 'web/components/messaging/send-message-button'
|
||||
import ProfilePrimaryInfo from './lover-primary-info'
|
||||
import ProfilePrimaryInfo from './profile-primary-info'
|
||||
import {OnlineIcon} from '../online-icon'
|
||||
import {track} from 'web/lib/service/analytics'
|
||||
import DropdownMenu from 'web/components/comments/dropdown-menu'
|
||||
import {ShareProfileButton} from '../widgets/share-profile-button'
|
||||
import {Profile} from 'common/love/lover'
|
||||
import {Profile} from 'common/love/profile'
|
||||
import {useUser} from 'web/hooks/use-user'
|
||||
import {linkClass} from 'web/components/widgets/site-link'
|
||||
import {StarButton} from '../widgets/star-button'
|
||||
@@ -23,7 +23,7 @@ import {VisibilityConfirmationModal} from './visibility-confirmation-modal'
|
||||
|
||||
export default function ProfileProfileHeader(props: {
|
||||
user: User
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
simpleView?: boolean
|
||||
starredUserIds: string[]
|
||||
refreshStars: () => Promise<void>
|
||||
@@ -32,7 +32,7 @@ export default function ProfileProfileHeader(props: {
|
||||
}) {
|
||||
const {
|
||||
user,
|
||||
lover,
|
||||
profile,
|
||||
simpleView,
|
||||
starredUserIds,
|
||||
refreshStars,
|
||||
@@ -43,7 +43,7 @@ export default function ProfileProfileHeader(props: {
|
||||
const isCurrentUser = currentUser?.id === user.id
|
||||
const [showVisibilityModal, setShowVisibilityModal] = useState(false)
|
||||
|
||||
console.log('ProfileProfileHeader', {user, lover, currentUser})
|
||||
console.log('ProfileProfileHeader', {user, profile, currentUser})
|
||||
|
||||
return (
|
||||
<Col className="w-full">
|
||||
@@ -51,7 +51,7 @@ export default function ProfileProfileHeader(props: {
|
||||
<Row className="items-center gap-1">
|
||||
<Col className="gap-1">
|
||||
<Row className="items-center gap-1 text-xl">
|
||||
<OnlineIcon last_online_time={lover.last_online_time}/>
|
||||
<OnlineIcon last_online_time={profile.last_online_time}/>
|
||||
<span>
|
||||
{simpleView ? (
|
||||
<Link className={linkClass} href={`/${user.username}`}>
|
||||
@@ -60,10 +60,10 @@ export default function ProfileProfileHeader(props: {
|
||||
) : (
|
||||
<span className="font-semibold">{user.name}</span>
|
||||
)}
|
||||
, {lover.age}
|
||||
, {profile.age}
|
||||
</span>
|
||||
</Row>
|
||||
<ProfilePrimaryInfo lover={lover}/>
|
||||
<ProfilePrimaryInfo profile={profile}/>
|
||||
</Col>
|
||||
</Row>
|
||||
{currentUser && isCurrentUser ? (
|
||||
@@ -91,11 +91,11 @@ export default function ProfileProfileHeader(props: {
|
||||
items={[
|
||||
{
|
||||
name:
|
||||
lover.visibility === 'member'
|
||||
profile.visibility === 'member'
|
||||
? 'List Profile Publicly'
|
||||
: 'Limit to Members Only',
|
||||
icon:
|
||||
lover.visibility === 'member' ? (
|
||||
profile.visibility === 'member' ? (
|
||||
<EyeIcon className="h-4 w-4"/>
|
||||
) : (
|
||||
<LockClosedIcon className="h-4 w-4"/>
|
||||
@@ -129,7 +129,7 @@ export default function ProfileProfileHeader(props: {
|
||||
/>
|
||||
{currentUser && (
|
||||
<StarButton
|
||||
targetProfile={lover}
|
||||
targetProfile={profile}
|
||||
isStarred={starredUserIds.includes(user.id)}
|
||||
refresh={refreshStars}
|
||||
/>
|
||||
@@ -149,10 +149,10 @@ export default function ProfileProfileHeader(props: {
|
||||
<VisibilityConfirmationModal
|
||||
open={showVisibilityModal}
|
||||
setOpen={setShowVisibilityModal}
|
||||
currentVisibility={lover.visibility}
|
||||
currentVisibility={profile.visibility}
|
||||
onConfirm={async () => {
|
||||
const newVisibility =
|
||||
lover.visibility === 'member' ? 'public' : 'member'
|
||||
profile.visibility === 'member' ? 'public' : 'member'
|
||||
await updateProfile({visibility: newVisibility})
|
||||
refreshProfile()
|
||||
}}
|
||||
@@ -1,17 +1,17 @@
|
||||
import {ProfileCommentSection} from 'web/components/lover-comment-section'
|
||||
import ProfileProfileHeader from 'web/components/profile/lover-profile-header'
|
||||
import {ProfileCommentSection} from 'web/components/profile-comment-section'
|
||||
import ProfileProfileHeader from 'web/components/profile/profile-profile-header'
|
||||
import ProfileCarousel from 'web/components/profile-carousel'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {Row} from 'web/components/layout/row'
|
||||
import {useUser} from 'web/hooks/use-user'
|
||||
import {User} from 'web/lib/firebase/users'
|
||||
import ProfileAbout from 'web/components/lover-about'
|
||||
import {ProfileAnswers} from 'web/components/answers/lover-answers'
|
||||
import ProfileAbout from 'web/components/profile-about'
|
||||
import {ProfileAnswers} from 'web/components/answers/profile-answers'
|
||||
import {SignUpButton} from 'web/components/nav/love-sidebar'
|
||||
import {Profile} from 'common/love/lover'
|
||||
import {ProfileBio} from 'web/components/bio/lover-bio'
|
||||
import {Profile} from 'common/love/profile'
|
||||
import {ProfileBio} from 'web/components/bio/profile-bio'
|
||||
import {areGenderCompatible} from 'common/love/compatibility-util'
|
||||
import {useProfile} from 'web/hooks/use-lover'
|
||||
import {useProfile} from 'web/hooks/use-profile'
|
||||
import {useGetter} from 'web/hooks/use-getter'
|
||||
import {getStars} from 'web/lib/supabase/stars'
|
||||
import {Content} from "web/components/widgets/editor";
|
||||
@@ -19,14 +19,14 @@ import {JSONContent} from "@tiptap/core";
|
||||
import React from "react";
|
||||
|
||||
export function ProfileProfile(props: {
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
user: User
|
||||
refreshProfile: () => void
|
||||
fromProfilePage?: Profile
|
||||
fromSignup?: boolean
|
||||
}) {
|
||||
console.log('Rendering ProfileProfile for ', props)
|
||||
const {lover, user, refreshProfile, fromProfilePage, fromSignup} = props
|
||||
const {profile, user, refreshProfile, fromProfilePage, fromSignup} = props
|
||||
|
||||
const currentUser = useUser()
|
||||
const currentProfile = useProfile()
|
||||
@@ -56,18 +56,18 @@ export function ProfileProfile(props: {
|
||||
// !!ships && hasShipped(currentUser, fromProfilePage?.user_id, user.id, ships)
|
||||
|
||||
const areCompatible =
|
||||
!!currentProfile && areGenderCompatible(currentProfile, lover)
|
||||
!!currentProfile && areGenderCompatible(currentProfile, profile)
|
||||
|
||||
// Allow everyone to message everyone for now
|
||||
const showMessageButton = true // liked || likedBack || !areCompatible
|
||||
|
||||
const isProfileVisible = currentUser || lover.visibility === 'public'
|
||||
const isProfileVisible = currentUser || profile.visibility === 'public'
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProfileProfileHeader
|
||||
user={user}
|
||||
lover={lover}
|
||||
profile={profile}
|
||||
simpleView={!!fromProfilePage}
|
||||
starredUserIds={starredUserIds ?? []}
|
||||
refreshStars={refreshStars}
|
||||
@@ -77,7 +77,7 @@ export function ProfileProfile(props: {
|
||||
{isProfileVisible ? (
|
||||
<ProfileContent
|
||||
user={user}
|
||||
lover={lover}
|
||||
profile={profile}
|
||||
refreshProfile={refreshProfile}
|
||||
fromProfilePage={fromProfilePage}
|
||||
fromSignup={fromSignup}
|
||||
@@ -89,7 +89,7 @@ export function ProfileProfile(props: {
|
||||
) : (
|
||||
<Col className="bg-canvas-0 w-full gap-4 rounded p-4">
|
||||
<div className="text-sm text-gray-500 dark:text-gray-400">
|
||||
<Content className="w-full line-clamp-6" content={lover.bio as JSONContent}/>
|
||||
<Content className="w-full line-clamp-6" content={profile.bio as JSONContent}/>
|
||||
</div>
|
||||
<Col className="relative gap-4">
|
||||
<div className="bg-ink-200 dark:bg-ink-400 h-4 w-2/5"/>
|
||||
@@ -106,7 +106,7 @@ export function ProfileProfile(props: {
|
||||
{/* ((!fromProfilePage && !isCurrentUser) ||*/}
|
||||
{/* (fromProfilePage && fromProfilePage.user_id === currentUser?.id)) && (*/}
|
||||
{/* <Row className="right-0 mr-1 self-end lg:bottom-6">*/}
|
||||
{/* <LikeButton targetProfile={lover} liked={liked} refresh={refresh} />*/}
|
||||
{/* <LikeButton targetProfile={profile} liked={liked} refresh={refresh} />*/}
|
||||
{/* </Row>*/}
|
||||
{/* )}*/}
|
||||
{/*{fromProfilePage &&*/}
|
||||
@@ -121,14 +121,14 @@ export function ProfileProfile(props: {
|
||||
{/* />*/}
|
||||
{/* </Row>*/}
|
||||
{/* )}*/}
|
||||
{isProfileVisible && lover.photo_urls && <ProfileCarousel lover={lover}/>}
|
||||
{isProfileVisible && profile.photo_urls && <ProfileCarousel profile={profile}/>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function ProfileContent(props: {
|
||||
user: User
|
||||
lover: Profile
|
||||
profile: Profile
|
||||
refreshProfile: () => void
|
||||
fromProfilePage?: Profile
|
||||
fromSignup?: boolean
|
||||
@@ -139,7 +139,7 @@ function ProfileContent(props: {
|
||||
}) {
|
||||
const {
|
||||
user,
|
||||
lover,
|
||||
profile,
|
||||
refreshProfile,
|
||||
fromProfilePage,
|
||||
fromSignup,
|
||||
@@ -154,10 +154,10 @@ function ProfileContent(props: {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ProfileAbout lover={lover}/>
|
||||
<ProfileAbout profile={profile}/>
|
||||
<ProfileBio
|
||||
isCurrentUser={isCurrentUser}
|
||||
lover={lover}
|
||||
profile={profile}
|
||||
refreshProfile={refreshProfile}
|
||||
fromProfilePage={fromProfilePage}
|
||||
/>
|
||||
@@ -166,11 +166,11 @@ function ProfileContent(props: {
|
||||
user={user}
|
||||
fromSignup={fromSignup}
|
||||
fromProfilePage={fromProfilePage}
|
||||
lover={lover}
|
||||
profile={profile}
|
||||
/>
|
||||
<ProfileCommentSection
|
||||
onUser={user}
|
||||
lover={lover}
|
||||
profile={profile}
|
||||
currentUser={currentUser}
|
||||
simpleView={!!fromProfilePage}
|
||||
/>
|
||||
@@ -179,7 +179,7 @@ function ProfileContent(props: {
|
||||
{/* likesReceived={likesReceived}*/}
|
||||
{/* ships={ships}*/}
|
||||
{/* refreshShips={refreshShips}*/}
|
||||
{/* profileProfile={lover}*/}
|
||||
{/* profileProfile={profile}*/}
|
||||
{/*/>*/}
|
||||
</>
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
import {Profile} from 'common/love/lover'
|
||||
import {Profile} from 'common/love/profile'
|
||||
import {removeNullOrUndefinedProps} from 'common/util/object'
|
||||
import {Search} from 'web/components/filters/search'
|
||||
import {useProfile} from 'web/hooks/use-lover'
|
||||
import {useProfile} from 'web/hooks/use-profile'
|
||||
import {useCompatibleProfiles} from 'web/hooks/use-profiles'
|
||||
import {getStars} from 'web/lib/supabase/stars'
|
||||
import Router from 'next/router'
|
||||
@@ -20,8 +20,8 @@ import {useFilters} from "web/components/filters/use-filters";
|
||||
|
||||
export function ProfilesHome() {
|
||||
const user = useUser();
|
||||
const lover = useProfile();
|
||||
const you = lover;
|
||||
const profile = useProfile();
|
||||
const you = profile;
|
||||
|
||||
const {
|
||||
filters,
|
||||
@@ -95,7 +95,7 @@ export function ProfilesHome() {
|
||||
|
||||
return (
|
||||
<>
|
||||
{!lover && <Button className="mb-4 lg:hidden" onClick={() => Router.push('signup')}>Create a profile</Button>}
|
||||
{!profile && <Button className="mb-4 lg:hidden" onClick={() => Router.push('signup')}>Create a profile</Button>}
|
||||
<Title className="!mb-2 text-3xl">Profiles</Title>
|
||||
<Search
|
||||
youProfile={you}
|
||||
@@ -117,7 +117,7 @@ export function ProfilesHome() {
|
||||
loadMore={loadMore}
|
||||
isLoadingMore={isLoadingMore}
|
||||
isReloading={isReloading}
|
||||
compatibilityScores={compatibleProfiles?.loverCompatibilityScores}
|
||||
compatibilityScores={compatibleProfiles?.profileCompatibilityScores}
|
||||
starredUserIds={starredUserIds}
|
||||
refreshStars={refreshStars}
|
||||
/>
|
||||
|
||||
@@ -10,7 +10,7 @@ import {User} from 'common/user'
|
||||
import {useEditableUserInfo} from 'web/hooks/use-editable-user-info'
|
||||
import {LoadingIndicator} from 'web/components/widgets/loading-indicator'
|
||||
import {Column} from 'common/supabase/utils'
|
||||
import {ProfileRow} from 'common/love/lover'
|
||||
import {ProfileRow} from 'common/love/profile'
|
||||
import {SignupBio} from "web/components/bio/editable-bio";
|
||||
import {JSONContent} from "@tiptap/core";
|
||||
|
||||
@@ -40,13 +40,13 @@ export const RequiredLoveUserForm = (props: {
|
||||
// TODO thread this properly instead of this jank
|
||||
setEditUsername?: (name: string) => unknown
|
||||
setEditDisplayName?: (name: string) => unknown
|
||||
lover: ProfileRow
|
||||
profile: ProfileRow
|
||||
setProfile: <K extends Column<'profiles'>>(key: K, value: ProfileRow[K] | undefined) => void
|
||||
isSubmitting: boolean
|
||||
onSubmit?: () => void
|
||||
loverCreatedAlready?: boolean
|
||||
profileCreatedAlready?: boolean
|
||||
}) => {
|
||||
const {user, onSubmit, loverCreatedAlready, setProfile, lover, isSubmitting} = props
|
||||
const {user, onSubmit, profileCreatedAlready, setProfile, profile, isSubmitting} = props
|
||||
const {updateUsername, updateDisplayName, userInfo, updateUserState} = useEditableUserInfo(user)
|
||||
|
||||
const {
|
||||
@@ -67,9 +67,9 @@ export const RequiredLoveUserForm = (props: {
|
||||
|
||||
const canContinue = true
|
||||
// const canContinue =
|
||||
// (!lover.looking_for_matches ||
|
||||
// (!profile.looking_for_matches ||
|
||||
// requiredKeys
|
||||
// .map((k) => lover[k])
|
||||
// .map((k) => profile[k])
|
||||
// .every((v) =>
|
||||
// typeof v == 'string'
|
||||
// ? v !== ''
|
||||
@@ -83,7 +83,7 @@ export const RequiredLoveUserForm = (props: {
|
||||
return (
|
||||
<>
|
||||
<Title>The Basics</Title>
|
||||
{!loverCreatedAlready && <div className="text-ink-500 mb-6 text-lg">No endless forms—write your own bio, your own way.</div>}
|
||||
{!profileCreatedAlready && <div className="text-ink-500 mb-6 text-lg">No endless forms—write your own bio, your own way.</div>}
|
||||
<Col className={'gap-8'}>
|
||||
<Col>
|
||||
<label className={clsx(labelClassName)}>Display name</label>
|
||||
@@ -103,7 +103,7 @@ export const RequiredLoveUserForm = (props: {
|
||||
{errorName && <span className="text-error text-sm">{errorName}</span>}
|
||||
</Col>
|
||||
|
||||
{!loverCreatedAlready && <>
|
||||
{!profileCreatedAlready && <>
|
||||
<Col>
|
||||
<label className={clsx(labelClassName)}>Username</label>
|
||||
<Row className={'items-center gap-2'}>
|
||||
@@ -128,7 +128,7 @@ export const RequiredLoveUserForm = (props: {
|
||||
<label className={clsx(labelClassName)}>Bio</label>
|
||||
<SignupBio
|
||||
onChange={(e: JSONContent) => {
|
||||
console.log('bio changed', e, lover.bio)
|
||||
console.log('bio changed', e, profile.bio)
|
||||
setProfile('bio', e)
|
||||
}}
|
||||
/>
|
||||
@@ -2,7 +2,7 @@ import clsx from 'clsx'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { api } from 'web/lib/api'
|
||||
import { countryCodeToFlag } from 'web/lib/util/location'
|
||||
import { ProfileRow } from 'common/love/lover'
|
||||
import { ProfileRow } from 'common/love/profile'
|
||||
import {OriginLocation} from "common/filters";
|
||||
|
||||
export type City = {
|
||||
@@ -15,15 +15,15 @@ export type City = {
|
||||
longitude: number
|
||||
}
|
||||
|
||||
export function loverToCity(lover: ProfileRow): City {
|
||||
export function profileToCity(profile: ProfileRow): City {
|
||||
return {
|
||||
geodb_city_id: lover.geodb_city_id!,
|
||||
city: lover.city,
|
||||
region_code: lover.region_code!,
|
||||
country: lover.country!,
|
||||
geodb_city_id: profile.geodb_city_id!,
|
||||
city: profile.city,
|
||||
region_code: profile.region_code!,
|
||||
country: profile.country!,
|
||||
country_code: '',
|
||||
latitude: lover.city_latitude!,
|
||||
longitude: lover.city_longitude!,
|
||||
latitude: profile.city_latitude!,
|
||||
longitude: profile.city_longitude!,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ import { Tooltip } from 'web/components/widgets/tooltip'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { MODAL_CLASS, Modal } from 'web/components/layout/modal'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import { useUserById } from 'web/hooks/use-user-supabase'
|
||||
import { MatchAvatars } from '../matches/match-avatars'
|
||||
import { useProfile } from 'web/hooks/use-lover'
|
||||
import { useProfile } from 'web/hooks/use-profile'
|
||||
import { useAPIGetter } from 'web/hooks/use-api-getter'
|
||||
|
||||
export const LikeButton = (props: {
|
||||
@@ -36,8 +36,8 @@ export const LikeButton = (props: {
|
||||
const like = async () => {
|
||||
setShowConfirmation(false)
|
||||
setIsLoading(true)
|
||||
await api('like-lover', { targetUserId: targetId, remove: liked })
|
||||
track('like lover', {
|
||||
await api('like-profile', { targetUserId: targetId, remove: liked })
|
||||
track('like profile', {
|
||||
targetId,
|
||||
remove: liked,
|
||||
})
|
||||
|
||||
@@ -3,8 +3,8 @@ import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
import { UserIcon } from '@heroicons/react/solid'
|
||||
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { useProfileByUserId } from 'web/hooks/use-lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import { useProfileByUserId } from 'web/hooks/use-profile'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { Avatar, EmptyAvatar } from 'web/components/widgets/avatar'
|
||||
import { Carousel } from 'web/components/widgets/carousel'
|
||||
@@ -13,7 +13,7 @@ import { useUser } from 'web/hooks/use-user'
|
||||
import { useUserById } from 'web/hooks/use-user-supabase'
|
||||
import { SendMessageButton } from 'web/components/messaging/send-message-button'
|
||||
import { ShipsList } from './ships-display'
|
||||
import { Subtitle } from './lover-subtitle'
|
||||
import { Subtitle } from './profile-subtitle'
|
||||
import { LikeData, ShipData } from 'common/api/love-types'
|
||||
|
||||
export const LikesDisplay = (props: {
|
||||
@@ -122,17 +122,17 @@ const LikesList = (props: { label: string; likes: LikeData[] }) => {
|
||||
|
||||
const UserAvatar = (props: { userId: string; className?: string }) => {
|
||||
const { userId, className } = props
|
||||
const lover = useProfileByUserId(userId)
|
||||
const profile = useProfileByUserId(userId)
|
||||
const user = useUserById(userId)
|
||||
|
||||
// console.log('UserAvatar', user?.username, lover?.pinned_url)
|
||||
// console.log('UserAvatar', user?.username, profile?.pinned_url)
|
||||
|
||||
if (!lover)
|
||||
if (!profile)
|
||||
return <EmptyAvatar className={className} size={10} />
|
||||
return (
|
||||
<Avatar
|
||||
className={className}
|
||||
avatarUrl={lover.pinned_url}
|
||||
avatarUrl={profile.pinned_url}
|
||||
username={user?.username}
|
||||
/>
|
||||
)
|
||||
@@ -143,14 +143,14 @@ export const MatchTile = (props: {
|
||||
matchUserId: string
|
||||
}) => {
|
||||
const { matchUserId, profileProfile } = props
|
||||
const lover = useProfileByUserId(matchUserId)
|
||||
const profile = useProfileByUserId(matchUserId)
|
||||
const user = useUserById(matchUserId)
|
||||
const currentUser = useUser()
|
||||
const isYourMatch = currentUser?.id === profileProfile.user_id
|
||||
|
||||
if (!lover || !user)
|
||||
if (!profile || !user)
|
||||
return <Col className="mb-2 h-[184px] w-[200px] shrink-0"></Col>
|
||||
const { pinned_url } = lover
|
||||
const { pinned_url } = profile
|
||||
|
||||
return (
|
||||
<Col className="mb-2 w-[200px] shrink-0 overflow-hidden rounded">
|
||||
|
||||
@@ -5,14 +5,14 @@ import clsx from 'clsx'
|
||||
import { MODAL_CLASS, Modal } from 'web/components/layout/modal'
|
||||
import { MatchAvatars } from '../matches/match-avatars'
|
||||
import { Row } from 'web/components/layout/row'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { useProfileByUserId } from 'web/hooks/use-lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
import { useProfileByUserId } from 'web/hooks/use-profile'
|
||||
import { Col } from 'web/components/layout/col'
|
||||
import { EmptyAvatar, Avatar } from 'web/components/widgets/avatar'
|
||||
import { Carousel } from 'web/components/widgets/carousel'
|
||||
import { UserLink } from 'web/components/widgets/user-link'
|
||||
import { useUser } from 'web/hooks/use-user'
|
||||
import { Subtitle } from './lover-subtitle'
|
||||
import { Subtitle } from './profile-subtitle'
|
||||
import { ShipButton } from './ship-button'
|
||||
import { hasShipped } from 'web/lib/util/ship-util'
|
||||
import { ShipData } from 'common/api/love-types'
|
||||
@@ -144,15 +144,15 @@ const ShipsTargetDisplay = (props: {
|
||||
|
||||
const UserAvatar = (props: { userId: string; className?: string }) => {
|
||||
const { userId, className } = props
|
||||
const lover = useProfileByUserId(userId)
|
||||
const profile = useProfileByUserId(userId)
|
||||
const user = useUserById(userId)
|
||||
|
||||
if (!lover || !lover.pinned_url)
|
||||
if (!profile || !profile.pinned_url)
|
||||
return <EmptyAvatar className={className} size={10} />
|
||||
return (
|
||||
<Avatar
|
||||
className={className}
|
||||
avatarUrl={lover.pinned_url}
|
||||
avatarUrl={profile.pinned_url}
|
||||
username={user?.username}
|
||||
noLink
|
||||
/>
|
||||
@@ -162,14 +162,14 @@ const UserAvatar = (props: { userId: string; className?: string }) => {
|
||||
const UserInfoRow = (props: { userId: string; className?: string }) => {
|
||||
const { userId, className } = props
|
||||
const user = useUserById(userId)
|
||||
const lover = useProfileByUserId(userId)
|
||||
const profile = useProfileByUserId(userId)
|
||||
|
||||
return (
|
||||
<Row className={clsx(className, 'items-center gap-2')}>
|
||||
{!lover || !lover.pinned_url ? (
|
||||
{!profile || !profile.pinned_url ? (
|
||||
<EmptyAvatar size={10} />
|
||||
) : (
|
||||
<Avatar avatarUrl={lover.pinned_url} username={user?.username} />
|
||||
<Avatar avatarUrl={profile.pinned_url} username={user?.username} />
|
||||
)}
|
||||
{user && <UserLink user={user} hideBadge />}
|
||||
</Row>
|
||||
|
||||
@@ -6,7 +6,7 @@ import { api } from 'web/lib/api'
|
||||
import { buttonClass } from 'web/components/buttons/button'
|
||||
import { track } from 'web/lib/service/analytics'
|
||||
import { Tooltip } from 'web/components/widgets/tooltip'
|
||||
import { Profile } from 'common/love/lover'
|
||||
import { Profile } from 'common/love/profile'
|
||||
|
||||
export const StarButton = (props: {
|
||||
targetProfile: Profile
|
||||
@@ -25,13 +25,13 @@ export const StarButton = (props: {
|
||||
|
||||
const star = async () => {
|
||||
setIsStarred(!isStarred)
|
||||
await api('star-lover', {
|
||||
await api('star-profile', {
|
||||
targetUserId: targetId,
|
||||
remove: isStarred,
|
||||
}).catch(() => {
|
||||
setIsStarred(isStarred)
|
||||
})
|
||||
track('star lover', {
|
||||
track('star profile', {
|
||||
targetId,
|
||||
remove: isStarred,
|
||||
})
|
||||
|
||||
@@ -36,7 +36,7 @@ export function useLiveCommentsOnProfile(userId: string) {
|
||||
|
||||
const getComments = async (userId: string) => {
|
||||
const { data, error } = await db
|
||||
.from('lover_comments')
|
||||
.from('profile_comments')
|
||||
.select('*')
|
||||
.eq('on_user_id', userId)
|
||||
if (error) {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useProfile } from './use-lover'
|
||||
import { useProfile } from './use-profile'
|
||||
|
||||
export const useIsLooking = () => {
|
||||
const lover = useProfile()
|
||||
return !!(lover && lover.looking_for_matches)
|
||||
const profile = useProfile()
|
||||
return !!(profile && profile.looking_for_matches)
|
||||
}
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
import {useUser} from 'web/hooks/use-user'
|
||||
import {useEffect} from 'react'
|
||||
import {Row} from 'common/supabase/utils'
|
||||
import {usePersistentInMemoryState} from 'web/hooks/use-persistent-in-memory-state'
|
||||
import {User} from 'common/user'
|
||||
import {getProfileRow, Profile, ProfileRow} from 'common/love/lover'
|
||||
import {db} from 'web/lib/supabase/db'
|
||||
import {usePersistentLocalState} from 'web/hooks/use-persistent-local-state'
|
||||
|
||||
export const useProfile = () => {
|
||||
const user = useUser()
|
||||
const [lover, setProfile] = usePersistentLocalState<
|
||||
Row<'profiles'> | undefined | null
|
||||
>(undefined, `lover-${user?.id}`)
|
||||
|
||||
const refreshProfile = () => {
|
||||
if (user) {
|
||||
console.log('Refreshing lover in useProfile for', user?.username, lover);
|
||||
getProfileRow(user.id, db).then((lover) => {
|
||||
if (!lover) setProfile(null)
|
||||
else setProfile(lover)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
refreshProfile()
|
||||
}, [user?.id])
|
||||
|
||||
return user && lover ? {...lover, user} : lover === null ? null : undefined
|
||||
}
|
||||
|
||||
export const useProfileByUser = (user: User | undefined) => {
|
||||
const userId = user?.id
|
||||
const [lover, setProfile] = usePersistentInMemoryState<
|
||||
Profile | undefined | null
|
||||
>(undefined, `lover-user-${userId}`)
|
||||
|
||||
function refreshProfile() {
|
||||
if (userId) {
|
||||
console.log('Refreshing lover in useProfileByUser for', user?.username, lover);
|
||||
getProfileRow(userId, db)
|
||||
.then((lover) => {
|
||||
if (!lover) setProfile(null)
|
||||
else setProfile({...lover, user})
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('Warning: lover not found', user?.username, error);
|
||||
setProfile(null)
|
||||
return
|
||||
});
|
||||
console.log('End Refreshing lover for', user?.username, lover);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
refreshProfile()
|
||||
}, [userId])
|
||||
|
||||
return {lover, refreshProfile}
|
||||
}
|
||||
|
||||
export const useProfileByUserId = (userId: string | undefined) => {
|
||||
const [lover, setProfile] = usePersistentInMemoryState<
|
||||
ProfileRow | undefined | null
|
||||
>(undefined, `lover-${userId}`)
|
||||
|
||||
useEffect(() => {
|
||||
console.log('Refreshing lover in useProfileByUserId for', userId, lover);
|
||||
if (userId)
|
||||
getProfileRow(userId, db).then((lover) => {
|
||||
if (!lover) setProfile(null)
|
||||
else setProfile(lover)
|
||||
})
|
||||
}, [userId])
|
||||
|
||||
return lover
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useProfile } from 'web/hooks/use-lover'
|
||||
import { useProfile } from 'web/hooks/use-profile'
|
||||
import { useIsAuthorized } from 'web/hooks/use-user'
|
||||
import { run } from 'common/supabase/utils'
|
||||
import { db } from 'web/lib/supabase/db'
|
||||
export const useOnline = () => {
|
||||
const lover = useProfile()
|
||||
const profile = useProfile()
|
||||
const isAuthed = useIsAuthorized()
|
||||
useEffect(() => {
|
||||
if (!lover || !isAuthed) return
|
||||
if (!profile || !isAuthed) return
|
||||
run(
|
||||
db
|
||||
.from('profiles')
|
||||
.update({ last_online_time: new Date().toISOString() })
|
||||
.eq('id', lover.id)
|
||||
.eq('id', profile.id)
|
||||
)
|
||||
}, [])
|
||||
}
|
||||
|
||||
78
web/hooks/use-profile.ts
Normal file
78
web/hooks/use-profile.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import {useUser} from 'web/hooks/use-user'
|
||||
import {useEffect} from 'react'
|
||||
import {Row} from 'common/supabase/utils'
|
||||
import {usePersistentInMemoryState} from 'web/hooks/use-persistent-in-memory-state'
|
||||
import {User} from 'common/user'
|
||||
import {getProfileRow, Profile, ProfileRow} from 'common/love/profile'
|
||||
import {db} from 'web/lib/supabase/db'
|
||||
import {usePersistentLocalState} from 'web/hooks/use-persistent-local-state'
|
||||
|
||||
export const useProfile = () => {
|
||||
const user = useUser()
|
||||
const [profile, setProfile] = usePersistentLocalState<
|
||||
Row<'profiles'> | undefined | null
|
||||
>(undefined, `profile-${user?.id}`)
|
||||
|
||||
const refreshProfile = () => {
|
||||
if (user) {
|
||||
console.log('Refreshing profile in useProfile for', user?.username, profile);
|
||||
getProfileRow(user.id, db).then((profile) => {
|
||||
if (!profile) setProfile(null)
|
||||
else setProfile(profile)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
refreshProfile()
|
||||
}, [user?.id])
|
||||
|
||||
return user && profile ? {...profile, user} : profile === null ? null : undefined
|
||||
}
|
||||
|
||||
export const useProfileByUser = (user: User | undefined) => {
|
||||
const userId = user?.id
|
||||
const [profile, setProfile] = usePersistentInMemoryState<
|
||||
Profile | undefined | null
|
||||
>(undefined, `profile-user-${userId}`)
|
||||
|
||||
function refreshProfile() {
|
||||
if (userId) {
|
||||
console.log('Refreshing profile in useProfileByUser for', user?.username, profile);
|
||||
getProfileRow(userId, db)
|
||||
.then((profile) => {
|
||||
if (!profile) setProfile(null)
|
||||
else setProfile({...profile, user})
|
||||
})
|
||||
.catch(error => {
|
||||
console.log('Warning: profile not found', user?.username, error);
|
||||
setProfile(null)
|
||||
return
|
||||
});
|
||||
console.log('End Refreshing profile for', user?.username, profile);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
refreshProfile()
|
||||
}, [userId])
|
||||
|
||||
return {profile, refreshProfile}
|
||||
}
|
||||
|
||||
export const useProfileByUserId = (userId: string | undefined) => {
|
||||
const [profile, setProfile] = usePersistentInMemoryState<
|
||||
ProfileRow | undefined | null
|
||||
>(undefined, `profile-${userId}`)
|
||||
|
||||
useEffect(() => {
|
||||
console.log('Refreshing profile in useProfileByUserId for', userId, profile);
|
||||
if (userId)
|
||||
getProfileRow(userId, db).then((profile) => {
|
||||
if (!profile) setProfile(null)
|
||||
else setProfile(profile)
|
||||
})
|
||||
}, [userId])
|
||||
|
||||
return profile
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { useEffect } from 'react'
|
||||
import { usePersistentInMemoryState } from 'web/hooks/use-persistent-in-memory-state'
|
||||
import { api } from 'web/lib/api'
|
||||
import { APIResponse } from 'common/api/schema'
|
||||
import { useProfileByUserId } from './use-lover'
|
||||
import { useProfileByUserId } from './use-profile'
|
||||
import { getProfilesCompatibilityFactor } from 'common/love/compatibility-score'
|
||||
|
||||
export const useCompatibleProfiles = (
|
||||
@@ -14,7 +14,7 @@ export const useCompatibleProfiles = (
|
||||
APIResponse<'compatible-profiles'> | undefined | null
|
||||
>(undefined, `compatible-profiles-${userId}`)
|
||||
|
||||
const lover = useProfileByUserId(userId ?? undefined)
|
||||
const profile = useProfileByUserId(userId ?? undefined)
|
||||
|
||||
useEffect(() => {
|
||||
if (userId) {
|
||||
@@ -30,10 +30,10 @@ export const useCompatibleProfiles = (
|
||||
} else if (userId === null) setData(null)
|
||||
}, [userId])
|
||||
|
||||
if (data && lover && options?.sortWithModifiers) {
|
||||
if (data && profile && options?.sortWithModifiers) {
|
||||
data.compatibleProfiles = sortBy(data.compatibleProfiles, (l) => {
|
||||
const modifier = !lover ? 1 : getProfilesCompatibilityFactor(lover, l)
|
||||
return -1 * modifier * data.loverCompatibilityScores[l.user.id].score
|
||||
const modifier = !profile ? 1 : getProfilesCompatibilityFactor(profile, l)
|
||||
return -1 * modifier * data.profileCompatibilityScores[l.user.id].score
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,6 @@ function curriedAPI<P extends APIPath>(path: P) {
|
||||
return (params: APIParams<P>) => api(path, params)
|
||||
}
|
||||
|
||||
export const updateProfile = curriedAPI('update-lover')
|
||||
export const updateProfile = curriedAPI('update-profile')
|
||||
export const updateUser = curriedAPI('me/update')
|
||||
export const report = curriedAPI('report')
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import Router from 'next/router'
|
||||
import { firebaseLogin } from 'web/lib/firebase/users'
|
||||
import { db } from 'web/lib/supabase/db'
|
||||
import { getProfileRow } from 'common/love/lover'
|
||||
import { getProfileRow } from 'common/love/profile'
|
||||
|
||||
export const signupThenMaybeRedirectToSignup = async () => {
|
||||
const creds = await firebaseLogin()
|
||||
await Router.push('/')
|
||||
const userId = creds?.user.uid
|
||||
if (userId) {
|
||||
const lover = await getProfileRow(userId, db)
|
||||
if (!lover) {
|
||||
const profile = await getProfileRow(userId, db)
|
||||
if (!profile) {
|
||||
await Router.push('/signup')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import Router from 'next/router'
|
||||
import Head from 'next/head'
|
||||
import {useRouter} from 'next/router'
|
||||
import {LovePage} from 'web/components/love-page'
|
||||
import {useProfileByUser} from 'web/hooks/use-lover'
|
||||
import {useProfileByUser} from 'web/hooks/use-profile'
|
||||
import {Button} from 'web/components/buttons/button'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {Row} from 'web/components/layout/row'
|
||||
@@ -13,9 +13,9 @@ import {useTracking} from 'web/hooks/use-tracking'
|
||||
import {BackButton} from 'web/components/back-button'
|
||||
import {useSaveReferral} from 'web/hooks/use-save-referral'
|
||||
import {getLoveOgImageUrl} from 'common/love/og-image'
|
||||
import {getProfileRow, ProfileRow} from 'common/love/lover'
|
||||
import {getProfileRow, ProfileRow} from 'common/love/profile'
|
||||
import {db} from 'web/lib/supabase/db'
|
||||
import {ProfileProfile} from 'web/components/profile/lover-profile'
|
||||
import {ProfileProfile} from 'web/components/profile/profile-profile'
|
||||
import {User} from 'common/user'
|
||||
import {getUserForStaticProps} from 'common/supabase/users'
|
||||
import {type GetStaticProps} from 'next'
|
||||
@@ -58,12 +58,12 @@ export const getStaticProps: GetStaticProps<
|
||||
}
|
||||
}
|
||||
|
||||
const lover = await getProfileRow(user.id, db)
|
||||
const profile = await getProfileRow(user.id, db)
|
||||
return {
|
||||
props: {
|
||||
user,
|
||||
username,
|
||||
lover,
|
||||
profile,
|
||||
},
|
||||
revalidate: 15,
|
||||
}
|
||||
@@ -82,7 +82,7 @@ type DeletedUserPageProps = {
|
||||
type ActiveUserPageProps = {
|
||||
user: User
|
||||
username: string
|
||||
lover: ProfileRow
|
||||
profile: ProfileRow
|
||||
}
|
||||
|
||||
export default function UserPage(props: UserPageProps) {
|
||||
@@ -112,12 +112,12 @@ function UserPageInner(props: ActiveUserPageProps) {
|
||||
useTracking('view love profile', {username: user?.username})
|
||||
|
||||
const [staticProfile] = useState(
|
||||
props.lover && user ? {...props.lover, user: user} : null
|
||||
props.profile && user ? {...props.profile, user: user} : null
|
||||
)
|
||||
const {lover: clientProfile, refreshProfile} = useProfileByUser(user)
|
||||
const {profile: clientProfile, refreshProfile} = useProfileByUser(user)
|
||||
// Show previous profile while loading another one
|
||||
const lover = clientProfile ?? staticProfile
|
||||
// console.log('lover:', user?.username, lover, clientProfile, staticProfile)
|
||||
const profile = clientProfile ?? staticProfile
|
||||
// console.log('profile:', user?.username, profile, clientProfile, staticProfile)
|
||||
|
||||
return (
|
||||
<LovePage
|
||||
@@ -129,7 +129,7 @@ function UserPageInner(props: ActiveUserPageProps) {
|
||||
title={`${user.name} (@${user.username})`}
|
||||
description={user.bio ?? ''}
|
||||
url={`/${user.username}`}
|
||||
image={getLoveOgImageUrl(user, lover)}
|
||||
image={getLoveOgImageUrl(user, profile)}
|
||||
/>
|
||||
{(user.isBannedFromPosting || user.userDeleted) && (
|
||||
<Head>
|
||||
@@ -140,10 +140,10 @@ function UserPageInner(props: ActiveUserPageProps) {
|
||||
|
||||
{currentUser !== undefined && (
|
||||
<Col className={'gap-4'}>
|
||||
{lover ? (
|
||||
{profile ? (
|
||||
<ProfileProfile
|
||||
key={lover.user_id}
|
||||
lover={lover}
|
||||
key={profile.user_id}
|
||||
profile={profile}
|
||||
user={user}
|
||||
refreshProfile={refreshProfile}
|
||||
fromSignup={fromSignup}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {Profile, ProfileRow} from 'common/love/lover'
|
||||
import {Profile, ProfileRow} from 'common/love/profile'
|
||||
import {Column} from 'common/supabase/utils'
|
||||
import {User} from 'common/user'
|
||||
import {OptionalLoveUserForm} from 'web/components/optional-lover-form'
|
||||
import {RequiredLoveUserForm} from 'web/components/required-lover-form'
|
||||
import {useProfileByUser} from 'web/hooks/use-lover'
|
||||
import {OptionalLoveUserForm} from 'web/components/optional-profile-form'
|
||||
import {RequiredLoveUserForm} from 'web/components/required-profile-form'
|
||||
import {useProfileByUser} from 'web/hooks/use-profile'
|
||||
import Router from 'next/router'
|
||||
import {useEffect, useState} from 'react'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
@@ -13,22 +13,22 @@ import {LovePage} from "web/components/love-page";
|
||||
|
||||
export default function ProfilePage() {
|
||||
const user = useUser()
|
||||
const {lover} = useProfileByUser(user ?? undefined)
|
||||
const {profile} = useProfileByUser(user ?? undefined)
|
||||
|
||||
useEffect(() => {
|
||||
if (user === null || lover === null) {
|
||||
if (user === null || profile === null) {
|
||||
Router.replace('/')
|
||||
}
|
||||
}, [user])
|
||||
|
||||
return user && lover && <ProfilePageInner user={user} lover={lover}/>
|
||||
return user && profile && <ProfilePageInner user={user} profile={profile}/>
|
||||
}
|
||||
|
||||
function ProfilePageInner(props: { user: User; lover: Profile }) {
|
||||
function ProfilePageInner(props: { user: User; profile: Profile }) {
|
||||
const {user} = props
|
||||
|
||||
const [lover, setProfile] = useState<Profile>({
|
||||
...props.lover,
|
||||
const [profile, setProfile] = useState<Profile>({
|
||||
...props.profile,
|
||||
user,
|
||||
})
|
||||
|
||||
@@ -46,15 +46,15 @@ function ProfilePageInner(props: { user: User; lover: Profile }) {
|
||||
<RequiredLoveUserForm
|
||||
user={user}
|
||||
setProfile={setProfileState}
|
||||
lover={lover}
|
||||
loverCreatedAlready={true}
|
||||
profile={profile}
|
||||
profileCreatedAlready={true}
|
||||
isSubmitting={false}
|
||||
setEditUsername={setUsername}
|
||||
setEditDisplayName={setDisplayName}
|
||||
/>
|
||||
<div className={'h-4'}/>
|
||||
<OptionalLoveUserForm
|
||||
lover={lover}
|
||||
profile={profile}
|
||||
user={user}
|
||||
setProfile={setProfileState}
|
||||
buttonLabel={'Save'}
|
||||
|
||||
@@ -9,7 +9,7 @@ import {createUserWithEmailAndPassword} from "firebase/auth";
|
||||
import {auth} from "web/lib/firebase/users";
|
||||
import FavIcon from "web/public/FavIcon";
|
||||
import {LovePage} from "web/components/love-page";
|
||||
import {getProfileRow} from "common/love/lover";
|
||||
import {getProfileRow} from "common/love/profile";
|
||||
import {db} from "web/lib/supabase/db";
|
||||
import Router from "next/router";
|
||||
import {useUser} from "web/hooks/use-user";
|
||||
@@ -42,8 +42,8 @@ function RegisterComponent() {
|
||||
useEffect(() => {
|
||||
const checkProfileAndRedirect = async () => {
|
||||
if (user) {
|
||||
const lover = await getProfileRow(user.id, db)
|
||||
if (lover) {
|
||||
const profile = await getProfileRow(user.id, db)
|
||||
if (profile) {
|
||||
await Router.push('/')
|
||||
} else {
|
||||
await Router.push('/signup')
|
||||
|
||||
@@ -7,7 +7,7 @@ import {auth, firebaseLogin} from "web/lib/firebase/users";
|
||||
import FavIcon from "web/public/FavIcon";
|
||||
|
||||
import {signInWithEmailAndPassword} from "firebase/auth";
|
||||
import {getProfileRow} from "common/love/lover";
|
||||
import {getProfileRow} from "common/love/profile";
|
||||
import {db} from "web/lib/supabase/db";
|
||||
import Router from "next/router";
|
||||
import {LovePage} from "web/components/love-page";
|
||||
@@ -43,14 +43,14 @@ function RegisterComponent() {
|
||||
if (user) {
|
||||
console.log("User signed in:", user);
|
||||
try {
|
||||
const lover = await getProfileRow(user.id, db)
|
||||
if (lover) {
|
||||
const profile = await getProfileRow(user.id, db)
|
||||
if (profile) {
|
||||
await Router.push('/')
|
||||
} else {
|
||||
await Router.push('/signup')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching lover profile:", error);
|
||||
console.error("Error fetching profile profile:", error);
|
||||
}
|
||||
setIsLoading(false);
|
||||
setIsLoadingGoogle(false);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {useEffect, useState} from 'react'
|
||||
import {Col} from 'web/components/layout/col'
|
||||
import {initialRequiredState, RequiredLoveUserForm,} from 'web/components/required-lover-form'
|
||||
import {OptionalLoveUserForm} from 'web/components/optional-lover-form'
|
||||
import {initialRequiredState, RequiredLoveUserForm,} from 'web/components/required-profile-form'
|
||||
import {OptionalLoveUserForm} from 'web/components/optional-profile-form'
|
||||
import {useUser} from 'web/hooks/use-user'
|
||||
import {LoadingIndicator} from 'web/components/widgets/loading-indicator'
|
||||
import {CACHED_REFERRAL_USERNAME_KEY,} from 'web/lib/firebase/users'
|
||||
@@ -12,8 +12,8 @@ import {useTracking} from 'web/hooks/use-tracking'
|
||||
import {track} from 'web/lib/service/analytics'
|
||||
import {safeLocalStorage} from 'web/lib/util/local'
|
||||
import {removeNullOrUndefinedProps} from 'common/util/object'
|
||||
import {useProfileByUserId} from 'web/hooks/use-lover'
|
||||
import {ProfileRow} from 'common/love/lover'
|
||||
import {useProfileByUserId} from 'web/hooks/use-profile'
|
||||
import {ProfileRow} from 'common/love/profile'
|
||||
import {LovePage} from "web/components/love-page";
|
||||
import {Button} from "web/components/buttons/button";
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function SignupPage() {
|
||||
useTracking('view love signup page')
|
||||
|
||||
// Omit the id, created_time?
|
||||
const [loverForm, setProfileForm] = useState<ProfileRow>({
|
||||
const [profileForm, setProfileForm] = useState<ProfileRow>({
|
||||
...initialRequiredState,
|
||||
} as any)
|
||||
const setProfileState = (key: keyof ProfileRow, value: any) => {
|
||||
@@ -47,7 +47,7 @@ export default function SignupPage() {
|
||||
<Col className={'w-full px-6 py-4'}>
|
||||
<OptionalLoveUserForm
|
||||
setProfile={setProfileState}
|
||||
lover={loverForm}
|
||||
profile={profileForm}
|
||||
user={user}
|
||||
fromSignup
|
||||
/>
|
||||
@@ -78,10 +78,10 @@ export default function SignupPage() {
|
||||
<RequiredLoveUserForm
|
||||
user={user}
|
||||
setProfile={setProfileState}
|
||||
lover={loverForm}
|
||||
profile={profileForm}
|
||||
isSubmitting={isSubmitting}
|
||||
onSubmit={async () => {
|
||||
if (!loverForm.looking_for_matches) {
|
||||
if (!profileForm.looking_for_matches) {
|
||||
router.push('/')
|
||||
return
|
||||
}
|
||||
@@ -91,11 +91,11 @@ export default function SignupPage() {
|
||||
: undefined
|
||||
|
||||
setIsSubmitting(true)
|
||||
console.log('loverForm', loverForm)
|
||||
const lover = await api(
|
||||
'create-lover',
|
||||
console.log('profileForm', profileForm)
|
||||
const profile = await api(
|
||||
'create-profile',
|
||||
removeNullOrUndefinedProps({
|
||||
...loverForm,
|
||||
...profileForm,
|
||||
referred_by_username: referredByUsername,
|
||||
}) as any
|
||||
).catch((e: unknown) => {
|
||||
@@ -103,8 +103,8 @@ export default function SignupPage() {
|
||||
return null
|
||||
})
|
||||
setIsSubmitting(false)
|
||||
if (lover) {
|
||||
setProfileForm(lover)
|
||||
if (profile) {
|
||||
setProfileForm(profile)
|
||||
setStep(1)
|
||||
scrollTo(0, 0)
|
||||
track('submit love required profile')
|
||||
|
||||
Reference in New Issue
Block a user