diff --git a/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx b/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx index b7ab33bf87e..63c89019637 100644 --- a/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx +++ b/apps/studio/components/interfaces/Account/TOTPFactors/AddNewFactorModal.tsx @@ -1,6 +1,5 @@ import { zodResolver } from '@hookform/resolvers/zod' import { useQueryClient } from '@tanstack/react-query' -import { LOCAL_STORAGE_KEYS } from 'common' import { useEffect, useState } from 'react' import { useForm, type SubmitHandler } from 'react-hook-form' import { toast } from 'sonner' @@ -16,7 +15,7 @@ import { organizationKeys } from '@/data/organizations/keys' import { useMfaChallengeAndVerifyMutation } from '@/data/profile/mfa-challenge-and-verify-mutation' import { useMfaEnrollMutation } from '@/data/profile/mfa-enroll-mutation' import { useMfaUnenrollMutation } from '@/data/profile/mfa-unenroll-mutation' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' type TOTP = { qr_code: string; secret: string; uri: string } @@ -140,10 +139,7 @@ const SecondStep = ({ onClose, }: SecondStepProps) => { const queryClient = useQueryClient() - const [lastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { lastVisitedOrganization } = useLastVisitedOrganization() const FormSchema = z.object({ code: z.string().min(1, 'Please provide a code from your authenticator app'), diff --git a/apps/studio/components/interfaces/Account/TOTPFactors/DeleteFactorModal.tsx b/apps/studio/components/interfaces/Account/TOTPFactors/DeleteFactorModal.tsx index 41f1667081c..06f887d3af9 100644 --- a/apps/studio/components/interfaces/Account/TOTPFactors/DeleteFactorModal.tsx +++ b/apps/studio/components/interfaces/Account/TOTPFactors/DeleteFactorModal.tsx @@ -1,11 +1,10 @@ import { useQueryClient } from '@tanstack/react-query' -import { LOCAL_STORAGE_KEYS } from 'common' import { toast } from 'sonner' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { organizationKeys } from '@/data/organizations/keys' import { useMfaUnenrollMutation } from '@/data/profile/mfa-unenroll-mutation' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' interface DeleteFactorModalProps { visible: boolean @@ -21,10 +20,7 @@ const DeleteFactorModal = ({ onClose, }: DeleteFactorModalProps) => { const queryClient = useQueryClient() - const [lastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { lastVisitedOrganization } = useLastVisitedOrganization() const { mutate: unenroll, isPending } = useMfaUnenrollMutation({ onSuccess: async () => { diff --git a/apps/studio/components/interfaces/App/RouteValidationWrapper.tsx b/apps/studio/components/interfaces/App/RouteValidationWrapper.tsx index e69aa8c9392..bb416823fcd 100644 --- a/apps/studio/components/interfaces/App/RouteValidationWrapper.tsx +++ b/apps/studio/components/interfaces/App/RouteValidationWrapper.tsx @@ -1,4 +1,4 @@ -import { LOCAL_STORAGE_KEYS, useIsLoggedIn, useIsMFAEnabled, useParams } from 'common' +import { useIsLoggedIn, useIsMFAEnabled, useParams } from 'common' import { useRouter } from 'next/router' import { PropsWithChildren, useEffect } from 'react' import { toast } from 'sonner' @@ -6,8 +6,8 @@ import { toast } from 'sonner' import { useOrganizationsQuery } from '@/data/organizations/organizations-query' import { useProjectDetailQuery } from '@/data/projects/project-detail-query' import { useDashboardHistory } from '@/hooks/misc/useDashboardHistory' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import useLatest from '@/hooks/misc/useLatest' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { IS_PLATFORM } from '@/lib/constants' @@ -21,10 +21,7 @@ export const RouteValidationWrapper = ({ children }: PropsWithChildren<{}>) => { const isUserMFAEnabled = useIsMFAEnabled() const { setLastVisitedSnippet, setLastVisitedTable } = useDashboardHistory() - const [lastVisitedOrganization, setLastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { lastVisitedOrganization, setLastVisitedOrganization } = useLastVisitedOrganization() const DEFAULT_HOME = IS_PLATFORM ? !!lastVisitedOrganization diff --git a/apps/studio/components/interfaces/Connect/OrganizationSelector.tsx b/apps/studio/components/interfaces/Connect/OrganizationSelector.tsx index 8e989dfaa92..feac48d13a2 100644 --- a/apps/studio/components/interfaces/Connect/OrganizationSelector.tsx +++ b/apps/studio/components/interfaces/Connect/OrganizationSelector.tsx @@ -1,4 +1,3 @@ -import { LOCAL_STORAGE_KEYS } from 'common' import { Check, ChevronDown } from 'lucide-react' import { useMemo, useState, type ReactNode } from 'react' import { cn, Collapsible, CollapsibleContent, CollapsibleTrigger } from 'ui' @@ -7,7 +6,7 @@ import { CreateOrganizationCard, OrganizationCard, } from '@/components/interfaces/Organization/OrganizationCard' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import type { Organization } from '@/types' const VISIBLE_ORGANIZATIONS_LIMIT = 3 @@ -46,10 +45,7 @@ export const OrganizationSelector = ({ unavailableReason?: ReactNode }) => { const [showMore, setShowMore] = useState(false) - const [lastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { lastVisitedOrganization } = useLastVisitedOrganization() const { visibleOrganizations, overflowOrganizations } = useMemo(() => { const lastVisitedOrg = organizations.find(({ slug }) => slug === lastVisitedOrganization) diff --git a/apps/studio/components/interfaces/Organization/GeneralSettings/DeleteOrganizationButton.tsx b/apps/studio/components/interfaces/Organization/GeneralSettings/DeleteOrganizationButton.tsx index 359d0868497..74baf2ba06e 100644 --- a/apps/studio/components/interfaces/Organization/GeneralSettings/DeleteOrganizationButton.tsx +++ b/apps/studio/components/interfaces/Organization/GeneralSettings/DeleteOrganizationButton.tsx @@ -1,5 +1,4 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' -import { LOCAL_STORAGE_KEYS } from 'common' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { toast } from 'sonner' @@ -11,7 +10,7 @@ import { TextConfirmModal } from '@/components/ui/TextConfirmModalWrapper' import { useOrganizationDeleteMutation } from '@/data/organizations/organization-delete-mutation' import { useOrgProjectsInfiniteQuery } from '@/data/projects/org-projects-infinite-query' import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' const MAX_PROJECT_ACKNOWLEDGEMENTS = 10 @@ -90,10 +89,7 @@ export const DeleteOrganizationButton = () => { const allChecked = isDeletionConfirmed() - const [_, setLastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { setLastVisitedOrganization } = useLastVisitedOrganization() const { can: canDeleteOrganization } = useAsyncCheckPermissions( PermissionAction.UPDATE, diff --git a/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.tsx b/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.tsx index 7197b5679d0..a7c147df6d1 100644 --- a/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.tsx +++ b/apps/studio/components/interfaces/Organization/NewOrg/NewOrgForm.tsx @@ -3,7 +3,6 @@ import { Elements } from '@stripe/react-stripe-js' import type { PaymentIntentResult, PaymentMethod, StripeElementsOptions } from '@stripe/stripe-js' import { loadStripe } from '@stripe/stripe-js' import { useDebounce } from '@uidotdev/usehooks' -import { LOCAL_STORAGE_KEYS } from 'common' import { groupBy } from 'lodash' import { HelpCircle } from 'lucide-react' import { useTheme } from 'next-themes' @@ -55,7 +54,7 @@ import { useProjectsInfiniteQuery } from '@/data/projects/projects-infinite-quer import { SetupIntentResponse } from '@/data/stripe/setup-intent-mutation' import { useConfirmPendingSubscriptionCreateMutation } from '@/data/subscriptions/org-subscription-confirm-pending-create' import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import { PRICING_TIER_LABELS_ORG, STRIPE_PUBLIC_KEY } from '@/lib/constants' import { validateReturnTo } from '@/lib/gotrue' import { useProfile } from '@/lib/profile' @@ -94,6 +93,7 @@ export const NewOrgForm = ({ const router = useRouter() const user = useProfile() const { resolvedTheme } = useTheme() + const { lastVisitedOrganization } = useLastVisitedOrganization() const isBillingEnabled = useIsFeatureEnabled('billing:all') @@ -101,11 +101,6 @@ export const NewOrgForm = ({ const { data } = useProjectsInfiniteQuery({}) const projects = useMemo(() => data?.pages.flatMap((page) => page.projects) ?? [], [data?.pages]) - const [lastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) - const freeOrgs = (organizations || []).filter((it) => it.plan.id === 'free') // [Joshen] JFYI because we're now using a paginated endpoint, there's a chance that not all projects will be diff --git a/apps/studio/components/interfaces/Organization/TeamSettings/LeaveTeamButton.tsx b/apps/studio/components/interfaces/Organization/TeamSettings/LeaveTeamButton.tsx index 556958d6ce0..336b89a4ddc 100644 --- a/apps/studio/components/interfaces/Organization/TeamSettings/LeaveTeamButton.tsx +++ b/apps/studio/components/interfaces/Organization/TeamSettings/LeaveTeamButton.tsx @@ -1,4 +1,4 @@ -import { LOCAL_STORAGE_KEYS, useParams } from 'common' +import { useParams } from 'common' import { useRouter } from 'next/router' import { useState } from 'react' import { toast } from 'sonner' @@ -11,7 +11,7 @@ import { useOrganizationMemberDeleteMutation } from '@/data/organizations/organi import { useOrganizationMembersQuery } from '@/data/organizations/organization-members-query' import { useOrganizationsQuery } from '@/data/organizations/organizations-query' import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { useProfile } from '@/lib/profile' @@ -20,6 +20,7 @@ export const LeaveTeamButton = () => { const { slug } = useParams() const { profile } = useProfile() const { data: selectedOrganization } = useSelectedOrganizationQuery() + const { setLastVisitedOrganization } = useLastVisitedOrganization() // if organizationMembersDeletionEnabled is false, you also can't delete yourself const { organizationMembersDelete: organizationMembersDeletionEnabled } = useIsFeatureEnabled([ @@ -28,10 +29,6 @@ export const LeaveTeamButton = () => { const [isLeaving, setIsLeaving] = useState(false) const [isLeaveTeamModalOpen, setIsLeaveTeamModalOpen] = useState(false) - const [_, setLastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) const { refetch: refetchOrganizations } = useOrganizationsQuery() const { data: members } = useOrganizationMembersQuery({ slug }) diff --git a/apps/studio/components/interfaces/ProjectCreation/ProjectCreationFooter.tsx b/apps/studio/components/interfaces/ProjectCreation/ProjectCreationFooter.tsx index ae6d34c9173..8d237ed1525 100644 --- a/apps/studio/components/interfaces/ProjectCreation/ProjectCreationFooter.tsx +++ b/apps/studio/components/interfaces/ProjectCreation/ProjectCreationFooter.tsx @@ -1,4 +1,4 @@ -import { LOCAL_STORAGE_KEYS, useFlag } from 'common' +import { useFlag } from 'common' import { useRouter } from 'next/router' import { UseFormReturn } from 'react-hook-form' import { @@ -18,7 +18,7 @@ import { CreateProjectForm } from './ProjectCreation.schema' import { instanceLabel, monthlyInstancePrice } from './ProjectCreation.utils' import { InlineLink } from '@/components/ui/InlineLink' import { OrgProject } from '@/data/projects/org-projects-infinite-query' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { DOCS_URL } from '@/lib/constants' @@ -42,14 +42,10 @@ export const ProjectCreationFooter = ({ const router = useRouter() const { data: currentOrg } = useSelectedOrganizationQuery() const isFreePlan = currentOrg?.plan?.id === 'free' + const { lastVisitedOrganization } = useLastVisitedOrganization() const projectCreationDisabled = useFlag('disableProjectCreationAndUpdate') - const [lastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) - const availableComputeCredits = organizationProjects.length === 0 ? 10 : 0 const additionalMonthlySpend = isFreePlan ? 0 diff --git a/apps/studio/components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectModal.tsx b/apps/studio/components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectModal.tsx index 1f6c291d868..c3af8e4f169 100644 --- a/apps/studio/components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectModal.tsx +++ b/apps/studio/components/interfaces/Settings/General/DeleteProjectPanel/DeleteProjectModal.tsx @@ -1,4 +1,3 @@ -import { LOCAL_STORAGE_KEYS } from 'common' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { toast } from 'sonner' @@ -12,7 +11,7 @@ import { useSendDowngradeFeedbackMutation } from '@/data/feedback/exit-survey-se import type { OrgProject } from '@/data/projects/org-projects-infinite-query' import { useProjectDeleteMutation } from '@/data/projects/project-delete-mutation' import { useOrgSubscriptionQuery } from '@/data/subscriptions/org-subscription-query' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import type { Organization } from '@/types' @@ -36,10 +35,7 @@ export const DeleteProjectModal = ({ const project = projectProp || projectFromQuery const organization = organizationProp || organizationFromQuery - const [lastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { lastVisitedOrganization } = useLastVisitedOrganization() const projectRef = project?.ref const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug }) diff --git a/apps/studio/components/layouts/AccountLayout/AccountLayout.selfhosted.test.tsx b/apps/studio/components/layouts/AccountLayout/AccountLayout.selfhosted.test.tsx index 34b25e4a231..0c581abb557 100644 --- a/apps/studio/components/layouts/AccountLayout/AccountLayout.selfhosted.test.tsx +++ b/apps/studio/components/layouts/AccountLayout/AccountLayout.selfhosted.test.tsx @@ -55,7 +55,7 @@ vi.mock('@/hooks/misc/useIsFeatureEnabled', () => ({ })) vi.mock('@/hooks/misc/useLocalStorage', () => ({ - useLocalStorageQuery: () => [''], + useLocalStorageQuery: () => ['', vi.fn(), { isLoading: false, isSuccess: true }], })) vi.mock('@/hooks/misc/withAuth', () => ({ diff --git a/apps/studio/components/layouts/AccountLayout/AccountLayout.tsx b/apps/studio/components/layouts/AccountLayout/AccountLayout.tsx index 2774fbbff19..6a7b39be1cd 100644 --- a/apps/studio/components/layouts/AccountLayout/AccountLayout.tsx +++ b/apps/studio/components/layouts/AccountLayout/AccountLayout.tsx @@ -1,4 +1,3 @@ -import { LOCAL_STORAGE_KEYS } from 'common' import Head from 'next/head' import { useRouter } from 'next/router' import type { PropsWithChildren } from 'react' @@ -10,7 +9,7 @@ import { AccountMenuContent } from './AccountMenuContent' import { WithSidebar } from './WithSidebar' import { useCustomContent } from '@/hooks/custom-content/useCustomContent' import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import { withAuth } from '@/hooks/misc/withAuth' import { IS_PLATFORM } from '@/lib/constants' import { buildStudioPageTitle } from '@/lib/page-title' @@ -23,6 +22,7 @@ export interface AccountLayoutProps { const AccountLayout = ({ children, title }: PropsWithChildren) => { const router = useRouter() const appSnap = useAppStateSnapshot() + const { lastVisitedOrganization } = useLastVisitedOrganization() const { setContent: setMobileSheetContent, registerOpenMenu } = useMobileSheet() const currentPath = router.pathname @@ -32,11 +32,6 @@ const AccountLayout = ({ children, title }: PropsWithChildren 0 ? appSnap.lastRouteBeforeVisitingAccountPage diff --git a/apps/studio/components/layouts/DefaultLayout.tsx b/apps/studio/components/layouts/DefaultLayout.tsx index 55853c36e06..5670934aafc 100644 --- a/apps/studio/components/layouts/DefaultLayout.tsx +++ b/apps/studio/components/layouts/DefaultLayout.tsx @@ -1,4 +1,4 @@ -import { LOCAL_STORAGE_KEYS, useBreakpoint, useParams } from 'common' +import { useBreakpoint, useParams } from 'common' import { useRouter } from 'next/router' import { PropsWithChildren, useEffect, useState } from 'react' import { ResizablePanel, ResizablePanelGroup, SidebarProvider } from 'ui' @@ -13,7 +13,7 @@ import { LayoutSidebarProvider } from './ProjectLayout/LayoutSidebar/LayoutSideb import { ProjectContextProvider } from './ProjectLayout/ProjectContext' import { AppBannerWrapper } from '@/components/interfaces/App/AppBannerWrapper' import { Sidebar } from '@/components/interfaces/Sidebar' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import { useCheckLatestDeploy } from '@/hooks/use-check-latest-deploy' import { IS_PLATFORM } from '@/lib/constants' import { useAppStateSnapshot } from '@/state/app-state' @@ -42,10 +42,7 @@ export const DefaultLayout = ({ const router = useRouter() const appSnap = useAppStateSnapshot() - const [lastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { lastVisitedOrganization } = useLastVisitedOrganization() const backToDashboardURL = router.pathname.startsWith('/account') ? appSnap.lastRouteBeforeVisitingAccountPage.length > 0 diff --git a/apps/studio/components/layouts/Navigation/LayoutHeader/HomeIcon.tsx b/apps/studio/components/layouts/Navigation/LayoutHeader/HomeIcon.tsx index 2203a98c43d..0d3b227d3d6 100644 --- a/apps/studio/components/layouts/Navigation/LayoutHeader/HomeIcon.tsx +++ b/apps/studio/components/layouts/Navigation/LayoutHeader/HomeIcon.tsx @@ -1,11 +1,10 @@ -import { LOCAL_STORAGE_KEYS } from 'common' import Link from 'next/link' import { useRouter } from 'next/router' import { cn } from 'ui' import { useOrganizationsQuery } from '@/data/organizations/organizations-query' import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { IS_PLATFORM } from '@/lib/constants' import { useTrack } from '@/lib/telemetry/track' @@ -18,10 +17,7 @@ export const HomeIcon = ({ className }: { className?: string }) => { const largeLogo = useIsFeatureEnabled('branding:large_logo') const router = useRouter() - const [lastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { lastVisitedOrganization } = useLastVisitedOrganization() const getDefaultOrgRedirect = () => { if (lastVisitedOrganization) return `/org/${lastVisitedOrganization}` diff --git a/apps/studio/hooks/misc/useLastVisitedOrganization.ts b/apps/studio/hooks/misc/useLastVisitedOrganization.ts new file mode 100644 index 00000000000..9459a6cea78 --- /dev/null +++ b/apps/studio/hooks/misc/useLastVisitedOrganization.ts @@ -0,0 +1,23 @@ +import { LOCAL_STORAGE_KEYS } from 'common' + +import { useLocalStorageQuery } from './useLocalStorage' +import { useProfile } from '@/lib/profile' + +export const useLastVisitedOrganization = () => { + const { profile, isLoading: isLoadingProfile, isSuccess: isSuccessProfile } = useProfile() + const [ + lastVisitedOrganization, + setLastVisitedOrganization, + { isLoading: isLoadingLocalStorage, isSuccess: isSuccessLocalStorage }, + ] = useLocalStorageQuery(LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION(profile?.id), '') + + const isSuccess = isSuccessProfile && isSuccessLocalStorage + const isPending = isLoadingProfile || isLoadingLocalStorage + + return { + isSuccess, + isPending, + lastVisitedOrganization: isSuccess ? lastVisitedOrganization : undefined, + setLastVisitedOrganization, + } +} diff --git a/apps/studio/pages/500.tsx b/apps/studio/pages/500.tsx index 85f3e13ece6..a3e42efd702 100644 --- a/apps/studio/pages/500.tsx +++ b/apps/studio/pages/500.tsx @@ -1,4 +1,3 @@ -import { LOCAL_STORAGE_KEYS } from 'common' import { NextPage } from 'next' import { useTheme } from 'next-themes' import Image from 'next/legacy/image' @@ -7,7 +6,7 @@ import { useRouter } from 'next/router' import { Button } from 'ui' import { SupportLink } from '@/components/interfaces/Support/SupportLink' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import { useSignOut } from '@/lib/auth' const Error500: NextPage = () => { @@ -15,10 +14,7 @@ const Error500: NextPage = () => { const signOut = useSignOut() const { resolvedTheme } = useTheme() - const [lastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { lastVisitedOrganization } = useLastVisitedOrganization() const onClickLogout = async () => { await signOut() diff --git a/apps/studio/pages/new/[slug].tsx b/apps/studio/pages/new/[slug].tsx index b700ec42b45..57ef2d799b3 100644 --- a/apps/studio/pages/new/[slug].tsx +++ b/apps/studio/pages/new/[slug].tsx @@ -1,6 +1,6 @@ import { zodResolver } from '@hookform/resolvers/zod' import { PermissionAction } from '@supabase/shared-types/out/constants' -import { LOCAL_STORAGE_KEYS, useFlag, useParams } from 'common' +import { useFlag, useParams } from 'common' import Head from 'next/head' import Link from 'next/link' import { useRouter } from 'next/router' @@ -64,7 +64,7 @@ import { useDataApiRevokeOnCreateDefaultEnabled, } from '@/hooks/misc/useDataApiRevokeOnCreateDefault' import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { withAuth } from '@/hooks/misc/withAuth' import { usePHFlag } from '@/hooks/ui/useFlag' @@ -92,10 +92,7 @@ const Wizard: NextPageWithLayout = () => { const isFreePlan = currentOrg?.plan?.id === 'free' const canChooseInstanceSize = !isFreePlan - const [lastVisitedOrganization] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { lastVisitedOrganization } = useLastVisitedOrganization() const { can: isAdmin } = useAsyncCheckPermissions(PermissionAction.CREATE, 'projects') const { can: canCreateGitHubConnection } = useAsyncCheckPermissions( PermissionAction.CREATE, diff --git a/apps/studio/pages/org/index.tsx b/apps/studio/pages/org/index.tsx index a9755ce8b28..dbe8af93bc0 100644 --- a/apps/studio/pages/org/index.tsx +++ b/apps/studio/pages/org/index.tsx @@ -1,4 +1,3 @@ -import { LOCAL_STORAGE_KEYS } from 'common' import { useRouter } from 'next/router' import { useEffect } from 'react' @@ -6,20 +5,20 @@ import { ShimmeringCard } from '@/components/interfaces/Home/ProjectList/Shimmer import { DefaultLayout } from '@/components/layouts/DefaultLayout' import OrganizationLayout from '@/components/layouts/OrganizationLayout' import { ScaffoldContainerLegacy } from '@/components/layouts/Scaffold' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import type { NextPageWithLayout } from '@/types' const OrgIndexPage: NextPageWithLayout = () => { const router = useRouter() - const [lastVisitedOrganization, _, { isSuccess }] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { lastVisitedOrganization, isSuccess } = useLastVisitedOrganization() useEffect(() => { if (isSuccess) { - if (lastVisitedOrganization.length > 0) router.push(`/org/${lastVisitedOrganization}`) - else router.push('/organizations') + if (lastVisitedOrganization) { + router.push(`/org/${lastVisitedOrganization}`) + } else { + router.push('/organizations') + } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isSuccess]) diff --git a/apps/studio/pages/project/_/[[...routeSlug]].tsx b/apps/studio/pages/project/_/[[...routeSlug]].tsx index 7f59242f587..61b83ea75e0 100644 --- a/apps/studio/pages/project/_/[[...routeSlug]].tsx +++ b/apps/studio/pages/project/_/[[...routeSlug]].tsx @@ -1,4 +1,4 @@ -import { IS_PLATFORM, LOCAL_STORAGE_KEYS, useParams } from 'common' +import { IS_PLATFORM, useParams } from 'common' import { AlertTriangleIcon } from 'lucide-react' import { NextPage } from 'next' import { useRouter } from 'next/router' @@ -25,7 +25,7 @@ import { HomePageActions } from '@/components/interfaces/HomePageActions' import { PageLayout } from '@/components/layouts/PageLayout/PageLayout' import { ScaffoldContainer, ScaffoldSection } from '@/components/layouts/Scaffold' import { useOrganizationsQuery } from '@/data/organizations/organizations-query' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { useLastVisitedOrganization } from '@/hooks/misc/useLastVisitedOrganization' import { withAuth } from '@/hooks/misc/withAuth' // [Joshen] I'd say we don't do route validation here, this page will act more @@ -37,10 +37,7 @@ const GenericProjectPage: NextPage = () => { const { slug } = useParams() const { routeSlug, ...queryParams } = router.query - const [lastVisitedOrgSlug] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, - '' - ) + const { lastVisitedOrganization } = useLastVisitedOrganization() const { data: organizations = [], @@ -52,7 +49,7 @@ const GenericProjectPage: NextPage = () => { }) const [selectedSlug, setSlug] = useState( - slug || lastVisitedOrgSlug || organizations[0]?.slug + slug || lastVisitedOrganization || organizations[0]?.slug ) const selectedOrganization = organizations.find((x) => x.slug === selectedSlug) @@ -74,13 +71,13 @@ const GenericProjectPage: NextPage = () => { } useEffect(() => { - if (!!lastVisitedOrgSlug) { - setSlug(lastVisitedOrgSlug) + if (!!lastVisitedOrganization) { + setSlug(lastVisitedOrganization) } else if (isSuccessOrganizations) { setSlug(organizations[0]?.slug) } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [lastVisitedOrgSlug, isSuccessOrganizations]) + }, [lastVisitedOrganization, isSuccessOrganizations]) return (
diff --git a/apps/studio/tests/pages/aws-marketplace-onboarding.test.tsx b/apps/studio/tests/pages/aws-marketplace-onboarding.test.tsx index 3c5537feb30..1422fe9d8b9 100644 --- a/apps/studio/tests/pages/aws-marketplace-onboarding.test.tsx +++ b/apps/studio/tests/pages/aws-marketplace-onboarding.test.tsx @@ -273,7 +273,7 @@ describe('AwsMarketplaceOnboardingScreen', () => { ] window.localStorage.setItem( - LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION, + LOCAL_STORAGE_KEYS.LAST_VISITED_ORGANIZATION(DEFAULT_PROFILE_CONTEXT.profile?.id), JSON.stringify('zeta-team') ) mockAwsEndpoints({ diff --git a/packages/common/constants/local-storage.ts b/packages/common/constants/local-storage.ts index 2c370016f34..40ac85123ab 100644 --- a/packages/common/constants/local-storage.ts +++ b/packages/common/constants/local-storage.ts @@ -87,7 +87,7 @@ export const LOCAL_STORAGE_KEYS = { // Shortcut preferences SHORTCUT_STORAGE_KEY: 'supabase-shortcut-preferences', - LAST_VISITED_ORGANIZATION: 'last-visited-organization', + LAST_VISITED_ORGANIZATION: (uid?: number) => `last-visited-organization-${uid}`, // user impersonation selector previous searches USER_IMPERSONATION_SELECTOR_PREVIOUS_SEARCHES: (ref: string) =>