Skip to content

Commit 70bd6ab

Browse files
luizhf42gustavosbarreto
authored andcommitted
fix(ui): fix Welcome dialog opening behavior
1 parent 9edef54 commit 70bd6ab

File tree

3 files changed

+36
-58
lines changed

3 files changed

+36
-58
lines changed

ui/src/components/Welcome/Welcome.vue

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<template>
22
<WindowDialog
3-
v-if="shouldShowWelcome"
43
v-model="showDialog"
54
title="Welcome to ShellHub!"
65
:description="`Step ${currentStep} of 4`"
@@ -85,7 +84,7 @@
8584
</template>
8685

8786
<script setup lang="ts">
88-
import { computed, onMounted, ref, watch } from "vue";
87+
import { computed, onMounted, ref } from "vue";
8988
import WelcomeFirstScreen from "./WelcomeFirstScreen.vue";
9089
import WelcomeSecondScreen from "./WelcomeSecondScreen.vue";
9190
import WelcomeThirdScreen from "./WelcomeThirdScreen.vue";
@@ -97,7 +96,6 @@ import { IDevice } from "@/interfaces/IDevice";
9796
import useDevicesStore from "@/store/modules/devices";
9897
import useStatsStore from "@/store/modules/stats";
9998
import useAuthStore from "@/store/modules/auth";
100-
import useNamespacesStore from "@/store/modules/namespaces";
10199
102100
type PollingTimer = ReturnType<typeof setInterval>;
103101
@@ -108,30 +106,18 @@ interface StepConfig {
108106
109107
const showDialog = ref(false);
110108
const authStore = useAuthStore();
111-
const namespacesStore = useNamespacesStore();
112109
const devicesStore = useDevicesStore();
113110
const statsStore = useStatsStore();
114111
const snackbar = useSnackbar();
115112
const currentStep = ref<number>(1);
116113
const firstPendingDevice = ref<IDevice>();
117114
const pollingTimer = ref<PollingTimer | undefined>(undefined);
118115
const hasDeviceDetected = ref(false);
119-
const tenantId = computed(() => namespacesStore.currentNamespace.tenant_id);
120-
const hasNamespaces = computed(() => namespacesStore.namespaceList.length > 0);
116+
const tenantId = computed(() => authStore.tenantId);
121117
122118
const namespaceHasBeenShown = () => (
123119
(JSON.parse(localStorage.getItem("namespacesWelcome") ?? "{}") as Record<string, boolean>)[tenantId.value] !== undefined);
124120
125-
const hasDevices = ref(false);
126-
127-
const shouldShowWelcome = computed(() => hasNamespaces.value && !namespaceHasBeenShown() && !hasDevices.value);
128-
129-
watch(shouldShowWelcome, (newValue) => {
130-
if (!newValue) return;
131-
authStore.setShowWelcomeScreen(tenantId.value);
132-
showDialog.value = true;
133-
});
134-
135121
const stopDevicePolling = () => {
136122
if (pollingTimer.value) {
137123
clearInterval(pollingTimer.value);
@@ -198,12 +184,23 @@ const stepConfigs: Record<number, StepConfig> = {
198184
const currentStepConfig = computed(() => stepConfigs[currentStep.value]);
199185
const handleConfirm = async () => { await currentStepConfig.value.action(); };
200186
201-
onMounted(() => {
202-
hasDevices.value = (
187+
onMounted(async () => {
188+
if (!tenantId.value) return;
189+
190+
await statsStore.fetchStats();
191+
192+
const hasDevices = (
203193
statsStore.stats.registered_devices > 0
204194
|| statsStore.stats.pending_devices > 0
205195
|| statsStore.stats.rejected_devices > 0
206196
);
197+
198+
const shouldShowWelcome = !namespaceHasBeenShown() && !hasDevices;
199+
200+
if (shouldShowWelcome) {
201+
authStore.setShowWelcomeScreen(tenantId.value);
202+
showDialog.value = true;
203+
}
207204
});
208205
209206
defineExpose({ currentStep, hasDeviceDetected, showDialog });

ui/tests/components/Welcome/Welcome.spec.ts

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,33 @@
11
import { createPinia, setActivePinia } from "pinia";
22
import { DOMWrapper, flushPromises, mount, VueWrapper } from "@vue/test-utils";
33
import { createVuetify } from "vuetify";
4-
import { expect, describe, it, beforeEach, vi, afterEach } from "vitest";
4+
import { expect, describe, it, vi, afterEach } from "vitest";
55
import Welcome from "@/components/Welcome/Welcome.vue";
66
import { SnackbarPlugin } from "@/plugins/snackbar";
7-
import useNamespacesStore from "@/store/modules/namespaces";
87
import useStatsStore from "@/store/modules/stats";
98

10-
const mockNamespace = {
11-
tenant_id: "test-tenant",
12-
name: "test-namespace",
13-
members: [],
14-
max_devices: 10,
15-
owner: "owner-id",
16-
created_at: "",
17-
settings: {
18-
session_record: false,
19-
},
20-
devices_accepted_count: 0,
21-
devices_pending_count: 0,
22-
devices_rejected_count: 0,
23-
billing: null,
24-
type: "personal" as const,
25-
};
26-
279
describe("Welcome", () => {
2810
let wrapper: VueWrapper<InstanceType<typeof Welcome>>;
2911
const vuetify = createVuetify();
12+
localStorage.setItem("tenant", "test-tenant");
3013
setActivePinia(createPinia());
31-
const namespacesStore = useNamespacesStore();
3214
const statsStore = useStatsStore();
15+
statsStore.fetchStats = vi.fn().mockResolvedValue({
16+
registered_devices: 0,
17+
pending_devices: 0,
18+
rejected_devices: 0,
19+
online_devices: 0,
20+
active_sessions: 0,
21+
});
3322

34-
beforeEach(() => {
35-
vi.spyOn(Storage.prototype, "getItem").mockReturnValue("{}");
36-
vi.spyOn(Storage.prototype, "setItem");
37-
namespacesStore.currentNamespace = mockNamespace;
38-
namespacesStore.namespaceList = [mockNamespace];
39-
statsStore.stats = {
40-
registered_devices: 0,
41-
pending_devices: 0,
42-
rejected_devices: 0,
43-
online_devices: 0,
44-
active_sessions: 0,
45-
};
46-
23+
const mountWrapper = () => {
4724
wrapper = mount(Welcome, { global: { plugins: [vuetify, SnackbarPlugin] } });
48-
});
25+
};
4926

50-
afterEach(() => { wrapper.unmount(); });
27+
afterEach(() => { wrapper?.unmount(); });
5128

5229
it("Enables 'Next' (confirm) button when the user sets up a device on step 2", async () => {
30+
mountWrapper();
5331
await flushPromises();
5432

5533
wrapper.vm.currentStep = 2;
@@ -65,8 +43,8 @@ describe("Welcome", () => {
6543
});
6644

6745
it("Does not render when namespace has already been shown", async () => {
68-
vi.spyOn(Storage.prototype, "getItem").mockReturnValue('{"test-tenant":true}');
69-
46+
localStorage.setItem("namespacesWelcome", "{\"test-tenant\":true}");
47+
mountWrapper();
7048
await flushPromises();
7149

7250
const dialog = new DOMWrapper(document.body);
@@ -76,14 +54,16 @@ describe("Welcome", () => {
7654
it("Does not render when namespace has devices", async () => {
7755
statsStore.stats.registered_devices = 1;
7856

57+
mountWrapper();
7958
await flushPromises();
8059

8160
const dialog = new DOMWrapper(document.body);
8261
expect(dialog.find('[data-test="welcome-window"]').exists()).toBe(false);
8362
});
8463

85-
it("Does not render when hasNamespaces is false", async () => {
86-
namespacesStore.namespaceList = [];
64+
it("Does not render when tenant ID doesn't exist", async () => {
65+
localStorage.removeItem("tenant");
66+
mountWrapper();
8767
await flushPromises();
8868
const dialog = new DOMWrapper(document.body);
8969
expect(dialog.find('[data-test="welcome-window"]').exists()).toBe(false);

ui/tests/layouts/__snapshots__/AppLayout.spec.ts.snap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,8 @@ exports[`App Layout Component > Renders the component 1`] = `
337337
</div>
338338
<!--teleport end-->
339339
<!--v-if-->
340-
<!--v-if-->
340+
<!---->
341+
<!---->
341342
<!--v-if-->
342343
<!---->
343344
<!---->

0 commit comments

Comments
 (0)