generazione applicazione e entita

This commit is contained in:
2025-12-10 17:19:16 +01:00
parent e4b8486f4b
commit 9ad99bd05f
363 changed files with 36699 additions and 44 deletions

View File

@@ -0,0 +1,91 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import AuditLogDetails from './audit-log-details.vue';
import AuditLogService from './audit-log.service';
type AuditLogDetailsComponentType = InstanceType<typeof AuditLogDetails>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const auditLogSample = { id: 123 };
describe('Component Tests', () => {
let alertService: AlertService;
afterEach(() => {
vitest.resetAllMocks();
});
describe('AuditLog Management Detail Component', () => {
let auditLogServiceStub: SinonStubbedInstance<AuditLogService>;
let mountOptions: MountingOptions<AuditLogDetailsComponentType>['global'];
beforeEach(() => {
route = {};
auditLogServiceStub = sinon.createStubInstance<AuditLogService>(AuditLogService);
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'router-link': true,
},
provide: {
alertService,
auditLogService: () => auditLogServiceStub,
},
};
});
describe('Navigate to details', () => {
it('Should call load all on init', async () => {
// GIVEN
auditLogServiceStub.find.resolves(auditLogSample);
route = {
params: {
auditLogId: `${123}`,
},
};
const wrapper = shallowMount(AuditLogDetails, { global: mountOptions });
const comp = wrapper.vm;
// WHEN
await comp.$nextTick();
// THEN
expect(comp.auditLog).toMatchObject(auditLogSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
auditLogServiceStub.find.resolves(auditLogSample);
const wrapper = shallowMount(AuditLogDetails, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,46 @@
import { type Ref, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type IAuditLog } from '@/shared/model/audit-log.model';
import AuditLogService from './audit-log.service';
export default defineComponent({
name: 'AuditLogDetails',
setup() {
const dateFormat = useDateFormat();
const auditLogService = inject('auditLogService', () => new AuditLogService());
const alertService = inject('alertService', () => useAlertService(), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const auditLog: Ref<IAuditLog> = ref({});
const retrieveAuditLog = async auditLogId => {
try {
const res = await auditLogService().find(auditLogId);
auditLog.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.auditLogId) {
retrieveAuditLog(route.params.auditLogId);
}
return {
...dateFormat,
alertService,
auditLog,
previousState,
t$: useI18n().t,
};
},
});

View File

@@ -0,0 +1,69 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<div v-if="auditLog">
<h2 class="jh-entity-heading" data-cy="auditLogDetailsHeading">
<span>{{ t$('smartbookingApp.auditLog.detail.title') }}AuditLog</span> {{ auditLog.id }}
</h2>
<dl class="row-md jh-entity-details">
<dt>
<span>{{ t$('smartbookingApp.auditLog.entitaTipo') }}</span>
</dt>
<dd>
<span>{{ t$('smartbookingApp.TipoEntita.' + auditLog.entitaTipo) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.auditLog.entitaId') }}</span>
</dt>
<dd>
<span>{{ auditLog.entitaId }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.auditLog.azione') }}</span>
</dt>
<dd>
<span>{{ t$('smartbookingApp.AzioneAudit.' + auditLog.azione) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.auditLog.dettagli') }}</span>
</dt>
<dd>
<span>{{ auditLog.dettagli }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.auditLog.ipAddress') }}</span>
</dt>
<dd>
<span>{{ auditLog.ipAddress }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.auditLog.createdAt') }}</span>
</dt>
<dd>
<span v-if="auditLog.createdAt">{{ formatDateLong(auditLog.createdAt) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.auditLog.utente') }}</span>
</dt>
<dd>
<div v-if="auditLog.utente">
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: auditLog.utente.id } }">{{
auditLog.utente.username
}}</router-link>
</div>
</dd>
</dl>
<button type="submit" @click.prevent="previousState()" class="btn btn-info" data-cy="entityDetailsBackButton">
<font-awesome-icon icon="arrow-left"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.back') }}</span>
</button>
<router-link v-if="auditLog.id" :to="{ name: 'AuditLogEdit', params: { auditLogId: auditLog.id } }" custom v-slot="{ navigate }">
<button @click="navigate" class="btn btn-primary">
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.edit') }}</span>
</button>
</router-link>
</div>
</div>
</div>
</template>
<script lang="ts" src="./audit-log-details.component.ts"></script>

View File

@@ -0,0 +1,161 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import dayjs from 'dayjs';
import sinon, { type SinonStubbedInstance } from 'sinon';
import UtenteAppService from '@/entities/utente-app/utente-app.service';
import AlertService from '@/shared/alert/alert.service';
import { DATE_TIME_LONG_FORMAT } from '@/shared/composables/date-format';
import AuditLogUpdate from './audit-log-update.vue';
import AuditLogService from './audit-log.service';
type AuditLogUpdateComponentType = InstanceType<typeof AuditLogUpdate>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const auditLogSample = { id: 123 };
describe('Component Tests', () => {
let mountOptions: MountingOptions<AuditLogUpdateComponentType>['global'];
let alertService: AlertService;
describe('AuditLog Management Update Component', () => {
let comp: AuditLogUpdateComponentType;
let auditLogServiceStub: SinonStubbedInstance<AuditLogService>;
beforeEach(() => {
route = {};
auditLogServiceStub = sinon.createStubInstance<AuditLogService>(AuditLogService);
auditLogServiceStub.retrieve.onFirstCall().resolves(Promise.resolve([]));
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'b-input-group': true,
'b-input-group-prepend': true,
'b-form-datepicker': true,
'b-form-input': true,
},
provide: {
alertService,
auditLogService: () => auditLogServiceStub,
utenteAppService: () =>
sinon.createStubInstance<UtenteAppService>(UtenteAppService, {
retrieve: sinon.stub().resolves({}),
} as any),
},
};
});
afterEach(() => {
vitest.resetAllMocks();
});
describe('load', () => {
beforeEach(() => {
const wrapper = shallowMount(AuditLogUpdate, { global: mountOptions });
comp = wrapper.vm;
});
it('Should convert date from string', () => {
// GIVEN
const date = new Date('2019-10-15T11:42:02Z');
// WHEN
const convertedDate = comp.convertDateTimeFromServer(date);
// THEN
expect(convertedDate).toEqual(dayjs(date).format(DATE_TIME_LONG_FORMAT));
});
it('Should not convert date if date is not present', () => {
expect(comp.convertDateTimeFromServer(null)).toBeNull();
});
});
describe('save', () => {
it('Should call update service on save for existing entity', async () => {
// GIVEN
const wrapper = shallowMount(AuditLogUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.auditLog = auditLogSample;
auditLogServiceStub.update.resolves(auditLogSample);
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(auditLogServiceStub.update.calledWith(auditLogSample)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
it('Should call create service on save for new entity', async () => {
// GIVEN
const entity = {};
auditLogServiceStub.create.resolves(entity);
const wrapper = shallowMount(AuditLogUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.auditLog = entity;
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(auditLogServiceStub.create.calledWith(entity)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
});
describe('Before route enter', () => {
it('Should retrieve data', async () => {
// GIVEN
auditLogServiceStub.find.resolves(auditLogSample);
auditLogServiceStub.retrieve.resolves([auditLogSample]);
// WHEN
route = {
params: {
auditLogId: `${auditLogSample.id}`,
},
};
const wrapper = shallowMount(AuditLogUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(comp.auditLog).toMatchObject(auditLogSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
auditLogServiceStub.find.resolves(auditLogSample);
const wrapper = shallowMount(AuditLogUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,122 @@
import { type Ref, computed, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useVuelidate } from '@vuelidate/core';
import UtenteAppService from '@/entities/utente-app/utente-app.service';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat, useValidation } from '@/shared/composables';
import { AuditLog, type IAuditLog } from '@/shared/model/audit-log.model';
import { AzioneAudit } from '@/shared/model/enumerations/azione-audit.model';
import { TipoEntita } from '@/shared/model/enumerations/tipo-entita.model';
import { type IUtenteApp } from '@/shared/model/utente-app.model';
import AuditLogService from './audit-log.service';
export default defineComponent({
name: 'AuditLogUpdate',
setup() {
const auditLogService = inject('auditLogService', () => new AuditLogService());
const alertService = inject('alertService', () => useAlertService(), true);
const auditLog: Ref<IAuditLog> = ref(new AuditLog());
const utenteAppService = inject('utenteAppService', () => new UtenteAppService());
const utenteApps: Ref<IUtenteApp[]> = ref([]);
const tipoEntitaValues: Ref<string[]> = ref(Object.keys(TipoEntita));
const azioneAuditValues: Ref<string[]> = ref(Object.keys(AzioneAudit));
const isSaving = ref(false);
const currentLanguage = inject('currentLanguage', () => computed(() => navigator.language ?? 'it'), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const retrieveAuditLog = async auditLogId => {
try {
const res = await auditLogService().find(auditLogId);
res.createdAt = new Date(res.createdAt);
auditLog.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.auditLogId) {
retrieveAuditLog(route.params.auditLogId);
}
const initRelationships = () => {
utenteAppService()
.retrieve()
.then(res => {
utenteApps.value = res.data;
});
};
initRelationships();
const { t: t$ } = useI18n();
const validations = useValidation();
const validationRules = {
entitaTipo: {},
entitaId: {},
azione: {},
dettagli: {},
ipAddress: {},
createdAt: {},
utente: {},
};
const v$ = useVuelidate(validationRules, auditLog as any);
v$.value.$validate();
return {
auditLogService,
alertService,
auditLog,
previousState,
tipoEntitaValues,
azioneAuditValues,
isSaving,
currentLanguage,
utenteApps,
v$,
...useDateFormat({ entityRef: auditLog }),
t$,
};
},
created(): void {},
methods: {
save(): void {
this.isSaving = true;
if (this.auditLog.id) {
this.auditLogService()
.update(this.auditLog)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showInfo(this.t$('smartbookingApp.auditLog.updated', { param: param.id }));
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
} else {
this.auditLogService()
.create(this.auditLog)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showSuccess(this.t$('smartbookingApp.auditLog.created', { param: param.id }).toString());
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
}
},
},
});

View File

@@ -0,0 +1,136 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<form name="editForm" novalidate @submit.prevent="save()">
<h2 id="smartbookingApp.auditLog.home.createOrEditLabel" data-cy="AuditLogCreateUpdateHeading">
{{ t$('smartbookingApp.auditLog.home.createOrEditLabel') }}
</h2>
<div>
<div class="mb-3" v-if="auditLog.id">
<label for="id">{{ t$('global.field.id') }}</label>
<input type="text" class="form-control" id="id" name="id" v-model="auditLog.id" readonly />
</div>
<div class="mb-3">
<label class="form-control-label" for="audit-log">{{ t$('smartbookingApp.auditLog.entitaTipo') }}</label>
<select
class="form-control"
name="entitaTipo"
:class="{ valid: !v$.entitaTipo.$invalid, invalid: v$.entitaTipo.$invalid }"
v-model="v$.entitaTipo.$model"
id="audit-log-entitaTipo"
data-cy="entitaTipo"
>
<option
v-for="tipoEntita in tipoEntitaValues"
:key="tipoEntita"
:value="tipoEntita"
:label="t$('smartbookingApp.TipoEntita.' + tipoEntita)"
>
{{ tipoEntita }}
</option>
</select>
</div>
<div class="mb-3">
<label class="form-control-label" for="audit-log">{{ t$('smartbookingApp.auditLog.entitaId') }}</label>
<input
type="number"
class="form-control"
name="entitaId"
id="audit-log-entitaId"
data-cy="entitaId"
:class="{ valid: !v$.entitaId.$invalid, invalid: v$.entitaId.$invalid }"
v-model.number="v$.entitaId.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="audit-log">{{ t$('smartbookingApp.auditLog.azione') }}</label>
<select
class="form-control"
name="azione"
:class="{ valid: !v$.azione.$invalid, invalid: v$.azione.$invalid }"
v-model="v$.azione.$model"
id="audit-log-azione"
data-cy="azione"
>
<option
v-for="azioneAudit in azioneAuditValues"
:key="azioneAudit"
:value="azioneAudit"
:label="t$('smartbookingApp.AzioneAudit.' + azioneAudit)"
>
{{ azioneAudit }}
</option>
</select>
</div>
<div class="mb-3">
<label class="form-control-label" for="audit-log">{{ t$('smartbookingApp.auditLog.dettagli') }}</label>
<input
type="text"
class="form-control"
name="dettagli"
id="audit-log-dettagli"
data-cy="dettagli"
:class="{ valid: !v$.dettagli.$invalid, invalid: v$.dettagli.$invalid }"
v-model="v$.dettagli.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="audit-log">{{ t$('smartbookingApp.auditLog.ipAddress') }}</label>
<input
type="text"
class="form-control"
name="ipAddress"
id="audit-log-ipAddress"
data-cy="ipAddress"
:class="{ valid: !v$.ipAddress.$invalid, invalid: v$.ipAddress.$invalid }"
v-model="v$.ipAddress.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="audit-log">{{ t$('smartbookingApp.auditLog.createdAt') }}</label>
<div class="d-flex">
<input
id="audit-log-createdAt"
data-cy="createdAt"
type="datetime-local"
class="form-control"
name="createdAt"
:class="{ valid: !v$.createdAt.$invalid, invalid: v$.createdAt.$invalid }"
:value="convertDateTimeFromServer(v$.createdAt.$model)"
@change="updateInstantField('createdAt', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="audit-log">{{ t$('smartbookingApp.auditLog.utente') }}</label>
<select class="form-control" id="audit-log-utente" data-cy="utente" name="utente" v-model="auditLog.utente">
<option :value="null"></option>
<option
:value="auditLog.utente && utenteAppOption.id === auditLog.utente.id ? auditLog.utente : utenteAppOption"
v-for="utenteAppOption in utenteApps"
:key="utenteAppOption.id"
>
{{ utenteAppOption.username }}
</option>
</select>
</div>
</div>
<div>
<button type="button" id="cancel-save" data-cy="entityCreateCancelButton" class="btn btn-secondary" @click="previousState()">
<font-awesome-icon icon="ban"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.cancel') }}</span>
</button>
<button
type="submit"
id="save-entity"
data-cy="entityCreateSaveButton"
:disabled="v$.$invalid || isSaving"
class="btn btn-primary"
>
<font-awesome-icon icon="save"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.save') }}</span>
</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts" src="./audit-log-update.component.ts"></script>

View File

@@ -0,0 +1,166 @@
import { vitest } from 'vitest';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import AuditLogService from './audit-log.service';
import AuditLog from './audit-log.vue';
type AuditLogComponentType = InstanceType<typeof AuditLog>;
const bModalStub = {
render: () => {},
methods: {
hide: () => {},
show: () => {},
},
};
describe('Component Tests', () => {
let alertService: AlertService;
describe('AuditLog Management Component', () => {
let auditLogServiceStub: SinonStubbedInstance<AuditLogService>;
let mountOptions: MountingOptions<AuditLogComponentType>['global'];
beforeEach(() => {
auditLogServiceStub = sinon.createStubInstance<AuditLogService>(AuditLogService);
auditLogServiceStub.retrieve.resolves({ headers: {} });
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
jhiItemCount: true,
bPagination: true,
bModal: bModalStub as any,
'font-awesome-icon': true,
'b-badge': true,
'jhi-sort-indicator': true,
'b-button': true,
'router-link': true,
},
directives: {
'b-modal': {},
},
provide: {
alertService,
auditLogService: () => auditLogServiceStub,
},
};
});
describe('Mount', () => {
it('Should call load all on init', async () => {
// GIVEN
auditLogServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
const wrapper = shallowMount(AuditLog, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(auditLogServiceStub.retrieve.calledOnce).toBeTruthy();
expect(comp.auditLogs[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for an id', async () => {
// WHEN
const wrapper = shallowMount(AuditLog, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(auditLogServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['id,asc'],
});
});
});
describe('Handles', () => {
let comp: AuditLogComponentType;
beforeEach(async () => {
const wrapper = shallowMount(AuditLog, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
auditLogServiceStub.retrieve.reset();
auditLogServiceStub.retrieve.resolves({ headers: {}, data: [] });
});
it('should load a page', async () => {
// GIVEN
auditLogServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.page = 2;
await comp.$nextTick();
// THEN
expect(auditLogServiceStub.retrieve.called).toBeTruthy();
expect(comp.auditLogs[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should not load a page if the page is the same as the previous page', () => {
// WHEN
comp.page = 1;
// THEN
expect(auditLogServiceStub.retrieve.called).toBeFalsy();
});
it('should re-initialize the page', async () => {
// GIVEN
comp.page = 2;
await comp.$nextTick();
auditLogServiceStub.retrieve.reset();
auditLogServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.clear();
await comp.$nextTick();
// THEN
expect(comp.page).toEqual(1);
expect(auditLogServiceStub.retrieve.callCount).toEqual(1);
expect(comp.auditLogs[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for a non-id attribute', async () => {
// WHEN
comp.propOrder = 'name';
await comp.$nextTick();
// THEN
expect(auditLogServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['name,asc', 'id'],
});
});
it('Should call delete service on confirmDelete', async () => {
// GIVEN
auditLogServiceStub.delete.resolves({});
// WHEN
comp.prepareRemove({ id: 123 });
comp.removeAuditLog();
await comp.$nextTick(); // clear components
// THEN
expect(auditLogServiceStub.delete.called).toBeTruthy();
// THEN
await comp.$nextTick(); // handle component clear watch
expect(auditLogServiceStub.retrieve.callCount).toEqual(1);
});
});
});
});

View File

@@ -0,0 +1,137 @@
import { type Ref, defineComponent, inject, onMounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type IAuditLog } from '@/shared/model/audit-log.model';
import AuditLogService from './audit-log.service';
export default defineComponent({
name: 'AuditLog',
setup() {
const { t: t$ } = useI18n();
const dateFormat = useDateFormat();
const auditLogService = inject('auditLogService', () => new AuditLogService());
const alertService = inject('alertService', () => useAlertService(), true);
const itemsPerPage = ref(20);
const queryCount: Ref<number> = ref(null);
const page: Ref<number> = ref(1);
const propOrder = ref('id');
const reverse = ref(false);
const totalItems = ref(0);
const auditLogs: Ref<IAuditLog[]> = ref([]);
const isFetching = ref(false);
const clear = () => {
page.value = 1;
};
const sort = (): Array<any> => {
const result = [`${propOrder.value},${reverse.value ? 'desc' : 'asc'}`];
if (propOrder.value !== 'id') {
result.push('id');
}
return result;
};
const retrieveAuditLogs = async () => {
isFetching.value = true;
try {
const paginationQuery = {
page: page.value - 1,
size: itemsPerPage.value,
sort: sort(),
};
const res = await auditLogService().retrieve(paginationQuery);
totalItems.value = Number(res.headers['x-total-count']);
queryCount.value = totalItems.value;
auditLogs.value = res.data;
} catch (err) {
alertService.showHttpError(err.response);
} finally {
isFetching.value = false;
}
};
const handleSyncList = () => {
retrieveAuditLogs();
};
onMounted(async () => {
await retrieveAuditLogs();
});
const removeId: Ref<number> = ref(null);
const removeEntity = ref<any>(null);
const prepareRemove = (instance: IAuditLog) => {
removeId.value = instance.id;
removeEntity.value.show();
};
const closeDialog = () => {
removeEntity.value.hide();
};
const removeAuditLog = async () => {
try {
await auditLogService().delete(removeId.value);
const message = t$('smartbookingApp.auditLog.deleted', { param: removeId.value }).toString();
alertService.showInfo(message, { variant: 'danger' });
removeId.value = null;
retrieveAuditLogs();
closeDialog();
} catch (error) {
alertService.showHttpError(error.response);
}
};
const changeOrder = (newOrder: string) => {
if (propOrder.value === newOrder) {
reverse.value = !reverse.value;
} else {
reverse.value = false;
}
propOrder.value = newOrder;
};
// Whenever order changes, reset the pagination
watch([propOrder, reverse], async () => {
if (page.value === 1) {
// first page, retrieve new data
await retrieveAuditLogs();
} else {
// reset the pagination
clear();
}
});
// Whenever page changes, switch to the new page.
watch(page, async () => {
await retrieveAuditLogs();
});
return {
auditLogs,
handleSyncList,
isFetching,
retrieveAuditLogs,
clear,
...dateFormat,
removeId,
removeEntity,
prepareRemove,
closeDialog,
removeAuditLog,
itemsPerPage,
queryCount,
page,
propOrder,
reverse,
totalItems,
changeOrder,
t$,
};
},
});

View File

@@ -0,0 +1,186 @@
import axios from 'axios';
import dayjs from 'dayjs';
import sinon from 'sinon';
import { DATE_TIME_FORMAT } from '@/shared/composables/date-format';
import { AuditLog } from '@/shared/model/audit-log.model';
import AuditLogService from './audit-log.service';
const error = {
response: {
status: null,
data: {
type: null,
},
},
};
const axiosStub = {
get: sinon.stub(axios, 'get'),
post: sinon.stub(axios, 'post'),
put: sinon.stub(axios, 'put'),
patch: sinon.stub(axios, 'patch'),
delete: sinon.stub(axios, 'delete'),
};
describe('Service Tests', () => {
describe('AuditLog Service', () => {
let service: AuditLogService;
let elemDefault;
let currentDate: Date;
beforeEach(() => {
service = new AuditLogService();
currentDate = new Date();
elemDefault = new AuditLog(123, 'PRENOTAZIONE', 0, 'CREATE', 'AAAAAAA', 'AAAAAAA', currentDate);
});
describe('Service methods', () => {
it('should find an element', async () => {
const returnedFromService = { createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT), ...elemDefault };
axiosStub.get.resolves({ data: returnedFromService });
return service.find(123).then(res => {
expect(res).toMatchObject(elemDefault);
});
});
it('should not find an element', async () => {
axiosStub.get.rejects(error);
return service
.find(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should create a AuditLog', async () => {
const returnedFromService = { id: 123, createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT), ...elemDefault };
const expected = { createdAt: currentDate, ...returnedFromService };
axiosStub.post.resolves({ data: returnedFromService });
return service.create({}).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not create a AuditLog', async () => {
axiosStub.post.rejects(error);
return service
.create({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should update a AuditLog', async () => {
const returnedFromService = {
entitaTipo: 'BBBBBB',
entitaId: 1,
azione: 'BBBBBB',
dettagli: 'BBBBBB',
ipAddress: 'BBBBBB',
createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { createdAt: currentDate, ...returnedFromService };
axiosStub.put.resolves({ data: returnedFromService });
return service.update(expected).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not update a AuditLog', async () => {
axiosStub.put.rejects(error);
return service
.update({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should partial update a AuditLog', async () => {
const patchObject = {
azione: 'BBBBBB',
dettagli: 'BBBBBB',
ipAddress: 'BBBBBB',
createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
...new AuditLog(),
};
const returnedFromService = Object.assign(patchObject, elemDefault);
const expected = { createdAt: currentDate, ...returnedFromService };
axiosStub.patch.resolves({ data: returnedFromService });
return service.partialUpdate(patchObject).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not partial update a AuditLog', async () => {
axiosStub.patch.rejects(error);
return service
.partialUpdate({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should return a list of AuditLog', async () => {
const returnedFromService = {
entitaTipo: 'BBBBBB',
entitaId: 1,
azione: 'BBBBBB',
dettagli: 'BBBBBB',
ipAddress: 'BBBBBB',
createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { createdAt: currentDate, ...returnedFromService };
axiosStub.get.resolves([returnedFromService]);
return service.retrieve({ sort: {}, page: 0, size: 10 }).then(res => {
expect(res).toContainEqual(expected);
});
});
it('should not return a list of AuditLog', async () => {
axiosStub.get.rejects(error);
return service
.retrieve()
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should delete a AuditLog', async () => {
axiosStub.delete.resolves({ ok: true });
return service.delete(123).then(res => {
expect(res.ok).toBeTruthy();
});
});
it('should not delete a AuditLog', async () => {
axiosStub.delete.rejects(error);
return service
.delete(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
});
});
});

View File

@@ -0,0 +1,86 @@
import axios from 'axios';
import { type IAuditLog } from '@/shared/model/audit-log.model';
import buildPaginationQueryOpts from '@/shared/sort/sorts';
const baseApiUrl = 'api/audit-logs';
export default class AuditLogService {
find(id: number): Promise<IAuditLog> {
return new Promise<IAuditLog>((resolve, reject) => {
axios
.get(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
retrieve(paginationQuery?: any): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.get(`${baseApiUrl}?${buildPaginationQueryOpts(paginationQuery)}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
delete(id: number): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.delete(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
create(entity: IAuditLog): Promise<IAuditLog> {
return new Promise<IAuditLog>((resolve, reject) => {
axios
.post(baseApiUrl, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
update(entity: IAuditLog): Promise<IAuditLog> {
return new Promise<IAuditLog>((resolve, reject) => {
axios
.put(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
partialUpdate(entity: IAuditLog): Promise<IAuditLog> {
return new Promise<IAuditLog>((resolve, reject) => {
axios
.patch(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
}

View File

@@ -0,0 +1,151 @@
<template>
<div>
<h2 id="page-heading" data-cy="AuditLogHeading">
<span id="audit-log">{{ t$('smartbookingApp.auditLog.home.title') }}</span>
<div class="d-flex justify-content-end">
<button class="btn btn-info me-2" @click="handleSyncList" :disabled="isFetching">
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
<span>{{ t$('smartbookingApp.auditLog.home.refreshListLabel') }}</span>
</button>
<router-link :to="{ name: 'AuditLogCreate' }" custom v-slot="{ navigate }">
<button
@click="navigate"
id="jh-create-entity"
data-cy="entityCreateButton"
class="btn btn-primary jh-create-entity create-audit-log"
>
<font-awesome-icon icon="plus"></font-awesome-icon>
<span>{{ t$('smartbookingApp.auditLog.home.createLabel') }}</span>
</button>
</router-link>
</div>
</h2>
<br />
<div class="alert alert-warning" v-if="!isFetching && auditLogs?.length === 0">
<span>{{ t$('smartbookingApp.auditLog.home.notFound') }}</span>
</div>
<div class="table-responsive" v-if="auditLogs?.length > 0">
<table class="table table-striped" aria-describedby="auditLogs">
<thead>
<tr>
<th scope="col" @click="changeOrder('id')">
<span>{{ t$('global.field.id') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'id'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('entitaTipo')">
<span>{{ t$('smartbookingApp.auditLog.entitaTipo') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'entitaTipo'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('entitaId')">
<span>{{ t$('smartbookingApp.auditLog.entitaId') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'entitaId'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('azione')">
<span>{{ t$('smartbookingApp.auditLog.azione') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'azione'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('dettagli')">
<span>{{ t$('smartbookingApp.auditLog.dettagli') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'dettagli'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('ipAddress')">
<span>{{ t$('smartbookingApp.auditLog.ipAddress') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'ipAddress'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('createdAt')">
<span>{{ t$('smartbookingApp.auditLog.createdAt') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'createdAt'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('utente.username')">
<span>{{ t$('smartbookingApp.auditLog.utente') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'utente.username'"></jhi-sort-indicator>
</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="auditLog in auditLogs" :key="auditLog.id" data-cy="entityTable">
<td>
<router-link :to="{ name: 'AuditLogView', params: { auditLogId: auditLog.id } }">{{ auditLog.id }}</router-link>
</td>
<td>{{ t$('smartbookingApp.TipoEntita.' + auditLog.entitaTipo) }}</td>
<td>{{ auditLog.entitaId }}</td>
<td>{{ t$('smartbookingApp.AzioneAudit.' + auditLog.azione) }}</td>
<td>{{ auditLog.dettagli }}</td>
<td>{{ auditLog.ipAddress }}</td>
<td>{{ formatDateShort(auditLog.createdAt) || '' }}</td>
<td>
<div v-if="auditLog.utente">
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: auditLog.utente.id } }">{{
auditLog.utente.username
}}</router-link>
</div>
</td>
<td class="text-end">
<div class="btn-group">
<router-link
:to="{ name: 'AuditLogView', params: { auditLogId: auditLog.id } }"
class="btn btn-info btn-sm details"
data-cy="entityDetailsButton"
>
<font-awesome-icon icon="eye"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
</router-link>
<router-link
:to="{ name: 'AuditLogEdit', params: { auditLogId: auditLog.id } }"
class="btn btn-primary btn-sm edit"
data-cy="entityEditButton"
>
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.edit') }}</span>
</router-link>
<b-button
@click="prepareRemove(auditLog)"
variant="danger"
class="btn btn-sm"
data-cy="entityDeleteButton"
v-b-modal.removeEntity
>
<font-awesome-icon icon="times"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
</b-button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<b-modal ref="removeEntity" id="removeEntity">
<template #title>
<span id="smartbookingApp.auditLog.delete.question" data-cy="auditLogDeleteDialogHeading">{{ t$('entity.delete.title') }}</span>
</template>
<div class="modal-body">
<p id="jhi-delete-auditLog-heading">{{ t$('smartbookingApp.auditLog.delete.question', { id: removeId }) }}</p>
</div>
<template #footer>
<div>
<button type="button" class="btn btn-secondary" @click="closeDialog()">{{ t$('entity.action.cancel') }}</button>
<button
type="button"
class="btn btn-primary"
id="jhi-confirm-delete-auditLog"
data-cy="entityConfirmDeleteButton"
@click="removeAuditLog"
>
{{ t$('entity.action.delete') }}
</button>
</div>
</template>
</b-modal>
<div v-show="auditLogs?.length > 0">
<div class="d-flex justify-content-center">
<jhi-item-count :page="page" :total="queryCount" :items-per-page="itemsPerPage"></jhi-item-count>
</div>
<div class="d-flex justify-content-center">
<b-pagination size="md" :total-rows="totalItems" v-model="page" :per-page="itemsPerPage"></b-pagination>
</div>
</div>
</div>
</template>
<script lang="ts" src="./audit-log.component.ts"></script>

View File

@@ -0,0 +1,91 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import ConfermaDetails from './conferma-details.vue';
import ConfermaService from './conferma.service';
type ConfermaDetailsComponentType = InstanceType<typeof ConfermaDetails>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const confermaSample = { id: 123 };
describe('Component Tests', () => {
let alertService: AlertService;
afterEach(() => {
vitest.resetAllMocks();
});
describe('Conferma Management Detail Component', () => {
let confermaServiceStub: SinonStubbedInstance<ConfermaService>;
let mountOptions: MountingOptions<ConfermaDetailsComponentType>['global'];
beforeEach(() => {
route = {};
confermaServiceStub = sinon.createStubInstance<ConfermaService>(ConfermaService);
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'router-link': true,
},
provide: {
alertService,
confermaService: () => confermaServiceStub,
},
};
});
describe('Navigate to details', () => {
it('Should call load all on init', async () => {
// GIVEN
confermaServiceStub.find.resolves(confermaSample);
route = {
params: {
confermaId: `${123}`,
},
};
const wrapper = shallowMount(ConfermaDetails, { global: mountOptions });
const comp = wrapper.vm;
// WHEN
await comp.$nextTick();
// THEN
expect(comp.conferma).toMatchObject(confermaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
confermaServiceStub.find.resolves(confermaSample);
const wrapper = shallowMount(ConfermaDetails, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,43 @@
import { type Ref, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useAlertService } from '@/shared/alert/alert.service';
import { type IConferma } from '@/shared/model/conferma.model';
import ConfermaService from './conferma.service';
export default defineComponent({
name: 'ConfermaDetails',
setup() {
const confermaService = inject('confermaService', () => new ConfermaService());
const alertService = inject('alertService', () => useAlertService(), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const conferma: Ref<IConferma> = ref({});
const retrieveConferma = async confermaId => {
try {
const res = await confermaService().find(confermaId);
conferma.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.confermaId) {
retrieveConferma(route.params.confermaId);
}
return {
alertService,
conferma,
previousState,
t$: useI18n().t,
};
},
});

View File

@@ -0,0 +1,45 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<div v-if="conferma">
<h2 class="jh-entity-heading" data-cy="confermaDetailsHeading">
<span>{{ t$('smartbookingApp.conferma.detail.title') }}Conferma</span> {{ conferma.id }}
</h2>
<dl class="row-md jh-entity-details">
<dt>
<span>{{ t$('smartbookingApp.conferma.motivoConferma') }}</span>
</dt>
<dd>
<span>{{ conferma.motivoConferma }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.conferma.tipoConferma') }}</span>
</dt>
<dd>
<span>{{ t$('smartbookingApp.TipoConferma.' + conferma.tipoConferma) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.conferma.confermataDa') }}</span>
</dt>
<dd>
<div v-if="conferma.confermataDa">
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: conferma.confermataDa.id } }">{{
conferma.confermataDa.username
}}</router-link>
</div>
</dd>
</dl>
<button type="submit" @click.prevent="previousState()" class="btn btn-info" data-cy="entityDetailsBackButton">
<font-awesome-icon icon="arrow-left"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.back') }}</span>
</button>
<router-link v-if="conferma.id" :to="{ name: 'ConfermaEdit', params: { confermaId: conferma.id } }" custom v-slot="{ navigate }">
<button @click="navigate" class="btn btn-primary">
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.edit') }}</span>
</button>
</router-link>
</div>
</div>
</div>
</template>
<script lang="ts" src="./conferma-details.component.ts"></script>

View File

@@ -0,0 +1,138 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import UtenteAppService from '@/entities/utente-app/utente-app.service';
import AlertService from '@/shared/alert/alert.service';
import ConfermaUpdate from './conferma-update.vue';
import ConfermaService from './conferma.service';
type ConfermaUpdateComponentType = InstanceType<typeof ConfermaUpdate>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const confermaSample = { id: 123 };
describe('Component Tests', () => {
let mountOptions: MountingOptions<ConfermaUpdateComponentType>['global'];
let alertService: AlertService;
describe('Conferma Management Update Component', () => {
let comp: ConfermaUpdateComponentType;
let confermaServiceStub: SinonStubbedInstance<ConfermaService>;
beforeEach(() => {
route = {};
confermaServiceStub = sinon.createStubInstance<ConfermaService>(ConfermaService);
confermaServiceStub.retrieve.onFirstCall().resolves(Promise.resolve([]));
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'b-input-group': true,
'b-input-group-prepend': true,
'b-form-datepicker': true,
'b-form-input': true,
},
provide: {
alertService,
confermaService: () => confermaServiceStub,
utenteAppService: () =>
sinon.createStubInstance<UtenteAppService>(UtenteAppService, {
retrieve: sinon.stub().resolves({}),
} as any),
},
};
});
afterEach(() => {
vitest.resetAllMocks();
});
describe('save', () => {
it('Should call update service on save for existing entity', async () => {
// GIVEN
const wrapper = shallowMount(ConfermaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.conferma = confermaSample;
confermaServiceStub.update.resolves(confermaSample);
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(confermaServiceStub.update.calledWith(confermaSample)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
it('Should call create service on save for new entity', async () => {
// GIVEN
const entity = {};
confermaServiceStub.create.resolves(entity);
const wrapper = shallowMount(ConfermaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.conferma = entity;
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(confermaServiceStub.create.calledWith(entity)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
});
describe('Before route enter', () => {
it('Should retrieve data', async () => {
// GIVEN
confermaServiceStub.find.resolves(confermaSample);
confermaServiceStub.retrieve.resolves([confermaSample]);
// WHEN
route = {
params: {
confermaId: `${confermaSample.id}`,
},
};
const wrapper = shallowMount(ConfermaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(comp.conferma).toMatchObject(confermaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
confermaServiceStub.find.resolves(confermaSample);
const wrapper = shallowMount(ConfermaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,114 @@
import { type Ref, computed, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useVuelidate } from '@vuelidate/core';
import UtenteAppService from '@/entities/utente-app/utente-app.service';
import { useAlertService } from '@/shared/alert/alert.service';
import { useValidation } from '@/shared/composables';
import { Conferma, type IConferma } from '@/shared/model/conferma.model';
import { TipoConferma } from '@/shared/model/enumerations/tipo-conferma.model';
import { type IUtenteApp } from '@/shared/model/utente-app.model';
import ConfermaService from './conferma.service';
export default defineComponent({
name: 'ConfermaUpdate',
setup() {
const confermaService = inject('confermaService', () => new ConfermaService());
const alertService = inject('alertService', () => useAlertService(), true);
const conferma: Ref<IConferma> = ref(new Conferma());
const utenteAppService = inject('utenteAppService', () => new UtenteAppService());
const utenteApps: Ref<IUtenteApp[]> = ref([]);
const tipoConfermaValues: Ref<string[]> = ref(Object.keys(TipoConferma));
const isSaving = ref(false);
const currentLanguage = inject('currentLanguage', () => computed(() => navigator.language ?? 'it'), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const retrieveConferma = async confermaId => {
try {
const res = await confermaService().find(confermaId);
conferma.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.confermaId) {
retrieveConferma(route.params.confermaId);
}
const initRelationships = () => {
utenteAppService()
.retrieve()
.then(res => {
utenteApps.value = res.data;
});
};
initRelationships();
const { t: t$ } = useI18n();
const validations = useValidation();
const validationRules = {
motivoConferma: {},
tipoConferma: {},
confermataDa: {},
prenotazione: {},
};
const v$ = useVuelidate(validationRules, conferma as any);
v$.value.$validate();
return {
confermaService,
alertService,
conferma,
previousState,
tipoConfermaValues,
isSaving,
currentLanguage,
utenteApps,
v$,
t$,
};
},
created(): void {},
methods: {
save(): void {
this.isSaving = true;
if (this.conferma.id) {
this.confermaService()
.update(this.conferma)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showInfo(this.t$('smartbookingApp.conferma.updated', { param: param.id }));
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
} else {
this.confermaService()
.create(this.conferma)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showSuccess(this.t$('smartbookingApp.conferma.created', { param: param.id }).toString());
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
}
},
},
});

View File

@@ -0,0 +1,83 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<form name="editForm" novalidate @submit.prevent="save()">
<h2 id="smartbookingApp.conferma.home.createOrEditLabel" data-cy="ConfermaCreateUpdateHeading">
{{ t$('smartbookingApp.conferma.home.createOrEditLabel') }}
</h2>
<div>
<div class="mb-3" v-if="conferma.id">
<label for="id">{{ t$('global.field.id') }}</label>
<input type="text" class="form-control" id="id" name="id" v-model="conferma.id" readonly />
</div>
<div class="mb-3">
<label class="form-control-label" for="conferma">{{ t$('smartbookingApp.conferma.motivoConferma') }}</label>
<input
type="text"
class="form-control"
name="motivoConferma"
id="conferma-motivoConferma"
data-cy="motivoConferma"
:class="{ valid: !v$.motivoConferma.$invalid, invalid: v$.motivoConferma.$invalid }"
v-model="v$.motivoConferma.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="conferma">{{ t$('smartbookingApp.conferma.tipoConferma') }}</label>
<select
class="form-control"
name="tipoConferma"
:class="{ valid: !v$.tipoConferma.$invalid, invalid: v$.tipoConferma.$invalid }"
v-model="v$.tipoConferma.$model"
id="conferma-tipoConferma"
data-cy="tipoConferma"
>
<option
v-for="tipoConferma in tipoConfermaValues"
:key="tipoConferma"
:value="tipoConferma"
:label="t$('smartbookingApp.TipoConferma.' + tipoConferma)"
>
{{ tipoConferma }}
</option>
</select>
</div>
<div class="mb-3">
<label class="form-control-label" for="conferma">{{ t$('smartbookingApp.conferma.confermataDa') }}</label>
<select
class="form-control"
id="conferma-confermataDa"
data-cy="confermataDa"
name="confermataDa"
v-model="conferma.confermataDa"
>
<option :value="null"></option>
<option
:value="conferma.confermataDa && utenteAppOption.id === conferma.confermataDa.id ? conferma.confermataDa : utenteAppOption"
v-for="utenteAppOption in utenteApps"
:key="utenteAppOption.id"
>
{{ utenteAppOption.username }}
</option>
</select>
</div>
</div>
<div>
<button type="button" id="cancel-save" data-cy="entityCreateCancelButton" class="btn btn-secondary" @click="previousState()">
<font-awesome-icon icon="ban"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.cancel') }}</span>
</button>
<button
type="submit"
id="save-entity"
data-cy="entityCreateSaveButton"
:disabled="v$.$invalid || isSaving"
class="btn btn-primary"
>
<font-awesome-icon icon="save"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.save') }}</span>
</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts" src="./conferma-update.component.ts"></script>

View File

@@ -0,0 +1,166 @@
import { vitest } from 'vitest';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import ConfermaService from './conferma.service';
import Conferma from './conferma.vue';
type ConfermaComponentType = InstanceType<typeof Conferma>;
const bModalStub = {
render: () => {},
methods: {
hide: () => {},
show: () => {},
},
};
describe('Component Tests', () => {
let alertService: AlertService;
describe('Conferma Management Component', () => {
let confermaServiceStub: SinonStubbedInstance<ConfermaService>;
let mountOptions: MountingOptions<ConfermaComponentType>['global'];
beforeEach(() => {
confermaServiceStub = sinon.createStubInstance<ConfermaService>(ConfermaService);
confermaServiceStub.retrieve.resolves({ headers: {} });
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
jhiItemCount: true,
bPagination: true,
bModal: bModalStub as any,
'font-awesome-icon': true,
'b-badge': true,
'jhi-sort-indicator': true,
'b-button': true,
'router-link': true,
},
directives: {
'b-modal': {},
},
provide: {
alertService,
confermaService: () => confermaServiceStub,
},
};
});
describe('Mount', () => {
it('Should call load all on init', async () => {
// GIVEN
confermaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
const wrapper = shallowMount(Conferma, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(confermaServiceStub.retrieve.calledOnce).toBeTruthy();
expect(comp.confermas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for an id', async () => {
// WHEN
const wrapper = shallowMount(Conferma, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(confermaServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['id,asc'],
});
});
});
describe('Handles', () => {
let comp: ConfermaComponentType;
beforeEach(async () => {
const wrapper = shallowMount(Conferma, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
confermaServiceStub.retrieve.reset();
confermaServiceStub.retrieve.resolves({ headers: {}, data: [] });
});
it('should load a page', async () => {
// GIVEN
confermaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.page = 2;
await comp.$nextTick();
// THEN
expect(confermaServiceStub.retrieve.called).toBeTruthy();
expect(comp.confermas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should not load a page if the page is the same as the previous page', () => {
// WHEN
comp.page = 1;
// THEN
expect(confermaServiceStub.retrieve.called).toBeFalsy();
});
it('should re-initialize the page', async () => {
// GIVEN
comp.page = 2;
await comp.$nextTick();
confermaServiceStub.retrieve.reset();
confermaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.clear();
await comp.$nextTick();
// THEN
expect(comp.page).toEqual(1);
expect(confermaServiceStub.retrieve.callCount).toEqual(1);
expect(comp.confermas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for a non-id attribute', async () => {
// WHEN
comp.propOrder = 'name';
await comp.$nextTick();
// THEN
expect(confermaServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['name,asc', 'id'],
});
});
it('Should call delete service on confirmDelete', async () => {
// GIVEN
confermaServiceStub.delete.resolves({});
// WHEN
comp.prepareRemove({ id: 123 });
comp.removeConferma();
await comp.$nextTick(); // clear components
// THEN
expect(confermaServiceStub.delete.called).toBeTruthy();
// THEN
await comp.$nextTick(); // handle component clear watch
expect(confermaServiceStub.retrieve.callCount).toEqual(1);
});
});
});
});

View File

@@ -0,0 +1,134 @@
import { type Ref, defineComponent, inject, onMounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAlertService } from '@/shared/alert/alert.service';
import { type IConferma } from '@/shared/model/conferma.model';
import ConfermaService from './conferma.service';
export default defineComponent({
name: 'Conferma',
setup() {
const { t: t$ } = useI18n();
const confermaService = inject('confermaService', () => new ConfermaService());
const alertService = inject('alertService', () => useAlertService(), true);
const itemsPerPage = ref(20);
const queryCount: Ref<number> = ref(null);
const page: Ref<number> = ref(1);
const propOrder = ref('id');
const reverse = ref(false);
const totalItems = ref(0);
const confermas: Ref<IConferma[]> = ref([]);
const isFetching = ref(false);
const clear = () => {
page.value = 1;
};
const sort = (): Array<any> => {
const result = [`${propOrder.value},${reverse.value ? 'desc' : 'asc'}`];
if (propOrder.value !== 'id') {
result.push('id');
}
return result;
};
const retrieveConfermas = async () => {
isFetching.value = true;
try {
const paginationQuery = {
page: page.value - 1,
size: itemsPerPage.value,
sort: sort(),
};
const res = await confermaService().retrieve(paginationQuery);
totalItems.value = Number(res.headers['x-total-count']);
queryCount.value = totalItems.value;
confermas.value = res.data;
} catch (err) {
alertService.showHttpError(err.response);
} finally {
isFetching.value = false;
}
};
const handleSyncList = () => {
retrieveConfermas();
};
onMounted(async () => {
await retrieveConfermas();
});
const removeId: Ref<number> = ref(null);
const removeEntity = ref<any>(null);
const prepareRemove = (instance: IConferma) => {
removeId.value = instance.id;
removeEntity.value.show();
};
const closeDialog = () => {
removeEntity.value.hide();
};
const removeConferma = async () => {
try {
await confermaService().delete(removeId.value);
const message = t$('smartbookingApp.conferma.deleted', { param: removeId.value }).toString();
alertService.showInfo(message, { variant: 'danger' });
removeId.value = null;
retrieveConfermas();
closeDialog();
} catch (error) {
alertService.showHttpError(error.response);
}
};
const changeOrder = (newOrder: string) => {
if (propOrder.value === newOrder) {
reverse.value = !reverse.value;
} else {
reverse.value = false;
}
propOrder.value = newOrder;
};
// Whenever order changes, reset the pagination
watch([propOrder, reverse], async () => {
if (page.value === 1) {
// first page, retrieve new data
await retrieveConfermas();
} else {
// reset the pagination
clear();
}
});
// Whenever page changes, switch to the new page.
watch(page, async () => {
await retrieveConfermas();
});
return {
confermas,
handleSyncList,
isFetching,
retrieveConfermas,
clear,
removeId,
removeEntity,
prepareRemove,
closeDialog,
removeConferma,
itemsPerPage,
queryCount,
page,
propOrder,
reverse,
totalItems,
changeOrder,
t$,
};
},
});

View File

@@ -0,0 +1,160 @@
import axios from 'axios';
import sinon from 'sinon';
import { Conferma } from '@/shared/model/conferma.model';
import ConfermaService from './conferma.service';
const error = {
response: {
status: null,
data: {
type: null,
},
},
};
const axiosStub = {
get: sinon.stub(axios, 'get'),
post: sinon.stub(axios, 'post'),
put: sinon.stub(axios, 'put'),
patch: sinon.stub(axios, 'patch'),
delete: sinon.stub(axios, 'delete'),
};
describe('Service Tests', () => {
describe('Conferma Service', () => {
let service: ConfermaService;
let elemDefault;
beforeEach(() => {
service = new ConfermaService();
elemDefault = new Conferma(123, 'AAAAAAA', 'CONFERMATA');
});
describe('Service methods', () => {
it('should find an element', async () => {
const returnedFromService = { ...elemDefault };
axiosStub.get.resolves({ data: returnedFromService });
return service.find(123).then(res => {
expect(res).toMatchObject(elemDefault);
});
});
it('should not find an element', async () => {
axiosStub.get.rejects(error);
return service
.find(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should create a Conferma', async () => {
const returnedFromService = { id: 123, ...elemDefault };
const expected = { ...returnedFromService };
axiosStub.post.resolves({ data: returnedFromService });
return service.create({}).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not create a Conferma', async () => {
axiosStub.post.rejects(error);
return service
.create({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should update a Conferma', async () => {
const returnedFromService = { motivoConferma: 'BBBBBB', tipoConferma: 'BBBBBB', ...elemDefault };
const expected = { ...returnedFromService };
axiosStub.put.resolves({ data: returnedFromService });
return service.update(expected).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not update a Conferma', async () => {
axiosStub.put.rejects(error);
return service
.update({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should partial update a Conferma', async () => {
const patchObject = { motivoConferma: 'BBBBBB', tipoConferma: 'BBBBBB', ...new Conferma() };
const returnedFromService = Object.assign(patchObject, elemDefault);
const expected = { ...returnedFromService };
axiosStub.patch.resolves({ data: returnedFromService });
return service.partialUpdate(patchObject).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not partial update a Conferma', async () => {
axiosStub.patch.rejects(error);
return service
.partialUpdate({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should return a list of Conferma', async () => {
const returnedFromService = { motivoConferma: 'BBBBBB', tipoConferma: 'BBBBBB', ...elemDefault };
const expected = { ...returnedFromService };
axiosStub.get.resolves([returnedFromService]);
return service.retrieve({ sort: {}, page: 0, size: 10 }).then(res => {
expect(res).toContainEqual(expected);
});
});
it('should not return a list of Conferma', async () => {
axiosStub.get.rejects(error);
return service
.retrieve()
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should delete a Conferma', async () => {
axiosStub.delete.resolves({ ok: true });
return service.delete(123).then(res => {
expect(res.ok).toBeTruthy();
});
});
it('should not delete a Conferma', async () => {
axiosStub.delete.rejects(error);
return service
.delete(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
});
});
});

View File

@@ -0,0 +1,86 @@
import axios from 'axios';
import { type IConferma } from '@/shared/model/conferma.model';
import buildPaginationQueryOpts from '@/shared/sort/sorts';
const baseApiUrl = 'api/confermas';
export default class ConfermaService {
find(id: number): Promise<IConferma> {
return new Promise<IConferma>((resolve, reject) => {
axios
.get(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
retrieve(paginationQuery?: any): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.get(`${baseApiUrl}?${buildPaginationQueryOpts(paginationQuery)}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
delete(id: number): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.delete(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
create(entity: IConferma): Promise<IConferma> {
return new Promise<IConferma>((resolve, reject) => {
axios
.post(baseApiUrl, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
update(entity: IConferma): Promise<IConferma> {
return new Promise<IConferma>((resolve, reject) => {
axios
.put(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
partialUpdate(entity: IConferma): Promise<IConferma> {
return new Promise<IConferma>((resolve, reject) => {
axios
.patch(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
}

View File

@@ -0,0 +1,131 @@
<template>
<div>
<h2 id="page-heading" data-cy="ConfermaHeading">
<span id="conferma">{{ t$('smartbookingApp.conferma.home.title') }}</span>
<div class="d-flex justify-content-end">
<button class="btn btn-info me-2" @click="handleSyncList" :disabled="isFetching">
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
<span>{{ t$('smartbookingApp.conferma.home.refreshListLabel') }}</span>
</button>
<router-link :to="{ name: 'ConfermaCreate' }" custom v-slot="{ navigate }">
<button
@click="navigate"
id="jh-create-entity"
data-cy="entityCreateButton"
class="btn btn-primary jh-create-entity create-conferma"
>
<font-awesome-icon icon="plus"></font-awesome-icon>
<span>{{ t$('smartbookingApp.conferma.home.createLabel') }}</span>
</button>
</router-link>
</div>
</h2>
<br />
<div class="alert alert-warning" v-if="!isFetching && confermas?.length === 0">
<span>{{ t$('smartbookingApp.conferma.home.notFound') }}</span>
</div>
<div class="table-responsive" v-if="confermas?.length > 0">
<table class="table table-striped" aria-describedby="confermas">
<thead>
<tr>
<th scope="col" @click="changeOrder('id')">
<span>{{ t$('global.field.id') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'id'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('motivoConferma')">
<span>{{ t$('smartbookingApp.conferma.motivoConferma') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'motivoConferma'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('tipoConferma')">
<span>{{ t$('smartbookingApp.conferma.tipoConferma') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'tipoConferma'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('confermataDa.username')">
<span>{{ t$('smartbookingApp.conferma.confermataDa') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'confermataDa.username'"></jhi-sort-indicator>
</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="conferma in confermas" :key="conferma.id" data-cy="entityTable">
<td>
<router-link :to="{ name: 'ConfermaView', params: { confermaId: conferma.id } }">{{ conferma.id }}</router-link>
</td>
<td>{{ conferma.motivoConferma }}</td>
<td>{{ t$('smartbookingApp.TipoConferma.' + conferma.tipoConferma) }}</td>
<td>
<div v-if="conferma.confermataDa">
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: conferma.confermataDa.id } }">{{
conferma.confermataDa.username
}}</router-link>
</div>
</td>
<td class="text-end">
<div class="btn-group">
<router-link
:to="{ name: 'ConfermaView', params: { confermaId: conferma.id } }"
class="btn btn-info btn-sm details"
data-cy="entityDetailsButton"
>
<font-awesome-icon icon="eye"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
</router-link>
<router-link
:to="{ name: 'ConfermaEdit', params: { confermaId: conferma.id } }"
class="btn btn-primary btn-sm edit"
data-cy="entityEditButton"
>
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.edit') }}</span>
</router-link>
<b-button
@click="prepareRemove(conferma)"
variant="danger"
class="btn btn-sm"
data-cy="entityDeleteButton"
v-b-modal.removeEntity
>
<font-awesome-icon icon="times"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
</b-button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<b-modal ref="removeEntity" id="removeEntity">
<template #title>
<span id="smartbookingApp.conferma.delete.question" data-cy="confermaDeleteDialogHeading">{{ t$('entity.delete.title') }}</span>
</template>
<div class="modal-body">
<p id="jhi-delete-conferma-heading">{{ t$('smartbookingApp.conferma.delete.question', { id: removeId }) }}</p>
</div>
<template #footer>
<div>
<button type="button" class="btn btn-secondary" @click="closeDialog()">{{ t$('entity.action.cancel') }}</button>
<button
type="button"
class="btn btn-primary"
id="jhi-confirm-delete-conferma"
data-cy="entityConfirmDeleteButton"
@click="removeConferma"
>
{{ t$('entity.action.delete') }}
</button>
</div>
</template>
</b-modal>
<div v-show="confermas?.length > 0">
<div class="d-flex justify-content-center">
<jhi-item-count :page="page" :total="queryCount" :items-per-page="itemsPerPage"></jhi-item-count>
</div>
<div class="d-flex justify-content-center">
<b-pagination size="md" :total-rows="totalItems" v-model="page" :per-page="itemsPerPage"></b-pagination>
</div>
</div>
</div>
</template>
<script lang="ts" src="./conferma.component.ts"></script>

View File

@@ -0,0 +1,91 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import DisponibilitaDetails from './disponibilita-details.vue';
import DisponibilitaService from './disponibilita.service';
type DisponibilitaDetailsComponentType = InstanceType<typeof DisponibilitaDetails>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const disponibilitaSample = { id: 123 };
describe('Component Tests', () => {
let alertService: AlertService;
afterEach(() => {
vitest.resetAllMocks();
});
describe('Disponibilita Management Detail Component', () => {
let disponibilitaServiceStub: SinonStubbedInstance<DisponibilitaService>;
let mountOptions: MountingOptions<DisponibilitaDetailsComponentType>['global'];
beforeEach(() => {
route = {};
disponibilitaServiceStub = sinon.createStubInstance<DisponibilitaService>(DisponibilitaService);
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'router-link': true,
},
provide: {
alertService,
disponibilitaService: () => disponibilitaServiceStub,
},
};
});
describe('Navigate to details', () => {
it('Should call load all on init', async () => {
// GIVEN
disponibilitaServiceStub.find.resolves(disponibilitaSample);
route = {
params: {
disponibilitaId: `${123}`,
},
};
const wrapper = shallowMount(DisponibilitaDetails, { global: mountOptions });
const comp = wrapper.vm;
// WHEN
await comp.$nextTick();
// THEN
expect(comp.disponibilita).toMatchObject(disponibilitaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
disponibilitaServiceStub.find.resolves(disponibilitaSample);
const wrapper = shallowMount(DisponibilitaDetails, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,46 @@
import { type Ref, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type IDisponibilita } from '@/shared/model/disponibilita.model';
import DisponibilitaService from './disponibilita.service';
export default defineComponent({
name: 'DisponibilitaDetails',
setup() {
const dateFormat = useDateFormat();
const disponibilitaService = inject('disponibilitaService', () => new DisponibilitaService());
const alertService = inject('alertService', () => useAlertService(), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const disponibilita: Ref<IDisponibilita> = ref({});
const retrieveDisponibilita = async disponibilitaId => {
try {
const res = await disponibilitaService().find(disponibilitaId);
disponibilita.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.disponibilitaId) {
retrieveDisponibilita(route.params.disponibilitaId);
}
return {
...dateFormat,
alertService,
disponibilita,
previousState,
t$: useI18n().t,
};
},
});

View File

@@ -0,0 +1,86 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<div v-if="disponibilita">
<h2 class="jh-entity-heading" data-cy="disponibilitaDetailsHeading">
<span>{{ t$('smartbookingApp.disponibilita.detail.title') }}Disponibilita</span> {{ disponibilita.id }}
</h2>
<dl class="row-md jh-entity-details">
<dt>
<span>{{ t$('smartbookingApp.disponibilita.giornoSettimana') }}</span>
</dt>
<dd>
<span>{{ t$('smartbookingApp.GiornoSettimana.' + disponibilita.giornoSettimana) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.disponibilita.dataSpecifica') }}</span>
</dt>
<dd>
<span>{{ disponibilita.dataSpecifica }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.disponibilita.oraInizio') }}</span>
</dt>
<dd>
<span v-if="disponibilita.oraInizio">{{ formatDateLong(disponibilita.oraInizio) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.disponibilita.oraFine') }}</span>
</dt>
<dd>
<span v-if="disponibilita.oraFine">{{ formatDateLong(disponibilita.oraFine) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.disponibilita.orarioInizio') }}</span>
</dt>
<dd>
<span>{{ disponibilita.orarioInizio }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.disponibilita.orarioFine') }}</span>
</dt>
<dd>
<span>{{ disponibilita.orarioFine }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.disponibilita.tipo') }}</span>
</dt>
<dd>
<span>{{ t$('smartbookingApp.TipoDisponibilita.' + disponibilita.tipo) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.disponibilita.note') }}</span>
</dt>
<dd>
<span>{{ disponibilita.note }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.disponibilita.struttura') }}</span>
</dt>
<dd>
<div v-if="disponibilita.struttura">
<router-link :to="{ name: 'StrutturaView', params: { strutturaId: disponibilita.struttura.id } }">{{
disponibilita.struttura.nome
}}</router-link>
</div>
</dd>
</dl>
<button type="submit" @click.prevent="previousState()" class="btn btn-info" data-cy="entityDetailsBackButton">
<font-awesome-icon icon="arrow-left"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.back') }}</span>
</button>
<router-link
v-if="disponibilita.id"
:to="{ name: 'DisponibilitaEdit', params: { disponibilitaId: disponibilita.id } }"
custom
v-slot="{ navigate }"
>
<button @click="navigate" class="btn btn-primary">
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.edit') }}</span>
</button>
</router-link>
</div>
</div>
</div>
</template>
<script lang="ts" src="./disponibilita-details.component.ts"></script>

View File

@@ -0,0 +1,161 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import dayjs from 'dayjs';
import sinon, { type SinonStubbedInstance } from 'sinon';
import StrutturaService from '@/entities/struttura/struttura.service';
import AlertService from '@/shared/alert/alert.service';
import { DATE_TIME_LONG_FORMAT } from '@/shared/composables/date-format';
import DisponibilitaUpdate from './disponibilita-update.vue';
import DisponibilitaService from './disponibilita.service';
type DisponibilitaUpdateComponentType = InstanceType<typeof DisponibilitaUpdate>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const disponibilitaSample = { id: 123 };
describe('Component Tests', () => {
let mountOptions: MountingOptions<DisponibilitaUpdateComponentType>['global'];
let alertService: AlertService;
describe('Disponibilita Management Update Component', () => {
let comp: DisponibilitaUpdateComponentType;
let disponibilitaServiceStub: SinonStubbedInstance<DisponibilitaService>;
beforeEach(() => {
route = {};
disponibilitaServiceStub = sinon.createStubInstance<DisponibilitaService>(DisponibilitaService);
disponibilitaServiceStub.retrieve.onFirstCall().resolves(Promise.resolve([]));
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'b-input-group': true,
'b-input-group-prepend': true,
'b-form-datepicker': true,
'b-form-input': true,
},
provide: {
alertService,
disponibilitaService: () => disponibilitaServiceStub,
strutturaService: () =>
sinon.createStubInstance<StrutturaService>(StrutturaService, {
retrieve: sinon.stub().resolves({}),
} as any),
},
};
});
afterEach(() => {
vitest.resetAllMocks();
});
describe('load', () => {
beforeEach(() => {
const wrapper = shallowMount(DisponibilitaUpdate, { global: mountOptions });
comp = wrapper.vm;
});
it('Should convert date from string', () => {
// GIVEN
const date = new Date('2019-10-15T11:42:02Z');
// WHEN
const convertedDate = comp.convertDateTimeFromServer(date);
// THEN
expect(convertedDate).toEqual(dayjs(date).format(DATE_TIME_LONG_FORMAT));
});
it('Should not convert date if date is not present', () => {
expect(comp.convertDateTimeFromServer(null)).toBeNull();
});
});
describe('save', () => {
it('Should call update service on save for existing entity', async () => {
// GIVEN
const wrapper = shallowMount(DisponibilitaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.disponibilita = disponibilitaSample;
disponibilitaServiceStub.update.resolves(disponibilitaSample);
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(disponibilitaServiceStub.update.calledWith(disponibilitaSample)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
it('Should call create service on save for new entity', async () => {
// GIVEN
const entity = {};
disponibilitaServiceStub.create.resolves(entity);
const wrapper = shallowMount(DisponibilitaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.disponibilita = entity;
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(disponibilitaServiceStub.create.calledWith(entity)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
});
describe('Before route enter', () => {
it('Should retrieve data', async () => {
// GIVEN
disponibilitaServiceStub.find.resolves(disponibilitaSample);
disponibilitaServiceStub.retrieve.resolves([disponibilitaSample]);
// WHEN
route = {
params: {
disponibilitaId: `${disponibilitaSample.id}`,
},
};
const wrapper = shallowMount(DisponibilitaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(comp.disponibilita).toMatchObject(disponibilitaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
disponibilitaServiceStub.find.resolves(disponibilitaSample);
const wrapper = shallowMount(DisponibilitaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,125 @@
import { type Ref, computed, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useVuelidate } from '@vuelidate/core';
import StrutturaService from '@/entities/struttura/struttura.service';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat, useValidation } from '@/shared/composables';
import { Disponibilita, type IDisponibilita } from '@/shared/model/disponibilita.model';
import { GiornoSettimana } from '@/shared/model/enumerations/giorno-settimana.model';
import { TipoDisponibilita } from '@/shared/model/enumerations/tipo-disponibilita.model';
import { type IStruttura } from '@/shared/model/struttura.model';
import DisponibilitaService from './disponibilita.service';
export default defineComponent({
name: 'DisponibilitaUpdate',
setup() {
const disponibilitaService = inject('disponibilitaService', () => new DisponibilitaService());
const alertService = inject('alertService', () => useAlertService(), true);
const disponibilita: Ref<IDisponibilita> = ref(new Disponibilita());
const strutturaService = inject('strutturaService', () => new StrutturaService());
const strutturas: Ref<IStruttura[]> = ref([]);
const giornoSettimanaValues: Ref<string[]> = ref(Object.keys(GiornoSettimana));
const tipoDisponibilitaValues: Ref<string[]> = ref(Object.keys(TipoDisponibilita));
const isSaving = ref(false);
const currentLanguage = inject('currentLanguage', () => computed(() => navigator.language ?? 'it'), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const retrieveDisponibilita = async disponibilitaId => {
try {
const res = await disponibilitaService().find(disponibilitaId);
res.oraInizio = new Date(res.oraInizio);
res.oraFine = new Date(res.oraFine);
disponibilita.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.disponibilitaId) {
retrieveDisponibilita(route.params.disponibilitaId);
}
const initRelationships = () => {
strutturaService()
.retrieve()
.then(res => {
strutturas.value = res.data;
});
};
initRelationships();
const { t: t$ } = useI18n();
const validations = useValidation();
const validationRules = {
giornoSettimana: {},
dataSpecifica: {},
oraInizio: {},
oraFine: {},
orarioInizio: {},
orarioFine: {},
tipo: {},
note: {},
struttura: {},
};
const v$ = useVuelidate(validationRules, disponibilita as any);
v$.value.$validate();
return {
disponibilitaService,
alertService,
disponibilita,
previousState,
giornoSettimanaValues,
tipoDisponibilitaValues,
isSaving,
currentLanguage,
strutturas,
v$,
...useDateFormat({ entityRef: disponibilita }),
t$,
};
},
created(): void {},
methods: {
save(): void {
this.isSaving = true;
if (this.disponibilita.id) {
this.disponibilitaService()
.update(this.disponibilita)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showInfo(this.t$('smartbookingApp.disponibilita.updated', { param: param.id }));
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
} else {
this.disponibilitaService()
.create(this.disponibilita)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showSuccess(this.t$('smartbookingApp.disponibilita.created', { param: param.id }).toString());
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
}
},
},
});

View File

@@ -0,0 +1,187 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<form name="editForm" novalidate @submit.prevent="save()">
<h2 id="smartbookingApp.disponibilita.home.createOrEditLabel" data-cy="DisponibilitaCreateUpdateHeading">
{{ t$('smartbookingApp.disponibilita.home.createOrEditLabel') }}
</h2>
<div>
<div class="mb-3" v-if="disponibilita.id">
<label for="id">{{ t$('global.field.id') }}</label>
<input type="text" class="form-control" id="id" name="id" v-model="disponibilita.id" readonly />
</div>
<div class="mb-3">
<label class="form-control-label" for="disponibilita">{{ t$('smartbookingApp.disponibilita.giornoSettimana') }}</label>
<select
class="form-control"
name="giornoSettimana"
:class="{ valid: !v$.giornoSettimana.$invalid, invalid: v$.giornoSettimana.$invalid }"
v-model="v$.giornoSettimana.$model"
id="disponibilita-giornoSettimana"
data-cy="giornoSettimana"
>
<option
v-for="giornoSettimana in giornoSettimanaValues"
:key="giornoSettimana"
:value="giornoSettimana"
:label="t$('smartbookingApp.GiornoSettimana.' + giornoSettimana)"
>
{{ giornoSettimana }}
</option>
</select>
</div>
<div class="mb-3">
<label class="form-control-label" for="disponibilita">{{ t$('smartbookingApp.disponibilita.dataSpecifica') }}</label>
<b-input-group class="mb-3">
<b-input-group-prepend>
<b-form-datepicker
aria-controls="disponibilita-dataSpecifica"
v-model="v$.dataSpecifica.$model"
name="dataSpecifica"
class="form-control"
:locale="currentLanguage"
button-only
today-button
reset-button
close-button
>
</b-form-datepicker>
</b-input-group-prepend>
<b-form-input
id="disponibilita-dataSpecifica"
data-cy="dataSpecifica"
type="text"
class="form-control"
name="dataSpecifica"
:class="{ valid: !v$.dataSpecifica.$invalid, invalid: v$.dataSpecifica.$invalid }"
v-model="v$.dataSpecifica.$model"
/>
</b-input-group>
</div>
<div class="mb-3">
<label class="form-control-label" for="disponibilita">{{ t$('smartbookingApp.disponibilita.oraInizio') }}</label>
<div class="d-flex">
<input
id="disponibilita-oraInizio"
data-cy="oraInizio"
type="datetime-local"
class="form-control"
name="oraInizio"
:class="{ valid: !v$.oraInizio.$invalid, invalid: v$.oraInizio.$invalid }"
:value="convertDateTimeFromServer(v$.oraInizio.$model)"
@change="updateInstantField('oraInizio', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="disponibilita">{{ t$('smartbookingApp.disponibilita.oraFine') }}</label>
<div class="d-flex">
<input
id="disponibilita-oraFine"
data-cy="oraFine"
type="datetime-local"
class="form-control"
name="oraFine"
:class="{ valid: !v$.oraFine.$invalid, invalid: v$.oraFine.$invalid }"
:value="convertDateTimeFromServer(v$.oraFine.$model)"
@change="updateInstantField('oraFine', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="disponibilita">{{ t$('smartbookingApp.disponibilita.orarioInizio') }}</label>
<input
type="text"
class="form-control"
name="orarioInizio"
id="disponibilita-orarioInizio"
data-cy="orarioInizio"
:class="{ valid: !v$.orarioInizio.$invalid, invalid: v$.orarioInizio.$invalid }"
v-model="v$.orarioInizio.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="disponibilita">{{ t$('smartbookingApp.disponibilita.orarioFine') }}</label>
<input
type="text"
class="form-control"
name="orarioFine"
id="disponibilita-orarioFine"
data-cy="orarioFine"
:class="{ valid: !v$.orarioFine.$invalid, invalid: v$.orarioFine.$invalid }"
v-model="v$.orarioFine.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="disponibilita">{{ t$('smartbookingApp.disponibilita.tipo') }}</label>
<select
class="form-control"
name="tipo"
:class="{ valid: !v$.tipo.$invalid, invalid: v$.tipo.$invalid }"
v-model="v$.tipo.$model"
id="disponibilita-tipo"
data-cy="tipo"
>
<option
v-for="tipoDisponibilita in tipoDisponibilitaValues"
:key="tipoDisponibilita"
:value="tipoDisponibilita"
:label="t$('smartbookingApp.TipoDisponibilita.' + tipoDisponibilita)"
>
{{ tipoDisponibilita }}
</option>
</select>
</div>
<div class="mb-3">
<label class="form-control-label" for="disponibilita">{{ t$('smartbookingApp.disponibilita.note') }}</label>
<input
type="text"
class="form-control"
name="note"
id="disponibilita-note"
data-cy="note"
:class="{ valid: !v$.note.$invalid, invalid: v$.note.$invalid }"
v-model="v$.note.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="disponibilita">{{ t$('smartbookingApp.disponibilita.struttura') }}</label>
<select
class="form-control"
id="disponibilita-struttura"
data-cy="struttura"
name="struttura"
v-model="disponibilita.struttura"
>
<option :value="null"></option>
<option
:value="
disponibilita.struttura && strutturaOption.id === disponibilita.struttura.id ? disponibilita.struttura : strutturaOption
"
v-for="strutturaOption in strutturas"
:key="strutturaOption.id"
>
{{ strutturaOption.nome }}
</option>
</select>
</div>
</div>
<div>
<button type="button" id="cancel-save" data-cy="entityCreateCancelButton" class="btn btn-secondary" @click="previousState()">
<font-awesome-icon icon="ban"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.cancel') }}</span>
</button>
<button
type="submit"
id="save-entity"
data-cy="entityCreateSaveButton"
:disabled="v$.$invalid || isSaving"
class="btn btn-primary"
>
<font-awesome-icon icon="save"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.save') }}</span>
</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts" src="./disponibilita-update.component.ts"></script>

View File

@@ -0,0 +1,158 @@
import { vitest } from 'vitest';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import DisponibilitaService from './disponibilita.service';
import Disponibilita from './disponibilita.vue';
type DisponibilitaComponentType = InstanceType<typeof Disponibilita>;
const bModalStub = {
render: () => {},
methods: {
hide: () => {},
show: () => {},
},
};
describe('Component Tests', () => {
let alertService: AlertService;
describe('Disponibilita Management Component', () => {
let disponibilitaServiceStub: SinonStubbedInstance<DisponibilitaService>;
let mountOptions: MountingOptions<DisponibilitaComponentType>['global'];
beforeEach(() => {
disponibilitaServiceStub = sinon.createStubInstance<DisponibilitaService>(DisponibilitaService);
disponibilitaServiceStub.retrieve.resolves({ headers: {} });
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
jhiItemCount: true,
bPagination: true,
bModal: bModalStub as any,
'font-awesome-icon': true,
'b-badge': true,
'jhi-sort-indicator': true,
'b-button': true,
'router-link': true,
},
directives: {
'b-modal': {},
},
provide: {
alertService,
disponibilitaService: () => disponibilitaServiceStub,
},
};
});
describe('Mount', () => {
it('Should call load all on init', async () => {
// GIVEN
disponibilitaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
const wrapper = shallowMount(Disponibilita, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(disponibilitaServiceStub.retrieve.calledOnce).toBeTruthy();
expect(comp.disponibilitas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for an id', async () => {
// WHEN
const wrapper = shallowMount(Disponibilita, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(disponibilitaServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['id,asc'],
});
});
});
describe('Handles', () => {
let comp: DisponibilitaComponentType;
beforeEach(async () => {
const wrapper = shallowMount(Disponibilita, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
disponibilitaServiceStub.retrieve.reset();
disponibilitaServiceStub.retrieve.resolves({ headers: {}, data: [] });
});
it('should load a page', async () => {
// GIVEN
disponibilitaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.page = 2;
await comp.$nextTick();
// THEN
expect(disponibilitaServiceStub.retrieve.called).toBeTruthy();
expect(comp.disponibilitas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should re-initialize the page', async () => {
// GIVEN
comp.page = 2;
await comp.$nextTick();
disponibilitaServiceStub.retrieve.reset();
disponibilitaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.clear();
await comp.$nextTick();
// THEN
expect(comp.page).toEqual(1);
expect(disponibilitaServiceStub.retrieve.callCount).toEqual(1);
expect(comp.disponibilitas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for a non-id attribute', async () => {
// WHEN
comp.propOrder = 'name';
await comp.$nextTick();
// THEN
expect(disponibilitaServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['name,asc', 'id'],
});
});
it('Should call delete service on confirmDelete', async () => {
// GIVEN
disponibilitaServiceStub.delete.resolves({});
// WHEN
comp.prepareRemove({ id: 123 });
comp.removeDisponibilita();
await comp.$nextTick(); // clear components
// THEN
expect(disponibilitaServiceStub.delete.called).toBeTruthy();
// THEN
await comp.$nextTick(); // handle component clear watch
expect(disponibilitaServiceStub.retrieve.callCount).toEqual(1);
});
});
});
});

View File

@@ -0,0 +1,164 @@
import { type Ref, defineComponent, inject, onMounted, ref, watch, watchEffect } from 'vue';
import { useI18n } from 'vue-i18n';
import { useIntersectionObserver } from '@vueuse/core';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import useDataUtils from '@/shared/data/data-utils.service';
import { type IDisponibilita } from '@/shared/model/disponibilita.model';
import DisponibilitaService from './disponibilita.service';
export default defineComponent({
name: 'Disponibilita',
setup() {
const { t: t$ } = useI18n();
const dateFormat = useDateFormat();
const dataUtils = useDataUtils();
const disponibilitaService = inject('disponibilitaService', () => new DisponibilitaService());
const alertService = inject('alertService', () => useAlertService(), true);
const itemsPerPage = ref(20);
const queryCount: Ref<number> = ref(null);
const page: Ref<number> = ref(1);
const propOrder = ref('id');
const reverse = ref(false);
const totalItems = ref(0);
const links: Ref<any> = ref({});
const disponibilitas: Ref<IDisponibilita[]> = ref([]);
const isFetching = ref(false);
const clear = () => {
page.value = 1;
links.value = {};
disponibilitas.value = [];
};
const sort = (): Array<any> => {
const result = [`${propOrder.value},${reverse.value ? 'desc' : 'asc'}`];
if (propOrder.value !== 'id') {
result.push('id');
}
return result;
};
const retrieveDisponibilitas = async () => {
isFetching.value = true;
try {
const paginationQuery = {
page: page.value - 1,
size: itemsPerPage.value,
sort: sort(),
};
const res = await disponibilitaService().retrieve(paginationQuery);
totalItems.value = Number(res.headers['x-total-count']);
queryCount.value = totalItems.value;
links.value = dataUtils.parseLinks(res.headers?.link);
disponibilitas.value.push(...(res.data ?? []));
} catch (err) {
alertService.showHttpError(err.response);
} finally {
isFetching.value = false;
}
};
const handleSyncList = () => {
clear();
};
onMounted(async () => {
await retrieveDisponibilitas();
});
const removeId: Ref<number> = ref(null);
const removeEntity = ref<any>(null);
const prepareRemove = (instance: IDisponibilita) => {
removeId.value = instance.id;
removeEntity.value.show();
};
const closeDialog = () => {
removeEntity.value.hide();
};
const removeDisponibilita = async () => {
try {
await disponibilitaService().delete(removeId.value);
const message = t$('smartbookingApp.disponibilita.deleted', { param: removeId.value }).toString();
alertService.showInfo(message, { variant: 'danger' });
removeId.value = null;
clear();
closeDialog();
} catch (error) {
alertService.showHttpError(error.response);
}
};
const changeOrder = (newOrder: string) => {
if (propOrder.value === newOrder) {
reverse.value = !reverse.value;
} else {
reverse.value = false;
}
propOrder.value = newOrder;
};
// Whenever order changes, reset the pagination
watch([propOrder, reverse], () => {
clear();
});
// Whenever the data resets or page changes, switch to the new page.
watch([disponibilitas, page], async ([data, page], [_prevData, prevPage]) => {
if (data.length === 0 || page !== prevPage) {
await retrieveDisponibilitas();
}
});
const infiniteScrollEl = ref<HTMLElement>(null);
const intersectionObserver = useIntersectionObserver(
infiniteScrollEl,
intersection => {
if (intersection[0].isIntersecting && !isFetching.value) {
page.value++;
}
},
{
threshold: 0.5,
immediate: false,
},
);
watchEffect(() => {
if (links.value.next) {
intersectionObserver.resume();
} else if (intersectionObserver.isActive) {
intersectionObserver.pause();
}
});
return {
disponibilitas,
handleSyncList,
isFetching,
retrieveDisponibilitas,
clear,
...dateFormat,
removeId,
removeEntity,
prepareRemove,
closeDialog,
removeDisponibilita,
itemsPerPage,
queryCount,
page,
propOrder,
reverse,
totalItems,
changeOrder,
infiniteScrollEl,
t$,
...dataUtils,
};
},
});

View File

@@ -0,0 +1,202 @@
import axios from 'axios';
import dayjs from 'dayjs';
import sinon from 'sinon';
import { DATE_FORMAT, DATE_TIME_FORMAT } from '@/shared/composables/date-format';
import { Disponibilita } from '@/shared/model/disponibilita.model';
import DisponibilitaService from './disponibilita.service';
const error = {
response: {
status: null,
data: {
type: null,
},
},
};
const axiosStub = {
get: sinon.stub(axios, 'get'),
post: sinon.stub(axios, 'post'),
put: sinon.stub(axios, 'put'),
patch: sinon.stub(axios, 'patch'),
delete: sinon.stub(axios, 'delete'),
};
describe('Service Tests', () => {
describe('Disponibilita Service', () => {
let service: DisponibilitaService;
let elemDefault;
let currentDate: Date;
beforeEach(() => {
service = new DisponibilitaService();
currentDate = new Date();
elemDefault = new Disponibilita(123, 'LUNEDI', currentDate, currentDate, currentDate, 'AAAAAAA', 'AAAAAAA', 'DISPONIBILE', 'AAAAAAA');
});
describe('Service methods', () => {
it('should find an element', async () => {
const returnedFromService = {
dataSpecifica: dayjs(currentDate).format(DATE_FORMAT),
oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
axiosStub.get.resolves({ data: returnedFromService });
return service.find(123).then(res => {
expect(res).toMatchObject(elemDefault);
});
});
it('should not find an element', async () => {
axiosStub.get.rejects(error);
return service
.find(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should create a Disponibilita', async () => {
const returnedFromService = {
id: 123,
dataSpecifica: dayjs(currentDate).format(DATE_FORMAT),
oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { dataSpecifica: currentDate, oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };
axiosStub.post.resolves({ data: returnedFromService });
return service.create({}).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not create a Disponibilita', async () => {
axiosStub.post.rejects(error);
return service
.create({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should update a Disponibilita', async () => {
const returnedFromService = {
giornoSettimana: 'BBBBBB',
dataSpecifica: dayjs(currentDate).format(DATE_FORMAT),
oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
orarioInizio: 'BBBBBB',
orarioFine: 'BBBBBB',
tipo: 'BBBBBB',
note: 'BBBBBB',
...elemDefault,
};
const expected = { dataSpecifica: currentDate, oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };
axiosStub.put.resolves({ data: returnedFromService });
return service.update(expected).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not update a Disponibilita', async () => {
axiosStub.put.rejects(error);
return service
.update({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should partial update a Disponibilita', async () => {
const patchObject = {
giornoSettimana: 'BBBBBB',
dataSpecifica: dayjs(currentDate).format(DATE_FORMAT),
oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
orarioInizio: 'BBBBBB',
tipo: 'BBBBBB',
...new Disponibilita(),
};
const returnedFromService = Object.assign(patchObject, elemDefault);
const expected = { dataSpecifica: currentDate, oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };
axiosStub.patch.resolves({ data: returnedFromService });
return service.partialUpdate(patchObject).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not partial update a Disponibilita', async () => {
axiosStub.patch.rejects(error);
return service
.partialUpdate({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should return a list of Disponibilita', async () => {
const returnedFromService = {
giornoSettimana: 'BBBBBB',
dataSpecifica: dayjs(currentDate).format(DATE_FORMAT),
oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
orarioInizio: 'BBBBBB',
orarioFine: 'BBBBBB',
tipo: 'BBBBBB',
note: 'BBBBBB',
...elemDefault,
};
const expected = { dataSpecifica: currentDate, oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };
axiosStub.get.resolves([returnedFromService]);
return service.retrieve({ sort: {}, page: 0, size: 10 }).then(res => {
expect(res).toContainEqual(expected);
});
});
it('should not return a list of Disponibilita', async () => {
axiosStub.get.rejects(error);
return service
.retrieve()
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should delete a Disponibilita', async () => {
axiosStub.delete.resolves({ ok: true });
return service.delete(123).then(res => {
expect(res.ok).toBeTruthy();
});
});
it('should not delete a Disponibilita', async () => {
axiosStub.delete.rejects(error);
return service
.delete(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
});
});
});

View File

@@ -0,0 +1,86 @@
import axios from 'axios';
import { type IDisponibilita } from '@/shared/model/disponibilita.model';
import buildPaginationQueryOpts from '@/shared/sort/sorts';
const baseApiUrl = 'api/disponibilitas';
export default class DisponibilitaService {
find(id: number): Promise<IDisponibilita> {
return new Promise<IDisponibilita>((resolve, reject) => {
axios
.get(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
retrieve(paginationQuery?: any): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.get(`${baseApiUrl}?${buildPaginationQueryOpts(paginationQuery)}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
delete(id: number): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.delete(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
create(entity: IDisponibilita): Promise<IDisponibilita> {
return new Promise<IDisponibilita>((resolve, reject) => {
axios
.post(baseApiUrl, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
update(entity: IDisponibilita): Promise<IDisponibilita> {
return new Promise<IDisponibilita>((resolve, reject) => {
axios
.put(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
partialUpdate(entity: IDisponibilita): Promise<IDisponibilita> {
return new Promise<IDisponibilita>((resolve, reject) => {
axios
.patch(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
}

View File

@@ -0,0 +1,158 @@
<template>
<div>
<h2 id="page-heading" data-cy="DisponibilitaHeading">
<span id="disponibilita">{{ t$('smartbookingApp.disponibilita.home.title') }}</span>
<div class="d-flex justify-content-end">
<button class="btn btn-info me-2" @click="handleSyncList" :disabled="isFetching">
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
<span>{{ t$('smartbookingApp.disponibilita.home.refreshListLabel') }}</span>
</button>
<router-link :to="{ name: 'DisponibilitaCreate' }" custom v-slot="{ navigate }">
<button
@click="navigate"
id="jh-create-entity"
data-cy="entityCreateButton"
class="btn btn-primary jh-create-entity create-disponibilita"
>
<font-awesome-icon icon="plus"></font-awesome-icon>
<span>{{ t$('smartbookingApp.disponibilita.home.createLabel') }}</span>
</button>
</router-link>
</div>
</h2>
<br />
<div class="alert alert-warning" v-if="!isFetching && disponibilitas?.length === 0">
<span>{{ t$('smartbookingApp.disponibilita.home.notFound') }}</span>
</div>
<div class="table-responsive" v-if="disponibilitas?.length > 0">
<table class="table table-striped" aria-describedby="disponibilitas">
<thead>
<tr>
<th scope="col" @click="changeOrder('id')">
<span>{{ t$('global.field.id') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'id'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('giornoSettimana')">
<span>{{ t$('smartbookingApp.disponibilita.giornoSettimana') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'giornoSettimana'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('dataSpecifica')">
<span>{{ t$('smartbookingApp.disponibilita.dataSpecifica') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'dataSpecifica'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('oraInizio')">
<span>{{ t$('smartbookingApp.disponibilita.oraInizio') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'oraInizio'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('oraFine')">
<span>{{ t$('smartbookingApp.disponibilita.oraFine') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'oraFine'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('orarioInizio')">
<span>{{ t$('smartbookingApp.disponibilita.orarioInizio') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'orarioInizio'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('orarioFine')">
<span>{{ t$('smartbookingApp.disponibilita.orarioFine') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'orarioFine'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('tipo')">
<span>{{ t$('smartbookingApp.disponibilita.tipo') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'tipo'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('note')">
<span>{{ t$('smartbookingApp.disponibilita.note') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'note'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('struttura.nome')">
<span>{{ t$('smartbookingApp.disponibilita.struttura') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'struttura.nome'"></jhi-sort-indicator>
</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="disponibilita in disponibilitas" :key="disponibilita.id" data-cy="entityTable">
<td>
<router-link :to="{ name: 'DisponibilitaView', params: { disponibilitaId: disponibilita.id } }">{{
disponibilita.id
}}</router-link>
</td>
<td>{{ t$('smartbookingApp.GiornoSettimana.' + disponibilita.giornoSettimana) }}</td>
<td>{{ disponibilita.dataSpecifica }}</td>
<td>{{ formatDateShort(disponibilita.oraInizio) || '' }}</td>
<td>{{ formatDateShort(disponibilita.oraFine) || '' }}</td>
<td>{{ disponibilita.orarioInizio }}</td>
<td>{{ disponibilita.orarioFine }}</td>
<td>{{ t$('smartbookingApp.TipoDisponibilita.' + disponibilita.tipo) }}</td>
<td>{{ disponibilita.note }}</td>
<td>
<div v-if="disponibilita.struttura">
<router-link :to="{ name: 'StrutturaView', params: { strutturaId: disponibilita.struttura.id } }">{{
disponibilita.struttura.nome
}}</router-link>
</div>
</td>
<td class="text-end">
<div class="btn-group">
<router-link
:to="{ name: 'DisponibilitaView', params: { disponibilitaId: disponibilita.id } }"
class="btn btn-info btn-sm details"
data-cy="entityDetailsButton"
>
<font-awesome-icon icon="eye"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
</router-link>
<router-link
:to="{ name: 'DisponibilitaEdit', params: { disponibilitaId: disponibilita.id } }"
class="btn btn-primary btn-sm edit"
data-cy="entityEditButton"
>
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.edit') }}</span>
</router-link>
<b-button
@click="prepareRemove(disponibilita)"
variant="danger"
class="btn btn-sm"
data-cy="entityDeleteButton"
v-b-modal.removeEntity
>
<font-awesome-icon icon="times"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
</b-button>
</div>
</td>
</tr>
</tbody>
<span ref="infiniteScrollEl"></span>
</table>
</div>
<b-modal ref="removeEntity" id="removeEntity">
<template #title>
<span id="smartbookingApp.disponibilita.delete.question" data-cy="disponibilitaDeleteDialogHeading">{{
t$('entity.delete.title')
}}</span>
</template>
<div class="modal-body">
<p id="jhi-delete-disponibilita-heading">{{ t$('smartbookingApp.disponibilita.delete.question', { id: removeId }) }}</p>
</div>
<template #footer>
<div>
<button type="button" class="btn btn-secondary" @click="closeDialog()">{{ t$('entity.action.cancel') }}</button>
<button
type="button"
class="btn btn-primary"
id="jhi-confirm-delete-disponibilita"
data-cy="entityConfirmDeleteButton"
@click="removeDisponibilita"
>
{{ t$('entity.action.delete') }}
</button>
</div>
</template>
</b-modal>
</div>
</template>
<script lang="ts" src="./disponibilita.component.ts"></script>

View File

@@ -1,5 +1,45 @@
<template>
<div>
<b-dropdown-item to="/audit-log">
<font-awesome-icon icon="asterisk" />
<span>{{ t$('global.menu.entities.auditLog') }}</span>
</b-dropdown-item>
<b-dropdown-item to="/disponibilita">
<font-awesome-icon icon="asterisk" />
<span>{{ t$('global.menu.entities.disponibilita') }}</span>
</b-dropdown-item>
<b-dropdown-item to="/notifica">
<font-awesome-icon icon="asterisk" />
<span>{{ t$('global.menu.entities.notifica') }}</span>
</b-dropdown-item>
<b-dropdown-item to="/prenotazione">
<font-awesome-icon icon="asterisk" />
<span>{{ t$('global.menu.entities.prenotazione') }}</span>
</b-dropdown-item>
<b-dropdown-item to="/conferma">
<font-awesome-icon icon="asterisk" />
<span>{{ t$('global.menu.entities.conferma') }}</span>
</b-dropdown-item>
<b-dropdown-item to="/struttura">
<font-awesome-icon icon="asterisk" />
<span>{{ t$('global.menu.entities.struttura') }}</span>
</b-dropdown-item>
<b-dropdown-item to="/utente-app">
<font-awesome-icon icon="asterisk" />
<span>{{ t$('global.menu.entities.utenteApp') }}</span>
</b-dropdown-item>
<b-dropdown-item to="/liberatoria">
<font-awesome-icon icon="asterisk" />
<span>{{ t$('global.menu.entities.liberatoria') }}</span>
</b-dropdown-item>
<b-dropdown-item to="/modello-liberatoria">
<font-awesome-icon icon="asterisk" />
<span>{{ t$('global.menu.entities.modelloLiberatoria') }}</span>
</b-dropdown-item>
<b-dropdown-item to="/messaggio">
<font-awesome-icon icon="asterisk" />
<span>{{ t$('global.menu.entities.messaggio') }}</span>
</b-dropdown-item>
<!-- jhipster-needle-add-entity-to-menu - JHipster will add entities to the menu here -->
</div>
</template>

View File

@@ -1,12 +1,33 @@
import { defineComponent, provide } from 'vue';
import UserService from '@/entities/user/user.service';
import AuditLogService from './audit-log/audit-log.service';
import ConfermaService from './conferma/conferma.service';
import DisponibilitaService from './disponibilita/disponibilita.service';
import LiberatoriaService from './liberatoria/liberatoria.service';
import MessaggioService from './messaggio/messaggio.service';
import ModelloLiberatoriaService from './modello-liberatoria/modello-liberatoria.service';
import NotificaService from './notifica/notifica.service';
import PrenotazioneService from './prenotazione/prenotazione.service';
import StrutturaService from './struttura/struttura.service';
import UtenteAppService from './utente-app/utente-app.service';
// jhipster-needle-add-entity-service-to-entities-component-import - JHipster will import entities services here
export default defineComponent({
name: 'Entities',
setup() {
provide('userService', () => new UserService());
provide('auditLogService', () => new AuditLogService());
provide('disponibilitaService', () => new DisponibilitaService());
provide('notificaService', () => new NotificaService());
provide('prenotazioneService', () => new PrenotazioneService());
provide('confermaService', () => new ConfermaService());
provide('strutturaService', () => new StrutturaService());
provide('utenteAppService', () => new UtenteAppService());
provide('liberatoriaService', () => new LiberatoriaService());
provide('modelloLiberatoriaService', () => new ModelloLiberatoriaService());
provide('messaggioService', () => new MessaggioService());
// jhipster-needle-add-entity-service-to-entities-component - JHipster will import entities services here
},
});

View File

@@ -0,0 +1,91 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import LiberatoriaDetails from './liberatoria-details.vue';
import LiberatoriaService from './liberatoria.service';
type LiberatoriaDetailsComponentType = InstanceType<typeof LiberatoriaDetails>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const liberatoriaSample = { id: 123 };
describe('Component Tests', () => {
let alertService: AlertService;
afterEach(() => {
vitest.resetAllMocks();
});
describe('Liberatoria Management Detail Component', () => {
let liberatoriaServiceStub: SinonStubbedInstance<LiberatoriaService>;
let mountOptions: MountingOptions<LiberatoriaDetailsComponentType>['global'];
beforeEach(() => {
route = {};
liberatoriaServiceStub = sinon.createStubInstance<LiberatoriaService>(LiberatoriaService);
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'router-link': true,
},
provide: {
alertService,
liberatoriaService: () => liberatoriaServiceStub,
},
};
});
describe('Navigate to details', () => {
it('Should call load all on init', async () => {
// GIVEN
liberatoriaServiceStub.find.resolves(liberatoriaSample);
route = {
params: {
liberatoriaId: `${123}`,
},
};
const wrapper = shallowMount(LiberatoriaDetails, { global: mountOptions });
const comp = wrapper.vm;
// WHEN
await comp.$nextTick();
// THEN
expect(comp.liberatoria).toMatchObject(liberatoriaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
liberatoriaServiceStub.find.resolves(liberatoriaSample);
const wrapper = shallowMount(LiberatoriaDetails, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,46 @@
import { type Ref, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type ILiberatoria } from '@/shared/model/liberatoria.model';
import LiberatoriaService from './liberatoria.service';
export default defineComponent({
name: 'LiberatoriaDetails',
setup() {
const dateFormat = useDateFormat();
const liberatoriaService = inject('liberatoriaService', () => new LiberatoriaService());
const alertService = inject('alertService', () => useAlertService(), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const liberatoria: Ref<ILiberatoria> = ref({});
const retrieveLiberatoria = async liberatoriaId => {
try {
const res = await liberatoriaService().find(liberatoriaId);
liberatoria.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.liberatoriaId) {
retrieveLiberatoria(route.params.liberatoriaId);
}
return {
...dateFormat,
alertService,
liberatoria,
previousState,
t$: useI18n().t,
};
},
});

View File

@@ -0,0 +1,54 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<div v-if="liberatoria">
<h2 class="jh-entity-heading" data-cy="liberatoriaDetailsHeading">
<span>{{ t$('smartbookingApp.liberatoria.detail.title') }}Liberatoria</span> {{ liberatoria.id }}
</h2>
<dl class="row-md jh-entity-details">
<dt>
<span>{{ t$('smartbookingApp.liberatoria.accettata') }}</span>
</dt>
<dd>
<span v-if="liberatoria.accettata">{{ formatDateLong(liberatoria.accettata) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.liberatoria.utente') }}</span>
</dt>
<dd>
<div v-if="liberatoria.utente">
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: liberatoria.utente.id } }">{{
liberatoria.utente.username
}}</router-link>
</div>
</dd>
<dt>
<span>{{ t$('smartbookingApp.liberatoria.modelloLiberatoria') }}</span>
</dt>
<dd>
<div v-if="liberatoria.modelloLiberatoria">
<router-link :to="{ name: 'ModelloLiberatoriaView', params: { modelloLiberatoriaId: liberatoria.modelloLiberatoria.id } }">{{
liberatoria.modelloLiberatoria.id
}}</router-link>
</div>
</dd>
</dl>
<button type="submit" @click.prevent="previousState()" class="btn btn-info" data-cy="entityDetailsBackButton">
<font-awesome-icon icon="arrow-left"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.back') }}</span>
</button>
<router-link
v-if="liberatoria.id"
:to="{ name: 'LiberatoriaEdit', params: { liberatoriaId: liberatoria.id } }"
custom
v-slot="{ navigate }"
>
<button @click="navigate" class="btn btn-primary">
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.edit') }}</span>
</button>
</router-link>
</div>
</div>
</div>
</template>
<script lang="ts" src="./liberatoria-details.component.ts"></script>

View File

@@ -0,0 +1,166 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import dayjs from 'dayjs';
import sinon, { type SinonStubbedInstance } from 'sinon';
import ModelloLiberatoriaService from '@/entities/modello-liberatoria/modello-liberatoria.service';
import UtenteAppService from '@/entities/utente-app/utente-app.service';
import AlertService from '@/shared/alert/alert.service';
import { DATE_TIME_LONG_FORMAT } from '@/shared/composables/date-format';
import LiberatoriaUpdate from './liberatoria-update.vue';
import LiberatoriaService from './liberatoria.service';
type LiberatoriaUpdateComponentType = InstanceType<typeof LiberatoriaUpdate>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const liberatoriaSample = { id: 123 };
describe('Component Tests', () => {
let mountOptions: MountingOptions<LiberatoriaUpdateComponentType>['global'];
let alertService: AlertService;
describe('Liberatoria Management Update Component', () => {
let comp: LiberatoriaUpdateComponentType;
let liberatoriaServiceStub: SinonStubbedInstance<LiberatoriaService>;
beforeEach(() => {
route = {};
liberatoriaServiceStub = sinon.createStubInstance<LiberatoriaService>(LiberatoriaService);
liberatoriaServiceStub.retrieve.onFirstCall().resolves(Promise.resolve([]));
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'b-input-group': true,
'b-input-group-prepend': true,
'b-form-datepicker': true,
'b-form-input': true,
},
provide: {
alertService,
liberatoriaService: () => liberatoriaServiceStub,
utenteAppService: () =>
sinon.createStubInstance<UtenteAppService>(UtenteAppService, {
retrieve: sinon.stub().resolves({}),
} as any),
modelloLiberatoriaService: () =>
sinon.createStubInstance<ModelloLiberatoriaService>(ModelloLiberatoriaService, {
retrieve: sinon.stub().resolves({}),
} as any),
},
};
});
afterEach(() => {
vitest.resetAllMocks();
});
describe('load', () => {
beforeEach(() => {
const wrapper = shallowMount(LiberatoriaUpdate, { global: mountOptions });
comp = wrapper.vm;
});
it('Should convert date from string', () => {
// GIVEN
const date = new Date('2019-10-15T11:42:02Z');
// WHEN
const convertedDate = comp.convertDateTimeFromServer(date);
// THEN
expect(convertedDate).toEqual(dayjs(date).format(DATE_TIME_LONG_FORMAT));
});
it('Should not convert date if date is not present', () => {
expect(comp.convertDateTimeFromServer(null)).toBeNull();
});
});
describe('save', () => {
it('Should call update service on save for existing entity', async () => {
// GIVEN
const wrapper = shallowMount(LiberatoriaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.liberatoria = liberatoriaSample;
liberatoriaServiceStub.update.resolves(liberatoriaSample);
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(liberatoriaServiceStub.update.calledWith(liberatoriaSample)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
it('Should call create service on save for new entity', async () => {
// GIVEN
const entity = {};
liberatoriaServiceStub.create.resolves(entity);
const wrapper = shallowMount(LiberatoriaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.liberatoria = entity;
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(liberatoriaServiceStub.create.calledWith(entity)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
});
describe('Before route enter', () => {
it('Should retrieve data', async () => {
// GIVEN
liberatoriaServiceStub.find.resolves(liberatoriaSample);
liberatoriaServiceStub.retrieve.resolves([liberatoriaSample]);
// WHEN
route = {
params: {
liberatoriaId: `${liberatoriaSample.id}`,
},
};
const wrapper = shallowMount(LiberatoriaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(comp.liberatoria).toMatchObject(liberatoriaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
liberatoriaServiceStub.find.resolves(liberatoriaSample);
const wrapper = shallowMount(LiberatoriaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,124 @@
import { type Ref, computed, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useVuelidate } from '@vuelidate/core';
import ModelloLiberatoriaService from '@/entities/modello-liberatoria/modello-liberatoria.service';
import UtenteAppService from '@/entities/utente-app/utente-app.service';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat, useValidation } from '@/shared/composables';
import { type ILiberatoria, Liberatoria } from '@/shared/model/liberatoria.model';
import { type IModelloLiberatoria } from '@/shared/model/modello-liberatoria.model';
import { type IUtenteApp } from '@/shared/model/utente-app.model';
import LiberatoriaService from './liberatoria.service';
export default defineComponent({
name: 'LiberatoriaUpdate',
setup() {
const liberatoriaService = inject('liberatoriaService', () => new LiberatoriaService());
const alertService = inject('alertService', () => useAlertService(), true);
const liberatoria: Ref<ILiberatoria> = ref(new Liberatoria());
const utenteAppService = inject('utenteAppService', () => new UtenteAppService());
const utenteApps: Ref<IUtenteApp[]> = ref([]);
const modelloLiberatoriaService = inject('modelloLiberatoriaService', () => new ModelloLiberatoriaService());
const modelloLiberatorias: Ref<IModelloLiberatoria[]> = ref([]);
const isSaving = ref(false);
const currentLanguage = inject('currentLanguage', () => computed(() => navigator.language ?? 'it'), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const retrieveLiberatoria = async liberatoriaId => {
try {
const res = await liberatoriaService().find(liberatoriaId);
res.accettata = new Date(res.accettata);
liberatoria.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.liberatoriaId) {
retrieveLiberatoria(route.params.liberatoriaId);
}
const initRelationships = () => {
utenteAppService()
.retrieve()
.then(res => {
utenteApps.value = res.data;
});
modelloLiberatoriaService()
.retrieve()
.then(res => {
modelloLiberatorias.value = res.data;
});
};
initRelationships();
const { t: t$ } = useI18n();
const validations = useValidation();
const validationRules = {
accettata: {},
utente: {},
modelloLiberatoria: {},
};
const v$ = useVuelidate(validationRules, liberatoria as any);
v$.value.$validate();
return {
liberatoriaService,
alertService,
liberatoria,
previousState,
isSaving,
currentLanguage,
utenteApps,
modelloLiberatorias,
v$,
...useDateFormat({ entityRef: liberatoria }),
t$,
};
},
created(): void {},
methods: {
save(): void {
this.isSaving = true;
if (this.liberatoria.id) {
this.liberatoriaService()
.update(this.liberatoria)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showInfo(this.t$('smartbookingApp.liberatoria.updated', { param: param.id }));
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
} else {
this.liberatoriaService()
.create(this.liberatoria)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showSuccess(this.t$('smartbookingApp.liberatoria.created', { param: param.id }).toString());
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
}
},
},
});

View File

@@ -0,0 +1,83 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<form name="editForm" novalidate @submit.prevent="save()">
<h2 id="smartbookingApp.liberatoria.home.createOrEditLabel" data-cy="LiberatoriaCreateUpdateHeading">
{{ t$('smartbookingApp.liberatoria.home.createOrEditLabel') }}
</h2>
<div>
<div class="mb-3" v-if="liberatoria.id">
<label for="id">{{ t$('global.field.id') }}</label>
<input type="text" class="form-control" id="id" name="id" v-model="liberatoria.id" readonly />
</div>
<div class="mb-3">
<label class="form-control-label" for="liberatoria">{{ t$('smartbookingApp.liberatoria.accettata') }}</label>
<div class="d-flex">
<input
id="liberatoria-accettata"
data-cy="accettata"
type="datetime-local"
class="form-control"
name="accettata"
:class="{ valid: !v$.accettata.$invalid, invalid: v$.accettata.$invalid }"
:value="convertDateTimeFromServer(v$.accettata.$model)"
@change="updateInstantField('accettata', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="liberatoria">{{ t$('smartbookingApp.liberatoria.utente') }}</label>
<select class="form-control" id="liberatoria-utente" data-cy="utente" name="utente" v-model="liberatoria.utente">
<option :value="null"></option>
<option
:value="liberatoria.utente && utenteAppOption.id === liberatoria.utente.id ? liberatoria.utente : utenteAppOption"
v-for="utenteAppOption in utenteApps"
:key="utenteAppOption.id"
>
{{ utenteAppOption.username }}
</option>
</select>
</div>
<div class="mb-3">
<label class="form-control-label" for="liberatoria">{{ t$('smartbookingApp.liberatoria.modelloLiberatoria') }}</label>
<select
class="form-control"
id="liberatoria-modelloLiberatoria"
data-cy="modelloLiberatoria"
name="modelloLiberatoria"
v-model="liberatoria.modelloLiberatoria"
>
<option :value="null"></option>
<option
:value="
liberatoria.modelloLiberatoria && modelloLiberatoriaOption.id === liberatoria.modelloLiberatoria.id
? liberatoria.modelloLiberatoria
: modelloLiberatoriaOption
"
v-for="modelloLiberatoriaOption in modelloLiberatorias"
:key="modelloLiberatoriaOption.id"
>
{{ modelloLiberatoriaOption.id }}
</option>
</select>
</div>
</div>
<div>
<button type="button" id="cancel-save" data-cy="entityCreateCancelButton" class="btn btn-secondary" @click="previousState()">
<font-awesome-icon icon="ban"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.cancel') }}</span>
</button>
<button
type="submit"
id="save-entity"
data-cy="entityCreateSaveButton"
:disabled="v$.$invalid || isSaving"
class="btn btn-primary"
>
<font-awesome-icon icon="save"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.save') }}</span>
</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts" src="./liberatoria-update.component.ts"></script>

View File

@@ -0,0 +1,102 @@
import { vitest } from 'vitest';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import LiberatoriaService from './liberatoria.service';
import Liberatoria from './liberatoria.vue';
type LiberatoriaComponentType = InstanceType<typeof Liberatoria>;
const bModalStub = {
render: () => {},
methods: {
hide: () => {},
show: () => {},
},
};
describe('Component Tests', () => {
let alertService: AlertService;
describe('Liberatoria Management Component', () => {
let liberatoriaServiceStub: SinonStubbedInstance<LiberatoriaService>;
let mountOptions: MountingOptions<LiberatoriaComponentType>['global'];
beforeEach(() => {
liberatoriaServiceStub = sinon.createStubInstance<LiberatoriaService>(LiberatoriaService);
liberatoriaServiceStub.retrieve.resolves({ headers: {} });
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
bModal: bModalStub as any,
'font-awesome-icon': true,
'b-badge': true,
'b-button': true,
'router-link': true,
},
directives: {
'b-modal': {},
},
provide: {
alertService,
liberatoriaService: () => liberatoriaServiceStub,
},
};
});
describe('Mount', () => {
it('Should call load all on init', async () => {
// GIVEN
liberatoriaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
const wrapper = shallowMount(Liberatoria, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(liberatoriaServiceStub.retrieve.calledOnce).toBeTruthy();
expect(comp.liberatorias[0]).toEqual(expect.objectContaining({ id: 123 }));
});
});
describe('Handles', () => {
let comp: LiberatoriaComponentType;
beforeEach(async () => {
const wrapper = shallowMount(Liberatoria, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
liberatoriaServiceStub.retrieve.reset();
liberatoriaServiceStub.retrieve.resolves({ headers: {}, data: [] });
});
it('Should call delete service on confirmDelete', async () => {
// GIVEN
liberatoriaServiceStub.delete.resolves({});
// WHEN
comp.prepareRemove({ id: 123 });
comp.removeLiberatoria();
await comp.$nextTick(); // clear components
// THEN
expect(liberatoriaServiceStub.delete.called).toBeTruthy();
// THEN
await comp.$nextTick(); // handle component clear watch
expect(liberatoriaServiceStub.retrieve.callCount).toEqual(1);
});
});
});
});

View File

@@ -0,0 +1,81 @@
import { type Ref, defineComponent, inject, onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type ILiberatoria } from '@/shared/model/liberatoria.model';
import LiberatoriaService from './liberatoria.service';
export default defineComponent({
name: 'Liberatoria',
setup() {
const { t: t$ } = useI18n();
const dateFormat = useDateFormat();
const liberatoriaService = inject('liberatoriaService', () => new LiberatoriaService());
const alertService = inject('alertService', () => useAlertService(), true);
const liberatorias: Ref<ILiberatoria[]> = ref([]);
const isFetching = ref(false);
const clear = () => {};
const retrieveLiberatorias = async () => {
isFetching.value = true;
try {
const res = await liberatoriaService().retrieve();
liberatorias.value = res.data;
} catch (err) {
alertService.showHttpError(err.response);
} finally {
isFetching.value = false;
}
};
const handleSyncList = () => {
retrieveLiberatorias();
};
onMounted(async () => {
await retrieveLiberatorias();
});
const removeId: Ref<number> = ref(null);
const removeEntity = ref<any>(null);
const prepareRemove = (instance: ILiberatoria) => {
removeId.value = instance.id;
removeEntity.value.show();
};
const closeDialog = () => {
removeEntity.value.hide();
};
const removeLiberatoria = async () => {
try {
await liberatoriaService().delete(removeId.value);
const message = t$('smartbookingApp.liberatoria.deleted', { param: removeId.value }).toString();
alertService.showInfo(message, { variant: 'danger' });
removeId.value = null;
retrieveLiberatorias();
closeDialog();
} catch (error) {
alertService.showHttpError(error.response);
}
};
return {
liberatorias,
handleSyncList,
isFetching,
retrieveLiberatorias,
clear,
...dateFormat,
removeId,
removeEntity,
prepareRemove,
closeDialog,
removeLiberatoria,
t$,
};
},
});

View File

@@ -0,0 +1,164 @@
import axios from 'axios';
import dayjs from 'dayjs';
import sinon from 'sinon';
import { DATE_TIME_FORMAT } from '@/shared/composables/date-format';
import { Liberatoria } from '@/shared/model/liberatoria.model';
import LiberatoriaService from './liberatoria.service';
const error = {
response: {
status: null,
data: {
type: null,
},
},
};
const axiosStub = {
get: sinon.stub(axios, 'get'),
post: sinon.stub(axios, 'post'),
put: sinon.stub(axios, 'put'),
patch: sinon.stub(axios, 'patch'),
delete: sinon.stub(axios, 'delete'),
};
describe('Service Tests', () => {
describe('Liberatoria Service', () => {
let service: LiberatoriaService;
let elemDefault;
let currentDate: Date;
beforeEach(() => {
service = new LiberatoriaService();
currentDate = new Date();
elemDefault = new Liberatoria(123, currentDate);
});
describe('Service methods', () => {
it('should find an element', async () => {
const returnedFromService = { accettata: dayjs(currentDate).format(DATE_TIME_FORMAT), ...elemDefault };
axiosStub.get.resolves({ data: returnedFromService });
return service.find(123).then(res => {
expect(res).toMatchObject(elemDefault);
});
});
it('should not find an element', async () => {
axiosStub.get.rejects(error);
return service
.find(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should create a Liberatoria', async () => {
const returnedFromService = { id: 123, accettata: dayjs(currentDate).format(DATE_TIME_FORMAT), ...elemDefault };
const expected = { accettata: currentDate, ...returnedFromService };
axiosStub.post.resolves({ data: returnedFromService });
return service.create({}).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not create a Liberatoria', async () => {
axiosStub.post.rejects(error);
return service
.create({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should update a Liberatoria', async () => {
const returnedFromService = { accettata: dayjs(currentDate).format(DATE_TIME_FORMAT), ...elemDefault };
const expected = { accettata: currentDate, ...returnedFromService };
axiosStub.put.resolves({ data: returnedFromService });
return service.update(expected).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not update a Liberatoria', async () => {
axiosStub.put.rejects(error);
return service
.update({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should partial update a Liberatoria', async () => {
const patchObject = { accettata: dayjs(currentDate).format(DATE_TIME_FORMAT), ...new Liberatoria() };
const returnedFromService = Object.assign(patchObject, elemDefault);
const expected = { accettata: currentDate, ...returnedFromService };
axiosStub.patch.resolves({ data: returnedFromService });
return service.partialUpdate(patchObject).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not partial update a Liberatoria', async () => {
axiosStub.patch.rejects(error);
return service
.partialUpdate({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should return a list of Liberatoria', async () => {
const returnedFromService = { accettata: dayjs(currentDate).format(DATE_TIME_FORMAT), ...elemDefault };
const expected = { accettata: currentDate, ...returnedFromService };
axiosStub.get.resolves([returnedFromService]);
return service.retrieve().then(res => {
expect(res).toContainEqual(expected);
});
});
it('should not return a list of Liberatoria', async () => {
axiosStub.get.rejects(error);
return service
.retrieve()
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should delete a Liberatoria', async () => {
axiosStub.delete.resolves({ ok: true });
return service.delete(123).then(res => {
expect(res.ok).toBeTruthy();
});
});
it('should not delete a Liberatoria', async () => {
axiosStub.delete.rejects(error);
return service
.delete(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
});
});
});

View File

@@ -0,0 +1,85 @@
import axios from 'axios';
import { type ILiberatoria } from '@/shared/model/liberatoria.model';
const baseApiUrl = 'api/liberatorias';
export default class LiberatoriaService {
find(id: number): Promise<ILiberatoria> {
return new Promise<ILiberatoria>((resolve, reject) => {
axios
.get(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
retrieve(): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.get(baseApiUrl)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
delete(id: number): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.delete(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
create(entity: ILiberatoria): Promise<ILiberatoria> {
return new Promise<ILiberatoria>((resolve, reject) => {
axios
.post(baseApiUrl, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
update(entity: ILiberatoria): Promise<ILiberatoria> {
return new Promise<ILiberatoria>((resolve, reject) => {
axios
.put(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
partialUpdate(entity: ILiberatoria): Promise<ILiberatoria> {
return new Promise<ILiberatoria>((resolve, reject) => {
axios
.patch(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
}

View File

@@ -0,0 +1,128 @@
<template>
<div>
<h2 id="page-heading" data-cy="LiberatoriaHeading">
<span id="liberatoria">{{ t$('smartbookingApp.liberatoria.home.title') }}</span>
<div class="d-flex justify-content-end">
<button class="btn btn-info me-2" @click="handleSyncList" :disabled="isFetching">
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
<span>{{ t$('smartbookingApp.liberatoria.home.refreshListLabel') }}</span>
</button>
<router-link :to="{ name: 'LiberatoriaCreate' }" custom v-slot="{ navigate }">
<button
@click="navigate"
id="jh-create-entity"
data-cy="entityCreateButton"
class="btn btn-primary jh-create-entity create-liberatoria"
>
<font-awesome-icon icon="plus"></font-awesome-icon>
<span>{{ t$('smartbookingApp.liberatoria.home.createLabel') }}</span>
</button>
</router-link>
</div>
</h2>
<br />
<div class="alert alert-warning" v-if="!isFetching && liberatorias?.length === 0">
<span>{{ t$('smartbookingApp.liberatoria.home.notFound') }}</span>
</div>
<div class="table-responsive" v-if="liberatorias?.length > 0">
<table class="table table-striped" aria-describedby="liberatorias">
<thead>
<tr>
<th scope="col">
<span>{{ t$('global.field.id') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.liberatoria.accettata') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.liberatoria.utente') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.liberatoria.modelloLiberatoria') }}</span>
</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="liberatoria in liberatorias" :key="liberatoria.id" data-cy="entityTable">
<td>
<router-link :to="{ name: 'LiberatoriaView', params: { liberatoriaId: liberatoria.id } }">{{ liberatoria.id }}</router-link>
</td>
<td>{{ formatDateShort(liberatoria.accettata) || '' }}</td>
<td>
<div v-if="liberatoria.utente">
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: liberatoria.utente.id } }">{{
liberatoria.utente.username
}}</router-link>
</div>
</td>
<td>
<div v-if="liberatoria.modelloLiberatoria">
<router-link
:to="{ name: 'ModelloLiberatoriaView', params: { modelloLiberatoriaId: liberatoria.modelloLiberatoria.id } }"
>{{ liberatoria.modelloLiberatoria.id }}</router-link
>
</div>
</td>
<td class="text-end">
<div class="btn-group">
<router-link
:to="{ name: 'LiberatoriaView', params: { liberatoriaId: liberatoria.id } }"
class="btn btn-info btn-sm details"
data-cy="entityDetailsButton"
>
<font-awesome-icon icon="eye"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
</router-link>
<router-link
:to="{ name: 'LiberatoriaEdit', params: { liberatoriaId: liberatoria.id } }"
class="btn btn-primary btn-sm edit"
data-cy="entityEditButton"
>
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.edit') }}</span>
</router-link>
<b-button
@click="prepareRemove(liberatoria)"
variant="danger"
class="btn btn-sm"
data-cy="entityDeleteButton"
v-b-modal.removeEntity
>
<font-awesome-icon icon="times"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
</b-button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<b-modal ref="removeEntity" id="removeEntity">
<template #title>
<span id="smartbookingApp.liberatoria.delete.question" data-cy="liberatoriaDeleteDialogHeading">{{
t$('entity.delete.title')
}}</span>
</template>
<div class="modal-body">
<p id="jhi-delete-liberatoria-heading">{{ t$('smartbookingApp.liberatoria.delete.question', { id: removeId }) }}</p>
</div>
<template #footer>
<div>
<button type="button" class="btn btn-secondary" @click="closeDialog()">{{ t$('entity.action.cancel') }}</button>
<button
type="button"
class="btn btn-primary"
id="jhi-confirm-delete-liberatoria"
data-cy="entityConfirmDeleteButton"
@click="removeLiberatoria"
>
{{ t$('entity.action.delete') }}
</button>
</div>
</template>
</b-modal>
</div>
</template>
<script lang="ts" src="./liberatoria.component.ts"></script>

View File

@@ -0,0 +1,91 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import MessaggioDetails from './messaggio-details.vue';
import MessaggioService from './messaggio.service';
type MessaggioDetailsComponentType = InstanceType<typeof MessaggioDetails>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const messaggioSample = { id: 123 };
describe('Component Tests', () => {
let alertService: AlertService;
afterEach(() => {
vitest.resetAllMocks();
});
describe('Messaggio Management Detail Component', () => {
let messaggioServiceStub: SinonStubbedInstance<MessaggioService>;
let mountOptions: MountingOptions<MessaggioDetailsComponentType>['global'];
beforeEach(() => {
route = {};
messaggioServiceStub = sinon.createStubInstance<MessaggioService>(MessaggioService);
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'router-link': true,
},
provide: {
alertService,
messaggioService: () => messaggioServiceStub,
},
};
});
describe('Navigate to details', () => {
it('Should call load all on init', async () => {
// GIVEN
messaggioServiceStub.find.resolves(messaggioSample);
route = {
params: {
messaggioId: `${123}`,
},
};
const wrapper = shallowMount(MessaggioDetails, { global: mountOptions });
const comp = wrapper.vm;
// WHEN
await comp.$nextTick();
// THEN
expect(comp.messaggio).toMatchObject(messaggioSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
messaggioServiceStub.find.resolves(messaggioSample);
const wrapper = shallowMount(MessaggioDetails, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,46 @@
import { type Ref, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type IMessaggio } from '@/shared/model/messaggio.model';
import MessaggioService from './messaggio.service';
export default defineComponent({
name: 'MessaggioDetails',
setup() {
const dateFormat = useDateFormat();
const messaggioService = inject('messaggioService', () => new MessaggioService());
const alertService = inject('alertService', () => useAlertService(), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const messaggio: Ref<IMessaggio> = ref({});
const retrieveMessaggio = async messaggioId => {
try {
const res = await messaggioService().find(messaggioId);
messaggio.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.messaggioId) {
retrieveMessaggio(route.params.messaggioId);
}
return {
...dateFormat,
alertService,
messaggio,
previousState,
t$: useI18n().t,
};
},
});

View File

@@ -0,0 +1,56 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<div v-if="messaggio">
<h2 class="jh-entity-heading" data-cy="messaggioDetailsHeading">
<span>{{ t$('smartbookingApp.messaggio.detail.title') }}Messaggio</span> {{ messaggio.id }}
</h2>
<dl class="row-md jh-entity-details">
<dt>
<span>{{ t$('smartbookingApp.messaggio.spedito') }}</span>
</dt>
<dd>
<span v-if="messaggio.spedito">{{ formatDateLong(messaggio.spedito) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.messaggio.testo') }}</span>
</dt>
<dd>
<span>{{ messaggio.testo }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.messaggio.letto') }}</span>
</dt>
<dd>
<span v-if="messaggio.letto">{{ formatDateLong(messaggio.letto) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.messaggio.utente') }}</span>
</dt>
<dd>
<div v-if="messaggio.utente">
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: messaggio.utente.id } }">{{
messaggio.utente.username
}}</router-link>
</div>
</dd>
</dl>
<button type="submit" @click.prevent="previousState()" class="btn btn-info" data-cy="entityDetailsBackButton">
<font-awesome-icon icon="arrow-left"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.back') }}</span>
</button>
<router-link
v-if="messaggio.id"
:to="{ name: 'MessaggioEdit', params: { messaggioId: messaggio.id } }"
custom
v-slot="{ navigate }"
>
<button @click="navigate" class="btn btn-primary">
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.edit') }}</span>
</button>
</router-link>
</div>
</div>
</div>
</template>
<script lang="ts" src="./messaggio-details.component.ts"></script>

View File

@@ -0,0 +1,161 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import dayjs from 'dayjs';
import sinon, { type SinonStubbedInstance } from 'sinon';
import UtenteAppService from '@/entities/utente-app/utente-app.service';
import AlertService from '@/shared/alert/alert.service';
import { DATE_TIME_LONG_FORMAT } from '@/shared/composables/date-format';
import MessaggioUpdate from './messaggio-update.vue';
import MessaggioService from './messaggio.service';
type MessaggioUpdateComponentType = InstanceType<typeof MessaggioUpdate>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const messaggioSample = { id: 123 };
describe('Component Tests', () => {
let mountOptions: MountingOptions<MessaggioUpdateComponentType>['global'];
let alertService: AlertService;
describe('Messaggio Management Update Component', () => {
let comp: MessaggioUpdateComponentType;
let messaggioServiceStub: SinonStubbedInstance<MessaggioService>;
beforeEach(() => {
route = {};
messaggioServiceStub = sinon.createStubInstance<MessaggioService>(MessaggioService);
messaggioServiceStub.retrieve.onFirstCall().resolves(Promise.resolve([]));
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'b-input-group': true,
'b-input-group-prepend': true,
'b-form-datepicker': true,
'b-form-input': true,
},
provide: {
alertService,
messaggioService: () => messaggioServiceStub,
utenteAppService: () =>
sinon.createStubInstance<UtenteAppService>(UtenteAppService, {
retrieve: sinon.stub().resolves({}),
} as any),
},
};
});
afterEach(() => {
vitest.resetAllMocks();
});
describe('load', () => {
beforeEach(() => {
const wrapper = shallowMount(MessaggioUpdate, { global: mountOptions });
comp = wrapper.vm;
});
it('Should convert date from string', () => {
// GIVEN
const date = new Date('2019-10-15T11:42:02Z');
// WHEN
const convertedDate = comp.convertDateTimeFromServer(date);
// THEN
expect(convertedDate).toEqual(dayjs(date).format(DATE_TIME_LONG_FORMAT));
});
it('Should not convert date if date is not present', () => {
expect(comp.convertDateTimeFromServer(null)).toBeNull();
});
});
describe('save', () => {
it('Should call update service on save for existing entity', async () => {
// GIVEN
const wrapper = shallowMount(MessaggioUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.messaggio = messaggioSample;
messaggioServiceStub.update.resolves(messaggioSample);
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(messaggioServiceStub.update.calledWith(messaggioSample)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
it('Should call create service on save for new entity', async () => {
// GIVEN
const entity = {};
messaggioServiceStub.create.resolves(entity);
const wrapper = shallowMount(MessaggioUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.messaggio = entity;
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(messaggioServiceStub.create.calledWith(entity)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
});
describe('Before route enter', () => {
it('Should retrieve data', async () => {
// GIVEN
messaggioServiceStub.find.resolves(messaggioSample);
messaggioServiceStub.retrieve.resolves([messaggioSample]);
// WHEN
route = {
params: {
messaggioId: `${messaggioSample.id}`,
},
};
const wrapper = shallowMount(MessaggioUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(comp.messaggio).toMatchObject(messaggioSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
messaggioServiceStub.find.resolves(messaggioSample);
const wrapper = shallowMount(MessaggioUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,114 @@
import { type Ref, computed, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useVuelidate } from '@vuelidate/core';
import UtenteAppService from '@/entities/utente-app/utente-app.service';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat, useValidation } from '@/shared/composables';
import { type IMessaggio, Messaggio } from '@/shared/model/messaggio.model';
import { type IUtenteApp } from '@/shared/model/utente-app.model';
import MessaggioService from './messaggio.service';
export default defineComponent({
name: 'MessaggioUpdate',
setup() {
const messaggioService = inject('messaggioService', () => new MessaggioService());
const alertService = inject('alertService', () => useAlertService(), true);
const messaggio: Ref<IMessaggio> = ref(new Messaggio());
const utenteAppService = inject('utenteAppService', () => new UtenteAppService());
const utenteApps: Ref<IUtenteApp[]> = ref([]);
const isSaving = ref(false);
const currentLanguage = inject('currentLanguage', () => computed(() => navigator.language ?? 'it'), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const retrieveMessaggio = async messaggioId => {
try {
const res = await messaggioService().find(messaggioId);
res.spedito = new Date(res.spedito);
res.letto = new Date(res.letto);
messaggio.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.messaggioId) {
retrieveMessaggio(route.params.messaggioId);
}
const initRelationships = () => {
utenteAppService()
.retrieve()
.then(res => {
utenteApps.value = res.data;
});
};
initRelationships();
const { t: t$ } = useI18n();
const validations = useValidation();
const validationRules = {
spedito: {},
testo: {},
letto: {},
utente: {},
};
const v$ = useVuelidate(validationRules, messaggio as any);
v$.value.$validate();
return {
messaggioService,
alertService,
messaggio,
previousState,
isSaving,
currentLanguage,
utenteApps,
v$,
...useDateFormat({ entityRef: messaggio }),
t$,
};
},
created(): void {},
methods: {
save(): void {
this.isSaving = true;
if (this.messaggio.id) {
this.messaggioService()
.update(this.messaggio)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showInfo(this.t$('smartbookingApp.messaggio.updated', { param: param.id }));
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
} else {
this.messaggioService()
.create(this.messaggio)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showSuccess(this.t$('smartbookingApp.messaggio.created', { param: param.id }).toString());
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
}
},
},
});

View File

@@ -0,0 +1,87 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<form name="editForm" novalidate @submit.prevent="save()">
<h2 id="smartbookingApp.messaggio.home.createOrEditLabel" data-cy="MessaggioCreateUpdateHeading">
{{ t$('smartbookingApp.messaggio.home.createOrEditLabel') }}
</h2>
<div>
<div class="mb-3" v-if="messaggio.id">
<label for="id">{{ t$('global.field.id') }}</label>
<input type="text" class="form-control" id="id" name="id" v-model="messaggio.id" readonly />
</div>
<div class="mb-3">
<label class="form-control-label" for="messaggio">{{ t$('smartbookingApp.messaggio.spedito') }}</label>
<div class="d-flex">
<input
id="messaggio-spedito"
data-cy="spedito"
type="datetime-local"
class="form-control"
name="spedito"
:class="{ valid: !v$.spedito.$invalid, invalid: v$.spedito.$invalid }"
:value="convertDateTimeFromServer(v$.spedito.$model)"
@change="updateInstantField('spedito', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="messaggio">{{ t$('smartbookingApp.messaggio.testo') }}</label>
<input
type="text"
class="form-control"
name="testo"
id="messaggio-testo"
data-cy="testo"
:class="{ valid: !v$.testo.$invalid, invalid: v$.testo.$invalid }"
v-model="v$.testo.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="messaggio">{{ t$('smartbookingApp.messaggio.letto') }}</label>
<div class="d-flex">
<input
id="messaggio-letto"
data-cy="letto"
type="datetime-local"
class="form-control"
name="letto"
:class="{ valid: !v$.letto.$invalid, invalid: v$.letto.$invalid }"
:value="convertDateTimeFromServer(v$.letto.$model)"
@change="updateInstantField('letto', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="messaggio">{{ t$('smartbookingApp.messaggio.utente') }}</label>
<select class="form-control" id="messaggio-utente" data-cy="utente" name="utente" v-model="messaggio.utente">
<option :value="null"></option>
<option
:value="messaggio.utente && utenteAppOption.id === messaggio.utente.id ? messaggio.utente : utenteAppOption"
v-for="utenteAppOption in utenteApps"
:key="utenteAppOption.id"
>
{{ utenteAppOption.username }}
</option>
</select>
</div>
</div>
<div>
<button type="button" id="cancel-save" data-cy="entityCreateCancelButton" class="btn btn-secondary" @click="previousState()">
<font-awesome-icon icon="ban"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.cancel') }}</span>
</button>
<button
type="submit"
id="save-entity"
data-cy="entityCreateSaveButton"
:disabled="v$.$invalid || isSaving"
class="btn btn-primary"
>
<font-awesome-icon icon="save"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.save') }}</span>
</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts" src="./messaggio-update.component.ts"></script>

View File

@@ -0,0 +1,102 @@
import { vitest } from 'vitest';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import MessaggioService from './messaggio.service';
import Messaggio from './messaggio.vue';
type MessaggioComponentType = InstanceType<typeof Messaggio>;
const bModalStub = {
render: () => {},
methods: {
hide: () => {},
show: () => {},
},
};
describe('Component Tests', () => {
let alertService: AlertService;
describe('Messaggio Management Component', () => {
let messaggioServiceStub: SinonStubbedInstance<MessaggioService>;
let mountOptions: MountingOptions<MessaggioComponentType>['global'];
beforeEach(() => {
messaggioServiceStub = sinon.createStubInstance<MessaggioService>(MessaggioService);
messaggioServiceStub.retrieve.resolves({ headers: {} });
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
bModal: bModalStub as any,
'font-awesome-icon': true,
'b-badge': true,
'b-button': true,
'router-link': true,
},
directives: {
'b-modal': {},
},
provide: {
alertService,
messaggioService: () => messaggioServiceStub,
},
};
});
describe('Mount', () => {
it('Should call load all on init', async () => {
// GIVEN
messaggioServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
const wrapper = shallowMount(Messaggio, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(messaggioServiceStub.retrieve.calledOnce).toBeTruthy();
expect(comp.messaggios[0]).toEqual(expect.objectContaining({ id: 123 }));
});
});
describe('Handles', () => {
let comp: MessaggioComponentType;
beforeEach(async () => {
const wrapper = shallowMount(Messaggio, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
messaggioServiceStub.retrieve.reset();
messaggioServiceStub.retrieve.resolves({ headers: {}, data: [] });
});
it('Should call delete service on confirmDelete', async () => {
// GIVEN
messaggioServiceStub.delete.resolves({});
// WHEN
comp.prepareRemove({ id: 123 });
comp.removeMessaggio();
await comp.$nextTick(); // clear components
// THEN
expect(messaggioServiceStub.delete.called).toBeTruthy();
// THEN
await comp.$nextTick(); // handle component clear watch
expect(messaggioServiceStub.retrieve.callCount).toEqual(1);
});
});
});
});

View File

@@ -0,0 +1,81 @@
import { type Ref, defineComponent, inject, onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type IMessaggio } from '@/shared/model/messaggio.model';
import MessaggioService from './messaggio.service';
export default defineComponent({
name: 'Messaggio',
setup() {
const { t: t$ } = useI18n();
const dateFormat = useDateFormat();
const messaggioService = inject('messaggioService', () => new MessaggioService());
const alertService = inject('alertService', () => useAlertService(), true);
const messaggios: Ref<IMessaggio[]> = ref([]);
const isFetching = ref(false);
const clear = () => {};
const retrieveMessaggios = async () => {
isFetching.value = true;
try {
const res = await messaggioService().retrieve();
messaggios.value = res.data;
} catch (err) {
alertService.showHttpError(err.response);
} finally {
isFetching.value = false;
}
};
const handleSyncList = () => {
retrieveMessaggios();
};
onMounted(async () => {
await retrieveMessaggios();
});
const removeId: Ref<number> = ref(null);
const removeEntity = ref<any>(null);
const prepareRemove = (instance: IMessaggio) => {
removeId.value = instance.id;
removeEntity.value.show();
};
const closeDialog = () => {
removeEntity.value.hide();
};
const removeMessaggio = async () => {
try {
await messaggioService().delete(removeId.value);
const message = t$('smartbookingApp.messaggio.deleted', { param: removeId.value }).toString();
alertService.showInfo(message, { variant: 'danger' });
removeId.value = null;
retrieveMessaggios();
closeDialog();
} catch (error) {
alertService.showHttpError(error.response);
}
};
return {
messaggios,
handleSyncList,
isFetching,
retrieveMessaggios,
clear,
...dateFormat,
removeId,
removeEntity,
prepareRemove,
closeDialog,
removeMessaggio,
t$,
};
},
});

View File

@@ -0,0 +1,183 @@
import axios from 'axios';
import dayjs from 'dayjs';
import sinon from 'sinon';
import { DATE_TIME_FORMAT } from '@/shared/composables/date-format';
import { Messaggio } from '@/shared/model/messaggio.model';
import MessaggioService from './messaggio.service';
const error = {
response: {
status: null,
data: {
type: null,
},
},
};
const axiosStub = {
get: sinon.stub(axios, 'get'),
post: sinon.stub(axios, 'post'),
put: sinon.stub(axios, 'put'),
patch: sinon.stub(axios, 'patch'),
delete: sinon.stub(axios, 'delete'),
};
describe('Service Tests', () => {
describe('Messaggio Service', () => {
let service: MessaggioService;
let elemDefault;
let currentDate: Date;
beforeEach(() => {
service = new MessaggioService();
currentDate = new Date();
elemDefault = new Messaggio(123, currentDate, 'AAAAAAA', currentDate);
});
describe('Service methods', () => {
it('should find an element', async () => {
const returnedFromService = {
spedito: dayjs(currentDate).format(DATE_TIME_FORMAT),
letto: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
axiosStub.get.resolves({ data: returnedFromService });
return service.find(123).then(res => {
expect(res).toMatchObject(elemDefault);
});
});
it('should not find an element', async () => {
axiosStub.get.rejects(error);
return service
.find(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should create a Messaggio', async () => {
const returnedFromService = {
id: 123,
spedito: dayjs(currentDate).format(DATE_TIME_FORMAT),
letto: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { spedito: currentDate, letto: currentDate, ...returnedFromService };
axiosStub.post.resolves({ data: returnedFromService });
return service.create({}).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not create a Messaggio', async () => {
axiosStub.post.rejects(error);
return service
.create({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should update a Messaggio', async () => {
const returnedFromService = {
spedito: dayjs(currentDate).format(DATE_TIME_FORMAT),
testo: 'BBBBBB',
letto: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { spedito: currentDate, letto: currentDate, ...returnedFromService };
axiosStub.put.resolves({ data: returnedFromService });
return service.update(expected).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not update a Messaggio', async () => {
axiosStub.put.rejects(error);
return service
.update({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should partial update a Messaggio', async () => {
const patchObject = { spedito: dayjs(currentDate).format(DATE_TIME_FORMAT), ...new Messaggio() };
const returnedFromService = Object.assign(patchObject, elemDefault);
const expected = { spedito: currentDate, letto: currentDate, ...returnedFromService };
axiosStub.patch.resolves({ data: returnedFromService });
return service.partialUpdate(patchObject).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not partial update a Messaggio', async () => {
axiosStub.patch.rejects(error);
return service
.partialUpdate({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should return a list of Messaggio', async () => {
const returnedFromService = {
spedito: dayjs(currentDate).format(DATE_TIME_FORMAT),
testo: 'BBBBBB',
letto: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { spedito: currentDate, letto: currentDate, ...returnedFromService };
axiosStub.get.resolves([returnedFromService]);
return service.retrieve().then(res => {
expect(res).toContainEqual(expected);
});
});
it('should not return a list of Messaggio', async () => {
axiosStub.get.rejects(error);
return service
.retrieve()
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should delete a Messaggio', async () => {
axiosStub.delete.resolves({ ok: true });
return service.delete(123).then(res => {
expect(res.ok).toBeTruthy();
});
});
it('should not delete a Messaggio', async () => {
axiosStub.delete.rejects(error);
return service
.delete(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
});
});
});

View File

@@ -0,0 +1,85 @@
import axios from 'axios';
import { type IMessaggio } from '@/shared/model/messaggio.model';
const baseApiUrl = 'api/messaggios';
export default class MessaggioService {
find(id: number): Promise<IMessaggio> {
return new Promise<IMessaggio>((resolve, reject) => {
axios
.get(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
retrieve(): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.get(baseApiUrl)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
delete(id: number): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.delete(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
create(entity: IMessaggio): Promise<IMessaggio> {
return new Promise<IMessaggio>((resolve, reject) => {
axios
.post(baseApiUrl, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
update(entity: IMessaggio): Promise<IMessaggio> {
return new Promise<IMessaggio>((resolve, reject) => {
axios
.put(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
partialUpdate(entity: IMessaggio): Promise<IMessaggio> {
return new Promise<IMessaggio>((resolve, reject) => {
axios
.patch(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
}

View File

@@ -0,0 +1,123 @@
<template>
<div>
<h2 id="page-heading" data-cy="MessaggioHeading">
<span id="messaggio">{{ t$('smartbookingApp.messaggio.home.title') }}</span>
<div class="d-flex justify-content-end">
<button class="btn btn-info me-2" @click="handleSyncList" :disabled="isFetching">
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
<span>{{ t$('smartbookingApp.messaggio.home.refreshListLabel') }}</span>
</button>
<router-link :to="{ name: 'MessaggioCreate' }" custom v-slot="{ navigate }">
<button
@click="navigate"
id="jh-create-entity"
data-cy="entityCreateButton"
class="btn btn-primary jh-create-entity create-messaggio"
>
<font-awesome-icon icon="plus"></font-awesome-icon>
<span>{{ t$('smartbookingApp.messaggio.home.createLabel') }}</span>
</button>
</router-link>
</div>
</h2>
<br />
<div class="alert alert-warning" v-if="!isFetching && messaggios?.length === 0">
<span>{{ t$('smartbookingApp.messaggio.home.notFound') }}</span>
</div>
<div class="table-responsive" v-if="messaggios?.length > 0">
<table class="table table-striped" aria-describedby="messaggios">
<thead>
<tr>
<th scope="col">
<span>{{ t$('global.field.id') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.messaggio.spedito') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.messaggio.testo') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.messaggio.letto') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.messaggio.utente') }}</span>
</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="messaggio in messaggios" :key="messaggio.id" data-cy="entityTable">
<td>
<router-link :to="{ name: 'MessaggioView', params: { messaggioId: messaggio.id } }">{{ messaggio.id }}</router-link>
</td>
<td>{{ formatDateShort(messaggio.spedito) || '' }}</td>
<td>{{ messaggio.testo }}</td>
<td>{{ formatDateShort(messaggio.letto) || '' }}</td>
<td>
<div v-if="messaggio.utente">
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: messaggio.utente.id } }">{{
messaggio.utente.username
}}</router-link>
</div>
</td>
<td class="text-end">
<div class="btn-group">
<router-link
:to="{ name: 'MessaggioView', params: { messaggioId: messaggio.id } }"
class="btn btn-info btn-sm details"
data-cy="entityDetailsButton"
>
<font-awesome-icon icon="eye"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
</router-link>
<router-link
:to="{ name: 'MessaggioEdit', params: { messaggioId: messaggio.id } }"
class="btn btn-primary btn-sm edit"
data-cy="entityEditButton"
>
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.edit') }}</span>
</router-link>
<b-button
@click="prepareRemove(messaggio)"
variant="danger"
class="btn btn-sm"
data-cy="entityDeleteButton"
v-b-modal.removeEntity
>
<font-awesome-icon icon="times"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
</b-button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<b-modal ref="removeEntity" id="removeEntity">
<template #title>
<span id="smartbookingApp.messaggio.delete.question" data-cy="messaggioDeleteDialogHeading">{{ t$('entity.delete.title') }}</span>
</template>
<div class="modal-body">
<p id="jhi-delete-messaggio-heading">{{ t$('smartbookingApp.messaggio.delete.question', { id: removeId }) }}</p>
</div>
<template #footer>
<div>
<button type="button" class="btn btn-secondary" @click="closeDialog()">{{ t$('entity.action.cancel') }}</button>
<button
type="button"
class="btn btn-primary"
id="jhi-confirm-delete-messaggio"
data-cy="entityConfirmDeleteButton"
@click="removeMessaggio"
>
{{ t$('entity.action.delete') }}
</button>
</div>
</template>
</b-modal>
</div>
</template>
<script lang="ts" src="./messaggio.component.ts"></script>

View File

@@ -0,0 +1,91 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import ModelloLiberatoriaDetails from './modello-liberatoria-details.vue';
import ModelloLiberatoriaService from './modello-liberatoria.service';
type ModelloLiberatoriaDetailsComponentType = InstanceType<typeof ModelloLiberatoriaDetails>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const modelloLiberatoriaSample = { id: 123 };
describe('Component Tests', () => {
let alertService: AlertService;
afterEach(() => {
vitest.resetAllMocks();
});
describe('ModelloLiberatoria Management Detail Component', () => {
let modelloLiberatoriaServiceStub: SinonStubbedInstance<ModelloLiberatoriaService>;
let mountOptions: MountingOptions<ModelloLiberatoriaDetailsComponentType>['global'];
beforeEach(() => {
route = {};
modelloLiberatoriaServiceStub = sinon.createStubInstance<ModelloLiberatoriaService>(ModelloLiberatoriaService);
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'router-link': true,
},
provide: {
alertService,
modelloLiberatoriaService: () => modelloLiberatoriaServiceStub,
},
};
});
describe('Navigate to details', () => {
it('Should call load all on init', async () => {
// GIVEN
modelloLiberatoriaServiceStub.find.resolves(modelloLiberatoriaSample);
route = {
params: {
modelloLiberatoriaId: `${123}`,
},
};
const wrapper = shallowMount(ModelloLiberatoriaDetails, { global: mountOptions });
const comp = wrapper.vm;
// WHEN
await comp.$nextTick();
// THEN
expect(comp.modelloLiberatoria).toMatchObject(modelloLiberatoriaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
modelloLiberatoriaServiceStub.find.resolves(modelloLiberatoriaSample);
const wrapper = shallowMount(ModelloLiberatoriaDetails, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,51 @@
import { type Ref, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import useDataUtils from '@/shared/data/data-utils.service';
import { type IModelloLiberatoria } from '@/shared/model/modello-liberatoria.model';
import ModelloLiberatoriaService from './modello-liberatoria.service';
export default defineComponent({
name: 'ModelloLiberatoriaDetails',
setup() {
const dateFormat = useDateFormat();
const modelloLiberatoriaService = inject('modelloLiberatoriaService', () => new ModelloLiberatoriaService());
const alertService = inject('alertService', () => useAlertService(), true);
const dataUtils = useDataUtils();
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const modelloLiberatoria: Ref<IModelloLiberatoria> = ref({});
const retrieveModelloLiberatoria = async modelloLiberatoriaId => {
try {
const res = await modelloLiberatoriaService().find(modelloLiberatoriaId);
modelloLiberatoria.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.modelloLiberatoriaId) {
retrieveModelloLiberatoria(route.params.modelloLiberatoriaId);
}
return {
...dateFormat,
alertService,
modelloLiberatoria,
...dataUtils,
previousState,
t$: useI18n().t,
};
},
});

View File

@@ -0,0 +1,68 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<div v-if="modelloLiberatoria">
<h2 class="jh-entity-heading" data-cy="modelloLiberatoriaDetailsHeading">
<span>{{ t$('smartbookingApp.modelloLiberatoria.detail.title') }}ModelloLiberatoria</span> {{ modelloLiberatoria.id }}
</h2>
<dl class="row-md jh-entity-details">
<dt>
<span>{{ t$('smartbookingApp.modelloLiberatoria.nome') }}</span>
</dt>
<dd>
<span>{{ modelloLiberatoria.nome }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.modelloLiberatoria.testo') }}</span>
</dt>
<dd>
<span>{{ modelloLiberatoria.testo }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.modelloLiberatoria.documento') }}</span>
</dt>
<dd>
<span>{{ modelloLiberatoria.documento }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.modelloLiberatoria.validoDal') }}</span>
</dt>
<dd>
<span v-if="modelloLiberatoria.validoDal">{{ formatDateLong(modelloLiberatoria.validoDal) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.modelloLiberatoria.validoAl') }}</span>
</dt>
<dd>
<span v-if="modelloLiberatoria.validoAl">{{ formatDateLong(modelloLiberatoria.validoAl) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.modelloLiberatoria.struttura') }}</span>
</dt>
<dd>
<div v-if="modelloLiberatoria.struttura">
<router-link :to="{ name: 'StrutturaView', params: { strutturaId: modelloLiberatoria.struttura.id } }">{{
modelloLiberatoria.struttura.id
}}</router-link>
</div>
</dd>
</dl>
<button type="submit" @click.prevent="previousState()" class="btn btn-info" data-cy="entityDetailsBackButton">
<font-awesome-icon icon="arrow-left"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.back') }}</span>
</button>
<router-link
v-if="modelloLiberatoria.id"
:to="{ name: 'ModelloLiberatoriaEdit', params: { modelloLiberatoriaId: modelloLiberatoria.id } }"
custom
v-slot="{ navigate }"
>
<button @click="navigate" class="btn btn-primary">
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.edit') }}</span>
</button>
</router-link>
</div>
</div>
</div>
</template>
<script lang="ts" src="./modello-liberatoria-details.component.ts"></script>

View File

@@ -0,0 +1,161 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import dayjs from 'dayjs';
import sinon, { type SinonStubbedInstance } from 'sinon';
import StrutturaService from '@/entities/struttura/struttura.service';
import AlertService from '@/shared/alert/alert.service';
import { DATE_TIME_LONG_FORMAT } from '@/shared/composables/date-format';
import ModelloLiberatoriaUpdate from './modello-liberatoria-update.vue';
import ModelloLiberatoriaService from './modello-liberatoria.service';
type ModelloLiberatoriaUpdateComponentType = InstanceType<typeof ModelloLiberatoriaUpdate>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const modelloLiberatoriaSample = { id: 123 };
describe('Component Tests', () => {
let mountOptions: MountingOptions<ModelloLiberatoriaUpdateComponentType>['global'];
let alertService: AlertService;
describe('ModelloLiberatoria Management Update Component', () => {
let comp: ModelloLiberatoriaUpdateComponentType;
let modelloLiberatoriaServiceStub: SinonStubbedInstance<ModelloLiberatoriaService>;
beforeEach(() => {
route = {};
modelloLiberatoriaServiceStub = sinon.createStubInstance<ModelloLiberatoriaService>(ModelloLiberatoriaService);
modelloLiberatoriaServiceStub.retrieve.onFirstCall().resolves(Promise.resolve([]));
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'b-input-group': true,
'b-input-group-prepend': true,
'b-form-datepicker': true,
'b-form-input': true,
},
provide: {
alertService,
modelloLiberatoriaService: () => modelloLiberatoriaServiceStub,
strutturaService: () =>
sinon.createStubInstance<StrutturaService>(StrutturaService, {
retrieve: sinon.stub().resolves({}),
} as any),
},
};
});
afterEach(() => {
vitest.resetAllMocks();
});
describe('load', () => {
beforeEach(() => {
const wrapper = shallowMount(ModelloLiberatoriaUpdate, { global: mountOptions });
comp = wrapper.vm;
});
it('Should convert date from string', () => {
// GIVEN
const date = new Date('2019-10-15T11:42:02Z');
// WHEN
const convertedDate = comp.convertDateTimeFromServer(date);
// THEN
expect(convertedDate).toEqual(dayjs(date).format(DATE_TIME_LONG_FORMAT));
});
it('Should not convert date if date is not present', () => {
expect(comp.convertDateTimeFromServer(null)).toBeNull();
});
});
describe('save', () => {
it('Should call update service on save for existing entity', async () => {
// GIVEN
const wrapper = shallowMount(ModelloLiberatoriaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.modelloLiberatoria = modelloLiberatoriaSample;
modelloLiberatoriaServiceStub.update.resolves(modelloLiberatoriaSample);
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(modelloLiberatoriaServiceStub.update.calledWith(modelloLiberatoriaSample)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
it('Should call create service on save for new entity', async () => {
// GIVEN
const entity = {};
modelloLiberatoriaServiceStub.create.resolves(entity);
const wrapper = shallowMount(ModelloLiberatoriaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.modelloLiberatoria = entity;
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(modelloLiberatoriaServiceStub.create.calledWith(entity)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
});
describe('Before route enter', () => {
it('Should retrieve data', async () => {
// GIVEN
modelloLiberatoriaServiceStub.find.resolves(modelloLiberatoriaSample);
modelloLiberatoriaServiceStub.retrieve.resolves([modelloLiberatoriaSample]);
// WHEN
route = {
params: {
modelloLiberatoriaId: `${modelloLiberatoriaSample.id}`,
},
};
const wrapper = shallowMount(ModelloLiberatoriaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(comp.modelloLiberatoria).toMatchObject(modelloLiberatoriaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
modelloLiberatoriaServiceStub.find.resolves(modelloLiberatoriaSample);
const wrapper = shallowMount(ModelloLiberatoriaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,120 @@
import { type Ref, computed, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useVuelidate } from '@vuelidate/core';
import StrutturaService from '@/entities/struttura/struttura.service';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat, useValidation } from '@/shared/composables';
import useDataUtils from '@/shared/data/data-utils.service';
import { type IModelloLiberatoria, ModelloLiberatoria } from '@/shared/model/modello-liberatoria.model';
import { type IStruttura } from '@/shared/model/struttura.model';
import ModelloLiberatoriaService from './modello-liberatoria.service';
export default defineComponent({
name: 'ModelloLiberatoriaUpdate',
setup() {
const modelloLiberatoriaService = inject('modelloLiberatoriaService', () => new ModelloLiberatoriaService());
const alertService = inject('alertService', () => useAlertService(), true);
const modelloLiberatoria: Ref<IModelloLiberatoria> = ref(new ModelloLiberatoria());
const strutturaService = inject('strutturaService', () => new StrutturaService());
const strutturas: Ref<IStruttura[]> = ref([]);
const isSaving = ref(false);
const currentLanguage = inject('currentLanguage', () => computed(() => navigator.language ?? 'it'), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const retrieveModelloLiberatoria = async modelloLiberatoriaId => {
try {
const res = await modelloLiberatoriaService().find(modelloLiberatoriaId);
res.validoDal = new Date(res.validoDal);
res.validoAl = new Date(res.validoAl);
modelloLiberatoria.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.modelloLiberatoriaId) {
retrieveModelloLiberatoria(route.params.modelloLiberatoriaId);
}
const initRelationships = () => {
strutturaService()
.retrieve()
.then(res => {
strutturas.value = res.data;
});
};
initRelationships();
const dataUtils = useDataUtils();
const { t: t$ } = useI18n();
const validations = useValidation();
const validationRules = {
nome: {},
testo: {},
documento: {},
validoDal: {},
validoAl: {},
struttura: {},
};
const v$ = useVuelidate(validationRules, modelloLiberatoria as any);
v$.value.$validate();
return {
modelloLiberatoriaService,
alertService,
modelloLiberatoria,
previousState,
isSaving,
currentLanguage,
strutturas,
...dataUtils,
v$,
...useDateFormat({ entityRef: modelloLiberatoria }),
t$,
};
},
created(): void {},
methods: {
save(): void {
this.isSaving = true;
if (this.modelloLiberatoria.id) {
this.modelloLiberatoriaService()
.update(this.modelloLiberatoria)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showInfo(this.t$('smartbookingApp.modelloLiberatoria.updated', { param: param.id }));
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
} else {
this.modelloLiberatoriaService()
.create(this.modelloLiberatoria)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showSuccess(this.t$('smartbookingApp.modelloLiberatoria.created', { param: param.id }).toString());
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
}
},
},
});

View File

@@ -0,0 +1,152 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<form name="editForm" novalidate @submit.prevent="save()">
<h2 id="smartbookingApp.modelloLiberatoria.home.createOrEditLabel" data-cy="ModelloLiberatoriaCreateUpdateHeading">
{{ t$('smartbookingApp.modelloLiberatoria.home.createOrEditLabel') }}
</h2>
<div>
<div class="mb-3" v-if="modelloLiberatoria.id">
<label for="id">{{ t$('global.field.id') }}</label>
<input type="text" class="form-control" id="id" name="id" v-model="modelloLiberatoria.id" readonly />
</div>
<div class="mb-3">
<label class="form-control-label" for="modello-liberatoria">{{ t$('smartbookingApp.modelloLiberatoria.nome') }}</label>
<input
type="text"
class="form-control"
name="nome"
id="modello-liberatoria-nome"
data-cy="nome"
:class="{ valid: !v$.nome.$invalid, invalid: v$.nome.$invalid }"
v-model="v$.nome.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="modello-liberatoria">{{ t$('smartbookingApp.modelloLiberatoria.testo') }}</label>
<input
type="text"
class="form-control"
name="testo"
id="modello-liberatoria-testo"
data-cy="testo"
:class="{ valid: !v$.testo.$invalid, invalid: v$.testo.$invalid }"
v-model="v$.testo.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="modello-liberatoria">{{ t$('smartbookingApp.modelloLiberatoria.documento') }}</label>
<div>
<div v-if="modelloLiberatoria.documento" class="form-text text-danger clearfix">
<span class="pull-start">{{ modelloLiberatoria.documentoContentType }}, {{ byteSize(modelloLiberatoria.documento) }}</span>
<button
type="button"
@click="
modelloLiberatoria.documento = null;
modelloLiberatoria.documentoContentType = null;
"
class="btn btn-secondary btn-xs pull-end"
>
<font-awesome-icon icon="times"></font-awesome-icon>
</button>
</div>
<label for="file_documento" class="btn btn-primary pull-end">{{ t$('entity.action.addblob') }}</label>
<input
type="file"
ref="file_documento"
id="file_documento"
style="display: none"
data-cy="documento"
@change="setFileData($event, modelloLiberatoria, 'documento', false)"
/>
</div>
<input
type="hidden"
class="form-control"
name="documento"
id="modello-liberatoria-documento"
data-cy="documento"
:class="{ valid: !v$.documento.$invalid, invalid: v$.documento.$invalid }"
v-model="v$.documento.$model"
/>
<input
type="hidden"
class="form-control"
name="documentoContentType"
id="modello-liberatoria-documentoContentType"
v-model="modelloLiberatoria.documentoContentType"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="modello-liberatoria">{{ t$('smartbookingApp.modelloLiberatoria.validoDal') }}</label>
<div class="d-flex">
<input
id="modello-liberatoria-validoDal"
data-cy="validoDal"
type="datetime-local"
class="form-control"
name="validoDal"
:class="{ valid: !v$.validoDal.$invalid, invalid: v$.validoDal.$invalid }"
:value="convertDateTimeFromServer(v$.validoDal.$model)"
@change="updateInstantField('validoDal', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="modello-liberatoria">{{ t$('smartbookingApp.modelloLiberatoria.validoAl') }}</label>
<div class="d-flex">
<input
id="modello-liberatoria-validoAl"
data-cy="validoAl"
type="datetime-local"
class="form-control"
name="validoAl"
:class="{ valid: !v$.validoAl.$invalid, invalid: v$.validoAl.$invalid }"
:value="convertDateTimeFromServer(v$.validoAl.$model)"
@change="updateInstantField('validoAl', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="modello-liberatoria">{{ t$('smartbookingApp.modelloLiberatoria.struttura') }}</label>
<select
class="form-control"
id="modello-liberatoria-struttura"
data-cy="struttura"
name="struttura"
v-model="modelloLiberatoria.struttura"
>
<option :value="null"></option>
<option
:value="
modelloLiberatoria.struttura && strutturaOption.id === modelloLiberatoria.struttura.id
? modelloLiberatoria.struttura
: strutturaOption
"
v-for="strutturaOption in strutturas"
:key="strutturaOption.id"
>
{{ strutturaOption.id }}
</option>
</select>
</div>
</div>
<div>
<button type="button" id="cancel-save" data-cy="entityCreateCancelButton" class="btn btn-secondary" @click="previousState()">
<font-awesome-icon icon="ban"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.cancel') }}</span>
</button>
<button
type="submit"
id="save-entity"
data-cy="entityCreateSaveButton"
:disabled="v$.$invalid || isSaving"
class="btn btn-primary"
>
<font-awesome-icon icon="save"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.save') }}</span>
</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts" src="./modello-liberatoria-update.component.ts"></script>

View File

@@ -0,0 +1,102 @@
import { vitest } from 'vitest';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import ModelloLiberatoriaService from './modello-liberatoria.service';
import ModelloLiberatoria from './modello-liberatoria.vue';
type ModelloLiberatoriaComponentType = InstanceType<typeof ModelloLiberatoria>;
const bModalStub = {
render: () => {},
methods: {
hide: () => {},
show: () => {},
},
};
describe('Component Tests', () => {
let alertService: AlertService;
describe('ModelloLiberatoria Management Component', () => {
let modelloLiberatoriaServiceStub: SinonStubbedInstance<ModelloLiberatoriaService>;
let mountOptions: MountingOptions<ModelloLiberatoriaComponentType>['global'];
beforeEach(() => {
modelloLiberatoriaServiceStub = sinon.createStubInstance<ModelloLiberatoriaService>(ModelloLiberatoriaService);
modelloLiberatoriaServiceStub.retrieve.resolves({ headers: {} });
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
bModal: bModalStub as any,
'font-awesome-icon': true,
'b-badge': true,
'b-button': true,
'router-link': true,
},
directives: {
'b-modal': {},
},
provide: {
alertService,
modelloLiberatoriaService: () => modelloLiberatoriaServiceStub,
},
};
});
describe('Mount', () => {
it('Should call load all on init', async () => {
// GIVEN
modelloLiberatoriaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
const wrapper = shallowMount(ModelloLiberatoria, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(modelloLiberatoriaServiceStub.retrieve.calledOnce).toBeTruthy();
expect(comp.modelloLiberatorias[0]).toEqual(expect.objectContaining({ id: 123 }));
});
});
describe('Handles', () => {
let comp: ModelloLiberatoriaComponentType;
beforeEach(async () => {
const wrapper = shallowMount(ModelloLiberatoria, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
modelloLiberatoriaServiceStub.retrieve.reset();
modelloLiberatoriaServiceStub.retrieve.resolves({ headers: {}, data: [] });
});
it('Should call delete service on confirmDelete', async () => {
// GIVEN
modelloLiberatoriaServiceStub.delete.resolves({});
// WHEN
comp.prepareRemove({ id: 123 });
comp.removeModelloLiberatoria();
await comp.$nextTick(); // clear components
// THEN
expect(modelloLiberatoriaServiceStub.delete.called).toBeTruthy();
// THEN
await comp.$nextTick(); // handle component clear watch
expect(modelloLiberatoriaServiceStub.retrieve.callCount).toEqual(1);
});
});
});
});

View File

@@ -0,0 +1,84 @@
import { type Ref, defineComponent, inject, onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import useDataUtils from '@/shared/data/data-utils.service';
import { type IModelloLiberatoria } from '@/shared/model/modello-liberatoria.model';
import ModelloLiberatoriaService from './modello-liberatoria.service';
export default defineComponent({
name: 'ModelloLiberatoria',
setup() {
const { t: t$ } = useI18n();
const dateFormat = useDateFormat();
const dataUtils = useDataUtils();
const modelloLiberatoriaService = inject('modelloLiberatoriaService', () => new ModelloLiberatoriaService());
const alertService = inject('alertService', () => useAlertService(), true);
const modelloLiberatorias: Ref<IModelloLiberatoria[]> = ref([]);
const isFetching = ref(false);
const clear = () => {};
const retrieveModelloLiberatorias = async () => {
isFetching.value = true;
try {
const res = await modelloLiberatoriaService().retrieve();
modelloLiberatorias.value = res.data;
} catch (err) {
alertService.showHttpError(err.response);
} finally {
isFetching.value = false;
}
};
const handleSyncList = () => {
retrieveModelloLiberatorias();
};
onMounted(async () => {
await retrieveModelloLiberatorias();
});
const removeId: Ref<number> = ref(null);
const removeEntity = ref<any>(null);
const prepareRemove = (instance: IModelloLiberatoria) => {
removeId.value = instance.id;
removeEntity.value.show();
};
const closeDialog = () => {
removeEntity.value.hide();
};
const removeModelloLiberatoria = async () => {
try {
await modelloLiberatoriaService().delete(removeId.value);
const message = t$('smartbookingApp.modelloLiberatoria.deleted', { param: removeId.value }).toString();
alertService.showInfo(message, { variant: 'danger' });
removeId.value = null;
retrieveModelloLiberatorias();
closeDialog();
} catch (error) {
alertService.showHttpError(error.response);
}
};
return {
modelloLiberatorias,
handleSyncList,
isFetching,
retrieveModelloLiberatorias,
clear,
...dateFormat,
removeId,
removeEntity,
prepareRemove,
closeDialog,
removeModelloLiberatoria,
t$,
...dataUtils,
};
},
});

View File

@@ -0,0 +1,193 @@
import axios from 'axios';
import dayjs from 'dayjs';
import sinon from 'sinon';
import { DATE_TIME_FORMAT } from '@/shared/composables/date-format';
import { ModelloLiberatoria } from '@/shared/model/modello-liberatoria.model';
import ModelloLiberatoriaService from './modello-liberatoria.service';
const error = {
response: {
status: null,
data: {
type: null,
},
},
};
const axiosStub = {
get: sinon.stub(axios, 'get'),
post: sinon.stub(axios, 'post'),
put: sinon.stub(axios, 'put'),
patch: sinon.stub(axios, 'patch'),
delete: sinon.stub(axios, 'delete'),
};
describe('Service Tests', () => {
describe('ModelloLiberatoria Service', () => {
let service: ModelloLiberatoriaService;
let elemDefault;
let currentDate: Date;
beforeEach(() => {
service = new ModelloLiberatoriaService();
currentDate = new Date();
elemDefault = new ModelloLiberatoria(123, 'AAAAAAA', 'AAAAAAA', 'image/png', 'AAAAAAA', currentDate, currentDate);
});
describe('Service methods', () => {
it('should find an element', async () => {
const returnedFromService = {
validoDal: dayjs(currentDate).format(DATE_TIME_FORMAT),
validoAl: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
axiosStub.get.resolves({ data: returnedFromService });
return service.find(123).then(res => {
expect(res).toMatchObject(elemDefault);
});
});
it('should not find an element', async () => {
axiosStub.get.rejects(error);
return service
.find(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should create a ModelloLiberatoria', async () => {
const returnedFromService = {
id: 123,
validoDal: dayjs(currentDate).format(DATE_TIME_FORMAT),
validoAl: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { validoDal: currentDate, validoAl: currentDate, ...returnedFromService };
axiosStub.post.resolves({ data: returnedFromService });
return service.create({}).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not create a ModelloLiberatoria', async () => {
axiosStub.post.rejects(error);
return service
.create({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should update a ModelloLiberatoria', async () => {
const returnedFromService = {
nome: 'BBBBBB',
testo: 'BBBBBB',
documento: 'BBBBBB',
validoDal: dayjs(currentDate).format(DATE_TIME_FORMAT),
validoAl: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { validoDal: currentDate, validoAl: currentDate, ...returnedFromService };
axiosStub.put.resolves({ data: returnedFromService });
return service.update(expected).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not update a ModelloLiberatoria', async () => {
axiosStub.put.rejects(error);
return service
.update({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should partial update a ModelloLiberatoria', async () => {
const patchObject = {
nome: 'BBBBBB',
testo: 'BBBBBB',
documento: 'BBBBBB',
validoAl: dayjs(currentDate).format(DATE_TIME_FORMAT),
...new ModelloLiberatoria(),
};
const returnedFromService = Object.assign(patchObject, elemDefault);
const expected = { validoDal: currentDate, validoAl: currentDate, ...returnedFromService };
axiosStub.patch.resolves({ data: returnedFromService });
return service.partialUpdate(patchObject).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not partial update a ModelloLiberatoria', async () => {
axiosStub.patch.rejects(error);
return service
.partialUpdate({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should return a list of ModelloLiberatoria', async () => {
const returnedFromService = {
nome: 'BBBBBB',
testo: 'BBBBBB',
documento: 'BBBBBB',
validoDal: dayjs(currentDate).format(DATE_TIME_FORMAT),
validoAl: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { validoDal: currentDate, validoAl: currentDate, ...returnedFromService };
axiosStub.get.resolves([returnedFromService]);
return service.retrieve().then(res => {
expect(res).toContainEqual(expected);
});
});
it('should not return a list of ModelloLiberatoria', async () => {
axiosStub.get.rejects(error);
return service
.retrieve()
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should delete a ModelloLiberatoria', async () => {
axiosStub.delete.resolves({ ok: true });
return service.delete(123).then(res => {
expect(res.ok).toBeTruthy();
});
});
it('should not delete a ModelloLiberatoria', async () => {
axiosStub.delete.rejects(error);
return service
.delete(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
});
});
});

View File

@@ -0,0 +1,85 @@
import axios from 'axios';
import { type IModelloLiberatoria } from '@/shared/model/modello-liberatoria.model';
const baseApiUrl = 'api/modello-liberatorias';
export default class ModelloLiberatoriaService {
find(id: number): Promise<IModelloLiberatoria> {
return new Promise<IModelloLiberatoria>((resolve, reject) => {
axios
.get(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
retrieve(): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.get(baseApiUrl)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
delete(id: number): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.delete(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
create(entity: IModelloLiberatoria): Promise<IModelloLiberatoria> {
return new Promise<IModelloLiberatoria>((resolve, reject) => {
axios
.post(baseApiUrl, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
update(entity: IModelloLiberatoria): Promise<IModelloLiberatoria> {
return new Promise<IModelloLiberatoria>((resolve, reject) => {
axios
.put(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
partialUpdate(entity: IModelloLiberatoria): Promise<IModelloLiberatoria> {
return new Promise<IModelloLiberatoria>((resolve, reject) => {
axios
.patch(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
}

View File

@@ -0,0 +1,135 @@
<template>
<div>
<h2 id="page-heading" data-cy="ModelloLiberatoriaHeading">
<span id="modello-liberatoria">{{ t$('smartbookingApp.modelloLiberatoria.home.title') }}</span>
<div class="d-flex justify-content-end">
<button class="btn btn-info me-2" @click="handleSyncList" :disabled="isFetching">
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
<span>{{ t$('smartbookingApp.modelloLiberatoria.home.refreshListLabel') }}</span>
</button>
<router-link :to="{ name: 'ModelloLiberatoriaCreate' }" custom v-slot="{ navigate }">
<button
@click="navigate"
id="jh-create-entity"
data-cy="entityCreateButton"
class="btn btn-primary jh-create-entity create-modello-liberatoria"
>
<font-awesome-icon icon="plus"></font-awesome-icon>
<span>{{ t$('smartbookingApp.modelloLiberatoria.home.createLabel') }}</span>
</button>
</router-link>
</div>
</h2>
<br />
<div class="alert alert-warning" v-if="!isFetching && modelloLiberatorias?.length === 0">
<span>{{ t$('smartbookingApp.modelloLiberatoria.home.notFound') }}</span>
</div>
<div class="table-responsive" v-if="modelloLiberatorias?.length > 0">
<table class="table table-striped" aria-describedby="modelloLiberatorias">
<thead>
<tr>
<th scope="col">
<span>{{ t$('global.field.id') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.modelloLiberatoria.nome') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.modelloLiberatoria.testo') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.modelloLiberatoria.documento') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.modelloLiberatoria.validoDal') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.modelloLiberatoria.validoAl') }}</span>
</th>
<th scope="col">
<span>{{ t$('smartbookingApp.modelloLiberatoria.struttura') }}</span>
</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="modelloLiberatoria in modelloLiberatorias" :key="modelloLiberatoria.id" data-cy="entityTable">
<td>
<router-link :to="{ name: 'ModelloLiberatoriaView', params: { modelloLiberatoriaId: modelloLiberatoria.id } }">{{
modelloLiberatoria.id
}}</router-link>
</td>
<td>{{ modelloLiberatoria.nome }}</td>
<td>{{ modelloLiberatoria.testo }}</td>
<td>{{ modelloLiberatoria.documento }}</td>
<td>{{ formatDateShort(modelloLiberatoria.validoDal) || '' }}</td>
<td>{{ formatDateShort(modelloLiberatoria.validoAl) || '' }}</td>
<td>
<div v-if="modelloLiberatoria.struttura">
<router-link :to="{ name: 'StrutturaView', params: { strutturaId: modelloLiberatoria.struttura.id } }">{{
modelloLiberatoria.struttura.id
}}</router-link>
</div>
</td>
<td class="text-end">
<div class="btn-group">
<router-link
:to="{ name: 'ModelloLiberatoriaView', params: { modelloLiberatoriaId: modelloLiberatoria.id } }"
class="btn btn-info btn-sm details"
data-cy="entityDetailsButton"
>
<font-awesome-icon icon="eye"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
</router-link>
<router-link
:to="{ name: 'ModelloLiberatoriaEdit', params: { modelloLiberatoriaId: modelloLiberatoria.id } }"
class="btn btn-primary btn-sm edit"
data-cy="entityEditButton"
>
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.edit') }}</span>
</router-link>
<b-button
@click="prepareRemove(modelloLiberatoria)"
variant="danger"
class="btn btn-sm"
data-cy="entityDeleteButton"
v-b-modal.removeEntity
>
<font-awesome-icon icon="times"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
</b-button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<b-modal ref="removeEntity" id="removeEntity">
<template #title>
<span id="smartbookingApp.modelloLiberatoria.delete.question" data-cy="modelloLiberatoriaDeleteDialogHeading">{{
t$('entity.delete.title')
}}</span>
</template>
<div class="modal-body">
<p id="jhi-delete-modelloLiberatoria-heading">{{ t$('smartbookingApp.modelloLiberatoria.delete.question', { id: removeId }) }}</p>
</div>
<template #footer>
<div>
<button type="button" class="btn btn-secondary" @click="closeDialog()">{{ t$('entity.action.cancel') }}</button>
<button
type="button"
class="btn btn-primary"
id="jhi-confirm-delete-modelloLiberatoria"
data-cy="entityConfirmDeleteButton"
@click="removeModelloLiberatoria"
>
{{ t$('entity.action.delete') }}
</button>
</div>
</template>
</b-modal>
</div>
</template>
<script lang="ts" src="./modello-liberatoria.component.ts"></script>

View File

@@ -0,0 +1,91 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import NotificaDetails from './notifica-details.vue';
import NotificaService from './notifica.service';
type NotificaDetailsComponentType = InstanceType<typeof NotificaDetails>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const notificaSample = { id: 123 };
describe('Component Tests', () => {
let alertService: AlertService;
afterEach(() => {
vitest.resetAllMocks();
});
describe('Notifica Management Detail Component', () => {
let notificaServiceStub: SinonStubbedInstance<NotificaService>;
let mountOptions: MountingOptions<NotificaDetailsComponentType>['global'];
beforeEach(() => {
route = {};
notificaServiceStub = sinon.createStubInstance<NotificaService>(NotificaService);
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'router-link': true,
},
provide: {
alertService,
notificaService: () => notificaServiceStub,
},
};
});
describe('Navigate to details', () => {
it('Should call load all on init', async () => {
// GIVEN
notificaServiceStub.find.resolves(notificaSample);
route = {
params: {
notificaId: `${123}`,
},
};
const wrapper = shallowMount(NotificaDetails, { global: mountOptions });
const comp = wrapper.vm;
// WHEN
await comp.$nextTick();
// THEN
expect(comp.notifica).toMatchObject(notificaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
notificaServiceStub.find.resolves(notificaSample);
const wrapper = shallowMount(NotificaDetails, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,46 @@
import { type Ref, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type INotifica } from '@/shared/model/notifica.model';
import NotificaService from './notifica.service';
export default defineComponent({
name: 'NotificaDetails',
setup() {
const dateFormat = useDateFormat();
const notificaService = inject('notificaService', () => new NotificaService());
const alertService = inject('alertService', () => useAlertService(), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const notifica: Ref<INotifica> = ref({});
const retrieveNotifica = async notificaId => {
try {
const res = await notificaService().find(notificaId);
notifica.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.notificaId) {
retrieveNotifica(route.params.notificaId);
}
return {
...dateFormat,
alertService,
notifica,
previousState,
t$: useI18n().t,
};
},
});

View File

@@ -0,0 +1,75 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<div v-if="notifica">
<h2 class="jh-entity-heading" data-cy="notificaDetailsHeading">
<span>{{ t$('smartbookingApp.notifica.detail.title') }}Notifica</span> {{ notifica.id }}
</h2>
<dl class="row-md jh-entity-details">
<dt>
<span>{{ t$('smartbookingApp.notifica.tipoCanale') }}</span>
</dt>
<dd>
<span>{{ t$('smartbookingApp.TipoCanaleNotifica.' + notifica.tipoCanale) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.notifica.tipoEvento') }}</span>
</dt>
<dd>
<span>{{ t$('smartbookingApp.TipoEventoNotifica.' + notifica.tipoEvento) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.notifica.messaggio') }}</span>
</dt>
<dd>
<span>{{ notifica.messaggio }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.notifica.inviata') }}</span>
</dt>
<dd>
<span>{{ notifica.inviata }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.notifica.inviataAt') }}</span>
</dt>
<dd>
<span v-if="notifica.inviataAt">{{ formatDateLong(notifica.inviataAt) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.notifica.errore') }}</span>
</dt>
<dd>
<span>{{ notifica.errore }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.notifica.createdAt') }}</span>
</dt>
<dd>
<span v-if="notifica.createdAt">{{ formatDateLong(notifica.createdAt) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.notifica.conferma') }}</span>
</dt>
<dd>
<div v-if="notifica.conferma">
<router-link :to="{ name: 'ConfermaView', params: { confermaId: notifica.conferma.id } }">{{
notifica.conferma.id
}}</router-link>
</div>
</dd>
</dl>
<button type="submit" @click.prevent="previousState()" class="btn btn-info" data-cy="entityDetailsBackButton">
<font-awesome-icon icon="arrow-left"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.back') }}</span>
</button>
<router-link v-if="notifica.id" :to="{ name: 'NotificaEdit', params: { notificaId: notifica.id } }" custom v-slot="{ navigate }">
<button @click="navigate" class="btn btn-primary">
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.edit') }}</span>
</button>
</router-link>
</div>
</div>
</div>
</template>
<script lang="ts" src="./notifica-details.component.ts"></script>

View File

@@ -0,0 +1,161 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import dayjs from 'dayjs';
import sinon, { type SinonStubbedInstance } from 'sinon';
import ConfermaService from '@/entities/conferma/conferma.service';
import AlertService from '@/shared/alert/alert.service';
import { DATE_TIME_LONG_FORMAT } from '@/shared/composables/date-format';
import NotificaUpdate from './notifica-update.vue';
import NotificaService from './notifica.service';
type NotificaUpdateComponentType = InstanceType<typeof NotificaUpdate>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const notificaSample = { id: 123 };
describe('Component Tests', () => {
let mountOptions: MountingOptions<NotificaUpdateComponentType>['global'];
let alertService: AlertService;
describe('Notifica Management Update Component', () => {
let comp: NotificaUpdateComponentType;
let notificaServiceStub: SinonStubbedInstance<NotificaService>;
beforeEach(() => {
route = {};
notificaServiceStub = sinon.createStubInstance<NotificaService>(NotificaService);
notificaServiceStub.retrieve.onFirstCall().resolves(Promise.resolve([]));
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'b-input-group': true,
'b-input-group-prepend': true,
'b-form-datepicker': true,
'b-form-input': true,
},
provide: {
alertService,
notificaService: () => notificaServiceStub,
confermaService: () =>
sinon.createStubInstance<ConfermaService>(ConfermaService, {
retrieve: sinon.stub().resolves({}),
} as any),
},
};
});
afterEach(() => {
vitest.resetAllMocks();
});
describe('load', () => {
beforeEach(() => {
const wrapper = shallowMount(NotificaUpdate, { global: mountOptions });
comp = wrapper.vm;
});
it('Should convert date from string', () => {
// GIVEN
const date = new Date('2019-10-15T11:42:02Z');
// WHEN
const convertedDate = comp.convertDateTimeFromServer(date);
// THEN
expect(convertedDate).toEqual(dayjs(date).format(DATE_TIME_LONG_FORMAT));
});
it('Should not convert date if date is not present', () => {
expect(comp.convertDateTimeFromServer(null)).toBeNull();
});
});
describe('save', () => {
it('Should call update service on save for existing entity', async () => {
// GIVEN
const wrapper = shallowMount(NotificaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.notifica = notificaSample;
notificaServiceStub.update.resolves(notificaSample);
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(notificaServiceStub.update.calledWith(notificaSample)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
it('Should call create service on save for new entity', async () => {
// GIVEN
const entity = {};
notificaServiceStub.create.resolves(entity);
const wrapper = shallowMount(NotificaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.notifica = entity;
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(notificaServiceStub.create.calledWith(entity)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
});
describe('Before route enter', () => {
it('Should retrieve data', async () => {
// GIVEN
notificaServiceStub.find.resolves(notificaSample);
notificaServiceStub.retrieve.resolves([notificaSample]);
// WHEN
route = {
params: {
notificaId: `${notificaSample.id}`,
},
};
const wrapper = shallowMount(NotificaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(comp.notifica).toMatchObject(notificaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
notificaServiceStub.find.resolves(notificaSample);
const wrapper = shallowMount(NotificaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,124 @@
import { type Ref, computed, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useVuelidate } from '@vuelidate/core';
import ConfermaService from '@/entities/conferma/conferma.service';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat, useValidation } from '@/shared/composables';
import { type IConferma } from '@/shared/model/conferma.model';
import { TipoCanaleNotifica } from '@/shared/model/enumerations/tipo-canale-notifica.model';
import { TipoEventoNotifica } from '@/shared/model/enumerations/tipo-evento-notifica.model';
import { type INotifica, Notifica } from '@/shared/model/notifica.model';
import NotificaService from './notifica.service';
export default defineComponent({
name: 'NotificaUpdate',
setup() {
const notificaService = inject('notificaService', () => new NotificaService());
const alertService = inject('alertService', () => useAlertService(), true);
const notifica: Ref<INotifica> = ref(new Notifica());
const confermaService = inject('confermaService', () => new ConfermaService());
const confermas: Ref<IConferma[]> = ref([]);
const tipoCanaleNotificaValues: Ref<string[]> = ref(Object.keys(TipoCanaleNotifica));
const tipoEventoNotificaValues: Ref<string[]> = ref(Object.keys(TipoEventoNotifica));
const isSaving = ref(false);
const currentLanguage = inject('currentLanguage', () => computed(() => navigator.language ?? 'it'), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const retrieveNotifica = async notificaId => {
try {
const res = await notificaService().find(notificaId);
res.inviataAt = new Date(res.inviataAt);
res.createdAt = new Date(res.createdAt);
notifica.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.notificaId) {
retrieveNotifica(route.params.notificaId);
}
const initRelationships = () => {
confermaService()
.retrieve()
.then(res => {
confermas.value = res.data;
});
};
initRelationships();
const { t: t$ } = useI18n();
const validations = useValidation();
const validationRules = {
tipoCanale: {},
tipoEvento: {},
messaggio: {},
inviata: {},
inviataAt: {},
errore: {},
createdAt: {},
conferma: {},
};
const v$ = useVuelidate(validationRules, notifica as any);
v$.value.$validate();
return {
notificaService,
alertService,
notifica,
previousState,
tipoCanaleNotificaValues,
tipoEventoNotificaValues,
isSaving,
currentLanguage,
confermas,
v$,
...useDateFormat({ entityRef: notifica }),
t$,
};
},
created(): void {},
methods: {
save(): void {
this.isSaving = true;
if (this.notifica.id) {
this.notificaService()
.update(this.notifica)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showInfo(this.t$('smartbookingApp.notifica.updated', { param: param.id }));
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
} else {
this.notificaService()
.create(this.notifica)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showSuccess(this.t$('smartbookingApp.notifica.created', { param: param.id }).toString());
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
}
},
},
});

View File

@@ -0,0 +1,151 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<form name="editForm" novalidate @submit.prevent="save()">
<h2 id="smartbookingApp.notifica.home.createOrEditLabel" data-cy="NotificaCreateUpdateHeading">
{{ t$('smartbookingApp.notifica.home.createOrEditLabel') }}
</h2>
<div>
<div class="mb-3" v-if="notifica.id">
<label for="id">{{ t$('global.field.id') }}</label>
<input type="text" class="form-control" id="id" name="id" v-model="notifica.id" readonly />
</div>
<div class="mb-3">
<label class="form-control-label" for="notifica">{{ t$('smartbookingApp.notifica.tipoCanale') }}</label>
<select
class="form-control"
name="tipoCanale"
:class="{ valid: !v$.tipoCanale.$invalid, invalid: v$.tipoCanale.$invalid }"
v-model="v$.tipoCanale.$model"
id="notifica-tipoCanale"
data-cy="tipoCanale"
>
<option
v-for="tipoCanaleNotifica in tipoCanaleNotificaValues"
:key="tipoCanaleNotifica"
:value="tipoCanaleNotifica"
:label="t$('smartbookingApp.TipoCanaleNotifica.' + tipoCanaleNotifica)"
>
{{ tipoCanaleNotifica }}
</option>
</select>
</div>
<div class="mb-3">
<label class="form-control-label" for="notifica">{{ t$('smartbookingApp.notifica.tipoEvento') }}</label>
<select
class="form-control"
name="tipoEvento"
:class="{ valid: !v$.tipoEvento.$invalid, invalid: v$.tipoEvento.$invalid }"
v-model="v$.tipoEvento.$model"
id="notifica-tipoEvento"
data-cy="tipoEvento"
>
<option
v-for="tipoEventoNotifica in tipoEventoNotificaValues"
:key="tipoEventoNotifica"
:value="tipoEventoNotifica"
:label="t$('smartbookingApp.TipoEventoNotifica.' + tipoEventoNotifica)"
>
{{ tipoEventoNotifica }}
</option>
</select>
</div>
<div class="mb-3">
<label class="form-control-label" for="notifica">{{ t$('smartbookingApp.notifica.messaggio') }}</label>
<input
type="text"
class="form-control"
name="messaggio"
id="notifica-messaggio"
data-cy="messaggio"
:class="{ valid: !v$.messaggio.$invalid, invalid: v$.messaggio.$invalid }"
v-model="v$.messaggio.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="notifica">{{ t$('smartbookingApp.notifica.inviata') }}</label>
<input
type="checkbox"
class="form-check"
name="inviata"
id="notifica-inviata"
data-cy="inviata"
:class="{ valid: !v$.inviata.$invalid, invalid: v$.inviata.$invalid }"
v-model="v$.inviata.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="notifica">{{ t$('smartbookingApp.notifica.inviataAt') }}</label>
<div class="d-flex">
<input
id="notifica-inviataAt"
data-cy="inviataAt"
type="datetime-local"
class="form-control"
name="inviataAt"
:class="{ valid: !v$.inviataAt.$invalid, invalid: v$.inviataAt.$invalid }"
:value="convertDateTimeFromServer(v$.inviataAt.$model)"
@change="updateInstantField('inviataAt', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="notifica">{{ t$('smartbookingApp.notifica.errore') }}</label>
<input
type="text"
class="form-control"
name="errore"
id="notifica-errore"
data-cy="errore"
:class="{ valid: !v$.errore.$invalid, invalid: v$.errore.$invalid }"
v-model="v$.errore.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="notifica">{{ t$('smartbookingApp.notifica.createdAt') }}</label>
<div class="d-flex">
<input
id="notifica-createdAt"
data-cy="createdAt"
type="datetime-local"
class="form-control"
name="createdAt"
:class="{ valid: !v$.createdAt.$invalid, invalid: v$.createdAt.$invalid }"
:value="convertDateTimeFromServer(v$.createdAt.$model)"
@change="updateInstantField('createdAt', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="notifica">{{ t$('smartbookingApp.notifica.conferma') }}</label>
<select class="form-control" id="notifica-conferma" data-cy="conferma" name="conferma" v-model="notifica.conferma">
<option :value="null"></option>
<option
:value="notifica.conferma && confermaOption.id === notifica.conferma.id ? notifica.conferma : confermaOption"
v-for="confermaOption in confermas"
:key="confermaOption.id"
>
{{ confermaOption.id }}
</option>
</select>
</div>
</div>
<div>
<button type="button" id="cancel-save" data-cy="entityCreateCancelButton" class="btn btn-secondary" @click="previousState()">
<font-awesome-icon icon="ban"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.cancel') }}</span>
</button>
<button
type="submit"
id="save-entity"
data-cy="entityCreateSaveButton"
:disabled="v$.$invalid || isSaving"
class="btn btn-primary"
>
<font-awesome-icon icon="save"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.save') }}</span>
</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts" src="./notifica-update.component.ts"></script>

View File

@@ -0,0 +1,166 @@
import { vitest } from 'vitest';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import NotificaService from './notifica.service';
import Notifica from './notifica.vue';
type NotificaComponentType = InstanceType<typeof Notifica>;
const bModalStub = {
render: () => {},
methods: {
hide: () => {},
show: () => {},
},
};
describe('Component Tests', () => {
let alertService: AlertService;
describe('Notifica Management Component', () => {
let notificaServiceStub: SinonStubbedInstance<NotificaService>;
let mountOptions: MountingOptions<NotificaComponentType>['global'];
beforeEach(() => {
notificaServiceStub = sinon.createStubInstance<NotificaService>(NotificaService);
notificaServiceStub.retrieve.resolves({ headers: {} });
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
jhiItemCount: true,
bPagination: true,
bModal: bModalStub as any,
'font-awesome-icon': true,
'b-badge': true,
'jhi-sort-indicator': true,
'b-button': true,
'router-link': true,
},
directives: {
'b-modal': {},
},
provide: {
alertService,
notificaService: () => notificaServiceStub,
},
};
});
describe('Mount', () => {
it('Should call load all on init', async () => {
// GIVEN
notificaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
const wrapper = shallowMount(Notifica, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(notificaServiceStub.retrieve.calledOnce).toBeTruthy();
expect(comp.notificas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for an id', async () => {
// WHEN
const wrapper = shallowMount(Notifica, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(notificaServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['id,asc'],
});
});
});
describe('Handles', () => {
let comp: NotificaComponentType;
beforeEach(async () => {
const wrapper = shallowMount(Notifica, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
notificaServiceStub.retrieve.reset();
notificaServiceStub.retrieve.resolves({ headers: {}, data: [] });
});
it('should load a page', async () => {
// GIVEN
notificaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.page = 2;
await comp.$nextTick();
// THEN
expect(notificaServiceStub.retrieve.called).toBeTruthy();
expect(comp.notificas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should not load a page if the page is the same as the previous page', () => {
// WHEN
comp.page = 1;
// THEN
expect(notificaServiceStub.retrieve.called).toBeFalsy();
});
it('should re-initialize the page', async () => {
// GIVEN
comp.page = 2;
await comp.$nextTick();
notificaServiceStub.retrieve.reset();
notificaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.clear();
await comp.$nextTick();
// THEN
expect(comp.page).toEqual(1);
expect(notificaServiceStub.retrieve.callCount).toEqual(1);
expect(comp.notificas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for a non-id attribute', async () => {
// WHEN
comp.propOrder = 'name';
await comp.$nextTick();
// THEN
expect(notificaServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['name,asc', 'id'],
});
});
it('Should call delete service on confirmDelete', async () => {
// GIVEN
notificaServiceStub.delete.resolves({});
// WHEN
comp.prepareRemove({ id: 123 });
comp.removeNotifica();
await comp.$nextTick(); // clear components
// THEN
expect(notificaServiceStub.delete.called).toBeTruthy();
// THEN
await comp.$nextTick(); // handle component clear watch
expect(notificaServiceStub.retrieve.callCount).toEqual(1);
});
});
});
});

View File

@@ -0,0 +1,137 @@
import { type Ref, defineComponent, inject, onMounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type INotifica } from '@/shared/model/notifica.model';
import NotificaService from './notifica.service';
export default defineComponent({
name: 'Notifica',
setup() {
const { t: t$ } = useI18n();
const dateFormat = useDateFormat();
const notificaService = inject('notificaService', () => new NotificaService());
const alertService = inject('alertService', () => useAlertService(), true);
const itemsPerPage = ref(20);
const queryCount: Ref<number> = ref(null);
const page: Ref<number> = ref(1);
const propOrder = ref('id');
const reverse = ref(false);
const totalItems = ref(0);
const notificas: Ref<INotifica[]> = ref([]);
const isFetching = ref(false);
const clear = () => {
page.value = 1;
};
const sort = (): Array<any> => {
const result = [`${propOrder.value},${reverse.value ? 'desc' : 'asc'}`];
if (propOrder.value !== 'id') {
result.push('id');
}
return result;
};
const retrieveNotificas = async () => {
isFetching.value = true;
try {
const paginationQuery = {
page: page.value - 1,
size: itemsPerPage.value,
sort: sort(),
};
const res = await notificaService().retrieve(paginationQuery);
totalItems.value = Number(res.headers['x-total-count']);
queryCount.value = totalItems.value;
notificas.value = res.data;
} catch (err) {
alertService.showHttpError(err.response);
} finally {
isFetching.value = false;
}
};
const handleSyncList = () => {
retrieveNotificas();
};
onMounted(async () => {
await retrieveNotificas();
});
const removeId: Ref<number> = ref(null);
const removeEntity = ref<any>(null);
const prepareRemove = (instance: INotifica) => {
removeId.value = instance.id;
removeEntity.value.show();
};
const closeDialog = () => {
removeEntity.value.hide();
};
const removeNotifica = async () => {
try {
await notificaService().delete(removeId.value);
const message = t$('smartbookingApp.notifica.deleted', { param: removeId.value }).toString();
alertService.showInfo(message, { variant: 'danger' });
removeId.value = null;
retrieveNotificas();
closeDialog();
} catch (error) {
alertService.showHttpError(error.response);
}
};
const changeOrder = (newOrder: string) => {
if (propOrder.value === newOrder) {
reverse.value = !reverse.value;
} else {
reverse.value = false;
}
propOrder.value = newOrder;
};
// Whenever order changes, reset the pagination
watch([propOrder, reverse], async () => {
if (page.value === 1) {
// first page, retrieve new data
await retrieveNotificas();
} else {
// reset the pagination
clear();
}
});
// Whenever page changes, switch to the new page.
watch(page, async () => {
await retrieveNotificas();
});
return {
notificas,
handleSyncList,
isFetching,
retrieveNotificas,
clear,
...dateFormat,
removeId,
removeEntity,
prepareRemove,
closeDialog,
removeNotifica,
itemsPerPage,
queryCount,
page,
propOrder,
reverse,
totalItems,
changeOrder,
t$,
};
},
});

View File

@@ -0,0 +1,197 @@
import axios from 'axios';
import dayjs from 'dayjs';
import sinon from 'sinon';
import { DATE_TIME_FORMAT } from '@/shared/composables/date-format';
import { Notifica } from '@/shared/model/notifica.model';
import NotificaService from './notifica.service';
const error = {
response: {
status: null,
data: {
type: null,
},
},
};
const axiosStub = {
get: sinon.stub(axios, 'get'),
post: sinon.stub(axios, 'post'),
put: sinon.stub(axios, 'put'),
patch: sinon.stub(axios, 'patch'),
delete: sinon.stub(axios, 'delete'),
};
describe('Service Tests', () => {
describe('Notifica Service', () => {
let service: NotificaService;
let elemDefault;
let currentDate: Date;
beforeEach(() => {
service = new NotificaService();
currentDate = new Date();
elemDefault = new Notifica(123, 'EMAIL', 'RICHIESTA_CREATA', 'AAAAAAA', false, currentDate, 'AAAAAAA', currentDate);
});
describe('Service methods', () => {
it('should find an element', async () => {
const returnedFromService = {
inviataAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
axiosStub.get.resolves({ data: returnedFromService });
return service.find(123).then(res => {
expect(res).toMatchObject(elemDefault);
});
});
it('should not find an element', async () => {
axiosStub.get.rejects(error);
return service
.find(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should create a Notifica', async () => {
const returnedFromService = {
id: 123,
inviataAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { inviataAt: currentDate, createdAt: currentDate, ...returnedFromService };
axiosStub.post.resolves({ data: returnedFromService });
return service.create({}).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not create a Notifica', async () => {
axiosStub.post.rejects(error);
return service
.create({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should update a Notifica', async () => {
const returnedFromService = {
tipoCanale: 'BBBBBB',
tipoEvento: 'BBBBBB',
messaggio: 'BBBBBB',
inviata: true,
inviataAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
errore: 'BBBBBB',
createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { inviataAt: currentDate, createdAt: currentDate, ...returnedFromService };
axiosStub.put.resolves({ data: returnedFromService });
return service.update(expected).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not update a Notifica', async () => {
axiosStub.put.rejects(error);
return service
.update({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should partial update a Notifica', async () => {
const patchObject = {
tipoEvento: 'BBBBBB',
messaggio: 'BBBBBB',
inviataAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
errore: 'BBBBBB',
...new Notifica(),
};
const returnedFromService = Object.assign(patchObject, elemDefault);
const expected = { inviataAt: currentDate, createdAt: currentDate, ...returnedFromService };
axiosStub.patch.resolves({ data: returnedFromService });
return service.partialUpdate(patchObject).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not partial update a Notifica', async () => {
axiosStub.patch.rejects(error);
return service
.partialUpdate({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should return a list of Notifica', async () => {
const returnedFromService = {
tipoCanale: 'BBBBBB',
tipoEvento: 'BBBBBB',
messaggio: 'BBBBBB',
inviata: true,
inviataAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
errore: 'BBBBBB',
createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { inviataAt: currentDate, createdAt: currentDate, ...returnedFromService };
axiosStub.get.resolves([returnedFromService]);
return service.retrieve({ sort: {}, page: 0, size: 10 }).then(res => {
expect(res).toContainEqual(expected);
});
});
it('should not return a list of Notifica', async () => {
axiosStub.get.rejects(error);
return service
.retrieve()
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should delete a Notifica', async () => {
axiosStub.delete.resolves({ ok: true });
return service.delete(123).then(res => {
expect(res.ok).toBeTruthy();
});
});
it('should not delete a Notifica', async () => {
axiosStub.delete.rejects(error);
return service
.delete(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
});
});
});

View File

@@ -0,0 +1,86 @@
import axios from 'axios';
import { type INotifica } from '@/shared/model/notifica.model';
import buildPaginationQueryOpts from '@/shared/sort/sorts';
const baseApiUrl = 'api/notificas';
export default class NotificaService {
find(id: number): Promise<INotifica> {
return new Promise<INotifica>((resolve, reject) => {
axios
.get(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
retrieve(paginationQuery?: any): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.get(`${baseApiUrl}?${buildPaginationQueryOpts(paginationQuery)}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
delete(id: number): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.delete(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
create(entity: INotifica): Promise<INotifica> {
return new Promise<INotifica>((resolve, reject) => {
axios
.post(baseApiUrl, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
update(entity: INotifica): Promise<INotifica> {
return new Promise<INotifica>((resolve, reject) => {
axios
.put(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
partialUpdate(entity: INotifica): Promise<INotifica> {
return new Promise<INotifica>((resolve, reject) => {
axios
.patch(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
}

View File

@@ -0,0 +1,156 @@
<template>
<div>
<h2 id="page-heading" data-cy="NotificaHeading">
<span id="notifica">{{ t$('smartbookingApp.notifica.home.title') }}</span>
<div class="d-flex justify-content-end">
<button class="btn btn-info me-2" @click="handleSyncList" :disabled="isFetching">
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
<span>{{ t$('smartbookingApp.notifica.home.refreshListLabel') }}</span>
</button>
<router-link :to="{ name: 'NotificaCreate' }" custom v-slot="{ navigate }">
<button
@click="navigate"
id="jh-create-entity"
data-cy="entityCreateButton"
class="btn btn-primary jh-create-entity create-notifica"
>
<font-awesome-icon icon="plus"></font-awesome-icon>
<span>{{ t$('smartbookingApp.notifica.home.createLabel') }}</span>
</button>
</router-link>
</div>
</h2>
<br />
<div class="alert alert-warning" v-if="!isFetching && notificas?.length === 0">
<span>{{ t$('smartbookingApp.notifica.home.notFound') }}</span>
</div>
<div class="table-responsive" v-if="notificas?.length > 0">
<table class="table table-striped" aria-describedby="notificas">
<thead>
<tr>
<th scope="col" @click="changeOrder('id')">
<span>{{ t$('global.field.id') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'id'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('tipoCanale')">
<span>{{ t$('smartbookingApp.notifica.tipoCanale') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'tipoCanale'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('tipoEvento')">
<span>{{ t$('smartbookingApp.notifica.tipoEvento') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'tipoEvento'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('messaggio')">
<span>{{ t$('smartbookingApp.notifica.messaggio') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'messaggio'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('inviata')">
<span>{{ t$('smartbookingApp.notifica.inviata') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'inviata'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('inviataAt')">
<span>{{ t$('smartbookingApp.notifica.inviataAt') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'inviataAt'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('errore')">
<span>{{ t$('smartbookingApp.notifica.errore') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'errore'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('createdAt')">
<span>{{ t$('smartbookingApp.notifica.createdAt') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'createdAt'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('conferma.id')">
<span>{{ t$('smartbookingApp.notifica.conferma') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'conferma.id'"></jhi-sort-indicator>
</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="notifica in notificas" :key="notifica.id" data-cy="entityTable">
<td>
<router-link :to="{ name: 'NotificaView', params: { notificaId: notifica.id } }">{{ notifica.id }}</router-link>
</td>
<td>{{ t$('smartbookingApp.TipoCanaleNotifica.' + notifica.tipoCanale) }}</td>
<td>{{ t$('smartbookingApp.TipoEventoNotifica.' + notifica.tipoEvento) }}</td>
<td>{{ notifica.messaggio }}</td>
<td>{{ notifica.inviata }}</td>
<td>{{ formatDateShort(notifica.inviataAt) || '' }}</td>
<td>{{ notifica.errore }}</td>
<td>{{ formatDateShort(notifica.createdAt) || '' }}</td>
<td>
<div v-if="notifica.conferma">
<router-link :to="{ name: 'ConfermaView', params: { confermaId: notifica.conferma.id } }">{{
notifica.conferma.id
}}</router-link>
</div>
</td>
<td class="text-end">
<div class="btn-group">
<router-link
:to="{ name: 'NotificaView', params: { notificaId: notifica.id } }"
class="btn btn-info btn-sm details"
data-cy="entityDetailsButton"
>
<font-awesome-icon icon="eye"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
</router-link>
<router-link
:to="{ name: 'NotificaEdit', params: { notificaId: notifica.id } }"
class="btn btn-primary btn-sm edit"
data-cy="entityEditButton"
>
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.edit') }}</span>
</router-link>
<b-button
@click="prepareRemove(notifica)"
variant="danger"
class="btn btn-sm"
data-cy="entityDeleteButton"
v-b-modal.removeEntity
>
<font-awesome-icon icon="times"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
</b-button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<b-modal ref="removeEntity" id="removeEntity">
<template #title>
<span id="smartbookingApp.notifica.delete.question" data-cy="notificaDeleteDialogHeading">{{ t$('entity.delete.title') }}</span>
</template>
<div class="modal-body">
<p id="jhi-delete-notifica-heading">{{ t$('smartbookingApp.notifica.delete.question', { id: removeId }) }}</p>
</div>
<template #footer>
<div>
<button type="button" class="btn btn-secondary" @click="closeDialog()">{{ t$('entity.action.cancel') }}</button>
<button
type="button"
class="btn btn-primary"
id="jhi-confirm-delete-notifica"
data-cy="entityConfirmDeleteButton"
@click="removeNotifica"
>
{{ t$('entity.action.delete') }}
</button>
</div>
</template>
</b-modal>
<div v-show="notificas?.length > 0">
<div class="d-flex justify-content-center">
<jhi-item-count :page="page" :total="queryCount" :items-per-page="itemsPerPage"></jhi-item-count>
</div>
<div class="d-flex justify-content-center">
<b-pagination size="md" :total-rows="totalItems" v-model="page" :per-page="itemsPerPage"></b-pagination>
</div>
</div>
</div>
</template>
<script lang="ts" src="./notifica.component.ts"></script>

View File

@@ -0,0 +1,91 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import PrenotazioneDetails from './prenotazione-details.vue';
import PrenotazioneService from './prenotazione.service';
type PrenotazioneDetailsComponentType = InstanceType<typeof PrenotazioneDetails>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const prenotazioneSample = { id: 123 };
describe('Component Tests', () => {
let alertService: AlertService;
afterEach(() => {
vitest.resetAllMocks();
});
describe('Prenotazione Management Detail Component', () => {
let prenotazioneServiceStub: SinonStubbedInstance<PrenotazioneService>;
let mountOptions: MountingOptions<PrenotazioneDetailsComponentType>['global'];
beforeEach(() => {
route = {};
prenotazioneServiceStub = sinon.createStubInstance<PrenotazioneService>(PrenotazioneService);
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'router-link': true,
},
provide: {
alertService,
prenotazioneService: () => prenotazioneServiceStub,
},
};
});
describe('Navigate to details', () => {
it('Should call load all on init', async () => {
// GIVEN
prenotazioneServiceStub.find.resolves(prenotazioneSample);
route = {
params: {
prenotazioneId: `${123}`,
},
};
const wrapper = shallowMount(PrenotazioneDetails, { global: mountOptions });
const comp = wrapper.vm;
// WHEN
await comp.$nextTick();
// THEN
expect(comp.prenotazione).toMatchObject(prenotazioneSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
prenotazioneServiceStub.find.resolves(prenotazioneSample);
const wrapper = shallowMount(PrenotazioneDetails, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,46 @@
import { type Ref, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type IPrenotazione } from '@/shared/model/prenotazione.model';
import PrenotazioneService from './prenotazione.service';
export default defineComponent({
name: 'PrenotazioneDetails',
setup() {
const dateFormat = useDateFormat();
const prenotazioneService = inject('prenotazioneService', () => new PrenotazioneService());
const alertService = inject('alertService', () => useAlertService(), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const prenotazione: Ref<IPrenotazione> = ref({});
const retrievePrenotazione = async prenotazioneId => {
try {
const res = await prenotazioneService().find(prenotazioneId);
prenotazione.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.prenotazioneId) {
retrievePrenotazione(route.params.prenotazioneId);
}
return {
...dateFormat,
alertService,
prenotazione,
previousState,
t$: useI18n().t,
};
},
});

View File

@@ -0,0 +1,94 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<div v-if="prenotazione">
<h2 class="jh-entity-heading" data-cy="prenotazioneDetailsHeading">
<span>{{ t$('smartbookingApp.prenotazione.detail.title') }}Prenotazione</span> {{ prenotazione.id }}
</h2>
<dl class="row-md jh-entity-details">
<dt>
<span>{{ t$('smartbookingApp.prenotazione.oraInizio') }}</span>
</dt>
<dd>
<span v-if="prenotazione.oraInizio">{{ formatDateLong(prenotazione.oraInizio) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.prenotazione.oraFine') }}</span>
</dt>
<dd>
<span v-if="prenotazione.oraFine">{{ formatDateLong(prenotazione.oraFine) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.prenotazione.stato') }}</span>
</dt>
<dd>
<span>{{ t$('smartbookingApp.StatoPrenotazione.' + prenotazione.stato) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.prenotazione.motivoEvento') }}</span>
</dt>
<dd>
<span>{{ prenotazione.motivoEvento }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.prenotazione.numeroPartecipanti') }}</span>
</dt>
<dd>
<span>{{ prenotazione.numeroPartecipanti }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.prenotazione.noteUtente') }}</span>
</dt>
<dd>
<span>{{ prenotazione.noteUtente }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.prenotazione.conferma') }}</span>
</dt>
<dd>
<div v-if="prenotazione.conferma">
<router-link :to="{ name: 'ConfermaView', params: { confermaId: prenotazione.conferma.id } }">{{
prenotazione.conferma.id
}}</router-link>
</div>
</dd>
<dt>
<span>{{ t$('smartbookingApp.prenotazione.utente') }}</span>
</dt>
<dd>
<div v-if="prenotazione.utente">
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: prenotazione.utente.id } }">{{
prenotazione.utente.username
}}</router-link>
</div>
</dd>
<dt>
<span>{{ t$('smartbookingApp.prenotazione.struttura') }}</span>
</dt>
<dd>
<div v-if="prenotazione.struttura">
<router-link :to="{ name: 'StrutturaView', params: { strutturaId: prenotazione.struttura.id } }">{{
prenotazione.struttura.nome
}}</router-link>
</div>
</dd>
</dl>
<button type="submit" @click.prevent="previousState()" class="btn btn-info" data-cy="entityDetailsBackButton">
<font-awesome-icon icon="arrow-left"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.back') }}</span>
</button>
<router-link
v-if="prenotazione.id"
:to="{ name: 'PrenotazioneEdit', params: { prenotazioneId: prenotazione.id } }"
custom
v-slot="{ navigate }"
>
<button @click="navigate" class="btn btn-primary">
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.edit') }}</span>
</button>
</router-link>
</div>
</div>
</div>
</template>
<script lang="ts" src="./prenotazione-details.component.ts"></script>

View File

@@ -0,0 +1,171 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import dayjs from 'dayjs';
import sinon, { type SinonStubbedInstance } from 'sinon';
import ConfermaService from '@/entities/conferma/conferma.service';
import StrutturaService from '@/entities/struttura/struttura.service';
import UtenteAppService from '@/entities/utente-app/utente-app.service';
import AlertService from '@/shared/alert/alert.service';
import { DATE_TIME_LONG_FORMAT } from '@/shared/composables/date-format';
import PrenotazioneUpdate from './prenotazione-update.vue';
import PrenotazioneService from './prenotazione.service';
type PrenotazioneUpdateComponentType = InstanceType<typeof PrenotazioneUpdate>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const prenotazioneSample = { id: 123 };
describe('Component Tests', () => {
let mountOptions: MountingOptions<PrenotazioneUpdateComponentType>['global'];
let alertService: AlertService;
describe('Prenotazione Management Update Component', () => {
let comp: PrenotazioneUpdateComponentType;
let prenotazioneServiceStub: SinonStubbedInstance<PrenotazioneService>;
beforeEach(() => {
route = {};
prenotazioneServiceStub = sinon.createStubInstance<PrenotazioneService>(PrenotazioneService);
prenotazioneServiceStub.retrieve.onFirstCall().resolves(Promise.resolve([]));
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'b-input-group': true,
'b-input-group-prepend': true,
'b-form-datepicker': true,
'b-form-input': true,
},
provide: {
alertService,
prenotazioneService: () => prenotazioneServiceStub,
confermaService: () =>
sinon.createStubInstance<ConfermaService>(ConfermaService, {
retrieve: sinon.stub().resolves({}),
} as any),
utenteAppService: () =>
sinon.createStubInstance<UtenteAppService>(UtenteAppService, {
retrieve: sinon.stub().resolves({}),
} as any),
strutturaService: () =>
sinon.createStubInstance<StrutturaService>(StrutturaService, {
retrieve: sinon.stub().resolves({}),
} as any),
},
};
});
afterEach(() => {
vitest.resetAllMocks();
});
describe('load', () => {
beforeEach(() => {
const wrapper = shallowMount(PrenotazioneUpdate, { global: mountOptions });
comp = wrapper.vm;
});
it('Should convert date from string', () => {
// GIVEN
const date = new Date('2019-10-15T11:42:02Z');
// WHEN
const convertedDate = comp.convertDateTimeFromServer(date);
// THEN
expect(convertedDate).toEqual(dayjs(date).format(DATE_TIME_LONG_FORMAT));
});
it('Should not convert date if date is not present', () => {
expect(comp.convertDateTimeFromServer(null)).toBeNull();
});
});
describe('save', () => {
it('Should call update service on save for existing entity', async () => {
// GIVEN
const wrapper = shallowMount(PrenotazioneUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.prenotazione = prenotazioneSample;
prenotazioneServiceStub.update.resolves(prenotazioneSample);
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(prenotazioneServiceStub.update.calledWith(prenotazioneSample)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
it('Should call create service on save for new entity', async () => {
// GIVEN
const entity = {};
prenotazioneServiceStub.create.resolves(entity);
const wrapper = shallowMount(PrenotazioneUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.prenotazione = entity;
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(prenotazioneServiceStub.create.calledWith(entity)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
});
describe('Before route enter', () => {
it('Should retrieve data', async () => {
// GIVEN
prenotazioneServiceStub.find.resolves(prenotazioneSample);
prenotazioneServiceStub.retrieve.resolves([prenotazioneSample]);
// WHEN
route = {
params: {
prenotazioneId: `${prenotazioneSample.id}`,
},
};
const wrapper = shallowMount(PrenotazioneUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(comp.prenotazione).toMatchObject(prenotazioneSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
prenotazioneServiceStub.find.resolves(prenotazioneSample);
const wrapper = shallowMount(PrenotazioneUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,146 @@
import { type Ref, computed, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useVuelidate } from '@vuelidate/core';
import ConfermaService from '@/entities/conferma/conferma.service';
import StrutturaService from '@/entities/struttura/struttura.service';
import UtenteAppService from '@/entities/utente-app/utente-app.service';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat, useValidation } from '@/shared/composables';
import { type IConferma } from '@/shared/model/conferma.model';
import { StatoPrenotazione } from '@/shared/model/enumerations/stato-prenotazione.model';
import { type IPrenotazione, Prenotazione } from '@/shared/model/prenotazione.model';
import { type IStruttura } from '@/shared/model/struttura.model';
import { type IUtenteApp } from '@/shared/model/utente-app.model';
import PrenotazioneService from './prenotazione.service';
export default defineComponent({
name: 'PrenotazioneUpdate',
setup() {
const prenotazioneService = inject('prenotazioneService', () => new PrenotazioneService());
const alertService = inject('alertService', () => useAlertService(), true);
const prenotazione: Ref<IPrenotazione> = ref(new Prenotazione());
const confermaService = inject('confermaService', () => new ConfermaService());
const confermas: Ref<IConferma[]> = ref([]);
const utenteAppService = inject('utenteAppService', () => new UtenteAppService());
const utenteApps: Ref<IUtenteApp[]> = ref([]);
const strutturaService = inject('strutturaService', () => new StrutturaService());
const strutturas: Ref<IStruttura[]> = ref([]);
const statoPrenotazioneValues: Ref<string[]> = ref(Object.keys(StatoPrenotazione));
const isSaving = ref(false);
const currentLanguage = inject('currentLanguage', () => computed(() => navigator.language ?? 'it'), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const retrievePrenotazione = async prenotazioneId => {
try {
const res = await prenotazioneService().find(prenotazioneId);
res.oraInizio = new Date(res.oraInizio);
res.oraFine = new Date(res.oraFine);
prenotazione.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.prenotazioneId) {
retrievePrenotazione(route.params.prenotazioneId);
}
const initRelationships = () => {
confermaService()
.retrieve()
.then(res => {
confermas.value = res.data;
});
utenteAppService()
.retrieve()
.then(res => {
utenteApps.value = res.data;
});
strutturaService()
.retrieve()
.then(res => {
strutturas.value = res.data;
});
};
initRelationships();
const { t: t$ } = useI18n();
const validations = useValidation();
const validationRules = {
oraInizio: {},
oraFine: {},
stato: {},
motivoEvento: {},
numeroPartecipanti: {},
noteUtente: {},
conferma: {},
utente: {},
struttura: {},
};
const v$ = useVuelidate(validationRules, prenotazione as any);
v$.value.$validate();
return {
prenotazioneService,
alertService,
prenotazione,
previousState,
statoPrenotazioneValues,
isSaving,
currentLanguage,
confermas,
utenteApps,
strutturas,
v$,
...useDateFormat({ entityRef: prenotazione }),
t$,
};
},
created(): void {},
methods: {
save(): void {
this.isSaving = true;
if (this.prenotazione.id) {
this.prenotazioneService()
.update(this.prenotazione)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showInfo(this.t$('smartbookingApp.prenotazione.updated', { param: param.id }));
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
} else {
this.prenotazioneService()
.create(this.prenotazione)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showSuccess(this.t$('smartbookingApp.prenotazione.created', { param: param.id }).toString());
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
}
},
},
});

View File

@@ -0,0 +1,159 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<form name="editForm" novalidate @submit.prevent="save()">
<h2 id="smartbookingApp.prenotazione.home.createOrEditLabel" data-cy="PrenotazioneCreateUpdateHeading">
{{ t$('smartbookingApp.prenotazione.home.createOrEditLabel') }}
</h2>
<div>
<div class="mb-3" v-if="prenotazione.id">
<label for="id">{{ t$('global.field.id') }}</label>
<input type="text" class="form-control" id="id" name="id" v-model="prenotazione.id" readonly />
</div>
<div class="mb-3">
<label class="form-control-label" for="prenotazione">{{ t$('smartbookingApp.prenotazione.oraInizio') }}</label>
<div class="d-flex">
<input
id="prenotazione-oraInizio"
data-cy="oraInizio"
type="datetime-local"
class="form-control"
name="oraInizio"
:class="{ valid: !v$.oraInizio.$invalid, invalid: v$.oraInizio.$invalid }"
:value="convertDateTimeFromServer(v$.oraInizio.$model)"
@change="updateInstantField('oraInizio', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="prenotazione">{{ t$('smartbookingApp.prenotazione.oraFine') }}</label>
<div class="d-flex">
<input
id="prenotazione-oraFine"
data-cy="oraFine"
type="datetime-local"
class="form-control"
name="oraFine"
:class="{ valid: !v$.oraFine.$invalid, invalid: v$.oraFine.$invalid }"
:value="convertDateTimeFromServer(v$.oraFine.$model)"
@change="updateInstantField('oraFine', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="prenotazione">{{ t$('smartbookingApp.prenotazione.stato') }}</label>
<select
class="form-control"
name="stato"
:class="{ valid: !v$.stato.$invalid, invalid: v$.stato.$invalid }"
v-model="v$.stato.$model"
id="prenotazione-stato"
data-cy="stato"
>
<option
v-for="statoPrenotazione in statoPrenotazioneValues"
:key="statoPrenotazione"
:value="statoPrenotazione"
:label="t$('smartbookingApp.StatoPrenotazione.' + statoPrenotazione)"
>
{{ statoPrenotazione }}
</option>
</select>
</div>
<div class="mb-3">
<label class="form-control-label" for="prenotazione">{{ t$('smartbookingApp.prenotazione.motivoEvento') }}</label>
<input
type="text"
class="form-control"
name="motivoEvento"
id="prenotazione-motivoEvento"
data-cy="motivoEvento"
:class="{ valid: !v$.motivoEvento.$invalid, invalid: v$.motivoEvento.$invalid }"
v-model="v$.motivoEvento.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="prenotazione">{{ t$('smartbookingApp.prenotazione.numeroPartecipanti') }}</label>
<input
type="number"
class="form-control"
name="numeroPartecipanti"
id="prenotazione-numeroPartecipanti"
data-cy="numeroPartecipanti"
:class="{ valid: !v$.numeroPartecipanti.$invalid, invalid: v$.numeroPartecipanti.$invalid }"
v-model.number="v$.numeroPartecipanti.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="prenotazione">{{ t$('smartbookingApp.prenotazione.noteUtente') }}</label>
<input
type="text"
class="form-control"
name="noteUtente"
id="prenotazione-noteUtente"
data-cy="noteUtente"
:class="{ valid: !v$.noteUtente.$invalid, invalid: v$.noteUtente.$invalid }"
v-model="v$.noteUtente.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="prenotazione">{{ t$('smartbookingApp.prenotazione.conferma') }}</label>
<select class="form-control" id="prenotazione-conferma" data-cy="conferma" name="conferma" v-model="prenotazione.conferma">
<option :value="null"></option>
<option
:value="prenotazione.conferma && confermaOption.id === prenotazione.conferma.id ? prenotazione.conferma : confermaOption"
v-for="confermaOption in confermas"
:key="confermaOption.id"
>
{{ confermaOption.id }}
</option>
</select>
</div>
<div class="mb-3">
<label class="form-control-label" for="prenotazione">{{ t$('smartbookingApp.prenotazione.utente') }}</label>
<select class="form-control" id="prenotazione-utente" data-cy="utente" name="utente" v-model="prenotazione.utente">
<option :value="null"></option>
<option
:value="prenotazione.utente && utenteAppOption.id === prenotazione.utente.id ? prenotazione.utente : utenteAppOption"
v-for="utenteAppOption in utenteApps"
:key="utenteAppOption.id"
>
{{ utenteAppOption.username }}
</option>
</select>
</div>
<div class="mb-3">
<label class="form-control-label" for="prenotazione">{{ t$('smartbookingApp.prenotazione.struttura') }}</label>
<select class="form-control" id="prenotazione-struttura" data-cy="struttura" name="struttura" v-model="prenotazione.struttura">
<option :value="null"></option>
<option
:value="
prenotazione.struttura && strutturaOption.id === prenotazione.struttura.id ? prenotazione.struttura : strutturaOption
"
v-for="strutturaOption in strutturas"
:key="strutturaOption.id"
>
{{ strutturaOption.nome }}
</option>
</select>
</div>
</div>
<div>
<button type="button" id="cancel-save" data-cy="entityCreateCancelButton" class="btn btn-secondary" @click="previousState()">
<font-awesome-icon icon="ban"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.cancel') }}</span>
</button>
<button
type="submit"
id="save-entity"
data-cy="entityCreateSaveButton"
:disabled="v$.$invalid || isSaving"
class="btn btn-primary"
>
<font-awesome-icon icon="save"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.save') }}</span>
</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts" src="./prenotazione-update.component.ts"></script>

View File

@@ -0,0 +1,166 @@
import { vitest } from 'vitest';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import PrenotazioneService from './prenotazione.service';
import Prenotazione from './prenotazione.vue';
type PrenotazioneComponentType = InstanceType<typeof Prenotazione>;
const bModalStub = {
render: () => {},
methods: {
hide: () => {},
show: () => {},
},
};
describe('Component Tests', () => {
let alertService: AlertService;
describe('Prenotazione Management Component', () => {
let prenotazioneServiceStub: SinonStubbedInstance<PrenotazioneService>;
let mountOptions: MountingOptions<PrenotazioneComponentType>['global'];
beforeEach(() => {
prenotazioneServiceStub = sinon.createStubInstance<PrenotazioneService>(PrenotazioneService);
prenotazioneServiceStub.retrieve.resolves({ headers: {} });
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
jhiItemCount: true,
bPagination: true,
bModal: bModalStub as any,
'font-awesome-icon': true,
'b-badge': true,
'jhi-sort-indicator': true,
'b-button': true,
'router-link': true,
},
directives: {
'b-modal': {},
},
provide: {
alertService,
prenotazioneService: () => prenotazioneServiceStub,
},
};
});
describe('Mount', () => {
it('Should call load all on init', async () => {
// GIVEN
prenotazioneServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
const wrapper = shallowMount(Prenotazione, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(prenotazioneServiceStub.retrieve.calledOnce).toBeTruthy();
expect(comp.prenotaziones[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for an id', async () => {
// WHEN
const wrapper = shallowMount(Prenotazione, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(prenotazioneServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['id,asc'],
});
});
});
describe('Handles', () => {
let comp: PrenotazioneComponentType;
beforeEach(async () => {
const wrapper = shallowMount(Prenotazione, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
prenotazioneServiceStub.retrieve.reset();
prenotazioneServiceStub.retrieve.resolves({ headers: {}, data: [] });
});
it('should load a page', async () => {
// GIVEN
prenotazioneServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.page = 2;
await comp.$nextTick();
// THEN
expect(prenotazioneServiceStub.retrieve.called).toBeTruthy();
expect(comp.prenotaziones[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should not load a page if the page is the same as the previous page', () => {
// WHEN
comp.page = 1;
// THEN
expect(prenotazioneServiceStub.retrieve.called).toBeFalsy();
});
it('should re-initialize the page', async () => {
// GIVEN
comp.page = 2;
await comp.$nextTick();
prenotazioneServiceStub.retrieve.reset();
prenotazioneServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.clear();
await comp.$nextTick();
// THEN
expect(comp.page).toEqual(1);
expect(prenotazioneServiceStub.retrieve.callCount).toEqual(1);
expect(comp.prenotaziones[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for a non-id attribute', async () => {
// WHEN
comp.propOrder = 'name';
await comp.$nextTick();
// THEN
expect(prenotazioneServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['name,asc', 'id'],
});
});
it('Should call delete service on confirmDelete', async () => {
// GIVEN
prenotazioneServiceStub.delete.resolves({});
// WHEN
comp.prepareRemove({ id: 123 });
comp.removePrenotazione();
await comp.$nextTick(); // clear components
// THEN
expect(prenotazioneServiceStub.delete.called).toBeTruthy();
// THEN
await comp.$nextTick(); // handle component clear watch
expect(prenotazioneServiceStub.retrieve.callCount).toEqual(1);
});
});
});
});

View File

@@ -0,0 +1,137 @@
import { type Ref, defineComponent, inject, onMounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type IPrenotazione } from '@/shared/model/prenotazione.model';
import PrenotazioneService from './prenotazione.service';
export default defineComponent({
name: 'Prenotazione',
setup() {
const { t: t$ } = useI18n();
const dateFormat = useDateFormat();
const prenotazioneService = inject('prenotazioneService', () => new PrenotazioneService());
const alertService = inject('alertService', () => useAlertService(), true);
const itemsPerPage = ref(20);
const queryCount: Ref<number> = ref(null);
const page: Ref<number> = ref(1);
const propOrder = ref('id');
const reverse = ref(false);
const totalItems = ref(0);
const prenotaziones: Ref<IPrenotazione[]> = ref([]);
const isFetching = ref(false);
const clear = () => {
page.value = 1;
};
const sort = (): Array<any> => {
const result = [`${propOrder.value},${reverse.value ? 'desc' : 'asc'}`];
if (propOrder.value !== 'id') {
result.push('id');
}
return result;
};
const retrievePrenotaziones = async () => {
isFetching.value = true;
try {
const paginationQuery = {
page: page.value - 1,
size: itemsPerPage.value,
sort: sort(),
};
const res = await prenotazioneService().retrieve(paginationQuery);
totalItems.value = Number(res.headers['x-total-count']);
queryCount.value = totalItems.value;
prenotaziones.value = res.data;
} catch (err) {
alertService.showHttpError(err.response);
} finally {
isFetching.value = false;
}
};
const handleSyncList = () => {
retrievePrenotaziones();
};
onMounted(async () => {
await retrievePrenotaziones();
});
const removeId: Ref<number> = ref(null);
const removeEntity = ref<any>(null);
const prepareRemove = (instance: IPrenotazione) => {
removeId.value = instance.id;
removeEntity.value.show();
};
const closeDialog = () => {
removeEntity.value.hide();
};
const removePrenotazione = async () => {
try {
await prenotazioneService().delete(removeId.value);
const message = t$('smartbookingApp.prenotazione.deleted', { param: removeId.value }).toString();
alertService.showInfo(message, { variant: 'danger' });
removeId.value = null;
retrievePrenotaziones();
closeDialog();
} catch (error) {
alertService.showHttpError(error.response);
}
};
const changeOrder = (newOrder: string) => {
if (propOrder.value === newOrder) {
reverse.value = !reverse.value;
} else {
reverse.value = false;
}
propOrder.value = newOrder;
};
// Whenever order changes, reset the pagination
watch([propOrder, reverse], async () => {
if (page.value === 1) {
// first page, retrieve new data
await retrievePrenotaziones();
} else {
// reset the pagination
clear();
}
});
// Whenever page changes, switch to the new page.
watch(page, async () => {
await retrievePrenotaziones();
});
return {
prenotaziones,
handleSyncList,
isFetching,
retrievePrenotaziones,
clear,
...dateFormat,
removeId,
removeEntity,
prepareRemove,
closeDialog,
removePrenotazione,
itemsPerPage,
queryCount,
page,
propOrder,
reverse,
totalItems,
changeOrder,
t$,
};
},
});

View File

@@ -0,0 +1,195 @@
import axios from 'axios';
import dayjs from 'dayjs';
import sinon from 'sinon';
import { DATE_TIME_FORMAT } from '@/shared/composables/date-format';
import { Prenotazione } from '@/shared/model/prenotazione.model';
import PrenotazioneService from './prenotazione.service';
const error = {
response: {
status: null,
data: {
type: null,
},
},
};
const axiosStub = {
get: sinon.stub(axios, 'get'),
post: sinon.stub(axios, 'post'),
put: sinon.stub(axios, 'put'),
patch: sinon.stub(axios, 'patch'),
delete: sinon.stub(axios, 'delete'),
};
describe('Service Tests', () => {
describe('Prenotazione Service', () => {
let service: PrenotazioneService;
let elemDefault;
let currentDate: Date;
beforeEach(() => {
service = new PrenotazioneService();
currentDate = new Date();
elemDefault = new Prenotazione(123, currentDate, currentDate, 'RICHIESTA', 'AAAAAAA', 0, 'AAAAAAA');
});
describe('Service methods', () => {
it('should find an element', async () => {
const returnedFromService = {
oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
axiosStub.get.resolves({ data: returnedFromService });
return service.find(123).then(res => {
expect(res).toMatchObject(elemDefault);
});
});
it('should not find an element', async () => {
axiosStub.get.rejects(error);
return service
.find(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should create a Prenotazione', async () => {
const returnedFromService = {
id: 123,
oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };
axiosStub.post.resolves({ data: returnedFromService });
return service.create({}).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not create a Prenotazione', async () => {
axiosStub.post.rejects(error);
return service
.create({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should update a Prenotazione', async () => {
const returnedFromService = {
oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
stato: 'BBBBBB',
motivoEvento: 'BBBBBB',
numeroPartecipanti: 1,
noteUtente: 'BBBBBB',
...elemDefault,
};
const expected = { oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };
axiosStub.put.resolves({ data: returnedFromService });
return service.update(expected).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not update a Prenotazione', async () => {
axiosStub.put.rejects(error);
return service
.update({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should partial update a Prenotazione', async () => {
const patchObject = {
oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
motivoEvento: 'BBBBBB',
noteUtente: 'BBBBBB',
...new Prenotazione(),
};
const returnedFromService = Object.assign(patchObject, elemDefault);
const expected = { oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };
axiosStub.patch.resolves({ data: returnedFromService });
return service.partialUpdate(patchObject).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not partial update a Prenotazione', async () => {
axiosStub.patch.rejects(error);
return service
.partialUpdate({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should return a list of Prenotazione', async () => {
const returnedFromService = {
oraInizio: dayjs(currentDate).format(DATE_TIME_FORMAT),
oraFine: dayjs(currentDate).format(DATE_TIME_FORMAT),
stato: 'BBBBBB',
motivoEvento: 'BBBBBB',
numeroPartecipanti: 1,
noteUtente: 'BBBBBB',
...elemDefault,
};
const expected = { oraInizio: currentDate, oraFine: currentDate, ...returnedFromService };
axiosStub.get.resolves([returnedFromService]);
return service.retrieve({ sort: {}, page: 0, size: 10 }).then(res => {
expect(res).toContainEqual(expected);
});
});
it('should not return a list of Prenotazione', async () => {
axiosStub.get.rejects(error);
return service
.retrieve()
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should delete a Prenotazione', async () => {
axiosStub.delete.resolves({ ok: true });
return service.delete(123).then(res => {
expect(res.ok).toBeTruthy();
});
});
it('should not delete a Prenotazione', async () => {
axiosStub.delete.rejects(error);
return service
.delete(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
});
});
});

View File

@@ -0,0 +1,86 @@
import axios from 'axios';
import { type IPrenotazione } from '@/shared/model/prenotazione.model';
import buildPaginationQueryOpts from '@/shared/sort/sorts';
const baseApiUrl = 'api/prenotaziones';
export default class PrenotazioneService {
find(id: number): Promise<IPrenotazione> {
return new Promise<IPrenotazione>((resolve, reject) => {
axios
.get(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
retrieve(paginationQuery?: any): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.get(`${baseApiUrl}?${buildPaginationQueryOpts(paginationQuery)}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
delete(id: number): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.delete(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
create(entity: IPrenotazione): Promise<IPrenotazione> {
return new Promise<IPrenotazione>((resolve, reject) => {
axios
.post(baseApiUrl, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
update(entity: IPrenotazione): Promise<IPrenotazione> {
return new Promise<IPrenotazione>((resolve, reject) => {
axios
.put(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
partialUpdate(entity: IPrenotazione): Promise<IPrenotazione> {
return new Promise<IPrenotazione>((resolve, reject) => {
axios
.patch(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
}

View File

@@ -0,0 +1,177 @@
<template>
<div>
<h2 id="page-heading" data-cy="PrenotazioneHeading">
<span id="prenotazione">{{ t$('smartbookingApp.prenotazione.home.title') }}</span>
<div class="d-flex justify-content-end">
<button class="btn btn-info me-2" @click="handleSyncList" :disabled="isFetching">
<font-awesome-icon icon="sync" :spin="isFetching"></font-awesome-icon>
<span>{{ t$('smartbookingApp.prenotazione.home.refreshListLabel') }}</span>
</button>
<router-link :to="{ name: 'PrenotazioneCreate' }" custom v-slot="{ navigate }">
<button
@click="navigate"
id="jh-create-entity"
data-cy="entityCreateButton"
class="btn btn-primary jh-create-entity create-prenotazione"
>
<font-awesome-icon icon="plus"></font-awesome-icon>
<span>{{ t$('smartbookingApp.prenotazione.home.createLabel') }}</span>
</button>
</router-link>
</div>
</h2>
<br />
<div class="alert alert-warning" v-if="!isFetching && prenotaziones?.length === 0">
<span>{{ t$('smartbookingApp.prenotazione.home.notFound') }}</span>
</div>
<div class="table-responsive" v-if="prenotaziones?.length > 0">
<table class="table table-striped" aria-describedby="prenotaziones">
<thead>
<tr>
<th scope="col" @click="changeOrder('id')">
<span>{{ t$('global.field.id') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'id'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('oraInizio')">
<span>{{ t$('smartbookingApp.prenotazione.oraInizio') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'oraInizio'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('oraFine')">
<span>{{ t$('smartbookingApp.prenotazione.oraFine') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'oraFine'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('stato')">
<span>{{ t$('smartbookingApp.prenotazione.stato') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'stato'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('motivoEvento')">
<span>{{ t$('smartbookingApp.prenotazione.motivoEvento') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'motivoEvento'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('numeroPartecipanti')">
<span>{{ t$('smartbookingApp.prenotazione.numeroPartecipanti') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'numeroPartecipanti'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('noteUtente')">
<span>{{ t$('smartbookingApp.prenotazione.noteUtente') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'noteUtente'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('conferma.id')">
<span>{{ t$('smartbookingApp.prenotazione.conferma') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'conferma.id'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('utente.username')">
<span>{{ t$('smartbookingApp.prenotazione.utente') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'utente.username'"></jhi-sort-indicator>
</th>
<th scope="col" @click="changeOrder('struttura.nome')">
<span>{{ t$('smartbookingApp.prenotazione.struttura') }}</span>
<jhi-sort-indicator :current-order="propOrder" :reverse="reverse" :field-name="'struttura.nome'"></jhi-sort-indicator>
</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr v-for="prenotazione in prenotaziones" :key="prenotazione.id" data-cy="entityTable">
<td>
<router-link :to="{ name: 'PrenotazioneView', params: { prenotazioneId: prenotazione.id } }">{{
prenotazione.id
}}</router-link>
</td>
<td>{{ formatDateShort(prenotazione.oraInizio) || '' }}</td>
<td>{{ formatDateShort(prenotazione.oraFine) || '' }}</td>
<td>{{ t$('smartbookingApp.StatoPrenotazione.' + prenotazione.stato) }}</td>
<td>{{ prenotazione.motivoEvento }}</td>
<td>{{ prenotazione.numeroPartecipanti }}</td>
<td>{{ prenotazione.noteUtente }}</td>
<td>
<div v-if="prenotazione.conferma">
<router-link :to="{ name: 'ConfermaView', params: { confermaId: prenotazione.conferma.id } }">{{
prenotazione.conferma.id
}}</router-link>
</div>
</td>
<td>
<div v-if="prenotazione.utente">
<router-link :to="{ name: 'UtenteAppView', params: { utenteAppId: prenotazione.utente.id } }">{{
prenotazione.utente.username
}}</router-link>
</div>
</td>
<td>
<div v-if="prenotazione.struttura">
<router-link :to="{ name: 'StrutturaView', params: { strutturaId: prenotazione.struttura.id } }">{{
prenotazione.struttura.nome
}}</router-link>
</div>
</td>
<td class="text-end">
<div class="btn-group">
<router-link
:to="{ name: 'PrenotazioneView', params: { prenotazioneId: prenotazione.id } }"
class="btn btn-info btn-sm details"
data-cy="entityDetailsButton"
>
<font-awesome-icon icon="eye"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.view') }}</span>
</router-link>
<router-link
:to="{ name: 'PrenotazioneEdit', params: { prenotazioneId: prenotazione.id } }"
class="btn btn-primary btn-sm edit"
data-cy="entityEditButton"
>
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.edit') }}</span>
</router-link>
<b-button
@click="prepareRemove(prenotazione)"
variant="danger"
class="btn btn-sm"
data-cy="entityDeleteButton"
v-b-modal.removeEntity
>
<font-awesome-icon icon="times"></font-awesome-icon>
<span class="d-none d-md-inline">{{ t$('entity.action.delete') }}</span>
</b-button>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<b-modal ref="removeEntity" id="removeEntity">
<template #title>
<span id="smartbookingApp.prenotazione.delete.question" data-cy="prenotazioneDeleteDialogHeading">{{
t$('entity.delete.title')
}}</span>
</template>
<div class="modal-body">
<p id="jhi-delete-prenotazione-heading">{{ t$('smartbookingApp.prenotazione.delete.question', { id: removeId }) }}</p>
</div>
<template #footer>
<div>
<button type="button" class="btn btn-secondary" @click="closeDialog()">{{ t$('entity.action.cancel') }}</button>
<button
type="button"
class="btn btn-primary"
id="jhi-confirm-delete-prenotazione"
data-cy="entityConfirmDeleteButton"
@click="removePrenotazione"
>
{{ t$('entity.action.delete') }}
</button>
</div>
</template>
</b-modal>
<div v-show="prenotaziones?.length > 0">
<div class="d-flex justify-content-center">
<jhi-item-count :page="page" :total="queryCount" :items-per-page="itemsPerPage"></jhi-item-count>
</div>
<div class="d-flex justify-content-center">
<b-pagination size="md" :total-rows="totalItems" v-model="page" :per-page="itemsPerPage"></b-pagination>
</div>
</div>
</div>
</template>
<script lang="ts" src="./prenotazione.component.ts"></script>

View File

@@ -0,0 +1,91 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import StrutturaDetails from './struttura-details.vue';
import StrutturaService from './struttura.service';
type StrutturaDetailsComponentType = InstanceType<typeof StrutturaDetails>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const strutturaSample = { id: 123 };
describe('Component Tests', () => {
let alertService: AlertService;
afterEach(() => {
vitest.resetAllMocks();
});
describe('Struttura Management Detail Component', () => {
let strutturaServiceStub: SinonStubbedInstance<StrutturaService>;
let mountOptions: MountingOptions<StrutturaDetailsComponentType>['global'];
beforeEach(() => {
route = {};
strutturaServiceStub = sinon.createStubInstance<StrutturaService>(StrutturaService);
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'router-link': true,
},
provide: {
alertService,
strutturaService: () => strutturaServiceStub,
},
};
});
describe('Navigate to details', () => {
it('Should call load all on init', async () => {
// GIVEN
strutturaServiceStub.find.resolves(strutturaSample);
route = {
params: {
strutturaId: `${123}`,
},
};
const wrapper = shallowMount(StrutturaDetails, { global: mountOptions });
const comp = wrapper.vm;
// WHEN
await comp.$nextTick();
// THEN
expect(comp.struttura).toMatchObject(strutturaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
strutturaServiceStub.find.resolves(strutturaSample);
const wrapper = shallowMount(StrutturaDetails, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,46 @@
import { type Ref, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type IStruttura } from '@/shared/model/struttura.model';
import StrutturaService from './struttura.service';
export default defineComponent({
name: 'StrutturaDetails',
setup() {
const dateFormat = useDateFormat();
const strutturaService = inject('strutturaService', () => new StrutturaService());
const alertService = inject('alertService', () => useAlertService(), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const struttura: Ref<IStruttura> = ref({});
const retrieveStruttura = async strutturaId => {
try {
const res = await strutturaService().find(strutturaId);
struttura.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.strutturaId) {
retrieveStruttura(route.params.strutturaId);
}
return {
...dateFormat,
alertService,
struttura,
previousState,
t$: useI18n().t,
};
},
});

View File

@@ -0,0 +1,76 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<div v-if="struttura">
<h2 class="jh-entity-heading" data-cy="strutturaDetailsHeading">
<span>{{ t$('smartbookingApp.struttura.detail.title') }}Struttura</span> {{ struttura.id }}
</h2>
<dl class="row-md jh-entity-details">
<dt>
<span>{{ t$('smartbookingApp.struttura.nome') }}</span>
</dt>
<dd>
<span>{{ struttura.nome }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.struttura.descrizione') }}</span>
</dt>
<dd>
<span>{{ struttura.descrizione }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.struttura.indirizzo') }}</span>
</dt>
<dd>
<span>{{ struttura.indirizzo }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.struttura.capienzaMax') }}</span>
</dt>
<dd>
<span>{{ struttura.capienzaMax }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.struttura.attiva') }}</span>
</dt>
<dd>
<span>{{ struttura.attiva }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.struttura.fotoUrl') }}</span>
</dt>
<dd>
<span>{{ struttura.fotoUrl }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.struttura.createdAt') }}</span>
</dt>
<dd>
<span v-if="struttura.createdAt">{{ formatDateLong(struttura.createdAt) }}</span>
</dd>
<dt>
<span>{{ t$('smartbookingApp.struttura.updatedAt') }}</span>
</dt>
<dd>
<span v-if="struttura.updatedAt">{{ formatDateLong(struttura.updatedAt) }}</span>
</dd>
</dl>
<button type="submit" @click.prevent="previousState()" class="btn btn-info" data-cy="entityDetailsBackButton">
<font-awesome-icon icon="arrow-left"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.back') }}</span>
</button>
<router-link
v-if="struttura.id"
:to="{ name: 'StrutturaEdit', params: { strutturaId: struttura.id } }"
custom
v-slot="{ navigate }"
>
<button @click="navigate" class="btn btn-primary">
<font-awesome-icon icon="pencil-alt"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.edit') }}</span>
</button>
</router-link>
</div>
</div>
</div>
</template>
<script lang="ts" src="./struttura-details.component.ts"></script>

View File

@@ -0,0 +1,156 @@
import { vitest } from 'vitest';
import { type RouteLocation } from 'vue-router';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import dayjs from 'dayjs';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import { DATE_TIME_LONG_FORMAT } from '@/shared/composables/date-format';
import StrutturaUpdate from './struttura-update.vue';
import StrutturaService from './struttura.service';
type StrutturaUpdateComponentType = InstanceType<typeof StrutturaUpdate>;
let route: Partial<RouteLocation>;
const routerGoMock = vitest.fn();
vitest.mock('vue-router', () => ({
useRoute: () => route,
useRouter: () => ({ go: routerGoMock }),
}));
const strutturaSample = { id: 123 };
describe('Component Tests', () => {
let mountOptions: MountingOptions<StrutturaUpdateComponentType>['global'];
let alertService: AlertService;
describe('Struttura Management Update Component', () => {
let comp: StrutturaUpdateComponentType;
let strutturaServiceStub: SinonStubbedInstance<StrutturaService>;
beforeEach(() => {
route = {};
strutturaServiceStub = sinon.createStubInstance<StrutturaService>(StrutturaService);
strutturaServiceStub.retrieve.onFirstCall().resolves(Promise.resolve([]));
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
'font-awesome-icon': true,
'b-input-group': true,
'b-input-group-prepend': true,
'b-form-datepicker': true,
'b-form-input': true,
},
provide: {
alertService,
strutturaService: () => strutturaServiceStub,
},
};
});
afterEach(() => {
vitest.resetAllMocks();
});
describe('load', () => {
beforeEach(() => {
const wrapper = shallowMount(StrutturaUpdate, { global: mountOptions });
comp = wrapper.vm;
});
it('Should convert date from string', () => {
// GIVEN
const date = new Date('2019-10-15T11:42:02Z');
// WHEN
const convertedDate = comp.convertDateTimeFromServer(date);
// THEN
expect(convertedDate).toEqual(dayjs(date).format(DATE_TIME_LONG_FORMAT));
});
it('Should not convert date if date is not present', () => {
expect(comp.convertDateTimeFromServer(null)).toBeNull();
});
});
describe('save', () => {
it('Should call update service on save for existing entity', async () => {
// GIVEN
const wrapper = shallowMount(StrutturaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.struttura = strutturaSample;
strutturaServiceStub.update.resolves(strutturaSample);
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(strutturaServiceStub.update.calledWith(strutturaSample)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
it('Should call create service on save for new entity', async () => {
// GIVEN
const entity = {};
strutturaServiceStub.create.resolves(entity);
const wrapper = shallowMount(StrutturaUpdate, { global: mountOptions });
comp = wrapper.vm;
comp.struttura = entity;
// WHEN
comp.save();
await comp.$nextTick();
// THEN
expect(strutturaServiceStub.create.calledWith(entity)).toBeTruthy();
expect(comp.isSaving).toEqual(false);
});
});
describe('Before route enter', () => {
it('Should retrieve data', async () => {
// GIVEN
strutturaServiceStub.find.resolves(strutturaSample);
strutturaServiceStub.retrieve.resolves([strutturaSample]);
// WHEN
route = {
params: {
strutturaId: `${strutturaSample.id}`,
},
};
const wrapper = shallowMount(StrutturaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(comp.struttura).toMatchObject(strutturaSample);
});
});
describe('Previous state', () => {
it('Should go previous state', async () => {
strutturaServiceStub.find.resolves(strutturaSample);
const wrapper = shallowMount(StrutturaUpdate, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
comp.previousState();
await comp.$nextTick();
expect(routerGoMock).toHaveBeenCalledWith(-1);
});
});
});
});

View File

@@ -0,0 +1,107 @@
import { type Ref, computed, defineComponent, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router';
import { useVuelidate } from '@vuelidate/core';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat, useValidation } from '@/shared/composables';
import { type IStruttura, Struttura } from '@/shared/model/struttura.model';
import StrutturaService from './struttura.service';
export default defineComponent({
name: 'StrutturaUpdate',
setup() {
const strutturaService = inject('strutturaService', () => new StrutturaService());
const alertService = inject('alertService', () => useAlertService(), true);
const struttura: Ref<IStruttura> = ref(new Struttura());
const isSaving = ref(false);
const currentLanguage = inject('currentLanguage', () => computed(() => navigator.language ?? 'it'), true);
const route = useRoute();
const router = useRouter();
const previousState = () => router.go(-1);
const retrieveStruttura = async strutturaId => {
try {
const res = await strutturaService().find(strutturaId);
res.createdAt = new Date(res.createdAt);
res.updatedAt = new Date(res.updatedAt);
struttura.value = res;
} catch (error) {
alertService.showHttpError(error.response);
}
};
if (route.params?.strutturaId) {
retrieveStruttura(route.params.strutturaId);
}
const initRelationships = () => {};
initRelationships();
const { t: t$ } = useI18n();
const validations = useValidation();
const validationRules = {
nome: {},
descrizione: {},
indirizzo: {},
capienzaMax: {},
attiva: {},
fotoUrl: {},
createdAt: {},
updatedAt: {},
disponibilitas: {},
moduliLiberatories: {},
};
const v$ = useVuelidate(validationRules, struttura as any);
v$.value.$validate();
return {
strutturaService,
alertService,
struttura,
previousState,
isSaving,
currentLanguage,
v$,
...useDateFormat({ entityRef: struttura }),
t$,
};
},
created(): void {},
methods: {
save(): void {
this.isSaving = true;
if (this.struttura.id) {
this.strutturaService()
.update(this.struttura)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showInfo(this.t$('smartbookingApp.struttura.updated', { param: param.id }));
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
} else {
this.strutturaService()
.create(this.struttura)
.then(param => {
this.isSaving = false;
this.previousState();
this.alertService.showSuccess(this.t$('smartbookingApp.struttura.created', { param: param.id }).toString());
})
.catch(error => {
this.isSaving = false;
this.alertService.showHttpError(error.response);
});
}
},
},
});

View File

@@ -0,0 +1,134 @@
<template>
<div class="d-flex justify-content-center">
<div class="col-8">
<form name="editForm" novalidate @submit.prevent="save()">
<h2 id="smartbookingApp.struttura.home.createOrEditLabel" data-cy="StrutturaCreateUpdateHeading">
{{ t$('smartbookingApp.struttura.home.createOrEditLabel') }}
</h2>
<div>
<div class="mb-3" v-if="struttura.id">
<label for="id">{{ t$('global.field.id') }}</label>
<input type="text" class="form-control" id="id" name="id" v-model="struttura.id" readonly />
</div>
<div class="mb-3">
<label class="form-control-label" for="struttura">{{ t$('smartbookingApp.struttura.nome') }}</label>
<input
type="text"
class="form-control"
name="nome"
id="struttura-nome"
data-cy="nome"
:class="{ valid: !v$.nome.$invalid, invalid: v$.nome.$invalid }"
v-model="v$.nome.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="struttura">{{ t$('smartbookingApp.struttura.descrizione') }}</label>
<input
type="text"
class="form-control"
name="descrizione"
id="struttura-descrizione"
data-cy="descrizione"
:class="{ valid: !v$.descrizione.$invalid, invalid: v$.descrizione.$invalid }"
v-model="v$.descrizione.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="struttura">{{ t$('smartbookingApp.struttura.indirizzo') }}</label>
<input
type="text"
class="form-control"
name="indirizzo"
id="struttura-indirizzo"
data-cy="indirizzo"
:class="{ valid: !v$.indirizzo.$invalid, invalid: v$.indirizzo.$invalid }"
v-model="v$.indirizzo.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="struttura">{{ t$('smartbookingApp.struttura.capienzaMax') }}</label>
<input
type="number"
class="form-control"
name="capienzaMax"
id="struttura-capienzaMax"
data-cy="capienzaMax"
:class="{ valid: !v$.capienzaMax.$invalid, invalid: v$.capienzaMax.$invalid }"
v-model.number="v$.capienzaMax.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="struttura">{{ t$('smartbookingApp.struttura.attiva') }}</label>
<input
type="checkbox"
class="form-check"
name="attiva"
id="struttura-attiva"
data-cy="attiva"
:class="{ valid: !v$.attiva.$invalid, invalid: v$.attiva.$invalid }"
v-model="v$.attiva.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="struttura">{{ t$('smartbookingApp.struttura.fotoUrl') }}</label>
<input
type="text"
class="form-control"
name="fotoUrl"
id="struttura-fotoUrl"
data-cy="fotoUrl"
:class="{ valid: !v$.fotoUrl.$invalid, invalid: v$.fotoUrl.$invalid }"
v-model="v$.fotoUrl.$model"
/>
</div>
<div class="mb-3">
<label class="form-control-label" for="struttura">{{ t$('smartbookingApp.struttura.createdAt') }}</label>
<div class="d-flex">
<input
id="struttura-createdAt"
data-cy="createdAt"
type="datetime-local"
class="form-control"
name="createdAt"
:class="{ valid: !v$.createdAt.$invalid, invalid: v$.createdAt.$invalid }"
:value="convertDateTimeFromServer(v$.createdAt.$model)"
@change="updateInstantField('createdAt', $event)"
/>
</div>
</div>
<div class="mb-3">
<label class="form-control-label" for="struttura">{{ t$('smartbookingApp.struttura.updatedAt') }}</label>
<div class="d-flex">
<input
id="struttura-updatedAt"
data-cy="updatedAt"
type="datetime-local"
class="form-control"
name="updatedAt"
:class="{ valid: !v$.updatedAt.$invalid, invalid: v$.updatedAt.$invalid }"
:value="convertDateTimeFromServer(v$.updatedAt.$model)"
@change="updateInstantField('updatedAt', $event)"
/>
</div>
</div>
</div>
<div>
<button type="button" id="cancel-save" data-cy="entityCreateCancelButton" class="btn btn-secondary" @click="previousState()">
<font-awesome-icon icon="ban"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.cancel') }}</span>
</button>
<button
type="submit"
id="save-entity"
data-cy="entityCreateSaveButton"
:disabled="v$.$invalid || isSaving"
class="btn btn-primary"
>
<font-awesome-icon icon="save"></font-awesome-icon>&nbsp;<span>{{ t$('entity.action.save') }}</span>
</button>
</div>
</form>
</div>
</div>
</template>
<script lang="ts" src="./struttura-update.component.ts"></script>

View File

@@ -0,0 +1,166 @@
import { vitest } from 'vitest';
import { type MountingOptions, shallowMount } from '@vue/test-utils';
import sinon, { type SinonStubbedInstance } from 'sinon';
import AlertService from '@/shared/alert/alert.service';
import StrutturaService from './struttura.service';
import Struttura from './struttura.vue';
type StrutturaComponentType = InstanceType<typeof Struttura>;
const bModalStub = {
render: () => {},
methods: {
hide: () => {},
show: () => {},
},
};
describe('Component Tests', () => {
let alertService: AlertService;
describe('Struttura Management Component', () => {
let strutturaServiceStub: SinonStubbedInstance<StrutturaService>;
let mountOptions: MountingOptions<StrutturaComponentType>['global'];
beforeEach(() => {
strutturaServiceStub = sinon.createStubInstance<StrutturaService>(StrutturaService);
strutturaServiceStub.retrieve.resolves({ headers: {} });
alertService = new AlertService({
i18n: { t: vitest.fn() } as any,
toast: {
show: vitest.fn(),
} as any,
});
mountOptions = {
stubs: {
jhiItemCount: true,
bPagination: true,
bModal: bModalStub as any,
'font-awesome-icon': true,
'b-badge': true,
'jhi-sort-indicator': true,
'b-button': true,
'router-link': true,
},
directives: {
'b-modal': {},
},
provide: {
alertService,
strutturaService: () => strutturaServiceStub,
},
};
});
describe('Mount', () => {
it('Should call load all on init', async () => {
// GIVEN
strutturaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
const wrapper = shallowMount(Struttura, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(strutturaServiceStub.retrieve.calledOnce).toBeTruthy();
expect(comp.strutturas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for an id', async () => {
// WHEN
const wrapper = shallowMount(Struttura, { global: mountOptions });
const comp = wrapper.vm;
await comp.$nextTick();
// THEN
expect(strutturaServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['id,asc'],
});
});
});
describe('Handles', () => {
let comp: StrutturaComponentType;
beforeEach(async () => {
const wrapper = shallowMount(Struttura, { global: mountOptions });
comp = wrapper.vm;
await comp.$nextTick();
strutturaServiceStub.retrieve.reset();
strutturaServiceStub.retrieve.resolves({ headers: {}, data: [] });
});
it('should load a page', async () => {
// GIVEN
strutturaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.page = 2;
await comp.$nextTick();
// THEN
expect(strutturaServiceStub.retrieve.called).toBeTruthy();
expect(comp.strutturas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should not load a page if the page is the same as the previous page', () => {
// WHEN
comp.page = 1;
// THEN
expect(strutturaServiceStub.retrieve.called).toBeFalsy();
});
it('should re-initialize the page', async () => {
// GIVEN
comp.page = 2;
await comp.$nextTick();
strutturaServiceStub.retrieve.reset();
strutturaServiceStub.retrieve.resolves({ headers: {}, data: [{ id: 123 }] });
// WHEN
comp.clear();
await comp.$nextTick();
// THEN
expect(comp.page).toEqual(1);
expect(strutturaServiceStub.retrieve.callCount).toEqual(1);
expect(comp.strutturas[0]).toEqual(expect.objectContaining({ id: 123 }));
});
it('should calculate the sort attribute for a non-id attribute', async () => {
// WHEN
comp.propOrder = 'name';
await comp.$nextTick();
// THEN
expect(strutturaServiceStub.retrieve.lastCall.firstArg).toMatchObject({
sort: ['name,asc', 'id'],
});
});
it('Should call delete service on confirmDelete', async () => {
// GIVEN
strutturaServiceStub.delete.resolves({});
// WHEN
comp.prepareRemove({ id: 123 });
comp.removeStruttura();
await comp.$nextTick(); // clear components
// THEN
expect(strutturaServiceStub.delete.called).toBeTruthy();
// THEN
await comp.$nextTick(); // handle component clear watch
expect(strutturaServiceStub.retrieve.callCount).toEqual(1);
});
});
});
});

View File

@@ -0,0 +1,137 @@
import { type Ref, defineComponent, inject, onMounted, ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
import { useAlertService } from '@/shared/alert/alert.service';
import { useDateFormat } from '@/shared/composables';
import { type IStruttura } from '@/shared/model/struttura.model';
import StrutturaService from './struttura.service';
export default defineComponent({
name: 'Struttura',
setup() {
const { t: t$ } = useI18n();
const dateFormat = useDateFormat();
const strutturaService = inject('strutturaService', () => new StrutturaService());
const alertService = inject('alertService', () => useAlertService(), true);
const itemsPerPage = ref(20);
const queryCount: Ref<number> = ref(null);
const page: Ref<number> = ref(1);
const propOrder = ref('id');
const reverse = ref(false);
const totalItems = ref(0);
const strutturas: Ref<IStruttura[]> = ref([]);
const isFetching = ref(false);
const clear = () => {
page.value = 1;
};
const sort = (): Array<any> => {
const result = [`${propOrder.value},${reverse.value ? 'desc' : 'asc'}`];
if (propOrder.value !== 'id') {
result.push('id');
}
return result;
};
const retrieveStrutturas = async () => {
isFetching.value = true;
try {
const paginationQuery = {
page: page.value - 1,
size: itemsPerPage.value,
sort: sort(),
};
const res = await strutturaService().retrieve(paginationQuery);
totalItems.value = Number(res.headers['x-total-count']);
queryCount.value = totalItems.value;
strutturas.value = res.data;
} catch (err) {
alertService.showHttpError(err.response);
} finally {
isFetching.value = false;
}
};
const handleSyncList = () => {
retrieveStrutturas();
};
onMounted(async () => {
await retrieveStrutturas();
});
const removeId: Ref<number> = ref(null);
const removeEntity = ref<any>(null);
const prepareRemove = (instance: IStruttura) => {
removeId.value = instance.id;
removeEntity.value.show();
};
const closeDialog = () => {
removeEntity.value.hide();
};
const removeStruttura = async () => {
try {
await strutturaService().delete(removeId.value);
const message = t$('smartbookingApp.struttura.deleted', { param: removeId.value }).toString();
alertService.showInfo(message, { variant: 'danger' });
removeId.value = null;
retrieveStrutturas();
closeDialog();
} catch (error) {
alertService.showHttpError(error.response);
}
};
const changeOrder = (newOrder: string) => {
if (propOrder.value === newOrder) {
reverse.value = !reverse.value;
} else {
reverse.value = false;
}
propOrder.value = newOrder;
};
// Whenever order changes, reset the pagination
watch([propOrder, reverse], async () => {
if (page.value === 1) {
// first page, retrieve new data
await retrieveStrutturas();
} else {
// reset the pagination
clear();
}
});
// Whenever page changes, switch to the new page.
watch(page, async () => {
await retrieveStrutturas();
});
return {
strutturas,
handleSyncList,
isFetching,
retrieveStrutturas,
clear,
...dateFormat,
removeId,
removeEntity,
prepareRemove,
closeDialog,
removeStruttura,
itemsPerPage,
queryCount,
page,
propOrder,
reverse,
totalItems,
changeOrder,
t$,
};
},
});

View File

@@ -0,0 +1,193 @@
import axios from 'axios';
import dayjs from 'dayjs';
import sinon from 'sinon';
import { DATE_TIME_FORMAT } from '@/shared/composables/date-format';
import { Struttura } from '@/shared/model/struttura.model';
import StrutturaService from './struttura.service';
const error = {
response: {
status: null,
data: {
type: null,
},
},
};
const axiosStub = {
get: sinon.stub(axios, 'get'),
post: sinon.stub(axios, 'post'),
put: sinon.stub(axios, 'put'),
patch: sinon.stub(axios, 'patch'),
delete: sinon.stub(axios, 'delete'),
};
describe('Service Tests', () => {
describe('Struttura Service', () => {
let service: StrutturaService;
let elemDefault;
let currentDate: Date;
beforeEach(() => {
service = new StrutturaService();
currentDate = new Date();
elemDefault = new Struttura(123, 'AAAAAAA', 'AAAAAAA', 'AAAAAAA', 0, false, 'AAAAAAA', currentDate, currentDate);
});
describe('Service methods', () => {
it('should find an element', async () => {
const returnedFromService = {
createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
updatedAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
axiosStub.get.resolves({ data: returnedFromService });
return service.find(123).then(res => {
expect(res).toMatchObject(elemDefault);
});
});
it('should not find an element', async () => {
axiosStub.get.rejects(error);
return service
.find(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should create a Struttura', async () => {
const returnedFromService = {
id: 123,
createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
updatedAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { createdAt: currentDate, updatedAt: currentDate, ...returnedFromService };
axiosStub.post.resolves({ data: returnedFromService });
return service.create({}).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not create a Struttura', async () => {
axiosStub.post.rejects(error);
return service
.create({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should update a Struttura', async () => {
const returnedFromService = {
nome: 'BBBBBB',
descrizione: 'BBBBBB',
indirizzo: 'BBBBBB',
capienzaMax: 1,
attiva: true,
fotoUrl: 'BBBBBB',
createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
updatedAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { createdAt: currentDate, updatedAt: currentDate, ...returnedFromService };
axiosStub.put.resolves({ data: returnedFromService });
return service.update(expected).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not update a Struttura', async () => {
axiosStub.put.rejects(error);
return service
.update({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should partial update a Struttura', async () => {
const patchObject = { nome: 'BBBBBB', indirizzo: 'BBBBBB', attiva: true, fotoUrl: 'BBBBBB', ...new Struttura() };
const returnedFromService = Object.assign(patchObject, elemDefault);
const expected = { createdAt: currentDate, updatedAt: currentDate, ...returnedFromService };
axiosStub.patch.resolves({ data: returnedFromService });
return service.partialUpdate(patchObject).then(res => {
expect(res).toMatchObject(expected);
});
});
it('should not partial update a Struttura', async () => {
axiosStub.patch.rejects(error);
return service
.partialUpdate({})
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should return a list of Struttura', async () => {
const returnedFromService = {
nome: 'BBBBBB',
descrizione: 'BBBBBB',
indirizzo: 'BBBBBB',
capienzaMax: 1,
attiva: true,
fotoUrl: 'BBBBBB',
createdAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
updatedAt: dayjs(currentDate).format(DATE_TIME_FORMAT),
...elemDefault,
};
const expected = { createdAt: currentDate, updatedAt: currentDate, ...returnedFromService };
axiosStub.get.resolves([returnedFromService]);
return service.retrieve({ sort: {}, page: 0, size: 10 }).then(res => {
expect(res).toContainEqual(expected);
});
});
it('should not return a list of Struttura', async () => {
axiosStub.get.rejects(error);
return service
.retrieve()
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
it('should delete a Struttura', async () => {
axiosStub.delete.resolves({ ok: true });
return service.delete(123).then(res => {
expect(res.ok).toBeTruthy();
});
});
it('should not delete a Struttura', async () => {
axiosStub.delete.rejects(error);
return service
.delete(123)
.then()
.catch(err => {
expect(err).toMatchObject(error);
});
});
});
});
});

View File

@@ -0,0 +1,86 @@
import axios from 'axios';
import { type IStruttura } from '@/shared/model/struttura.model';
import buildPaginationQueryOpts from '@/shared/sort/sorts';
const baseApiUrl = 'api/strutturas';
export default class StrutturaService {
find(id: number): Promise<IStruttura> {
return new Promise<IStruttura>((resolve, reject) => {
axios
.get(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
retrieve(paginationQuery?: any): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.get(`${baseApiUrl}?${buildPaginationQueryOpts(paginationQuery)}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
delete(id: number): Promise<any> {
return new Promise<any>((resolve, reject) => {
axios
.delete(`${baseApiUrl}/${id}`)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
});
});
}
create(entity: IStruttura): Promise<IStruttura> {
return new Promise<IStruttura>((resolve, reject) => {
axios
.post(baseApiUrl, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
update(entity: IStruttura): Promise<IStruttura> {
return new Promise<IStruttura>((resolve, reject) => {
axios
.put(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
partialUpdate(entity: IStruttura): Promise<IStruttura> {
return new Promise<IStruttura>((resolve, reject) => {
axios
.patch(`${baseApiUrl}/${entity.id}`, entity)
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
}
}

Some files were not shown because too many files have changed in this diff Show More