fix: add confirm and reject icon in email (#7457)

* fix: add confirm and reject icon in email

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

* fix: remove is_production

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

* wip

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

* style: calltoAction

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

* fix: brightness

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

* fix: styling of button

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>

---------

Signed-off-by: Udit Takkar <udit.07814802719@cse.mait.ac.in>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
This commit is contained in:
Udit Takkar 2023-03-12 23:09:46 +05:30 committed by GitHub
parent a22e4eed32
commit 71a3374930
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 119 additions and 51 deletions

View File

@ -60,7 +60,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
res.setHeader("Content-Type", "text/html");
res.setHeader("Cache-Control", "no-cache, no-store, private, must-revalidate");
res.write(
renderEmail("OrganizerScheduledEmail", {
renderEmail("OrganizerRequestEmail", {
calEvent: evt,
attendee: evt.organizer,
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke="white" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" />
</svg>

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

View File

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
<path stroke="white" stroke-linecap="round" stroke-linejoin="round" d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728A9 9 0 015.636 5.636m12.728 12.728L5.636 5.636" />
</svg>

After

Width:  |  Height:  |  Size: 309 B

View File

@ -1,33 +1,76 @@
import { LinkIcon } from "./LinkIcon";
import { CallToActionIcon } from "./CallToActionIcon";
export const CallToAction = (props: { label: string; href: string; secondary?: boolean }) => (
<p
style={{
display: "inline-block",
background: props.secondary ? "#FFFFFF" : "#292929",
border: props.secondary ? "1px solid #d1d5db" : "",
color: "#ffffff",
fontFamily: "Roboto, Helvetica, sans-serif",
fontSize: "14px",
fontWeight: 500,
lineHeight: "20px",
margin: 0,
textDecoration: "none",
textTransform: "none",
padding: "16px 24px",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
msoPaddingAlt: "0px",
borderRadius: "6px",
boxSizing: "border-box",
}}>
<a
style={{ color: props.secondary ? "#292929" : "#FFFFFF", textDecoration: "none" }}
href={props.href}
target="_blank"
rel="noreferrer">
{props.label}
<LinkIcon secondary={props.secondary} />
</a>
</p>
);
export const CallToAction = (props: {
label: string;
href: string;
secondary?: boolean;
startIconName?: string;
endIconName?: string;
}) => {
const { label, href, secondary, startIconName, endIconName } = props;
const calculatePadding = () => {
const paddingTop = "0.625rem";
const paddingBottom = "0.625rem";
let paddingLeft = "1rem";
let paddingRight = "1rem";
if (startIconName) {
paddingLeft = "0.875rem";
} else if (endIconName) {
paddingRight = "0.875rem";
}
return `${paddingTop} ${paddingRight} ${paddingBottom} ${paddingLeft}`;
};
return (
<p
style={{
display: "inline-block",
background: secondary ? "#FFFFFF" : "#292929",
border: secondary ? "1px solid #d1d5db" : "",
color: "#ffffff",
fontFamily: "Roboto, Helvetica, sans-serif",
fontSize: "0.875rem",
fontWeight: 500,
lineHeight: "1rem",
margin: 0,
textDecoration: "none",
textTransform: "none",
padding: calculatePadding(),
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
msoPaddingAlt: "0px",
borderRadius: "6px",
boxSizing: "border-box",
height: "2.25rem",
}}>
<a
style={{
color: secondary ? "#292929" : "#FFFFFF",
textDecoration: "none",
display: "flex",
alignItems: "center",
justifyContent: "center",
margin: "auto",
}}
href={href}
target="_blank"
rel="noreferrer">
{startIconName && (
<CallToActionIcon
style={{
marginRight: "0.5rem",
marginLeft: 0,
}}
iconName={startIconName}
secondary={secondary}
/>
)}
{label}
{endIconName && <CallToActionIcon iconName={endIconName} secondary={secondary} />}
</a>
</p>
);
};

View File

@ -0,0 +1,27 @@
import React from "react";
import { WEBAPP_URL } from "@calcom/lib/constants";
export const CallToActionIcon = ({
secondary,
iconName,
style,
}: {
secondary?: boolean;
iconName: string;
style?: React.CSSProperties;
}) => (
<img
src={`${WEBAPP_URL}/emails/${iconName}.png`}
srcSet={`${WEBAPP_URL}/emails/${iconName}.svg`}
width="1rem"
style={{
height: "1rem",
width: "1rem",
marginLeft: "0.5rem",
...(secondary && { filter: "brightness(50%)" }),
...style,
}}
alt=""
/>
);

View File

@ -1,11 +0,0 @@
import { BASE_URL, IS_PRODUCTION } from "@calcom/lib/constants";
export const LinkIcon = ({ secondary }: { secondary?: boolean }) => (
<img
src={IS_PRODUCTION ? BASE_URL + "/emails/linkIcon.png" : "https://app.cal.com/emails/linkIcon.png"}
srcSet={IS_PRODUCTION ? BASE_URL + "/emails/linkIcon.svg" : "https://app.cal.com/emails/linkIcon.svg"}
width="16px"
style={{ marginBottom: "-3px", marginLeft: "8px", ...(secondary && { filter: "brightness(80%)" }) }}
alt=""
/>
);

View File

@ -5,8 +5,8 @@ import { getVideoCallUrl } from "@calcom/lib/CalEventParser";
import logger from "@calcom/lib/logger";
import type { CalendarEvent } from "@calcom/types/Calendar";
import { CallToActionIcon } from "./CallToActionIcon";
import { Info } from "./Info";
import { LinkIcon } from "./LinkIcon";
export function LocationInfo(props: { calEvent: CalendarEvent; t: TFunction }) {
const { t } = props;
@ -40,7 +40,7 @@ export function LocationInfo(props: { calEvent: CalendarEvent; t: TFunction }) {
title={t("meeting_url")}
style={{ color: "#101010" }}
rel="noreferrer">
{providerName || "Link"} <LinkIcon />
{providerName || "Link"} <CallToActionIcon iconName="linkIcon" />
</a>
}
extraInfo={

View File

@ -4,7 +4,7 @@ export { CallToAction } from "./CallToAction";
export { CallToActionTable } from "./CallToActionTable";
export { UserFieldsResponses } from "./UserFieldsResponses";
export { Info } from "./Info";
export { LinkIcon } from "./LinkIcon";
export { CallToActionIcon } from "./CallToActionIcon";
export { LocationInfo } from "./LocationInfo";
export { ManageLink } from "./ManageLink";
export { default as RawHtml } from "./RawHtml";

View File

@ -8,7 +8,7 @@ function ManageLink(props: React.ComponentProps<typeof AttendeeScheduledEmail>)
return (
<CallToActionTable>
<CallToAction label={manageText} href={props.calEvent.paymentInfo.link} />
<CallToAction label={manageText} href={props.calEvent.paymentInfo.link} endIconName="linkIcon" />
</CallToActionTable>
);
}

View File

@ -17,7 +17,7 @@ export const AttendeeWasRequestedToRescheduleEmail = (
subject="rescheduled_event_type_subject"
callToAction={
<CallToActionTable>
<CallToAction label="Book a new time" href={props.metadata.rescheduleLink} />
<CallToAction label="Book a new time" href={props.metadata.rescheduleLink} endIconName="linkIcon" />
</CallToActionTable>
}
{...props}

View File

@ -1,7 +1,7 @@
import { WEBAPP_URL } from "@calcom/lib/constants";
import { symmetricEncrypt } from "@calcom/lib/crypto";
import { CallToAction, CallToActionTable, Separator } from "../components";
import { CallToAction, Separator, CallToActionTable } from "../components";
import { OrganizerScheduledEmail } from "./OrganizerScheduledEmail";
export const OrganizerRequestEmail = (props: React.ComponentProps<typeof OrganizerScheduledEmail>) => {
@ -21,13 +21,15 @@ export const OrganizerRequestEmail = (props: React.ComponentProps<typeof Organiz
callToAction={
<CallToActionTable>
<CallToAction
label={props.calEvent.organizer.language.translate("accept")}
label={props.calEvent.organizer.language.translate("confirm")}
href={`${actionHref}&action=accept`}
startIconName="confirmIcon"
/>
<Separator />
<CallToAction
label={props.calEvent.organizer.language.translate("reject")}
href={`${actionHref}&action=reject`}
startIconName="rejectIcon"
secondary
/>
</CallToActionTable>

View File

@ -55,6 +55,7 @@ export const TeamInviteEmail = (
<CallToAction
label={props.language(props.isCalcomMember ? "email_user_cta" : "email_no_user_cta")}
href={props.joinLink}
endIconName="linkIcon"
/>
</div>
<p