Skip to content

Commit

Permalink
Add internationalization for newsletter preview and add salutation bl…
Browse files Browse the repository at this point in the history
…ock for testing (#73)

* Add internationalization for newsletter preview and add salutation block for testing

* Add changeset

* Adapt changeset - specify that previewUrl was removed
  • Loading branch information
raphaelblum authored Aug 26, 2024
1 parent 7e56895 commit e5dbbfa
Show file tree
Hide file tree
Showing 19 changed files with 108 additions and 29 deletions.
13 changes: 13 additions & 0 deletions .changeset/lemon-vans-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@comet/brevo-admin": major
---

Add `resolvePreviewUrlForScope` in `BrevoConfigProvider` to be able to provide internationalization for the preview. The previous `previewUrl` option has been removed and must be defined via the `resolvePreviewUrlForScope`.

**The project can then call different urls based on the scope like that:**

```typescript
resolvePreviewUrlForScope: (scope: ContentScope) => {
return `${config.campaignUrl}/preview/${scope.domain}/${scope.language}`;
},
```
9 changes: 8 additions & 1 deletion demo/admin/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,14 @@ export function App() {
<MuiThemeProvider theme={theme}>
<DndProvider backend={HTML5Backend}>
<SnackbarProvider>
<BrevoConfigProvider value={{ apiUrl: config.apiUrl }}>
<BrevoConfigProvider
value={{
apiUrl: config.apiUrl,
resolvePreviewUrlForScope: (scope: ContentScope) => {
return `${config.campaignUrl}/preview/${scope.domain}/${scope.language}`;
},
}}
>
<CmsBlockContextProvider
damConfig={{
apiUrl: config.apiUrl,
Expand Down
2 changes: 0 additions & 2 deletions demo/admin/src/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Domain } from "@comet/admin-icons";
import { createBrevoContactsPage, createEmailCampaignsPage, createTargetGroupsPage } from "@comet/brevo-admin";
import { ContentScopeIndicator, createRedirectsPage, DamPage, PagesPage, PublisherPage, SitePreview } from "@comet/cms-admin";
import { getBrevoContactConfig } from "@src/common/brevoModuleConfig/brevoContactsPageAttributesConfig";
import { config } from "@src/config";
import { pageTreeCategories, urlParamToCategory } from "@src/pageTree/pageTreeCategories";
import * as React from "react";
import { useIntl } from "react-intl";
Expand Down Expand Up @@ -48,7 +47,6 @@ export const Routes: React.FC = () => {
const EmailCampaignsPage = createEmailCampaignsPage({
scopeParts: ["domain", "language"],
EmailCampaignContentBlock: EmailCampaignContentBlock,
previewUrl: `${config.campaignUrl}/preview`,
});

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import { PixelImageBlock } from "@comet/cms-admin";
import { RichTextBlock } from "@src/common/blocks/RichTextBlock";

import { DividerBlock } from "./DividerBlock";
import { EmailCampaignSalutationBlock } from "./EmailCampaignSalutationBlock";

export const EmailCampaignContentBlock = createBlocksBlock({
name: "EmailCampaignContent",
supportedBlocks: {
divider: DividerBlock,
text: RichTextBlock,
salutation: EmailCampaignSalutationBlock,
image: PixelImageBlock,
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { BlockCategory, createCompositeBlock } from "@comet/blocks-admin";
import * as React from "react";
import { FormattedMessage } from "react-intl";

export const EmailCampaignSalutationBlock = createCompositeBlock({
name: "EmailCampaignSalutation",
displayName: <FormattedMessage id="emailCampaign.salutationBlock.displayName" defaultMessage="Salutation" />,
category: BlockCategory.TextAndContent,
blocks: {},
});
7 changes: 7 additions & 0 deletions demo/api/block-meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@
"blocks": {
"text": "RichText",
"divider": "EmailCampaignDivider",
"salutation": "EmailCampaignSalutation",
"image": "PixelImage"
},
"nullable": false
Expand Down Expand Up @@ -245,6 +246,7 @@
"blocks": {
"text": "RichText",
"divider": "EmailCampaignDivider",
"salutation": "EmailCampaignSalutation",
"image": "PixelImage"
},
"nullable": false
Expand Down Expand Up @@ -321,6 +323,11 @@
}
]
},
{
"name": "EmailCampaignSalutation",
"fields": [],
"inputFields": []
},
{
"name": "ExternalLink",
"fields": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import { PixelImageBlock } from "@comet/cms-api";

import { EmailCampaignDividerBlock } from "./email-campaign-divider.block";
import { EmailCampaignRichTextBlock } from "./email-campaign-rich-text.block";
import { EmailCampaignSalutationBlock } from "./email-campaign-salutation.block";

export const EmailCampaignContentBlock = createBlocksBlock(
{
supportedBlocks: {
text: EmailCampaignRichTextBlock,
divider: EmailCampaignDividerBlock,
salutation: EmailCampaignSalutationBlock,
image: PixelImageBlock,
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { BlockData, BlockInput, createBlock, inputToData } from "@comet/blocks-api";

class EmailCampaignSalutationBlockData extends BlockData {}

class EmailCampaignSalutationBlockInput extends BlockInput {
transformToBlockData(): EmailCampaignSalutationBlockData {
return inputToData(EmailCampaignSalutationBlockData, this);
}
}

export const EmailCampaignSalutationBlock = createBlock(
EmailCampaignSalutationBlockData,
EmailCampaignSalutationBlockInput,
"EmailCampaignSalutation",
);
1 change: 1 addition & 0 deletions demo/campaign/.prettierignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.next/
block-meta.json
lang-compiled/
lang-extracted/
lang/
preBuild/
2 changes: 1 addition & 1 deletion demo/campaign/intl-update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ cd "$(dirname "$0")" || exit
rm -rf ./lang/
mkdir -p ./lang

git clone https://github.com/vivid-planet/comet-starter-lang.git lang/comet-brevo-module-demo-lang
git clone https://github.com/vivid-planet/comet-brevo-module-lang.git lang/comet-brevo-module-demo-lang
1 change: 1 addition & 0 deletions demo/campaign/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"export": "next export",
"gql:types": "graphql-codegen",
"gql:watch": "graphql-codegen --watch",
"intl:extract": "formatjs extract \"src/**/*.ts*\" --ignore ./**.d.ts --out-file lang-extracted/en.json --format simple",
"lint": "run-p gql:types generate-block-types && run-p lint:prettier lint:eslint lint:tsc",
"lint:prettier": "npx prettier --check './**/*.{js,json,md,yml,yaml}'",
"lint:eslint": "eslint --max-warnings 0 --config ./.eslintrc.cli.js --ext .ts,.tsx,.js,.jsx,.json,.md src/ package.json",
Expand Down
2 changes: 2 additions & 0 deletions demo/campaign/src/blocks/ContentBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import { DividerBlock } from "@src/blocks/DividerBlock";
import React from "react";

import { ImageBlock } from "./ImageBlock";
import { SalutationBlock } from "./SalutationBlock";

const supportedBlocks: SupportedBlocks = {
divider: (data) => <DividerBlock />,
text: (data) => <RichTextBlock data={data} />,
salutation: (data) => <SalutationBlock data={data} />,
image: (data) => <ImageBlock data={data} />,
};

Expand Down
18 changes: 18 additions & 0 deletions demo/campaign/src/blocks/SalutationBlock.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { PropsWithData } from "@comet/cms-site";
import { MjmlColumn, MjmlText } from "@luma-team/mjml-react";
import { RichTextBlockData } from "@src/blocks.generated";
import { IndentedSectionGroup } from "@src/components/IndentedSectionGroup";
import * as React from "react";
import { FormattedMessage } from "react-intl";

export const SalutationBlock: React.FC<PropsWithData<RichTextBlockData>> = ({ data }) => {
return (
<IndentedSectionGroup>
<MjmlColumn>
<MjmlText>
<FormattedMessage id="salutationBlock.salutation" defaultMessage="Dear customer!" />
</MjmlText>
</MjmlColumn>
</IndentedSectionGroup>
);
};
4 changes: 2 additions & 2 deletions demo/campaign/src/lang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { IntlConfig } from "react-intl";

export function getMessages(language: string): Promise<IntlConfig["messages"]> {
if (language === "en") {
return require("../lang/comet-brevo-module-demo-lang/site/en.json");
return require("../lang/comet-brevo-module-demo-lang/campaign/en.json");
}
return require("../lang/comet-brevo-module-demo-lang/site/de.json");
return require("../lang/comet-brevo-module-demo-lang/campaign/de.json");
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,9 @@ const MailPreviewPage: React.FC<Props> = (props) => (

export default MailPreviewPage;

export async function getServerSideProps({ locale: localeFromContext }: GetServerSidePropsContext): Promise<{ props: Props } | undefined> {
const locale = localeFromContext ?? defaultLanguage;
export async function getServerSideProps({ params }: GetServerSidePropsContext): Promise<{ props: Props } | undefined> {
const locale = typeof params?.language === "string" ? params.language : defaultLanguage;
const [messages] = await Promise.all([getMessages(locale)]);

return {
props: {
intlProviderValues: {
Expand Down
16 changes: 14 additions & 2 deletions packages/admin/src/common/BrevoConfigProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { ContentScopeInterface, useContentScope } from "@comet/cms-admin";
import React from "react";

export interface BrevoConfig {
apiUrl: string;
resolvePreviewUrlForScope: (scope: ContentScopeInterface) => string;
}

const BrevoConfigContext = React.createContext<BrevoConfig | undefined>(undefined);
Expand All @@ -14,10 +16,20 @@ export const BrevoConfigProvider = ({ children, value }: React.PropsWithChildren
return <BrevoConfigContext.Provider value={value}>{children}</BrevoConfigContext.Provider>;
};

export const useBrevoConfig = (): BrevoConfig => {
interface UseBrevoConfigReturn {
apiUrl: string;
previewUrl: string;
}

export const useBrevoConfig = (): UseBrevoConfigReturn => {
const { scope } = useContentScope();

const context = React.useContext(BrevoConfigContext);
if (context === undefined) {
throw new Error("useBrevoConfig must be used within a BrevoConfigProvider");
}
return context;

const previewUrl = context.resolvePreviewUrlForScope(scope);

return { ...context, previewUrl };
};
18 changes: 4 additions & 14 deletions packages/admin/src/emailCampaigns/EmailCampaignsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ import { EmailCampaignView } from "./view/EmailCampaignView";
interface CreateEmailCampaignsPageOptions {
scopeParts: string[];
EmailCampaignContentBlock: BlockInterface;
previewUrl: string;
}

export function createEmailCampaignsPage({ scopeParts, EmailCampaignContentBlock, previewUrl }: CreateEmailCampaignsPageOptions) {
export function createEmailCampaignsPage({ scopeParts, EmailCampaignContentBlock }: CreateEmailCampaignsPageOptions) {
function EmailCampaignsPage(): JSX.Element {
const { scope: completeScope } = useContentScope();
const intl = useIntl();
Expand All @@ -33,29 +32,20 @@ export function createEmailCampaignsPage({ scopeParts, EmailCampaignContentBlock
</StackPage>
<StackPage name="statistics">{(selectedId) => <EmailCampaignStatistics id={selectedId} />}</StackPage>
<StackPage name="view">
{(selectedId) => (
<EmailCampaignView id={selectedId} previewUrl={previewUrl} EmailCampaignContentBlock={EmailCampaignContentBlock} />
)}
{(selectedId) => <EmailCampaignView id={selectedId} EmailCampaignContentBlock={EmailCampaignContentBlock} />}
</StackPage>

<StackPage
name="edit"
title={intl.formatMessage({ id: "cometBrevoModule.emailCampaigns.editEmailCampaign", defaultMessage: "Edit email campaign" })}
>
{(selectedId) => (
<EmailCampaignForm
previewUrl={previewUrl}
id={selectedId}
EmailCampaignContentBlock={EmailCampaignContentBlock}
scope={scope}
/>
)}
{(selectedId) => <EmailCampaignForm id={selectedId} EmailCampaignContentBlock={EmailCampaignContentBlock} scope={scope} />}
</StackPage>
<StackPage
name="add"
title={intl.formatMessage({ id: "cometBrevoModule.emailCampaigns.addEmailCampaign", defaultMessage: "Add email campaign" })}
>
<EmailCampaignForm previewUrl={previewUrl} EmailCampaignContentBlock={EmailCampaignContentBlock} scope={scope} />
<EmailCampaignForm EmailCampaignContentBlock={EmailCampaignContentBlock} scope={scope} />
</StackPage>
</StackSwitch>
</Stack>
Expand Down
5 changes: 3 additions & 2 deletions packages/admin/src/emailCampaigns/form/EmailCampaignForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import React, { useMemo } from "react";
import { FormattedMessage } from "react-intl";
import { useRouteMatch } from "react-router";

import { useBrevoConfig } from "../../common/BrevoConfigProvider";
import { GQLEmailCampaignInput } from "../../graphql.generated";
import { ConfigFields } from "./ConfigFields";
import { createEmailCampaignMutation, emailCampaignFormQuery, updateEmailCampaignMutation } from "./EmailCampaignForm.gql";
Expand All @@ -59,10 +60,9 @@ interface FormProps {
id?: string;
EmailCampaignContentBlock: BlockInterface;
scope: ContentScopeInterface;
previewUrl: string;
}

export function EmailCampaignForm({ id, EmailCampaignContentBlock, scope, previewUrl }: FormProps): React.ReactElement {
export function EmailCampaignForm({ id, EmailCampaignContentBlock, scope }: FormProps): React.ReactElement {
const rootBlocks = {
content: EmailCampaignContentBlock,
};
Expand All @@ -71,6 +71,7 @@ export function EmailCampaignForm({ id, EmailCampaignContentBlock, scope, previe
[key in keyof typeof rootBlocks]: BlockState<(typeof rootBlocks)[key]>;
};

const { previewUrl } = useBrevoConfig();
const stackApi = useStackApi();
const stackSwitchApi = useStackSwitchApi();
const client = useApolloClient();
Expand Down
5 changes: 3 additions & 2 deletions packages/admin/src/emailCampaigns/view/EmailCampaignView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,22 @@ import React from "react";
import { FormattedMessage } from "react-intl";
import { useRouteMatch } from "react-router";

import { useBrevoConfig } from "../../common/BrevoConfigProvider";
import { emailCampaignViewQuery } from "./EmailCampaignView.gql";
import { GQLEmailCampaignViewQuery, GQLEmailCampaignViewQueryVariables } from "./EmailCampaignView.gql.generated";

interface EmailCampaignViewProps {
id: string;
EmailCampaignContentBlock: BlockInterface;
previewUrl: string;
}

export function EmailCampaignView({ id, EmailCampaignContentBlock, previewUrl }: EmailCampaignViewProps): React.ReactElement {
export function EmailCampaignView({ id, EmailCampaignContentBlock }: EmailCampaignViewProps): React.ReactElement {
const stackApi = useStackApi();
const previewApi = useBlockPreview();
const blockContext = useCmsBlockContext();
const match = useRouteMatch();
const { scope } = useContentScope();
const { previewUrl } = useBrevoConfig();

const { data, error, loading } = useQuery<GQLEmailCampaignViewQuery, GQLEmailCampaignViewQueryVariables>(emailCampaignViewQuery, {
variables: { id },
Expand Down

0 comments on commit e5dbbfa

Please sign in to comment.