Files
supabase/apps/studio/components/interfaces/Auth/Users/Users.utils.ts
T
Joshen Lim 6af9ff6061 Chore/user management v2 panel (#29468)
* Midway implementing user management v2 panel

* Do up overview panel less provider information

* Midway provider info

* Wrap up provider information

* Add banned until banner

* Slight adjustment to search input

* Fix

* Fix provider icons in data grid

* Fix

* Moar fixes

* Add loading line

* Address some feedback

* Reorder some elements in the user overview panel

* Fix icons going over cell headers
2024-09-25 12:40:18 +08:00

159 lines
4.2 KiB
TypeScript

import { UIEvent } from 'react'
import { User } from 'data/auth/users-query'
import { BASE_PATH } from 'lib/constants'
export const isAtBottom = ({ currentTarget }: UIEvent<HTMLDivElement>): boolean => {
return currentTarget.scrollTop + 10 >= currentTarget.scrollHeight - currentTarget.clientHeight
}
export const formatUsersData = (users: User[]) => {
return users.map((user) => {
const provider: string = user.raw_app_meta_data?.provider ?? ''
const providers: string[] = user.raw_app_meta_data?.providers ?? []
return {
id: user.id,
email: user.email,
phone: user.phone,
created_at: user.created_at,
last_sign_in_at: user.last_sign_in_at,
providers: user.is_anonymous ? '-' : providers,
provider_icons: providers
.map((p) => {
return p === 'email'
? `${BASE_PATH}/img/icons/email-icon2.svg`
: providerIconMap[p]
? `${BASE_PATH}/img/icons/${providerIconMap[p]}.svg`
: undefined
})
.filter(Boolean),
// I think it's alright to just check via the main provider since email and phone should be mutually exclusive
provider_type: user.is_anonymous
? 'Anonymous'
: socialProviders.includes(provider)
? 'Social'
: phoneProviders.includes(provider)
? 'Phone'
: '-',
// [Joshen] Note that the images might not load due to CSP issues
img: getAvatarUrl(user),
name: getDisplayName(user),
}
})
}
const providers = {
social: [
// { email: 'email-icon2' },
{ apple: 'apple-icon' },
{ azure: 'microsoft-icon' },
{ bitbucket: 'bitbucket-icon' },
{ discord: 'discord-icon' },
{ facebook: 'facebook-icon' },
{ figma: 'figma-icon' },
{ github: 'github-icon' },
{ gitlab: 'gitlab-icon' },
{ google: 'google-icon' },
{ kakao: 'kakao-icon' },
{ keycloak: 'keycloak-icon' },
{ linkedin: 'linkedin-icon' },
{ notion: 'notion-icon' },
{ twitch: 'twitch-icon' },
{ twitter: 'twitter-icon' },
{ slack: 'slack-icon' },
{ spotify: 'spotify-icon' },
{ workos: 'workos-icon' },
{ zoom: 'zoom-icon' },
],
phone: [
{ twilio: 'twilio-icon' },
{ messagebird: 'messagebird-icon' },
{ textlocal: 'messagebird-icon' },
{ vonage: 'messagebird-icon' },
{ twilioverify: 'twilio-verify-icon' },
],
}
// [Joshen] Just FYI this is not stress tested as I'm not sure what
// all the potential values for each provider is under user.raw_app_meta_data.provider
// Will need to go through one by one to properly verify https://supabase.com/docs/guides/auth/social-login
// But I've made the UI handle to not render any icon if nothing matches in this map
export const providerIconMap: { [key: string]: string } = Object.values([
...providers.social,
...providers.phone,
]).reduce((a, b) => {
const [[key, value]] = Object.entries(b)
return { ...a, [key]: value }
}, {})
const socialProviders = providers.social.map((x) => {
const [key] = Object.keys(x)
return key
})
const phoneProviders = providers.phone.map((x) => {
const [key] = Object.keys(x)
return key
})
export function getDisplayName(user: User, fallback = '-'): string {
const {
displayName,
display_name,
fullName,
full_name,
familyName,
family_name,
givenName,
given_name,
surname,
lastName,
last_name,
firstName,
first_name,
} = user.raw_user_meta_data ?? {}
const last = familyName || family_name || surname || lastName || last_name
const first = givenName || given_name || firstName || first_name
return (
displayName ||
display_name ||
fullName ||
full_name ||
(first && last && `${first} ${last}`) ||
fallback
)
}
export function getAvatarUrl(user: User): string | undefined {
const {
avatarUrl,
avatarURL,
avatar_url,
profileUrl,
profileURL,
profile_url,
profileImage,
profile_image,
profileImageUrl,
profileImageURL,
profile_image_url,
} = user.raw_user_meta_data ?? {}
return (
avatarUrl ||
avatarURL ||
avatar_url ||
profileImage ||
profile_image ||
profileUrl ||
profileURL ||
profile_url ||
profileImageUrl ||
profileImageURL ||
profile_image_url
)
}