diff --git a/packages/frontend-2/components/auth/LoginWithEmailBlock.vue b/packages/frontend-2/components/auth/LoginWithEmailBlock.vue index 748743f83..9e2dbf8f8 100644 --- a/packages/frontend-2/components/auth/LoginWithEmailBlock.vue +++ b/packages/frontend-2/components/auth/LoginWithEmailBlock.vue @@ -12,6 +12,7 @@ show-label :disabled="!!(loading || shouldForceInviteEmail)" auto-focus + autocomplete="email" /> diff --git a/packages/frontend-2/components/auth/RegisterWithEmailBlock.vue b/packages/frontend-2/components/auth/RegisterWithEmailBlock.vue index 4949acc51..2b339b982 100644 --- a/packages/frontend-2/components/auth/RegisterWithEmailBlock.vue +++ b/packages/frontend-2/components/auth/RegisterWithEmailBlock.vue @@ -13,6 +13,7 @@ :rules="emailRules" show-label :disabled="isEmailDisabled" + autocomplete="email" /> diff --git a/packages/frontend-2/components/auth/VerificationReminderMenuNotice.vue b/packages/frontend-2/components/auth/VerificationReminderMenuNotice.vue deleted file mode 100644 index 3c0df1c75..000000000 --- a/packages/frontend-2/components/auth/VerificationReminderMenuNotice.vue +++ /dev/null @@ -1,113 +0,0 @@ - - diff --git a/packages/frontend-2/components/auth/sso/Register.vue b/packages/frontend-2/components/auth/sso/Register.vue index 14f3756b5..3c638ce2f 100644 --- a/packages/frontend-2/components/auth/sso/Register.vue +++ b/packages/frontend-2/components/auth/sso/Register.vue @@ -39,7 +39,7 @@ import { useQuery } from '@vue/apollo-composable' const route = useRoute() const loading = ref(false) -const newsletterConsent = ref(undefined) +const newsletterConsent = ref(false) const { challenge } = useLoginOrRegisterUtils() const { signInOrSignUpWithSso } = useAuthManager() diff --git a/packages/frontend-2/components/header/Empty.vue b/packages/frontend-2/components/header/Empty.vue new file mode 100644 index 000000000..8e34c5b93 --- /dev/null +++ b/packages/frontend-2/components/header/Empty.vue @@ -0,0 +1,14 @@ + diff --git a/packages/frontend-2/components/header/LogoBlock.vue b/packages/frontend-2/components/header/LogoBlock.vue index 8d19559cf..c9ddf3881 100644 --- a/packages/frontend-2/components/header/LogoBlock.vue +++ b/packages/frontend-2/components/header/LogoBlock.vue @@ -1,7 +1,7 @@ diff --git a/packages/frontend-2/pages/verify-email.vue b/packages/frontend-2/pages/verify-email.vue new file mode 100644 index 000000000..f8c6d63b3 --- /dev/null +++ b/packages/frontend-2/pages/verify-email.vue @@ -0,0 +1,183 @@ + + + diff --git a/packages/server/assets/emails/templates/components/footer.mjml b/packages/server/assets/emails/templates/components/footer.mjml index 40b35e764..efb333941 100644 --- a/packages/server/assets/emails/templates/components/footer.mjml +++ b/packages/server/assets/emails/templates/components/footer.mjml @@ -18,7 +18,7 @@ - + Brought to you by Speckle , the Open Source Data Platform for 3D Data. Follow Us diff --git a/packages/server/assets/emails/templates/components/headerLogo.mjml b/packages/server/assets/emails/templates/components/headerLogo.mjml index 0bf3640f5..383d1750f 100644 --- a/packages/server/assets/emails/templates/components/headerLogo.mjml +++ b/packages/server/assets/emails/templates/components/headerLogo.mjml @@ -1,13 +1,8 @@ - - - - - diff --git a/packages/server/assets/public/speckle-email-logo.png b/packages/server/assets/public/speckle-email-logo.png new file mode 100644 index 000000000..79aef8d15 Binary files /dev/null and b/packages/server/assets/public/speckle-email-logo.png differ diff --git a/packages/server/modules/emails/services/verification/request.ts b/packages/server/modules/emails/services/verification/request.ts index 87347ac28..5547b33cb 100644 --- a/packages/server/modules/emails/services/verification/request.ts +++ b/packages/server/modules/emails/services/verification/request.ts @@ -101,33 +101,17 @@ const createNewEmailVerificationFactory = } function buildMjmlBody(verificationCode: string) { - const bodyStart = `Hello,

You have just registered to the Speckle server, or initiated the email verification process manually. To finalize the verification process, use the code below.
` - const bodyEnd = `This code expires in 5 minutes:
-${verificationCode} -
- If the code does not work, please proceed by

- - Logging in with your e-mail address and password - Clicking on the Notification icon - Selecting "Send Verification" - Verifying your e-mail address by using the new code -
- - See you soon,
- Speckle -
- ` - - return { bodyStart, bodyEnd } + const bodyStart = `

You have just registered to the Speckle server, or initiated the email verification process manually. To finalize the verification process, use the code below.

+ ${verificationCode} +

This code will expire in 5 minutes. Please do not disclose this code to others.

+

If you did not make this request, please disregard this email.

+

See you soon,
Speckle

` + return { bodyStart } } -function buildTextBody(verificationCode: string) { - const bodyStart = `Hello,\n\nYou have just registered to the Speckle server, or initiated the email verification process manually. To finalize the verification process, use the code below:` - const bodyEnd = `This code expires in 5 minutes: -${verificationCode} -\r\n -If the code does not work, please proceed by logging in to your Speckle account with your e-mail address and password, clicking the Notification icon, selecting "Send Verification" and verifying your e-mail address by new code.\n\nSee you soon,\nSpeckle - ` +function buildTextBody() { + const bodyStart = `` + const bodyEnd = `` return { bodyStart, bodyEnd } } @@ -135,7 +119,7 @@ If the code does not work, please proceed by logging in to your Speckle account function buildEmailTemplateParams(verificationCode: string): EmailTemplateParams { return { mjml: buildMjmlBody(verificationCode), - text: buildTextBody(verificationCode) + text: buildTextBody() } } diff --git a/packages/ui-components/src/components/form/CodeInput.stories.ts b/packages/ui-components/src/components/form/CodeInput.stories.ts new file mode 100644 index 000000000..4ac6da267 --- /dev/null +++ b/packages/ui-components/src/components/form/CodeInput.stories.ts @@ -0,0 +1,90 @@ +import type { Meta, StoryObj } from '@storybook/vue3' +import FormCodeInput from '~~/src/components/form/CodeInput.vue' + +type StoryType = StoryObj< + Record & { + 'update:modelValue': (val: string) => void + complete: (val: string) => void + } +> + +export default { + component: FormCodeInput, + parameters: { + docs: { + description: { + component: + 'A verification code input component that handles digit-by-digit entry with auto-advance and paste support.' + } + } + }, + argTypes: { + 'update:modelValue': { + type: 'function', + action: 'v-model' + }, + complete: { + type: 'function', + action: 'complete' + }, + digitCount: { + control: { type: 'number' } + } + } +} as Meta + +export const Default: StoryType = { + render: (args, ctx) => ({ + components: { FormCodeInput }, + setup: () => ({ args }), + template: ` +
+ +
+ `, + methods: { + onModelUpdate(val: string) { + args['update:modelValue'](val) + ctx.updateArgs({ ...args, modelValue: val }) + } + } + }), + args: { + modelValue: '', + digitCount: 6, + disabled: false, + errorMessage: '', + error: false, + complete: (val: string) => console.log('Complete:', val) + } +} + +export const Disabled: StoryType = { + ...Default, + args: { + ...Default.args, + disabled: true, + modelValue: '123456' + } +} + +export const DifferentLength: StoryType = { + ...Default, + args: { + ...Default.args, + digitCount: 4 + } +} + +export const WithError: StoryType = { + ...Default, + args: { + ...Default.args, + error: true, + modelValue: '123456' + } +} diff --git a/packages/ui-components/src/components/form/CodeInput.vue b/packages/ui-components/src/components/form/CodeInput.vue new file mode 100644 index 000000000..517221745 --- /dev/null +++ b/packages/ui-components/src/components/form/CodeInput.vue @@ -0,0 +1,151 @@ + + + diff --git a/packages/ui-components/src/components/form/TextInput.vue b/packages/ui-components/src/components/form/TextInput.vue index 2eecce44e..99f215459 100644 --- a/packages/ui-components/src/components/form/TextInput.vue +++ b/packages/ui-components/src/components/form/TextInput.vue @@ -358,12 +358,6 @@ const leadingIconClasses = computed(() => { const iconClasses = computed((): string => { const classParts: string[] = [] - if (props.customIcon) { - classParts.push('pl-8') - } else { - classParts.push('pl-2') - } - if (!slots['input-right']) { if (props.rightIcon || errorMessage.value || shouldShowClear.value) { classParts.push('pr-8') diff --git a/packages/ui-components/src/components/form/select/Multi.vue b/packages/ui-components/src/components/form/select/Multi.vue index 0fd02da70..e1f3ba7fc 100644 --- a/packages/ui-components/src/components/form/select/Multi.vue +++ b/packages/ui-components/src/components/form/select/Multi.vue @@ -132,7 +132,9 @@ -
+
@@ -162,7 +164,6 @@

): void diff --git a/packages/ui-components/src/composables/form/textInput.ts b/packages/ui-components/src/composables/form/textInput.ts index e33be00e6..692e638e5 100644 --- a/packages/ui-components/src/composables/form/textInput.ts +++ b/packages/ui-components/src/composables/form/textInput.ts @@ -91,7 +91,7 @@ export function useTextInputCore(params: { const color = unref(props.color) if (color === 'foundation') { classParts.push( - 'bg-foundation !border border-outline-2 hover:border-outline-5 focus-visible:border-outline-4 !ring-0 focus-visible:!outline-0 !text-[13px]' + 'bg-foundation !border border-outline-2 hover:border-outline-5 focus-visible:border-outline-4 !ring-0 focus-visible:!outline-0' ) } else if (color === 'transparent') { classParts.push('bg-transparent') diff --git a/packages/ui-components/src/helpers/global/toast.ts b/packages/ui-components/src/helpers/global/toast.ts index 4c070cf69..ef7fead14 100644 --- a/packages/ui-components/src/helpers/global/toast.ts +++ b/packages/ui-components/src/helpers/global/toast.ts @@ -2,7 +2,8 @@ export enum ToastNotificationType { Success, Warning, Danger, - Info + Info, + Loading } export type ToastNotification = { diff --git a/packages/ui-components/src/lib.ts b/packages/ui-components/src/lib.ts index 5cf4c3fb2..2919200f4 100644 --- a/packages/ui-components/src/lib.ts +++ b/packages/ui-components/src/lib.ts @@ -35,6 +35,7 @@ import FormSelectBadges from '~~/src/components/form/select/Badges.vue' import FormSelectMulti from '~~/src/components/form/select/Multi.vue' import FormSwitch from '~~/src/components/form/Switch.vue' import FormClipboardInput from '~~/src/components/form/ClipboardInput.vue' +import FormCodeInput from '~~/src/components/form/CodeInput.vue' import CommonLoadingBar from '~~/src/components/common/loading/Bar.vue' import SourceAppBadge from '~~/src/components/SourceAppBadge.vue' import { onKeyboardShortcut, useFormCheckboxModel } from '~~/src/composables/form/input' @@ -130,6 +131,7 @@ export { FormTextInput, FormSwitch, FormClipboardInput, + FormCodeInput, ValidationHelpers, useWrappingContainerHiddenCount, useFormSelectChildInternals,