|
@@ -1,49 +1,92 @@
|
|
|
<template>
|
|
<template>
|
|
|
<q-card-section class="no-padding">
|
|
<q-card-section class="no-padding">
|
|
|
- <div class="text-text font12 fontbold q-mb-sm">{{ $t('provider.login.steps.step_5.daily_price_title') }}</div>
|
|
|
|
|
|
|
+ <div class="text-text font12 fontbold q-mb-sm">
|
|
|
|
|
+ {{ $t('provider.login.steps.step_5.daily_price_title') }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
<DefaultCurrencyInput
|
|
<DefaultCurrencyInput
|
|
|
v-model="form.daily_price_8h"
|
|
v-model="form.daily_price_8h"
|
|
|
- rounded
|
|
|
|
|
- no-error-icon
|
|
|
|
|
class="bg-surface q-mb-sm custom-currency-input"
|
|
class="bg-surface q-mb-sm custom-currency-input"
|
|
|
|
|
+ hide-bottom-space
|
|
|
input-class="text-text font12 fontmedium"
|
|
input-class="text-text font12 fontmedium"
|
|
|
|
|
+ label=""
|
|
|
placeholder="R$ 0,00"
|
|
placeholder="R$ 0,00"
|
|
|
|
|
+ rounded
|
|
|
|
|
+ no-error-icon
|
|
|
:error="!!priceError"
|
|
:error="!!priceError"
|
|
|
- hide-bottom-space
|
|
|
|
|
- label=""
|
|
|
|
|
|
|
+ :error-message="priceError"
|
|
|
|
|
+ :rules="[validateDailyPrice]"
|
|
|
/>
|
|
/>
|
|
|
|
|
|
|
|
- <div class="text-center text-grey-7 font10 fontmedium q-mb-md">{{ $t('provider.login.steps.step_5.daily_price_min_max') }}</div>
|
|
|
|
|
|
|
+ <div class="text-center text-grey-7 font10 fontmedium q-mb-md">
|
|
|
|
|
+ {{ dailyPriceMinMaxText }}
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
<q-banner class="bg-blue-1 text-primary q-mb-lg q-pa-md bannerRound">
|
|
<q-banner class="bg-blue-1 text-primary q-mb-lg q-pa-md bannerRound">
|
|
|
<template #avatar>
|
|
<template #avatar>
|
|
|
- <q-icon name="mdi-alert-outline" color="primary" />
|
|
|
|
|
|
|
+ <q-icon color="primary" name="mdi-alert-outline" />
|
|
|
</template>
|
|
</template>
|
|
|
- <span class="fontbold font12">{{ $t('provider.login.steps.step_5.dont_worry') }}</span>
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <span class="fontbold font12">
|
|
|
|
|
+ {{ $t('provider.login.steps.step_5.dont_worry') }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+
|
|
|
<span class="font12 q-ml-xs">
|
|
<span class="font12 q-ml-xs">
|
|
|
{{ $t('provider.login.steps.step_5.change_anytime') }}
|
|
{{ $t('provider.login.steps.step_5.change_anytime') }}
|
|
|
</span>
|
|
</span>
|
|
|
</q-banner>
|
|
</q-banner>
|
|
|
|
|
|
|
|
- <div class="text-text text-center font12 fontmedium q-mb-sm">{{ $t('provider.login.steps.step_5.shorter_services') }}</div>
|
|
|
|
|
|
|
+ <div class="text-text text-center font12 fontmedium q-mb-sm">
|
|
|
|
|
+ {{ $t('provider.login.steps.step_5.shorter_services') }}
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
<div class="row q-col-gutter-sm q-mb-lg q-mt-md">
|
|
<div class="row q-col-gutter-sm q-mb-lg q-mt-md">
|
|
|
<div class="col-4">
|
|
<div class="col-4">
|
|
|
- <div class="text-text text-center fontbold font12">{{ $t('provider.login.steps.step_5.up_to_6h') }}</div>
|
|
|
|
|
- <q-input :model-value="formatCurrency(form.daily_price_6h)" readonly class="bg-surface" input-class="text-text font12 fontmedium"/>
|
|
|
|
|
|
|
+ <div class="text-text text-center fontbold font12">
|
|
|
|
|
+ {{ $t('provider.login.steps.step_5.up_to_6h') }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <q-input
|
|
|
|
|
+ :model-value="formatCurrency(form.daily_price_6h)"
|
|
|
|
|
+ class="bg-surface"
|
|
|
|
|
+ input-class="text-text font12 fontmedium"
|
|
|
|
|
+ readonly
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
<div class="col-4">
|
|
<div class="col-4">
|
|
|
- <div class="text-text text-center fontbold font12">{{ $t('provider.login.steps.step_5.up_to_4h') }}</div>
|
|
|
|
|
- <q-input :model-value="formatCurrency(form.daily_price_4h)" readonly class="bg-surface" input-class="text-text font12 fontmedium"/>
|
|
|
|
|
|
|
+ <div class="text-text text-center fontbold font12">
|
|
|
|
|
+ {{ $t('provider.login.steps.step_5.up_to_4h') }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <q-input
|
|
|
|
|
+ :model-value="formatCurrency(form.daily_price_4h)"
|
|
|
|
|
+ class="bg-surface"
|
|
|
|
|
+ input-class="text-text font12 fontmedium"
|
|
|
|
|
+ readonly
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
<div class="col-4 column">
|
|
<div class="col-4 column">
|
|
|
- <div class="text-text text-center fontbold font12">{{ $t('provider.login.steps.step_5.up_to_2h') }}</div>
|
|
|
|
|
- <q-input :model-value="formatCurrency(form.daily_price_2h)" readonly class="bg-surface" input-class="text-text font12 fontmedium"/>
|
|
|
|
|
|
|
+ <div class="text-text text-center fontbold font12">
|
|
|
|
|
+ {{ $t('provider.login.steps.step_5.up_to_2h') }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <q-input
|
|
|
|
|
+ :model-value="formatCurrency(form.daily_price_2h)"
|
|
|
|
|
+ class="bg-surface"
|
|
|
|
|
+ input-class="text-text font12 fontmedium"
|
|
|
|
|
+ readonly
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div class="text-text q-mb-xs text-center fontbold 12">{{ $t('provider.login.steps.step_5.other_services') }}</div>
|
|
|
|
|
- <div class="text-grey-7 q-mb-md text-center font10">{{ $t('provider.login.steps.step_5.change_in_profile') }}</div>
|
|
|
|
|
|
|
+ <div class="text-text q-mb-xs text-center fontbold 12">
|
|
|
|
|
+ {{ $t('provider.login.steps.step_5.other_services') }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="text-grey-7 q-mb-md text-center font10">
|
|
|
|
|
+ {{ $t('provider.login.steps.step_5.change_in_profile') }}
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
<div v-if="loadingServiceTypes" class="row justify-center q-mb-lg">
|
|
<div v-if="loadingServiceTypes" class="row justify-center q-mb-lg">
|
|
|
<q-spinner color="primary" size="28px" />
|
|
<q-spinner color="primary" size="28px" />
|
|
@@ -53,33 +96,57 @@
|
|
|
<div v-for="service in serviceOptions" :key="service.value" class="col-6">
|
|
<div v-for="service in serviceOptions" :key="service.value" class="col-6">
|
|
|
<q-checkbox
|
|
<q-checkbox
|
|
|
:model-value="selectedServices.includes(service.value)"
|
|
:model-value="selectedServices.includes(service.value)"
|
|
|
- :label="service.label"
|
|
|
|
|
- color="primary"
|
|
|
|
|
class="q-mb-md text-text font12 fontmedium"
|
|
class="q-mb-md text-text font12 fontmedium"
|
|
|
|
|
+ color="primary"
|
|
|
keep-color
|
|
keep-color
|
|
|
|
|
+ :label="service.label"
|
|
|
@update:model-value="(checked) => onServiceToggle(service.value, checked)"
|
|
@update:model-value="(checked) => onServiceToggle(service.value, checked)"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div v-else class="text-grey-7 q-mb-lg font12 fontmedium">{{ $t('provider.login.steps.step_5.no_services') }}</div>
|
|
|
|
|
|
|
+ <div v-else class="text-grey-7 q-mb-lg font12 fontmedium">
|
|
|
|
|
+ {{ $t('provider.login.steps.step_5.no_services') }}
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
- <div class="text-grey-7 text-center font12 fontmedium">{{ $t('provider.login.steps.step_5.search_visibility') }}</div>
|
|
|
|
|
|
|
+ <div class="text-grey-7 text-center font12 fontmedium">
|
|
|
|
|
+ {{ $t('provider.login.steps.step_5.search_visibility') }}
|
|
|
|
|
+ </div>
|
|
|
</q-card-section>
|
|
</q-card-section>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
import { computed, onMounted, ref, watch } from 'vue';
|
|
import { computed, onMounted, ref, watch } from 'vue';
|
|
|
|
|
+import { getProviderDailyPriceMin } from 'src/api/provider';
|
|
|
import { getPublicServiceTypes } from 'src/api/serviceType';
|
|
import { getPublicServiceTypes } from 'src/api/serviceType';
|
|
|
import DefaultCurrencyInput from 'src/components/defaults/DefaultCurrencyInput.vue';
|
|
import DefaultCurrencyInput from 'src/components/defaults/DefaultCurrencyInput.vue';
|
|
|
|
|
|
|
|
const form = defineModel({ type: Object, required: true });
|
|
const form = defineModel({ type: Object, required: true });
|
|
|
|
|
|
|
|
|
|
+const DEFAULT_DAILY_PRICE_MIN = 100;
|
|
|
|
|
+const DAILY_PRICE_MAX = 500;
|
|
|
|
|
+
|
|
|
|
|
+const dailyPriceMin = ref(DEFAULT_DAILY_PRICE_MIN);
|
|
|
const loadingServiceTypes = ref(false);
|
|
const loadingServiceTypes = ref(false);
|
|
|
const serviceOptions = ref([]);
|
|
const serviceOptions = ref([]);
|
|
|
|
|
|
|
|
-const priceError = computed(() => {
|
|
|
|
|
- const value = form.value.daily_price_8h;
|
|
|
|
|
|
|
+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 dailyPriceMinMaxText = computed(() => {
|
|
|
|
|
+ return `Valor mínimo ${formatCurrency(dailyPriceMin.value)}. Valor máximo ${formatCurrency(DAILY_PRICE_MAX)}.`;
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const getDailyPriceError = (value) => {
|
|
|
if (value === null || value === undefined || value === '') {
|
|
if (value === null || value === undefined || value === '') {
|
|
|
return 'Este campo é obrigatório';
|
|
return 'Este campo é obrigatório';
|
|
|
}
|
|
}
|
|
@@ -90,16 +157,18 @@ const priceError = computed(() => {
|
|
|
return 'Valor inválido';
|
|
return 'Valor inválido';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (numericValue < 3) {
|
|
|
|
|
- return 'Valor mínimo R$ 3,00';
|
|
|
|
|
|
|
+ if (numericValue < dailyPriceMin.value) {
|
|
|
|
|
+ return `Valor mínimo ${formatCurrency(dailyPriceMin.value)}`;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (numericValue > 500) {
|
|
|
|
|
- return 'Valor máximo R$ 500,00';
|
|
|
|
|
|
|
+ if (numericValue > DAILY_PRICE_MAX) {
|
|
|
|
|
+ return `Valor máximo ${formatCurrency(DAILY_PRICE_MAX)}`;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return '';
|
|
return '';
|
|
|
-});
|
|
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const priceError = computed(() => getDailyPriceError(form.value.daily_price_8h));
|
|
|
|
|
|
|
|
const selectedServices = computed(() => {
|
|
const selectedServices = computed(() => {
|
|
|
if (!Array.isArray(form.value.services_types_ids)) {
|
|
if (!Array.isArray(form.value.services_types_ids)) {
|
|
@@ -109,16 +178,38 @@ const selectedServices = computed(() => {
|
|
|
return form.value.services_types_ids;
|
|
return form.value.services_types_ids;
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-const formatCurrency = (value) => {
|
|
|
|
|
- if (value === null || value === undefined || Number.isNaN(Number(value))) {
|
|
|
|
|
- return 'R$ 0,00';
|
|
|
|
|
|
|
+const loadServiceTypes = async () => {
|
|
|
|
|
+ loadingServiceTypes.value = true;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const serviceTypes = await getPublicServiceTypes();
|
|
|
|
|
+
|
|
|
|
|
+ serviceOptions.value = (Array.isArray(serviceTypes) ? serviceTypes : [])
|
|
|
|
|
+ .filter((item) => item?.is_active !== false)
|
|
|
|
|
+ .map((item) => ({
|
|
|
|
|
+ label: item.description,
|
|
|
|
|
+ value: Number(item.id),
|
|
|
|
|
+ }))
|
|
|
|
|
+ .filter((item) => Number.isInteger(item.value) && item.value > 0);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ serviceOptions.value = [];
|
|
|
|
|
+
|
|
|
|
|
+ console.error(error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loadingServiceTypes.value = false;
|
|
|
}
|
|
}
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
- return Number(value).toLocaleString('pt-BR', {
|
|
|
|
|
- style: 'currency',
|
|
|
|
|
- currency: 'BRL',
|
|
|
|
|
- minimumFractionDigits: 2,
|
|
|
|
|
- });
|
|
|
|
|
|
|
+const loadDailyPriceMin = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const payload = await getProviderDailyPriceMin();
|
|
|
|
|
+
|
|
|
|
|
+ dailyPriceMin.value = parseDailyPriceMin(payload);
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ dailyPriceMin.value = DEFAULT_DAILY_PRICE_MIN;
|
|
|
|
|
+
|
|
|
|
|
+ console.error(error);
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
const normalizeSelectedServiceIds = () => {
|
|
const normalizeSelectedServiceIds = () => {
|
|
@@ -138,31 +229,31 @@ const onServiceToggle = (value, checked) => {
|
|
|
if (!form.value.services_types_ids.includes(value)) {
|
|
if (!form.value.services_types_ids.includes(value)) {
|
|
|
form.value.services_types_ids.push(value);
|
|
form.value.services_types_ids.push(value);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
form.value.services_types_ids = form.value.services_types_ids.filter((serviceId) => serviceId !== value);
|
|
form.value.services_types_ids = form.value.services_types_ids.filter((serviceId) => serviceId !== value);
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-const loadServiceTypes = async () => {
|
|
|
|
|
- loadingServiceTypes.value = true;
|
|
|
|
|
|
|
+const parseDailyPriceMin = (payload) => {
|
|
|
|
|
+ const rawValue = payload?.daily_price_min
|
|
|
|
|
+ ?? payload?.dailyPriceMin
|
|
|
|
|
+ ?? payload?.min
|
|
|
|
|
+ ?? payload?.value
|
|
|
|
|
+ ?? payload;
|
|
|
|
|
|
|
|
- try {
|
|
|
|
|
- const serviceTypes = await getPublicServiceTypes();
|
|
|
|
|
|
|
+ const value = Number(rawValue);
|
|
|
|
|
|
|
|
- serviceOptions.value = (Array.isArray(serviceTypes) ? serviceTypes : [])
|
|
|
|
|
- .filter((item) => item?.is_active !== false)
|
|
|
|
|
- .map((item) => ({
|
|
|
|
|
- label: item.description,
|
|
|
|
|
- value: Number(item.id),
|
|
|
|
|
- }))
|
|
|
|
|
- .filter((item) => Number.isInteger(item.value) && item.value > 0);
|
|
|
|
|
- } catch (error) {
|
|
|
|
|
- serviceOptions.value = [];
|
|
|
|
|
- console.error(error);
|
|
|
|
|
- } finally {
|
|
|
|
|
- loadingServiceTypes.value = false;
|
|
|
|
|
|
|
+ if (!Number.isFinite(value) || value < 0) {
|
|
|
|
|
+ return DEFAULT_DAILY_PRICE_MIN;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ return value;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const validateDailyPrice = () => {
|
|
|
|
|
+ return getDailyPriceError(form.value.daily_price_8h) || true;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
watch(
|
|
watch(
|
|
@@ -186,6 +277,7 @@ watch(
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
loadServiceTypes();
|
|
loadServiceTypes();
|
|
|
|
|
+ loadDailyPriceMin();
|
|
|
});
|
|
});
|
|
|
</script>
|
|
</script>
|
|
|
<style scoped>
|
|
<style scoped>
|
|
@@ -195,4 +287,4 @@ onMounted(() => {
|
|
|
:deep(.custom-currency-input .q-field__control) {
|
|
:deep(.custom-currency-input .q-field__control) {
|
|
|
border-radius: 28px;
|
|
border-radius: 28px;
|
|
|
}
|
|
}
|
|
|
-</style>
|
|
|
|
|
|
|
+</style>
|