| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- <template>
- <q-dialog ref="dialogRef" @hide="onDialogHide">
- <q-card class="q-dialog-plugin" style="width: 800px; max-width: 90vw">
- <DefaultDialogHeader :title="title" @close="onDialogCancel" />
- <q-form ref="formRef" @submit="onOKClick">
- <q-card-section class="row q-col-gutter-sm">
- <q-select
- v-if="!review"
- v-model="selectedSchedule"
- :label="$t('reviews.schedule')"
- :options="scheduleOptions"
- :rules="[inputRules.required]"
- :error="!!serverErrors?.schedule_id"
- :error-message="serverErrors?.schedule_id"
- :loading="loadingSchedules"
- option-value="value"
- option-label="label"
- emit-value
- map-options
- class="col-12"
- @update:model-value="onScheduleChange"
- />
- <q-input
- v-else
- :model-value="review.schedule_label"
- :label="$t('reviews.schedule')"
- readonly
- class="col-12"
- />
- <q-select
- v-if="!review"
- v-model="form.origin"
- :label="$t('reviews.origin')"
- :options="originOptions"
- :rules="[inputRules.required]"
- :error="!!serverErrors?.origin"
- :error-message="serverErrors?.origin"
- emit-value
- map-options
- class="col-12 col-md-6"
- @update:model-value="onOriginChange"
- />
- <q-input
- v-else
- :model-value="$t(`reviews.origins.${review.origin}`)"
- :label="$t('reviews.origin')"
- readonly
- class="col-12 col-md-6"
- />
- <template v-if="!review">
- <ProviderSelect
- v-if="form.origin === 'providers'"
- :key="'provider-select'"
- v-model="selectedOriginModel"
- :label="$t('reviews.origin_id')"
- :rules="[inputRules.required]"
- :error="!!serverErrors?.origin_id"
- :error-message="serverErrors?.origin_id"
- class="col-12 col-md-6"
- @update:model-value="onOriginIdChange"
- />
- <ClientSelect
- v-else-if="form.origin === 'clients'"
- :key="'client-select'"
- v-model="selectedOriginModel"
- :label="$t('reviews.origin_id')"
- :rules="[inputRules.required]"
- :error="!!serverErrors?.origin_id"
- :error-message="serverErrors?.origin_id"
- class="col-12 col-md-6"
- @update:model-value="onOriginIdChange"
- />
- <q-input
- v-else
- :label="$t('reviews.origin_id')"
- readonly
- :placeholder="$t('reviews.origin')"
- class="col-12 col-md-6"
- disable
- />
- </template>
- <div class="col-12">
- <div class="text-caption q-mb-xs">{{ $t('reviews.stars') }}</div>
- <q-rating
- v-model="form.stars"
- :max="5"
- size="md"
- color="amber"
- icon="star_border"
- icon-selected="star"
- class="q-mb-xs"
- />
- <div
- v-if="serverErrors?.stars"
- class="text-negative text-caption"
- >
- {{ serverErrors.stars }}
- </div>
- </div>
- <q-input
- v-model="form.comment"
- :label="$t('reviews.comment')"
- :error="!!serverErrors?.comment"
- :error-message="serverErrors?.comment"
- type="textarea"
- autogrow
- class="col-12"
- @update:model-value="serverErrors.comment = null"
- />
- <q-select
- v-if="!review"
- v-model="selectedImprovements"
- :label="$t('reviews.improvements')"
- :options="improvementOptions"
- :loading="loadingImprovements"
- option-value="value"
- option-label="label"
- emit-value
- map-options
- multiple
- use-chips
- class="col-12"
- @update:model-value="($event) => attImprovementsOnForm($event)"
- />
- <div v-else>
- <div>{{reviewsImprovements?.length > 0 ? t('reviews.improvements_suggested') : t('reviews.no_improvements_suggested')}}</div>
- <q-chip
- v-for="improvement in reviewsImprovements"
- :key="improvement.id"
- class="q-mb-xs"
- >
- {{ improvement.description }}
- </q-chip>
- </div>
- </q-card-section>
- <q-card-actions align="right" class="q-px-md q-pb-md">
- <q-btn
- flat
- :label="$t('common.actions.cancel')"
- color="negative"
- @click="onDialogCancel"
- />
- <q-btn
- type="submit"
- :label="$t('common.actions.save')"
- :loading="loading"
- :disable="!hasUpdatedFields"
- color="primary"
- unelevated
- />
- </q-card-actions>
- </q-form>
- </q-card>
- </q-dialog>
- </template>
- <script setup>
- import { ref, computed, onMounted } from 'vue'
- import { useDialogPluginComponent } from 'quasar'
- import { useFormUpdateTracker } from 'src/composables/useFormUpdateTracker'
- import { useSubmitHandler } from 'src/composables/useSubmitHandler'
- import { createReview, updateReview, getFinishedSchedules } from 'src/api/review'
- import { createReviewImprovement } from 'src/api/reviewImprovement'
- import { getImprovementTypes } from 'src/api/improvementType'
- import DefaultDialogHeader from 'src/components/defaults/DefaultDialogHeader.vue'
- import ProviderSelect from 'src/components/provider/ProviderSelect.vue'
- import ClientSelect from 'src/components/client/ClientSelect.vue'
- import { useInputRules } from 'src/composables/useInputRules'
- import { useI18n } from 'vue-i18n'
- import { format, parseISO } from 'date-fns'
- const props = defineProps({
- review: {
- type: Object,
- default: null
- },
- title: {
- type: Function,
- default: () => ''
- }
- })
- defineEmits([...useDialogPluginComponent.emits])
- const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent()
- const { inputRules } = useInputRules()
- const { t } = useI18n()
- const formRef = ref(null)
- const selectedSchedule = ref(props.review ? props.review.schedule_id : null)
- const selectedOriginModel = ref(null)
- const selectedImprovements = ref([])
- const scheduleOptions = ref([])
- const improvementOptions = ref([])
- const loadingSchedules = ref(false)
- const loadingImprovements = ref(false)
- const reviewsImprovements = ref([])
- const originOptions = computed(() => [
- { label: t('reviews.origins.providers'), value: 'providers' },
- { label: t('reviews.origins.clients'), value: 'clients' }
- ])
- const { form, hasUpdatedFields } = useFormUpdateTracker({
- schedule_id: props.review ? props.review.schedule_id : null,
- origin: props.review ? props.review.origin : null,
- origin_id: props.review ? props.review.origin_id : null,
- stars: props.review ? Number(props.review.stars) : 0,
- comment: props.review ? props.review.comment : null,
- improvements_ids: props.review ? props.review.improvements?.map(i => i.id) : [],
- })
- const {
- loading,
- serverErrors,
- execute: submitForm,
- } = useSubmitHandler({
- onSuccess: () => onDialogOK(true),
- formRef: formRef,
- })
- const onScheduleChange = (val) => {
- form.schedule_id = val
- serverErrors.schedule_id = null
- }
- const onOriginChange = () => {
- selectedOriginModel.value = null
- form.origin_id = null
- serverErrors.origin = null
- serverErrors.origin_id = null
- }
- const onOriginIdChange = (selected) => {
- form.origin_id = selected?.value ?? null
- serverErrors.origin_id = null
- }
- const onOKClick = async () => {
- await submitForm(async () => {
- if (props.review) {
- return updateReview(props.review.id, {
- stars: form.stars,
- comment: form.comment,
- })
- } else {
- const created = await createReview({ ...form })
- for (const improvementTypeId of selectedImprovements.value) {
- await createReviewImprovement({
- review_id: created.id,
- improvement_type_id: improvementTypeId,
- })
- }
- return created
- }
- })
- }
- const attImprovementsOnForm = (event) => {
- form.improvements_ids = event;
- serverErrors.improvements_ids = null;
- }
- onMounted(async () => {
- loadingSchedules.value = true
- loadingImprovements.value = true
- try {
- const [schedules, improvements] = await Promise.all([
- getFinishedSchedules(),
- getImprovementTypes(),
- ])
- scheduleOptions.value = schedules.map((s) => ({
- value: s.id,
- label: `${s.id} - ${s.client_name ?? '?'} - ${s.provider_name ?? '?'} - ${s.date ? format(parseISO(s.date), 'dd/MM/yyyy') : '?'}`,
- }))
- improvementOptions.value = improvements.map((i) => ({
- value: i.id,
- label: i.description,
- }))
- reviewsImprovements.value = props.review?.reviews_improvements;
- } catch (error) {
- console.error('Error loading data:', error)
- } finally {
- loadingSchedules.value = false
- loadingImprovements.value = false
- }
- })
- </script>
|