Files
calendar/apps/web/modules/users/components/UserTable/EditSheet/EditUserSheet.tsx
T
Benny JooGitHubbenny@cal.com <sldisek783@gmail.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
ab21c7f805 refactor: Cal.diy (#28903)
* feat: Cal.diy — community-driven MIT-licensed fork of Cal.com

This squashed commit contains all Cal.diy changes applied on top of calcom/cal.com main:

- Rebrand Cal.com to Cal.diy across the entire codebase
- Remove Enterprise Edition (EE) features, license checks, and AGPL restrictions
- Switch license from AGPL-3.0 to MIT
- Remove docs/ directory (migrated to Nextra at cal.diy)
- Remove dead code: org tests, EE tips, platform nav, premium username, SAML/SSO, etc.
- Clean up .env.example for self-hosted Cal.diy
- Update Docker image references to calcom/cal.diy
- Update README, CONTRIBUTING.md, and issue templates for Cal.diy community fork
- Add PR welcome bot for Cal.diy contributors
- Fix API v2 breaking changes oasdiff ignore entries
- Replace Blacksmith CI runners with default GitHub Actions

3893 files changed, 20789 insertions(+), 411020 deletions(-)

Co-Authored-By: benny@cal.com <sldisek783@gmail.com>

* refactor: remove org-specific /organizations/:orgId endpoints from API v2 atoms controllers (#1701)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: revert Cal.diy Inc to Cal.com, Inc. in license files, copyright notices, and package metadata (#1702)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* rip out org related comments in api v2

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-04-15 09:52:36 -03:00

129 lines
4.9 KiB
TypeScript

import { WEBAPP_URL } from "@calcom/lib/constants";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { trpc } from "@calcom/trpc/react";
import { Avatar } from "@calcom/ui/components/avatar";
import { Sheet, SheetBody, SheetContent, SheetFooter, SheetHeader } from "@calcom/ui/components/sheet";
import { Loader } from "@calcom/ui/components/skeleton";
import type { Dispatch } from "react";
import { shallow } from "zustand/shallow";
import type { UserTableAction, UserTableState } from "../types";
import { DisplayInfo } from "./DisplayInfo";
import { EditForm } from "./EditUserForm";
import { OrganizationBanner } from "./OrganizationBanner";
import { SheetFooterControls } from "./SheetFooterControls";
import { useEditMode } from "./store";
function removeProtocol(url: string) {
return url.replace(/^(https?:\/\/)/, "");
}
export function EditUserSheet({
state,
dispatch,
canViewAttributes,
canEditAttributesForUser,
canChangeMemberRole,
}: {
state: UserTableState;
dispatch: Dispatch<UserTableAction>;
canViewAttributes?: boolean;
canEditAttributesForUser?: boolean;
canChangeMemberRole?: boolean;
}) {
const { t } = useLocale();
const { user: selectedUser } = state.editSheet;
const [editMode, setEditMode] = useEditMode((state) => [state.editMode, state.setEditMode], shallow);
const loadedUser = selectedUser as
| (typeof selectedUser & {
schedules?: { name: string }[];
teams?: { name: string; accepted: boolean }[];
bio?: string;
avatarUrl?: string | null;
role?: string;
timeZone?: string;
email?: string;
username?: string;
})
| undefined;
type TeamWithAccepted = { name: string; accepted: boolean };
const avatarURL = `${WEBAPP_URL}/${loadedUser?.username}/avatar.png`;
const schedulesNames = loadedUser?.schedules?.map((s) => s.name);
const teamNames = (loadedUser?.teams as TeamWithAccepted[] | undefined)?.map(
(t) => `${t.name} ${!t.accepted ? "(pending)" : ""}`
);
return (
<Sheet
open={true}
onOpenChange={() => {
setEditMode(false);
dispatch({ type: "CLOSE_MODAL" });
}}>
<SheetContent className="bg-default">
{loadedUser ? (
!editMode ? (
<>
<SheetHeader showCloseButton={false} className="w-full">
<div className="w-full rounded-xl border border-subtle bg-default p-4">
<OrganizationBanner />
<div className="ml-3 w-fit translate-y-[-50%] rounded-full bg-default p-1 ring-1 ring-[#0000000F]">
<Avatar asChild size="lg" alt={`${loadedUser?.name} avatar`} imageSrc={avatarURL} />
</div>
<h2 className="-mt-8 font-sans font-semibold text-2xl text-emphasis">
{loadedUser?.name || "Nameless User"}
</h2>
<p className="max-h-[3em] overflow-hidden text-ellipsis font-normal text-sm text-subtle">
{loadedUser?.bio || "This user does not have a bio..."}
</p>
</div>
</SheetHeader>
<SheetBody className="stack-y-4 flex flex-col p-4">
<div className="stack-y-4 mb-4 flex flex-col">
<h3 className="mb-1 font-semibold text-base text-emphasis">{t("profile")}</h3>
<DisplayInfo
label="Cal"
value={removeProtocol(`${WEBAPP_URL}/${loadedUser?.username}`)}
icon="external-link"
/>
<DisplayInfo label={t("email")} value={loadedUser?.email ?? ""} icon="at-sign" />
<DisplayInfo label={t("role")} value={[loadedUser?.role ?? ""]} icon="fingerprint" />
<DisplayInfo label={t("timezone")} value={loadedUser?.timeZone ?? ""} icon="clock" />
<DisplayInfo
label={t("teams")}
value={!teamNames || teamNames.length === 0 ? "" : teamNames}
icon="users"
coloredBadges
/>
<DisplayInfo
label={t("availability")}
value={!schedulesNames || schedulesNames.length === 0 ? "" : schedulesNames}
icon="calendar"
/>
</div>
</SheetBody>
<SheetFooter>
<SheetFooterControls
canEditAttributesForUser={canEditAttributesForUser}
canChangeMemberRole={canChangeMemberRole}
/>
</SheetFooter>
</>
) : (
<EditForm
selectedUser={loadedUser}
avatarUrl={loadedUser.avatarUrl ?? avatarURL}
domainUrl={WEBAPP_URL}
dispatch={dispatch}
/>
)
) : (
<Loader />
)}
</SheetContent>
</Sheet>
);
}