import { useParams } from 'common'
import dayjs from 'dayjs'
import { AlertCircle } from 'lucide-react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { toast } from 'sonner'
import AuthorizeRequesterDetails from 'components/interfaces/Organization/OAuthApps/AuthorizeRequesterDetails'
import APIAuthorizationLayout from 'components/layouts/APIAuthorizationLayout'
import { FormPanel } from 'components/ui/Forms/FormPanel'
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
import { useApiAuthorizationApproveMutation } from 'data/api-authorization/api-authorization-approve-mutation'
import { useApiAuthorizationDeclineMutation } from 'data/api-authorization/api-authorization-decline-mutation'
import { useApiAuthorizationQuery } from 'data/api-authorization/api-authorization-query'
import { useOrganizationsQuery } from 'data/organizations/organizations-query'
import { withAuth } from 'hooks/misc/withAuth'
import type { NextPageWithLayout } from 'types'
import {
Alert,
Alert_Shadcn_,
AlertDescription_Shadcn_,
AlertTitle_Shadcn_,
Button,
Listbox,
} from 'ui'
// Need to handle if no organizations in account
// Need to handle if not logged in yet state
const APIAuthorizationPage: NextPageWithLayout = () => {
const router = useRouter()
const { auth_id } = useParams()
const [isApproving, setIsApproving] = useState(false)
const [isDeclining, setIsDeclining] = useState(false)
const [selectedOrgSlug, setSelectedOrgSlug] = useState()
const {
data: organizations,
isSuccess: isSuccessOrganizations,
isLoading: isLoadingOrganizations,
} = useOrganizationsQuery()
const { data: requester, isLoading, isError, error } = useApiAuthorizationQuery({ id: auth_id })
const isApproved = (requester?.approved_at ?? null) !== null
const isExpired = dayjs().isAfter(dayjs(requester?.expires_at))
const { mutate: approveRequest } = useApiAuthorizationApproveMutation({
onSuccess: (res) => {
window.location.href = res.url
},
})
const { mutate: declineRequest } = useApiAuthorizationDeclineMutation({
onSuccess: () => {
toast.success('Declined API authorization request')
router.push('/projects')
},
})
useEffect(() => {
if (isSuccessOrganizations && organizations.length > 0) {
setSelectedOrgSlug(organizations[0].slug)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSuccessOrganizations])
const onApproveRequest = async () => {
if (!auth_id) {
return toast.error('Unable to approve request: auth_id is missing ')
}
if (!selectedOrgSlug) {
return toast.error('Unable to approve request: No organization selected')
}
setIsApproving(true)
approveRequest({ id: auth_id, slug: selectedOrgSlug }, { onError: () => setIsApproving(false) })
}
const onDeclineRequest = async () => {
if (!auth_id) {
return toast.error('Unable to decline request: auth_id is missing ')
}
if (!selectedOrgSlug) {
return toast.error('Unable to decline request: No organization selected')
}
setIsDeclining(true)
declineRequest({ id: auth_id, slug: selectedOrgSlug }, { onError: () => setIsDeclining(false) })
}
if (isLoading) {
return (
Authorize API access
}>
)
}
if (auth_id === undefined) {
return (
Authorization for API access}>
Please provide a valid authorization ID in the URL
)
}
if (isError) {
return (
Authorize API access}>
Please retry your authorization request from the requesting app
{error !== undefined && Error: {error?.message}
}
)
}
if (isApproved) {
const approvedOrganization = organizations?.find(
(org) => org?.slug === requester.approved_organization_slug
)
return (
Authorize API access for {requester?.name}}>
{requester.name} has read and write access to the organization "
{approvedOrganization?.name ?? 'Unknown'}" and all of its projects
Approved on: {dayjs(requester.approved_at).format('DD MMM YYYY HH:mm:ss (ZZ)')}
)
}
const searchParams = new URLSearchParams(location.search)
let pathname = location.pathname
const basePath = process.env.NEXT_PUBLIC_BASE_PATH
if (basePath) {
pathname = pathname.replace(basePath, '')
}
searchParams.set('returnTo', pathname)
return (
Authorize API access for {requester?.name}}
footer={
Decline
{isLoadingOrganizations ? (
Authorize {requester?.name}
) : isSuccessOrganizations && organizations.length === 0 ? (
Create an organization
) : (
Authorize {requester?.name}
)}
}
>
{/* API Authorization requester details */}
{/* Expiry warning */}
{isExpired && (
Please retry your authorization request from the requesting app
)}
{/* Organization selection */}
{isLoadingOrganizations ? (
) : organizations?.length === 0 ? (
Organization is needed for installing an integration
Your account isn't associated with any organizations. To use this integration, it must
be installed within an organization. You'll be redirected to create an organization
first.
) : (
{(organizations ?? []).map((organization) => (
{organization.name}
))}
)}
)
}
APIAuthorizationPage.getLayout = (page) => {page}
export default withAuth(APIAuthorizationPage)