Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nv 2995 reusable email preview component #5143

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
cc949fe
feat: email preview
BiswaViraj Feb 1, 2024
62164cc
feat: add custom locale support
BiswaViraj Feb 1, 2024
66ba987
feat: add locale selection state
BiswaViraj Feb 1, 2024
2dafcc2
feat: remove log
BiswaViraj Feb 1, 2024
f58e970
feat: added locale dropdown
BiswaViraj Feb 3, 2024
c3cb3b0
refactor: file structure
BiswaViraj Feb 3, 2024
19ca87e
feat: email preview
BiswaViraj Feb 1, 2024
be3ac43
feat: added locale dropdown
BiswaViraj Feb 3, 2024
097ea7d
feat: implemented chat preview foundation
BiswaViraj Feb 3, 2024
e4cc4bc
feat: update locale select
BiswaViraj Feb 3, 2024
d26128d
feat: error
BiswaViraj Feb 3, 2024
81e6e6b
fix: error
BiswaViraj Feb 3, 2024
6d3c122
feat: overlay
BiswaViraj Feb 3, 2024
c9ca994
feat: chat preview
ainouzgali Feb 4, 2024
5ce224b
fix: tests
BiswaViraj Feb 5, 2024
5f93f0f
Merge pull request #5157 from novuhq/nv-2997-reusable-chat-preview-co…
BiswaViraj Feb 6, 2024
228d579
feat: click on overlay
BiswaViraj Feb 6, 2024
391d323
feat: apply suggestions
BiswaViraj Feb 6, 2024
321d62f
fix: pass locale
BiswaViraj Feb 6, 2024
9f8d83e
fix: text row
BiswaViraj Feb 6, 2024
45cbd76
feat: reusable header skeleton
BiswaViraj Feb 6, 2024
4c751eb
feat: reusable skeleton for email
BiswaViraj Feb 6, 2024
7e87e0e
Merge branch 'translation-management-beta' into nv-2995-reusable-emai…
LetItRock Feb 7, 2024
bd9d984
fix: removed duplicate file
BiswaViraj Feb 7, 2024
a8f4db0
feat: pr suggestions
BiswaViraj Feb 7, 2024
9f7f2b1
fix: overlapping input
BiswaViraj Feb 7, 2024
3c9483d
Merge branch 'nv-2995-reusable-email-preview-component' of https://gi…
BiswaViraj Feb 7, 2024
593af6a
Merge branch 'translation-management-beta' into nv-2995-reusable-emai…
LetItRock Feb 7, 2024
8da6a70
feat: test
BiswaViraj Feb 8, 2024
2ee0ed5
chore: remove unnecessary files
LetItRock Feb 9, 2024
0f52753
Merge branch 'translation-management-beta' into nv-2995-reusable-emai…
LetItRock Feb 9, 2024
9ae98ee
chore: update the source file
LetItRock Feb 9, 2024
cd9f145
fix: test
BiswaViraj Feb 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .source
24 changes: 19 additions & 5 deletions apps/api/src/app/content-templates/content-templates.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export class ContentTemplatesController {
@Body('contentType') contentType: MessageTemplateContentType,
@Body('payload') payload: any,
@Body('subject') subject: string,
@Body('layoutId') layoutId: string
@Body('layoutId') layoutId: string,
@Body('locale') locale?: string
) {
return this.compileEmailTemplateUsecase.execute(
CompileEmailTemplateCommand.create({
Expand All @@ -46,6 +47,7 @@ export class ContentTemplatesController {
payload,
subject,
layoutId,
locale,
}),
this.initiateTranslations.bind(this)
);
Expand All @@ -56,7 +58,8 @@ export class ContentTemplatesController {
@UserSession() user: IJwtPayload,
@Body('content') content: string,
@Body('payload') payload: any,
@Body('cta') cta: IMessageCTA
@Body('cta') cta: IMessageCTA,
@Body('locale') locale?: string
) {
return this.compileInAppTemplate.execute(
CompileInAppTemplateCommand.create({
Expand All @@ -66,20 +69,27 @@ export class ContentTemplatesController {
content,
payload,
cta,
locale,
}),
this.initiateTranslations.bind(this)
);
}
// TODO: refactor this to use params and single endpoint to manage all the channels
@Post('/preview/sms')
public previewSms(@UserSession() user: IJwtPayload, @Body('content') content: string, @Body('payload') payload: any) {
public previewSms(
@UserSession() user: IJwtPayload,
@Body('content') content: string,
@Body('payload') payload: any,
@Body('locale') locale?: string
) {
return this.compileStepTemplate.execute(
CompileStepTemplateCommand.create({
userId: user._id,
organizationId: user.organizationId,
environmentId: user.environmentId,
content,
payload,
locale,
}),
this.initiateTranslations.bind(this)
);
Expand All @@ -89,7 +99,8 @@ export class ContentTemplatesController {
public previewChat(
@UserSession() user: IJwtPayload,
@Body('content') content: string,
@Body('payload') payload: any
@Body('payload') payload: any,
@Body('locale') locale?: string
) {
return this.compileStepTemplate.execute(
CompileStepTemplateCommand.create({
Expand All @@ -98,6 +109,7 @@ export class ContentTemplatesController {
environmentId: user.environmentId,
content,
payload,
locale,
}),
this.initiateTranslations.bind(this)
);
Expand All @@ -107,7 +119,8 @@ export class ContentTemplatesController {
public previewPush(
@UserSession() user: IJwtPayload,
@Body('content') content: string,
@Body('payload') payload: any
@Body('payload') payload: any,
@Body('locale') locale?: string
) {
return this.compileStepTemplate.execute(
CompileStepTemplateCommand.create({
Expand All @@ -116,6 +129,7 @@ export class ContentTemplatesController {
environmentId: user.environmentId,
content,
payload,
locale,
}),
this.initiateTranslations.bind(this)
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { UserSession } from '@novu/testing';
import { expect } from 'chai';

const createTranslationGroup = {
name: 'test',
identifier: 'test',
locales: ['hi_IN', 'en_US'],
};

const content = 'Hello {{i18n "test.key1"}}, {{i18n "test.key2"}}, {{i18n "test.key3"}}';

describe('Get locales from content - /translations/groups/:identifier/locales/:locale (PATCH)', async () => {
let session: UserSession;

before(async () => {
session = new UserSession();
await session.initialize();
await session.testAgent.put(`/v1/organizations/language`).send({
locale: createTranslationGroup.locales[0],
});

await session.testAgent.post('/v1/translations/groups').send(createTranslationGroup);
});

it('should get locales from the content', async () => {
const { body } = await session.testAgent.post('/v1/translations/groups/preview/locales').send({
content,
});

const locales = body.data;

expect(locales.length).to.equal(2);
expect(locales[0].langIso).to.equal(createTranslationGroup.locales[0]);
expect(locales[1].langIso).to.equal(createTranslationGroup.locales[1]);
});
});
4 changes: 2 additions & 2 deletions apps/web/cypress/tests/tenants-page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('Tenants Page', function () {
cy.getByTestId('tenants-list-table')
.find('tr')
.eq(1)
.click()
.click({ force: true })
.then(() => {
cy.getByTestId('tenant-name').clear().type('New Name');
cy.getByTestId('update-tenant-sidebar-submit').click();
Expand All @@ -40,7 +40,7 @@ describe('Tenants Page', function () {
cy.getByTestId('tenants-list-table')
.find('tr')
.eq(1)
.click()
.click({ force: true })
.then(() => {
cy.getByTestId('tenant-identifier').clear().type('new-identifier');
cy.getByTestId('update-tenant-sidebar-submit').click();
Expand Down
30 changes: 27 additions & 3 deletions apps/web/src/api/content-templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,40 @@ export async function previewEmail({
payload,
subject,
layoutId,
locale,
}: {
content?: string | IEmailBlock[];
contentType?: MessageTemplateContentType;
payload: string;
subject?: string;
layoutId?: string;
locale?: string;
}) {
return api.post('/v1/content-templates/preview/email', { content, contentType, payload, subject, layoutId });
return api.post('/v1/content-templates/preview/email', { content, contentType, payload, subject, layoutId, locale });
}

export async function previewInApp({ content, cta, payload }: { content?: string; cta: any; payload: string }) {
return api.post('/v1/content-templates/preview/in-app', { content, payload, cta });
export async function previewInApp({
content,
cta,
payload,
locale,
}: {
content?: string;
cta: any;
payload: string;
locale?: string;
}) {
return api.post('/v1/content-templates/preview/in-app', { content, payload, cta, locale });
}

export async function previewChat({
content,
payload,
locale,
}: {
content?: string;
payload: string;
locale?: string;
}) {
return api.post('/v1/content-templates/preview/chat', { content, payload, locale });
}
2 changes: 2 additions & 0 deletions apps/web/src/api/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ export * from './useInAppActivated';
export * from './useDeleteIntegration';
export * from './useWebhookSupportStatus';
export * from './notification-templates';
export * from './useGetLocalesFromContent';
export * from './usePreviewEmail';
56 changes: 56 additions & 0 deletions apps/web/src/api/hooks/useGetLocalesFromContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { errorMessage } from '@novu/design-system';
import { IEmailBlock } from '@novu/shared';
import { IS_DOCKER_HOSTED } from '@novu/shared-web';
import { useMutation } from '@tanstack/react-query';
import { useCallback } from 'react';
import { getLocalesFromContent } from '../translations';

export interface ILocale {
name: string;
officialName: string | null;
numeric: string;
alpha2: string;
alpha3: string;
currencyName: string | null;
currencyAlphabeticCode: string | null;
langName: string;
langIso: string;
}

type Payload = {
content: string | IEmailBlock[];
};

export const useGetLocalesFromContent = () => {
const {
mutateAsync: getLocalesFromContentMutation,
isLoading,
data,
} = useMutation<ILocale[], { error: string; message: string; statusCode: number }, Payload>(
({ content }) => getLocalesFromContent({ content }),
{
onError: (e: any) => {
errorMessage(e.message || 'Unexpected error');
},
}
);

const getLocalesFromContentCallback = useCallback(
async ({ content }: Payload) => {
if (IS_DOCKER_HOSTED) {
return;
}

await getLocalesFromContentMutation({
content,
});
},
[getLocalesFromContentMutation]
);

return {
getLocalesFromContent: getLocalesFromContentCallback,
isLoading,
data: data || [],
};
};
58 changes: 58 additions & 0 deletions apps/web/src/api/hooks/usePreviewEmail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { errorMessage } from '@novu/design-system';
import { IEmailBlock, MessageTemplateContentType } from '@novu/shared';
import { IS_DOCKER_HOSTED } from '@novu/shared-web';
import { useMutation, UseMutationOptions } from '@tanstack/react-query';
import { useCallback } from 'react';
import { previewEmail } from '../content-templates';

export type PayloadType = {
content?: string | IEmailBlock[];
contentType?: MessageTemplateContentType;
payload: string;
subject?: string;
layoutId?: string;
locale?: string;
};

export type ResultType = { html: string; subject: string };

type ErrorType = { error: string; message: string; statusCode: number };

export const usePreviewEmail = (options: UseMutationOptions<ResultType, ErrorType, PayloadType> = {}) => {
const { mutateAsync, isLoading } = useMutation<ResultType, ErrorType, PayloadType>(
({ content, payload, contentType, layoutId, locale, subject }) =>
previewEmail({ content, payload, contentType, layoutId, locale, subject }),

{
onError: (e: any) => {
errorMessage(e.message || 'Unexpected error');
},
onSuccess: (result, variables, context) => {
options?.onSuccess?.(result, variables, context);
},
}
);

const getEmailPreviewCallback = useCallback(
async ({ content, payload, contentType, layoutId, locale, subject }: PayloadType) => {
if (IS_DOCKER_HOSTED) {
return;
}

await mutateAsync({
content,
payload,
contentType,
layoutId,
locale,
subject,
});
},
[mutateAsync]
);

return {
getEmailPreview: getEmailPreviewCallback,
isLoading,
};
};
5 changes: 5 additions & 0 deletions apps/web/src/api/translations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { api } from './api.client';

export async function getLocalesFromContent({ content }) {
return api.post('/v1/translations/groups/preview/locales', { content });
}
Loading
Loading