Skip to content

Commit

Permalink
fix(web): Rework the first time modal tutorial experience
Browse files Browse the repository at this point in the history
This wasn't working in App.vue so we needed to move it to WorkspaceSinglePage - this is guaranteed to be an authenticated user and we are using localstorage to control that we don't serve the popup on a page refresh
  • Loading branch information
stack72 committed Jul 23, 2024
1 parent f4d339d commit a12803f
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 81 deletions.
81 changes: 2 additions & 79 deletions app/web/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,52 +24,16 @@
class="fixed w-full h-full top-0 left-0 pointer-events-none z-100"
></canvas>
</Teleport>
<Modal
ref="firstTimeModalRef"
noExit
size="2xl"
title="Welcome To System Initiative!"
>
<!-- TODO(Wendy) - PLACEHOLDER VIDEO, please replace with our video before pushing to prod! -->
<iframe
class="aspect-video"
src="https://www.youtube.com/embed/dQw4w9WgXcQ?si=vdaJeJEq66s6wYTO"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen
></iframe>
<div class="flex flex-row gap-sm mt-xs">
<VormInput
v-model="firstTimeModalCheckbox"
class="flex flex-row-reverse gap-0 italic"
type="checkbox"
label="Don't show me this video again."
inlineLabel
/>
<VButton
class="flex-grow"
label="Let's Get Started!"
@click="closeFirstTimeModal"
/>
</div>
</Modal>
</template>
</div>
</template>

<script lang="ts" setup>
import { computed, ref, watch } from "vue";
import { computed } from "vue";
import "floating-vue/dist/style.css";

import { tw } from "@si/vue-lib";
import {
Modal,
VButton,
VormInput,
useThemeContainer,
} from "@si/vue-lib/design-system";
import { useThemeContainer } from "@si/vue-lib/design-system";
import SiLogoUrlLight from "@si/vue-lib/brand-assets/si-logo-symbol-white-bg.svg?url";
import SiLogoUrlDark from "@si/vue-lib/brand-assets/si-logo-symbol-black-bg.svg?url";
import { useHead } from "@vueuse/head";
Expand All @@ -80,9 +44,6 @@ import { useWorkspacesStore } from "./store/workspaces.store";
import { useRealtimeStore } from "./store/realtime/realtime.store";
import RealtimeConnectionStatus from "./components/RealtimeConnectionStatus.vue";
import CachedAppNotification from "./components/CachedAppNotification.vue";
import { useFeatureFlagsStore } from "./store/feature_flags.store";

const featureFlagsStore = useFeatureFlagsStore();

useCustomFontsLoadedProvider();

Expand Down Expand Up @@ -128,44 +89,6 @@ const reconnectAuthReqStatus = authStore.getRequestStatus("AUTH_RECONNECT");
const workspacesStore = useWorkspacesStore();
const selectedWorkspace = computed(() => workspacesStore.selectedWorkspace);

const firstTimeModalFired = ref(false);
const firstTimeModalRef = ref<InstanceType<typeof Modal>>();

watch(restoreAuthReqStatus, async () => {
if (!featureFlagsStore.FIRST_TIME_TUTORIAL_MODAL) return;

if (restoreAuthReqStatus.value.isSuccess) {
if (authStore.user) {
const res = await fetch(
`${import.meta.env.VITE_AUTH_API_URL}/users/${
authStore.user.pk
}/firstTimeModal`,
);

const data = await res.json();

if (!firstTimeModalFired.value && data.firstTimeModal) {
firstTimeModalRef.value?.open();
firstTimeModalFired.value = true;
}
}
}
});

const firstTimeModalCheckbox = ref(false);

const closeFirstTimeModal = () => {
if (authStore.user && firstTimeModalCheckbox.value) {
fetch(
`${import.meta.env.VITE_AUTH_API_URL}/users/${
authStore.user.pk
}/dismissFirstTimeModal`,
{ method: "POST" },
);
}
firstTimeModalRef.value?.close();
};

