187 lines
5.0 KiB
JavaScript

import { useContext, useEffect, useMemo, useState } from 'react'
import { Alert, Button, Card, Flex, message } from 'antd'
import CheckIcon from '../../../Icons/CheckIcon'
import { useLocation, useNavigate } from 'react-router-dom'
import { LoadingOutlined } from '@ant-design/icons'
import { ApiServerContext } from '../../context/ApiServerContext'
import {
clearMarketplaceAuthState,
parseMarketplaceAuthState,
readMarketplaceAuthState
} from './authUtils'
import { AuthContext } from '../../context/AuthContext'
import AuthParticles from '../../../App/AppParticles'
import FarmControlLogo from '../../../Logos/FarmControlLogo'
import ExclamationOctagonIcon from '../../../Icons/ExclamationOctagonIcon'
import ArrowLeftIcon from '../../../Icons/ArrowLeftIcon'
const MarketplaceAuthCallback = () => {
const location = useLocation()
const navigate = useNavigate()
const { token } = useContext(AuthContext)
const { sendObjectFunction, connected } = useContext(ApiServerContext)
const [status, setStatus] = useState('loading')
const [redirectLoading, setRedirectLoading] = useState(false)
const [resultMessage, setResultMessage] = useState('')
const params = useMemo(
() => new URLSearchParams(location.search),
[location.search]
)
const rawState = params.get('state') || ''
const parsedState = parseMarketplaceAuthState(rawState)
const storedState = readMarketplaceAuthState(rawState)
const marketplaceId =
params.get('marketplaceId') ||
parsedState?.marketplaceId ||
storedState?.marketplaceId ||
''
const returnTo =
parsedState?.returnTo ||
storedState?.returnTo ||
(marketplaceId
? `/dashboard/sales/marketplaces/info?marketplaceId=${marketplaceId}`
: '/dashboard/sales/marketplaces')
useEffect(() => {
if (!connected || token == null || !token) {
return
}
const error = params.get('error') || params.get('error_description')
const code = params.get('code') || params.get('auth_code')
if (error) {
setStatus('error')
setResultMessage(error)
if (rawState) {
clearMarketplaceAuthState(rawState)
}
return
}
if (!marketplaceId) {
setStatus('error')
setResultMessage('Could not determine which marketplace to connect.')
return
}
if (!code) {
setStatus('error')
setResultMessage('Authorization code was not returned by the provider.')
return
}
let cancelled = false
const exchangeCode = async () => {
try {
const result = await sendObjectFunction(
marketplaceId,
'Marketplace',
'auth/exchange',
{
code,
state: rawState
}
)
if (!result?.success) {
throw new Error(
result?.error || 'Failed to complete marketplace authorization.'
)
}
if (cancelled) {
return
}
setStatus('success')
setResultMessage('Marketplace authorization completed successfully.')
message.success('Marketplace connected')
if (rawState) {
clearMarketplaceAuthState(rawState)
}
} catch (error) {
if (cancelled) {
return
}
console.error('Marketplace auth callback failed:', error)
setStatus('error')
setResultMessage(
error?.response?.data?.error ||
error?.message ||
'Failed to complete marketplace authorization.'
)
}
}
exchangeCode()
return () => {
cancelled = true
}
}, [marketplaceId, params, rawState, sendObjectFunction, token, connected])
return (
<>
<AuthParticles />
<Flex
align='center'
justify='center'
vertical
style={{ height: '100vh' }}
gap='large'
>
<Card style={{ borderRadius: 20 }}>
<Flex vertical align='center'>
<FarmControlLogo style={{ fontSize: '500px', height: '40px' }} />
</Flex>
</Card>
{status != 'error' && status != 'success' && (
<Alert
message='Completing provider authorization...'
icon={<LoadingOutlined />}
type='info'
showIcon
/>
)}
{status === 'success' && (
<Alert
message={resultMessage}
icon={<CheckIcon />}
type='success'
showIcon
/>
)}
{status === 'error' && (
<Alert
message={resultMessage}
icon={<ExclamationOctagonIcon />}
type='error'
showIcon
/>
)}
<Flex gap='middle'>
<Button
icon={<ArrowLeftIcon />}
onClick={() => {
setRedirectLoading(true)
navigate(returnTo)
}}
loading={redirectLoading}
disabled={status === 'loading' || redirectLoading}
size='large'
></Button>
</Flex>
</Flex>
</>
)
}
export default MarketplaceAuthCallback