claim-project.tsx129 lines · main
| 1 | import { useParams } from 'common' |
| 2 | import Head from 'next/head' |
| 3 | import { PropsWithChildren, useMemo, useState } from 'react' |
| 4 | import { Admonition } from 'ui-patterns/admonition' |
| 5 | import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' |
| 6 | |
| 7 | import { ProjectClaimBenefits } from '@/components/interfaces/Organization/ProjectClaim/benefits' |
| 8 | import { ProjectClaimChooseOrg } from '@/components/interfaces/Organization/ProjectClaim/choose-org' |
| 9 | import { ProjectClaimConfirm } from '@/components/interfaces/Organization/ProjectClaim/confirm' |
| 10 | import { ProjectClaimLayout } from '@/components/interfaces/Organization/ProjectClaim/layout' |
| 11 | import { useApiAuthorizationQuery } from '@/data/api-authorization/api-authorization-query' |
| 12 | import { useOrganizationProjectClaimQuery } from '@/data/organizations/organization-project-claim-query' |
| 13 | import { useOrganizationsQuery } from '@/data/organizations/organizations-query' |
| 14 | import { useCustomContent } from '@/hooks/custom-content/useCustomContent' |
| 15 | import { withAuth } from '@/hooks/misc/withAuth' |
| 16 | import type { NextPageWithLayout } from '@/types' |
| 17 | |
| 18 | const ClaimProjectPageLayout = ({ children }: PropsWithChildren) => { |
| 19 | const { appTitle } = useCustomContent(['app:title']) |
| 20 | |
| 21 | return ( |
| 22 | <> |
| 23 | <Head> |
| 24 | <title>{`Claim project | ${appTitle ?? 'Briven'}`}</title> |
| 25 | </Head> |
| 26 | {children} |
| 27 | </> |
| 28 | ) |
| 29 | } |
| 30 | |
| 31 | const ClaimProjectPage: NextPageWithLayout = () => { |
| 32 | const { auth_id, token: claimToken } = useParams() |
| 33 | const [selectedOrgSlug, setSelectedOrgSlug] = useState<string>() |
| 34 | const [step, setStep] = useState<'choose-org' | 'benefits' | 'confirm'>('choose-org') |
| 35 | |
| 36 | const { |
| 37 | data: requester, |
| 38 | isPending: isLoadingRequester, |
| 39 | isError: isErrorRequester, |
| 40 | error: errorRequester, |
| 41 | } = useApiAuthorizationQuery({ id: auth_id }) |
| 42 | const { data: organizations } = useOrganizationsQuery() |
| 43 | |
| 44 | const selectedOrganization = useMemo(() => { |
| 45 | return (organizations || []).find((org) => org.slug === selectedOrgSlug) |
| 46 | }, [selectedOrgSlug, organizations]) |
| 47 | |
| 48 | const { |
| 49 | data: projectClaim, |
| 50 | error: errorProjectClaim, |
| 51 | isError: isErrorProjectClaim, |
| 52 | isPending: isLoadingProjectClaim, |
| 53 | isSuccess: isSuccessProjectClaim, |
| 54 | } = useOrganizationProjectClaimQuery( |
| 55 | { |
| 56 | slug: selectedOrgSlug!, |
| 57 | token: claimToken!, |
| 58 | }, |
| 59 | { |
| 60 | enabled: !!claimToken && !!selectedOrgSlug, |
| 61 | } |
| 62 | ) |
| 63 | |
| 64 | if ((selectedOrgSlug && claimToken && isLoadingProjectClaim) || isLoadingRequester) { |
| 65 | return ( |
| 66 | <ProjectClaimLayout title="Claim a project" className="py-6"> |
| 67 | <div className="space-y-2"> |
| 68 | <ShimmeringLoader /> |
| 69 | <ShimmeringLoader className="w-3/4" /> |
| 70 | <ShimmeringLoader className="w-1/2" /> |
| 71 | </div> |
| 72 | </ProjectClaimLayout> |
| 73 | ) |
| 74 | } |
| 75 | |
| 76 | if ((selectedOrgSlug && claimToken && isErrorProjectClaim) || isErrorRequester) { |
| 77 | return ( |
| 78 | <ProjectClaimLayout title="Claim a project" className="py-6"> |
| 79 | <Admonition type="warning" title="Failed to retrieve project claim request details"> |
| 80 | <p>Please retry your claim request from the requesting app</p> |
| 81 | {!!errorProjectClaim && <p className="mt-2">Error: {errorProjectClaim?.message}</p>} |
| 82 | {!!errorRequester && <p className="mt-2">Error: {errorRequester?.message}</p>} |
| 83 | </Admonition> |
| 84 | </ProjectClaimLayout> |
| 85 | ) |
| 86 | } |
| 87 | |
| 88 | if (step === 'choose-org' || !selectedOrganization) { |
| 89 | return ( |
| 90 | <ProjectClaimChooseOrg |
| 91 | onChoose={(orgSlug) => { |
| 92 | setSelectedOrgSlug(orgSlug) |
| 93 | setStep('benefits') |
| 94 | }} |
| 95 | /> |
| 96 | ) |
| 97 | } |
| 98 | |
| 99 | if (isSuccessProjectClaim) { |
| 100 | if (step === 'benefits') { |
| 101 | return ( |
| 102 | <ProjectClaimBenefits |
| 103 | projectClaim={projectClaim} |
| 104 | requester={requester} |
| 105 | onContinue={() => setStep('confirm')} |
| 106 | /> |
| 107 | ) |
| 108 | } |
| 109 | |
| 110 | return ( |
| 111 | <ProjectClaimConfirm |
| 112 | setStep={setStep} |
| 113 | selectedOrganization={selectedOrganization} |
| 114 | projectClaim={projectClaim} |
| 115 | requester={requester} |
| 116 | /> |
| 117 | ) |
| 118 | } |
| 119 | |
| 120 | return null |
| 121 | } |
| 122 | |
| 123 | ClaimProjectPage.getLayout = (page) => ( |
| 124 | <ClaimProjectPageLayout> |
| 125 | <main className="flex flex-col w-full min-h-screen overflow-y-auto">{page}</main> |
| 126 | </ClaimProjectPageLayout> |
| 127 | ) |
| 128 | |
| 129 | export default withAuth(ClaimProjectPage) |