Files
Benny JooandDevin AI 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

92 lines
3.4 KiB
TypeScript

import { IS_SELF_HOSTED, WEBSITE_URL } from "@calcom/lib/constants";
import { trpc } from "@calcom/trpc/react";
import type { AppRouter } from "@calcom/trpc/types/server/routers/_app";
import useRouterQuery from "@lib/hooks/useRouterQuery";
import type { TRPCClientErrorLike } from "@trpc/client";
import dynamic from "next/dynamic";
import { useSearchParams } from "next/navigation";
import type { ReactNode, RefCallback } from "react";
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";
interface UsernameAvailabilityFieldProps {
onSuccessMutation?: () => void;
onErrorMutation?: (error: TRPCClientErrorLike<AppRouter>) => void;
disabled?: boolean;
}
interface ICustomUsernameProps extends UsernameAvailabilityFieldProps {
currentUsername: string | undefined;
setCurrentUsername?: (newUsername: string) => void;
inputUsernameValue: string | undefined;
usernameRef: RefCallback<HTMLInputElement>;
setInputUsernameValue: (value: string) => void;
disabled?: boolean | undefined;
addOnLeading?: ReactNode;
isPremium: boolean;
}
const PremiumTextfield = dynamic(() => import("./PremiumTextfield").then((m) => m.PremiumTextfield), {
ssr: false,
});
const UsernameTextfield = dynamic(() => import("./UsernameTextfield").then((m) => m.UsernameTextfield), {
ssr: false,
});
export const UsernameAvailability = (props: ICustomUsernameProps) => {
const { isPremium, disabled, ...otherProps } = props;
const UsernameAvailabilityComponent = isPremium ? PremiumTextfield : UsernameTextfield;
// PremiumTextfield uses `readonly` prop, UsernameTextfield uses `disabled` prop
const componentProps = isPremium ? { ...otherProps, readonly: disabled } : { ...otherProps, disabled };
return <UsernameAvailabilityComponent {...componentProps} />;
};
export const UsernameAvailabilityField = ({
onSuccessMutation,
onErrorMutation,
disabled,
}: UsernameAvailabilityFieldProps) => {
const searchParams = useSearchParams();
const [user] = trpc.viewer.me.get.useSuspenseQuery();
const [currentUsernameState, setCurrentUsernameState] = useState(user.username || "");
const { username: usernameFromQuery, setQuery: setUsernameFromQuery } = useRouterQuery("username");
const { username: currentUsername, setQuery: setCurrentUsername } =
searchParams?.get("username") && user.username === null
? { username: usernameFromQuery, setQuery: setUsernameFromQuery }
: { username: currentUsernameState || "", setQuery: setCurrentUsernameState };
const formMethods = useForm({
defaultValues: {
username: currentUsername,
},
});
const orgBranding = null;
const usernamePrefix = orgBranding
? "".replace(/^(https?:|)\/\//, "")
: `${WEBSITE_URL?.replace(/^(https?:|)\/\//, "")}`;
const isPremium = !IS_SELF_HOSTED && !user.organization?.id;
return (
<Controller
control={formMethods.control}
name="username"
render={({ field: { ref, onChange, value } }) => (
<UsernameAvailability
currentUsername={currentUsername}
setCurrentUsername={setCurrentUsername}
inputUsernameValue={value}
usernameRef={ref}
setInputUsernameValue={onChange}
onSuccessMutation={onSuccessMutation}
onErrorMutation={onErrorMutation}
disabled={disabled ?? !!user.organization?.id}
addOnLeading={`${usernamePrefix}/`}
isPremium={isPremium}
/>
)}
/>
);
};