Skip to content

Commit

Permalink
refactor(dashboard/user-overview): refactored create user form (#324)
Browse files Browse the repository at this point in the history
* refactor(dashboard/user-overview): refactored create user form

* fix(dashboard/user-overview): re-added code that was thought to be unused

* refactor(dashboard/user-create-form): some small code changes
  • Loading branch information
CodeNamedRobin authored Sep 4, 2024
1 parent cc2d7b5 commit 9975799
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 112 deletions.
3 changes: 2 additions & 1 deletion apps/dashboard/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@
"User Type": "User Type",
"firstName": "First Name",
"lastName": "Last Name",
"ofAge": "18+"
"ofAge": "18+",
"createUser": "Create user"
},
"errorMessages": {
"posNotFound": "The requested POS was not found."
Expand Down
3 changes: 2 additions & 1 deletion apps/dashboard/src/locales/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@
"User Type": "Gebruikerstype",
"firstName": "Voornaam",
"lastName": "Achternaam",
"ofAge": "18+"
"ofAge": "18+",
"createUser": "Maak gebruiker"
},
"contact": {
"Contact": "Contact",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<template>
<div class="flex flex-column gap-2">
<InputSpan :label="t('userDetails.First name')"
:value="form.model.firstName.value.value"
:attributes="form.model.firstName.attr.value"
@update:value="form.context.setFieldValue('firstName', $event)"
:errors="form.context.errors.value.firstName"
:disabled="!edit"
id="name" :placeholder="t('userDetails.First name')" type="text" />
<InputSpan :label="t('userDetails.Last name')"
:value="form.model.lastName?.value.value"
:attributes="form.model.lastName?.attr.value"
@update:value="form.context.setFieldValue('lastName', $event)"
:errors="form.context.errors.value.lastName"
:disabled="!edit"
id="name" placeholder="Doe" type="text" />
<InputSpan :label="t('userDetails.Nickname')"
:value="form.model.nickname?.value.value || undefined"
:attributes="form.model.nickname?.attr.value"
@update:value="form.context.setFieldValue('nickname', $event)"
:errors="form.context.errors.value.nickname"
:disabled="!edit"
id="name" :placeholder="t('userDetails.Nickname')" type="text" />
<InputSpan
:label="t('userDetails.Email address')"
:value="form.model.email?.value.value"
:attributes="form.model.email?.attr.value"
@update:value="form.context.setFieldValue('email', $event)"
:errors="form.context.errors.value.email"
:disabled="!edit"
id="name" placeholder="[email protected]" type="text" />
<InputSpan :label="t('userDetails.Usertype')"
:value="form.model.userType?.value.value"
:attributes="form.model.userType?.attr.value"
@update:value="form.context.setFieldValue('userType', $event)"
:errors="form.context.errors.value.userType"
id="name" :placeholder="t('userDetails.Usertype')" type="usertype"/>
<InputSpan :label="t('profile.ofAge')"
:value="form.model.ofAge?.value.value"
:attributes="form.model.ofAge?.attr.value"
@update:value="form.context.setFieldValue('ofAge', $event)"
:errors="form.context.errors.value.ofAge"
:disabled="!edit"
id="name" :placeholder="t('profile.ofAge')" type="boolean"/>
<InputSpan :label="t('profile.canGoIntoDebt')"
:value="form.model.canGoIntoDebt?.value.value"
:attributes="form.model.canGoIntoDebt?.attr.value"
@update:value="form.context.setFieldValue('canGoIntoDebt', $event)"
:errors="form.context.errors.value.canGoIntoDebt"
:disabled="!edit"
id="name" :placeholder="t('profile.canGoIntoDebt')" type="boolean"/>
</div>
</template>

<script setup lang="ts">
import InputSpan from "@/components/InputSpan.vue";
import { useI18n } from "vue-i18n";
import { useToast } from "primevue/usetoast";
import { type Form, setSubmit } from "@/utils/formUtils";
import type { CreateUserRequest } from "@sudosos/sudosos-client";
import { type PropType } from "vue";
import { createUserSchema } from "@/utils/validation-schema";
import * as yup from "yup";
import apiService from "@/services/ApiService";
import { handleError } from "@/utils/errorUtils";
const { t } = useI18n();
const toast = useToast();
const emit = defineEmits(['update:edit']);
const props = defineProps({
form: {
type: Object as PropType<Form<yup.InferType<typeof createUserSchema>>>,
required: true,
},
edit: {
type: Boolean,
required: false,
default: true,
},
});
setSubmit(props.form, props.form.context.handleSubmit(async (values) => {
const createUserRequest: CreateUserRequest = {
...values,
email: values.email || '',
nickname: values.nickname || '',
type: values.userType,
ofAge: values.ofAge,
canGoIntoDebt: values.canGoIntoDebt,
};
await apiService.user.createUser(createUserRequest).then(() => {
toast.add({
severity: 'success',
summary: t('successMessages.success'),
detail: t('successMessages.userUpdated'),
life: 3000,
});
emit('update:edit', false);
}).catch((error) => {
handleError(error, toast);
});
}));
</script>

<style scoped>
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
</CardComponent>
</div>
</div>
</template>s
</template>

<script setup lang="ts">
import { onBeforeMount, ref } from "vue";
Expand Down
132 changes: 31 additions & 101 deletions apps/dashboard/src/modules/admin/views/AdminUserOverView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<InputIcon class="pi pi-search"> </InputIcon>
<InputText v-model="searchQuery" :placeholder="t('app.Search')" />
</IconField>
<Button :label="t('app.Create')" icon="pi pi-plus" @click="visible = true" />
<Button :label="t('app.Create')" icon="pi pi-plus" @click="showDialog = true" />
</div>
</template>
<Column field="gewisId" header="GEWIS ID">
Expand Down Expand Up @@ -105,101 +105,60 @@

</Column>
</DataTable>
<Dialog v-model:visible="visible" modal header="Create User" :style="{ width: '50vw' }" @hide="resetForm">
<form @submit.prevent="handleCreateUser" class="p-fluid">
<div class="field">
<label for="firstName">{{ t('c_userTable.firstName')}}</label>
<InputText id="firstName" v-model="firstName" v-bind="firstNameAttrs" />
<small class="p-error">{{ errors.firstName }}</small>
</div>
<div class="field">
<label for="lastName">{{ t('c_userTable.lastName')}}</label>
<InputText id="lastName" v-model="lastName" v-bind="lastNameAttrs" />
<small class="p-error">{{ errors.lastName }}</small>
</div>
<div class="field">
<label for="userType">{{ t('c_userTable.User Type')}}</label>
<Dropdown
id="userType"
v-model="userType"
v-bind="userTypeAttrs"
:options="userTypes"
optionLabel="name"
:placeholder="t('c_userTable.Select Type')"
optionValue="name"
/>
<small class="p-error">{{ errors.userType }}</small>
</div>
<div class="field">
<label for="email">{{ t('userDetails.Email address')}}</label>
<InputText id="email" v-model="email" v-bind="emailAttrs" />
<small class="p-error">{{ errors.email }}</small>
</div>
<div class="field">
<label for="ofAge">{{ t('c_userTable.ofAge')}}</label>
<Checkbox id="ofAge" v-model="ofAge" v-bind="ofAgeAttrs" binary />
<small class="p-error">{{ errors.ofAge }}</small>
</div>
<div class="field">
<label for="canGoIntoDebt">{{ t('profile.canGoIntoDebt') }}</label>
<Checkbox id="canGoIntoDebt" v-model="canGoIntoDebt" v-bind="canGoIntoDebtAttrs" binary />
<small class="p-error">{{ errors.canGoIntoDebt }}</small>
</div>
<div class="flex justify-content-end">
<Button :label="t('c_containerEditModal.cancel')" class="p-button-text" @click="visible = false" />
<Button :label="t('c_confirmationModal.Save')" class="p-button-outlined" type="submit" />
</div>
</form>
</Dialog>
</CardComponent>
<FormDialog :header="t('c_userTable.createUser')" v-model:modelValue="showDialog"
:form="form" >
<template #form="slotProps">
<UserCreateForm
:form="slotProps.form"
v-model:isVisible="showDialog"
:edit="true"
@submit:success="showDialog = false"
/>
</template>
</FormDialog>
</div>
</template>

<script setup lang="ts">
import { useUserStore } from "@sudosos/sudosos-frontend-common";
import { computed, onMounted, ref, type Ref, watch } from "vue";
import apiService from '@/services/ApiService';
import type { CreateUserRequest, GewisUserResponse, UserResponse } from "@sudosos/sudosos-client";
import type { GewisUserResponse, UserResponse } from "@sudosos/sudosos-client";
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
import { FilterMatchMode } from 'primevue/api';
import Checkbox from "primevue/checkbox";
import Dropdown from 'primevue/dropdown';
import InputText from 'primevue/inputtext';
import router from '@/router';
import { userDetailsSchema, userTypes } from "@/utils/validation-schema";
import { useForm } from 'vee-validate';
import { createUserSchema, userTypes } from "@/utils/validation-schema";
import Fuse from 'fuse.js';
import CardComponent from '@/components/CardComponent.vue';
import Skeleton from "primevue/skeleton";
import IconField from "primevue/iconfield";
import InputIcon from "primevue/inputicon";
import { useI18n } from "vue-i18n";
import FormDialog from "@/components/FormDialog.vue";
import UserCreateForm from "@/modules/admin/components/users/forms/UserCreateForm.vue";
import { schemaToForm } from "@/utils/formUtils";
import { useUserStore } from "@sudosos/sudosos-frontend-common";
import router from "@/router";
const { t } = useI18n();
const userStore = useUserStore();
const searchQuery: Ref<string> = ref('');
const { defineField, handleSubmit, errors, resetForm } = useForm({
validationSchema: userDetailsSchema,
});
const showDialog: Ref<boolean> = ref(false);
const form = schemaToForm(createUserSchema);
const filters = ref({
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
type: { value: null, matchMode: FilterMatchMode.EQUALS },
});
const [firstName, firstNameAttrs] = defineField('firstName', {});
const [lastName, lastNameAttrs] = defineField('lastName', {});
const [userType, userTypeAttrs] = defineField('userType', {});
const [email, emailAttrs] = defineField('email', {});
const [ofAge, ofAgeAttrs] = defineField('ofAge', {});
const [canGoIntoDebt, canGoIntoDebtAttrs] = defineField('canGoIntoDebt', {});
const isActiveFilter: Ref<boolean> = ref(true);
const ofAgeFilter: Ref<boolean> = ref(true);
const visible: Ref<boolean> = ref(false);
const isLoading = ref(true);
const totalRecords = ref(0);
const allUsers: Ref<GewisUserResponse[]> = ref(new Array(10));
Expand Down Expand Up @@ -270,42 +229,6 @@ watch(searchQuery, () => {
delayedAPICall(0);
});
const handleCreateUser = handleSubmit(async (values) => {
// Ensure userType is a number. You might need a more complex check depending on your data.
const userTypeAsNumber = Number(values.userType);
// Check if conversion was successful or if the value was already a number
if (isNaN(userTypeAsNumber)) {
console.error('User type is not a valid number:', values.userType);
// Handle error appropriately, possibly aborting the submit or setting a default
return;
}
const createUserRequest: CreateUserRequest = {
firstName: values.firstName,
lastName: values.lastName,
type: userTypeAsNumber, // Use the converted/validated number here
email: values.email || '',
ofAge: values.ofAge,
canGoIntoDebt: values.canGoIntoDebt,
};
const response = await apiService.user.createUser(createUserRequest);
if (response.status === 200) {
await router.push({ name: 'user-overview' });
} else {
console.error(response.status + ': ' + response.statusText);
}
visible.value = false;
});
async function handleInfoPush(userId: number) {
const clickedUser: UserResponse | undefined = allUsers.value.find(
(record) => record.id == userId
);
if (clickedUser) userStore.addUser(clickedUser);
router.push({ name: 'user', params: { userId } });
}
const sortedUsers = computed(() => {
const fuzzed: UserResponse[] = new Fuse(allUsersWithFullName.value, {
keys: ['fullName'],
Expand All @@ -318,6 +241,13 @@ const sortedUsers = computed(() => {
return fuzzed;
});
async function handleInfoPush(userId: number) {
const clickedUser: UserResponse | undefined = allUsers.value.find(
(record) => record.id == userId
);
if (clickedUser) userStore.addUser(clickedUser);
router.push({ name: 'user', params: { userId } });
}
</script>

<style scoped>
Expand Down
13 changes: 5 additions & 8 deletions apps/dashboard/src/utils/validation-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,23 @@ import type { ContainerInStore } from "@/stores/container.store";

const t = i18n.global.t;

export const userDetailsSchema = toTypedSchema(
export const createUserSchema =
yup.object({
firstName: yup.string().required(),
lastName: yup.string().required(),
email: yup.string().email(),
nickname: yup.string(),
userType: yup.mixed().required(),
isActive: yup.boolean().required().default(true),
userType: yup.number().required().default(4),
ofAge: yup.boolean().required().default(false),
canGoIntoDebt: yup.boolean().required().default(false),
})
);
});

export const simpleUserDetailsSchema = toTypedSchema(
export const simpleUserDetailsSchema =
yup.object({
firstName: yup.string().required(),
lastName: yup.string().required(),
email: yup.string().email(),
})
);
});

export const editPasswordSchema = toTypedSchema(
yup.object({
Expand Down

0 comments on commit 9975799

Please sign in to comment.