Skip to content

Commit

Permalink
chore: remove personal branding if in an org and use org branding (#1…
Browse files Browse the repository at this point in the history
…4872)

* chore: remove personal branding if in an org and use org branding

* fix: minor fix

* Update SettingsLayout.tsx

* Update SettingsLayout.tsx

* Update profile.tsx

* some fixes and e2e test

* fix: e2e test

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Udit Takkar <udit222001@gmail.com>
  • Loading branch information
3 people authored Jul 4, 2024
1 parent 785ab8b commit 7d06d9f
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 143 deletions.
2 changes: 1 addition & 1 deletion apps/web/playwright/settings/upload-avatar.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ test.describe("Organization Logo", async () => {

await page.getByTestId("upload-avatar").click();

await page.getByText("Update").click();
await page.getByTestId("update-org-profile-button").click();
await page.waitForSelector("text=Your organization updated successfully");

const response = await prisma.avatar.findUniqueOrThrow({
Expand Down
203 changes: 71 additions & 132 deletions packages/features/ee/organizations/pages/settings/appearance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,17 @@ import { useRouter } from "next/navigation";
import { useState, useEffect } from "react";
import { useForm } from "react-hook-form";

import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import BrandColorsForm from "@calcom/features/ee/components/BrandColorsForm";
import { AppearanceSkeletonLoader } from "@calcom/features/ee/components/CommonSkeletonLoaders";
import SectionBottomActions from "@calcom/features/settings/SectionBottomActions";
import ThemeLabel from "@calcom/features/settings/ThemeLabel";
import { getLayout } from "@calcom/features/settings/layouts/SettingsLayout";
import { DEFAULT_LIGHT_BRAND_COLOR, DEFAULT_DARK_BRAND_COLOR } from "@calcom/lib/constants";
import { APP_NAME } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { MembershipRole } from "@calcom/prisma/enums";
import { trpc } from "@calcom/trpc/react";
import type { RouterOutputs } from "@calcom/trpc/react";
import { Button, Form, Meta, showToast, SettingsToggle, Avatar, ImageUploader } from "@calcom/ui";
import { Icon } from "@calcom/ui";
import { Button, Form, showToast, SettingsToggle } from "@calcom/ui";

type BrandColorsFormValues = {
brandColor: string;
Expand All @@ -27,7 +24,6 @@ type BrandColorsFormValues = {

const OrgAppearanceView = ({
currentOrg,
isAdminOrOwner,
}: {
currentOrg: RouterOutputs["viewer"]["organizations"]["listCurrent"];
isAdminOrOwner: boolean;
Expand Down Expand Up @@ -79,134 +75,79 @@ const OrgAppearanceView = ({
};

return (
<LicenseRequired>
<Meta
title={t("appearance")}
description={t("appearance_org_description")}
borderInShellHeader={false}
/>
{isAdminOrOwner ? (
<div>
<div className="my-6">
<div className="flex items-center text-sm">
<Avatar
alt="calVideoLogo"
imageSrc={currentOrg?.calVideoLogo}
fallback={<Icon name="plus" className="text-subtle h-6 w-6" />}
size="lg"
/>
<div className="ms-4">
<div className="flex gap-2">
<ImageUploader
target="avatar"
id="cal-video-logo-upload"
buttonMsg={
currentOrg?.calVideoLogo ? t("update_cal_video_logo") : t("upload_cal_video_logo")
}
handleAvatarChange={(newLogo) => {
mutation.mutate({
calVideoLogo: newLogo,
});
}}
disabled={mutation.isPending}
imageSrc={currentOrg?.calVideoLogo ?? undefined}
uploadInstruction={t("cal_video_logo_upload_instruction")}
triggerButtonColor={currentOrg?.calVideoLogo ? "secondary" : "primary"}
/>
{currentOrg?.calVideoLogo && (
<Button
color="destructive"
disabled={mutation.isPending}
onClick={() => {
mutation.mutate({
calVideoLogo: null,
});
}}>
{t("remove")}
</Button>
)}
</div>
</div>
</div>
<div>
<Form
form={themeForm}
handleSubmit={(value) => {
mutation.mutate({
theme: value.theme ?? null,
});
}}>
<div className="border-subtle mt-6 flex items-center rounded-t-xl border p-6 text-sm">
<div>
<p className="text-default text-base font-semibold">{t("theme")}</p>
<p className="text-default">{t("theme_applies_note")}</p>
</div>
<Form
form={themeForm}
handleSubmit={(value) => {
mutation.mutate({
theme: value.theme ?? null,
});
}}>
<div className="border-subtle mt-6 flex items-center rounded-t-xl border p-6 text-sm">
<div>
<p className="text-default text-base font-semibold">{t("theme")}</p>
<p className="text-default">{t("theme_applies_note")}</p>
</div>
</div>
<div className="border-subtle flex flex-col justify-between border-x px-6 py-8 sm:flex-row">
<ThemeLabel
variant="system"
value={undefined}
label={t("theme_system")}
defaultChecked={currentOrg.theme === null}
register={themeForm.register}
/>
<ThemeLabel
variant="light"
value="light"
label={t("light")}
defaultChecked={currentOrg.theme === "light"}
register={themeForm.register}
/>
<ThemeLabel
variant="dark"
value="dark"
label={t("dark")}
defaultChecked={currentOrg.theme === "dark"}
register={themeForm.register}
/>
</div>
<SectionBottomActions className="mb-6" align="end">
<Button
disabled={isOrgThemeSubmitting || !isOrgThemeDirty}
type="submit"
data-testid="update-org-theme-btn"
color="primary">
{t("update")}
</Button>
</SectionBottomActions>
</Form>

<Form
form={brandColorsFormMethods}
handleSubmit={(values) => {
onBrandColorsFormSubmit(values);
}}>
<BrandColorsForm
onSubmit={onBrandColorsFormSubmit}
brandColor={currentOrg?.brandColor ?? DEFAULT_LIGHT_BRAND_COLOR}
darkBrandColor={currentOrg?.darkBrandColor ?? DEFAULT_DARK_BRAND_COLOR}
/>
</Form>

<SettingsToggle
toggleSwitchAtTheEnd={true}
title={t("disable_cal_branding", { appName: APP_NAME })}
disabled={mutation?.isPending}
description={t("removes_cal_branding", { appName: APP_NAME })}
checked={hideBrandingValue}
onCheckedChange={(checked) => {
setHideBrandingValue(checked);
mutation.mutate({ hideBranding: checked });
}}
switchContainerClassName="mt-6"
/>
</div>
) : (
<div className="py-5">
<span className="text-default text-sm">{t("only_owner_change")}</span>
<div className="border-subtle flex flex-col justify-between border-x px-6 py-8 sm:flex-row">
<ThemeLabel
variant="system"
value={undefined}
label={t("theme_system")}
defaultChecked={currentOrg.theme === null}
register={themeForm.register}
/>
<ThemeLabel
variant="light"
value="light"
label={t("light")}
defaultChecked={currentOrg.theme === "light"}
register={themeForm.register}
/>
<ThemeLabel
variant="dark"
value="dark"
label={t("dark")}
defaultChecked={currentOrg.theme === "dark"}
register={themeForm.register}
/>
</div>
)}
</LicenseRequired>
<SectionBottomActions className="mb-6" align="end">
<Button
disabled={isOrgThemeSubmitting || !isOrgThemeDirty}
type="submit"
data-testid="update-org-theme-btn"
color="primary">
{t("update")}
</Button>
</SectionBottomActions>
</Form>

<Form
form={brandColorsFormMethods}
handleSubmit={(values) => {
onBrandColorsFormSubmit(values);
}}>
<BrandColorsForm
onSubmit={onBrandColorsFormSubmit}
brandColor={currentOrg?.brandColor ?? DEFAULT_LIGHT_BRAND_COLOR}
darkBrandColor={currentOrg?.darkBrandColor ?? DEFAULT_DARK_BRAND_COLOR}
/>
</Form>

<SettingsToggle
toggleSwitchAtTheEnd={true}
title={t("disable_cal_branding", { appName: APP_NAME })}
disabled={mutation?.isPending}
description={t("removes_cal_branding", { appName: APP_NAME })}
checked={hideBrandingValue}
onCheckedChange={(checked) => {
setHideBrandingValue(checked);
mutation.mutate({ hideBranding: checked });
}}
switchContainerClassName="mt-6"
/>
</div>
);
};

Expand Down Expand Up @@ -237,6 +178,4 @@ const OrgAppearanceViewWrapper = () => {
return <OrgAppearanceView currentOrg={currentOrg} isAdminOrOwner={isAdminOrOwner} />;
};

OrgAppearanceViewWrapper.getLayout = getLayout;

export default OrgAppearanceViewWrapper;
57 changes: 55 additions & 2 deletions packages/features/ee/organizations/pages/settings/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import { z } from "zod";

import LicenseRequired from "@calcom/features/ee/common/components/LicenseRequired";
import { subdomainSuffix } from "@calcom/features/ee/organizations/lib/orgDomains";
import OrgAppearanceViewWrapper from "@calcom/features/ee/organizations/pages/settings/appearance";
import SectionBottomActions from "@calcom/features/settings/SectionBottomActions";
import { getPlaceholderAvatar } from "@calcom/lib/defaultAvatarImage";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { md } from "@calcom/lib/markdownIt";
import turndown from "@calcom/lib/turndownService";
import { MembershipRole } from "@calcom/prisma/enums";
import { trpc } from "@calcom/trpc/react";
import { Icon } from "@calcom/ui";
import {
Avatar,
BannerUploader,
Expand All @@ -41,6 +43,7 @@ const orgProfileFormSchema = z.object({
name: z.string(),
logoUrl: z.string().nullable(),
banner: z.string().nullable(),
calVideoLogo: z.string().nullable(),
bio: z.string(),
});

Expand All @@ -50,6 +53,7 @@ type FormValues = {
banner: string | null;
bio: string;
slug: string;
calVideoLogo: string | null;
};

const SkeletonLoader = ({ title, description }: { title: string; description: string }) => {
Expand Down Expand Up @@ -114,6 +118,7 @@ const OrgProfileView = () => {
logoUrl: currentOrganisation?.logoUrl,
banner: currentOrganisation?.bannerUrl || "",
bio: currentOrganisation?.bio || "",
calVideoLogo: currentOrganisation?.calVideoLogo || "",
slug:
currentOrganisation?.slug ||
((currentOrganisation?.metadata as Prisma.JsonObject)?.requestedSlug as string) ||
Expand All @@ -125,7 +130,10 @@ const OrgProfileView = () => {
<Meta title={t("profile")} description={t("profile_org_description")} borderInShellHeader={true} />
<>
{isOrgAdminOrOwner ? (
<OrgProfileForm defaultValues={defaultValues} />
<>
<OrgProfileForm defaultValues={defaultValues} />
<OrgAppearanceViewWrapper />
</>
) : (
<div className="border-subtle flex rounded-b-md border border-t-0 px-4 py-8 sm:px-6">
<div className="flex-grow">
Expand Down Expand Up @@ -182,6 +190,7 @@ const OrgProfileForm = ({ defaultValues }: { defaultValues: FormValues }) => {
bio: (res.data?.bio || "") as string,
slug: defaultValues["slug"],
banner: (res.data?.bannerUrl || "") as string,
calVideoLogo: (res.data?.calVideoLogo || "") as string,
});
await utils.viewer.teams.get.invalidate();
await utils.viewer.organizations.listCurrent.invalidate();
Expand All @@ -206,6 +215,7 @@ const OrgProfileForm = ({ defaultValues }: { defaultValues: FormValues }) => {
slug: values.slug,
bio: values.bio,
banner: values.banner,
calVideoLogo: values.calVideoLogo,
};

mutation.mutate(variables);
Expand Down Expand Up @@ -288,6 +298,44 @@ const OrgProfileForm = ({ defaultValues }: { defaultValues: FormValues }) => {
}}
/>
</div>
<div className="mt-2 flex items-center">
<Controller
control={form.control}
name="calVideoLogo"
render={({ field: { value, onChange } }) => {
const showRemoveLogoButton = !!value;
return (
<>
<Avatar
alt="calVideoLogo"
imageSrc={value}
fallback={<Icon name="plus" className="text-subtle h-6 w-6" />}
size="lg"
/>
<div className="ms-4">
<div className="flex gap-2">
<ImageUploader
target="avatar"
id="cal-video-logo-upload"
buttonMsg={t("upload_cal_video_logo")}
handleAvatarChange={onChange}
imageSrc={value || undefined}
uploadInstruction={t("cal_video_logo_upload_instruction")}
triggerButtonColor={showRemoveLogoButton ? "secondary" : "primary"}
testId="cal-video-logo"
/>
{showRemoveLogoButton && (
<Button color="secondary" onClick={() => onChange(null)}>
{t("remove")}
</Button>
)}
</div>
</div>
</>
);
}}
/>
</div>

<Controller
control={form.control}
Expand Down Expand Up @@ -334,7 +382,12 @@ const OrgProfileForm = ({ defaultValues }: { defaultValues: FormValues }) => {
<p className="text-default mt-2 text-sm">{t("org_description")}</p>
</div>
<SectionBottomActions align="end">
<Button color="primary" type="submit" loading={mutation.isPending} disabled={isDisabled}>
<Button
data-testid="update-org-profile-button"
color="primary"
type="submit"
loading={mutation.isPending}
disabled={isDisabled}>
{t("update")}
</Button>
</SectionBottomActions>
Expand Down
Loading

0 comments on commit 7d06d9f

Please sign in to comment.