From 8e2c1e60383f7ebce2313b58472201d90884a85e Mon Sep 17 00:00:00 2001 From: Akhileshwar Shriram <112577383+AkhilTheBoss@users.noreply.github.com> Date: Mon, 12 Jan 2026 07:12:20 -0800 Subject: [PATCH] feat: added marketing email opt-in feature --- components/ThemedInput.vue | 37 ++++++++++++------- .../account_management/PersonalInfo.vue | 12 +++++- .../complete_registration/TimezoneForm.vue | 16 +++++++- server/controllers/UserController.ts | 1 + server/models/User.ts | 4 ++ server/types/users.ts | 2 + server/validators/user.ts | 1 + 7 files changed, 57 insertions(+), 16 deletions(-) diff --git a/components/ThemedInput.vue b/components/ThemedInput.vue index 50d0229..c8c6b3a 100644 --- a/components/ThemedInput.vue +++ b/components/ThemedInput.vue @@ -1,12 +1,12 @@ @@ -51,7 +60,7 @@ label?: string; placeholder?: string; instructions?: string; - modelValue?: string; + modelValue?: string | boolean; type?: string; required?: boolean; }>(), @@ -65,4 +74,4 @@ required: false, }, ); - + \ No newline at end of file diff --git a/components/account_management/PersonalInfo.vue b/components/account_management/PersonalInfo.vue index b63af73..aba59d8 100644 --- a/components/account_management/PersonalInfo.vue +++ b/components/account_management/PersonalInfo.vue @@ -58,6 +58,13 @@ required class="my-4" /> +

{{ $t("common.email") }} @@ -139,6 +146,7 @@ const editMode = ref(false); const firstName = ref(''); const lastName = ref(''); + const mktgEmailOptIn = ref(false); const firstErr = ref(false); const lastErr = ref(false); const isDirty = ref(false); @@ -148,10 +156,11 @@ // Intialize the form with the user's current name firstName.value = pageContext.user?.first_name ?? ''; lastName.value = pageContext.user?.last_name ?? ''; + mktgEmailOptIn.value = pageContext.user?.mktg_email_opt_in ?? false; // Watch for changes to the form fields and set the dirty flag watch( - () => [firstName.value, lastName.value, fileToUploadName.value], + () => [firstName.value, lastName.value, fileToUploadName.value, mktgEmailOptIn.value], () => { if (isDirty.value) return; // Don't set dirty flag if already dirty isDirty.value = true; @@ -282,6 +291,7 @@ const response = await axios.patch(`/users/${pageContext.user.uuid}`, { first_name: firstName.value, last_name: lastName.value, + mktg_email_opt_in: mktgEmailOptIn.value, }); if (!response.data) { diff --git a/components/complete_registration/TimezoneForm.vue b/components/complete_registration/TimezoneForm.vue index 406e1ef..fc83d57 100644 --- a/components/complete_registration/TimezoneForm.vue +++ b/components/complete_registration/TimezoneForm.vue @@ -29,6 +29,12 @@ />

+ Language, { foreignKey: 'lang', targetKey: 'tag' diff --git a/server/types/users.ts b/server/types/users.ts index a9124e2..144ac71 100644 --- a/server/types/users.ts +++ b/server/types/users.ts @@ -22,6 +22,7 @@ export type User = { last_password_change: Date; lang: string; is_developer: boolean; + mktg_email_opt_in?: boolean; created_at: Date; updated_at: Date; }; @@ -81,6 +82,7 @@ export type UpdateUserBody = { time_zone?: string; student_id?: string; lang?: string; + mktg_email_opt_in?: boolean; }; export type UpdateUserAcademyOnlineBody = { diff --git a/server/validators/user.ts b/server/validators/user.ts index 65f11f2..d234802 100644 --- a/server/validators/user.ts +++ b/server/validators/user.ts @@ -93,6 +93,7 @@ export const updateUserSchema = joi.object({ student_id: joi.string().min(3).max(50), disabled: joi.boolean(), lang: joi.string().min(2).max(10), + mktg_email_opt_in: joi.boolean(), }); export const updateUserEmailSchema = joi.object({