From 776cfe1104760be37ca221a111dea344272713cf Mon Sep 17 00:00:00 2001 From: jecui Date: Thu, 4 Dec 2025 15:12:30 -0500 Subject: [PATCH 1/6] Create first study modal and welcome wizard + icons --- packages/api/src/models/user.ts | 1 + packages/api/src/services/auth.service.ts | 9 +- packages/shared/types/models/user.ts | 1 + packages/ui/public/hearing.svg | 3 + packages/ui/public/training.svg | 11 + .../src/pages/MyStudiesPage/MyStudiesPage.vue | 260 +++++++++++++++++- .../StudyBuilderPage/StudyBuilderPage.vue | 67 ++++- .../components/StudyPanel.vue | 89 +++++- packages/ui/src/stores/auth.ts | 1 + 9 files changed, 427 insertions(+), 15 deletions(-) create mode 100644 packages/ui/public/hearing.svg create mode 100644 packages/ui/public/training.svg diff --git a/packages/api/src/models/user.ts b/packages/api/src/models/user.ts index 413a7bc2..e6622782 100644 --- a/packages/api/src/models/user.ts +++ b/packages/api/src/models/user.ts @@ -28,6 +28,7 @@ const userSchema = new Schema({ verified: { type: Boolean, required: true, default: false }, favoriteBatteries: [{ type: Schema.Types.ObjectId, ref: "Battery" }], recentBatteries: [{ type: Schema.Types.ObjectId, ref: "Battery" }], + welcomeWizardStep: { type: Number, required: true, default: 0 }, }); userSchema.methods.verifyPassword = function (password: string) { diff --git a/packages/api/src/services/auth.service.ts b/packages/api/src/services/auth.service.ts index efcc68fe..be880bbb 100644 --- a/packages/api/src/services/auth.service.ts +++ b/packages/api/src/services/auth.service.ts @@ -130,14 +130,17 @@ export const updateUser = async (req: any): APIResponse => { const user = req.user; if (!user) throw new HttpError(401, "Unauthorized"); - const { name, email, password } = req.body as Partial & { - password?: string; - }; + const { name, email, password, welcomeWizardStep } = + req.body as Partial & { + password?: string; + }; if (typeof name === "string") user.name = name; if (typeof email === "string") user.email = email; if (typeof password === "string" && password.length > 0) user.password = password; + if (typeof welcomeWizardStep === "number") + user.welcomeWizardStep = welcomeWizardStep; await user.save(); return [200, user]; diff --git a/packages/shared/types/models/user.ts b/packages/shared/types/models/user.ts index 8d537071..84701650 100644 --- a/packages/shared/types/models/user.ts +++ b/packages/shared/types/models/user.ts @@ -17,6 +17,7 @@ export interface CreateUser { favoriteBatteries?: Types.ObjectId[]; recentStudyIds?: string[] | null; recentBatteries?: Types.ObjectId[]; + welcomeWizardStep: number; } export interface IUser extends Required { diff --git a/packages/ui/public/hearing.svg b/packages/ui/public/hearing.svg new file mode 100644 index 00000000..475e2c82 --- /dev/null +++ b/packages/ui/public/hearing.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/ui/public/training.svg b/packages/ui/public/training.svg new file mode 100644 index 00000000..189d1a95 --- /dev/null +++ b/packages/ui/public/training.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue b/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue index 7863e5b5..e1ca9c6a 100644 --- a/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue +++ b/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue @@ -1,13 +1,16 @@ +const firstStudyForm = reactive({ + title: "", + description: "", + tags: [] as string[], + serverCode: "", +}); + +const createFirstStudy = async () => { + const createdStudyId = await studiesAPI.createStudy(); + const study = await studiesAPI.getStudy(createdStudyId); + await studiesAPI.saveStudy(createdStudyId, { + ...study, + name: firstStudyForm.title, + description: firstStudyForm.description, + variants: study.variants.map((variant, index) => + index === 0 + ? { + ...variant, + serverCode: firstStudyForm.serverCode, + tags: firstStudyForm.tags, + } + : variant + ), + }); + router.push({ name: "study", params: { id: createdStudyId } }); +}; + +const updateWizardSteps = (step: number) => { + authAPI.updateCurrentUser({ welcomeWizardStep: step }); + if (authStore.currentUser) authStore.currentUser.welcomeWizardStep = step; +}; + + + diff --git a/packages/ui/src/pages/StudyBuilderPage/StudyBuilderPage.vue b/packages/ui/src/pages/StudyBuilderPage/StudyBuilderPage.vue index 6b455111..9593274b 100644 --- a/packages/ui/src/pages/StudyBuilderPage/StudyBuilderPage.vue +++ b/packages/ui/src/pages/StudyBuilderPage/StudyBuilderPage.vue @@ -1,7 +1,8 @@ - - - + + + +
+ + diff --git a/packages/ui/src/stores/auth.ts b/packages/ui/src/stores/auth.ts index 3cf24a32..aa3974b7 100644 --- a/packages/ui/src/stores/auth.ts +++ b/packages/ui/src/stores/auth.ts @@ -10,6 +10,7 @@ export interface IUser { role: Role; studies: string[]; favoriteBatteries: IBattery[]; + welcomeWizardStep: number; } export const useAuthStore = defineStore("auth", () => { From acccd73e05520d7470b12d3eed658b2a4e3f9aed Mon Sep 17 00:00:00 2001 From: jecui Date: Fri, 5 Dec 2025 17:52:56 -0500 Subject: [PATCH 2/6] UI adjustments --- .../src/pages/MyStudiesPage/MyStudiesPage.vue | 9 ++-- .../StudyBuilderPage/StudyBuilderPage.vue | 47 ++++++++++++++++++- .../components/components/TagLabel.vue | 2 + 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue b/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue index e1ca9c6a..10e682d1 100644 --- a/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue +++ b/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue @@ -231,9 +231,8 @@ const updateWizardSteps = (step: number) => { - {{ tag }} + style="width: 12px; height: 12px" + />{{ tag }} { } } " + class="tag-checkbox" > {{ tag }} @@ -351,4 +351,7 @@ const updateWizardSteps = (step: number) => { color: inherit !important; background-color: #f5f5f5 !important; } +:deep(.tag-checkbox.is-checked .el-checkbox__label) { + color: inherit !important; +} diff --git a/packages/ui/src/pages/StudyBuilderPage/StudyBuilderPage.vue b/packages/ui/src/pages/StudyBuilderPage/StudyBuilderPage.vue index 9593274b..a99bd6db 100644 --- a/packages/ui/src/pages/StudyBuilderPage/StudyBuilderPage.vue +++ b/packages/ui/src/pages/StudyBuilderPage/StudyBuilderPage.vue @@ -11,9 +11,21 @@ import AppBreadcrumb from "@/components/ui/AppBreadcrumb.vue"; import { useTaskEditingStore } from "@/stores/taskEditing"; import TaskEditPanel from "./components/TaskEditPanel.vue"; import { useStudyBuilderStore } from "@/stores/studyBuilder"; +import { ElMessageBox } from "element-plus"; const router = useRouter(); const authStore = useAuthStore(); +const finishWelcomeWizard = () => { + ElMessageBox.alert( + "Congratulations! You've finished the walkthrough.", + "Finish", + { + confirmButtonText: "Close", + customStyle: { borderRadius: "10px", width: "278px", height: "160px" }, + customClass: "finish-msgbox", + } + ); +}; if (!authStore.currentUser) { router.push("/login"); @@ -76,7 +88,10 @@ const updateWizardSteps = (step: number) => { font-size: 14px; font-weight: 700; " - @click="updateWizardSteps(welcomeWizardStep + 1)" + @click=" + updateWizardSteps(welcomeWizardStep + 1); + finishWelcomeWizard(); + " >Close
3/3
@@ -112,3 +127,33 @@ const updateWizardSteps = (step: number) => { + + diff --git a/packages/ui/src/pages/StudyConditions/components/components/TagLabel.vue b/packages/ui/src/pages/StudyConditions/components/components/TagLabel.vue index 48f14af1..c2c68e5a 100644 --- a/packages/ui/src/pages/StudyConditions/components/components/TagLabel.vue +++ b/packages/ui/src/pages/StudyConditions/components/components/TagLabel.vue @@ -9,6 +9,8 @@ const props = defineProps<{ const tagIconMap: Record = { cognitive: "/brain.svg", vision: "/vision.svg", + hearing: "/hearing.svg", + training: "/training.svg", }; const icon = computed(() => { From e1f2641e854ec537e99eb1346819c9ee51cc5dad Mon Sep 17 00:00:00 2001 From: jecui Date: Sun, 7 Dec 2025 01:34:11 -0500 Subject: [PATCH 3/6] Fixes --- packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue b/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue index 10e682d1..05b1b820 100644 --- a/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue +++ b/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue @@ -66,6 +66,7 @@ const firstStudyForm = reactive({ }); const createFirstStudy = async () => { + createStudyPopup.value = false; const createdStudyId = await studiesAPI.createStudy(); const study = await studiesAPI.getStudy(createdStudyId); await studiesAPI.saveStudy(createdStudyId, { @@ -102,7 +103,7 @@ const updateWizardSteps = (step: number) => { title="Create a new Study" placement="left-start" width="308px" - popper-style="border-radius: 10px;" + popper-style="border-radius: 10px; z-index: 1500" :hide-after="0" :visible="welcomeWizardStep == 0" trigger="manual" @@ -256,6 +257,7 @@ const updateWizardSteps = (step: number) => { > {{ tag }} From b91b8a6fe974a514f1efe74575753302be03eec7 Mon Sep 17 00:00:00 2001 From: jecui Date: Sun, 7 Dec 2025 01:50:29 -0500 Subject: [PATCH 4/6] Fix ESLint errors --- .../StudyConditions/components/components/ConditionPanel.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/pages/StudyConditions/components/components/ConditionPanel.vue b/packages/ui/src/pages/StudyConditions/components/components/ConditionPanel.vue index a98018a9..cf0d2f56 100644 --- a/packages/ui/src/pages/StudyConditions/components/components/ConditionPanel.vue +++ b/packages/ui/src/pages/StudyConditions/components/components/ConditionPanel.vue @@ -19,17 +19,17 @@ const emit = defineEmits<(e: "open-sidebar") => void>();
From 552ae74db1ce95b3e1d17b65a2f810da4372dc77 Mon Sep 17 00:00:00 2001 From: jecui Date: Thu, 11 Dec 2025 17:03:31 -0500 Subject: [PATCH 5/6] Welcome wizard disappears upon restart --- .../src/pages/MyStudiesPage/MyStudiesPage.vue | 25 +++++++++------- .../StudyBuilderPage/StudyBuilderPage.vue | 22 +++++++------- .../components/StudyPanel.vue | 30 +++++++++++-------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue b/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue index 12cbfc35..1a4db181 100644 --- a/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue +++ b/packages/ui/src/pages/MyStudiesPage/MyStudiesPage.vue @@ -1,5 +1,5 @@ diff --git a/packages/ui/src/pages/StudyBuilderPage/components/StudyPanel.vue b/packages/ui/src/pages/StudyBuilderPage/components/StudyPanel.vue index f885cfea..10e8fb3f 100644 --- a/packages/ui/src/pages/StudyBuilderPage/components/StudyPanel.vue +++ b/packages/ui/src/pages/StudyBuilderPage/components/StudyPanel.vue @@ -4,23 +4,24 @@ import AppButton from "@/components/ui/AppButton.vue"; import SessionCard from "./SessionCard.vue"; import Draggable from "vuedraggable"; import StudyServerCode from "./StudyServerCode.vue"; -import { ref, watch, computed } from "vue"; +import { ref, watch } from "vue"; import { ArrowRight, ArrowLeft, Plus, Delete } from "@element-plus/icons-vue"; import { useRoute } from "vue-router"; import authAPI from "@/api/auth"; -import { useAuthStore } from "@/stores/auth"; +import { useQueryClient, useQuery } from "@tanstack/vue-query"; const studyBuilderStore = useStudyBuilderStore(); const route = useRoute(); const currentVariantIndex = ref(0); -const authStore = useAuthStore(); -const welcomeWizardStep = computed( - () => authStore.currentUser?.welcomeWizardStep ?? 0 -); +const queryClient = useQueryClient(); +const { data: currentUser } = useQuery({ + queryKey: ["user"], + queryFn: authAPI.getCurrentUser, +}); -const updateWizardSteps = (step: number) => { - authAPI.updateCurrentUser({ welcomeWizardStep: step }); - if (authStore.currentUser) authStore.currentUser.welcomeWizardStep = step; +const updateWizardSteps = async (step: number) => { + await authAPI.updateCurrentUser({ welcomeWizardStep: step }); + await queryClient.invalidateQueries(["user"]); }; const switchVariantByIndex = (index: number) => { @@ -203,7 +204,7 @@ watch( Close
2/3
@@ -258,7 +261,7 @@ watch(
SignupSign Up