[[...routeSlug]].tsx138 lines · main
1import { IS_PLATFORM, LOCAL_STORAGE_KEYS, useParams } from 'common'
2import { AlertTriangleIcon } from 'lucide-react'
3import { NextPage } from 'next'
4import { useRouter } from 'next/router'
5import { useEffect, useState } from 'react'
6import {
7 Alert,
8 AlertDescription,
9 AlertTitle,
10 Select,
11 SelectContent,
12 SelectItem,
13 SelectTrigger,
14 SelectValue,
15} from 'ui'
16import { ShimmeringLoader } from 'ui-patterns'
17
18import {
19 Header,
20 LoadingCardView,
21 NoOrganizationsState,
22} from '@/components/interfaces/Home/ProjectList/EmptyStates'
23import { ProjectList } from '@/components/interfaces/Home/ProjectList/ProjectList'
24import { HomePageActions } from '@/components/interfaces/HomePageActions'
25import { PageLayout } from '@/components/layouts/PageLayout/PageLayout'
26import { ScaffoldContainer, ScaffoldSection } from '@/components/layouts/Scaffold'
27import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
28import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage'
29import { withAuth } from '@/hooks/misc/withAuth'
30
31// [Joshen] I'd say we don't do route validation here, this page will act more
32// like a proxy to the project specific pages, and we let those pages handle
33// any route validation logic instead
34
35const GenericProjectPage: NextPage = () => {
36 const router = useRouter()
37 const { slug } = useParams()
38 const { routeSlug, ...queryParams } = router.query
39
40 const [lastVisitedOrgSlug] = useLocalStorageQuery(
41 LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION,
42 ''
43 )
44
45 const {
46 data: organizations = [],
47 isSuccess: isSuccessOrganizations,
48 isPending: isLoadingOrganizations,
49 isError: isErrorOrganizations,
50 } = useOrganizationsQuery({
51 enabled: IS_PLATFORM,
52 })
53
54 const [selectedSlug, setSlug] = useState<string>(
55 slug || lastVisitedOrgSlug || organizations[0]?.slug
56 )
57 const selectedOrganization = organizations.find((x) => x.slug === selectedSlug)
58
59 const query = Object.keys(queryParams).length
60 ? `?${new URLSearchParams(queryParams as Record<string, string>)}`
61 : undefined
62
63 const urlRewriterFactory = (slug: string | string[] | undefined) => {
64 return (projectRef: string) => {
65 const hash = location.hash
66
67 if (!Array.isArray(slug)) {
68 return [`/project/${projectRef}`, query, hash].filter(Boolean).join('')
69 }
70
71 const slugPath = slug.join('/')
72 return [`/project/${projectRef}/${slugPath}`, query, hash].filter(Boolean).join('')
73 }
74 }
75
76 useEffect(() => {
77 if (!!lastVisitedOrgSlug) {
78 setSlug(lastVisitedOrgSlug)
79 } else if (isSuccessOrganizations) {
80 setSlug(organizations[0]?.slug)
81 }
82 // eslint-disable-next-line react-hooks/exhaustive-deps
83 }, [lastVisitedOrgSlug, isSuccessOrganizations])
84
85 return (
86 <div className="h-screen flex flex-col">
87 <Header />
88 <PageLayout className="grow min-h-0" title="Select a project to continue">
89 <ScaffoldContainer className="grow flex flex-col gap-y-4">
90 <ScaffoldSection isFullWidth className="py-0">
91 <div className="flex items-center gap-x-2">
92 {isLoadingOrganizations ? (
93 <ShimmeringLoader className="w-60 py-0 h-[26px]" />
94 ) : (
95 <Select value={selectedSlug} onValueChange={setSlug}>
96 <SelectTrigger size="tiny" className="w-60 truncate">
97 <div className="flex items-center gap-x-2">
98 <p className="text-xs text-foreground-light">Organization:</p>
99 <SelectValue placeholder="Select an organization" />
100 </div>
101 </SelectTrigger>
102 <SelectContent className="col-span-8">
103 {organizations.map((org) => (
104 <SelectItem key={org.slug} value={org.slug} className="text-xs">
105 {org.name}
106 </SelectItem>
107 ))}
108 </SelectContent>
109 </Select>
110 )}
111 <HomePageActions hideNewProject />
112 </div>
113 </ScaffoldSection>
114 <ScaffoldSection isFullWidth className="py-0">
115 {isLoadingOrganizations ? (
116 <LoadingCardView />
117 ) : isErrorOrganizations ? (
118 <Alert variant="warning">
119 <AlertTriangleIcon />
120 <AlertTitle>Failed to load your Briven organizations</AlertTitle>
121 <AlertDescription>Try refreshing the page</AlertDescription>
122 </Alert>
123 ) : organizations.length === 0 ? (
124 <NoOrganizationsState />
125 ) : !!selectedOrganization ? (
126 <ProjectList
127 organization={selectedOrganization}
128 rewriteHref={urlRewriterFactory(routeSlug)}
129 />
130 ) : null}
131 </ScaffoldSection>
132 </ScaffoldContainer>
133 </PageLayout>
134 </div>
135 )
136}
137
138export default withAuth(GenericProjectPage)