mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
135 lines
3.7 KiB
TypeScript
135 lines
3.7 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { useNavigate, useParams } from 'react-router-dom'
|
|
import { toast } from 'react-toastify'
|
|
|
|
import { useAuth } from '#components/Auth/useAuth'
|
|
import { useMyProfile } from '#components/Map/hooks/useMyProfile'
|
|
import { MapOverlayPage } from '#components/Templates/MapOverlayPage'
|
|
|
|
import type { FullItemsApi } from '#types/FullItemsApi'
|
|
import type { InviteApi } from '#types/InviteApi'
|
|
import type { Item } from '#types/Item'
|
|
|
|
interface Props {
|
|
inviteApi: InviteApi
|
|
itemsApi: FullItemsApi<Item>
|
|
}
|
|
|
|
/**
|
|
* @category Onboarding
|
|
*/
|
|
export function InvitePage({ inviteApi, itemsApi }: Props) {
|
|
const { isAuthenticated, isInitialized: isAuthenticationInitialized } = useAuth()
|
|
const { id } = useParams<{ id: string }>()
|
|
const navigate = useNavigate()
|
|
|
|
const { myProfile, isMyProfileLoaded } = useMyProfile()
|
|
|
|
if (!id) throw new Error('Invite ID is required')
|
|
|
|
const [invitingProfile, setInvitingProfile] = useState<Item | null>(null)
|
|
|
|
useEffect(() => {
|
|
async function redeemInvite() {
|
|
if (!id) throw new Error('Invite ID is required')
|
|
|
|
if (!isMyProfileLoaded) return
|
|
|
|
if (!myProfile) {
|
|
toast.error('Could not find your profile to redeem the invite.')
|
|
return
|
|
}
|
|
|
|
const invitingProfileId = await inviteApi.redeemInvite(id, myProfile.id)
|
|
|
|
if (invitingProfileId) {
|
|
toast.success('Invite redeemed successfully!')
|
|
navigate(`/item/${invitingProfileId}`)
|
|
} else {
|
|
toast.error('Failed to redeem invite')
|
|
navigate('/')
|
|
}
|
|
}
|
|
|
|
async function validateInvite() {
|
|
if (!id) throw new Error('Invite ID is required')
|
|
|
|
const invitingProfileId = await inviteApi.validateInvite(id)
|
|
|
|
if (!invitingProfileId) {
|
|
toast.error('Invalid invite code')
|
|
navigate('/')
|
|
return
|
|
}
|
|
|
|
const invitingProfile = await itemsApi.getItem(invitingProfileId)
|
|
|
|
if (!invitingProfile) {
|
|
toast.error('Inviting profile not found')
|
|
navigate('/')
|
|
return
|
|
}
|
|
|
|
setInvitingProfile(invitingProfile)
|
|
}
|
|
|
|
if (!isAuthenticationInitialized) return
|
|
|
|
if (isAuthenticated) {
|
|
void redeemInvite()
|
|
} else {
|
|
// Save invite code in local storage
|
|
localStorage.setItem('inviteCode', id)
|
|
|
|
void validateInvite()
|
|
}
|
|
}, [
|
|
id,
|
|
isAuthenticated,
|
|
inviteApi,
|
|
navigate,
|
|
isAuthenticationInitialized,
|
|
myProfile,
|
|
isMyProfileLoaded,
|
|
itemsApi,
|
|
])
|
|
|
|
const goToSignup = () => {
|
|
navigate('/signup')
|
|
}
|
|
|
|
const goToLogin = () => {
|
|
navigate('/login')
|
|
}
|
|
|
|
return (
|
|
<MapOverlayPage backdrop className='tw:max-w-xs tw:h-fit'>
|
|
<h2 className='tw:text-2xl tw:font-semibold tw:mb-2 tw:text-center'>Invitation</h2>
|
|
{invitingProfile ? (
|
|
<div className='tw-text-center tw-mb-4'>
|
|
<p className='tw-text-lg tw-font-semibold'>Welcome to Utopia!</p>
|
|
<p className='tw-text-sm tw-text-gray-600'>
|
|
You have been invited by: <strong>{invitingProfile.name}</strong> to join the Utopia
|
|
community.
|
|
</p>
|
|
<div className='tw-flex tw:justify-center tw:mt-4'>
|
|
<button
|
|
className='tw-btn tw-btn-primary'
|
|
onClick={isAuthenticated ? () => navigate('/') : goToSignup}
|
|
>
|
|
{isAuthenticated ? 'Go to Dashboard' : 'Sign Up'}
|
|
</button>
|
|
{!isAuthenticated && (
|
|
<button className='tw-btn tw-btn-secondary' onClick={goToLogin}>
|
|
Login
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<p className='tw-text-center'>Validating invite...</p>
|
|
)}
|
|
</MapOverlayPage>
|
|
)
|
|
}
|