* Implement secondary email * Fix already existing tests failing * Added tests for secondary email feature * Skip email verification if user is changing the primary email to a verified secondary email * Fix type errors in tests * Fix email becoming unverified when switched between primary and secondary email * Added a check to prevent prisma error from throwing up due to duplicate records * Improved error handling when adding a secondary email * Add test for resend verification email flow for secondary emails and validation of invite link * Add a new column to link secondary emails with verification tokens * Fix failing to update email to an unverified secondary email of the same user * Fix failing tests * Change text of resend verification email * Add ability to use the verified secondary emails to get the event details to * Fix type errors * Fix failing e2e tests * Fix failing unit tests * Fix failing type checks * Fix secondary verification email subject * Fix failing e2e tests --------- Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com>
128 lines
4.0 KiB
TypeScript
128 lines
4.0 KiB
TypeScript
import type { FormValues } from "@pages/settings/my-account/profile";
|
|
import { useState } from "react";
|
|
import type { UseFormReturn } from "react-hook-form";
|
|
|
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|
import {
|
|
Badge,
|
|
TextField,
|
|
Dropdown,
|
|
DropdownItem,
|
|
DropdownMenuContent,
|
|
DropdownMenuItem,
|
|
DropdownMenuTrigger,
|
|
Button,
|
|
InputError,
|
|
} from "@calcom/ui";
|
|
import { MoreHorizontal, Flag, Trash, Send } from "@calcom/ui/components/icon";
|
|
|
|
type CustomEmailTextFieldProps = {
|
|
formMethods: UseFormReturn<FormValues>;
|
|
formMethodFieldName: keyof FormValues;
|
|
errorMessage: string;
|
|
emailVerified: boolean;
|
|
emailPrimary: boolean;
|
|
dataTestId: string;
|
|
handleChangePrimary: () => void;
|
|
handleVerifyEmail: () => void;
|
|
handleItemDelete: () => void;
|
|
};
|
|
|
|
const CustomEmailTextField = ({
|
|
formMethods,
|
|
formMethodFieldName,
|
|
errorMessage,
|
|
emailVerified,
|
|
emailPrimary,
|
|
dataTestId,
|
|
handleChangePrimary,
|
|
handleVerifyEmail,
|
|
handleItemDelete,
|
|
}: CustomEmailTextFieldProps) => {
|
|
const { t } = useLocale();
|
|
const [inputFocus, setInputFocus] = useState(false);
|
|
|
|
return (
|
|
<>
|
|
<div
|
|
className={`border-default mt-2 flex items-center rounded-md border ${
|
|
inputFocus ? "ring-brand-default border-neutral-300 ring-2" : ""
|
|
}`}>
|
|
<TextField
|
|
{...formMethods.register(formMethodFieldName)}
|
|
label=""
|
|
containerClassName="flex flex-1 items-center"
|
|
className="mb-0 border-none outline-none focus:ring-0"
|
|
data-testid={dataTestId}
|
|
onFocus={() => setInputFocus(true)}
|
|
onBlur={() => setInputFocus(false)}
|
|
/>
|
|
<div className="flex items-center pr-2">
|
|
{emailPrimary && (
|
|
<Badge variant="blue" size="sm" data-testid={`${dataTestId}-primary-badge`}>
|
|
{t("primary")}
|
|
</Badge>
|
|
)}
|
|
{!emailVerified && (
|
|
<Badge variant="orange" size="sm" className="ml-2" data-testid={`${dataTestId}-unverified-badge`}>
|
|
{t("unverified")}
|
|
</Badge>
|
|
)}
|
|
<Dropdown>
|
|
<DropdownMenuTrigger asChild>
|
|
<Button
|
|
StartIcon={MoreHorizontal}
|
|
variant="icon"
|
|
size="sm"
|
|
color="secondary"
|
|
className="ml-2 rounded-md"
|
|
data-testid="secondary-email-action-group-button"
|
|
/>
|
|
</DropdownMenuTrigger>
|
|
<DropdownMenuContent>
|
|
<DropdownMenuItem>
|
|
<DropdownItem
|
|
StartIcon={Flag}
|
|
color="secondary"
|
|
className="disabled:opacity-40"
|
|
onClick={handleChangePrimary}
|
|
disabled={!emailVerified || emailPrimary}
|
|
data-testid="secondary-email-make-primary-button">
|
|
{t("make_primary")}
|
|
</DropdownItem>
|
|
</DropdownMenuItem>
|
|
{!emailVerified && (
|
|
<DropdownMenuItem>
|
|
<DropdownItem
|
|
StartIcon={Send}
|
|
color="secondary"
|
|
className="disabled:opacity-40"
|
|
onClick={handleVerifyEmail}
|
|
disabled={emailVerified}
|
|
data-testid="resend-verify-email-button">
|
|
{t("resend_email")}
|
|
</DropdownItem>
|
|
</DropdownMenuItem>
|
|
)}
|
|
<DropdownMenuItem>
|
|
<DropdownItem
|
|
StartIcon={Trash}
|
|
color="destructive"
|
|
className="disabled:opacity-40"
|
|
onClick={handleItemDelete}
|
|
disabled={emailPrimary}
|
|
data-testid="secondary-email-delete-button">
|
|
{t("delete")}
|
|
</DropdownItem>
|
|
</DropdownMenuItem>
|
|
</DropdownMenuContent>
|
|
</Dropdown>
|
|
</div>
|
|
</div>
|
|
{errorMessage && <InputError message={errorMessage} />}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default CustomEmailTextField;
|