Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 2 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,7 @@
"putVocabularies",
"pythonapi",
"qafh",
"qconnect",
"QLAPINONEDS",
"QLAPI",
"QLID",
Expand Down Expand Up @@ -1353,6 +1354,7 @@
"Unauth",
"uncategorized",
"uncommenting",
"unconfigured",
"unencrypted",
"unioned",
"unmarshall",
Expand Down
5 changes: 4 additions & 1 deletion src/components/Layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,10 @@ export const Layout = ({
/>
</Flex>
)}
{(asPathWithNoHash.includes('/push-notifications/') ||
{((asPathWithNoHash.includes('/push-notifications/') &&
!asPathWithNoHash.includes(
'/push-notifications/customer-profiles/'
)) ||
asPathWithNoHash.includes('/analytics/') ||
asPathWithNoHash.includes('/in-app-messaging/')) &&
!asPathWithNoHash.includes('/kinesis') &&
Expand Down
50 changes: 48 additions & 2 deletions src/components/Layout/__tests__/Layout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ import { render, screen } from '@testing-library/react';
import { Layout } from '../index';
import userEvent from '@testing-library/user-event';

const routerState: { asPath: string; pathname: string } = {
asPath: '/[platform]/start/getting-started/introduction/',
pathname: '/[platform]/start/getting-started/introduction/'
};

const routerMock = {
__esModule: true,
useRouter: () => {
return {
query: { platform: 'react' },
pathname: '/[platform]/start/getting-started/introduction/',
asPath: '/[platform]/start/getting-started/introduction/'
pathname: routerState.pathname,
asPath: routerState.asPath
};
}
};
Expand All @@ -32,6 +37,11 @@ describe('Layout', () => {
</Layout>
);

beforeEach(() => {
routerState.asPath = '/[platform]/start/getting-started/introduction/';
routerState.pathname = '/[platform]/start/getting-started/introduction/';
});

it('should render the Layout component', async () => {
render(layoutComponent);
const layout = await screen.getByRole('main', { name: 'Main content' });
Expand Down Expand Up @@ -108,4 +118,40 @@ describe('Layout', () => {
'layout-sidebar__mobile-toggle--open'
);
});

describe('PinpointEOLBanner', () => {
Comment thread
soberm marked this conversation as resolved.
it('is not rendered for the Customer Profiles push-notifications client pages', async () => {
routerState.asPath =
'/react/frontend/push-notifications/customer-profiles/';
render(layoutComponent);
expect(document.body.textContent).not.toContain('Amazon Pinpoint');
});

it('is not rendered for the Customer Profiles push-notifications child pages', async () => {
routerState.asPath =
'/react/frontend/push-notifications/customer-profiles/register-device/';
render(layoutComponent);
expect(document.body.textContent).not.toContain('Amazon Pinpoint');
});

it('is rendered for a non-Customer-Profiles push-notifications sibling route', async () => {
routerState.asPath =
'/react/frontend/push-notifications/customer-profiles-legacy/';
render(layoutComponent);
expect(document.body.textContent).toContain('Amazon Pinpoint');
});

it('is rendered for the legacy (gen1) push-notifications pages', async () => {
routerState.asPath =
'/gen1/react/build-a-backend/push-notifications/set-up-push-notifications/';
render(layoutComponent);
expect(document.body.textContent).toContain('Amazon Pinpoint');
});

it('is rendered for analytics pages', async () => {
routerState.asPath = '/react/build-a-backend/add-aws-services/analytics/';
render(layoutComponent);
expect(document.body.textContent).toContain('Amazon Pinpoint');
});
});
});
47 changes: 47 additions & 0 deletions src/directory/directory.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,24 @@ export const directory = {
}
]
},
{
path: 'src/pages/[platform]/build-a-backend/add-aws-services/notifications/index.mdx',
section: 'backend',
children: [
{
path: 'src/pages/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/index.mdx',
section: 'backend'
},
{
path: 'src/pages/[platform]/build-a-backend/add-aws-services/notifications/author-message-templates/index.mdx',
section: 'backend'
},
{
path: 'src/pages/[platform]/build-a-backend/add-aws-services/notifications/existing-resources/index.mdx',
section: 'backend'
}
]
},
{
path: 'src/pages/[platform]/build-a-backend/add-aws-services/pinpoint-migration/index.mdx',
section: 'backend'
Expand Down Expand Up @@ -873,6 +891,35 @@ export const directory = {
}
]
},
{
path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/index.mdx',
children: [
{
path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/identify-user/index.mdx'
},
{
path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/register-device/index.mdx'
},
{
path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/remove-device/index.mdx'
},
{
path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/guest-and-authenticated-users/index.mdx'
},
{
path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/request-permissions/index.mdx'
},
{
path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/manage-device-token/index.mdx'
},
{
path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/interact-with-notifications/index.mdx'
},
{
path: 'src/pages/[platform]/frontend/push-notifications/customer-profiles/app-badge-count/index.mdx'
}
]
},
{
path: 'src/pages/[platform]/frontend/geo/index.mdx',
children: [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { getCustomStaticPath } from '@/utils/getCustomStaticPath';

export const meta = {
title: 'Author message templates',
description:
'Create a push message template with the Amazon Q in Connect API and connect it to an Amazon Connect journey custom action.',
platforms: [
'javascript',
'react-native',
'swift',
'android',
'flutter',
'angular',
'nextjs',
'react',
'vue'
]
};

export const getStaticPaths = async () => {
return getCustomStaticPath(meta.platforms);
};

export function getStaticProps(context) {
return {
props: {
platform: context.params.platform,
meta
}
};
}

Amplify provisions the delivery path for your notifications, but not the message content. The text your users receive comes from a **push message template** stored in an Amazon Q in Connect knowledge base.

<Callout warning>

**The Amazon Q in Connect console does not support authoring PUSH-channel message templates.** You create and publish push templates with the `qconnect` AWS CLI (or the underlying Amazon Q in Connect API), against the knowledge base that `defineNotifications` provisions. Amplify does not create the templates themselves, and a journey that has no matching template falls back to default placeholder copy.

</Callout>

## Name the template to match your journey

A push template's name is the only way Amplify links it to a journey: give the template the exact same name as the custom action block in your Amazon Connect journey.

## Find your knowledge base ID

In create mode, `defineNotifications` provisions an empty `MESSAGE_TEMPLATES` knowledge base and associates it with your Amazon Connect instance through the `Q_MESSAGE_TEMPLATES` integration. In attach mode, associate a `MESSAGE_TEMPLATES` knowledge base with your existing Connect instance yourself so this lookup resolves.

Either way, look up the knowledge base ID with the AWS CLI:

```bash title="Terminal" showLineNumbers={false}
aws connect list-integration-associations \
--instance-id <INSTANCE_ID> \
--integration-type Q_MESSAGE_TEMPLATES
```

The knowledge base ID is the last segment of the returned `IntegrationArn`, which ends in `knowledge-base/<KB_ID>`.

## Create the message template

Create the template with `qconnect create-message-template`, using the same name you will give the journey's custom action block:

```bash title="Terminal" showLineNumbers={false}
aws qconnect create-message-template \
--knowledge-base-id <KB_ID> \
--name 'Push Notification' \
--channel-subtype PUSH \
--content '{"push":{"apns":{"title":"Hello {{Attributes.firstName}}","body":{"content":"Your order shipped."}},"fcm":{"title":"Hello {{Attributes.firstName}}","body":{"content":"Your order shipped."}}}}'
```

Per-platform content maps to channels as `push.apns` (Apple Push Notification service, including the sandbox channel) and `push.fcm` (Firebase Cloud Messaging). A platform entry needs both a title and a body to be used; a platform you leave out falls back to default copy for that platform.

Publish a version after every copy change:

```bash title="Terminal" showLineNumbers={false}
aws qconnect create-message-template-version \
--knowledge-base-id <KB_ID> \
--message-template-id <TEMPLATE_ID>
```

## Personalize the message

Templates support `{{Attributes.<key>}}` variables, which resolve to the target Customer Profile's fields, including custom attributes set on the profile:

```handlebars
Hello {{Attributes.firstName}}, your order is on the way.
```

A variable with no matching profile value stays literal in the rendered copy, so use variables only for fields you populate consistently, and prefer copy that reads correctly when a value is absent.

See the [Amazon Q in Connect message template API reference](https://docs.aws.amazon.com/amazon-q-connect/latest/APIReference/API_CreateMessageTemplate.html) for the full content schema.

## Add the custom action to your journey

Building the journey itself is done in the Amazon Connect console; only template authoring is CLI-only:

1. In the Amazon Connect console, navigate to **Journeys** and open or create a journey.
2. Add a **custom action** block and point it at the push-delivery Lambda function that Amplify deployed.
3. Set the block name to the exact `--name` value you gave the template above, including capitalization.
4. Publish the journey.
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { getCustomStaticPath } from '@/utils/getCustomStaticPath';

export const meta = {
title: 'Use existing AWS resources',
description:
'Attach your Amplify notifications resource to an Amazon Connect Customer Profiles domain that already exists.',
platforms: [
'javascript',
'react-native',
'swift',
'android',
'flutter',
'angular',
'nextjs',
'react',
'vue'
]
};

export const getStaticPaths = async () => {
return getCustomStaticPath(meta.platforms);
};

export function getStaticProps(context) {
return {
props: {
platform: context.params.platform,
meta
}
};
}

Pass `domainName` to `defineNotifications` to attach to an Amazon Connect Customer Profiles domain that already exists:

```ts title="amplify/backend.ts"
import { defineBackend } from '@aws-amplify/backend';
import { defineNotifications } from '@aws-amplify/backend-notifications';
import { auth } from './auth/resource';

defineBackend({
auth,
notifications: defineNotifications({
domainName: 'amazon-connect-my-instance'
})
});
```

In this mode Amplify **attaches** to the domain rather than creating one. It registers the `AmplifyProfile` object type into the domain additively and does not create an Amazon Connect instance or a Customer Profiles domain. Object types that already exist on the domain are left unchanged, so you can attach to a domain that other workloads are using.

## Requirements for the existing domain

The domain must meet the following requirements:

- **Same AWS account and Region as your Amplify project.** The construct references the domain by name, which resolves only within the account and Region your backend deploys to.
- **The name must begin with `amazon-connect-`.** This is a functional requirement, not a naming preference. The AWS-managed `AmazonConnectServiceLinkedRolePolicy` grants your Amazon Connect instance access to Customer Profiles only on domains matching `arn:aws:profile:*:*:domains/amazon-connect-*`. A domain named otherwise is unreachable by the instance, and the Amazon Connect console reports that it does not have permission to access Customer Profiles. Because the service-linked role and its managed policy cannot be edited, the domain name is the only way to satisfy the policy.
- **Customer Profiles enabled on your Amazon Connect instance.** The most common domain to attach to is the one Amazon Connect creates for you when you enable Customer Profiles, which is named `amazon-connect-<instance-alias>`.

<Callout info>

To find the domain name, open the [Amazon Connect console](https://console.aws.amazon.com/connect/), select your instance, and choose **Customer Profiles**.

</Callout>

## Properties that do not apply

`instanceAlias` and `expirationDays` configure a domain that Amplify creates, so they cannot be combined with `domainName`. Set the data retention period on the existing domain in the Amazon Connect console instead.

To have Amplify create the Amazon Connect instance and the domain for you, see [Set up notifications](/[platform]/build-a-backend/add-aws-services/notifications/set-up-notifications/).
Loading
Loading