('system');
const [themeOverride, setThemeOverride] = React.useState('');
+ configure();
+ trackPageVisit();
+
return (
@@ -38,6 +42,8 @@ function MyApp({ Component, pageProps }) {
themeOverride={themeOverride}
/>
+
+
);
}
diff --git a/docs/src/pages/_document.page.tsx b/docs/src/pages/_document.page.tsx
index 5605fcc6ca6..ac73f081556 100644
--- a/docs/src/pages/_document.page.tsx
+++ b/docs/src/pages/_document.page.tsx
@@ -25,7 +25,9 @@ const getCSPContent = (context: Readonly) => {
style-src 'self' 'unsafe-inline';
font-src 'self' data:;
frame-src *.codesandbox.io;
- script-src 'unsafe-eval' 'self' '${cspInlineScriptHash}'
+ img-src 'self' cm.everesttech.net amazonwebservices.d2.sc.omtrdc.net dpm.demdex.net;
+ connect-src 'self' *.shortbread.aws.dev dpm.demdex.net;
+ script-src 'unsafe-eval' 'self' '${cspInlineScriptHash}' a0.awsstatic.com;
`;
}
@@ -33,8 +35,10 @@ const getCSPContent = (context: Readonly) => {
return `default-src 'self';
style-src 'self' 'unsafe-inline';
font-src 'self';
- frame-src *.codesandbox.io;
- script-src 'self' '${cspInlineScriptHash}'
+ frame-src *.codesandbox.io aws.demdex.net;
+ img-src 'self' cm.everesttech.net amazonwebservices.d2.sc.omtrdc.net dpm.demdex.net;
+ connect-src 'self' *.shortbread.aws.dev dpm.demdex.net;
+ script-src 'self' '${cspInlineScriptHash}' a0.awsstatic.com;
`;
};
diff --git a/docs/src/pages/components/authenticator/index.page.mdx b/docs/src/pages/components/authenticator/index.page.mdx
index f8c7751f1b4..c56a5074778 100644
--- a/docs/src/pages/components/authenticator/index.page.mdx
+++ b/docs/src/pages/components/authenticator/index.page.mdx
@@ -295,10 +295,7 @@ The following example customizes these slots with:
const { tokens } = useTheme();
return (
-
+
);
},
@@ -451,7 +448,7 @@ Using the same techniques as [Internationalization (I18n)](#internationalization
-
+
```js
I18n.putVocabulariesForLanguage('en', {
'Create Account': 'Register', // Tab header
@@ -469,7 +466,7 @@ Using the same techniques as [Internationalization (I18n)](#internationalization
-
+
```js
I18n.putVocabulariesForLanguage('en', {
'Reset your password': 'Forgot your password?',
diff --git a/docs/src/pages/components/image/demo.tsx b/docs/src/pages/components/image/demo.tsx
index 49cb7d53557..32a10c9ed93 100644
--- a/docs/src/pages/components/image/demo.tsx
+++ b/docs/src/pages/components/image/demo.tsx
@@ -22,7 +22,7 @@ export const ImageDemo = () => {
padding: '0',
});
const imageProps = useImageProps({
- src: 'https://docs.amplify.aws/assets/logo-dark.svg',
+ src: '/amplify-logo.svg',
alt: 'Amplify logo',
objectFit: 'fill',
objectPosition: 'initial',
diff --git a/docs/src/pages/components/scrollview/demo.tsx b/docs/src/pages/components/scrollview/demo.tsx
index 259b6e1e5ac..4a09b11095e 100644
--- a/docs/src/pages/components/scrollview/demo.tsx
+++ b/docs/src/pages/components/scrollview/demo.tsx
@@ -19,7 +19,7 @@ export const ScrollViewDemo = () => {
diff --git a/docs/src/pages/components/scrollview/react.mdx b/docs/src/pages/components/scrollview/react.mdx
index b997970535b..8b435de6aed 100644
--- a/docs/src/pages/components/scrollview/react.mdx
+++ b/docs/src/pages/components/scrollview/react.mdx
@@ -21,7 +21,7 @@ import '@aws-amplify/ui-react/styles.css';
;
@@ -33,7 +33,7 @@ import '@aws-amplify/ui-react/styles.css';
@@ -56,7 +56,7 @@ import '@aws-amplify/ui-react/styles.css';
;
@@ -68,7 +68,7 @@ import '@aws-amplify/ui-react/styles.css';
diff --git a/docs/src/utils/track.ts b/docs/src/utils/track.ts
new file mode 100644
index 00000000000..a81f525470e
--- /dev/null
+++ b/docs/src/utils/track.ts
@@ -0,0 +1,161 @@
+// https://github.com/aws-amplify/docs/blob/main/src/utils/track.ts
+let configured = false;
+
+declare global {
+ interface Window {
+ s: any;
+ AWSCShortbread: any;
+ }
+}
+
+export const configure = (): void => {
+ if (!configured) {
+ if (
+ typeof window !== 'undefined' &&
+ typeof window.AWSCShortbread !== 'undefined'
+ ) {
+ window
+ .AWSCShortbread({
+ domain: '.amplify.aws',
+ })
+ .checkForCookieConsent();
+ if (typeof window.s !== 'undefined') window.s.trackExternalLinks = false;
+ configured = true;
+ }
+ }
+};
+
+export enum AnalyticsEventType {
+ PAGE_VISIT = 'PAGE_VISIT',
+ INTERNAL_LINK_CLICK = 'INTERNAL_LINK_CLICK',
+ EXTERNAL_LINK_CLICK = 'EXTERNAL_LINK_CLICK',
+ PAGE_DATA_FETCH_EXCEPTION = 'PAGE_DATA_FETCH_EXCEPTION',
+}
+
+interface AnalyticsEventPageVisit {
+ type: AnalyticsEventType.PAGE_VISIT;
+ attributes: {
+ url: string;
+ previousUrl: string;
+ referrer: string;
+ };
+}
+
+interface AnalyticsEventInternalLinkClick {
+ type: AnalyticsEventType.INTERNAL_LINK_CLICK;
+ attributes: {
+ from: string;
+ to: string;
+ };
+}
+
+interface AnalyticsEventExternalLinkClick {
+ type: AnalyticsEventType.EXTERNAL_LINK_CLICK;
+ attributes: {
+ from: string;
+ to: string;
+ };
+}
+
+interface AnalyticsEventPageDataFetchException {
+ type: AnalyticsEventType.PAGE_DATA_FETCH_EXCEPTION;
+ attributes: {
+ url: string;
+ exception: Error;
+ };
+}
+
+type AnalyticsEvent =
+ | AnalyticsEventPageVisit
+ | AnalyticsEventInternalLinkClick
+ | AnalyticsEventExternalLinkClick
+ | AnalyticsEventPageDataFetchException;
+
+export const trackPageVisit = (): void => {
+ if (typeof window !== 'undefined' && typeof window.s !== 'undefined') {
+ const { s } = window;
+ s.pageURL = window.location.href;
+ s.t();
+ }
+};
+
+export const trackPageFetchException = (): void => {
+ if (typeof window !== 'undefined' && typeof window.s !== 'undefined') {
+ const { s } = window;
+ s.linkTrackVars =
+ 'prop39,prop41,prop50,prop61,prop62,eVar39,eVar41,eVar50,eVar61,eVar62,eVar69';
+ s.tl(true, 'o', 'page fetch exception');
+ }
+};
+
+export const trackExternalLink = (hrefTo: string): void => {
+ if (typeof window !== 'undefined' && typeof window.s !== 'undefined') {
+ const { s } = window;
+ s.linkTrackVars =
+ 'prop39,prop41,prop50,prop61,prop62,eVar39,eVar41,eVar50,eVar61,eVar62,eVar69';
+ s.tl(true, 'e', hrefTo);
+ }
+};
+
+export const setSearchQuery = (query: string): void => {
+ if (typeof window !== 'undefined' && typeof window.s != 'undefined') {
+ const { s } = window;
+ s.eVar26 = query;
+ }
+};
+
+const triggerNoSearchResults = (query: string): void => {
+ if (typeof window !== 'undefined' && typeof window.s != 'undefined') {
+ const { s } = window;
+ const queryBackup: string = s.eVar26;
+ const resultCountBackup: number = parseInt(s.eVar27, 10);
+
+ s.eVar26 = query;
+ s.eVar27 = '0'; // If it's the number 0, the variable won't be sent
+ s.linkTrackVars =
+ 'prop39,prop41,prop50,prop61,prop62,eVar26,eVar27,eVar39,eVar41,eVar50,eVar61,eVar62,eVar69,events';
+ s.linkTrackEvents = 'event2';
+ s.events = 'event2';
+ s.tl(true, 'o', 'internal search');
+
+ s.eVar26 = queryBackup;
+ s.eVar27 = resultCountBackup.toString();
+ }
+};
+
+let noResultsTimeout: NodeJS.Timeout;
+export const setSearchResultCount = (resultCount: number): void => {
+ if (typeof window !== 'undefined' && typeof window.s !== 'undefined') {
+ const { s } = window;
+ s.eVar27 = resultCount.toString();
+ s.events = resultCount === 0 ? 'event1' : 'event2';
+
+ if (resultCount === 0) {
+ if (noResultsTimeout) {
+ clearTimeout(noResultsTimeout);
+ }
+ noResultsTimeout = setTimeout(
+ triggerNoSearchResults.bind(null, s.eVar26),
+ 1000
+ );
+ }
+ }
+};
+
+export const trackSearchQuery = (
+ _input,
+ _event,
+ suggestion,
+ _datasetNumber,
+ _context
+): void => {
+ if (typeof window !== 'undefined' && typeof window.s !== 'undefined') {
+ const { s } = window;
+ s.linkTrackVars =
+ 'prop39,prop41,prop50,prop61,prop62,eVar26,eVar27,eVar39,eVar41,eVar50,eVar61,eVar62,eVar69,events';
+ s.linkTrackEvents = 'event1';
+ s.events = 'event1';
+ s.tl(true, 'o', 'internal search');
+ }
+ window.location.assign(suggestion.url);
+};
diff --git a/examples/next/package.json b/examples/next/package.json
index d293b56cfaa..eae9102668f 100644
--- a/examples/next/package.json
+++ b/examples/next/package.json
@@ -12,7 +12,7 @@
"@aws-amplify/ui-react": "^2.1.5",
"@types/node": "^15.12.4",
"@types/react": "^17.0.11",
- "next": "12",
+ "next": "^11.1.3",
"next-global-css": "^1.1.1",
"react": "latest",
"react-dom": "latest",
diff --git a/package.json b/package.json
index 7ed98ad7036..d2e416267d7 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,6 @@
"fs-extra": "^10.0.0",
"jest": "^26.6.3",
"json-schema": "^0.4.0",
- "next": "^11.0.1",
"prismjs": "^1.25.0",
"trim": "^0.0.3",
"ts-jest": "^26.5.6",
diff --git a/packages/e2e/cypress/fixtures/force-change-password-mfa-setup.json b/packages/e2e/cypress/fixtures/force-change-password-mfa-setup.json
new file mode 100644
index 00000000000..d363f6a236b
--- /dev/null
+++ b/packages/e2e/cypress/fixtures/force-change-password-mfa-setup.json
@@ -0,0 +1,7 @@
+{
+ "ChallengeName": "MFA_SETUP",
+ "ChallengeParameters": {
+ "MFAS_CAN_SETUP": "[\"SMS_MFA\",\"SOFTWARE_TOKEN_MFA\"]"
+ },
+ "Session": "••••••••••••••••••••••••••••••••••••••••••••••••"
+}
diff --git a/packages/e2e/features/ui/components/authenticator/sign-in-totp-mfa.feature b/packages/e2e/features/ui/components/authenticator/sign-in-totp-mfa.feature
index 3113201019b..4d59cc64002 100644
--- a/packages/e2e/features/ui/components/authenticator/sign-in-totp-mfa.feature
+++ b/packages/e2e/features/ui/components/authenticator/sign-in-totp-mfa.feature
@@ -37,3 +37,19 @@ Feature: Sign In with TOTP MFA
And I type my password
And I click the "Sign in" button
Then I see "User does not exist"
+
+
+@angular @react @vue
+ Scenario: Sign in with force change password with mfa setup
+ Given I intercept '{ "headers": { "X-Amz-Target": "AWSCognitoIdentityProviderService.RespondToAuthChallenge" } }' with fixture "force-change-password"
+ When I type my "email" with status "FORCE_CHANGE_PASSWORD"
+ And I type my password
+ And I click the "Sign in" button
+ Then I see "Change Password"
+ And I type my password
+ And I confirm my password
+ Given I intercept '{ "headers": { "X-Amz-Target": "AWSCognitoIdentityProviderService.RespondToAuthChallenge" } }' with fixture "force-change-password-mfa-setup"
+ And I click the "Change Password" button
+ Then I see "Setup TOTP"
+
+
diff --git a/packages/ui/src/machines/authenticator/actors/signIn.ts b/packages/ui/src/machines/authenticator/actors/signIn.ts
index fdc814c00b6..2cd55d7d6f4 100644
--- a/packages/ui/src/machines/authenticator/actors/signIn.ts
+++ b/packages/ui/src/machines/authenticator/actors/signIn.ts
@@ -231,7 +231,11 @@ export function signInActor({ services }: SignInMachineOptions) {
actions: ['setUser', 'setChallengeName'],
target: '#signInActor.confirmSignIn',
},
-
+ {
+ cond: 'shouldSetupTOTP',
+ actions: ['setUser', 'setChallengeName'],
+ target: '#signInActor.setupTOTP',
+ },
{
target: 'resolved',
actions: ['setUser', 'setCredentials'],
diff --git a/yarn.lock b/yarn.lock
index 713f5ae8cf1..08bf0976bfb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -16060,7 +16060,7 @@ next-tick@~1.0.0:
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
-next@12, next@^11.0.1:
+next@^11.1.3:
version "11.1.3"
resolved "https://registry.yarnpkg.com/next/-/next-11.1.3.tgz#0226b283cb9890e446aea759db8a867de2b279ef"
integrity sha512-ud/gKmnKQ8wtHC+pd1ZiqPRa7DdgulPkAk94MbpsspfNliwZkYs9SIYWhlLSyg+c661LzdUI2nZshvrtggSYWA==