Skip to content

Commit

Permalink
Initial pass at FTUE state management.
Browse files Browse the repository at this point in the history
  • Loading branch information
MelissaAutumn committed Jun 12, 2024
1 parent 1391d7d commit e77705b
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 0 deletions.
2 changes: 2 additions & 0 deletions frontend/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
'min-h-full pb-32 pt-8': routeIsPublic,
}"
>
<first-time-user-experience v-if="!currentUser.data.setup"></first-time-user-experience>
<router-view/>
</main>
<footer-bar/>
Expand Down Expand Up @@ -47,6 +48,7 @@ import { useAppointmentStore } from '@/stores/appointment-store';
import { useScheduleStore } from '@/stores/schedule-store';
import RouteNotFoundView from '@/views/errors/RouteNotFoundView.vue';
import NotAuthenticatedView from '@/views/errors/NotAuthenticatedView.vue';
import FirstTimeUserExperience from '@/components/FirstTimeUserExperience.vue';
// component constants
const currentUser = useUserStore(); // data: { username, email, name, level, timezone, id }
Expand Down
10 changes: 10 additions & 0 deletions frontend/src/components/FTUE/GooglePermissions.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<template>
{{ t('text.googlePermissionDisclaimer') }}
</template>

<script setup>
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
</script>
22 changes: 22 additions & 0 deletions frontend/src/components/FTUE/SetupProfile.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script setup>
</script>

<template>
<label>
Full Name
<input type="text"/>
</label>
<label>
Username
<input type="text"/>
</label>
<label>
Timezone
<input type="text"/>
</label>
</template>

<style scoped>
</style>
50 changes: 50 additions & 0 deletions frontend/src/components/FirstTimeUserExperience.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<template>
<div
class="mdl-overlay-close fixed left-0 top-0 z-40 h-screen w-screen bg-gray-800/50"
></div>
<div
class="position-center fixed z-50 flex w-full max-w-lg flex-col items-center gap-6 rounded-xl bg-white p-12 dark:bg-gray-700"
>
<div class="text-2xl font-semibold text-teal-500">
{{ stepTitle }}
</div>
<ftue-view/>
<div class="flex gap-4">
<secondary-button
v-if="hasPreviousStep"
class="btn-close"
label="Back"
@click="previousStep()"
title="Back"
/>
<primary-button
v-if="hasNextStep"
class="btn-copy"
label="Continue"
title="Continue"
@click="nextStep()"
/>
</div>
</div>
</template>

<script setup>
import PrimaryButton from '@/elements/PrimaryButton.vue';
import { IconX } from '@tabler/icons-vue';
import SecondaryButton from '@/elements/SecondaryButton.vue';
import ArtConfetti from '@/elements/arts/ArtConfetti.vue';
import { useI18n } from 'vue-i18n';
import SetupProfile from '@/components/FTUE/SetupProfile.vue';
import { useFTUEStore } from '@/stores/ftue-store';
import { storeToRefs } from 'pinia';
const ftueStore = useFTUEStore();
const { previousStep, nextStep } = ftueStore;
const {
ftueView, hasPreviousStep, hasNextStep, stepTitle,
} = storeToRefs(ftueStore);
const { t } = useI18n();
</script>
20 changes: 20 additions & 0 deletions frontend/src/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,12 +256,32 @@ export const tableDataType = {
bool: 5,
};

/**
* @enum
* @readonly
*/
export const tableDataButtonType = {
primary: 1,
secondary: 2,
caution: 3,
};

/**
* First Time User Experience Steps
* Step amounts are 10-based to allow us flexibility in adding steps later.
* @enum
* @readonly
*/
export const ftueStep = {
setupProfile: 10,
// Right now we only support Google calendars during ftue
googlePermissions: 20,
connectCalendars: 30,
setupSchedule: 40,
connectVideoConferencing: 50,
finish: 100,
};

export default {
subscriberLevels,
appointmentState,
Expand Down
103 changes: 103 additions & 0 deletions frontend/src/stores/ftue-store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { defineStore } from 'pinia';
import { ref, computed, defineAsyncComponent } from 'vue';
import { useLocalStorage } from '@vueuse/core';
import { ftueStep } from '@/definitions';

const initialObject = {
// First step
step: ftueStep.setupProfile,
previousStep: ftueStep.setupProfile,
nextStep: ftueStep.googlePermissions,
};

// eslint-disable-next-line import/prefer-default-export
export const useFTUEStore = defineStore('FTUE', () => {
// State
const data = useLocalStorage('tba/ftue', structuredClone(initialObject));

const stepList = {
[ftueStep.setupProfile]: {
previous: null,
next: ftueStep.googlePermissions,
title: 'Setup your profile',
component: defineAsyncComponent({
loader: () => import('@/components/FTUE/SetupProfile.vue'),
}),
},
[ftueStep.googlePermissions]: {
previous: ftueStep.setupProfile,
next: ftueStep.connectCalendars,
title: 'Allow Google Calendar permissions',
component: defineAsyncComponent({
loader: () => import('@/components/FTUE/GooglePermissions.vue'),
}),
},
[ftueStep.connectCalendars]: {
previous: ftueStep.googlePermissions,
next: ftueStep.setupSchedule,
title: 'Connect calendars',
component: defineAsyncComponent({
loader: () => import('@/components/FTUE/GooglePermissions.vue'),
}),
},
[ftueStep.setupSchedule]: {
previous: ftueStep.connectCalendars,
next: ftueStep.connectVideoConferencing,
title: 'Create schedule',
component: defineAsyncComponent({
loader: () => import('@/components/FTUE/GooglePermissions.vue'),
}),
},
[ftueStep.connectVideoConferencing]: {
previous: ftueStep.setupSchedule,
next: ftueStep.finish,
title: 'Connect video',
component: defineAsyncComponent({
loader: () => import('@/components/FTUE/GooglePermissions.vue'),
}),
},
[ftueStep.finish]: {
previous: ftueStep.connectVideoConferencing,
next: null,
title: 'You are set to go!',
component: defineAsyncComponent({
loader: () => import('@/components/FTUE/GooglePermissions.vue'),
}),
},
};

const ftueView = computed(() => {
if (!stepList[data.value.step]) {
// This should be an error component
return defineAsyncComponent({
loader: () => import('@/components/FTUE/SetupProfile.vue'),
});
}

return stepList[data.value.step].component;
});

const hasNextStep = computed(() => !!(stepList[data.value.step] && stepList[data.value.step].next));
const hasPreviousStep = computed(() => !!(stepList[data.value.step] && stepList[data.value.step].previous));
const stepTitle = computed(() => {
if (stepList[data.value.step]) {
return stepList[data.value.step].title;
}
});

const nextStep = () => {
if (hasNextStep.value) {
data.value.step = stepList[data.value.step].next;
}
};

const previousStep = () => {
if (hasPreviousStep.value) {
data.value.step = stepList[data.value.step].previous;
}
};

return {
data, ftueView, nextStep, previousStep, hasNextStep, hasPreviousStep, stepTitle,
};
});
1 change: 1 addition & 0 deletions frontend/src/stores/user-store.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { i18n } from '@/composables/i18n';
import { computed } from 'vue';

const initialUserObject = {
setup: false,
email: null,
preferredEmail: null,
level: null,
Expand Down

0 comments on commit e77705b

Please sign in to comment.