claim-project.tsx129 lines · main
1import { useParams } from 'common'
2import Head from 'next/head'
3import { PropsWithChildren, useMemo, useState } from 'react'
4import { Admonition } from 'ui-patterns/admonition'
5import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
6
7import { ProjectClaimBenefits } from '@/components/interfaces/Organization/ProjectClaim/benefits'
8import { ProjectClaimChooseOrg } from '@/components/interfaces/Organization/ProjectClaim/choose-org'
9import { ProjectClaimConfirm } from '@/components/interfaces/Organization/ProjectClaim/confirm'
10import { ProjectClaimLayout } from '@/components/interfaces/Organization/ProjectClaim/layout'
11import { useApiAuthorizationQuery } from '@/data/api-authorization/api-authorization-query'
12import { useOrganizationProjectClaimQuery } from '@/data/organizations/organization-project-claim-query'
13import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
14import { useCustomContent } from '@/hooks/custom-content/useCustomContent'
15import { withAuth } from '@/hooks/misc/withAuth'
16import type { NextPageWithLayout } from '@/types'
17
18const 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
31const 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
123ClaimProjectPage.getLayout = (page) => (
124 <ClaimProjectPageLayout>
125 <main className="flex flex-col w-full min-h-screen overflow-y-auto">{page}</main>
126 </ClaimProjectPageLayout>
127)
128
129export default withAuth(ClaimProjectPage)