chore: preserve non-org dashboard for platform users (#16181)

This commit is contained in:
Morgan authored and GitHub committed 2024-08-14 15:11:46 -07:00
1 parent a11242e93d
commit 84606543ae
10 files changed
+107 -25

No files matched your search

+4
View File
@@ -51,6 +51,10 @@
<path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" ></path>
<path d="M10.3 21a1.94 1.94 0 0 0 3.4 0" ></path>
</symbol>
<symbol class="lucide lucide-blocks" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" id="blocks">
<rect width="7" height="7" x="14" y="3" rx="1" ></rect>
<path d="M10 21V8a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1H3" ></path>
</symbol>
<symbol class="lucide lucide-bold" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" id="bold">
<path d="M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8" ></path>
</symbol>

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

+13 -11
View File
@@ -531,17 +531,19 @@ export const AUTH_OPTIONS: AuthOptions = {
belongsToActiveTeam,
// All organizations in the token would be too big to store. It breaks the sessions request.
// So, we just set the currently switched organization only here.
org: profileOrg
? {
id: profileOrg.id,
name: profileOrg.name,
slug: profileOrg.slug ?? profileOrg.requestedSlug ?? "",
logoUrl: profileOrg.logoUrl,
fullDomain: getOrgFullOrigin(profileOrg.slug ?? profileOrg.requestedSlug ?? ""),
domainSuffix: subdomainSuffix(),
role: orgRole as MembershipRole, // It can't be undefined if we have a profileOrg
}
: null,
// platform org user don't need profiles nor domains
org:
profileOrg && !profileOrg.isPlatform
? {
id: profileOrg.id,
name: profileOrg.name,
slug: profileOrg.slug ?? profileOrg.requestedSlug ?? "",
logoUrl: profileOrg.logoUrl,
fullDomain: getOrgFullOrigin(profileOrg.slug ?? profileOrg.requestedSlug ?? ""),
domainSuffix: subdomainSuffix(),
role: orgRole as MembershipRole, // It can't be undefined if we have a profileOrg
}
: null,
} as JWT;
};
if (!user) {
@@ -248,7 +248,7 @@ export const getPublicEvent = async (
};
// In case it's not a group event, it's either a single user or a team, and we query that data.
const event = await prisma.eventType.findFirst({
let event = await prisma.eventType.findFirst({
where: {
slug: eventSlug,
...usersOrTeamQuery,
@@ -256,6 +256,27 @@ export const getPublicEvent = async (
select: publicEventSelect,
});
// If no event was found, check for platform org user event
if (!event && !orgQuery) {
event = await prisma.eventType.findFirst({
where: {
slug: eventSlug,
users: {
some: {
username,
isPlatformManaged: false,
movedToProfile: {
organization: {
isPlatform: true,
},
},
},
},
},
select: publicEventSelect,
});
}
if (!event) return null;
const eventMetaData = EventTypeMetaDataSchema.parse(event.metadata || {});
+22 -8
View File
@@ -384,7 +384,8 @@ function UserDropdown({ small }: UserDropdownProps) {
const { data: user } = useMeQuery();
const utils = trpc.useUtils();
const bookerUrl = useBookerUrl();
const pathname = usePathname();
const isPlatformPages = pathname?.startsWith("/settings/platform");
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
@@ -468,7 +469,7 @@ function UserDropdown({ small }: UserDropdownProps) {
<HelpMenuItem onHelpItemSelect={() => onHelpItemSelect()} />
) : (
<>
{!isPlatformUser && (
{!isPlatformPages && (
<>
<DropdownMenuItem>
<DropdownItem
@@ -527,7 +528,7 @@ function UserDropdown({ small }: UserDropdownProps) {
{t("help")}
</DropdownItem>
</DropdownMenuItem>
{!isPlatformUser && (
{!isPlatformPages && (
<DropdownMenuItem className="todesktop:hidden hidden lg:flex">
<DropdownItem
StartIcon="download"
@@ -539,6 +540,17 @@ function UserDropdown({ small }: UserDropdownProps) {
</DropdownMenuItem>
)}
{!isPlatformPages && (
<DropdownMenuItem className="todesktop:hidden hidden lg:flex">
<DropdownItem
StartIcon="blocks"
target="_blank"
rel="noreferrer"
href="/settings/platform">
Platform
</DropdownItem>
</DropdownMenuItem>
)}
<DropdownMenuSeparator />
<DropdownMenuItem>
@@ -912,9 +924,11 @@ function SideBarContainer({ bannersHeight, isPlatformUser = false }: SideBarCont
return <SideBar isPlatformUser={isPlatformUser} bannersHeight={bannersHeight} user={data?.user} />;
}
function SideBar({ bannersHeight, user, isPlatformUser = false }: SideBarProps) {
function SideBar({ bannersHeight, user }: SideBarProps) {
const { t, isLocaleReady } = useLocale();
const orgBranding = useOrgBranding();
const pathname = usePathname();
const isPlatformPages = pathname?.startsWith("/settings/platform");
const publicPageUrl = useMemo(() => {
if (!user?.org?.id) return `${process.env.NEXT_PUBLIC_WEBSITE_URL}/${user?.username}`;
@@ -953,10 +967,10 @@ function SideBar({ bannersHeight, user, isPlatformUser = false }: SideBarProps)
return (
<div className="relative">
<aside
style={!isPlatformUser ? sidebarStylingAttributes : {}}
style={!isPlatformPages ? sidebarStylingAttributes : {}}
className={classNames(
"bg-muted border-muted fixed left-0 hidden h-full w-14 flex-col overflow-y-auto overflow-x-hidden border-r md:sticky md:flex lg:w-56 lg:px-3",
!isPlatformUser && "max-h-screen"
!isPlatformPages && "max-h-screen"
)}>
<div className="flex h-full flex-col justify-between py-3 lg:pt-4">
<header className="todesktop:-mt-3 todesktop:flex-col-reverse todesktop:[-webkit-app-region:drag] items-center justify-between md:hidden lg:flex">
@@ -1018,10 +1032,10 @@ function SideBar({ bannersHeight, user, isPlatformUser = false }: SideBarProps)
<Link href="/event-types" className="text-center md:inline lg:hidden">
<Logo small icon />
</Link>
<Navigation isPlatformNavigation={isPlatformUser} />
<Navigation isPlatformNavigation={isPlatformPages} />
</div>
{!isPlatformUser && (
{!isPlatformPages && (
<div>
<Tips />
{bottomNavItems.map((item, index) => (
+7
View File
@@ -15,11 +15,18 @@ export const getBrand = async (orgId: number | null) => {
name: true,
slug: true,
metadata: true,
isPlatform: true,
},
});
if (!org) {
return null;
}
// platform orgs don't have a brand nor a domain
if (org.isPlatform) {
return null;
}
const metadata = teamMetadataSchema.parse(org.metadata);
const slug = (org.slug || metadata?.requestedSlug) as string;
const fullDomain = getOrgFullOrigin(slug);
@@ -23,6 +23,7 @@ const userSelect = Prisma.validator<Prisma.UserSelect>()({
startTime: true,
endTime: true,
bufferTime: true,
isPlatformManaged: true,
});
const membershipSelect = Prisma.validator<Prisma.MembershipSelect>()({
@@ -43,6 +44,7 @@ const organizationSelect = {
logoUrl: true,
calVideoLogo: true,
bannerUrl: true,
isPlatform: true,
};
export enum LookupTarget {
@@ -329,6 +331,12 @@ export class ProfileRepository {
return null;
}
const user = profile.user;
if (profile.organization?.isPlatform && !user.isPlatformManaged) {
return {
...this.buildPersonalProfileFromUser({ user }),
...ProfileRepository.getInheritedDataFromUser({ user }),
};
}
return {
...profile,
...ProfileRepository.getInheritedDataFromUser({ user }),
+11
View File
@@ -30,6 +30,7 @@ const teamSelect = Prisma.validator<Prisma.TeamSelect>()({
logoUrl: true,
organizationSettings: true,
isOrganization: true,
isPlatform: true,
});
const userSelect = Prisma.validator<Prisma.UserSelect>()({
@@ -67,6 +68,7 @@ const userSelect = Prisma.validator<Prisma.UserSelect>()({
locked: true,
movedToProfileId: true,
metadata: true,
isPlatformManaged: true,
});
export class UserRepository {
@@ -330,6 +332,15 @@ export class UserRepository {
const profiles = await ProfileRepository.findManyForUser({ id: user.id });
if (profiles.length) {
const profile = profiles[0];
// platform org user doesn't need org profile
if (profile?.organization?.isPlatform) {
return {
...user,
nonProfileUsername: user.username,
profile: ProfileRepository.buildPersonalProfileFromUser({ user }),
};
}
return {
...user,
username: profile.username,
@@ -106,6 +106,23 @@ export const meHandler = async ({ ctx, input }: MeOptions) => {
// Destructuring here only makes it more illegible
// pick only the part we want to expose in the API
const profileData = user.organization?.isPlatform
? {
organizationId: null,
organization: { id: -1, isPlatform: true, slug: "", isOrgAdmin: false },
username: user.username ?? null,
profile: ProfileRepository.buildPersonalProfileFromUser({ user }),
profiles: [],
}
: {
organizationId: user.profile?.organizationId ?? null,
organization: user.organization,
username: user.profile?.username ?? user.username ?? null,
profile: user.profile ?? null,
profiles: allUserEnrichedProfiles,
};
return {
id: user.id,
name: user.name,
@@ -140,11 +157,7 @@ export const meHandler = async ({ ctx, input }: MeOptions) => {
allowDynamicBooking: user.allowDynamicBooking,
allowSEOIndexing: user.allowSEOIndexing,
receiveMonthlyDigestEmail: user.receiveMonthlyDigestEmail,
organizationId: user.profile?.organizationId ?? null,
organization: user.organization,
username: user.profile?.username ?? user.username ?? null,
profile: user.profile ?? null,
profiles: allUserEnrichedProfiles,
...profileData,
secondaryEmails,
sumOfBookings: additionalUserInfo?.bookings.length,
sumOfCalendars: additionalUserInfo?.selectedCalendars.length,
@@ -136,4 +136,5 @@ export const lucideIconList = new Set([
"webhook",
"x",
"zap",
"blocks",
]);
@@ -13,6 +13,7 @@ export type IconName =
| "badge-check"
| "ban"
| "bell"
| "blocks"
| "bold"
| "book-open-check"
| "book-open"