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={
{isLoadingOrganizations ? ( ) : isSuccessOrganizations && organizations.length === 0 ? ( ) : ( )}
} >
{/* 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)