| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- <template>
- <q-dialog ref="dialogRef" persistent maximized transition-show="slide-left" transition-hide="slide-right">
- <div class="bg-page full-height column no-shadow">
- <div class="row items-center q-px-md q-pb-sm bg-white shadow-profile bg-surface dialog-safe-header">
- <q-btn v-close-popup icon="mdi-chevron-left" flat round dense color="primary" />
- <q-space />
- <span class="gradient-diarista font16 fontbold">{{ $t('profile.service_data.title') }}</span>
- <q-space />
- <div style="width: 32px"></div>
- </div>
- <div class="col overflow-auto">
- <div class="q-px-md q-pt-lg q-pb-xl justify-between column full-height">
- <div class="text-center q-mb-lg">
- <q-img :src="LogoDiariaCampos" style="max-width: 160px;" />
- </div>
- <div class="q-mb-lg">
- <div class="text-text q-mb-sm font12 fontbold">
- {{ $t('profile.service_data.price_8h_label') }}
- </div>
- <DefaultCurrencyInput
- v-model="form.daily_price_8h"
- class="q-mb-xs bg-surface"
- input-class="text-text"
- :error="!!priceError"
- :error-message="priceError"
- hide-bottom-space
- label=""
- />
- <div class="text-text text-center q-mb-lg font10 fontmedium">
- {{ $t('profile.service_data.price_min_max') }}
- </div>
- <div class="text-text text-center q-mb-sm font12 fontmedium">
- {{ $t('profile.service_data.shorter_services') }}
- </div>
- <div class="row q-col-gutter-sm q-mb-sm">
- <div class="col-4">
- <div class="text-text text-center q-mb-xs font11 fontbold">
- {{ $t('profile.service_data.up_to_6h') }}
- </div>
- <q-input
- :model-value="formatCurrency(form.daily_price_6h)"
- outlined
- dense
- readonly
- class="bg-surface"
- input-class="text-text text-center"
- />
- </div>
- <div class="col-4">
- <div class="text-text text-center q-mb-xs font11 fontbold">
- {{ $t('profile.service_data.up_to_4h') }}
- </div>
- <q-input
- :model-value="formatCurrency(form.daily_price_4h)"
- outlined
- dense
- readonly
- class="bg-surface"
- input-class="text-text text-center"
- />
- </div>
- <div class="col-4">
- <div class="text-text text-center q-mb-xs font11 fontbold">
- {{ $t('profile.service_data.up_to_2h') }}
- </div>
- <q-input
- :model-value="formatCurrency(form.daily_price_2h)"
- outlined
- dense
- readonly
- class="bg-surface"
- input-class="text-text text-center"
- />
- </div>
- </div>
- </div>
- <div class="text-text text-center font12">
- <span class="fontbold">
- {{ $t('profile.service_data.services_subtitle') }}
- </span>
- <div class="text-text q-mb-md text-center font12">
- {{ $t('profile.service_data.change_in_profile') }}
- </div>
- <div class="q-mb-lg">
- <div v-if="loadingServiceTypes" class="row justify-center q-py-md">
- <q-spinner color="primary" size="28px" />
- </div>
- <div v-else-if="serviceOptions.length" class="row q-col-gutter-sm">
- <div v-for="service in serviceOptions" :key="service.value" class="col-6">
- <q-checkbox
- :model-value="isServiceSelected(service.value)"
- :label="service.label"
- :disable="togglingService[service.value]"
- color="primary"
- class="text-text"
- keep-color
- @update:model-value="(checked) => onServiceToggle(service, checked)"
- />
- </div>
- </div>
- <div v-else class="text-grey-7 text-center q-py-md font12">
- {{ $t('profile.service_data.no_services') }}
- </div>
- <div class="text-grey-6 text-center q-mt-md font12">
- {{ $t('profile.service_data.services_hint') }}
- </div>
- </div>
- </div>
- <q-btn
- unelevated
- rounded
- no-caps
- color="primary"
- padding="4px 12px"
- class="full-width q-py-md"
- :label="$t('common.actions.update')"
- :loading="saving"
- :disable="!!priceError || saving"
- @click="save"
- />
- </div>
- </div>
- </div>
- </q-dialog>
- </template>
- <script setup>
- import { ref, computed, watch, onMounted } from 'vue';
- import { useDialogPluginComponent, useQuasar } from 'quasar';
- import { useI18n } from 'vue-i18n';
- import { getPublicServiceTypes } from 'src/api/serviceType';
- import { getProviderServiceTypes, createProviderServiceType, deleteProviderServiceType } from 'src/api/providerServiceType';
- import { getUser } from 'src/api/user';
- import { updateProvider } from 'src/api/provider';
- import { userStore } from 'src/stores/user';
- import DefaultCurrencyInput from 'src/components/defaults/DefaultCurrencyInput.vue';
- import LogoDiariaCampos from 'src/assets/logo_diaria_campos_login.svg';
- defineEmits([...useDialogPluginComponent.emits]);
- const { dialogRef, onDialogOK } = useDialogPluginComponent();
- const $q = useQuasar();
- const { t } = useI18n();
- const user = userStore();
- const form = ref({
- daily_price_8h: null,
- daily_price_6h: null,
- daily_price_4h: null,
- daily_price_2h: null,
- });
- const serviceOptions = ref([]);
- const providerServiceTypes = ref([]);
- const loadingServiceTypes = ref(false);
- const togglingService = ref({});
- const saving = ref(false);
- const priceError = computed(() => {
- const value = Number(form.value.daily_price_8h);
- if (!form.value.daily_price_8h && form.value.daily_price_8h !== 0) return '';
- if (Number.isNaN(value)) return t('validation.rules.required');
- if (value < 100) return t('profile.service_data.price_min_error');
- if (value > 500) return t('profile.service_data.price_max_error');
- return '';
- });
- const formatCurrency = (value) => {
- if (value === null || value === undefined || Number.isNaN(Number(value))) return 'R$ 0,00';
- return Number(value).toLocaleString('pt-BR', {
- style: 'currency',
- currency: 'BRL',
- minimumFractionDigits: 2,
- });
- };
- const isServiceSelected = (serviceTypeId) => {
- return providerServiceTypes.value.some((pst) => pst.service_type_id === serviceTypeId);
- };
- watch(
- () => form.value.daily_price_8h,
- (value) => {
- const price = Number(value);
- if (!price || Number.isNaN(price)) {
- form.value.daily_price_6h = null;
- form.value.daily_price_4h = null;
- form.value.daily_price_2h = null;
- return;
- }
- form.value.daily_price_6h = Number((price * 0.85).toFixed(2));
- form.value.daily_price_4h = Number((price * 0.55).toFixed(2));
- form.value.daily_price_2h = Number((price * 0.30).toFixed(2));
- },
- { immediate: true },
- );
- const loadData = async () => {
- try {
- const userData = await getUser();
- form.value.daily_price_8h = userData.provider_daily_price_8h ?? null;
- form.value.daily_price_6h = userData.provider_daily_price_6h ?? null;
- form.value.daily_price_4h = userData.provider_daily_price_4h ?? null;
- form.value.daily_price_2h = userData.provider_daily_price_2h ?? null;
- } catch (error) {
- console.error('Erro ao carregar dados do prestador:', error);
- }
- };
- const loadServiceTypes = async () => {
- loadingServiceTypes.value = true;
- try {
- const [allTypes, providerTypes] = await Promise.all([
- getPublicServiceTypes(),
- getProviderServiceTypes(user.user.provider_id),
- ]);
- serviceOptions.value = (Array.isArray(allTypes) ? allTypes : [])
- .filter((item) => item?.is_active !== false)
- .map((item) => ({ label: item.description, value: Number(item.id) }))
- .filter((item) => Number.isInteger(item.value) && item.value > 0);
- providerServiceTypes.value = Array.isArray(providerTypes) ? providerTypes : [];
- } catch (error) {
- console.error('Erro ao carregar tipos de serviço:', error);
- $q.notify({ type: 'negative', message: t('http.errors.failed') });
- } finally {
- loadingServiceTypes.value = false;
- }
- };
- const onServiceToggle = async (service, checked) => {
- togglingService.value = { ...togglingService.value, [service.value]: true };
- try {
- if (checked) {
- const created = await createProviderServiceType(user.user.provider_id, {
- service_type_id: service.value,
- });
- providerServiceTypes.value = [...providerServiceTypes.value, created];
- } else {
- const existing = providerServiceTypes.value.find((pst) => pst.service_type_id === service.value);
- if (existing) {
- await deleteProviderServiceType(user.user.provider_id, existing.id);
- providerServiceTypes.value = providerServiceTypes.value.filter((pst) => pst.id !== existing.id);
- }
- }
- } catch {
- $q.notify({ type: 'negative', message: t('http.errors.failed') });
- } finally {
- const updated = { ...togglingService.value };
- delete updated[service.value];
- togglingService.value = updated;
- }
- };
- const save = async () => {
- if (priceError.value) return;
- saving.value = true;
- try {
- await updateProvider(user.user.provider_id, {
- daily_price_8h: form.value.daily_price_8h,
- daily_price_6h: form.value.daily_price_6h,
- daily_price_4h: form.value.daily_price_4h,
- daily_price_2h: form.value.daily_price_2h,
- });
- onDialogOK();
- } catch {
- $q.notify({ type: 'negative', message: t('http.errors.failed') });
- } finally {
- saving.value = false;
- }
- };
- onMounted(async () => {
- await Promise.all([loadData(), loadServiceTypes()]);
- });
- </script>
- <style scoped lang="scss">
- :deep(.q-field--outlined .q-field__control) {
- border-radius: 10px;
- }
- </style>
|