mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-05-11 08:35:42 -04:00
Refactor user profile handling by removing deprecated fields and improving link management
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
import { toUserAPIResponse } from 'common/api/user-types'
|
||||
import { RESERVED_PATHS } from 'common/envs/constants'
|
||||
import { cleanDisplayName, cleanUsername } from 'common/util/clean-username'
|
||||
import { removeUndefinedProps } from 'common/util/object'
|
||||
import { cloneDeep, mapValues } from 'lodash'
|
||||
import { createSupabaseDirectClient } from 'shared/supabase/init'
|
||||
import { getUser, getUserByUsername } from 'shared/utils'
|
||||
import { APIError, APIHandler } from './helpers/endpoint'
|
||||
import { updateUser } from 'shared/supabase/users'
|
||||
import { broadcastUpdatedUser } from 'shared/websockets/helpers'
|
||||
import { strip } from 'common/socials'
|
||||
import {toUserAPIResponse} from 'common/api/user-types'
|
||||
import {RESERVED_PATHS} from 'common/envs/constants'
|
||||
import {cleanDisplayName, cleanUsername} from 'common/util/clean-username'
|
||||
import {removeUndefinedProps} from 'common/util/object'
|
||||
import {cloneDeep, mapValues} from 'lodash'
|
||||
import {createSupabaseDirectClient} from 'shared/supabase/init'
|
||||
import {getUser, getUserByUsername} from 'shared/utils'
|
||||
import {APIError, APIHandler} from './helpers/endpoint'
|
||||
import {updateUser} from 'shared/supabase/users'
|
||||
import {broadcastUpdatedUser} from 'shared/websockets/helpers'
|
||||
import {strip} from 'common/socials'
|
||||
|
||||
export const updateMe: APIHandler<'me/update'> = async (props, auth) => {
|
||||
const update = cloneDeep(props)
|
||||
@@ -35,10 +35,6 @@ export const updateMe: APIHandler<'me/update'> = async (props, auth) => {
|
||||
const { name, username, avatarUrl, link = {}, ...rest } = update
|
||||
await updateUser(pg, auth.uid, removeUndefinedProps(rest))
|
||||
|
||||
if (update.website != undefined) link.site = update.website
|
||||
if (update.twitterHandle != undefined) link.x = update.twitterHandle
|
||||
if (update.discordHandle != undefined) link.discord = update.discordHandle
|
||||
|
||||
const stripped = mapValues(
|
||||
link,
|
||||
(value, site) => value && strip(site as any, value)
|
||||
@@ -69,23 +65,26 @@ export const updateMe: APIHandler<'me/update'> = async (props, auth) => {
|
||||
newLinks = data?.link
|
||||
}
|
||||
|
||||
if (name || username || avatarUrl) {
|
||||
if (name) {
|
||||
await pg.none(`update users set name = $1 where id = $2`, [
|
||||
name,
|
||||
auth.uid,
|
||||
])
|
||||
}
|
||||
if (username) {
|
||||
await pg.none(`update users set username = $1 where id = $2`, [
|
||||
username,
|
||||
auth.uid,
|
||||
])
|
||||
}
|
||||
if (avatarUrl) {
|
||||
await updateUser(pg, auth.uid, { avatarUrl })
|
||||
}
|
||||
if (name) {
|
||||
await pg.none(`update users
|
||||
set name = $1
|
||||
where id = $2`, [name, auth.uid])
|
||||
}
|
||||
if (username) {
|
||||
await pg.none(`update users
|
||||
set username = $1
|
||||
where id = $2`, [
|
||||
username,
|
||||
auth.uid,
|
||||
])
|
||||
}
|
||||
if (avatarUrl) {
|
||||
await updateUser(pg, auth.uid, {avatarUrl})
|
||||
}
|
||||
|
||||
// Ensure clients listening on `user/{id}` (e.g. AuthContext via useWebsocketUser)
|
||||
// get notified about link-only changes as well.
|
||||
if (name || username || avatarUrl || newLinks != null) {
|
||||
broadcastUpdatedUser(
|
||||
removeUndefinedProps({
|
||||
id: auth.uid,
|
||||
|
||||
@@ -8,8 +8,8 @@ jest.mock('shared/supabase/users');
|
||||
jest.mock('shared/websockets/helpers');
|
||||
jest.mock('common/envs/constants');
|
||||
|
||||
import { updateMe } from "api/update-me";
|
||||
import { toUserAPIResponse } from "common/api/user-types";
|
||||
import {updateMe} from "api/update-me";
|
||||
import {toUserAPIResponse} from "common/api/user-types";
|
||||
import * as cleanUsernameModules from "common/util/clean-username";
|
||||
import * as supabaseInit from "shared/supabase/init";
|
||||
import * as objectUtils from "common/util/object";
|
||||
@@ -17,7 +17,7 @@ import * as lodashModules from "lodash";
|
||||
import * as sharedUtils from "shared/utils";
|
||||
import * as supabaseUsers from "shared/supabase/users";
|
||||
import * as websocketHelperModules from "shared/websockets/helpers";
|
||||
import { AuthedUser } from "api/helpers/endpoint";
|
||||
import {AuthedUser} from "api/helpers/endpoint";
|
||||
|
||||
describe('updateMe', () => {
|
||||
let mockPg = {} as any;
|
||||
@@ -44,12 +44,7 @@ describe('updateMe', () => {
|
||||
name: "mockName",
|
||||
username: "mockUsername",
|
||||
avatarUrl: "mockAvatarUrl",
|
||||
bio: "mockBio",
|
||||
link: {"mockLink" : "mockLinkValue"},
|
||||
optOutBetWarnings:true,
|
||||
website: "mockWebsite",
|
||||
twitterHandle: "mockTwitterHandle",
|
||||
discordHandle: "mockDiscordHandle",
|
||||
};
|
||||
const mockStripped = {
|
||||
bio: "mockBio"
|
||||
@@ -152,12 +147,7 @@ describe('updateMe', () => {
|
||||
name: "mockName",
|
||||
username: "mockUsername",
|
||||
avatarUrl: "mockAvatarUrl",
|
||||
bio: "mockBio",
|
||||
link: {"mockLink" : "mockLinkValue"},
|
||||
optOutBetWarnings:true,
|
||||
website: "mockWebsite",
|
||||
twitterHandle: "mockTwitterHandle",
|
||||
discordHandle: "mockDiscordHandle",
|
||||
};
|
||||
|
||||
(lodashModules.cloneDeep as jest.Mock).mockReturnValue(mockUpdate);
|
||||
@@ -176,12 +166,7 @@ describe('updateMe', () => {
|
||||
name: "mockName",
|
||||
username: "mockUsername",
|
||||
avatarUrl: "mockAvatarUrl",
|
||||
bio: "mockBio",
|
||||
link: {"mockLink" : "mockLinkValue"},
|
||||
optOutBetWarnings:true,
|
||||
website: "mockWebsite",
|
||||
twitterHandle: "mockTwitterHandle",
|
||||
discordHandle: "mockDiscordHandle",
|
||||
};
|
||||
|
||||
(lodashModules.cloneDeep as jest.Mock).mockReturnValue(mockUpdate);
|
||||
@@ -202,12 +187,7 @@ describe('updateMe', () => {
|
||||
name: "mockName",
|
||||
username: "mockUsername",
|
||||
avatarUrl: "mockAvatarUrl",
|
||||
bio: "mockBio",
|
||||
link: {"mockLink" : "mockLinkValue"},
|
||||
optOutBetWarnings:true,
|
||||
website: "mockWebsite",
|
||||
twitterHandle: "mockTwitterHandle",
|
||||
discordHandle: "mockDiscordHandle",
|
||||
};
|
||||
|
||||
const arrySpy = jest.spyOn(Array.prototype, 'includes');
|
||||
@@ -231,12 +211,7 @@ describe('updateMe', () => {
|
||||
name: "mockName",
|
||||
username: "mockUsername",
|
||||
avatarUrl: "mockAvatarUrl",
|
||||
bio: "mockBio",
|
||||
link: {"mockLink" : "mockLinkValue"},
|
||||
optOutBetWarnings:true,
|
||||
website: "mockWebsite",
|
||||
twitterHandle: "mockTwitterHandle",
|
||||
discordHandle: "mockDiscordHandle",
|
||||
};
|
||||
const arrySpy = jest.spyOn(Array.prototype, 'includes');
|
||||
|
||||
|
||||
@@ -208,23 +208,7 @@ export const API = (_apiTypeCheck = {
|
||||
name: z.string().trim().min(1).optional(),
|
||||
username: z.string().trim().min(1).optional(),
|
||||
avatarUrl: z.string().optional(),
|
||||
bio: z.string().optional(),
|
||||
link: z.record(z.string().nullable()).optional(),
|
||||
// settings
|
||||
optOutBetWarnings: z.boolean().optional(),
|
||||
isAdvancedTrader: z.boolean().optional(),
|
||||
//internal
|
||||
shouldShowWelcome: z.boolean().optional(),
|
||||
hasSeenContractFollowModal: z.boolean().optional(),
|
||||
hasSeenLoanModal: z.boolean().optional(),
|
||||
|
||||
// Legacy fields (deprecated)
|
||||
/** @deprecated Use links.site instead */
|
||||
website: z.string().optional(),
|
||||
/** @deprecated Use links.x instead */
|
||||
twitterHandle: z.string().optional(),
|
||||
/** @deprecated Use links.discord instead */
|
||||
discordHandle: z.string().optional(),
|
||||
}),
|
||||
returns: {} as FullUser,
|
||||
summary: 'Update authenticated user profile and settings',
|
||||
|
||||
@@ -90,9 +90,7 @@ export const OptionalProfileUserForm = (props: {
|
||||
setHeightInches(Math.round(h % 12))
|
||||
}
|
||||
|
||||
const [newLinks, setNewLinks] = useState<Record<string, string | null>>(
|
||||
user.link
|
||||
)
|
||||
const [newLinks, setNewLinks] = useState<Record<string, string | null>>(user.link)
|
||||
|
||||
const [newLinkPlatform, setNewLinkPlatform] = useState('')
|
||||
const [newLinkValue, setNewLinkValue] = useState('')
|
||||
@@ -201,7 +199,7 @@ export const OptionalProfileUserForm = (props: {
|
||||
i++
|
||||
}
|
||||
if (profile) {
|
||||
await sleep(5000)
|
||||
await sleep(5000) // attempt to mitigate profile not found at /${username} upon creation
|
||||
router.push(`/${user.username}${fromSignup ? '?fromSignup=true' : ''}`)
|
||||
} else {
|
||||
console.log("Profile not found after fetching, going back home...")
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client'
|
||||
import { PrivateUser, User } from 'common/user'
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
import { AuthContext } from 'web/components/auth-context'
|
||||
import { useIsPageVisible } from './use-page-visible'
|
||||
import { useApiSubscription } from './use-api-subscription'
|
||||
import { getFullUserById, getPrivateUserSafe } from 'web/lib/supabase/users'
|
||||
import {PrivateUser, User} from 'common/user'
|
||||
import {useContext, useEffect, useState} from 'react'
|
||||
import {AuthContext} from 'web/components/auth-context'
|
||||
import {useIsPageVisible} from './use-page-visible'
|
||||
import {useApiSubscription} from './use-api-subscription'
|
||||
import {getFullUserById, getPrivateUserSafe} from 'web/lib/supabase/users'
|
||||
|
||||
export const useUser = () => {
|
||||
const authUser = useContext(AuthContext)
|
||||
@@ -29,7 +29,7 @@ export const useWebsocketUser = (userId: string | undefined) => {
|
||||
useApiSubscription({
|
||||
topics: [`user/${userId ?? '_'}`],
|
||||
onBroadcast: ({ data }) => {
|
||||
console.debug(data)
|
||||
console.debug('User broadcast', {data})
|
||||
setUser((user) => {
|
||||
if (!user || !data.user) {
|
||||
return user
|
||||
|
||||
Reference in New Issue
Block a user