Refactor account handling to improve performance
This commit dates the transition from a global user session to individual account handling based on user ID. The transition was made across several components, notably the account settings, icons, and selector. This change improves performance by reducing unnecessary requests and ensures more accurate data handling. The commit also includes some cleanups and minor fixes spread across different components.
This commit is contained in:
@@ -18,6 +18,7 @@ export function HomeAccountSelector(props: {
|
||||
image: string | null;
|
||||
}>;
|
||||
|
||||
userId: string;
|
||||
collapsed: boolean;
|
||||
}) {
|
||||
const router = useRouter();
|
||||
@@ -27,6 +28,7 @@ export function HomeAccountSelector(props: {
|
||||
collapsed={props.collapsed}
|
||||
accounts={props.accounts}
|
||||
features={features}
|
||||
userId={props.userId}
|
||||
onAccountChange={(value) => {
|
||||
if (value) {
|
||||
const path = pathsConfig.app.accountHome.replace('[account]', value);
|
||||
|
||||
@@ -12,7 +12,7 @@ import { personalAccountNavigationConfig } from '~/config/personal-account-navig
|
||||
// home imports
|
||||
import { HomeAccountSelector } from '../_components/home-account-selector';
|
||||
import { UserNotifications } from '../_components/user-notifications';
|
||||
import { type UserWorkspace } from '../_lib/server/load-user-workspace';
|
||||
import { type UserWorkspace } from '../_lib/server/user-workspace.loader';
|
||||
|
||||
export function HomeMenuNavigation(props: { workspace: UserWorkspace }) {
|
||||
const { workspace, user, accounts } = props.workspace;
|
||||
@@ -50,7 +50,11 @@ export function HomeMenuNavigation(props: { workspace: UserWorkspace }) {
|
||||
|
||||
<div className={'flex justify-end space-x-2.5'}>
|
||||
<If condition={featuresFlagConfig.enableTeamAccounts}>
|
||||
<HomeAccountSelector accounts={accounts} collapsed={false} />
|
||||
<HomeAccountSelector
|
||||
userId={user.id}
|
||||
accounts={accounts}
|
||||
collapsed={false}
|
||||
/>
|
||||
</If>
|
||||
|
||||
<UserNotifications userId={user.id} />
|
||||
|
||||
@@ -22,7 +22,7 @@ import { personalAccountNavigationConfig } from '~/config/personal-account-navig
|
||||
|
||||
// home imports
|
||||
import { HomeAccountSelector } from '../_components/home-account-selector';
|
||||
import type { UserWorkspace } from '../_lib/server/load-user-workspace';
|
||||
import type { UserWorkspace } from '../_lib/server/user-workspace.loader';
|
||||
|
||||
export function HomeMobileNavigation(props: { workspace: UserWorkspace }) {
|
||||
const signOut = useSignOut();
|
||||
@@ -69,6 +69,7 @@ export function HomeMobileNavigation(props: { workspace: UserWorkspace }) {
|
||||
</DropdownMenuLabel>
|
||||
|
||||
<HomeAccountSelector
|
||||
userId={props.workspace.user.id}
|
||||
accounts={props.workspace.accounts}
|
||||
collapsed={false}
|
||||
/>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { personalAccountNavigationConfig } from '~/config/personal-account-navig
|
||||
import { UserNotifications } from '~/home/(user)/_components/user-notifications';
|
||||
|
||||
// home imports
|
||||
import type { UserWorkspace } from '../_lib/server/load-user-workspace';
|
||||
import type { UserWorkspace } from '../_lib/server/user-workspace.loader';
|
||||
import { HomeAccountSelector } from './home-account-selector';
|
||||
|
||||
export function HomeSidebar(props: { workspace: UserWorkspace }) {
|
||||
@@ -22,7 +22,11 @@ export function HomeSidebar(props: { workspace: UserWorkspace }) {
|
||||
condition={featuresFlagConfig.enableTeamAccounts}
|
||||
fallback={<AppLogo className={'py-2'} />}
|
||||
>
|
||||
<HomeAccountSelector collapsed={false} accounts={accounts} />
|
||||
<HomeAccountSelector
|
||||
userId={user.id}
|
||||
collapsed={false}
|
||||
accounts={accounts}
|
||||
/>
|
||||
</If>
|
||||
|
||||
<UserNotifications userId={user.id} />
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { cache } from 'react';
|
||||
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
import { createAccountsApi } from '@kit/accounts/api';
|
||||
import { requireUser } from '@kit/supabase/require-user';
|
||||
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
||||
|
||||
import featureFlagsConfig from '~/config/feature-flags.config';
|
||||
@@ -24,20 +27,19 @@ export const loadUserWorkspace = cache(async () => {
|
||||
: () => Promise.resolve([]);
|
||||
|
||||
const workspacePromise = api.getAccountWorkspace();
|
||||
const userPromise = client.auth.getUser();
|
||||
|
||||
const [accounts, workspace, userResult] = await Promise.all([
|
||||
const [accounts, workspace, auth] = await Promise.all([
|
||||
accountsPromise(),
|
||||
workspacePromise,
|
||||
userPromise,
|
||||
requireUser(client),
|
||||
]);
|
||||
|
||||
const user = userResult.data.user;
|
||||
|
||||
if (!user) {
|
||||
throw new Error('User is not logged in');
|
||||
if (!auth.data) {
|
||||
return redirect(auth.redirectTo);
|
||||
}
|
||||
|
||||
const user = auth.data;
|
||||
|
||||
return {
|
||||
accounts,
|
||||
workspace,
|
||||
@@ -18,7 +18,7 @@ import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
import { HomeMenuNavigation } from './_components/home-menu-navigation';
|
||||
import { HomeMobileNavigation } from './_components/home-mobile-navigation';
|
||||
import { HomeSidebar } from './_components/home-sidebar';
|
||||
import { loadUserWorkspace } from './_lib/server/load-user-workspace';
|
||||
import { loadUserWorkspace } from './_lib/server/user-workspace.loader';
|
||||
|
||||
function UserHomeLayout({ children }: React.PropsWithChildren) {
|
||||
const workspace = use(loadUserWorkspace());
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
import { use } from 'react';
|
||||
|
||||
import { PersonalAccountSettingsContainer } from '@kit/accounts/personal-account-settings';
|
||||
import { PageBody } from '@kit/ui/page';
|
||||
|
||||
import featureFlagsConfig from '~/config/feature-flags.config';
|
||||
import pathsConfig from '~/config/paths.config';
|
||||
import { loadUserWorkspace } from '~/home/(user)/_lib/server/user-workspace.loader';
|
||||
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
@@ -24,10 +27,16 @@ export const generateMetadata = async () => {
|
||||
};
|
||||
|
||||
function PersonalAccountSettingsPage() {
|
||||
const { user } = use(loadUserWorkspace());
|
||||
|
||||
return (
|
||||
<PageBody>
|
||||
<div className={'flex w-full flex-1 flex-col lg:max-w-2xl'}>
|
||||
<PersonalAccountSettingsContainer features={features} paths={paths} />
|
||||
<PersonalAccountSettingsContainer
|
||||
userId={user.id}
|
||||
features={features}
|
||||
paths={paths}
|
||||
/>
|
||||
</div>
|
||||
</PageBody>
|
||||
);
|
||||
|
||||
@@ -13,6 +13,8 @@ const features = {
|
||||
|
||||
export function TeamAccountAccountsSelector(params: {
|
||||
selectedAccount: string;
|
||||
userId: string;
|
||||
|
||||
accounts: Array<{
|
||||
label: string | null;
|
||||
value: string | null;
|
||||
@@ -25,6 +27,7 @@ export function TeamAccountAccountsSelector(params: {
|
||||
<AccountSelector
|
||||
selectedAccount={params.selectedAccount}
|
||||
accounts={params.accounts}
|
||||
userId={params.userId}
|
||||
collapsed={false}
|
||||
features={features}
|
||||
onAccountChange={(value) => {
|
||||
|
||||
@@ -41,6 +41,7 @@ const features = {
|
||||
export const TeamAccountLayoutMobileNavigation = (
|
||||
props: React.PropsWithChildren<{
|
||||
account: string;
|
||||
userId: string;
|
||||
accounts: Accounts;
|
||||
}>,
|
||||
) => {
|
||||
@@ -83,7 +84,7 @@ export const TeamAccountLayoutMobileNavigation = (
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
<DropdownMenuContent sideOffset={10} className={'w-screen rounded-none'}>
|
||||
<TeamAccountsModal accounts={props.accounts} />
|
||||
<TeamAccountsModal userId={props.userId} accounts={props.accounts} />
|
||||
|
||||
{Links}
|
||||
|
||||
@@ -137,7 +138,7 @@ function SignOutDropdownItem(
|
||||
);
|
||||
}
|
||||
|
||||
function TeamAccountsModal(props: { accounts: Accounts }) {
|
||||
function TeamAccountsModal(props: { accounts: Accounts; userId: string }) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
@@ -165,6 +166,7 @@ function TeamAccountsModal(props: { accounts: Accounts }) {
|
||||
<div className={'py-16'}>
|
||||
<AccountSelector
|
||||
className={'w-full max-w-full'}
|
||||
userId={props.userId}
|
||||
onAccountChange={(value) => {
|
||||
const path = value
|
||||
? pathsConfig.app.accountHome.replace('[account]', value)
|
||||
|
||||
@@ -59,7 +59,8 @@ function SidebarContainer(props: {
|
||||
collapsible?: boolean;
|
||||
user: User;
|
||||
}) {
|
||||
const { account, accounts } = props;
|
||||
const { account, accounts, user } = props;
|
||||
const userId = user.id;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -68,12 +69,13 @@ function SidebarContainer(props: {
|
||||
className={'flex max-w-full items-center justify-between space-x-4'}
|
||||
>
|
||||
<TeamAccountAccountsSelector
|
||||
userId={userId}
|
||||
selectedAccount={account}
|
||||
accounts={accounts}
|
||||
/>
|
||||
|
||||
<TeamAccountNotifications
|
||||
userId={props.user.id}
|
||||
userId={userId}
|
||||
accountId={props.accountId}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -50,6 +50,7 @@ export function TeamAccountNavigationMenu(props: {
|
||||
|
||||
<div className={'flex justify-end space-x-2.5'}>
|
||||
<TeamAccountAccountsSelector
|
||||
userId={user.id}
|
||||
selectedAccount={account.slug}
|
||||
accounts={accounts.map((account) => ({
|
||||
label: account.name,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { cache } from 'react';
|
||||
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
import { requireUser } from '@kit/supabase/require-user';
|
||||
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
||||
import { createTeamAccountsApi } from '@kit/team-accounts/api';
|
||||
|
||||
@@ -26,19 +27,25 @@ export const loadTeamWorkspace = cache(async (accountSlug: string) => {
|
||||
const client = getSupabaseServerComponentClient();
|
||||
const api = createTeamAccountsApi(client);
|
||||
|
||||
const workspace = await api.getAccountWorkspace(accountSlug);
|
||||
|
||||
if (workspace.error) {
|
||||
throw workspace.error;
|
||||
}
|
||||
|
||||
const account = workspace.data.account;
|
||||
const [workspace, auth] = await Promise.all([
|
||||
api.getAccountWorkspace(accountSlug),
|
||||
requireUser(client),
|
||||
]);
|
||||
|
||||
// we cannot find any record for the selected account
|
||||
// so we redirect the user to the home page
|
||||
if (!account) {
|
||||
if (!workspace.data?.account) {
|
||||
return redirect(pathsConfig.app.home);
|
||||
}
|
||||
|
||||
return workspace.data;
|
||||
if (!auth.data) {
|
||||
return redirect(auth.redirectTo);
|
||||
}
|
||||
|
||||
const user = auth.data;
|
||||
|
||||
return {
|
||||
...workspace.data,
|
||||
user,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -62,6 +62,7 @@ function TeamWorkspaceLayout({
|
||||
|
||||
<div className={'flex space-x-4'}>
|
||||
<TeamAccountLayoutMobileNavigation
|
||||
userId={data.user.id}
|
||||
accounts={accounts}
|
||||
account={params.account}
|
||||
/>
|
||||
|
||||
@@ -19,7 +19,6 @@ export async function loadMembersPageData(
|
||||
loadTeamWorkspace(slug),
|
||||
loadAccountMembers(client, slug),
|
||||
loadInvitations(client, slug),
|
||||
loadUser(client),
|
||||
canAddMember,
|
||||
]);
|
||||
}
|
||||
@@ -38,16 +37,6 @@ async function canAddMember() {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
|
||||
async function loadUser(client: SupabaseClient<Database>) {
|
||||
const { data, error } = await client.auth.getUser();
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return data.user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load account members
|
||||
* @param client
|
||||
|
||||
@@ -18,6 +18,7 @@ import { If } from '@kit/ui/if';
|
||||
import { PageBody } from '@kit/ui/page';
|
||||
import { Trans } from '@kit/ui/trans';
|
||||
|
||||
import { loadTeamWorkspace } from '~/home/[account]/_lib/server/team-account-workspace.loader';
|
||||
import { createI18nServerInstance } from '~/lib/i18n/i18n.server';
|
||||
import { withI18n } from '~/lib/i18n/with-i18n';
|
||||
|
||||
@@ -43,7 +44,9 @@ export const generateMetadata = async () => {
|
||||
async function TeamAccountMembersPage({ params }: Params) {
|
||||
const client = getSupabaseServerComponentClient();
|
||||
|
||||
const [{ account }, members, invitations, user, canAddMember] =
|
||||
const { user } = await loadTeamWorkspace(params.account);
|
||||
|
||||
const [{ account }, members, invitations, canAddMember] =
|
||||
await loadMembersPageData(client, params.account);
|
||||
|
||||
const canManageRoles = account.permissions.includes('roles.manage');
|
||||
|
||||
Reference in New Issue
Block a user