Skip to content

Commit

Permalink
web/satellite: add generic partner signup page
Browse files Browse the repository at this point in the history
This change extends the registration partner configuration to support a
"general" partner signup page, which looks like the default signup page,
but also contains the partner's logo and name.

There is still the option to configure a "detailed" partner registration
page, which allows for more customization.

#6750
#6822

Change-Id: I4a36fffd39155048f1a4b8d1fd85cd2de7d2834d
  • Loading branch information
mobyvb authored and Storj Robot committed Mar 13, 2024
1 parent 64b66ef commit 25990c5
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 51 deletions.
13 changes: 1 addition & 12 deletions web/satellite/src/configs/registrationViewConfig.json
@@ -1,12 +1 @@
{
"default": {
"title": "Experience better cloud storage for your business.",
"partnerUrl": "",
"partnerLogoTopUrl": "",
"partnerLogoBottomUrl": "",
"description": "Start for free and get unparalleled performance and security, while shaving a zero of your cloud bill and carbon footprint.",
"customHtmlDescription": "",
"signupButtonLabel": "Get Started",
"tooltip": "When selecting the Satellite for your project, you'll want to choose the geographic region where the majority of the end users of your service who will be interacting with the objects on Storj will be located."
}
}
{}
72 changes: 57 additions & 15 deletions web/satellite/src/layouts/default/AuthBar.vue
Expand Up @@ -3,21 +3,37 @@

<template>
<v-app-bar :elevation="0" border="0">
<v-app-bar-title class="mr-1">
<v-img
v-if="theme.global.current.value.dark"
src="@/assets/logo-dark.svg"
width="120"
alt="Storj Logo"
/>
<v-img
v-else
src="@/assets/logo.svg"
width="120"
alt="Storj Logo"
/>
</v-app-bar-title>

