diff --git a/package.json b/package.json index 2c2be59..ff632f5 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "pete-nimara-mailer", + "name": "nimara-mailer", "version": "1.0.2", "type": "module", "author": { @@ -15,7 +15,7 @@ "scripts": { "dev": "concurrently -k -p \"[{name}]\" -n \"TSC,BUILD,RECEIVER,SENDER\" -c \"blue.bold,red.bold,cyan.bold,green.bold\" \"pnpm tsc:watch\" \"pnpm dev:build\" \"pnpm dev:run:events-receiver\" \"pnpm dev:run:emails-sender-proxy\"", "dev:build": "dotenv -v NODE_ENV=development -- node ./etc/scripts/dev.mjs", - "dev:emails": "dotenv -- email dev -d ./src/emails -p 3002", + "dev:emails": "dotenv -- email dev -d ./src/emails/templates -p 3002", "dev:run:events-receiver": "dotenv -v NODE_ENV=development -- nodemon --inspect=0.0.0.0:9229 --watch build/events-receiver.js build/events-receiver.js", "dev:run:emails-sender-proxy": "dotenv -v NODE_ENV=development -- nodemon --inspect=0.0.0.0:9230 --watch build/emails-sender-proxy.js build/emails-sender-proxy.js", "build": "dotenv -v NODE_ENV=production node ./etc/scripts/build.mjs", diff --git a/src/const.ts b/src/const.ts index 4036ee9..1c0782a 100644 --- a/src/const.ts +++ b/src/const.ts @@ -41,5 +41,6 @@ export const CUSTOM_EVENTS_SCHEMA = { custom_event: z.object({ name: z.string(), email: z.string(), + channel: z.string(), }), } satisfies Record; diff --git a/src/emails/templates/custom/CustomEventEmail.tsx b/src/emails/templates/custom/CustomEventEmail.tsx new file mode 100644 index 0000000..4752aad --- /dev/null +++ b/src/emails/templates/custom/CustomEventEmail.tsx @@ -0,0 +1,39 @@ +import { type z } from "zod"; + +import { type CUSTOM_EVENTS_SCHEMA } from "@/const"; +import Header from "@/emails/components/Header"; +import Layout from "@/emails/components/Layout"; +import Text from "@/emails/components/Text"; +import { type CustomEventData } from "@/lib/types"; + +type CustomEventEmailProps = CustomEventData< + z.infer<(typeof CUSTOM_EVENTS_SCHEMA)["custom_event"]> +>; + +const CustomEventEmail = ({ + data: { channel, email, name }, +}: CustomEventEmailProps) => { + return ( + + {() => ( + <> +
Hi {name}!
+ This is a custom email event sent by the Mirumee team. + + )} +
+ ); +}; + +const previewProps: CustomEventEmailProps = { + data: { + name: "Name", + email: "user@example.com", + channel: "channel-us", + }, +}; + +CustomEventEmail.PreviewProps = previewProps; +CustomEventEmail.Subject = "Custom event"; + +export default CustomEventEmail; diff --git a/src/emails/templates/AccountChangeEmailRequestedEmail.tsx b/src/emails/templates/saleor/AccountChangeEmailRequestedEmail.tsx similarity index 87% rename from src/emails/templates/AccountChangeEmailRequestedEmail.tsx rename to src/emails/templates/saleor/AccountChangeEmailRequestedEmail.tsx index 05ba403..7d44369 100644 --- a/src/emails/templates/AccountChangeEmailRequestedEmail.tsx +++ b/src/emails/templates/saleor/AccountChangeEmailRequestedEmail.tsx @@ -5,9 +5,12 @@ import Text from "@/emails/components/Text"; import { type AccountChangeEmailRequestedSubscription } from "@/graphql/operations/subscriptions/generated"; import { type EventData } from "@/lib/types"; +type AccountChangeEmailRequestedEmailProps = + EventData; + const AccountChangeEmailRequestedEmail = ({ data, -}: EventData) => { +}: AccountChangeEmailRequestedEmailProps) => { return ( = { +const previewProps: AccountChangeEmailRequestedEmailProps = { data: { redirectUrl: "https://example.com", user: { diff --git a/src/emails/templates/AccountConfirmationRequestedEmail.tsx b/src/emails/templates/saleor/AccountConfirmationRequestedEmail.tsx similarity index 86% rename from src/emails/templates/AccountConfirmationRequestedEmail.tsx rename to src/emails/templates/saleor/AccountConfirmationRequestedEmail.tsx index 206bfc7..58a0ebd 100644 --- a/src/emails/templates/AccountConfirmationRequestedEmail.tsx +++ b/src/emails/templates/saleor/AccountConfirmationRequestedEmail.tsx @@ -5,9 +5,12 @@ import Text from "@/emails/components/Text"; import { type AccountConfirmationRequestedSubscription } from "@/graphql/operations/subscriptions/generated"; import { type EventData } from "@/lib/types"; +type AccountConfirmationRequestedEmailProps = + EventData; + const AccountConfirmationRequestedEmail = ({ data, -}: EventData) => { +}: AccountConfirmationRequestedEmailProps) => { return ( = { +const previewProps: AccountConfirmationRequestedEmailProps = { data: { redirectUrl: "https://example.com", user: { diff --git a/src/emails/templates/AccountConfirmedEmail.tsx b/src/emails/templates/saleor/AccountConfirmedEmail.tsx similarity index 84% rename from src/emails/templates/AccountConfirmedEmail.tsx rename to src/emails/templates/saleor/AccountConfirmedEmail.tsx index 85a3527..f8a6f48 100644 --- a/src/emails/templates/AccountConfirmedEmail.tsx +++ b/src/emails/templates/saleor/AccountConfirmedEmail.tsx @@ -4,9 +4,9 @@ import Text from "@/emails/components/Text"; import { type AccountConfirmedSubscription } from "@/graphql/operations/subscriptions/generated"; import { type EventData } from "@/lib/types"; -const AccountConfirmedEmail = ({ - data, -}: EventData) => { +type AccountConfirmedEmailProps = EventData; + +const AccountConfirmedEmail = ({ data }: AccountConfirmedEmailProps) => { return ( {() => ( @@ -24,7 +24,7 @@ const AccountConfirmedEmail = ({ ); }; -const previewProps: EventData = { +const previewProps: AccountConfirmedEmailProps = { data: { user: { email: "user@example.com", diff --git a/src/emails/templates/AccountDeleteRequestedEmail.tsx b/src/emails/templates/saleor/AccountDeleteRequestedEmail.tsx similarity index 86% rename from src/emails/templates/AccountDeleteRequestedEmail.tsx rename to src/emails/templates/saleor/AccountDeleteRequestedEmail.tsx index 4bb1db9..693ecf1 100644 --- a/src/emails/templates/AccountDeleteRequestedEmail.tsx +++ b/src/emails/templates/saleor/AccountDeleteRequestedEmail.tsx @@ -5,9 +5,12 @@ import Text from "@/emails/components/Text"; import { type AccountDeleteRequestedSubscription } from "@/graphql/operations/subscriptions/generated"; import { type EventData } from "@/lib/types"; +type AccountDeleteRequestedEmailProps = + EventData; + const AccountDeleteRequestedEmail = ({ data, -}: EventData) => { +}: AccountDeleteRequestedEmailProps) => { return ( {() => ( @@ -29,7 +32,7 @@ const AccountDeleteRequestedEmail = ({ ); }; -const previewProps: EventData = { +const previewProps: AccountDeleteRequestedEmailProps = { data: { redirectUrl: "https://example.com", user: { diff --git a/src/emails/templates/AccountDeletedEmail.tsx b/src/emails/templates/saleor/AccountDeletedEmail.tsx similarity index 86% rename from src/emails/templates/AccountDeletedEmail.tsx rename to src/emails/templates/saleor/AccountDeletedEmail.tsx index 912ca95..5caddf8 100644 --- a/src/emails/templates/AccountDeletedEmail.tsx +++ b/src/emails/templates/saleor/AccountDeletedEmail.tsx @@ -4,9 +4,9 @@ import Text from "@/emails/components/Text"; import { type AccountDeletedSubscription } from "@/graphql/operations/subscriptions/generated"; import { type EventData } from "@/lib/types"; -const AccountDeletedEmail = ({ - data, -}: EventData) => { +type AccountDeletedEmailProps = EventData; + +const AccountDeletedEmail = ({ data }: AccountDeletedEmailProps) => { return ( {() => ( @@ -27,7 +27,7 @@ const AccountDeletedEmail = ({ ); }; -const previewProps: EventData = { +const previewProps: AccountDeletedEmailProps = { data: { user: { email: "user@example.com", diff --git a/src/emails/templates/AccountEmailChangedEmail.tsx b/src/emails/templates/saleor/AccountEmailChangedEmail.tsx similarity index 80% rename from src/emails/templates/AccountEmailChangedEmail.tsx rename to src/emails/templates/saleor/AccountEmailChangedEmail.tsx index 7d10e4d..b981b3e 100644 --- a/src/emails/templates/AccountEmailChangedEmail.tsx +++ b/src/emails/templates/saleor/AccountEmailChangedEmail.tsx @@ -4,9 +4,9 @@ import Text from "@/emails/components/Text"; import { type AccountEmailChangedSubscription } from "@/graphql/operations/subscriptions/generated"; import { type EventData } from "@/lib/types"; -const AccountEmailChangedEmail = ({ - data, -}: EventData) => { +type AccountEmailChangedEmailProps = EventData; + +const AccountEmailChangedEmail = ({ data }: AccountEmailChangedEmailProps) => { return ( {() => ( @@ -19,7 +19,7 @@ const AccountEmailChangedEmail = ({ ); }; -const previewProps: EventData = { +const previewProps: AccountEmailChangedEmailProps = { data: { user: { email: "user@example.com", diff --git a/src/emails/templates/AccountSetPasswordRequestedEmail.tsx b/src/emails/templates/saleor/AccountSetPasswordRequestedEmail.tsx similarity index 83% rename from src/emails/templates/AccountSetPasswordRequestedEmail.tsx rename to src/emails/templates/saleor/AccountSetPasswordRequestedEmail.tsx index ced2028..6b407cb 100644 --- a/src/emails/templates/AccountSetPasswordRequestedEmail.tsx +++ b/src/emails/templates/saleor/AccountSetPasswordRequestedEmail.tsx @@ -1,14 +1,16 @@ +import Header from "@/emails/components/Header"; import Layout from "@/emails/components/Layout"; import Link from "@/emails/components/Link"; import Text from "@/emails/components/Text"; import { type AccountSetPasswordRequestedSubscription } from "@/graphql/operations/subscriptions/generated"; import { type EventData } from "@/lib/types"; -import Header from "../components/Header"; +type AccountSetPasswordRequestedEmailProps = + EventData; const AccountSetPasswordRequestedEmail = ({ data, -}: EventData) => { +}: AccountSetPasswordRequestedEmailProps) => { return ( = { +const previewProps: AccountSetPasswordRequestedEmailProps = { data: { redirectUrl: "https://example.com", user: { diff --git a/src/emails/templates/FulfillmentCreatedEmail.tsx b/src/emails/templates/saleor/FulfillmentCreatedEmail.tsx similarity index 94% rename from src/emails/templates/FulfillmentCreatedEmail.tsx rename to src/emails/templates/saleor/FulfillmentCreatedEmail.tsx index e3957d2..00105ee 100644 --- a/src/emails/templates/FulfillmentCreatedEmail.tsx +++ b/src/emails/templates/saleor/FulfillmentCreatedEmail.tsx @@ -10,9 +10,9 @@ import { type FulfillmentCreatedSubscription } from "@/graphql/operations/subscr import { orderLineToLine } from "@/lib/saleor/utils"; import { type EventData } from "@/lib/types"; -const FulfillmentCreatedEmail = ({ - data, -}: EventData) => { +type FulfillmentCreatedEmailProps = EventData; + +const FulfillmentCreatedEmail = ({ data }: FulfillmentCreatedEmailProps) => { const order = data!.order!; return ( @@ -67,7 +67,7 @@ const FulfillmentCreatedEmail = ({ ); }; -const previewProps: EventData = { +const previewProps: FulfillmentCreatedEmailProps = { data: { order: { number: "941", diff --git a/src/emails/templates/FulfillmentTrackingNumberUpdatedEmail.tsx b/src/emails/templates/saleor/FulfillmentTrackingNumberUpdatedEmail.tsx similarity index 95% rename from src/emails/templates/FulfillmentTrackingNumberUpdatedEmail.tsx rename to src/emails/templates/saleor/FulfillmentTrackingNumberUpdatedEmail.tsx index fb6ca7a..403eedf 100644 --- a/src/emails/templates/FulfillmentTrackingNumberUpdatedEmail.tsx +++ b/src/emails/templates/saleor/FulfillmentTrackingNumberUpdatedEmail.tsx @@ -12,9 +12,12 @@ import { orderLineToLine } from "@/lib/saleor/utils"; import { type EventData } from "@/lib/types"; import { isURL } from "@/lib/utils"; +type FulfillmentTrackingNumberUpdatedEmailProps = + EventData; + const FulfillmentTrackingNumberUpdatedEmail = ({ data, -}: EventData) => { +}: FulfillmentTrackingNumberUpdatedEmailProps) => { const order = data!.order!; return ( @@ -81,7 +84,7 @@ const FulfillmentTrackingNumberUpdatedEmail = ({ ); }; -const previewProps: EventData = { +const previewProps: FulfillmentTrackingNumberUpdatedEmailProps = { data: { order: { number: "941", diff --git a/src/emails/templates/GiftCardSentEmail.tsx b/src/emails/templates/saleor/GiftCardSentEmail.tsx similarity index 88% rename from src/emails/templates/GiftCardSentEmail.tsx rename to src/emails/templates/saleor/GiftCardSentEmail.tsx index 807a76a..aaa52c1 100644 --- a/src/emails/templates/GiftCardSentEmail.tsx +++ b/src/emails/templates/saleor/GiftCardSentEmail.tsx @@ -7,7 +7,9 @@ import Text from "@/emails/components/Text"; import { type GiftCardSentSubscription } from "@/graphql/operations/subscriptions/generated"; import { type EventData } from "@/lib/types"; -const GiftCardSentEmail = ({ data }: EventData) => { +type GiftCardSentEmailProps = EventData; + +const GiftCardSentEmail = ({ data }: GiftCardSentEmailProps) => { return ( {() => ( @@ -28,7 +30,7 @@ const GiftCardSentEmail = ({ data }: EventData) => { ); }; -const previewProps: EventData = { +const previewProps: GiftCardSentEmailProps = { data: { sentToEmail: "user@example.com", channel: "channel-us", diff --git a/src/emails/templates/OrderCancelledEmail.tsx b/src/emails/templates/saleor/OrderCancelledEmail.tsx similarity index 85% rename from src/emails/templates/OrderCancelledEmail.tsx rename to src/emails/templates/saleor/OrderCancelledEmail.tsx index c2ee5a4..338a63f 100644 --- a/src/emails/templates/OrderCancelledEmail.tsx +++ b/src/emails/templates/saleor/OrderCancelledEmail.tsx @@ -4,9 +4,9 @@ import Text from "@/emails/components/Text"; import { type OrderCancelledSubscription } from "@/graphql/operations/subscriptions/generated"; import { type EventData } from "@/lib/types"; -const OrderCancelledEmail = ({ - data, -}: EventData) => { +type OrderCancelledEmailProps = EventData; + +const OrderCancelledEmail = ({ data }: OrderCancelledEmailProps) => { const order = data!.order!; return ( @@ -28,7 +28,7 @@ const OrderCancelledEmail = ({ ); }; -const previewProps: EventData = { +const previewProps: OrderCancelledEmailProps = { data: { order: { channel: { diff --git a/src/emails/templates/OrderCreatedEmail.tsx b/src/emails/templates/saleor/OrderCreatedEmail.tsx similarity index 95% rename from src/emails/templates/OrderCreatedEmail.tsx rename to src/emails/templates/saleor/OrderCreatedEmail.tsx index 1b5a963..ab7a672 100644 --- a/src/emails/templates/OrderCreatedEmail.tsx +++ b/src/emails/templates/saleor/OrderCreatedEmail.tsx @@ -8,7 +8,9 @@ import { type OrderCreatedSubscription } from "@/graphql/operations/subscription import { orderLineToLine } from "@/lib/saleor/utils"; import { type EventData } from "@/lib/types"; -const OrderCreatedEmail = ({ data }: EventData) => { +type OrderCreatedEmailProps = EventData; + +const OrderCreatedEmail = ({ data }: OrderCreatedEmailProps) => { const order = data.order!; return ( @@ -62,7 +64,7 @@ const OrderCreatedEmail = ({ data }: EventData) => { ); }; -const previewProps: EventData = { +const previewProps: OrderCreatedEmailProps = { data: { order: { number: "939", diff --git a/src/emails/templates/OrderRefundedEmail.tsx b/src/emails/templates/saleor/OrderRefundedEmail.tsx similarity index 95% rename from src/emails/templates/OrderRefundedEmail.tsx rename to src/emails/templates/saleor/OrderRefundedEmail.tsx index 9becdc5..fe03298 100644 --- a/src/emails/templates/OrderRefundedEmail.tsx +++ b/src/emails/templates/saleor/OrderRefundedEmail.tsx @@ -8,7 +8,9 @@ import { type OrderRefundedSubscription } from "@/graphql/operations/subscriptio import { orderLineToLine } from "@/lib/saleor/utils"; import { type EventData } from "@/lib/types"; -const OrderRefundedEmail = ({ data }: EventData) => { +type OrderRefundedEmailProps = EventData; + +const OrderRefundedEmail = ({ data }: OrderRefundedEmailProps) => { const order = data!.order!; return ( @@ -60,7 +62,7 @@ const OrderRefundedEmail = ({ data }: EventData) => { ); }; -const previewProps: EventData = { +const previewProps: OrderRefundedEmailProps = { data: { order: { number: "939", diff --git a/src/lib/emails/const.ts b/src/lib/emails/const.ts index 7a10f81..3039a3f 100644 --- a/src/lib/emails/const.ts +++ b/src/lib/emails/const.ts @@ -1,19 +1,20 @@ import { type ComponentType } from "react"; -import AccountChangeEmailRequestedEmail from "@/emails/templates/AccountChangeEmailRequestedEmail"; -import AccountConfirmationRequestedEmail from "@/emails/templates/AccountConfirmationRequestedEmail"; -import AccountConfirmedEmail from "@/emails/templates/AccountConfirmedEmail"; -import AccountDeletedEmail from "@/emails/templates/AccountDeletedEmail"; -import AccountDeleteRequestedEmail from "@/emails/templates/AccountDeleteRequestedEmail"; -import AccountEmailChangedEmail from "@/emails/templates/AccountEmailChangedEmail"; -import AccountSetPasswordRequestedEmail from "@/emails/templates/AccountSetPasswordRequestedEmail"; -import FulfillmentCreatedEmail from "@/emails/templates/FulfillmentCreatedEmail"; -import FulfillmentTrackingNumberUpdatedEmail from "@/emails/templates/FulfillmentTrackingNumberUpdatedEmail"; -import GiftCardSentEmail from "@/emails/templates/GiftCardSentEmail"; -import OrderCancelledEmail from "@/emails/templates/OrderCancelledEmail"; -import OrderCreatedEmail from "@/emails/templates/OrderCreatedEmail"; -import OrderRefundedEmail from "@/emails/templates/OrderRefundedEmail"; -import { type Event } from "@/lib/payload"; +import { type EmailEventType } from "@/const"; +import CustomEventEmail from "@/emails/templates/custom/CustomEventEmail"; +import AccountChangeEmailRequestedEmail from "@/emails/templates/saleor/AccountChangeEmailRequestedEmail"; +import AccountConfirmationRequestedEmail from "@/emails/templates/saleor/AccountConfirmationRequestedEmail"; +import AccountConfirmedEmail from "@/emails/templates/saleor/AccountConfirmedEmail"; +import AccountDeletedEmail from "@/emails/templates/saleor/AccountDeletedEmail"; +import AccountDeleteRequestedEmail from "@/emails/templates/saleor/AccountDeleteRequestedEmail"; +import AccountEmailChangedEmail from "@/emails/templates/saleor/AccountEmailChangedEmail"; +import AccountSetPasswordRequestedEmail from "@/emails/templates/saleor/AccountSetPasswordRequestedEmail"; +import FulfillmentCreatedEmail from "@/emails/templates/saleor/FulfillmentCreatedEmail"; +import FulfillmentTrackingNumberUpdatedEmail from "@/emails/templates/saleor/FulfillmentTrackingNumberUpdatedEmail"; +import GiftCardSentEmail from "@/emails/templates/saleor/GiftCardSentEmail"; +import OrderCancelledEmail from "@/emails/templates/saleor/OrderCancelledEmail"; +import OrderCreatedEmail from "@/emails/templates/saleor/OrderCreatedEmail"; +import OrderRefundedEmail from "@/emails/templates/saleor/OrderRefundedEmail"; const extractEmailFromOrder = (data: { order: { userEmail: string } }) => data.order.userEmail; @@ -24,8 +25,10 @@ const extractEmailFromGiftCard = (data: { sentToEmail: string }) => const extractEmailFromUser = (data: { user: { email: string } }) => data.user.email; +const extractEmailFromCustomEvent = (data: { email: string }) => data.email; + export const TEMPLATES_MAP: { - [key in Event]?: { + [key in EmailEventType]?: { extractFn: (data: any) => string; template: ComponentType & { Subject: string }; }; @@ -82,4 +85,8 @@ export const TEMPLATES_MAP: { template: AccountChangeEmailRequestedEmail, extractFn: extractEmailFromUser, }, + custom_event: { + template: CustomEventEmail, + extractFn: extractEmailFromCustomEvent, + }, }; diff --git a/src/lib/types.ts b/src/lib/types.ts index 3a3eda1..1a6ebfd 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -12,4 +12,8 @@ export type EventData = { data: NonNullable; }; +export type CustomEventData = { + data: NonNullable; +}; + export type PartialBy = Pick, K> & Omit;