web/satellite: move register page to composition api

This change updates RegisterArea.vue to use the composition API.

Issue: https://github.com/storj/storj/issues/5059

Change-Id: Ieea65731cd76a9e98282f23aed90e625c6d09387
This commit is contained in:
Wilfred Asomani 2023-03-14 08:48:19 +00:00 committed by Storj Robot
parent b95ef36541
commit 61af5b3191

View File

@ -278,10 +278,10 @@
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
<script setup lang="ts">
import VueRecaptcha from 'vue-recaptcha';
import VueHcaptcha from '@hcaptcha/vue-hcaptcha';
import { computed, onBeforeMount, ref } from 'vue';
import BottomArrowIcon from '../../../static/images/common/lightBottomArrow.svg';
import SelectedCheckIcon from '../../../static/images/common/selectedCheck.svg';
@ -295,6 +295,7 @@ import { User } from '@/types/users';
import { MetaUtils } from '@/utils/meta';
import { Validator } from '@/utils/validation';
import { AnalyticsHttpApi } from '@/api/analytics';
import { useNotify, useRoute, useRouter, useStore } from '@/utils/hooks';
import SelectInput from '@/components/common/SelectInput.vue';
import PasswordStrength from '@/components/common/PasswordStrength.vue';
@ -316,467 +317,448 @@ type ViewConfig = {
tooltip: string;
}
// @vue/component
@Component({
components: {
VInput,
VButton,
BottomArrowIcon,
SelectedCheckIcon,
LogoIcon,
PasswordStrength,
AddCouponCodeInput,
SelectInput,
VueRecaptcha,
VueHcaptcha,
LogoWithPartnerIcon,
RegisterGlobe,
InfoIcon,
},
})
export default class RegisterArea extends Vue {
private readonly user = new User();
private viewConfig: ViewConfig;
const user = ref(new User());
const viewConfig = ref<ViewConfig | null>(null);
// DCS logic
private secret = '';
// DCS logic
const secret = ref('');
private isTermsAccepted = false;
private password = '';
private repeatedPassword = '';
const isTermsAccepted = ref(false);
const password = ref('');
const repeatedPassword = ref('');
// Only for beta sats (like US2).
private areBetaTermsAccepted = false;
private areBetaTermsAcceptedError = false;
// Only for beta sats (like US2).
const areBetaTermsAccepted = ref(false);
const areBetaTermsAcceptedError = ref(false);
private fullNameError = '';
private emailError = '';
private passwordError = '';
private repeatedPasswordError = '';
private companyNameError = '';
private employeeCountError = '';
private positionError = '';
private isTermsAcceptedError = false;
private isLoading = false;
private isProfessional = false;
private haveSalesContact = false;
const fullNameError = ref('');
const emailError = ref('');
const passwordError = ref('');
const repeatedPasswordError = ref('');
const companyNameError = ref('');
const employeeCountError = ref('');
const positionError = ref('');
const isTermsAcceptedError = ref(false);
const isLoading = ref(false);
const isProfessional = ref(false);
const haveSalesContact = ref(false);
private captchaError = false;
private captchaResponseToken = '';
const captchaError = ref(false);
const captchaResponseToken = ref('');
private readonly auth: AuthHttpApi = new AuthHttpApi();
const recaptchaEnabled: boolean = MetaUtils.getMetaContent('registration-recaptcha-enabled') === 'true';
const recaptchaSiteKey: string = MetaUtils.getMetaContent('registration-recaptcha-site-key');
const hcaptchaEnabled: boolean = MetaUtils.getMetaContent('registration-hcaptcha-enabled') === 'true';
const hcaptchaSiteKey: string = MetaUtils.getMetaContent('registration-hcaptcha-site-key');
private readonly recaptchaEnabled: boolean = MetaUtils.getMetaContent('registration-recaptcha-enabled') === 'true';
private readonly recaptchaSiteKey: string = MetaUtils.getMetaContent('registration-recaptcha-site-key');
private readonly hcaptchaEnabled: boolean = MetaUtils.getMetaContent('registration-hcaptcha-enabled') === 'true';
private readonly hcaptchaSiteKey: string = MetaUtils.getMetaContent('registration-hcaptcha-site-key');
const isPasswordStrengthShown = ref(false);
public isPasswordStrengthShown = false;
// DCS logic
const isDropdownShown = ref(false);
// DCS logic
public isDropdownShown = false;
// Employee Count dropdown options
const employeeCountOptions = ['1-50', '51-1000', '1001+'];
// Employee Count dropdown options
public employeeCountOptions = ['1-50', '51-1000', '1001+'];
const loginPath = RouteConfig.Login.path;
public readonly loginPath: string = RouteConfig.Login.path;
const captcha = ref<VueRecaptcha | VueHcaptcha | null>(null);
public $refs!: {
captcha: VueRecaptcha | VueHcaptcha;
};
const analytics = new AnalyticsHttpApi();
const auth = new AuthHttpApi();
const notify = useNotify();
const router = useRouter();
const store = useStore();
const route = useRoute();
public readonly analytics: AnalyticsHttpApi = new AnalyticsHttpApi();
/**
* Lifecycle hook before initial render.
* Sets up variables from route params and loads config.
*/
onBeforeMount(() => {
if (route.query.token) {
secret.value = route.query.token.toString();
}
/**
* Lifecycle hook before initial render.
* Sets up variables from route params and loads config.
*/
public beforeMount(): void {
if (this.$route.query.token) {
this.secret = this.$route.query.token.toString();
if (route.query.partner) {
user.value.partner = route.query.partner.toString();
}
if (route.query.promo) {
user.value.signupPromoCode = route.query.promo.toString();
}
try {
const config = require('@/views/registration/registrationViewConfig.json');
viewConfig.value = user.value.partner && config[user.value.partner] ? config[user.value.partner] : config['default'];
} catch (e) {
notify.error('No configuration file for registration page.', null);
}
});
/**
* Redirects to chosen satellite.
*/
function clickSatellite(address): void {
window.location.href = address;
}
/**
* Toggles satellite selection dropdown visibility (Tardigrade).
*/
function toggleDropdown(): void {
isDropdownShown.value = !isDropdownShown.value;
}
/**
* Closes satellite selection dropdown (Tardigrade).
*/
function closeDropdown(): void {
isDropdownShown.value = false;
}
/**
* Makes password strength container visible.
*/
function showPasswordStrength(): void {
isPasswordStrengthShown.value = true;
}
/**
* Hides password strength container.
*/
function hidePasswordStrength(): void {
isPasswordStrengthShown.value = false;
}
/**
* Validates input fields and proceeds user creation.
*/
async function onCreateClick(): Promise<void> {
if (isLoading.value && !isDropdownShown.value) {
return;
}
let activeElement = document.activeElement;
if (activeElement && activeElement.id === 'registerDropdown') return;
if (isDropdownShown.value) {
isDropdownShown.value = false;
return;
}
await createUser();
}
/**
* Redirects to storj.io homepage.
*/
function onLogoClick(): void {
window.location.href = MetaUtils.getMetaContent('homepage-url');
}
/**
* Sets user's email field from value string.
*/
function setEmail(value: string): void {
user.value.email = value.trim();
emailError.value = '';
}
/**
* Sets user's full name field from value string.
*/
function setFullName(value: string): void {
user.value.fullName = value.trim();
fullNameError.value = '';
}
/**
* Sets user's password field from value string.
*/
function setPassword(value: string): void {
user.value.password = value;
password.value = value;
passwordError.value = '';
}
/**
* Sets user's repeat password field from value string.
*/
function setRepeatedPassword(value: string): void {
repeatedPassword.value = value;
repeatedPasswordError.value = '';
}
/**
* Name of the current satellite.
*/
const satelliteName = computed((): string => {
return store.state.appStateModule.satelliteName;
});
/**
* Information about partnered satellites, including name and signup link.
*/
const partneredSatellites = computed((): PartneredSatellite[] => {
const satellites = store.state.appStateModule.partneredSatellites;
return satellites.map((s: PartneredSatellite) => {
s.address = `${s.address}/signup`;
if (user.value.partner) {
s.address = `${s.address}?partner=${user.value.partner}`;
}
if (this.$route.query.partner) {
this.user.partner = this.$route.query.partner.toString();
}
return s;
});
});
if (this.$route.query.promo) {
this.user.signupPromoCode = this.$route.query.promo.toString();
}
/**
* Indicates if satellite is in beta.
*/
const isBetaSatellite = computed((): boolean => {
return store.state.appStateModule.isBetaSatellite;
});
try {
const config = require('@/views/registration/registrationViewConfig.json');
this.viewConfig = this.user.partner && config[this.user.partner] ? config[this.user.partner] : config['default'];
} catch (e) {
this.$notify.error('No configuration file for registration page.', null);
}
}
/**
* Indicates if coupon code ui is enabled
*/
const couponCodeSignupUIEnabled = computed((): boolean => {
return store.state.appStateModule.couponCodeSigunpUIEnabled;
});
/**
* Redirects to chosen satellite.
*/
public clickSatellite(address): void {
window.location.href = address;
}
/**
* Sets user's company name field from value string.
*/
function setCompanyName(value: string): void {
user.value.companyName = value.trim();
companyNameError.value = '';
}
/**
* Toggles satellite selection dropdown visibility (Tardigrade).
*/
public toggleDropdown(): void {
this.isDropdownShown = !this.isDropdownShown;
}
/**
* Sets user's company size field from value string.
*/
function setEmployeeCount(value: string): void {
user.value.employeeCount = value;
employeeCountError.value = '';
}
/**
* Closes satellite selection dropdown (Tardigrade).
*/
public closeDropdown(): void {
this.isDropdownShown = false;
}
/**
* Sets user's position field from value string.
*/
function setPosition(value: string): void {
user.value.position = value.trim();
positionError.value = '';
}
/**
* Makes password strength container visible.
*/
public showPasswordStrength(): void {
this.isPasswordStrengthShown = true;
}
/**
* toggle user account type
*/
function toggleAccountType(value: boolean): void {
isProfessional.value = value;
}
/**
* Hides password strength container.
*/
public hidePasswordStrength(): void {
this.isPasswordStrengthShown = false;
}
/**
* Handles captcha verification response.
*/
function onCaptchaVerified(response: string): void {
captchaResponseToken.value = response;
captchaError.value = false;
createUser();
}
/**
* Validates input fields and proceeds user creation.
*/
public async onCreateClick(): Promise<void> {
if (this.isLoading && !this.isDropdownShown) {
return;
}
/**
* Handles captcha error.
*/
function onCaptchaError(): void {
captchaResponseToken.value = '';
notify.error('The captcha encountered an error. Please try again.', null);
}
let activeElement = document.activeElement;
if (activeElement && activeElement.id === 'registerDropdown') return;
if (this.isDropdownShown) {
this.isDropdownShown = false;
return;
}
await this.createUser();
}
/**
* Redirects to storj.io homepage.
*/
public onLogoClick(): void {
window.location.href = MetaUtils.getMetaContent('homepage-url');
}
/**
* Sets user's email field from value string.
*/
public setEmail(value: string): void {
this.user.email = value.trim();
this.emailError = '';
}
/**
* Sets user's full name field from value string.
*/
public setFullName(value: string): void {
this.user.fullName = value.trim();
this.fullNameError = '';
}
/**
* Sets user's password field from value string.
*/
public setPassword(value: string): void {
this.user.password = value;
this.password = value;
this.passwordError = '';
}
/**
* Sets user's repeat password field from value string.
*/
public setRepeatedPassword(value: string): void {
this.repeatedPassword = value;
this.repeatedPasswordError = '';
}
/**
* Name of the current satellite.
*/
public get satelliteName(): string {
return this.$store.state.appStateModule.satelliteName;
}
/**
* Information about partnered satellites, including name and signup link.
*/
public get partneredSatellites(): PartneredSatellite[] {
const satellites = this.$store.state.appStateModule.partneredSatellites;
return satellites.map((s: PartneredSatellite) => {
s.address = `${s.address}/signup`;
if (this.user.partner) {
s.address = `${s.address}?partner=${this.user.partner}`;
}
return s;
});
}
/**
* Indicates if satellite is in beta.
*/
public get isBetaSatellite(): boolean {
return this.$store.state.appStateModule.isBetaSatellite;
}
/**
* Indicates if coupon code ui is enabled
*/
public get couponCodeSignupUIEnabled(): boolean {
return this.$store.state.appStateModule.couponCodeSigunpUIEnabled;
}
/**
* Sets user's company name field from value string.
*/
public setCompanyName(value: string): void {
this.user.companyName = value.trim();
this.companyNameError = '';
}
/**
* Sets user's company size field from value string.
*/
public setEmployeeCount(value: string): void {
this.user.employeeCount = value;
this.employeeCountError = '';
}
/**
* Sets user's position field from value string.
*/
public setPosition(value: string): void {
this.user.position = value.trim();
this.positionError = '';
}
/**
* toggle user account type
*/
public toggleAccountType(value: boolean): void {
this.isProfessional = value;
}
/**
* Handles captcha verification response.
*/
public onCaptchaVerified(response: string): void {
this.captchaResponseToken = response;
this.captchaError = false;
this.createUser();
}
/**
* Handles captcha error.
*/
public onCaptchaError(): void {
this.captchaResponseToken = '';
this.$notify.error('The captcha encountered an error. Please try again.', null);
}
/**
* Executes when the Terms of Service checkbox has been toggled.
*/
public onTermsAcceptedToggled(event: KeyboardEvent): void {
if (event.key === ' ' || event.code === 'Space' || event.keyCode === 32) {
const checkbox = ((event.target as HTMLElement).parentElement as HTMLLabelElement).control as HTMLInputElement;
checkbox.checked = !checkbox.checked;
checkbox.setAttribute('checked', String(checkbox.checked));
this.isTermsAccepted = checkbox.checked;
this.isTermsAcceptedError = false;
} else {
this.isTermsAccepted = (event.target as HTMLInputElement).checked;
this.isTermsAcceptedError = false;
}
}
/**
* Executes when the beta satellite terms checkbox has been toggled.
*/
public onBetaTermsAcceptedToggled(event: KeyboardEvent): void {
if (event.key === ' ' || event.code === 'Space' || event.keyCode === 32) {
const checkbox = ((event.target as HTMLElement).parentElement as HTMLLabelElement).control as HTMLInputElement;
checkbox.checked = !checkbox.checked;
checkbox.setAttribute('checked', String(checkbox.checked));
this.areBetaTermsAccepted = checkbox.checked;
this.isTermsAcceptedError = false;
} else {
this.areBetaTermsAccepted = (event.target as HTMLInputElement).checked;
this.areBetaTermsAcceptedError = false;
}
}
/**
* Executes when the space bar is pressed on a focused checkbox.
*/
public toggleCheckbox(event: Event): void {
/**
* Executes when the Terms of Service checkbox has been toggled.
*/
function onTermsAcceptedToggled(event: KeyboardEvent): void {
if (event.key === ' ' || event.code === 'Space' || event.keyCode === 32) {
const checkbox = ((event.target as HTMLElement).parentElement as HTMLLabelElement).control as HTMLInputElement;
checkbox.checked = !checkbox.checked;
checkbox.setAttribute('checked', String(checkbox.checked));
isTermsAccepted.value = checkbox.checked;
isTermsAcceptedError.value = false;
} else {
isTermsAccepted.value = (event.target as HTMLInputElement).checked;
isTermsAcceptedError.value = false;
}
/**
* Validates input values to satisfy expected rules.
*/
private validateFields(): boolean {
let isNoErrors = true;
}
if (!this.user.fullName) {
this.fullNameError = 'Name can\'t be empty';
isNoErrors = false;
}
/**
* Executes when the beta satellite terms checkbox has been toggled.
*/
function onBetaTermsAcceptedToggled(event: KeyboardEvent): void {
if (event.key === ' ' || event.code === 'Space' || event.keyCode === 32) {
const checkbox = ((event.target as HTMLElement).parentElement as HTMLLabelElement).control as HTMLInputElement;
if (!this.isEmailValid()) {
this.emailError = 'Invalid Email';
isNoErrors = false;
}
checkbox.checked = !checkbox.checked;
checkbox.setAttribute('checked', String(checkbox.checked));
if (!Validator.password(this.password)) {
this.passwordError = 'Invalid Password';
isNoErrors = false;
}
areBetaTermsAccepted.value = checkbox.checked;
isTermsAcceptedError.value = false;
if (this.isProfessional) {
} else {
areBetaTermsAccepted.value = (event.target as HTMLInputElement).checked;
areBetaTermsAcceptedError.value = false;
}
}
if (!this.user.companyName) {
this.companyNameError = 'No Company Name filled in';
isNoErrors = false;
}
/**
* Executes when the space bar is pressed on a focused checkbox.
*/
function toggleCheckbox(event: Event): void {
const checkbox = ((event.target as HTMLElement).parentElement as HTMLLabelElement).control as HTMLInputElement;
if (!this.user.position) {
this.positionError = 'No Position filled in';
isNoErrors = false;
}
checkbox.checked = !checkbox.checked;
checkbox.setAttribute('checked', String(checkbox.checked));
}
if (!this.user.employeeCount) {
this.employeeCountError = 'No Company Size filled in';
isNoErrors = false;
}
/**
* Validates input values to satisfy expected rules.
*/
function validateFields(): boolean {
let isNoErrors = true;
}
if (this.repeatedPassword !== this.password) {
this.repeatedPasswordError = 'Password doesn\'t match';
isNoErrors = false;
}
if (!this.isTermsAccepted) {
this.isTermsAcceptedError = true;
isNoErrors = false;
}
// only for beta US2 sats.
if (this.isBetaSatellite && !this.areBetaTermsAccepted) {
this.areBetaTermsAcceptedError = true;
isNoErrors = false;
}
if (this.user.partner.length > 100) {
this.$notify.error('Partner must be less than or equal to 100 characters', null);
return false;
}
if (this.user.signupPromoCode.length > 100) {
this.$notify.error('Promo code must be less than or equal to 100 characters', null);
return false;
}
return isNoErrors;
if (!user.value.fullName) {
fullNameError.value = 'Name can\'t be empty';
isNoErrors = false;
}
/**
* Detect if user uses Brave browser
*/
public async detectBraveBrowser(): Promise<boolean> {
return (navigator['brave'] && await navigator['brave'].isBrave() || false);
if (!isEmailValid()) {
emailError.value = 'Invalid Email';
isNoErrors = false;
}
/**
* Validates email string.
* We'll have this email validation for new users instead of using regular Validator.email method because of backwards compatibility.
* We don't want to block old users who managed to create and verify their accounts with some weird email addresses.
*/
private isEmailValid(): boolean {
// This regular expression fulfills our needs to validate international emails.
// It was built according to RFC 5322 and then extended to include international characters using these resources
// https://emailregex.com/
// https://awik.io/international-email-address-validation-javascript/
// eslint-disable-next-line no-misleading-character-class
const regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9\u0080-\u00FF\u0100-\u017F\u0180-\u024F\u0250-\u02AF\u0300-\u036F\u0370-\u03FF\u0400-\u04FF\u0500-\u052F\u0530-\u058F\u0590-\u05FF\u0600-\u06FF\u0700-\u074F\u0750-\u077F\u0780-\u07BF\u07C0-\u07FF\u0900-\u097F\u0980-\u09FF\u0A00-\u0A7F\u0A80-\u0AFF\u0B00-\u0B7F\u0B80-\u0BFF\u0C00-\u0C7F\u0C80-\u0CFF\u0D00-\u0D7F\u0D80-\u0DFF\u0E00-\u0E7F\u0E80-\u0EFF\u0F00-\u0FFF\u1000-\u109F\u10A0-\u10FF\u1100-\u11FF\u1200-\u137F\u1380-\u139F\u13A0-\u13FF\u1400-\u167F\u1680-\u169F\u16A0-\u16FF\u1700-\u171F\u1720-\u173F\u1740-\u175F\u1760-\u177F\u1780-\u17FF\u1800-\u18AF\u1900-\u194F\u1950-\u197F\u1980-\u19DF\u19E0-\u19FF\u1A00-\u1A1F\u1B00-\u1B7F\u1D00-\u1D7F\u1D80-\u1DBF\u1DC0-\u1DFF\u1E00-\u1EFF\u1F00-\u1FFF\u20D0-\u20FF\u2100-\u214F\u2C00-\u2C5F\u2C60-\u2C7F\u2C80-\u2CFF\u2D00-\u2D2F\u2D30-\u2D7F\u2D80-\u2DDF\u2F00-\u2FDF\u2FF0-\u2FFF\u3040-\u309F\u30A0-\u30FF\u3100-\u312F\u3130-\u318F\u3190-\u319F\u31C0-\u31EF\u31F0-\u31FF\u3200-\u32FF\u3300-\u33FF\u3400-\u4DBF\u4DC0-\u4DFF\u4E00-\u9FFF\uA000-\uA48F\uA490-\uA4CF\uA700-\uA71F\uA800-\uA82F\uA840-\uA87F\uAC00-\uD7AF\uF900-\uFAFF]+\.)+[a-zA-Z\u0080-\u00FF\u0100-\u017F\u0180-\u024F\u0250-\u02AF\u0300-\u036F\u0370-\u03FF\u0400-\u04FF\u0500-\u052F\u0530-\u058F\u0590-\u05FF\u0600-\u06FF\u0700-\u074F\u0750-\u077F\u0780-\u07BF\u07C0-\u07FF\u0900-\u097F\u0980-\u09FF\u0A00-\u0A7F\u0A80-\u0AFF\u0B00-\u0B7F\u0B80-\u0BFF\u0C00-\u0C7F\u0C80-\u0CFF\u0D00-\u0D7F\u0D80-\u0DFF\u0E00-\u0E7F\u0E80-\u0EFF\u0F00-\u0FFF\u1000-\u109F\u10A0-\u10FF\u1100-\u11FF\u1200-\u137F\u1380-\u139F\u13A0-\u13FF\u1400-\u167F\u1680-\u169F\u16A0-\u16FF\u1700-\u171F\u1720-\u173F\u1740-\u175F\u1760-\u177F\u1780-\u17FF\u1800-\u18AF\u1900-\u194F\u1950-\u197F\u1980-\u19DF\u19E0-\u19FF\u1A00-\u1A1F\u1B00-\u1B7F\u1D00-\u1D7F\u1D80-\u1DBF\u1DC0-\u1DFF\u1E00-\u1EFF\u1F00-\u1FFF\u20D0-\u20FF\u2100-\u214F\u2C00-\u2C5F\u2C60-\u2C7F\u2C80-\u2CFF\u2D00-\u2D2F\u2D30-\u2D7F\u2D80-\u2DDF\u2F00-\u2FDF\u2FF0-\u2FFF\u3040-\u309F\u30A0-\u30FF\u3100-\u312F\u3130-\u318F\u3190-\u319F\u31C0-\u31EF\u31F0-\u31FF\u3200-\u32FF\u3300-\u33FF\u3400-\u4DBF\u4DC0-\u4DFF\u4E00-\u9FFF\uA000-\uA48F\uA490-\uA4CF\uA700-\uA71F\uA800-\uA82F\uA840-\uA87F\uAC00-\uD7AF\uF900-\uFAFF]{2,}))$/;
return regex.test(this.user.email);
if (!Validator.password(password.value)) {
passwordError.value = 'Invalid Password';
isNoErrors = false;
}
/**
* Creates user and toggles successful registration area visibility.
*/
private async createUser(): Promise<void> {
if (isProfessional.value) {
let activeElement = document.activeElement;
if (activeElement && activeElement.classList.contains('account-tab')) {
return;
if (!user.value.companyName) {
companyNameError.value = 'No Company Name filled in';
isNoErrors = false;
}
if (!this.validateFields()) {
return;
if (!user.value.position) {
positionError.value = 'No Position filled in';
isNoErrors = false;
}
if (this.$refs.captcha && !this.captchaResponseToken) {
this.$refs.captcha.execute();
return;
if (!user.value.employeeCount) {
employeeCountError.value = 'No Company Size filled in';
isNoErrors = false;
}
this.isLoading = true;
this.user.isProfessional = this.isProfessional;
this.user.haveSalesContact = this.haveSalesContact;
try {
await this.auth.register(this.user, this.secret, this.captchaResponseToken);
// Brave browser conversions are tracked via the RegisterSuccess path in the satellite app
// signups outside of the brave browser may use a configured URL to track conversions
// if the URL is not configured, the RegisterSuccess path will be used for non-Brave browsers
const internalRegisterSuccessPath = RouteConfig.RegisterSuccess.path;
const configuredRegisterSuccessPath = MetaUtils.getMetaContent('optional-signup-success-url') || internalRegisterSuccessPath;
const nonBraveSuccessPath = `${configuredRegisterSuccessPath}?email=${encodeURIComponent(this.user.email)}`;
const braveSuccessPath = `${internalRegisterSuccessPath}?email=${encodeURIComponent(this.user.email)}`;
await this.detectBraveBrowser() ? await this.$router.push(braveSuccessPath) : window.location.href = nonBraveSuccessPath;
} catch (error) {
await this.$notify.error(error.message, null);
}
this.$refs.captcha?.reset();
this.captchaResponseToken = '';
this.isLoading = false;
}
if (repeatedPassword.value !== password.value) {
repeatedPasswordError.value = 'Password doesn\'t match';
isNoErrors = false;
}
if (!isTermsAccepted.value) {
isTermsAcceptedError.value = true;
isNoErrors = false;
}
// only for beta US2 sats.
if (isBetaSatellite.value && !areBetaTermsAccepted.value) {
areBetaTermsAcceptedError.value = true;
isNoErrors = false;
}
if (user.value.partner.length > 100) {
notify.error('Partner must be less than or equal to 100 characters', null);
return false;
}
if (user.value.signupPromoCode.length > 100) {
notify.error('Promo code must be less than or equal to 100 characters', null);
return false;
}
return isNoErrors;
}
/**
* Detect if user uses Brave browser
*/
async function detectBraveBrowser(): Promise<boolean> {
return (navigator['brave'] && await navigator['brave'].isBrave() || false);
}
/**
* Validates email string.
* We'll have this email validation for new users instead of using regular Validator.email method because of backwards compatibility.
* We don't want to block old users who managed to create and verify their accounts with some weird email addresses.
*/
function isEmailValid(): boolean {
// This regular expression fulfills our needs to validate international emails.
// It was built according to RFC 5322 and then extended to include international characters using these resources
// https://emailregex.com/
// https://awik.io/international-email-address-validation-javascript/
// eslint-disable-next-line no-misleading-character-class
const regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9\u0080-\u00FF\u0100-\u017F\u0180-\u024F\u0250-\u02AF\u0300-\u036F\u0370-\u03FF\u0400-\u04FF\u0500-\u052F\u0530-\u058F\u0590-\u05FF\u0600-\u06FF\u0700-\u074F\u0750-\u077F\u0780-\u07BF\u07C0-\u07FF\u0900-\u097F\u0980-\u09FF\u0A00-\u0A7F\u0A80-\u0AFF\u0B00-\u0B7F\u0B80-\u0BFF\u0C00-\u0C7F\u0C80-\u0CFF\u0D00-\u0D7F\u0D80-\u0DFF\u0E00-\u0E7F\u0E80-\u0EFF\u0F00-\u0FFF\u1000-\u109F\u10A0-\u10FF\u1100-\u11FF\u1200-\u137F\u1380-\u139F\u13A0-\u13FF\u1400-\u167F\u1680-\u169F\u16A0-\u16FF\u1700-\u171F\u1720-\u173F\u1740-\u175F\u1760-\u177F\u1780-\u17FF\u1800-\u18AF\u1900-\u194F\u1950-\u197F\u1980-\u19DF\u19E0-\u19FF\u1A00-\u1A1F\u1B00-\u1B7F\u1D00-\u1D7F\u1D80-\u1DBF\u1DC0-\u1DFF\u1E00-\u1EFF\u1F00-\u1FFF\u20D0-\u20FF\u2100-\u214F\u2C00-\u2C5F\u2C60-\u2C7F\u2C80-\u2CFF\u2D00-\u2D2F\u2D30-\u2D7F\u2D80-\u2DDF\u2F00-\u2FDF\u2FF0-\u2FFF\u3040-\u309F\u30A0-\u30FF\u3100-\u312F\u3130-\u318F\u3190-\u319F\u31C0-\u31EF\u31F0-\u31FF\u3200-\u32FF\u3300-\u33FF\u3400-\u4DBF\u4DC0-\u4DFF\u4E00-\u9FFF\uA000-\uA48F\uA490-\uA4CF\uA700-\uA71F\uA800-\uA82F\uA840-\uA87F\uAC00-\uD7AF\uF900-\uFAFF]+\.)+[a-zA-Z\u0080-\u00FF\u0100-\u017F\u0180-\u024F\u0250-\u02AF\u0300-\u036F\u0370-\u03FF\u0400-\u04FF\u0500-\u052F\u0530-\u058F\u0590-\u05FF\u0600-\u06FF\u0700-\u074F\u0750-\u077F\u0780-\u07BF\u07C0-\u07FF\u0900-\u097F\u0980-\u09FF\u0A00-\u0A7F\u0A80-\u0AFF\u0B00-\u0B7F\u0B80-\u0BFF\u0C00-\u0C7F\u0C80-\u0CFF\u0D00-\u0D7F\u0D80-\u0DFF\u0E00-\u0E7F\u0E80-\u0EFF\u0F00-\u0FFF\u1000-\u109F\u10A0-\u10FF\u1100-\u11FF\u1200-\u137F\u1380-\u139F\u13A0-\u13FF\u1400-\u167F\u1680-\u169F\u16A0-\u16FF\u1700-\u171F\u1720-\u173F\u1740-\u175F\u1760-\u177F\u1780-\u17FF\u1800-\u18AF\u1900-\u194F\u1950-\u197F\u1980-\u19DF\u19E0-\u19FF\u1A00-\u1A1F\u1B00-\u1B7F\u1D00-\u1D7F\u1D80-\u1DBF\u1DC0-\u1DFF\u1E00-\u1EFF\u1F00-\u1FFF\u20D0-\u20FF\u2100-\u214F\u2C00-\u2C5F\u2C60-\u2C7F\u2C80-\u2CFF\u2D00-\u2D2F\u2D30-\u2D7F\u2D80-\u2DDF\u2F00-\u2FDF\u2FF0-\u2FFF\u3040-\u309F\u30A0-\u30FF\u3100-\u312F\u3130-\u318F\u3190-\u319F\u31C0-\u31EF\u31F0-\u31FF\u3200-\u32FF\u3300-\u33FF\u3400-\u4DBF\u4DC0-\u4DFF\u4E00-\u9FFF\uA000-\uA48F\uA490-\uA4CF\uA700-\uA71F\uA800-\uA82F\uA840-\uA87F\uAC00-\uD7AF\uF900-\uFAFF]{2,}))$/;
return regex.test(user.value.email);
}
/**
* Creates user and toggles successful registration area visibility.
*/
async function createUser(): Promise<void> {
let activeElement = document.activeElement;
if (activeElement && activeElement.classList.contains('account-tab')) {
return;
}
if (!validateFields()) {
return;
}
if (captcha.value && !captchaResponseToken.value) {
captcha.value?.execute();
return;
}
isLoading.value = true;
user.value.isProfessional = isProfessional.value;
user.value.haveSalesContact = haveSalesContact.value;
try {
await auth.register(user.value, secret.value, captchaResponseToken.value);
// Brave browser conversions are tracked via the RegisterSuccess path in the satellite app
// signups outside of the brave browser may use a configured URL to track conversions
// if the URL is not configured, the RegisterSuccess path will be used for non-Brave browsers
const internalRegisterSuccessPath = RouteConfig.RegisterSuccess.path;
const configuredRegisterSuccessPath = MetaUtils.getMetaContent('optional-signup-success-url') || internalRegisterSuccessPath;
const nonBraveSuccessPath = `${configuredRegisterSuccessPath}?email=${encodeURIComponent(user.value.email)}`;
const braveSuccessPath = `${internalRegisterSuccessPath}?email=${encodeURIComponent(user.value.email)}`;
await detectBraveBrowser() ? await router.push(braveSuccessPath) : window.location.href = nonBraveSuccessPath;
} catch (error) {
await notify.error(error.message, null);
}
captcha.value?.reset();
captchaResponseToken.value = '';
isLoading.value = false;
}
</script>