diff --git a/package-lock.json b/package-lock.json
index a532227482..450e463298 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -47,6 +47,7 @@
"json-refs": "^3.0.15",
"lodash": "^4.17.21",
"logrocket": "^8.1.2",
+ "logrocket-react": "^5.0.1",
"luxon": "^3.4.3",
"material-ui-popup-state": "^5.0.10",
"mnemonist": "^0.39.8",
@@ -10779,6 +10780,17 @@
"resolved": "https://registry.npmjs.org/logrocket/-/logrocket-8.1.2.tgz",
"integrity": "sha512-9D9ZiDkRkoDqjY/vV5L31Ry7dtNRDGiEFniPWmDUILBRdrCX/kPTMjXlD/RdHd/mUbRYM827lXJBIuoVHpShtA=="
},
+ "node_modules/logrocket-react": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/logrocket-react/-/logrocket-react-5.0.1.tgz",
+ "integrity": "sha512-d5RAi1giur9Yv7/lDK/c2S1hviopN5K1XMMpfpSFRDG3Rr/j5RmGuvNHdXNTJUwGuxTVrpnKUOB43ceQMJfO1Q==",
+ "license": "MIT",
+ "peerDependencies": {
+ "logrocket": ">=2.0",
+ "react": ">=17.0",
+ "react-dom": ">=17.0"
+ }
+ },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
diff --git a/package.json b/package.json
index 0da5ea4b41..2659a111dc 100644
--- a/package.json
+++ b/package.json
@@ -72,6 +72,7 @@
"json-refs": "^3.0.15",
"lodash": "^4.17.21",
"logrocket": "^8.1.2",
+ "logrocket-react": "^5.0.1",
"luxon": "^3.4.3",
"material-ui-popup-state": "^5.0.10",
"mnemonist": "^0.39.8",
diff --git a/src/app/guards/LegalGuard.tsx b/src/app/guards/LegalGuard.tsx
index ca40141a23..ac87b0b96b 100644
--- a/src/app/guards/LegalGuard.tsx
+++ b/src/app/guards/LegalGuard.tsx
@@ -3,6 +3,7 @@ import ClickToAccept from 'directives/ClickToAccept';
import FullPageWrapper from 'app/FullPageWrapper';
import { FormattedMessage } from 'react-intl';
import { BaseComponentProps } from 'types';
+import { Box } from '@mui/material';
import useDirectiveGuard from './hooks';
const SELECTED_DIRECTIVE = 'clickToAccept';
@@ -37,11 +38,17 @@ function LegalGuard({ children }: BaseComponentProps) {
if (status !== 'fulfilled') {
return (
-
+
+
+
);
} else {
diff --git a/src/app/guards/OnboardGuard.tsx b/src/app/guards/OnboardGuard.tsx
index ff40345440..caa1f2e418 100644
--- a/src/app/guards/OnboardGuard.tsx
+++ b/src/app/guards/OnboardGuard.tsx
@@ -5,6 +5,8 @@ import { createOnboardingStore } from 'directives/Onboard/Store/create';
import { useMemo } from 'react';
import { OnboardingStoreNames } from 'stores/names';
import { BaseComponentProps } from 'types';
+import CustomerQuote from 'directives/Onboard/CustomerQuote';
+import { Grid } from '@mui/material';
import useDirectiveGuard from './hooks';
const SELECTED_DIRECTIVE = 'betaOnboard';
@@ -34,14 +36,26 @@ function OnboardGuard({ children, forceDisplay, grantsMutate }: Props) {
return null;
} else if (forceDisplay || status !== 'fulfilled') {
return (
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
);
} else {
diff --git a/src/app/guards/RegistrationProgress.tsx b/src/app/guards/RegistrationProgress.tsx
new file mode 100644
index 0000000000..b8207aafda
--- /dev/null
+++ b/src/app/guards/RegistrationProgress.tsx
@@ -0,0 +1,37 @@
+import { LinearProgress, Stack, Typography } from '@mui/material';
+import { useIntl } from 'react-intl';
+import { RegistrationProgressProps } from './types';
+
+const totalSteps = 2;
+
+function RegistrationProgress({
+ loading,
+ status,
+ step,
+}: RegistrationProgressProps) {
+ const intl = useIntl();
+
+ if (status === 'outdated') {
+ return null;
+ }
+
+ return (
+
+
+ {intl.formatMessage(
+ { id: 'login.progress.indicator' },
+ {
+ step,
+ totalSteps,
+ }
+ )}
+
+
+
+ );
+}
+
+export default RegistrationProgress;
diff --git a/src/app/guards/types.ts b/src/app/guards/types.ts
new file mode 100644
index 0000000000..aef199c318
--- /dev/null
+++ b/src/app/guards/types.ts
@@ -0,0 +1,7 @@
+import { DirectiveStates } from 'directives/types';
+
+export interface RegistrationProgressProps {
+ status: DirectiveStates;
+ step: 1 | 2;
+ loading?: boolean;
+}
diff --git a/src/components/collection/Selector/List/Header/Toggle/MenuContent.tsx b/src/components/collection/Selector/List/Header/Toggle/MenuContent.tsx
index d70819e402..eccec5fb73 100644
--- a/src/components/collection/Selector/List/Header/Toggle/MenuContent.tsx
+++ b/src/components/collection/Selector/List/Header/Toggle/MenuContent.tsx
@@ -18,6 +18,11 @@ interface Props {
updateScope: (event: SyntheticEvent, newScope: Scopes) => void;
}
+// TODO (accessibility) this menu is not acessible and we have some options
+// - wait for https://github.com/mui/material-ui/issues/43330 to be fixed
+// - Write some tricky CSS in the parent that allows things to look the way they do but have all the items have a `MenuItem` around them
+// - fork MUI's Menu just for these and disable the up/down keyboard interactions
+// - Overhaul the entire approach to this menu and redesign it to somehow not need menu... let's not do this one
function ScopeMenuContent({
closeMenu,
initialScope,
diff --git a/src/components/login/Providers/buttons/SSO.tsx b/src/components/login/Providers/buttons/SSO.tsx
index 7f8ea41e08..8d93d7a812 100644
--- a/src/components/login/Providers/buttons/SSO.tsx
+++ b/src/components/login/Providers/buttons/SSO.tsx
@@ -1,37 +1,46 @@
-import { Box, Button, useTheme } from '@mui/material';
+import { Button, Typography, useTheme } from '@mui/material';
import { loginButtonStyling } from 'context/Theme';
-import { FormattedMessage } from 'react-intl';
+import { useIntl } from 'react-intl';
import { unauthenticatedRoutes } from 'app/routes';
-import { Lock } from 'iconoir-react';
-import MessageWithLink from 'components/content/MessageWithLink';
+import { Lock, OpenNewWindow } from 'iconoir-react';
+import { HTMLAttributeAnchorTarget, ReactNode } from 'react';
import { LoginProps } from '../types';
function SSOButton({ isRegister }: LoginProps) {
+ const intl = useIntl();
const theme = useTheme();
+ let href: string = unauthenticatedRoutes.sso.login.fullPath;
+ let endIcon: ReactNode | undefined;
+ let startIcon: ReactNode | undefined = ;
+ let labelMessageId: string = 'cta.login.sso';
+ let target: HTMLAttributeAnchorTarget = '_self';
if (isRegister) {
- return (
-
-
-
+ endIcon = (
+
+
+
);
+ href = intl.formatMessage({
+ id: 'login.sso.register.message.help.docPath',
+ });
+ startIcon = undefined;
+ labelMessageId = 'login.sso.register.message.help';
+ target = '_blank';
}
return (
}
- sx={loginButtonStyling[theme.palette.mode]}
+ href={href}
size="large"
+ startIcon={startIcon}
+ target={target}
variant="text"
- href={unauthenticatedRoutes.sso.login.fullPath}
+ sx={loginButtonStyling[theme.palette.mode]}
>
-
+ {intl.formatMessage({ id: labelMessageId })}
);
}
diff --git a/src/components/login/Providers/index.tsx b/src/components/login/Providers/index.tsx
index d8093726ae..0683a30657 100644
--- a/src/components/login/Providers/index.tsx
+++ b/src/components/login/Providers/index.tsx
@@ -1,5 +1,5 @@
import { Divider, Stack } from '@mui/material';
-import { FormattedMessage } from 'react-intl';
+import { useIntl } from 'react-intl';
import { getLoginSettings } from 'utils/env-utils';
import LoginButton from './LoginButton';
import { LoginProvidersProps } from './types';
@@ -13,6 +13,7 @@ function LoginProviders({
isRegister,
providers = ['google', 'github', 'azure'],
}: LoginProvidersProps) {
+ const intl = useIntl();
const { login } = useLoginHandler(grantToken, isRegister);
return (
@@ -35,7 +36,11 @@ function LoginProviders({
{loginSettings.showSSO ? (
<>
-
+ {intl.formatMessage({
+ id: isRegister
+ ? 'login.sso.separator'
+ : 'login.separator',
+ })}
>
diff --git a/src/components/login/SSO/index.tsx b/src/components/login/SSO/index.tsx
index 81259b32a3..e0c007c113 100644
--- a/src/components/login/SSO/index.tsx
+++ b/src/components/login/SSO/index.tsx
@@ -10,7 +10,7 @@ import { supabaseClient } from 'context/GlobalProviders';
import React, { useState } from 'react';
import AlertBox from 'components/shared/AlertBox';
import { useSnackbar, VariantType } from 'notistack';
-import { FormattedMessage, useIntl } from 'react-intl';
+import { useIntl } from 'react-intl';
import { useNavigate } from 'react-router';
import { hasLength } from 'utils/misc-utils';
@@ -109,14 +109,14 @@ const SSOForm = ({ grantToken }: DefaultLoginProps) => {
return (
-
+ {intl.formatMessage({ id: 'login.sso.header' })}
{submitError ? (
{submitError}
-
+ {intl.formatMessage({ id: 'error.tryAgain' })}
@@ -126,11 +126,11 @@ const SSOForm = ({ grantToken }: DefaultLoginProps) => {
diff --git a/src/context/Theme.tsx b/src/context/Theme.tsx
index 6f03a65253..94f371f155 100644
--- a/src/context/Theme.tsx
+++ b/src/context/Theme.tsx
@@ -328,6 +328,20 @@ export const editorToolBarSx: SxProps = {
alignItems: 'center',
};
+export const hiddenButAccessibleInput: SxProps = {
+ position: 'fixed',
+ opacity: 0,
+ pointerEvents: 'none',
+};
+
+export const hiddenButAccessibleRadio: SxProps = {
+ '& .MuiRadio-root, & .MuiRadio-root input': {
+ position: 'fixed',
+ opacity: 0,
+ pointerEvents: 'none',
+ },
+};
+
export const defaultBoxShadow =
'rgb(50 50 93 / 7%) 0px 3px 6px -1px, rgb(0 0 0 / 10%) 0px -2px 4px -1px, rgb(0 0 0 / 10%) 0px 2px 4px -1px';
diff --git a/src/directives/AcceptGrant.tsx b/src/directives/AcceptGrant.tsx
index 8103388d10..56289dc15c 100644
--- a/src/directives/AcceptGrant.tsx
+++ b/src/directives/AcceptGrant.tsx
@@ -1,4 +1,4 @@
-import { Box, Stack, Typography } from '@mui/material';
+import { Box, LinearProgress, Stack, Typography } from '@mui/material';
import {
PostgrestError,
PostgrestSingleResponse,
@@ -103,8 +103,11 @@ function AcceptGrant({
}
};
+ // TODO (RegistrationProgress) get this wired up to know what step it is and use the RegistrationProgress component
return (
+ {saving ? : null}
+
{serverError ? (
{
+ const intl = useIntl();
+
+ return (
+
+
+
+ {intl.formatMessage({
+ id: primaryMessageId,
+ })}
+
+
+ );
+};
+
+export default Actions;
diff --git a/src/directives/BetaOnboard.tsx b/src/directives/BetaOnboard.tsx
index c6c9d3dd7f..8f77dcd9af 100644
--- a/src/directives/BetaOnboard.tsx
+++ b/src/directives/BetaOnboard.tsx
@@ -1,16 +1,8 @@
-import {
- Box,
- Stack,
- Toolbar,
- Typography,
- useMediaQuery,
- useTheme,
-} from '@mui/material';
+import { Box, Stack, Typography } from '@mui/material';
import { PostgrestError } from '@supabase/postgrest-js';
import { submitDirective } from 'api/directives';
-import SafeLoadingButton from 'components/SafeLoadingButton';
+import RegistrationProgress from 'app/guards/RegistrationProgress';
import AlertBox from 'components/shared/AlertBox';
-import CustomerQuote from 'directives/Onboard/CustomerQuote';
import OrganizationNameField from 'directives/Onboard/OrganizationName';
import {
useOnboardingStore_nameInvalid,
@@ -22,16 +14,18 @@ import {
} from 'directives/Onboard/Store/hooks';
import OnboardingSurvey from 'directives/Onboard/Survey';
import useJobStatusPoller from 'hooks/useJobStatusPoller';
-import { useMemo, useState } from 'react';
-import { FormattedMessage } from 'react-intl';
+import HeaderMessage from 'pages/login/HeaderMessage';
+import { useState } from 'react';
+import { FormattedMessage, useIntl } from 'react-intl';
import { useMount, useUnmount } from 'react-use';
import { fireGtmEvent } from 'services/gtm';
import { hasLength } from 'utils/misc-utils';
+import Actions from './Actions';
import { jobStatusQuery, trackEvent } from './shared';
import { DirectiveProps } from './types';
const directiveName = 'betaOnboard';
-const nameTaken = 'is already in use';
+const NAME_TAKEN_MESSAGE = 'is already in use';
const submit_onboard = async (
requestedTenant: string,
@@ -46,9 +40,8 @@ const submit_onboard = async (
);
};
-const BetaOnboard = ({ directive, mutate }: DirectiveProps) => {
- const theme = useTheme();
- const belowMd = useMediaQuery(theme.breakpoints.down('md'));
+const BetaOnboard = ({ directive, mutate, status }: DirectiveProps) => {
+ const intl = useIntl();
const { jobStatusPoller } = useJobStatusPoller();
@@ -60,6 +53,7 @@ const BetaOnboard = ({ directive, mutate }: DirectiveProps) => {
const surveyResponse = useOnboardingStore_surveyResponse();
const resetOnboardingState = useOnboardingStore_resetState();
+ const [nameTaken, setNameTaken] = useState(false);
const [saving, setSaving] = useState(false);
const [serverError, setServerError] = useState(null);
@@ -103,108 +97,107 @@ const BetaOnboard = ({ directive, mutate }: DirectiveProps) => {
void mutate();
},
async (payload: any) => {
+ const tenantTaken = Boolean(
+ payload?.job_status?.error?.includes(
+ NAME_TAKEN_MESSAGE
+ )
+ );
+
+ // Handle tracking right away
+ fireGtmEvent('RegisterFailed', {
+ tenantAlreadyTaken: tenantTaken,
+ tenant: requestedTenant,
+ });
trackEvent(`${directiveName}:Error`, directive);
+
+ // Update local state
setSaving(false);
- setServerError(payload.job_status.error);
+ setServerError(payload?.job_status?.error);
+ setNameTaken(tenantTaken);
}
);
}
},
};
- const nameAlreadyUsed = useMemo(
- () => serverError?.includes(nameTaken),
- [serverError]
- );
-
useMount(() => {
trackEvent(`${directiveName}:Viewed`);
});
useUnmount(() => resetOnboardingState());
return (
-
-
+ <>
+
+
+
+
+
+ {serverError ? (
+
+
+ {serverError}
+
+
+ ) : null}
+
+ {nameMissing ? (
+
+ }
+ >
+
+ {intl.formatMessage({
+ id: 'tenant.errorMessage.empty',
+ })}
+
+
+
+ ) : null}
+
-
+
-
-
+
+
+
+
+
+ >
);
};
diff --git a/src/directives/ClickToAccept.tsx b/src/directives/ClickToAccept.tsx
index a66b60e8a0..e63991c6c0 100644
--- a/src/directives/ClickToAccept.tsx
+++ b/src/directives/ClickToAccept.tsx
@@ -7,14 +7,16 @@ import {
} from '@mui/material';
import { PostgrestError } from '@supabase/postgrest-js';
import { submitDirective } from 'api/directives';
-import SafeLoadingButton from 'components/SafeLoadingButton';
+import RegistrationProgress from 'app/guards/RegistrationProgress';
import AlertBox from 'components/shared/AlertBox';
import ExternalLink from 'components/shared/ExternalLink';
import useJobStatusPoller from 'hooks/useJobStatusPoller';
+import HeaderMessage from 'pages/login/HeaderMessage';
import { useState } from 'react';
-import { FormattedMessage } from 'react-intl';
+import { FormattedMessage, useIntl } from 'react-intl';
import { useMount } from 'react-use';
import { getUrls } from 'utils/env-utils';
+import Actions from './Actions';
import {
CLICK_TO_ACCEPT_LATEST_VERSION,
jobStatusQuery,
@@ -34,6 +36,7 @@ const submit_clickToAccept = async (directive: any) => {
};
const ClickToAccept = ({ directive, status, mutate }: DirectiveProps) => {
+ const intl = useIntl();
const { jobStatusPoller } = useJobStatusPoller();
const [acknowledgedDocuments, setAcknowledgedDocuments] =
@@ -104,23 +107,26 @@ const ClickToAccept = ({ directive, status, mutate }: DirectiveProps) => {
alignItems: 'center',
}}
>
-
-
-
+
+
+
{showErrors ? (
}
+ title={intl.formatMessage({ id: 'error.title' })}
>
-
+ {intl.formatMessage({ id: 'legal.docs.errorMessage' })}
) : null}
@@ -128,7 +134,7 @@ const ClickToAccept = ({ directive, status, mutate }: DirectiveProps) => {
}
+ title={intl.formatMessage({ id: 'common.fail' })}
>
{serverError}
@@ -146,11 +152,11 @@ const ClickToAccept = ({ directive, status, mutate }: DirectiveProps) => {
-
+ {intl.formatMessage({ id: 'legal.docs.privacy' })}
-
+ {intl.formatMessage({ id: 'legal.docs.terms' })}
@@ -173,30 +179,21 @@ const ClickToAccept = ({ directive, status, mutate }: DirectiveProps) => {
}
onChange={handlers.update}
name="accept"
- label={
-
- ),
- terms: (
-
- ),
- }}
- />
- }
+ label={intl.formatMessage(
+ { id: 'legal.docs.accept' },
+ {
+ privacy: intl.formatMessage({
+ id: 'legal.docs.privacy',
+ }),
+ terms: intl.formatMessage({
+ id: 'legal.docs.terms',
+ }),
+ }
+ )}
/>
-
-
-
+
>
);
diff --git a/src/directives/Onboard/CustomerQuote.tsx b/src/directives/Onboard/CustomerQuote.tsx
index 119c3bc75c..1229032b1b 100644
--- a/src/directives/Onboard/CustomerQuote.tsx
+++ b/src/directives/Onboard/CustomerQuote.tsx
@@ -1,26 +1,66 @@
-import { Box, useTheme } from '@mui/material';
+import { Box, useMediaQuery, useTheme } from '@mui/material';
+import { useIntl } from 'react-intl';
import customerQuoteDark from 'images/customer_quote-dark.png';
import customerQuoteLight from 'images/customer_quote-light.png';
-import { useIntl } from 'react-intl';
-interface Props {
- hideQuote: boolean;
-}
-function CustomerQuote({ hideQuote }: Props) {
+function CustomerQuote() {
const theme = useTheme();
const intl = useIntl();
+ const belowMd = useMediaQuery(theme.breakpoints.down('md'));
- if (hideQuote) {
+ if (belowMd) {
return null;
} else {
return (
+ // TODO (customer quote) should switch this to HTML to load faster
+ //
+ //
+ //
+ //
+ //
+ // {`"${intl.formatMessage({
+ // id: 'tenant.customer.quote',
+ // })}"`}
+ //
+ //
+ //
+ //
+ //
);
diff --git a/src/directives/Onboard/Survey/OriginOption.tsx b/src/directives/Onboard/Survey/OriginOption.tsx
new file mode 100644
index 0000000000..97408cde2b
--- /dev/null
+++ b/src/directives/Onboard/Survey/OriginOption.tsx
@@ -0,0 +1,36 @@
+import { Chip, FormControlLabel, Radio } from '@mui/material';
+import { chipOutlinedStyling } from 'context/Theme';
+import { useOnboardingStore_surveyResponse } from 'directives/Onboard/Store/hooks';
+import { OriginOptionProps } from './types';
+
+function OriginOption({ optionLabel: option }: OriginOptionProps) {
+ const surveyResponse = useOnboardingStore_surveyResponse();
+ const currentOption = surveyResponse.origin === option;
+
+ const labelId = `${option} label`;
+ const inputId = `${option} input`;
+
+ return (
+ }
+ htmlFor={inputId}
+ label={
+
+ }
+ />
+ );
+}
+
+export default OriginOption;
diff --git a/src/directives/Onboard/Survey.tsx b/src/directives/Onboard/Survey/index.tsx
similarity index 56%
rename from src/directives/Onboard/Survey.tsx
rename to src/directives/Onboard/Survey/index.tsx
index 172b776100..057b6969fe 100644
--- a/src/directives/Onboard/Survey.tsx
+++ b/src/directives/Onboard/Survey/index.tsx
@@ -1,11 +1,5 @@
-import {
- FormControl,
- FormControlLabel,
- FormLabel,
- Radio,
- RadioGroup,
- TextField,
-} from '@mui/material';
+import { FormControl, FormLabel, RadioGroup } from '@mui/material';
+import { hiddenButAccessibleRadio } from 'context/Theme';
import {
useOnboardingStore_setSurveyResponse,
useOnboardingStore_surveyOptionOther,
@@ -14,11 +8,7 @@ import {
import { ChangeEvent } from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
import useConstant from 'use-constant';
-
-export interface SurveyResponse {
- origin: string;
- details: string;
-}
+import OriginOption from './OriginOption';
function OnboardingSurvey() {
const intl = useIntl();
@@ -31,12 +21,11 @@ function OnboardingSurvey() {
const originOptions: string[] = useConstant(() => [
intl.formatMessage({ id: 'tenant.origin.radio.browserSearch.label' }),
- intl.formatMessage({ id: 'tenant.origin.radio.linkedIn.label' }),
- intl.formatMessage({ id: 'tenant.origin.radio.referral.label' }),
- intl.formatMessage({ id: 'tenant.origin.radio.youTube.label' }),
- intl.formatMessage({ id: 'tenant.origin.radio.email.label' }),
- intl.formatMessage({ id: 'tenant.origin.radio.gitHub.label' }),
+ intl.formatMessage({ id: 'tenant.origin.radio.socialMedia.label' }),
intl.formatMessage({ id: 'tenant.origin.radio.paidAdvertising.label' }),
+ intl.formatMessage({ id: 'tenant.origin.radio.content.label' }),
+ intl.formatMessage({ id: 'tenant.origin.radio.referral.label' }),
+ intl.formatMessage({ id: 'tenant.origin.radio.webinar.label' }),
surveyOptionOther,
]);
@@ -57,38 +46,47 @@ function OnboardingSurvey() {
};
return (
-
-
+
+
- {originOptions.map((option, index) => (
- }
- label={option}
- />
- ))}
-
-
-
- handlers.updateSurveyDetails(event.target.value)
- }
+ row
sx={{
- 'maxWidth': 400,
- 'ml': 3,
- '& .MuiInputBase-root': { borderRadius: 3 },
+ ...hiddenButAccessibleRadio,
+ 'gap': 1,
+ '& .MuiFormControlLabel-root': {
+ ml: 0,
+ mr: 0,
+ },
+ '& .MuiChip-root': {
+ p: 1,
+ },
}}
- />
+ >
+ {originOptions.map((option, index) => {
+ return (
+
+ );
+ })}
+
);
}
diff --git a/src/directives/Onboard/Survey/types.ts b/src/directives/Onboard/Survey/types.ts
new file mode 100644
index 0000000000..4bd5fd183d
--- /dev/null
+++ b/src/directives/Onboard/Survey/types.ts
@@ -0,0 +1,3 @@
+export interface OriginOptionProps {
+ optionLabel: string;
+}
diff --git a/src/directives/types.ts b/src/directives/types.ts
index d5a7b47db8..2c398a3076 100644
--- a/src/directives/types.ts
+++ b/src/directives/types.ts
@@ -14,6 +14,11 @@ export interface Directives {
storageMappings: DirectiveSettings;
}
+export interface ActionsProps {
+ primaryMessageId: string;
+ saving: boolean;
+}
+
export type DirectiveStates =
| 'unfulfilled'
| 'in progress'
@@ -61,6 +66,9 @@ export interface DirectiveSettings {
calculateStatus: (
appliedDirective?: AppliedDirective | null
) => DirectiveStates;
+ // TODO (RegistrationProgress) - we need to know if a directive was used during the current session (this can be just in memory)
+ // so we need to store off if the user used something. That way we know which directive is which step in the process.
+ // updatedThisSession: boolean;
}
export interface DirectiveProps {
diff --git a/src/lang/en-US/Authentication.ts b/src/lang/en-US/Authentication.ts
index 2796fd9b18..fe5b09d364 100644
--- a/src/lang/en-US/Authentication.ts
+++ b/src/lang/en-US/Authentication.ts
@@ -24,8 +24,9 @@ export const Authentication: Record = {
'login.sso.back': `Back to Sign In`,
'login.sso.header': `Enter your company email to access ${CommonMessages.productName} via Single Sign-On.`,
- 'login.sso.register.message.help': `To register with Single Sign-On {docLink}.`,
- 'login.sso.register.message.help.docLink': `${CTAs['cta.contactUs']}`,
+ 'login.sso.separator': `Or to register with Single Sign-On`,
+
+ 'login.sso.register.message.help': `${CTAs['cta.contactUs']}`,
'login.sso.register.message.help.docPath': `${Navigation['helpMenu.contact.link']}`,
'login.sso.message.help': `To enable Single Sign-On on your account {docLink}.`,
@@ -56,6 +57,8 @@ export const Authentication: Record = {
'login.registerFailed.github': 'Failed to register with GitHub',
'login.userNotFound': 'User not found. Please sign up below.',
+ 'login.progress.indicator': 'Step {step} of {totalSteps}',
+
'login.marketPlace.loggedOut': `To apply marketplace subscription, please login below.`,
// Legal
@@ -72,7 +75,6 @@ export const Authentication: Record = {
'legal.error.failedToFetch.message': `There was an issue while checking if you have accepted the latest {privacy} and {terms}.`,
// Tenant
- 'tenant.heading': `Let's get started`,
'tenant.message.1': `The organization name will be used as a prefix for everything you create within Estuary. It will only be public if you share data with other organizations.`,
'tenant.expectations': `You can use ${CommonMessages['catalogName.limitations']}`,
@@ -80,19 +82,21 @@ export const Authentication: Record = {
'tenant.input.label': `Organization Name`,
'tenant.input.placeholder': `acmeCo`,
- 'tenant.errorMessage.empty': `You must provide a name before continuing.`,
+ 'tenant.errorMessage.empty': `You must provide an organization name before continuing.`,
'tenant.docs.message': `To see a detailed explanation please view our {link}`,
'tenant.docs.message.link': `https://docs.estuary.dev/concepts/catalogs/#namespace`,
- 'tenant.origin.radioGroup.label': `How'd you hear about us?`,
- 'tenant.origin.radio.browserSearch.label': `Search (Google, Bing, etc.)`,
- 'tenant.origin.radio.linkedIn.label': `LinkedIn`,
- 'tenant.origin.radio.referral.label': `Referral by a Partner`,
- 'tenant.origin.radio.youTube.label': `YouTube`,
- 'tenant.origin.radio.email.label': `Email`,
- 'tenant.origin.radio.gitHub.label': `GitHub`,
- 'tenant.origin.radio.paidAdvertising.label': `Paid Advertising`,
+ 'tenant.customer.quote': `We're a big fan of Estuary's real-time, no code model. It's magic that we're getting real time data without much effort and we don't have to spend time thinking about broken pipelines. We've also experienced fantastic support!`,
+
+ 'tenant.origin.radioGroup.label': `Where did you hear about ${CommonMessages.company}?`,
+
+ 'tenant.origin.radio.browserSearch.label': `Google / Search Engine`,
+ 'tenant.origin.radio.socialMedia.label': `Social Media`,
+ 'tenant.origin.radio.paidAdvertising.label': `Online Ads`,
+ 'tenant.origin.radio.content.label': `Blog`,
+ 'tenant.origin.radio.referral.label': `Word of Mouth`,
+ 'tenant.origin.radio.webinar.label': `Webinar`,
'tenant.origin.radio.other.label': `Other`,
'tenant.grantDirective.header': `Tenant shared with you`,
diff --git a/src/lang/en-US/CTAs.ts b/src/lang/en-US/CTAs.ts
index 49608fac7a..b0cf2c1ea7 100644
--- a/src/lang/en-US/CTAs.ts
+++ b/src/lang/en-US/CTAs.ts
@@ -11,6 +11,7 @@ export const CTAs: Record = {
'cta.logout': `Logout`,
'cta.materialize': `Materialize`,
'cta.register': `Sign up`,
+ 'cta.registerFinish': `Complete Registration`,
'cta.resetPassword': `Reset Password`,
'cta.magicLink': `Sign in with magic link`,
'cta.verifyOTP': `Sign in with OTP`,
diff --git a/src/pages/login/HeaderMessage.tsx b/src/pages/login/HeaderMessage.tsx
new file mode 100644
index 0000000000..4a04f017db
--- /dev/null
+++ b/src/pages/login/HeaderMessage.tsx
@@ -0,0 +1,25 @@
+import { Stack, Typography } from '@mui/material';
+import Logo from 'components/navigation/Logo';
+import { FormattedMessage } from 'react-intl';
+import { HeaderMessageProps } from './types';
+
+function HeaderMessage({ isRegister, headerMessageId }: HeaderMessageProps) {
+ return (
+
+
+
+
+
+
+
+ );
+}
+
+export default HeaderMessage;
diff --git a/src/pages/login/Wrapper.tsx b/src/pages/login/Wrapper.tsx
index 8cde6c0092..e78b5936de 100644
--- a/src/pages/login/Wrapper.tsx
+++ b/src/pages/login/Wrapper.tsx
@@ -1,21 +1,13 @@
-import { Button, Stack, Typography } from '@mui/material';
+import { Button, Stack } from '@mui/material';
import { unauthenticatedRoutes } from 'app/routes';
import FullPageDialog from 'components/fullPage/Dialog';
-import Logo from 'components/navigation/Logo';
import useLoginBodyClass from 'hooks/login/useLoginBodyClass';
import { NavArrowLeft } from 'iconoir-react';
import { FormattedMessage } from 'react-intl';
-import { BaseComponentProps } from 'types';
+import HeaderMessage from './HeaderMessage';
import RegisterPerk from './Perk';
import LoginTabs from './Tabs';
-
-interface Props extends BaseComponentProps {
- isRegister: boolean;
- tabIndex: number;
- handleChange?: (event: any, val: any) => void;
- headerMessageId?: string;
- showBack?: boolean;
-}
+import { LoginWrapperProps } from './types';
const LoginWrapper = ({
children,
@@ -24,7 +16,7 @@ const LoginWrapper = ({
showBack,
tabIndex,
headerMessageId,
-}: Props) => {
+}: LoginWrapperProps) => {
useLoginBodyClass();
return (
@@ -48,20 +40,10 @@ const LoginWrapper = ({
-
-
- {/*Using h1 as this is the "most important" text on the page and might help with SEO*/}
-
-
-
-
+
{isRegister ? (
void;
+ headerMessageId?: string;
+ showBack?: boolean;
+}
+
+export type HeaderMessageProps = Pick<
+ LoginWrapperProps,
+ 'isRegister' | 'headerMessageId'
+>;
diff --git a/src/services/gtm.ts b/src/services/gtm.ts
index 421d0488a7..27ace26b19 100644
--- a/src/services/gtm.ts
+++ b/src/services/gtm.ts
@@ -3,7 +3,11 @@ import { getGoogleTageManagerSettings } from 'utils/env-utils';
// GTM is loaded/initialized in index.html
-type EVENTS = 'Connector_Search' | 'Register' | 'Payment_Entered';
+type EVENTS =
+ | 'Connector_Search'
+ | 'Register'
+ | 'RegisterFailed'
+ | 'Payment_Entered';
const { allowedToRun } = getGoogleTageManagerSettings();
diff --git a/src/services/logrocket.ts b/src/services/logrocket.ts
index 4b4eff6166..e8a7583ee9 100644
--- a/src/services/logrocket.ts
+++ b/src/services/logrocket.ts
@@ -2,6 +2,7 @@ import { User } from '@supabase/supabase-js';
import { includeKeys } from 'filter-obj';
import { isEmpty } from 'lodash';
import LogRocket from 'logrocket';
+import setupLogRocketReact from 'logrocket-react';
import {
DEFAULT_FILTER,
getUserDetails,
@@ -201,6 +202,7 @@ export const initLogRocket = () => {
}
LogRocket.init(logRocketSettings.appID, settings);
+ setupLogRocketReact(LogRocket);
}
};