Update database types and relationships
The commit removes semicolons at the ends of lines and makes updates to the Database object in the `database.types.ts` file. This better aligns the syntax with TypeScript norms. It also affects many database relationships, including but not limited to `Accounts`, `Roles`, and `Subscriptions`.
This commit is contained in:
@@ -20,7 +20,7 @@ import pathsConfig from '~/config/paths.config';
|
||||
export const loadTeamWorkspace = cache(async (accountSlug: string) => {
|
||||
const client = getSupabaseServerComponentClient();
|
||||
|
||||
const accountPromise = client.rpc('organization_account_workspace', {
|
||||
const accountPromise = client.rpc('team_account_workspace', {
|
||||
account_slug: accountSlug,
|
||||
});
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ import { loadUserWorkspace } from '../_lib/load-user-workspace';
|
||||
|
||||
export function HomeSidebar() {
|
||||
const collapsed = getSidebarCollapsed();
|
||||
const { accounts, user } = use(loadUserWorkspace());
|
||||
const { accounts, user, workspace } = use(loadUserWorkspace());
|
||||
|
||||
return (
|
||||
<Sidebar collapsed={collapsed}>
|
||||
@@ -38,7 +38,11 @@ export function HomeSidebar() {
|
||||
|
||||
<div className={'absolute bottom-4 left-0 w-full'}>
|
||||
<SidebarContent>
|
||||
<ProfileAccountDropdownContainer collapsed={collapsed} user={user} />
|
||||
<ProfileAccountDropdownContainer
|
||||
collapsed={collapsed}
|
||||
user={user}
|
||||
account={workspace}
|
||||
/>
|
||||
</SidebarContent>
|
||||
</div>
|
||||
</Sidebar>
|
||||
|
||||
@@ -9,27 +9,37 @@ import { useUser } from '@kit/supabase/hooks/use-user';
|
||||
import featuresFlagConfig from '~/config/feature-flags.config';
|
||||
import pathsConfig from '~/config/paths.config';
|
||||
|
||||
const paths = {
|
||||
home: pathsConfig.app.home,
|
||||
};
|
||||
|
||||
const features = {
|
||||
enableThemeToggle: featuresFlagConfig.enableThemeToggle,
|
||||
};
|
||||
|
||||
export function ProfileAccountDropdownContainer(props: {
|
||||
collapsed: boolean;
|
||||
user: User | null;
|
||||
|
||||
account?: {
|
||||
id: string | null;
|
||||
name: string | null;
|
||||
picture_url: string | null;
|
||||
};
|
||||
}) {
|
||||
const signOut = useSignOut();
|
||||
const user = useUser(props.user);
|
||||
|
||||
const userData = user.data ?? props.user ?? null;
|
||||
|
||||
return (
|
||||
<div className={props.collapsed ? '' : 'w-full animate-in fade-in-90'}>
|
||||
<div className={props.collapsed ? '' : 'w-full'}>
|
||||
<PersonalAccountDropdown
|
||||
paths={{
|
||||
home: pathsConfig.app.home,
|
||||
}}
|
||||
features={{
|
||||
enableThemeToggle: featuresFlagConfig.enableThemeToggle,
|
||||
}}
|
||||
className={'w-full'}
|
||||
paths={paths}
|
||||
features={features}
|
||||
showProfileName={!props.collapsed}
|
||||
user={userData}
|
||||
account={props.account}
|
||||
signOutRequested={() => signOut.mutateAsync()}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,26 +1,62 @@
|
||||
import { cache } from 'react';
|
||||
|
||||
import { SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
import { getSupabaseServerComponentClient } from '@kit/supabase/server-component-client';
|
||||
|
||||
import featureFlagsConfig from '~/config/feature-flags.config';
|
||||
import { Database } from '~/lib/database.types';
|
||||
|
||||
/**
|
||||
* @name loadUserWorkspace
|
||||
* @description
|
||||
* Load the user workspace data. It's a cached per-request function that fetches the user workspace data.
|
||||
* It can be used across the server components to load the user workspace data.
|
||||
*/
|
||||
export const loadUserWorkspace = cache(async () => {
|
||||
const client = getSupabaseServerComponentClient();
|
||||
const loadAccounts = featureFlagsConfig.enableTeamAccounts;
|
||||
|
||||
const accounts = loadAccounts ? await loadUserAccounts(client) : [];
|
||||
const { data } = await client.auth.getUser();
|
||||
const accountsPromise = loadAccounts
|
||||
? loadUserAccounts(client)
|
||||
: Promise.resolve([]);
|
||||
|
||||
const workspacePromise = loadUserAccountWorkspace(client);
|
||||
const userPromise = client.auth.getUser();
|
||||
|
||||
const [accounts, workspace, userResult] = await Promise.all([
|
||||
accountsPromise,
|
||||
workspacePromise,
|
||||
userPromise,
|
||||
]);
|
||||
|
||||
const user = userResult.data.user;
|
||||
|
||||
if (!user) {
|
||||
throw new Error('User is not logged in');
|
||||
}
|
||||
|
||||
return {
|
||||
accounts,
|
||||
user: data.user,
|
||||
workspace,
|
||||
user,
|
||||
};
|
||||
});
|
||||
|
||||
async function loadUserAccounts(
|
||||
client: ReturnType<typeof getSupabaseServerComponentClient<Database>>,
|
||||
) {
|
||||
async function loadUserAccountWorkspace(client: SupabaseClient<Database>) {
|
||||
const { data, error } = await client
|
||||
.from('user_account_workspace')
|
||||
.select(`*`)
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
async function loadUserAccounts(client: SupabaseClient<Database>) {
|
||||
const { data: accounts, error } = await client
|
||||
.from('user_accounts')
|
||||
.select(`name, slug, picture_url`);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 92 KiB |
@@ -1781,19 +1781,21 @@ language plpgsql;
|
||||
--
|
||||
-- VIEW "user_account_workspace":
|
||||
-- we create a view to load the general app data for the authenticated
|
||||
-- user which includes the user's accounts, memberships, and roles, and relative subscription status
|
||||
-- user which includes the user accounts and memberships
|
||||
create or replace view public.user_account_workspace as
|
||||
select
|
||||
accounts.id as id,
|
||||
accounts.name as name,
|
||||
accounts.picture_url as picture_url,
|
||||
accounts.public_data as public_data,
|
||||
subscriptions.status as subscription_status
|
||||
from
|
||||
public.accounts
|
||||
left join public.subscriptions on accounts.id = subscriptions.account_id
|
||||
where
|
||||
primary_owner_user_id = auth.uid()
|
||||
and accounts.is_personal_account = true;
|
||||
and accounts.is_personal_account = true
|
||||
limit 1;
|
||||
|
||||
grant select on public.user_account_workspace to authenticated, service_role;
|
||||
|
||||
@@ -1822,7 +1824,7 @@ grant select on public.user_accounts to authenticated, service_role;
|
||||
-- Function: get the account workspace for an organization account
|
||||
-- to load all the required data for the authenticated user within the account scope
|
||||
create or replace function
|
||||
public.organization_account_workspace(account_slug text)
|
||||
public.team_account_workspace(account_slug text)
|
||||
returns table(
|
||||
id uuid,
|
||||
name varchar(255),
|
||||
@@ -1869,7 +1871,7 @@ end;
|
||||
$$
|
||||
language plpgsql;
|
||||
|
||||
grant execute on function public.organization_account_workspace(text)
|
||||
grant execute on function public.team_account_workspace(text)
|
||||
to authenticated, service_role;
|
||||
|
||||
-- Functions: get account members
|
||||
|
||||
@@ -36,19 +36,29 @@ export function PersonalAccountDropdown({
|
||||
showProfileName,
|
||||
paths,
|
||||
features,
|
||||
account,
|
||||
}: {
|
||||
className?: string;
|
||||
user: User | null;
|
||||
|
||||
account?: {
|
||||
id: string | null;
|
||||
name: string | null;
|
||||
picture_url: string | null;
|
||||
};
|
||||
|
||||
signOutRequested: () => unknown;
|
||||
showProfileName?: boolean;
|
||||
|
||||
paths: {
|
||||
home: string;
|
||||
};
|
||||
|
||||
features: {
|
||||
enableThemeToggle: boolean;
|
||||
};
|
||||
}) {
|
||||
const { data: personalAccountData } = usePersonalAccountData();
|
||||
const { data: personalAccountData } = usePersonalAccountData(account);
|
||||
|
||||
const signedInAsLabel = useMemo(() => {
|
||||
const email = user?.email ?? undefined;
|
||||
@@ -57,7 +67,8 @@ export function PersonalAccountDropdown({
|
||||
return email ?? phone;
|
||||
}, [user?.email, user?.phone]);
|
||||
|
||||
const displayName = personalAccountData?.name ?? user?.email ?? '';
|
||||
const displayName =
|
||||
account?.name ?? personalAccountData?.name ?? user?.email ?? '';
|
||||
|
||||
const isSuperAdmin = useMemo(() => {
|
||||
return user?.app_metadata.role === 'super-admin';
|
||||
|
||||
@@ -5,7 +5,15 @@ import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { useSupabase } from '@kit/supabase/hooks/use-supabase';
|
||||
import { useUser } from '@kit/supabase/hooks/use-user';
|
||||
|
||||
export function usePersonalAccountData() {
|
||||
export function usePersonalAccountData(
|
||||
partialAccount?:
|
||||
| {
|
||||
id: string | null;
|
||||
name: string | null;
|
||||
picture_url: string | null;
|
||||
}
|
||||
| undefined,
|
||||
) {
|
||||
const client = useSupabase();
|
||||
const user = useUser();
|
||||
const userId = user.data?.id;
|
||||
@@ -43,6 +51,7 @@ export function usePersonalAccountData() {
|
||||
enabled: !!userId,
|
||||
refetchOnWindowFocus: false,
|
||||
refetchOnMount: false,
|
||||
initialData: partialAccount,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user