Add connection interest notification and update related API logic

This commit is contained in:
MartinBraquet
2026-02-24 17:32:36 +01:00
parent 80a877301a
commit df2473929a
6 changed files with 84 additions and 3 deletions

View File

@@ -1,5 +1,10 @@
import {APIHandler} from 'api/helpers/endpoint'
import {Notification} from 'common/notifications'
import {getNotificationDestinationsForUser} from 'common/user-notification-preferences'
import {getProfile} from 'shared/profiles/supabase'
import {createSupabaseDirectClient} from 'shared/supabase/init'
import {insertNotificationToSupabase} from 'shared/supabase/notifications'
import {getPrivateUser, getUser} from 'shared/utils'
export const updateConnectionInterests: APIHandler<'update-connection-interest'> = async (
props,
@@ -13,15 +18,54 @@ export const updateConnectionInterests: APIHandler<'update-connection-interest'>
}
if (seeking) {
// Insert or update the interest
await pg.query(
`INSERT INTO connection_interests (user_id, target_user_id, connection_type)
VALUES ($1, $2, $3)
ON CONFLICT (user_id, target_user_id, connection_type) DO NOTHING`,
[auth.uid, targetUserId, connectionType],
)
const matchingInterest = await pg.oneOrNone(
`SELECT 1 FROM connection_interests
WHERE user_id = $1 AND target_user_id = $2 AND connection_type = $3`,
[targetUserId, auth.uid, connectionType],
)
if (matchingInterest) {
const targetPrivateUser = await getPrivateUser(targetUserId)
const currentUser = await getUser(auth.uid)
const currentUserProfile = await getProfile(auth.uid)
if (targetPrivateUser && currentUser && currentUserProfile) {
const {sendToBrowser} = getNotificationDestinationsForUser(
targetPrivateUser,
'connection_interest_match',
)
if (sendToBrowser) {
const notification: Notification = {
id: `${auth.uid}-${targetUserId}-${connectionType}-${Date.now()}`,
userId: targetUserId,
reason: 'connection_interest_match',
createdTime: Date.now(),
isSeen: false,
sourceType: 'connection_interest_match',
sourceUpdateType: 'created',
sourceUserName: currentUser.name,
sourceUserUsername: currentUser.username,
sourceUserAvatarUrl: currentUserProfile.pinned_url ?? currentUser.avatarUrl,
sourceText: connectionType,
data: {
connectionType,
},
}
await insertNotificationToSupabase(notification, pg)
// Send it to mobile as well
}
}
}
} else {
// Remove the interest
await pg.query(
'DELETE FROM connection_interests WHERE user_id = $1 AND target_user_id = $2 AND connection_type = $3',
[auth.uid, targetUserId, connectionType],

View File

@@ -478,6 +478,7 @@
"notifications.comment.on_your_profile": "auf Ihrem Profil",
"notifications.match.proposed_new_match": "schlug einen neuen Match vor:",
"notifications.profile.liked_you": "mag dich gerne!",
"notifications.connection.interested_in_you": "ist an dir interessiert für {type}",
"notifications.who_liked_it": "Wer hat es gern?",
"notifications.profile.are_being_shipped_by": "werden versandt von",
"time.units.y": "y",

View File

@@ -478,6 +478,7 @@
"notifications.comment.on_your_profile": "votre profil",
"notifications.match.proposed_new_match": "proposé un nouveau match :",
"notifications.profile.liked_you": "vous a plu !",
"notifications.connection.interested_in_you": "est intéressé·e par un(e) {type} avec vous",
"notifications.who_liked_it": "Qui l'a aimé ?",
"time.units.y": "ans",
"time.units.mo": "mo",

View File

@@ -11,6 +11,7 @@ export type notification_preferences = {
new_profile_like: notification_destination_types[]
new_profile_ship: notification_destination_types[]
new_search_alerts: notification_destination_types[]
connection_interest_match: notification_destination_types[]
// User-related
new_message: notification_destination_types[]
@@ -36,6 +37,7 @@ export const getDefaultNotificationPreferences = (isDev?: boolean) => {
new_endorsement: constructPref(true, true, true),
new_profile_like: constructPref(true, false, false),
new_profile_ship: constructPref(true, false, false),
connection_interest_match: constructPref(true, false, true),
// User-related
new_message: constructPref(true, true, true),

View File

@@ -36,6 +36,8 @@ export function NotificationItem(props: {notification: Notification}) {
return <ProfileLikeNotification {...params} />
} else if (reason === 'new_profile_ship') {
return <ProfileShipNotification {...params} />
} else if (reason === 'connection_interest_match') {
return <ConnectionInterestMatchNotification {...params} />
} else {
return <BaseNotification {...params} />
}
@@ -226,6 +228,37 @@ function ProfileShipNotification(props: {
)
}
export function ConnectionInterestMatchNotification(props: {
notification: Notification
highlighted: boolean
setHighlighted: (highlighted: boolean) => void
isChildOfGroup?: boolean
}) {
const {notification, highlighted, setHighlighted, isChildOfGroup} = props
const {sourceUserName, sourceUserUsername, sourceText} = notification
const t = useT()
const connectionType = notification.data?.connectionType || sourceText
const type = t(`profile.relationship.${connectionType}`, connectionType)
return (
<NotificationFrame
notification={notification}
isChildOfGroup={isChildOfGroup}
highlighted={highlighted}
setHighlighted={setHighlighted}
icon={<AvatarNotificationIcon notification={notification} symbol={'💕'} />}
link={`/${sourceUserUsername}`}
subtitle={<></>}
>
<NotificationUserLink name={sourceUserName} username={sourceUserUsername} />{' '}
{t('notifications.connection.interested_in_you', 'is interested in a {type} with you', {
type,
})}
!
</NotificationFrame>
)
}
const getSourceUrl = (notification: Notification) => {
const {sourceSlug, sourceId} = notification
if (sourceSlug) {

View File

@@ -6,11 +6,11 @@ import {ProfileBio} from 'web/components/bio/profile-bio'
import {Col} from 'web/components/layout/col'
import {Row} from 'web/components/layout/row'
import {SignUpButton} from 'web/components/nav/sidebar'
import {ConnectActions} from 'web/components/profile/connect-actions'
import ProfileHeader from 'web/components/profile/profile-header'
import ProfileAbout from 'web/components/profile-about'
import ProfileCarousel from 'web/components/profile-carousel'
import {ProfileCommentSection} from 'web/components/profile-comment-section'
import {ConnectActions} from 'web/components/profile/connect-actions'
import {Content} from 'web/components/widgets/editor'
import {useGetter} from 'web/hooks/use-getter'
import {useHiddenProfiles} from 'web/hooks/use-hidden-profiles'