* 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>
129 lines
4.9 KiB
TypeScript
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>
|
|
);
|
|
}
|