diff --git a/src/components/Employees/EmployeeForm.vue b/src/components/Employees/EmployeeForm.vue new file mode 100644 index 0000000..cd76fb7 --- /dev/null +++ b/src/components/Employees/EmployeeForm.vue @@ -0,0 +1,327 @@ + + + + + + + + Persönliche Informationen + + Vorname: + + + {{error.$message}} + + + Nachname: + + + Kürzel: + + + + {{ error.$message }} + + + + + Kontaktdaten + Telefonnummer: + + Handynummer: + + E-Mail-Adresse: + + + {{error.$message}} + + + + + + + Vertragsinformationen: + Wochenstunden: + + + + + {{error.$message}} + + + + + + {{ labelUserEnabled }} + + + Benutzername: + + + {{ error.$message }} + + Neues Passwort: + + + {{error.$message}} + + Neues Passwort wiederholen: + + + {{error.$message}} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/components/VProfileControls.vue b/src/components/Employees/EmployeeFormControls.vue similarity index 79% rename from src/components/VProfileControls.vue rename to src/components/Employees/EmployeeFormControls.vue index 2a69927..6c36c72 100644 --- a/src/components/VProfileControls.vue +++ b/src/components/Employees/EmployeeFormControls.vue @@ -1,12 +1,14 @@ + - + Zurück @@ -35,7 +38,7 @@ function onCancel() { Mitarbeiter speichern - + Abbrechen diff --git a/src/components/Employees/IndexControls.vue b/src/components/Employees/IndexControls.vue new file mode 100644 index 0000000..aba648f --- /dev/null +++ b/src/components/Employees/IndexControls.vue @@ -0,0 +1,20 @@ + + + + + Zurück + + + + + Neuer Mitarbeiter + + + + + + + \ No newline at end of file diff --git a/src/components/Schedule/Schedule.vue b/src/components/Schedule/Schedule.vue index c45ed80..b8cf864 100644 --- a/src/components/Schedule/Schedule.vue +++ b/src/components/Schedule/Schedule.vue @@ -3,7 +3,7 @@ AddEmployeeModal( :searchData="store.state.rows" - :searchFields="['first_name', 'last_name']" + :searchFields="['firstName', 'lastName']" :searchRow="addEmployeeRow" :modalId="modalId" @emitResult="addEmployee($event)" diff --git a/src/router/index.ts b/src/router/index.ts index 0dfec62..af5f1b4 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -30,6 +30,15 @@ const routes: Array = [ requiresAdmin: true, } }, + { + path: '/employees/new', + name: 'Employees/New', + component: () => import('@/views/Employees/New.vue'), + meta: { + requiresAuth: true, + requiresAdmin: true + } + }, { path: '/employees/:id', name: 'Employees/Details', diff --git a/src/stores/employee.ts b/src/stores/employee.ts index 879e3bc..43a3be5 100644 --- a/src/stores/employee.ts +++ b/src/stores/employee.ts @@ -2,6 +2,7 @@ import { defineStore, acceptHMRUpdate } from 'pinia' import axios from '@/axios' import { useUser } from './user' import { useNotifications } from './notifications' +import Axios from 'axios' const user = useUser() const notifications = useNotifications() @@ -12,7 +13,7 @@ export const useEmployee = defineStore({ state: () => { return { clean: { - /** @type Employee */ + /** @type { Employee } */ employee: { id: NaN, firstName: '', @@ -25,7 +26,8 @@ export const useEmployee = defineStore({ isActive: false, username: '', password: '', - passwordConfirm: '' + passwordConfirm: '', + role: '' }, }, @@ -42,8 +44,12 @@ export const useEmployee = defineStore({ isActive: false, username: '', password: '', - passwordConfirm: '' + passwordConfirm: '', + role: '' }, + + /** @type { EmployeeApiValidationError[] } */ + apiValidationErrors: Array(), } }, @@ -77,8 +83,17 @@ export const useEmployee = defineStore({ Object.assign(this.employee, this.clean.employee) }, - /** TODO: #23 Persist user if password is changed */ async persist() { + + if(this.employee.id){ + this.patchEmployee() + } + else { + this.postEmployee() + } + }, + + async patchEmployee() { try { let result let payload = Object.assign({}, this.employee) @@ -101,15 +116,52 @@ export const useEmployee = defineStore({ Object.assign(this.clean.employee, this.employee) notifications.add('success', result.statusText) + return true } catch(error) { - if(error instanceof Error) { - console.log(error) + console.log("Patch Employee Error") + if(Axios.isAxiosError(error)) { + let data = error.response?.data as { errors: EmployeeApiValidationError[] } + this.apiValidationErrors = [...data.errors] + } + else if(error instanceof Error) { notifications.add('danger', error.message, -1) } - else console.log(error) + console.log(error) + return false } - } + }, + + async postEmployee() { + let result + try { + result = await axios.post( + 'employees', + this.employee, + { + headers: user.header + } + ) + + this.assignTruthyValues(this.employee, result.data) + this.assignTruthyValues(this.clean.employee, result.data) + notifications.add('success', result.statusText) + + return true + } + catch(error){ + console.log("Post Employee Error") + if(Axios.isAxiosError(error)) { + let data = error.response?.data as { errors: EmployeeApiValidationError[] } + this.apiValidationErrors = [...data.errors] + } + else if(error instanceof Error) { + notifications.add('danger', error.message, -1) + } + console.log(error) + return false + } + }, }, getters: { diff --git a/src/stores/employees.ts b/src/stores/employees.ts index 7722543..92f4b5e 100644 --- a/src/stores/employees.ts +++ b/src/stores/employees.ts @@ -9,7 +9,7 @@ export default defineStore('employees', () => { const user = useUser() const state = reactive({ - rows: Array(), + rows: Array(), columns: Array(), meta : { @@ -41,7 +41,7 @@ export default defineStore('employees', () => { } )).data - Object.assign(state.meta, data.meta) + _assign(state.meta, data.meta) state.rows = _cloneDeep(data.data) _assign(state.columns, fetchColumns()) @@ -91,89 +91,4 @@ export default defineStore('employees', () => { setPage } -}) - -/* -export const useEmployees = defineStore('employees', { - state: () => { - return { - /** - * @type any[] - - rows: Array(), - - meta: { - current_page: NaN, - first_page: NaN, - last_page: NaN, - per_page: NaN, - total: NaN - }, - - columns: Array(), - - limit: 10, - page: 1, - sort_by: '', - simple_search: '' - } - }, - - actions: { - /** - * @param: {number} limit - QueryString: limit=20 etc. - * @param: {number} page - QueryString: page=1 etc. - * @param: {string} sortBy - QueryString: sort_by=asc(col1),desc(col2),... - * @param: {string} simpleSearch - QueryString: simple_search=query(col1,col2,...) - ** - async fetchFromApi() { - try { - - const data : any = (await axios.get( - '/employees', - { - params: { - limit: this.limit, - page: this.page, - sort_by: this.sort_by, - simple_search: this.simple_search - }, - headers: user.header - } - )).data - - Object.assign(this.meta, data.meta) - this.rows = _cloneDeep(data.data) - - this.columns = this.fetchColumns() - } - catch(err) { - console.log(err) - } - }, - - fetchColumns() : string[] { - if(this.rows[0]){ - return Object.keys(this.rows[0]) - } - return [] - }, - - setLimit(limit : number) { - this.limit = limit - this.fetchFromApi() - }, - setSortBy(sortBy : string) { - this.sort_by = sortBy - this.fetchFromApi() - }, - setSimpleSearch(simpleSearch : string) { - this.simple_search = simpleSearch - this.fetchFromApi() - }, - setPage(page : number) { - this.page = page - this.fetchFromApi() - } - } -}) */ \ No newline at end of file +}) \ No newline at end of file diff --git a/src/stores/settings.ts b/src/stores/settings.ts index 605d61c..fe15e76 100644 --- a/src/stores/settings.ts +++ b/src/stores/settings.ts @@ -37,8 +37,6 @@ export const useSettings = defineStore({ headers: user.header }) - console.log(result) - result.data.forEach((element) => { this.settings[_camelCase(element.key)] = JSON.parse(element.value) }) @@ -67,7 +65,6 @@ export const useSettings = defineStore({ settings.push({key: _kebabCase(key), value: JSON.stringify(value)}) } } - console.log(settings) const result = await axios.post('settings', { settings @@ -75,7 +72,6 @@ export const useSettings = defineStore({ { headers: user.header }) - console.log(result) } } }) \ No newline at end of file diff --git a/src/types/employees.d.ts b/src/types/employees.d.ts new file mode 100644 index 0000000..d2d3a8e --- /dev/null +++ b/src/types/employees.d.ts @@ -0,0 +1,23 @@ +type Employee = { + id: number, + firstName: string, + lastName: string, + email: string, + phone: string, + mobile: string, + role: string, + shorthand: string, + contractHours?: number, + username?: string, + password?: string, + passwordConfirm?: string, + isActive: boolean, + createdAt?: Date, + updatedAt?: Date +} + +type EmployeeApiValidationError = { + rule: string, + field: keyof Employee, + message: string +} \ No newline at end of file diff --git a/src/types/schedule-data.d.ts b/src/types/schedule-data.d.ts index fa74e99..cd54422 100644 --- a/src/types/schedule-data.d.ts +++ b/src/types/schedule-data.d.ts @@ -2,19 +2,6 @@ type ScheduleData = [ ...ScheduleMonth[] ] -type Employee = { - id: number, - first_name: string, - last_name: string, - email: string, - phone: string, - mobile: string, - role: string, - shorthand: string, - contractHours?: number - username?: string -} - type ScheduleRow = { dates : (Date | null)[], employees : Employee[] diff --git a/src/views/Employees/Details.vue b/src/views/Employees/Details.vue index 3105a6e..25504e0 100644 --- a/src/views/Employees/Details.vue +++ b/src/views/Employees/Details.vue @@ -1,256 +1,28 @@ - - + + - - Persönliche Informationen - - Vorname: - - - {{error.$message}} - - - Nachname: - - - Kürzel: - - - - {{ error.$message }} - - - - - Kontaktdaten - Telefonnummer: - - Handynummer: - - E-Mail-Adresse: - - - {{error.$message}} - - - - - - - Vertragsinformationen: - Wochenstunden: - - - - - {{error.$message}} - - - - - - {{ labelUserEnabled }} - - - Benutzername: - - - {{ error.$message }} - - Neues Passwort: - - - {{error.$message}} - - Neues Passwort wiederholen: - - - {{error.$message}} - - - - - - - + /> + diff --git a/src/views/Employees/Index.vue b/src/views/Employees/Index.vue index b99b762..e80e6d2 100644 --- a/src/views/Employees/Index.vue +++ b/src/views/Employees/Index.vue @@ -8,6 +8,7 @@ @update-columns-selected="updateColumnsSelected" /> + import SimpleSearch from '@/components/Employees/SimpleSearch.vue'; import IndexSettingsModal from '@/components/Employees/IndexSettingsModal.vue'; +import IndexControls from '@/components/Employees/IndexControls.vue'; import VPaginator from '@/components/VPaginator.vue'; import { onMounted, reactive, computed } from 'vue' import { useRouter } from 'vue-router' @@ -77,6 +79,7 @@ const sort_by = reactive({ }) onMounted(async () =>{ + console.log("Employees Index onMounted") await store.fetchFromApi() await settingsStore.fetchFromApi() }) diff --git a/src/views/Employees/New.vue b/src/views/Employees/New.vue new file mode 100644 index 0000000..aa9c30f --- /dev/null +++ b/src/views/Employees/New.vue @@ -0,0 +1,17 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/views/Login.vue b/src/views/Login.vue index d0e8c89..e9ba0f6 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -95,10 +95,6 @@ watch(input, () => { v$.value.$reset() }) -userStore.$subscribe((mutation, state) => { - // if(state.isLoggedIn) router.push({name: 'Home'}) -}) - async function onClick() { if(await v$.value.$validate()) { await userStore.login(input.username, input.password, router)