Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 23 additions & 14 deletions components/ThemedInput.vue
Original file line number Diff line number Diff line change
@@ -1,44 +1,53 @@
<template>
<div
class="flex flex-col"
:class="type === 'checkbox' ? 'flex flex-row items-start' : 'flex flex-col'"
v-bind="$attrs"
>
<label
v-if="label && type !== 'checkbox'"
:for="id"
:class="`block text-sm font-medium ${instructions ? 'mb-1' : 'mb-2'}`"
v-if="label"
>
{{ label }}<span
v-if="required"
class="text-red-500"
>*</span>
</label>
<p
v-if="instructions"
v-if="instructions && type !== 'checkbox'"
class="text-xs mb-2 text-slate-500 italic"
>
{{ instructions }}
</p>
<input
:id="id"
:value="modelValue"
:checked="type === 'checkbox' ? (modelValue as boolean) : undefined"
:value="type !== 'checkbox' ? (modelValue as string) : undefined"
:type="type"
:required="required"
:aria-required="required"
@input="
$emit('update:modelValue', ($event.target as HTMLInputElement).value)
type === 'checkbox'
? $emit('update:modelValue', ($event.target as HTMLInputElement).checked)
: $emit('update:modelValue', ($event.target as HTMLInputElement).value)
"
:placeholder="placeholder"
:class="[
'border',
'block',
'h-10',
'w-full',
'rounded-md',
'px-2',
'placeholder:text-slate-400',
type === 'checkbox'
? 'h-4 w-4 mt-0.5 mr-2 cursor-pointer flex-shrink-0'
: 'border block h-10 w-full rounded-md px-2 placeholder:text-slate-400',
]"
>
<label
v-if="label && type === 'checkbox'"
:for="id"
class="text-sm font-normal cursor-pointer flex-1"
>
{{ label }}<span
v-if="required"
class="text-red-500"
>*</span>
</label>
</div>
</template>

Expand All @@ -51,7 +60,7 @@
label?: string;
placeholder?: string;
instructions?: string;
modelValue?: string;
modelValue?: string | boolean;
type?: string;
required?: boolean;
}>(),
Expand All @@ -65,4 +74,4 @@
required: false,
},
);
</script>
</script>
12 changes: 11 additions & 1 deletion components/account_management/PersonalInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@
required
class="my-4"
/>
<ThemedInput
id="mktg_email_opt_in_input"
v-model="mktgEmailOptIn"
type="checkbox"
:label="'Yes, I\'d like to receive occasional update and newsletter emails from LibreTexts. You can unsubscribe at any time using the link in our emails.'"
class="my-4"
/>
<div class="my-4">
<p class="text-sm font-light mt-4">
{{ $t("common.email") }}
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
16 changes: 15 additions & 1 deletion components/complete_registration/TimezoneForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
/>
</div>
</div>
<ThemedInput
id="mktg_email_opt_in_input"
v-model="mktg_email_opt_in"
type="checkbox"
:label="'Yes, I\'d like to receive occasional update and newsletter emails from LibreTexts. You can unsubscribe at any time using the link in our emails.'"
/>
<ThemedButton
type="submit"
@click="handleSubmit"
Expand All @@ -53,6 +59,7 @@
import { useAxios } from '@renderer/useAxios';
import LoadingIndicator from '@components/LoadingIndicator.vue';
import ThemedSelectInput from '../ThemedSelectInput.vue';
import ThemedInput from '../ThemedInput.vue';
import ThemedButton from '../ThemedButton.vue';
import { TimezoneOpts } from '@renderer/utils/timezones';
import { ADAPT_SPECIAL_ROLES } from '@renderer/utils/auth';
Expand All @@ -71,6 +78,7 @@ import { ADAPT_SPECIAL_ROLES } from '@renderer/utils/auth';
// UI & Data
const loading = ref(false);
const timezone = ref('');
const mktg_email_opt_in = ref(false);

// Methods

Expand All @@ -92,7 +100,13 @@ import { ADAPT_SPECIAL_ROLES } from '@renderer/utils/auth';
async function submitTimezone(data: TimezonePatch) {
try {
loading.value = true;
await axios.patch(`/users/${props.uuid}`, data);
console.log(
"mktg_email_opt_in", mktg_email_opt_in.value
)
await axios.patch(`/users/${props.uuid}`, {
...data,
mktg_email_opt_in: mktg_email_opt_in.value,
});

const queryParams = new URLSearchParams(window.location.search);

Expand Down
1 change: 1 addition & 0 deletions server/controllers/UserController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,7 @@ export class UserController {
'student_id',
'verify_status',
'lang',
'mktg_email_opt_in',
];
const unallowedExternalKeys = ['first_name', 'last_name'];
const apiUserOnlyKeys = ['verify_status'];
Expand Down
4 changes: 4 additions & 0 deletions server/models/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ export class User extends Model {
@Column(DataType.STRING)
declare stripe_id: string;

@Default(false)
@Column(DataType.BOOLEAN)
declare mktg_email_opt_in: boolean;

@BelongsTo(() => Language, {
foreignKey: 'lang',
targetKey: 'tag'
Expand Down
2 changes: 2 additions & 0 deletions server/types/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -81,6 +82,7 @@ export type UpdateUserBody = {
time_zone?: string;
student_id?: string;
lang?: string;
mktg_email_opt_in?: boolean;
};

export type UpdateUserAcademyOnlineBody = {
Expand Down
1 change: 1 addition & 0 deletions server/validators/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down