chore: move AccountLayout to getLayout

This commit is contained in:
Alaister Young committed 2022-04-28 20:31:17 +10:00
1 parent e2e534eac1
commit b0d5c849a4
6 files changed
+195 -164

No files matched your search

@@ -3,7 +3,7 @@ import { useRouter } from 'next/router'
import { observer } from 'mobx-react-lite'
import { API_URL, IS_PLATFORM } from 'lib/constants'
import { useStore } from 'hooks'
import { useStore, withAuth } from 'hooks'
import WithSidebar from './WithSidebar'
import { auth } from 'lib/gotrue'
@@ -118,7 +118,7 @@ const AccountLayout = ({ children, title, breadcrumbs }: any) => {
<div className="flex h-full">
<main
style={{ maxHeight: '100vh' }}
className="w-full flex flex-col flex-1 overflow-y-auto"
className="flex w-full flex-1 flex-col overflow-y-auto"
>
<WithSidebar title={title} breadcrumbs={breadcrumbs} links={linksWithHeaders}>
{children}
@@ -129,4 +129,6 @@ const AccountLayout = ({ children, title, breadcrumbs }: any) => {
)
}
export default observer(AccountLayout)
export default withAuth(observer(AccountLayout))
export const AccountLayoutWithoutAuth = observer(AccountLayout)
+5 -3
View File
@@ -6,12 +6,13 @@ import DatabaseLayout from './DatabaseLayout/DatabaseLayout'
import DocsLayout from './DocsLayout/DocsLayout'
import SettingsLayout from './SettingsLayout/SettingsLayout'
import StorageLayout from './StorageLayout/StorageLayout'
import AccountLayout from './AccountLayout/AccountLayout'
import { AccountLayoutWithoutAuth } from './AccountLayout/AccountLayout'
import WizardLayout from './WizardLayout'
import VercelIntegrationLayout from './VercelIntegrationLayout'
import BillingLayout from './BillingLayout'
import LogsExplorerLayout from './LogsExplorerLayout/LogsExplorerLayout'
export {
AuthLayout,
DatabaseLayout,
@@ -21,10 +22,11 @@ export {
SettingsLayout,
StorageLayout,
AccountLayout,
AccountLayoutWithoutAuth,
WizardLayout,
VercelIntegrationLayout,
BillingLayout,
LogsExplorerLayout
LogsExplorerLayout,
}
export default ProjectLayout
+22 -17
View File
@@ -2,32 +2,37 @@ import React from 'react'
import { observer } from 'mobx-react-lite'
import { IconMoon, IconSun, Typography, Input, Listbox } from '@supabase/ui'
import { useProfile, useStore, withAuth } from 'hooks'
import { useProfile, useStore } from 'hooks'
import { post } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { AccountLayout } from 'components/layouts'
import Panel from 'components/to-be-cleaned/Panel'
import SchemaFormPanel from 'components/to-be-cleaned/forms/SchemaFormPanel'
import { NextPageWithLayout } from 'types'
const User = () => {
const User: NextPageWithLayout = () => {
return (
<AccountLayout
title="Supabase"
breadcrumbs={[
{
key: `supabase-settings`,
label: 'Preferences',
},
]}
>
<div className="my-2">
<ProfileCard />
</div>
</AccountLayout>
<div className="my-2">
<ProfileCard />
</div>
)
}
export default withAuth(User)
User.getLayout = (page) => (
<AccountLayout
title="Supabase"
breadcrumbs={[
{
key: `supabase-settings`,
label: 'Preferences',
},
]}
>
{page}
</AccountLayout>
)
export default User
const ProfileCard = observer(() => {
const { ui } = useStore()
@@ -50,7 +55,7 @@ const ProfileCard = observer(() => {
}
return (
<article className="p-4 max-w-4xl">
<article className="max-w-4xl p-4">
<section>
<GithubProfile />
</section>
+22 -18
View File
@@ -1,25 +1,29 @@
import { withAuth } from 'hooks'
import { AccountLayout } from 'components/layouts'
import { AccessTokenList, NewAccessTokenButton } from 'components/interfaces/Account'
import { NextPageWithLayout } from 'types'
const UserAccessTokens = () => {
const UserAccessTokens: NextPageWithLayout = () => {
return (
<AccountLayout
title="Supabase"
breadcrumbs={[
{
key: `supabase-account-tokens`,
label: 'Access Tokens',
},
]}
>
<div className="p-4 pt-0 mt-4 space-y-8">
<h2 className="text-xl">Access Tokens</h2>
<NewAccessTokenButton />
<AccessTokenList />
</div>
</AccountLayout>
<div className="mt-4 space-y-8 p-4 pt-0">
<h2 className="text-xl">Access Tokens</h2>
<NewAccessTokenButton />
<AccessTokenList />
</div>
)
}
export default withAuth(UserAccessTokens)
UserAccessTokens.getLayout = (page) => (
<AccountLayout
title="Supabase"
breadcrumbs={[
{
key: `supabase-account-tokens`,
label: 'Access Tokens',
},
]}
>
{page}
</AccountLayout>
)
export default UserAccessTokens
+57 -41
View File
@@ -5,53 +5,27 @@ import { NextRouter, useRouter } from 'next/router'
import { isUndefined } from 'lodash'
import { Typography } from '@supabase/ui'
import { Project } from 'types'
import { NextPageWithLayout, Project } from 'types'
import { useStore, withAuth } from 'hooks'
import { auth } from 'lib/gotrue'
import { post, delete_ } from 'lib/common/fetch'
import { API_URL, IS_PLATFORM, PROJECT_STATUS } from 'lib/constants'
import Connecting from 'components/ui/Loading'
import { AccountLayout } from 'components/layouts'
import { AccountLayoutWithoutAuth } from 'components/layouts'
import Landing from 'components/interfaces/Home/Landing'
import ProjectList from 'components/interfaces/Home/ProjectList'
import OrganizationDropdown from 'components/to-be-cleaned/Dropdown/OrganizationDropdown'
import TextConfirmModal from 'components/to-be-cleaned/ModalsDeprecated/TextConfirmModal'
const Home: NextPage = () => {
const Home: NextPageWithLayout = () => {
const { app, ui } = useStore()
const { profile } = ui
const router = useRouter()
const [isDeletingProject, setIsDeletingProject] = useState<boolean>(false)
const [selectedProjectToDelete, setSelectedProjectToDelete] = useState<Project>()
if (!profile) {
return <UnauthorizedLanding />
} else {
const isRedirect = isRedirectFromThirdPartyService(router)
if (isRedirect) {
const queryParams = (router.query as any) || {}
const params = new URLSearchParams(queryParams)
if (router.query?.next?.includes('https://vercel.com')) {
router.push(`/vercel/integrate?${params.toString()}`)
} else if (router.query?.next?.includes('new-project')) {
router.push('/new/project')
} else if (router.query['x-amzn-marketplace-token'] != undefined) {
router.push(`/account/associate?${params.toString()}`)
} else if (
typeof router.query?.next === 'string' &&
router.query?.next?.startsWith('project/_/')
) {
router.push(router.query.next as string)
} else {
router.push('/')
}
return <Connecting />
}
}
const onSelectDeleteProject = async (project: Project) => {
setSelectedProjectToDelete(project)
setIsDeletingProject(false)
@@ -80,16 +54,7 @@ const Home: NextPage = () => {
}
return (
<AccountLayout
title="Supabase"
// @ts-ignore
breadcrumbs={[
{
key: `supabase-projects`,
label: 'Projects',
},
]}
>
<>
{app.organizations.isLoading ? (
<div className="flex h-full items-center justify-center space-x-2">
<Connecting />
@@ -132,10 +97,13 @@ const Home: NextPage = () => {
onCancel={() => setSelectedProjectToDelete(undefined)}
onConfirm={() => onDeleteProject(selectedProjectToDelete)}
/>
</AccountLayout>
</>
)
}
export default withAuth(observer(Home))
Home.getLayout = (page) => <IndexLayout>{page}</IndexLayout>
export default observer(Home)
// detect for redirect from 3rd party service like vercel, aws...
function isRedirectFromThirdPartyService(router: NextRouter) {
@@ -162,3 +130,51 @@ const UnauthorizedLanding = () => {
return autoLogin ? <Connecting /> : <Landing />
}
const IndexLayout = withAuth(
observer(({ children }) => {
const { ui } = useStore()
const { profile } = ui
const router = useRouter()
if (!profile) {
return <UnauthorizedLanding />
} else {
const isRedirect = isRedirectFromThirdPartyService(router)
if (isRedirect) {
const queryParams = (router.query as any) || {}
const params = new URLSearchParams(queryParams)
if (router.query?.next?.includes('https://vercel.com')) {
router.push(`/vercel/integrate?${params.toString()}`)
} else if (router.query?.next?.includes('new-project')) {
router.push('/new/project')
} else if (router.query['x-amzn-marketplace-token'] != undefined) {
router.push(`/account/associate?${params.toString()}`)
} else if (
typeof router.query?.next === 'string' &&
router.query?.next?.startsWith('project/_/')
) {
router.push(router.query.next as string)
} else {
router.push('/')
}
return <Connecting />
}
}
return (
<AccountLayoutWithoutAuth
title="Supabase"
breadcrumbs={[
{
key: `supabase-projects`,
label: 'Projects',
},
]}
>
{children}
</AccountLayoutWithoutAuth>
)
})
)
+84 -82
View File
@@ -23,7 +23,7 @@ import {
import { API_URL } from 'lib/constants'
import { useOrganizationDetail, useStore, withAuth } from 'hooks'
import { post, delete_, patch } from 'lib/common/fetch'
import { AccountLayout } from 'components/layouts'
import { AccountLayoutWithoutAuth } from 'components/layouts'
import { BillingSettings, InvoicesSettings } from 'components/interfaces/Organization'
import Table from 'components/to-be-cleaned/Table'
@@ -32,91 +32,93 @@ import { confirmAlert } from 'components/to-be-cleaned/ModalsDeprecated/ConfirmM
import InviteMemberModal from 'components/to-be-cleaned/ModalsDeprecated/InviteMemberModal'
import TextConfirmModal from 'components/to-be-cleaned/ModalsDeprecated/TextConfirmModal'
import SchemaFormPanel from 'components/to-be-cleaned/forms/SchemaFormPanel'
import { Project } from 'types'
import { NextPageWithLayout, Project } from 'types'
// [Joshen] Low prio refactor: Bring out general and team settings into their own components too
const PageContext = createContext(null)
const OrgSettings = () => {
const { app, ui } = useStore()
const router = useRouter()
const PageState: any = useLocalObservable(() => ({
user: {} as any,
organization: {},
projects: [],
members: [],
products: [],
membersFilterString: '',
get isOrgOwner() {
return (
this.members.find((x: any) => x.profile.id === this.user?.id && x.is_owner) != undefined
)
},
get filteredMembers() {
const temp = this.members.filter((x: any) => {
let profile = x.profile
const OrgSettingsLayout = withAuth(
observer(({ children }) => {
const { app, ui } = useStore()
const router = useRouter()
const PageState: any = useLocalObservable(() => ({
user: {} as any,
organization: {},
projects: [],
members: [],
products: [],
membersFilterString: '',
get isOrgOwner() {
return (
profile.username.includes(this.membersFilterString) ||
profile.primary_email.includes(this.membersFilterString)
this.members.find((x: any) => x.profile.id === this.user?.id && x.is_owner) != undefined
)
})
return temp.sort((a: any, b: any) => a.profile.username.localeCompare(b.profile.username))
},
initData(organization: any, user: any, projects: any) {
this.organization = organization
this.user = user
this.projects = projects
},
onOrgUpdated(updatedOrg: any) {
app.onOrgUpdated(updatedOrg)
},
onOrgDeleted() {
app.onOrgDeleted(this.organization)
},
}))
},
get filteredMembers() {
const temp = this.members.filter((x: any) => {
let profile = x.profile
return (
profile.username.includes(this.membersFilterString) ||
profile.primary_email.includes(this.membersFilterString)
)
})
return temp.sort((a: any, b: any) => a.profile.username.localeCompare(b.profile.username))
},
initData(organization: any, user: any, projects: any) {
this.organization = organization
this.user = user
this.projects = projects
},
onOrgUpdated(updatedOrg: any) {
app.onOrgUpdated(updatedOrg)
},
onOrgDeleted() {
app.onOrgDeleted(this.organization)
},
}))
useEffect(() => {
// User added a new payment method
if (router.query.setup_intent && router.query.redirect_status) {
ui.setNotification({ category: 'success', message: 'Successfully added new payment method' })
}
}, [])
useEffect(() => {
// User added a new payment method
if (router.query.setup_intent && router.query.redirect_status) {
ui.setNotification({
category: 'success',
message: 'Successfully added new payment method',
})
}
}, [])
useEffect(() => {
const organization = ui.selectedOrganization
const user = ui.profile
const projects = app.projects.list((x: Project) => x.organization_id == organization?.id)
PageState.initData(organization, user, projects)
}, [ui.selectedOrganization, ui.profile])
useEffect(() => {
const organization = ui.selectedOrganization
const user = ui.profile
const projects = app.projects.list((x: Project) => x.organization_id == organization?.id)
PageState.initData(organization, user, projects)
}, [ui.selectedOrganization, ui.profile])
return (
<PageContext.Provider value={PageState}>
<PageLayout />
</PageContext.Provider>
)
}
export default withAuth(observer(OrgSettings))
return (
<AccountLayoutWithoutAuth
title={PageState.organization?.name || 'Supabase'}
breadcrumbs={[
{
key: `org-settings`,
label: 'Settings',
},
]}
>
<PageContext.Provider value={PageState}>{children}</PageContext.Provider>
</AccountLayoutWithoutAuth>
)
})
)
const PageLayout = observer(() => {
const OrgSettings: NextPageWithLayout = () => {
const { ui } = useStore()
const PageState: any = useContext(PageContext)
return (
<AccountLayout
title={PageState.organization?.name || 'Supabase'}
// @ts-ignore
breadcrumbs={[
{
key: `org-settings`,
label: 'Settings',
},
]}
>
{ui.selectedOrganization && <OrganizationSettings />}
</AccountLayout>
)
})
return <>{ui.selectedOrganization && <OrganizationSettings />}</>
}
OrgSettings.getLayout = (page) => <OrgSettingsLayout>{page}</OrgSettingsLayout>
export default observer(OrgSettings)
const OrganizationSettings = observer(() => {
const PageState: any = useContext(PageContext)
@@ -217,7 +219,7 @@ const GeneralSettings = observer(() => {
}
return (
<article className="my-4 container max-w-4xl space-y-8">
<article className="container my-4 max-w-4xl space-y-8">
<SchemaFormPanel
title="General"
schema={pluckJsonSchemaFields(organizations, BASIC_FIELDS)}
@@ -300,9 +302,9 @@ const OrgDeleteModal = observer(() => {
visible={isOpen}
onCancel={toggle}
header={
<div className="flex gap-2 items-baseline">
<h5 className="text-sm text-scale-1200">Delete organisation</h5>
<span className="text-xs text-scale-900">Are you sure?</span>
<div className="flex items-baseline gap-2">
<h5 className="text-scale-1200 text-sm">Delete organisation</h5>
<span className="text-scale-900 text-xs">Are you sure?</span>
</div>
}
size="small"
@@ -416,7 +418,7 @@ const TeamSettings = observer(() => {
return (
<>
<div className="my-4 container max-w-4xl space-y-8">
<div className="container my-4 max-w-4xl space-y-8">
<div className="flex justify-between">
<MembersFilterInput />
{PageState.isOrgOwner ? (
@@ -435,7 +437,7 @@ const TeamSettings = observer(() => {
)}
</div>
</div>
<div className="my-4 container max-w-4xl space-y-8">
<div className="container my-4 max-w-4xl space-y-8">
<MembersView />
</div>
</>
@@ -483,7 +485,7 @@ const MembersView = observer(() => {
<img
src={`https://github.com/${x.profile.username}.png?size=80`}
width="40"
className="rounded-full border border-border-secondary-light dark:border-border-secondary-dark"
className="border-border-secondary-light dark:border-border-secondary-dark rounded-full border"
/>
</div>
<div>
@@ -607,7 +609,7 @@ const OwnerDropdown = observer(({ members, member }: any) => {
<Dropdown.Item onClick={() => setOwnerTransferIsVisble(!ownerTransferIsVisble)}>
<div className="flex flex-col">
<p>Make owner</p>
<p className="opacity-50 block">Transfer ownership of "{orgName}"</p>
<p className="block opacity-50">Transfer ownership of "{orgName}"</p>
</div>
</Dropdown.Item>
<Dropdown.Seperator />
@@ -639,7 +641,7 @@ const OwnerDropdown = observer(({ members, member }: any) => {
text={
<span>
By transferring this organization, it will be solely owned by{' '}
<span className="dark:text-white font-medium">{member.profile.username}</span>, they
<span className="font-medium dark:text-white">{member.profile.username}</span>, they
will also be able to remove you from the organization as a member
</span>
}