| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- // @ts-nocheck
- import * as Sentry from '@sentry/nextjs'
- import { useIsLoggedIn, useUser } from 'common'
- import { useRouter } from 'next/router'
- import { createContext, PropsWithChildren, useContext, useEffect, useMemo } from 'react'
- import { toast } from 'sonner'
- import { useSignOut } from './auth'
- import { getGitHubProfileImgUrl } from './github'
- import { usePermissionsQuery } from '@/data/permissions/permissions-query'
- import { useProfileCreateMutation } from '@/data/profile/profile-create-mutation'
- import { useProfileIdentitiesQuery } from '@/data/profile/profile-identities-query'
- import { useProfileQuery } from '@/data/profile/profile-query'
- import type { Profile } from '@/data/profile/types'
- import { useSendEventMutation } from '@/data/telemetry/send-event-mutation'
- import type { ResponseError } from '@/types'
- export type ProfileContextType = {
- profile: Profile | undefined
- error: ResponseError | null
- isLoading: boolean
- isError: boolean
- isSuccess: boolean
- }
- export const ProfileContext = createContext<ProfileContextType>({
- profile: undefined,
- error: null,
- isLoading: true,
- isError: false,
- isSuccess: false,
- })
- export const ProfileProvider = ({ children }: PropsWithChildren<{}>) => {
- const user = useUser()
- const isLoggedIn = useIsLoggedIn()
- const router = useRouter()
- const signOut = useSignOut()
- const { mutate: sendEvent } = useSendEventMutation()
- const { mutate: createProfile, isPending: isCreatingProfile } = useProfileCreateMutation({
- onSuccess: () => {
- sendEvent({ action: 'sign_up', properties: { category: 'conversion' } })
- if (user) {
- // Send an event to GTM, will do nothing if GTM is not enabled
- const thisWindow = window as any
- thisWindow.dataLayer = thisWindow.dataLayer || []
- thisWindow.dataLayer.push({
- event: 'sign_up',
- email: user.email,
- })
- }
- },
- onError: (error) => {
- if (error.code === 409) {
- // [Joshen] There's currently an assumption that createProfile is getting triggered
- // multiple times unnecessarily, although the tracing the code i can't see why this might
- // be happening unless GET profile is somehow returning `User's profile not found` incorrectly
- // Adding a Sentry capture + toast in hopes to catch this while developing on local / staging
- Sentry.captureMessage('Profile already exists: ' + error.message)
- if (process.env.NEXT_PUBLIC_ENVIRONMENT !== 'prod') {
- toast.error('[DEV] createProfile called despite profile already exists: ' + error.message)
- }
- } else {
- Sentry.captureMessage('Failed to create users profile: ' + error.message)
- toast.error('Failed to create your profile. Please refresh to try again.')
- }
- },
- })
- // Track telemetry for the current user
- const {
- error,
- data: profile,
- isPending: isLoadingProfile,
- isError,
- isSuccess,
- } = useProfileQuery({
- enabled: isLoggedIn,
- })
- useEffect(() => {
- if (!isError) return
- // if the user does not yet exist, create a profile for them
- if (error?.message === "User's profile not found") {
- createProfile()
- }
- // [Alaister] If the user has a bad auth token, auth-js won't know about it
- // and will think the user is authenticated. Since fetching the profile happens
- // on every page load, we can check for a 401 here and sign the user out if
- // they have a bad token.
- if (error?.code === 401) {
- signOut().then(() => router.push('/sign-in'))
- }
- }, [error, signOut, router, createProfile, isError])
- const { isInitialLoading: isLoadingPermissions } = usePermissionsQuery({ enabled: isLoggedIn })
- const value = useMemo(() => {
- const isLoading = isLoadingProfile || isCreatingProfile || isLoadingPermissions
- return {
- error,
- profile,
- isLoading,
- isError,
- isSuccess,
- }
- }, [
- isLoadingProfile,
- isCreatingProfile,
- isLoadingPermissions,
- profile,
- error,
- isError,
- isSuccess,
- ])
- return <ProfileContext.Provider value={value}>{children}</ProfileContext.Provider>
- }
- export const useProfile = () => useContext(ProfileContext)
- export function useProfileNameAndPicture(): {
- username?: string
- primaryEmail?: string
- avatarUrl?: string
- isLoading: boolean
- } {
- const { profile, isLoading: isLoadingProfile } = useProfile()
- const { data: identitiesData, isPending: isLoadingIdentities } = useProfileIdentitiesQuery()
- const isGitHubProfile = profile?.auth0_id?.startsWith('github')
- const gitHubUsername = isGitHubProfile
- ? identitiesData?.identities.find((x) => x.provider === 'github')?.identity_data?.user_name
- : undefined
- const avatarUrl = isGitHubProfile ? getGitHubProfileImgUrl(gitHubUsername) : undefined
- return {
- username: profile?.username,
- primaryEmail: profile?.primary_email,
- avatarUrl,
- isLoading: isLoadingProfile || isLoadingIdentities,
- }
- }
|