Skip to content

Commit

Permalink
➕ Frontend validation for FTUE
Browse files Browse the repository at this point in the history
  • Loading branch information
devmount committed Sep 13, 2024
1 parent 68ccc2b commit 640e321
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 9 deletions.
29 changes: 26 additions & 3 deletions frontend/src/components/FTUE/SetupProfile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import { storeToRefs } from 'pinia';
import { useFTUEStore } from '@/stores/ftue-store';
import { useUserStore } from '@/stores/user-store';
import { useI18n } from 'vue-i18n';
import { dayjsKey, callKey } from '@/keys';
import { dayjsKey, callKey, hasProfanityKey } from '@/keys';
import TextInput from '@/tbpro/elements/TextInput.vue';
import SelectInput from '@/tbpro/elements/SelectInput.vue';
import PrimaryButton from '@/tbpro/elements/PrimaryButton.vue';
const { t } = useI18n();
const dj = inject(dayjsKey);
const call = inject(callKey);
const hasProfanity = inject(hasProfanityKey);
const ftueStore = useFTUEStore();
const { hasNextStep } = storeToRefs(ftueStore);
const { nextStep } = ftueStore;
Expand All @@ -30,14 +32,31 @@ const username = ref(user.data?.username ?? '');
const timezone = ref(user.data.timezone ?? dj.tz.guess());
const isLoading = ref(false);
// Form validation
const errorFullName = ref<string>(null);
const errorUsername = ref<string>(null);
const onSubmit = async () => {
isLoading.value = true;
errorFullName.value = null;
errorUsername.value = null;
if (!formRef.value.checkValidity()) {
isLoading.value = false;
return;
}
if (hasProfanity(fullName.value)) {
errorFullName.value = t('validation.fieldContainsProfanity', { field: t('ftue.fullName') });
}
if (hasProfanity(username.value)) {
errorUsername.value = t('validation.fieldContainsProfanity', { field: t('label.username') });
}
if (errorFullName.value || errorUsername.value) {
isLoading.value = false;
return;
}
const response = await user.updateUser(call, {
name: fullName.value,
username: username.value,
Expand All @@ -57,8 +76,12 @@ const onSubmit = async () => {
<template>
<div class="content">
<form ref="formRef" autocomplete="off" autofocus @submit.prevent @keyup.enter="onSubmit">
<text-input name="full-name" v-model="fullName" :required="true">{{ t('ftue.fullName') }}</text-input>
<text-input name="username" v-model="username" :required="true">{{ t('label.username') }}</text-input>
<text-input name="full-name" v-model="fullName" :required="true" :error="errorFullName">
{{ t('ftue.fullName') }}
</text-input>
<text-input name="username" v-model="username" :required="true" :error="errorUsername">
{{ t('label.username') }}
</text-input>
<select-input
name="timezone"
:options="timezoneOptions"
Expand Down
25 changes: 21 additions & 4 deletions frontend/src/components/FTUE/SetupSchedule.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useFTUEStore } from '@/stores/ftue-store';
import { useUserStore } from '@/stores/user-store';
import { useCalendarStore } from '@/stores/calendar-store';
import { useScheduleStore } from '@/stores/schedule-store';
import { dayjsKey, callKey, isoWeekdaysKey } from '@/keys';
import { dayjsKey, callKey, isoWeekdaysKey, hasProfanityKey } from '@/keys';
import { Error, SelectOption } from '@/models';
import TextInput from '@/tbpro/elements/TextInput.vue';
import SelectInput from '@/tbpro/elements/SelectInput.vue';
Expand All @@ -19,6 +19,7 @@ const { t } = useI18n();
const dj = inject(dayjsKey);
const call = inject(callKey);
const isoWeekdays = inject(isoWeekdaysKey);
const hasProfanity = inject(hasProfanityKey);
const ftueStore = useFTUEStore();
const {
Expand Down Expand Up @@ -61,15 +62,25 @@ const schedule = ref({
const duration = computed(() => `${schedule.value.duration} minute`);
const isLoading = ref(false);
// Form validation
const errorScheduleName = ref<string>(null);
const onSubmit = async () => {
isLoading.value = true;
errorMessage.value = null;
errorScheduleName.value = null;
if (!formRef.value.checkValidity()) {
isLoading.value = false;
return;
}
if (hasProfanity(schedule.value.name)) {
errorScheduleName.value = t('validation.fieldContainsProfanity', { field: t('ftue.scheduleName') });
isLoading.value = false;
return;
}
const scheduleData = {
...schedules?.value[0] ?? {},
active: true,
Expand Down Expand Up @@ -131,10 +142,16 @@ onMounted(async () => {
<div class="content">
<form ref="formRef" autocomplete="off" autofocus @submit.prevent @keyup.enter="onSubmit">
<div class="column">
<text-input name="scheduleName" v-model="schedule.name" required>{{ t('ftue.scheduleName') }}</text-input>
<text-input name="scheduleName" v-model="schedule.name" required :error="errorScheduleName">
{{ t('ftue.scheduleName') }}
</text-input>
<div class="pair">
<text-input type="time" name="startTime" v-model="schedule.startTime" required>{{ t('label.startTime') }}</text-input>
<text-input type="time" name="endTime" v-model="schedule.endTime" required>{{ t('label.endTime') }}</text-input>
<text-input type="time" name="startTime" v-model="schedule.startTime" required>
{{ t('label.startTime') }}
</text-input>
<text-input type="time" name="endTime" v-model="schedule.endTime" required>
{{ t('label.endTime') }}
</text-input>
</div>
<bubble-select class="bubbleSelect" :options="scheduleDayOptions" v-model="schedule.days" />
</div>
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/tbpro/elements/TextInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const focus = () => {
interface Props {
name: string;
help?: string;
remoteError?: string;
error?: string;
type?: string;
placeholder?: string;
prefix?: string; // A prefix shows up at the start of the input field and moves the actual input to the right.
Expand All @@ -38,7 +38,7 @@ interface Props {
const props = withDefaults(defineProps<Props>(), {
type: 'text',
help: null,
remoteError: null,
error: null,
placeholder: null,
prefix: null,
required: false,
Expand Down Expand Up @@ -96,6 +96,9 @@ const onChange = () => {
<span v-if="isInvalid" class="help-label invalid">
{{ validationMessage }}
</span>
<span v-else-if="error" class="help-label invalid">
{{ error }}
</span>
<span v-else-if="help" class="help-label">
{{ help }}
</span>
Expand Down

0 comments on commit 640e321

Please sign in to comment.