// initialize the realtime store - which will watch for auth and open/close websocket
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const realtimeStore = useRealtimeStore();
Expand Down
68 changes: 66 additions & 2 deletions app/web/src/pages/WorkspaceSinglePage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,57 @@
class="flex-none"
/>
</template>
<Modal
ref="firstTimeModalRef"
noExit
size="2xl"
title="Welcome To System Initiative!"
>
<!-- TODO(Wendy) - PLACEHOLDER VIDEO, please replace with our video before pushing to prod! -->
<iframe
class="aspect-video"
src="https://www.youtube.com/embed/dQw4w9WgXcQ?si=vdaJeJEq66s6wYTO"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen
></iframe>
<div class="flex flex-row gap-sm mt-xs">
<VormInput
v-model="firstTimeModalCheckbox"
class="flex flex-row-reverse gap-0 italic"
type="checkbox"
label="Don't show me this video again."
inlineLabel
/>
<VButton
class="flex-grow"
label="Let's Get Started!"
@click="closeFirstTimeModal"
/>
</div>
</Modal>
</template>
</AppLayout>
</template>

<script lang="ts" setup>
import { computed, PropType, watch } from "vue";
import { computed, onMounted, PropType, ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";
import * as _ from "lodash-es";
import { ErrorMessage, Icon, LoadingMessage } from "@si/vue-lib/design-system";
import storage from "local-storage-fallback";
import {
ErrorMessage,
Icon,
LoadingMessage,
Modal,
VButton,
VormInput,
} from "@si/vue-lib/design-system";
import { useChangeSetsStore } from "@/store/change_sets.store";
import { useWorkspacesStore } from "@/store/workspaces.store";
import { useAuthStore } from "@/store/auth.store";
import AppLayout from "@/components/layout/AppLayout.vue";
import Navbar from "@/components/layout/navbar/Navbar.vue";
import StatusBar from "@/components/StatusBar/StatusBar.vue";
Expand All @@ -96,6 +136,7 @@ const route = useRoute();
const workspacesStore = useWorkspacesStore();
const changeSetsStore = useChangeSetsStore();
const authStore = useAuthStore();
const workspacesReqStatus = workspacesStore.getRequestStatus(
"FETCH_USER_WORKSPACES",
Expand All @@ -109,6 +150,29 @@ const changeSetsReqStatus =
// this page is the parent of many child routes so we watch the route rather than use mounted hooks
watch([route, changeSetsReqStatus], handleUrlChange, { immediate: true });
const firstTimeModalFired = ref(false);
const firstTimeModalRef = ref<InstanceType<typeof Modal>>();
onMounted(async () => {
if (authStore.user) {
const showModal = await authStore.CHECK_FIRST_MODAL(authStore.user.pk);
const hasServedModal = storage.getItem("SI_FIRST_TIME_MODAL_SHOWN");
if (!firstTimeModalFired.value && showModal && !hasServedModal) {
firstTimeModalRef.value?.open();
firstTimeModalFired.value = true;
storage.setItem("SI_FIRST_TIME_MODAL_SHOWN", "1");
}
}
});
const firstTimeModalCheckbox = ref(false);
const closeFirstTimeModal = () => {
if (authStore.user && firstTimeModalCheckbox.value) {
authStore.DISMISS_FIRST_TIME_MODAL(authStore.user.pk);
}
firstTimeModalRef.value?.close();
};
// TODO: this logic needs some work
function handleUrlChange() {
changeSetsStore.creatingChangeSet = false;
Expand Down
14 changes: 14 additions & 0 deletions app/web/src/store/auth.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { User } from "@/api/sdf/dal/user";
import { Workspace } from "@/api/sdf/dal/workspace";
import { useWorkspacesStore } from "./workspaces.store";
import handleStoreError from "./errors";
import { AuthApiRequest } from ".";

export type UserId = string;

Expand Down Expand Up @@ -98,6 +99,19 @@ export const useAuthStore = defineStore("auth", {
});
},

async CHECK_FIRST_MODAL(userPk: string) {
return new AuthApiRequest<boolean>({
url: `/users/${userPk}/firstTimeModal`,
});
},

async DISMISS_FIRST_TIME_MODAL(userPk: string) {
return new AuthApiRequest<boolean>({
method: "post",
url: `/users/${userPk}/dismissFirstTimeModal`,
});
},

// uses existing auth token (jwt) to re-fetch and initialize workspace/user from auth api
// this is needed if user is still logged inbut the running SI instance DB is empty
// for example after updating containers via the launcher
Expand Down

0 comments on commit a12803f

Please sign in to comment.