chore: unify org data access (#11158)
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: Omar López <zomars@me.com>pull/11226/head
parent
f326a9a620
commit
ba4e717b59
|
@ -14,7 +14,6 @@ import DynamicHelpscoutProvider from "@calcom/features/ee/support/lib/helpscout/
|
||||||
import DynamicIntercomProvider from "@calcom/features/ee/support/lib/intercom/providerDynamic";
|
import DynamicIntercomProvider from "@calcom/features/ee/support/lib/intercom/providerDynamic";
|
||||||
import { FeatureProvider } from "@calcom/features/flags/context/provider";
|
import { FeatureProvider } from "@calcom/features/flags/context/provider";
|
||||||
import { useFlags } from "@calcom/features/flags/hooks";
|
import { useFlags } from "@calcom/features/flags/hooks";
|
||||||
import { trpc } from "@calcom/trpc/react";
|
|
||||||
import { MetaProvider } from "@calcom/ui";
|
import { MetaProvider } from "@calcom/ui";
|
||||||
|
|
||||||
import useIsBookingPage from "@lib/hooks/useIsBookingPage";
|
import useIsBookingPage from "@lib/hooks/useIsBookingPage";
|
||||||
|
@ -222,19 +221,7 @@ function FeatureFlagsProvider({ children }: { children: React.ReactNode }) {
|
||||||
|
|
||||||
function useOrgBrandingValues() {
|
function useOrgBrandingValues() {
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
|
return session?.data?.user.org;
|
||||||
const res = trpc.viewer.organizations.getBrand.useQuery(undefined, {
|
|
||||||
// Only fetch if we have a session to avoid flooding logs with errors
|
|
||||||
enabled: session.status === "authenticated",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (res.status === "loading") {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.status === "error") return null;
|
|
||||||
|
|
||||||
return res.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function OrgBrandProvider({ children }: { children: React.ReactNode }) {
|
function OrgBrandProvider({ children }: { children: React.ReactNode }) {
|
||||||
|
|
|
@ -72,7 +72,7 @@ export async function getServerSession(options: {
|
||||||
image: `${CAL_URL}/${user.username}/avatar.png`,
|
image: `${CAL_URL}/${user.username}/avatar.png`,
|
||||||
impersonatedByUID: token.impersonatedByUID ?? undefined,
|
impersonatedByUID: token.impersonatedByUID ?? undefined,
|
||||||
belongsToActiveTeam: token.belongsToActiveTeam,
|
belongsToActiveTeam: token.belongsToActiveTeam,
|
||||||
organizationId: token.organizationId,
|
org: token.org,
|
||||||
locale: user.locale ?? undefined,
|
locale: user.locale ?? undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,7 @@ import GoogleProvider from "next-auth/providers/google";
|
||||||
|
|
||||||
import checkLicense from "@calcom/features/ee/common/server/checkLicense";
|
import checkLicense from "@calcom/features/ee/common/server/checkLicense";
|
||||||
import ImpersonationProvider from "@calcom/features/ee/impersonation/lib/ImpersonationProvider";
|
import ImpersonationProvider from "@calcom/features/ee/impersonation/lib/ImpersonationProvider";
|
||||||
|
import { getOrgFullDomain, subdomainSuffix } from "@calcom/features/ee/organizations/lib/orgDomains";
|
||||||
import { clientSecretVerifier, hostedCal, isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
import { clientSecretVerifier, hostedCal, isSAMLLoginEnabled } from "@calcom/features/ee/sso/lib/saml";
|
||||||
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
|
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
|
||||||
import { IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
|
import { IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
|
@ -402,7 +403,14 @@ export const AUTH_OPTIONS: AuthOptions = {
|
||||||
username: true,
|
username: true,
|
||||||
name: true,
|
name: true,
|
||||||
email: true,
|
email: true,
|
||||||
organizationId: true,
|
organization: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
slug: true,
|
||||||
|
metadata: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
role: true,
|
role: true,
|
||||||
locale: true,
|
locale: true,
|
||||||
teams: {
|
teams: {
|
||||||
|
@ -419,12 +427,23 @@ export const AUTH_OPTIONS: AuthOptions = {
|
||||||
|
|
||||||
// Check if the existingUser has any active teams
|
// Check if the existingUser has any active teams
|
||||||
const belongsToActiveTeam = checkIfUserBelongsToActiveTeam(existingUser);
|
const belongsToActiveTeam = checkIfUserBelongsToActiveTeam(existingUser);
|
||||||
const { teams: _teams, ...existingUserWithoutTeamsField } = existingUser;
|
const { teams: _teams, organization, ...existingUserWithoutTeamsField } = existingUser;
|
||||||
|
|
||||||
|
const parsedOrgMetadata = teamMetadataSchema.parse(organization?.metadata ?? {});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...existingUserWithoutTeamsField,
|
...existingUserWithoutTeamsField,
|
||||||
...token,
|
...token,
|
||||||
belongsToActiveTeam,
|
belongsToActiveTeam,
|
||||||
|
org: organization
|
||||||
|
? {
|
||||||
|
id: organization.id,
|
||||||
|
name: organization.name,
|
||||||
|
slug: organization.slug ?? parsedOrgMetadata?.requestedSlug ?? "",
|
||||||
|
fullDomain: getOrgFullDomain(organization.slug ?? parsedOrgMetadata?.requestedSlug ?? ""),
|
||||||
|
domainSuffix: subdomainSuffix(),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
@ -448,7 +467,7 @@ export const AUTH_OPTIONS: AuthOptions = {
|
||||||
role: user.role,
|
role: user.role,
|
||||||
impersonatedByUID: user?.impersonatedByUID,
|
impersonatedByUID: user?.impersonatedByUID,
|
||||||
belongsToActiveTeam: user?.belongsToActiveTeam,
|
belongsToActiveTeam: user?.belongsToActiveTeam,
|
||||||
organizationId: user?.organizationId,
|
org: user?.org,
|
||||||
locale: user?.locale,
|
locale: user?.locale,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -487,7 +506,7 @@ export const AUTH_OPTIONS: AuthOptions = {
|
||||||
role: existingUser.role,
|
role: existingUser.role,
|
||||||
impersonatedByUID: token.impersonatedByUID as number,
|
impersonatedByUID: token.impersonatedByUID as number,
|
||||||
belongsToActiveTeam: token?.belongsToActiveTeam as boolean,
|
belongsToActiveTeam: token?.belongsToActiveTeam as boolean,
|
||||||
organizationId: token?.organizationId,
|
org: token?.org,
|
||||||
locale: existingUser.locale,
|
locale: existingUser.locale,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -507,7 +526,7 @@ export const AUTH_OPTIONS: AuthOptions = {
|
||||||
role: token.role as UserPermissionRole,
|
role: token.role as UserPermissionRole,
|
||||||
impersonatedByUID: token.impersonatedByUID as number,
|
impersonatedByUID: token.impersonatedByUID as number,
|
||||||
belongsToActiveTeam: token?.belongsToActiveTeam as boolean,
|
belongsToActiveTeam: token?.belongsToActiveTeam as boolean,
|
||||||
organizationId: token?.organizationId,
|
org: token?.org,
|
||||||
locale: token.locale,
|
locale: token.locale,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,7 +10,7 @@ import type { teamMetadataSchema } from "@calcom/prisma/zod-utils";
|
||||||
*/
|
*/
|
||||||
export type OrganizationBranding =
|
export type OrganizationBranding =
|
||||||
| ({
|
| ({
|
||||||
logo?: string | null | undefined;
|
id: number;
|
||||||
name?: string;
|
name?: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
fullDomain: string;
|
fullDomain: string;
|
||||||
|
|
|
@ -16,7 +16,7 @@ export const getServerSideProps = async ({ req, res }: GetServerSidePropsContext
|
||||||
|
|
||||||
// Check if logged in user has an organization assigned
|
// Check if logged in user has an organization assigned
|
||||||
const session = await getServerSession({ req, res });
|
const session = await getServerSession({ req, res });
|
||||||
if (!session?.user.organizationId) {
|
if (!session?.user.org?.id) {
|
||||||
return {
|
return {
|
||||||
notFound: true,
|
notFound: true,
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,7 @@ export const getServerSideProps = async ({ req, res }: GetServerSidePropsContext
|
||||||
const membership = await prisma.membership.findFirst({
|
const membership = await prisma.membership.findFirst({
|
||||||
where: {
|
where: {
|
||||||
userId: session?.user.id,
|
userId: session?.user.id,
|
||||||
teamId: session?.user.organizationId,
|
teamId: session?.user.org.id,
|
||||||
},
|
},
|
||||||
select: {
|
select: {
|
||||||
role: true,
|
role: true,
|
||||||
|
|
|
@ -69,7 +69,7 @@ const MembersView = () => {
|
||||||
const [showMemberInvitationModal, setShowMemberInvitationModal] = useState<boolean>(false);
|
const [showMemberInvitationModal, setShowMemberInvitationModal] = useState<boolean>(false);
|
||||||
const [members, setMembers] = useState<Members>([]);
|
const [members, setMembers] = useState<Members>([]);
|
||||||
const { data: currentOrg } = trpc.viewer.organizations.listCurrent.useQuery(undefined, {
|
const { data: currentOrg } = trpc.viewer.organizations.listCurrent.useQuery(undefined, {
|
||||||
enabled: !!session.data?.user?.organizationId,
|
enabled: !!session.data?.user?.org,
|
||||||
});
|
});
|
||||||
const { data: team, isLoading: isTeamLoading } = trpc.viewer.organizations.getOtherTeam.useQuery(
|
const { data: team, isLoading: isTeamLoading } = trpc.viewer.organizations.getOtherTeam.useQuery(
|
||||||
{ teamId },
|
{ teamId },
|
||||||
|
|
|
@ -215,7 +215,7 @@ const PendingMemberItem = (props: { member: TeamMember; index: number; teamId: n
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
const bookerUrl = useBookerUrl();
|
const bookerUrl = useBookerUrl();
|
||||||
const { data: currentOrg } = trpc.viewer.organizations.listCurrent.useQuery(undefined, {
|
const { data: currentOrg } = trpc.viewer.organizations.listCurrent.useQuery(undefined, {
|
||||||
enabled: !!session.data?.user?.organizationId,
|
enabled: !!session.data?.user?.org,
|
||||||
});
|
});
|
||||||
const removeMemberMutation = trpc.viewer.teams.removeMember.useMutation({
|
const removeMemberMutation = trpc.viewer.teams.removeMember.useMutation({
|
||||||
async onSuccess() {
|
async onSuccess() {
|
||||||
|
|
|
@ -80,7 +80,7 @@ const MembersView = () => {
|
||||||
const [showMemberInvitationModal, setShowMemberInvitationModal] = useState(showDialog);
|
const [showMemberInvitationModal, setShowMemberInvitationModal] = useState(showDialog);
|
||||||
const [showInviteLinkSettingsModal, setInviteLinkSettingsModal] = useState(false);
|
const [showInviteLinkSettingsModal, setInviteLinkSettingsModal] = useState(false);
|
||||||
const { data: currentOrg } = trpc.viewer.organizations.listCurrent.useQuery(undefined, {
|
const { data: currentOrg } = trpc.viewer.organizations.listCurrent.useQuery(undefined, {
|
||||||
enabled: !!session.data?.user?.organizationId,
|
enabled: !!session.data?.user?.org,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: orgMembersNotInThisTeam, isLoading: isOrgListLoading } =
|
const { data: orgMembersNotInThisTeam, isLoading: isOrgListLoading } =
|
||||||
|
|
|
@ -159,7 +159,7 @@ const useTabs = () => {
|
||||||
|
|
||||||
// check if name is in adminRequiredKeys
|
// check if name is in adminRequiredKeys
|
||||||
return tabs.filter((tab) => {
|
return tabs.filter((tab) => {
|
||||||
if (organizationRequiredKeys.includes(tab.name)) return !!session.data?.user?.organizationId;
|
if (organizationRequiredKeys.includes(tab.name)) return !!session.data?.user?.org;
|
||||||
|
|
||||||
if (isAdmin) return true;
|
if (isAdmin) return true;
|
||||||
return !adminRequiredKeys.includes(tab.name);
|
return !adminRequiredKeys.includes(tab.name);
|
||||||
|
@ -205,7 +205,7 @@ const SettingsSidebarContainer = ({
|
||||||
const { data: teams } = trpc.viewer.teams.list.useQuery();
|
const { data: teams } = trpc.viewer.teams.list.useQuery();
|
||||||
const session = useSession();
|
const session = useSession();
|
||||||
const { data: currentOrg } = trpc.viewer.organizations.listCurrent.useQuery(undefined, {
|
const { data: currentOrg } = trpc.viewer.organizations.listCurrent.useQuery(undefined, {
|
||||||
enabled: !!session.data?.user?.organizationId,
|
enabled: !!session.data?.user?.org,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: otherTeams } = trpc.viewer.organizations.listOtherTeams.useQuery();
|
const { data: otherTeams } = trpc.viewer.organizations.listOtherTeams.useQuery();
|
||||||
|
|
|
@ -22,7 +22,6 @@ import AdminPasswordBanner from "@calcom/features/users/components/AdminPassword
|
||||||
import VerifyEmailBanner from "@calcom/features/users/components/VerifyEmailBanner";
|
import VerifyEmailBanner from "@calcom/features/users/components/VerifyEmailBanner";
|
||||||
import classNames from "@calcom/lib/classNames";
|
import classNames from "@calcom/lib/classNames";
|
||||||
import { APP_NAME, DESKTOP_APP_LINK, JOIN_DISCORD, ROADMAP, WEBAPP_URL } from "@calcom/lib/constants";
|
import { APP_NAME, DESKTOP_APP_LINK, JOIN_DISCORD, ROADMAP, WEBAPP_URL } from "@calcom/lib/constants";
|
||||||
import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage";
|
|
||||||
import getBrandColours from "@calcom/lib/getBrandColours";
|
import getBrandColours from "@calcom/lib/getBrandColours";
|
||||||
import { useBookerUrl } from "@calcom/lib/hooks/useBookerUrl";
|
import { useBookerUrl } from "@calcom/lib/hooks/useBookerUrl";
|
||||||
import { useIsomorphicLayoutEffect } from "@calcom/lib/hooks/useIsomorphicLayoutEffect";
|
import { useIsomorphicLayoutEffect } from "@calcom/lib/hooks/useIsomorphicLayoutEffect";
|
||||||
|
@ -792,13 +791,12 @@ function SideBarContainer({ bannersHeight }: SideBarContainerProps) {
|
||||||
function SideBar({ bannersHeight, user }: SideBarProps) {
|
function SideBar({ bannersHeight, user }: SideBarProps) {
|
||||||
const { t, isLocaleReady } = useLocale();
|
const { t, isLocaleReady } = useLocale();
|
||||||
const orgBranding = useOrgBranding();
|
const orgBranding = useOrgBranding();
|
||||||
const isOrgBrandingDataFetched = orgBranding !== undefined;
|
|
||||||
|
|
||||||
const publicPageUrl = useMemo(() => {
|
const publicPageUrl = useMemo(() => {
|
||||||
if (!user?.organizationId) return `${process.env.NEXT_PUBLIC_WEBSITE_URL}/${user?.username}`;
|
if (!user?.org?.id) return `${process.env.NEXT_PUBLIC_WEBSITE_URL}/${user?.username}`;
|
||||||
const publicPageUrl = orgBranding?.slug ? getOrgFullDomain(orgBranding.slug) : "";
|
const publicPageUrl = orgBranding?.slug ? getOrgFullDomain(orgBranding.slug) : "";
|
||||||
return publicPageUrl;
|
return publicPageUrl;
|
||||||
}, [orgBranding?.slug, user?.organizationId, user?.username]);
|
}, [orgBranding?.slug, user?.username, user?.org?.id]);
|
||||||
|
|
||||||
const bottomNavItems: NavigationItemType[] = [
|
const bottomNavItems: NavigationItemType[] = [
|
||||||
{
|
{
|
||||||
|
@ -819,7 +817,7 @@ function SideBar({ bannersHeight, user }: SideBarProps) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "settings",
|
name: "settings",
|
||||||
href: user?.organizationId ? `/settings/organizations/profile` : "/settings/my-account/profile",
|
href: user?.org ? `/settings/organizations/profile` : "/settings/my-account/profile",
|
||||||
icon: Settings,
|
icon: Settings,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@ -830,12 +828,12 @@ function SideBar({ bannersHeight, user }: SideBarProps) {
|
||||||
className="desktop-transparent bg-muted border-muted fixed left-0 hidden h-full max-h-screen w-14 flex-col overflow-y-auto overflow-x-hidden border-r dark:bg-gradient-to-tr dark:from-[#2a2a2a] dark:to-[#1c1c1c] md:sticky md:flex lg:w-56 lg:px-3">
|
className="desktop-transparent bg-muted border-muted fixed left-0 hidden h-full max-h-screen w-14 flex-col overflow-y-auto overflow-x-hidden border-r dark:bg-gradient-to-tr dark:from-[#2a2a2a] dark:to-[#1c1c1c] md:sticky md:flex lg:w-56 lg:px-3">
|
||||||
<div className="flex h-full flex-col justify-between py-3 lg:pt-4">
|
<div className="flex h-full flex-col justify-between py-3 lg:pt-4">
|
||||||
<header className="items-center justify-between md:hidden lg:flex">
|
<header className="items-center justify-between md:hidden lg:flex">
|
||||||
{!isOrgBrandingDataFetched ? null : orgBranding ? (
|
{orgBranding ? (
|
||||||
<Link href="/settings/organizations/profile" className="px-1.5">
|
<Link href="/settings/organizations/profile" className="px-1.5">
|
||||||
<div className="flex items-center gap-2 font-medium">
|
<div className="flex items-center gap-2 font-medium">
|
||||||
<Avatar
|
<Avatar
|
||||||
alt={`${orgBranding.name} logo`}
|
alt={`${orgBranding.name} logo`}
|
||||||
imageSrc={getPlaceholderAvatar(orgBranding.logo, orgBranding.name)}
|
imageSrc={`${orgBranding.fullDomain}/avatar.png`}
|
||||||
size="xsm"
|
size="xsm"
|
||||||
/>
|
/>
|
||||||
<p className="text line-clamp-1 text-sm">
|
<p className="text line-clamp-1 text-sm">
|
||||||
|
|
|
@ -7,7 +7,7 @@ import type { Action, State } from "./UserListTable";
|
||||||
|
|
||||||
export function ChangeUserRoleModal(props: { state: State; dispatch: Dispatch<Action> }) {
|
export function ChangeUserRoleModal(props: { state: State; dispatch: Dispatch<Action> }) {
|
||||||
const { data: session } = useSession();
|
const { data: session } = useSession();
|
||||||
const orgId = session?.user.organizationId;
|
const orgId = session?.user.org?.id;
|
||||||
if (!orgId || !props.state.changeMemberRole.user) return null;
|
if (!orgId || !props.state.changeMemberRole.user) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -40,10 +40,10 @@ export function DeleteMemberModal({ state, dispatch }: { state: State; dispatch:
|
||||||
confirmBtnText={t("confirm_remove_member")}
|
confirmBtnText={t("confirm_remove_member")}
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
// Shouldnt ever happen just for type safety
|
// Shouldnt ever happen just for type safety
|
||||||
if (!session?.user.organizationId || !state?.deleteMember?.user?.id) return;
|
if (!session?.user.org?.id || !state?.deleteMember?.user?.id) return;
|
||||||
|
|
||||||
removeMemberMutation.mutate({
|
removeMemberMutation.mutate({
|
||||||
teamId: session?.user.organizationId,
|
teamId: session?.user.org.id,
|
||||||
memberId: state?.deleteMember?.user.id,
|
memberId: state?.deleteMember?.user.id,
|
||||||
isOrg: true,
|
isOrg: true,
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,7 +9,7 @@ import type { Action, State } from "./UserListTable";
|
||||||
export function ImpersonationMemberModal(props: { state: State; dispatch: Dispatch<Action> }) {
|
export function ImpersonationMemberModal(props: { state: State; dispatch: Dispatch<Action> }) {
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const { data: session } = useSession();
|
const { data: session } = useSession();
|
||||||
const teamId = session?.user.organizationId;
|
const teamId = session?.user.org?.id;
|
||||||
const user = props.state.impersonateMember.user;
|
const user = props.state.impersonateMember.user;
|
||||||
|
|
||||||
if (!user || !teamId) return null;
|
if (!user || !teamId) return null;
|
||||||
|
|
|
@ -46,9 +46,9 @@ export function InviteMemberModal(props: Props) {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!session?.user.organizationId) return null;
|
if (!session?.user.org?.id) return null;
|
||||||
|
|
||||||
const orgId = session.user.organizationId;
|
const orgId = session.user.org.id;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MemberInvitationModal
|
<MemberInvitationModal
|
||||||
|
|
|
@ -16,7 +16,13 @@ declare module "next-auth" {
|
||||||
email_verified?: boolean;
|
email_verified?: boolean;
|
||||||
impersonatedByUID?: number;
|
impersonatedByUID?: number;
|
||||||
belongsToActiveTeam?: boolean;
|
belongsToActiveTeam?: boolean;
|
||||||
organizationId?: number | null;
|
org?: {
|
||||||
|
id: number;
|
||||||
|
name?: string;
|
||||||
|
slug: string;
|
||||||
|
fullDomain: string;
|
||||||
|
domainSuffix: string;
|
||||||
|
};
|
||||||
username?: PrismaUser["username"];
|
username?: PrismaUser["username"];
|
||||||
role?: PrismaUser["role"] | "INACTIVE_ADMIN";
|
role?: PrismaUser["role"] | "INACTIVE_ADMIN";
|
||||||
locale?: string | null;
|
locale?: string | null;
|
||||||
|
@ -32,6 +38,13 @@ declare module "next-auth/jwt" {
|
||||||
role?: UserPermissionRole | "INACTIVE_ADMIN" | null;
|
role?: UserPermissionRole | "INACTIVE_ADMIN" | null;
|
||||||
impersonatedByUID?: number | null;
|
impersonatedByUID?: number | null;
|
||||||
belongsToActiveTeam?: boolean;
|
belongsToActiveTeam?: boolean;
|
||||||
|
org?: {
|
||||||
|
id: number;
|
||||||
|
name?: string;
|
||||||
|
slug: string;
|
||||||
|
fullDomain: string;
|
||||||
|
domainSuffix: string;
|
||||||
|
};
|
||||||
organizationId?: number | null;
|
organizationId?: number | null;
|
||||||
locale?: string;
|
locale?: string;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue