Latest changes

This commit is contained in:
Nithin David Thomas
2024-02-15 22:22:21 +05:30
parent 90a6a9d058
commit f7088b29cc
12 changed files with 156 additions and 88 deletions
@@ -41,7 +41,7 @@
"SUBMIT": "Create account",
"HAVE_AN_ACCOUNT": "Already have an account?"
},
"ONBOARDING": {
"START_ONBOARDING": {
"PROFILE": {
"INTRO": "Welcome, lets get started.",
"TITLE": "Set up profile",
+1 -1
View File
@@ -28,7 +28,7 @@
'px-3 py-2 mb-0': spacing === 'compact',
'pl-9': icon,
}"
class="block w-full border-none shadow-sm appearance-none rounded-xl outline outline-1 focus:outline-2 text-slate-900 dark:text-slate-100 placeholder:text-slate-400 sm:text-sm sm:leading-6 dark:bg-slate-800"
class="block w-full border-none shadow-sm appearance-none rounded-xl outline outline-1 focus:outline focus:outline-2 text-slate-900 dark:text-slate-100 placeholder:text-slate-400 sm:text-sm sm:leading-6 dark:bg-slate-800"
@input="onInput"
@blur="$emit('blur')"
/>
+10 -3
View File
@@ -19,7 +19,7 @@
<mask id="cutoutMask">
<path
d="M263.999 65.0769C293.048 65.0769 317.641 45.9499 325.929 19.5735C329.219 9.10348 337.794 0 348.744 0H508.172C519.122 0 527.999 8.89875 527.999 19.8759V95.5C527.999 95.5 519.122 95.5 508.172 95.5H263.999H-0.000976562V19.8759C-0.000976562 8.89877 8.87604 0 19.8264 0H179.254C190.204 0 198.779 9.10349 202.069 19.5735C210.357 45.9499 234.95 65.0769 263.999 65.0769Z"
fill="#FCFCFD"
fill="white"
/>
</mask>
</defs>
@@ -29,10 +29,10 @@
class="flex w-full h-full relative z-50 items-center justify-center overflow-auto"
>
<div
class="flex-1 min-h-[640px] inline-flex items-center h-full justify-center py-6"
class="relative flex-1 min-h-[640px] inline-flex items-center h-full justify-center py-6"
>
<div
class="relative bg-white dark:bg-slate-800 before:bg-white dark:before:bg-slate-800 px-16 pt-8 pb-16 max-w-[528px] w-full rounded-3xl signup-box"
class="relative bg-white dark:bg-slate-800 before:bg-white before:border-slate-200 dark:before:border-slate-700 dark:before:bg-slate-800 px-16 pt-8 pb-16 max-w-[528px] w-full rounded-3xl signup-box"
>
<div class="absolute -top-[116px] right-0 left-0 w-24 h-24 mx-auto">
<img
@@ -112,4 +112,11 @@ export default {
-webkit-mask-image: url('#cutoutMask');
mask-image: url('#cutoutMask');
}
.dark .signup-box {
-webkit-filter: drop-shadow(1px 1px 0 var(--s-800))
drop-shadow(-1px -1px 0 var(--s-800));
filter: drop-shadow(1px 1px 0 var(--s-800))
drop-shadow(-1px -1px 0 var(--s-800));
}
</style>
@@ -59,7 +59,7 @@
<submit-button
button-class="flex justify-center w-full text-sm text-center mt-8"
:button-text="$t('ONBOARDING.FOUNDERS_NOTE.SUBMIT')"
:button-text="$t('START_ONBOARDING.FOUNDERS_NOTE.SUBMIT')"
@click="onSubmit"
/>
</div>
@@ -6,12 +6,12 @@
<h2
class="font-bold text-[28px] leading-8 tracking-[2%] text-slate-900 dark:text-white"
>
{{ $t('ONBOARDING.INVITE_TEAM.TITLE') }}
{{ $t('START_ONBOARDING.INVITE_TEAM.TITLE') }}
</h2>
<p
class="text-base text-slate-600 leading-6 tracking-[-1.1%] mt-2 dark:text-slate-200"
>
{{ $t('ONBOARDING.INVITE_TEAM.BODY') }}
{{ $t('START_ONBOARDING.INVITE_TEAM.BODY') }}
</p>
<div class="mt-10">
<section class="space-y-5">
@@ -21,7 +21,7 @@
name="email"
spacing="compact"
class="flex-grow"
:placeholder="$t('ONBOARDING.INVITE_TEAM.PLACEHOLDER')"
:placeholder="$t('START_ONBOARDING.INVITE_TEAM.PLACEHOLDER')"
@keyup.enter="pushEmail"
/>
<woot-button
@@ -29,7 +29,7 @@
color-scheme="secondary"
@click="pushEmail"
>
{{ $t('ONBOARDING.INVITE_TEAM.ADD') }}
{{ $t('START_ONBOARDING.INVITE_TEAM.ADD') }}
</woot-button>
</div>
<div
@@ -41,7 +41,7 @@
>
<div v-if="emailsToInvite.length === 0" class="px-5 py-16">
<p class="text-sm text-slate-400">
{{ $t('ONBOARDING.INVITE_TEAM.LIST_EMPTY') }}
{{ $t('START_ONBOARDING.INVITE_TEAM.LIST_EMPTY') }}
</p>
</div>
<div
@@ -69,7 +69,7 @@
<div class="space-y-2">
<submit-button
button-class="flex justify-center w-full text-sm text-center"
:button-text="$t('ONBOARDING.INVITE_TEAM.SUBMIT.BUTTON')"
:button-text="$t('START_ONBOARDING.INVITE_TEAM.SUBMIT.BUTTON')"
@click="onSubmit"
/>
@@ -80,7 +80,7 @@
is-expanded
@click="skipToFoundersNote"
>
{{ $t('ONBOARDING.INVITE_TEAM.SKIP') }}
{{ $t('START_ONBOARDING.INVITE_TEAM.SKIP') }}
</woot-button>
</div>
</section>
@@ -114,23 +114,29 @@ export default {
this.emailsToInvite = [...new Set(this.emailsToInvite)];
this.emailToAdd = '';
},
skipToFoundersNote() {
async skipToFoundersNote() {
try {
await AgentAPI.bulkInvite({ emails: [] });
this.$router.push({ name: 'onboarding_founders_note' });
} catch (error) {
this.showAlert(this.$t('START_ONBOARDING.INVITE_TEAM.SUBMIT.ERROR'));
}
this.$router.push({ name: 'onboarding_founders_note' });
},
async onSubmit() {
if (this.emailsToInvite.length === 0) {
this.showAlert(
this.$t('ONBOARDING.INVITE_TEAM.SUBMIT.NO_MEMBER_ERROR')
this.$t('START_ONBOARDING.INVITE_TEAM.SUBMIT.NO_MEMBER_ERROR')
);
return;
}
try {
await AgentAPI.bulkInvite({ emails: this.emailsToInvite });
this.showAlert(this.$t('ONBOARDING.INVITE_TEAM.SUBMIT.SUCCESS'));
this.showAlert(this.$t('START_ONBOARDING.INVITE_TEAM.SUBMIT.SUCCESS'));
this.$router.push({ name: 'onboarding_founders_note' });
} catch (error) {
this.showAlert(this.$t('ONBOARDING.INVITE_TEAM.SUBMIT.ERROR'));
this.showAlert(this.$t('START_ONBOARDING.INVITE_TEAM.SUBMIT.ERROR'));
}
},
},
@@ -2,7 +2,9 @@
<section
class="relative min-h-screen px-8 dark:text-white bg-[#FCFCFD] dark:bg-slate-900 flex items-center justify-center bg-[url('/assets/images/dashboard/onboarding/intro.svg')] dark:bg-[url('/assets/images/dashboard/onboarding/intro-dark.svg')] bg-[length:715px_555px] bg-no-repeat bg-[left_calc(-56px)_bottom_calc(-133px)]"
>
<spinner v-if="!showIntroHeader" class="absolute inset-0" />
<div
v-else
class="relative max-w-[1440px] w-full mx-auto flex gap-16 min-h-[80vh] justify-center"
>
<div class="relative w-5/12 px-16 py-[88px] mt-10">
@@ -43,7 +45,7 @@
class="relative w-7/12 py-[88px] flex justify-center overflow-hidden h-fit"
>
<div
class="absolute inset-0 h-full w-full bg-white dark:bg-slate-900 bg-[radial-gradient(var(--w-200)_1px,transparent_1px)] [background-size:16px_16px]"
class="absolute inset-0 h-full w-full bg-[#FCFCFD] dark:bg-slate-900 bg-[radial-gradient(var(--w-200)_1px,transparent_1px)] [background-size:16px_16px]"
/>
<div
class="absolute h-full w-full overlay-gradient top-0 left-0 scale-y-110 blur-[3px]"
@@ -61,50 +63,29 @@
import { mapGetters } from 'vuex';
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
import Spinner from 'shared/components/Spinner.vue';
import OnboardingStep from './OnboardingStep.vue';
import { UISteps, API_ONBOARDING_STEP_ROUTE } from './constants';
const UISteps = [
{
name: 'onboarding_setup_profile',
title: 'Setup Profile',
icon: 'person',
isActive: false,
isComplete: false,
},
{
name: 'onboarding_setup_company',
title: 'Setup Company',
icon: 'toolbox',
isActive: false,
isComplete: false,
},
{
name: 'onboarding_invite_team',
title: 'Invite your team',
icon: 'people-team',
isActive: false,
isComplete: false,
},
// {
// name: 'onboarding_founders_note',
// title: "Founder's Note",
// icon: '',
// hidden: true,
// isActive: false,
// isComplete: false,
// },
];
export default {
components: {
Spinner,
OnboardingStep,
},
mixins: [globalConfigMixin],
data() {
return {
showIntroHeader: false,
showLoading: true,
};
},
computed: {
...mapGetters({
globalConfig: 'globalConfig/get',
currentUser: 'getCurrentUser',
currentAccountId: 'getCurrentAccountId',
getAccount: 'accounts/getAccount',
}),
currentStep() {
return this.$route.name;
},
@@ -113,12 +94,12 @@ export default {
this.currentStep === 'onboarding_setup_company' ||
this.currentStep === 'onboarding_invite_team'
) {
return this.$t('ONBOARDING.COMPANY.PAGE_TITLE', {
return this.$t('START_ONBOARDING.COMPANY.PAGE_TITLE', {
userName: this.userName,
});
}
return this.$t('ONBOARDING.PROFILE.INTRO');
return this.$t('START_ONBOARDING.PROFILE.INTRO');
},
steps() {
let foundCurrentStep = false;
@@ -136,27 +117,46 @@ export default {
userName() {
return this.currentUser.name;
},
...mapGetters({
globalConfig: 'globalConfig/get',
currentUser: 'getCurrentUser',
}),
accountDetails() {
return this.getAccount(this.currentAccountId);
},
},
watch: {
watch: {
$route() {
this.showIntroHeader = false;
this.showLoading = true;
setTimeout(() => {
this.showIntroHeader = true;
}, 10);
},
accountDetails() {
this.navigateToSavedStep();
},
},
},
mounted() {
this.showIntroHeader = true;
this.showLoading = true;
this.navigateToSavedStep();
},
beforeDestroy() {
this.showIntroHeader = false;
},
methods: {
navigateToSavedStep() {
if (!this.accountDetails) return;
const { custom_attributes: { onboarding_step: savedStep } = {} } =
this.accountDetails;
const stepName = API_ONBOARDING_STEP_ROUTE[savedStep];
if (stepName !== this.currentStep) {
this.showLoading = false;
this.$router.replace({ name: stepName });
}
},
},
};
</script>
<style scoped>
@@ -6,12 +6,12 @@
<h2
class="font-bold text-[28px] leading-8 tracking-[2%] text-slate-900 dark:text-white"
>
{{ $t('ONBOARDING.COMPANY.TITLE') }}
{{ $t('START_ONBOARDING.COMPANY.TITLE') }}
</h2>
<p
class="text-base text-slate-600 leading-6 tracking-[-1.1%] mt-2 dark:text-slate-200"
>
{{ $t('ONBOARDING.COMPANY.BODY') }}
{{ $t('START_ONBOARDING.COMPANY.BODY') }}
</p>
<div class="space-y-8 mt-10">
@@ -22,16 +22,16 @@
name="companyName"
spacing="compact"
:has-error="$v.companyName.$error"
:label="$t('ONBOARDING.COMPANY.COMPANY_NAME.LABEL')"
:placeholder="$t('ONBOARDING.COMPANY.COMPANY_NAME.PLACEHOLDER')"
:error-message="$t('ONBOARDING.COMPANY.COMPANY_NAME.ERROR')"
:label="$t('START_ONBOARDING.COMPANY.COMPANY_NAME.LABEL')"
:placeholder="$t('START_ONBOARDING.COMPANY.COMPANY_NAME.PLACEHOLDER')"
:error-message="$t('START_ONBOARDING.COMPANY.COMPANY_NAME.ERROR')"
/>
<form-select
v-model="locale"
name="locale"
icon="local-language"
:label="$t('ONBOARDING.COMPANY.LOCALE.LABEL')"
:placeholder="$t('ONBOARDING.COMPANY.LOCALE.PLACEHOLDER')"
:label="$t('START_ONBOARDING.COMPANY.LOCALE.LABEL')"
:placeholder="$t('START_ONBOARDING.COMPANY.LOCALE.PLACEHOLDER')"
>
<option
v-for="lang in languagesSortedByCode"
@@ -47,8 +47,8 @@
name="timezone"
icon="globe-clock"
spacing="compact"
:label="$t('ONBOARDING.COMPANY.TIMEZONE.LABEL')"
:placeholder="$t('ONBOARDING.COMPANY.TIMEZONE.PLACEHOLDER')"
:label="$t('START_ONBOARDING.COMPANY.TIMEZONE.LABEL')"
:placeholder="$t('START_ONBOARDING.COMPANY.TIMEZONE.PLACEHOLDER')"
>
<option
v-for="zone in timeZones"
@@ -62,21 +62,21 @@
<form-radio-tags
v-model="industry"
name="industry"
:label="$t('ONBOARDING.COMPANY.INDUSTRY.LABEL')"
:placeholder="$t('ONBOARDING.COMPANY.SIZE.PLACEHOLDER')"
:label="$t('START_ONBOARDING.COMPANY.INDUSTRY.LABEL')"
:placeholder="$t('START_ONBOARDING.COMPANY.SIZE.PLACEHOLDER')"
:options="industryOptions"
/>
<form-radio-tags
v-model="companySize"
name="companySize"
:label="$t('ONBOARDING.COMPANY.SIZE.LABEL')"
:placeholder="$t('ONBOARDING.COMPANY.SIZE.PLACEHOLDER')"
:label="$t('START_ONBOARDING.COMPANY.SIZE.LABEL')"
:placeholder="$t('START_ONBOARDING.COMPANY.SIZE.PLACEHOLDER')"
:options="companySizeOptions"
/>
</div>
<submit-button
button-class="flex justify-center w-full text-sm text-center"
:button-text="$t('ONBOARDING.COMPANY.SUBMIT.BUTTON')"
:button-text="$t('START_ONBOARDING.COMPANY.SUBMIT.BUTTON')"
@click="onSubmit"
/>
</div>
@@ -189,11 +189,12 @@ export default {
locale: this.locale,
company_size: this.companySize,
industry: this.industry,
onboarding_step: 'account_update',
});
this.showAlert(this.$t('ONBOARDING.COMPANY.SUBMIT.SUCCESS'));
this.showAlert(this.$t('START_ONBOARDING.COMPANY.SUBMIT.SUCCESS'));
this.$router.push({ name: 'onboarding_invite_team' });
} catch (error) {
this.showAlert(this.$t('ONBOARDING.COMPANY.SUBMIT.ERROR'));
this.showAlert(this.$t('START_ONBOARDING.COMPANY.SUBMIT.ERROR'));
}
},
setLocale(locale) {
@@ -6,12 +6,12 @@
<h2
class="font-bold text-[28px] leading-8 tracking-[2%] text-slate-900 dark:text-white"
>
{{ $t('ONBOARDING.PROFILE.TITLE') }}
{{ $t('START_ONBOARDING.PROFILE.TITLE') }}
</h2>
<p
class="text-base text-slate-600 leading-6 tracking-[-1.1%] mt-2 dark:text-slate-200"
>
{{ $t('ONBOARDING.PROFILE.BODY') }}
{{ $t('START_ONBOARDING.PROFILE.BODY') }}
</p>
<div class="mt-10">
<form class="space-y-6" @submit="onSubmit">
@@ -19,7 +19,7 @@
<div>
<with-label name="user_avatar">
<template #label>
{{ $t('ONBOARDING.PROFILE.AVATAR.LABEL') }}
{{ $t('START_ONBOARDING.PROFILE.AVATAR.LABEL') }}
</template>
<div class="flex gap-2">
<woot-thumbnail
@@ -65,7 +65,7 @@
variant="hollow"
@click="onFileBrowse"
>
{{ $t('ONBOARDING.PROFILE.AVATAR.PLACEHOLDER') }}
{{ $t('START_ONBOARDING.PROFILE.AVATAR.PLACEHOLDER') }}
</woot-button>
<woot-button
v-else
@@ -84,26 +84,30 @@
name="full_name"
spacing="compact"
:has-error="$v.fullName.$error"
:label="$t('ONBOARDING.PROFILE.FULL_NAME.LABEL')"
:placeholder="$t('ONBOARDING.PROFILE.FULL_NAME.PLACEHOLDER')"
:error-message="$t('ONBOARDING.PROFILE.FULL_NAME.ERROR')"
:label="$t('START_ONBOARDING.PROFILE.FULL_NAME.LABEL')"
:placeholder="$t('START_ONBOARDING.PROFILE.FULL_NAME.PLACEHOLDER')"
:error-message="$t('START_ONBOARDING.PROFILE.FULL_NAME.ERROR')"
/>
<form-input
v-model="displayName"
name="display_name"
spacing="compact"
:has-error="$v.displayName.$error"
:label="$t('ONBOARDING.PROFILE.DISPLAY_NAME.LABEL')"
:placeholder="$t('ONBOARDING.PROFILE.DISPLAY_NAME.PLACEHOLDER')"
:error-message="$t('ONBOARDING.PROFILE.DISPLAY_NAME.ERROR')"
:label="$t('START_ONBOARDING.PROFILE.DISPLAY_NAME.LABEL')"
:placeholder="
$t('START_ONBOARDING.PROFILE.DISPLAY_NAME.PLACEHOLDER')
"
:error-message="$t('START_ONBOARDING.PROFILE.DISPLAY_NAME.ERROR')"
/>
<form-input
v-model="phoneNumber"
name="phone_number"
spacing="compact"
:has-error="$v.phoneNumber.$error"
:label="$t('ONBOARDING.PROFILE.PHONE_NUMBER.LABEL')"
:placeholder="$t('ONBOARDING.PROFILE.PHONE_NUMBER.PLACEHOLDER')"
:label="$t('START_ONBOARDING.PROFILE.PHONE_NUMBER.LABEL')"
:placeholder="
$t('START_ONBOARDING.PROFILE.PHONE_NUMBER.PLACEHOLDER')
"
:error-message="$t('CONTACT_FORM.FORM.PHONE_NUMBER.ERROR')"
@blur="$v.phoneNumber.$touch"
/>
@@ -112,13 +116,13 @@
name="signature"
spacing="compact"
:allow-resize="false"
:label="$t('ONBOARDING.PROFILE.SIGNATURE.LABEL')"
:placeholder="$t('ONBOARDING.PROFILE.SIGNATURE.PLACEHOLDER')"
:label="$t('START_ONBOARDING.PROFILE.SIGNATURE.LABEL')"
:placeholder="$t('START_ONBOARDING.PROFILE.SIGNATURE.PLACEHOLDER')"
/>
</div>
<submit-button
button-class="flex justify-center w-full text-sm text-center"
:button-text="$t('ONBOARDING.PROFILE.SUBMIT.BUTTON')"
:button-text="$t('START_ONBOARDING.PROFILE.SUBMIT.BUTTON')"
/>
</form>
</div>
@@ -229,13 +233,13 @@ export default {
avatar: this.avatarFile,
message_signature: this.signature || '',
});
this.showAlert(this.$t('ONBOARDING.PROFILE.SUBMIT.SUCCESS'));
this.showAlert(this.$t('START_ONBOARDING.PROFILE.SUBMIT.SUCCESS'));
document.startViewTransition(() => {
this.$router.push({ name: 'onboarding_setup_company' });
});
} catch (error) {
this.showAlert(this.$t('ONBOARDING.PROFILE.SUBMIT.ERROR'));
this.showAlert(this.$t('START_ONBOARDING.PROFILE.SUBMIT.ERROR'));
}
},
async deleteAvatar(event) {
@@ -0,0 +1,29 @@
export const UISteps = [
{
name: 'onboarding_setup_profile',
title: 'Setup Profile',
icon: 'person',
isActive: false,
isComplete: false,
},
{
name: 'onboarding_setup_company',
title: 'Setup Company',
icon: 'toolbox',
isActive: false,
isComplete: false,
},
{
name: 'onboarding_invite_team',
title: 'Invite your team',
icon: 'people-team',
isActive: false,
isComplete: false,
},
];
export const API_ONBOARDING_STEP_ROUTE = {
profile_update: 'onboarding_setup_profile',
account_update: 'onboarding_setup_company',
invite_team: 'onboarding_invite_team',
};
@@ -213,6 +213,16 @@ RSpec.describe 'Accounts API', type: :request do
end
end
it 'updates onboarding step to invite_agents if onboarding step is present in account custom attributes' do
account.update(custom_attributes: { onboarding_step: 'completed' })
put "/api/v1/accounts/#{account.id}",
params: params,
headers: admin.create_new_auth_token,
as: :json
expect(account.reload.custom_attributes['onboarding_step']).to eq('invite_agents')
end
it 'Throws error 422' do
params[:name] = 'test' * 999
@@ -41,5 +41,15 @@ RSpec.describe 'Agents API', type: :request do
expect(response.body).to include('Account limit exceeded. Please purchase more licenses')
end
end
context 'when onboarding step is present in account custom attributes' do
it 'removes onboarding step from account custom attributes' do
account.update(custom_attributes: { onboarding_step: 'completed' })
post "/api/v1/accounts/#{account.id}/agents/bulk_create", params: bulk_create_params, headers: admin.create_new_auth_token
expect(account.reload.custom_attributes).not_to include('onboarding_step')
end
end
end
end
@@ -48,6 +48,7 @@ RSpec.describe Enterprise::Api::V2::AccountsController, type: :request do
expect(custom_attributes['industry']).to eq('Software')
expect(custom_attributes['company_size']).to eq('51-200')
expect(custom_attributes['timezone']).to eq('America/Los_Angeles')
expect(custom_attributes['onboarding_step']).to eq('profile_update')
end
end