<template #prepend>
<div class="d-flex flex-row align-center mr-1">
<img
v-if="theme.global.current.value.dark"
src="@/assets/logo-dark.svg"
height="36"
width="auto"
alt="Storj Logo"
>
<img
v-else
src="@/assets/logo.svg"
height="36"
width="auto"
alt="Storj Logo"
>
<template v-if="partnerConfig && partnerConfig.partnerLogoTopUrl && route.name === ROUTES.Signup.name">
<p class="mx-1">+</p>
<a :href="partnerConfig.partnerUrl">
<img
:src="partnerConfig.partnerLogoTopUrl"
height="36"
width="auto"
:alt="partnerConfig.name + ' logo'"
class="rounded mt-2"
style="background-color: white;"
>
</a>
</template>
</div>
</template>
<template #append>
<!-- Theme Toggle Light/Dark Mode -->
<v-btn-toggle
Expand Down Expand Up @@ -69,12 +85,19 @@
<script setup lang="ts">
import { useTheme } from 'vuetify';
import { onBeforeMount, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { VAppBar, VAppBarTitle, VBtn, VBtnToggle, VIcon, VImg, VMenu, VTooltip } from 'vuetify/components';
import { mdiWeatherNight, mdiWeatherSunny } from '@mdi/js';
import { PartnerConfig } from '@/types/partners';
import { ROUTES } from '@/router';
const route = useRoute();
const theme = useTheme();
const activeTheme = ref(0);
const menu = ref(false);
const partnerConfig = ref<PartnerConfig | null>(null);
function toggleTheme(newTheme: string): void {
if ((newTheme === 'dark' && theme.global.current.value.dark) || (newTheme === 'light' && !theme.global.current.value.dark)) {
Expand All @@ -89,6 +112,25 @@ onBeforeMount(() => {
toggleTheme(localStorage.getItem('theme') || 'light');
});
onBeforeMount(async () => {
// if on signup page, and has partner in route, see if there is a partner config to display logo
if (route.name !== ROUTES.Signup.name) {
return;
}
let partner = '';
if (route.query.partner) {
partner = route.query.partner.toString();
}
// If partner.value is true, attempt to load the partner-specific configuration
if (partner !== '') {
try {
const config = (await import('@/configs/registrationViewConfig.json')).default;
partnerConfig.value = config[partner];
// eslint-disable-next-line no-empty
} catch (_) {}
}
});
watch(() => theme.global.current.value.dark, (newVal: boolean) => {
activeTheme.value = newVal ? 1 : 0;
});
Expand Down
14 changes: 14 additions & 0 deletions web/satellite/src/types/partners.ts
@@ -0,0 +1,14 @@
// Copyright (C) 2024 Storj Labs, Inc.
// See LICENSE for copying information.

export class PartnerConfig {
title: string;
name: string;
partnerUrl: string;
partnerLogoTopUrl: string;
partnerLogoBottomUrl: string;
description: string;
customHtmlDescription: string;
signupButtonLabel: string;
tooltip: string;
}
49 changes: 25 additions & 24 deletions web/satellite/src/views/Signup.vue
Expand Up @@ -193,25 +193,28 @@
@error="onCaptchaError"
/>
</v-col>
<template v-if="partner">
<v-col v-if="viewConfig" cols="12" sm="10" md="6" lg="5" xl="4" xxl="3">
<template v-if="partnerConfig && partnerConfig.title && partnerConfig.description">
<v-col cols="12" sm="10" md="6" lg="5" xl="4" xxl="3">
<v-card class="pa-2 pa-sm-6 h-100 no-position">
<v-card-item>
<v-card-title class="text-wrap">
{{ viewConfig.title }}
{{ partnerConfig.title }}
</v-card-title>
<v-card-subtitle class="text-wrap">
{{ viewConfig.description }}
{{ partnerConfig.description }}
</v-card-subtitle>
</v-card-item>
<v-card-text>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-if="viewConfig.customHtmlDescription" v-html="viewConfig.customHtmlDescription" />
<a v-if="viewConfig.partnerLogoTopUrl" :href="viewConfig.partnerUrl">
<img :src="viewConfig.partnerLogoTopUrl" :srcset="viewConfig.partnerLogoTopUrl" alt="partner logo" height="44" class="mt-6 mr-5">
</a>
<a v-if="viewConfig.partnerLogoBottomUrl" :href="viewConfig.partnerUrl">
<img :src="viewConfig.partnerLogoBottomUrl" :srcset="viewConfig.partnerLogoBottomUrl" alt="partner logo" height="44" class="mt-6">
<div v-if="partnerConfig.customHtmlDescription" v-html="partnerConfig.customHtmlDescription" />
<a v-if="partnerConfig.partnerLogoBottomUrl" :href="partnerConfig.partnerUrl">
<img
:src="partnerConfig.partnerLogoBottomUrl" :srcset="partnerConfig.partnerLogoBottomUrl"
:alt="partnerConfig.name + ' logo'"
height="44"
class="mt-6 rounded"
style="background-color: white;"
>
</a>
</v-card-text>
</v-card>
Expand All @@ -221,7 +224,10 @@
<v-col cols="12" sm="10" md="6" lg="5" xl="4" xxl="3">
<v-card class="pa-2 pa-sm-6 h-100 no-position d-flex align-center">
<v-card-text>
<h1 class="font-weight-black">Start using Storj today.</h1>
<h1 class="font-weight-black" style="line-height: 1.25;">
<template v-if="partnerConfig && partnerConfig.name">Start using Storj on {{ partnerConfig.name }} today.</template>
<template v-else>Start using Storj today.</template>
</h1>
<p class="text-subtitle-1 mt-4">
Whether migrating your data or just testing out Storj, your journey starts here.
</p>
Expand All @@ -241,6 +247,11 @@
Total set up takes less than 5 min.
</p>

<p class="mt-4">
<v-icon :icon="mdiCheckBold" color="primary" />
No credit card required.
</p>

<p class="mt-6">
Need help figuring out if Storj is a fit for your business? <a href="https://meetings.hubspot.com/tom144/meeting-with-tom-troy" target="_blank" class="link font-weight-bold">Schedule a meeting.</a>
</p>
Expand Down Expand Up @@ -285,6 +296,7 @@ import { useAppStore } from '@/store/modules/appStore';
import { useUsersStore } from '@/store/modules/usersStore';
import { EmailRule, RequiredRule, ValidationRule } from '@/types/common';
import { MultiCaptchaConfig } from '@/types/config.gen';
import { PartnerConfig } from '@/types/partners';
import { AuthHttpApi } from '@/api/auth';
import { useNotify } from '@/utils/hooks';
import { useAnalyticsStore } from '@/store/modules/analyticsStore';
Expand All @@ -295,17 +307,6 @@ import SignupConfirmation from '@/views/SignupConfirmation.vue';
import PasswordInputEyeIcons from '@/components/PasswordInputEyeIcons.vue';
import PasswordStrength from '@/components/PasswordStrength.vue';
type ViewConfig = {
title: string;
partnerUrl: string;
partnerLogoTopUrl: string;
partnerLogoBottomUrl: string;
description: string;
customHtmlDescription: string;
signupButtonLabel: string;
tooltip: string;
}
const auth = new AuthHttpApi();
const analyticsStore = useAnalyticsStore();
Expand Down Expand Up @@ -341,7 +342,7 @@ const inviterEmail = queryRef('inviter_email');
const hcaptcha = ref<VueHcaptcha | null>(null);
const form = ref<VForm | null>(null);
const repPasswordField = ref<VTextField | null>(null);
const viewConfig = ref<ViewConfig | null>(null);
const partnerConfig = ref<PartnerConfig | null>(null);
const satellitesHints = [
{ satellite: 'Storj', hint: 'Recommended satellite.' },
Expand Down Expand Up @@ -550,7 +551,7 @@ onBeforeMount(async () => {
if (partner.value) {
try {
const config = (await import('@/configs/registrationViewConfig.json')).default;
viewConfig.value = config[partner.value];
partnerConfig.value = config[partner.value];
} catch (e) {
// Handle errors, such as a missing configuration file
notify.error('No configuration file for registration page.');
Expand Down

0 comments on commit 25990c5

Please sign in to comment.