|
@@ -1,76 +1,181 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <q-dialog ref="dialogRef" persistent maximized transition-show="slide-left" transition-hide="slide-right">
|
|
|
|
|
|
|
+ <q-dialog
|
|
|
|
|
+ ref="dialogRef"
|
|
|
|
|
+ maximized
|
|
|
|
|
+ persistent
|
|
|
|
|
+ transition-hide="slide-right"
|
|
|
|
|
+ transition-show="slide-left"
|
|
|
|
|
+ >
|
|
|
<div class="bg-page full-height no-shadow">
|
|
<div class="bg-page full-height no-shadow">
|
|
|
- <div class="row items-center q-px-md q-pt-md q-pb-sm bg-white shadow-profile bg-surface">
|
|
|
|
|
- <q-btn v-close-popup icon="mdi-chevron-left" flat round dense color="primary" />
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="row items-center q-px-md q-pt-md q-pb-sm bg-white shadow-profile bg-surface"
|
|
|
|
|
+ >
|
|
|
|
|
+ <q-btn
|
|
|
|
|
+ v-close-popup
|
|
|
|
|
+ color="primary"
|
|
|
|
|
+ dense
|
|
|
|
|
+ flat
|
|
|
|
|
+ icon="mdi-chevron-left"
|
|
|
|
|
+ round
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
<q-space />
|
|
<q-space />
|
|
|
- <span class="text-subtitle1 text-primary font16 fontbold gradient-diarista">{{ $t('profile.address.title') }}</span>
|
|
|
|
|
|
|
+
|
|
|
|
|
+ <span
|
|
|
|
|
+ class="gradient-diarista text-subtitle1 text-primary font16 fontbold"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ $t("profile.address.title") }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+
|
|
|
<q-space />
|
|
<q-space />
|
|
|
|
|
+
|
|
|
<div style="width: 32px"></div>
|
|
<div style="width: 32px"></div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
<div class="col column q-px-lg q-pt-lg overflow-auto">
|
|
<div class="col column q-px-lg q-pt-lg overflow-auto">
|
|
|
- <span class="gradient-diarista q-mb-xs font16 fontbold gradient-diarista">{{ isEditing ? $t('profile.address.edit_address') : $t('profile.address.add_new_address') }}</span>
|
|
|
|
|
- <span class="text-grey-7 q-mb-lg font12 fontregular" style="line-height: 1.3;">{{ isEditing ? $t('profile.address.manage_addresses') : $t('profile.address.add_new_address_label') }}</span>
|
|
|
|
|
|
|
+ <span class="gradient-diarista q-mb-xs font16 fontbold">
|
|
|
|
|
+ {{
|
|
|
|
|
+ isEditing
|
|
|
|
|
+ ? $t("profile.address.edit_address")
|
|
|
|
|
+ : $t("profile.address.add_new_address")
|
|
|
|
|
+ }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+
|
|
|
|
|
+ <span
|
|
|
|
|
+ class="text-grey-7 q-mb-lg font12 fontregular"
|
|
|
|
|
+ style="line-height: 1.3"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{
|
|
|
|
|
+ isEditing
|
|
|
|
|
+ ? $t("profile.address.manage_addresses")
|
|
|
|
|
+ : $t("profile.address.add_new_address_label")
|
|
|
|
|
+ }}
|
|
|
|
|
+ </span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
<q-card-section class="col">
|
|
<q-card-section class="col">
|
|
|
<div class="text-text">
|
|
<div class="text-text">
|
|
|
- <q-card class="q-pa-lg bg-white shadow-card" style="border-radius: 25px;" :flat="false">
|
|
|
|
|
- <div class="text-text q-mb-xs font12 fontbold">{{ $t('profile.address.cep') }}</div>
|
|
|
|
|
|
|
+ <q-card
|
|
|
|
|
+ class="q-pa-lg bg-white shadow-card"
|
|
|
|
|
+ style="border-radius: 25px"
|
|
|
|
|
+ :flat="false"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div class="text-text q-mb-xs font12 fontbold">
|
|
|
|
|
+ {{ $t("profile.address.cep") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
<q-input
|
|
<q-input
|
|
|
v-model="form.zip_code"
|
|
v-model="form.zip_code"
|
|
|
- input-class="text-text"
|
|
|
|
|
- outlined
|
|
|
|
|
|
|
+ class="q-mb-md"
|
|
|
dense
|
|
dense
|
|
|
|
|
+ input-class="text-text"
|
|
|
mask="#####-###"
|
|
mask="#####-###"
|
|
|
- unmasked-value
|
|
|
|
|
|
|
+ outlined
|
|
|
placeholder="00000-000"
|
|
placeholder="00000-000"
|
|
|
- class="q-mb-md"
|
|
|
|
|
|
|
+ unmasked-value
|
|
|
@update:model-value="onCepChange"
|
|
@update:model-value="onCepChange"
|
|
|
>
|
|
>
|
|
|
<template #append>
|
|
<template #append>
|
|
|
- <q-spinner v-if="loadingCep" size="xs" color="primary" />
|
|
|
|
|
|
|
+ <q-spinner
|
|
|
|
|
+ v-if="loadingCep"
|
|
|
|
|
+ color="primary"
|
|
|
|
|
+ size="xs"
|
|
|
|
|
+ />
|
|
|
</template>
|
|
</template>
|
|
|
</q-input>
|
|
</q-input>
|
|
|
|
|
|
|
|
|
|
+ <q-btn
|
|
|
|
|
+ class="full-width q-mb-md"
|
|
|
|
|
+ color="primary-button"
|
|
|
|
|
+ padding="8px 12px"
|
|
|
|
|
+ rounded
|
|
|
|
|
+ :label="$t('auth.use_location')"
|
|
|
|
|
+ :loading="loadingLocation"
|
|
|
|
|
+ @click="useLocation"
|
|
|
|
|
+ />
|
|
|
|
|
+
|
|
|
|
|
+ <div class="q-mb-xs text-text font12 fontbold">
|
|
|
|
|
+ {{ $t("profile.address.address_label") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
|
|
|
- <div class="q-mb-xs text-text font12 fontbold">{{ $t('profile.address.address_label') }}</div>
|
|
|
|
|
<q-input
|
|
<q-input
|
|
|
v-model="form.address"
|
|
v-model="form.address"
|
|
|
- outlined
|
|
|
|
|
- dense
|
|
|
|
|
class="q-mb-md"
|
|
class="q-mb-md"
|
|
|
|
|
+ dense
|
|
|
input-class="text-text"
|
|
input-class="text-text"
|
|
|
|
|
+ outlined
|
|
|
:placeholder="$t('profile.address.address_placeholder')"
|
|
:placeholder="$t('profile.address.address_placeholder')"
|
|
|
/>
|
|
/>
|
|
|
|
|
|
|
|
<div class="row q-col-gutter-sm q-mb-md">
|
|
<div class="row q-col-gutter-sm q-mb-md">
|
|
|
<div class="col-4">
|
|
<div class="col-4">
|
|
|
- <div class="q-mb-xs text-text font12 fontbold">{{ $t('profile.address.number') }}</div>
|
|
|
|
|
- <q-input v-model="form.number" outlined dense input-class="text-text" placeholder="0000" />
|
|
|
|
|
|
|
+ <div class="q-mb-xs text-text font12 fontbold">
|
|
|
|
|
+ {{ $t("profile.address.number") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <q-input
|
|
|
|
|
+ v-model="form.number"
|
|
|
|
|
+ dense
|
|
|
|
|
+ input-class="text-text"
|
|
|
|
|
+ outlined
|
|
|
|
|
+ placeholder="0000"
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
<div class="col-8">
|
|
<div class="col-8">
|
|
|
- <div class="q-mb-xs text-text font12 fontbold">{{ $t('profile.address.complement') }}</div>
|
|
|
|
|
|
|
+ <div class="q-mb-xs text-text font12 fontbold">
|
|
|
|
|
+ {{ $t("profile.address.complement") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
<q-input
|
|
<q-input
|
|
|
v-model="form.complement"
|
|
v-model="form.complement"
|
|
|
- outlined
|
|
|
|
|
dense
|
|
dense
|
|
|
input-class="text-text"
|
|
input-class="text-text"
|
|
|
|
|
+ outlined
|
|
|
:placeholder="$t('profile.address.complement_placeholder')"
|
|
:placeholder="$t('profile.address.complement_placeholder')"
|
|
|
/>
|
|
/>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div class="q-mb-xs text-text font12 fontbold">{{ $t('profile.address.district_label') }}</div>
|
|
|
|
|
- <q-input v-model="form.district" outlined dense class="q-mb-md" input-class="text-text" />
|
|
|
|
|
|
|
+ <div class="q-mb-xs text-text font12 fontbold">
|
|
|
|
|
+ {{ $t("profile.address.district_label") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <q-input
|
|
|
|
|
+ v-model="form.district"
|
|
|
|
|
+ class="q-mb-md"
|
|
|
|
|
+ dense
|
|
|
|
|
+ input-class="text-text"
|
|
|
|
|
+ outlined
|
|
|
|
|
+ />
|
|
|
|
|
|
|
|
<div class="row q-col-gutter-sm q-mb-lg">
|
|
<div class="row q-col-gutter-sm q-mb-lg">
|
|
|
<div class="col-8">
|
|
<div class="col-8">
|
|
|
- <div class="q-mb-xs text-text font12 fontbold">{{ $t('profile.address.city_label') }}</div>
|
|
|
|
|
- <q-input :model-value="form.city?.name" readonly outlined dense input-class="text-text" />
|
|
|
|
|
|
|
+ <div class="q-mb-xs text-text font12 fontbold">
|
|
|
|
|
+ {{ $t("profile.address.city_label") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <q-input
|
|
|
|
|
+ dense
|
|
|
|
|
+ input-class="text-text"
|
|
|
|
|
+ outlined
|
|
|
|
|
+ readonly
|
|
|
|
|
+ :model-value="form.city?.name"
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
<div class="col-4">
|
|
<div class="col-4">
|
|
|
- <div class="q-mb-xs text-text font12 fontbold">{{ $t('profile.address.state_label') }}</div>
|
|
|
|
|
- <q-input :model-value="form.state?.name" readonly outlined dense input-class="text-text" />
|
|
|
|
|
|
|
+ <div class="q-mb-xs text-text font12 fontbold">
|
|
|
|
|
+ {{ $t("profile.address.state_label") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <q-input
|
|
|
|
|
+ dense
|
|
|
|
|
+ input-class="text-text"
|
|
|
|
|
+ outlined
|
|
|
|
|
+ readonly
|
|
|
|
|
+ :model-value="form.state?.name"
|
|
|
|
|
+ />
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
@@ -79,13 +184,13 @@
|
|
|
<q-chip
|
|
<q-chip
|
|
|
v-for="type in addressTypes"
|
|
v-for="type in addressTypes"
|
|
|
:key="type.value"
|
|
:key="type.value"
|
|
|
|
|
+ :icon="type.icon"
|
|
|
|
|
+ :icon-selected="type.icon"
|
|
|
|
|
+ :outline="form.address_type !== type.value"
|
|
|
:selected="form.address_type === type.value"
|
|
:selected="form.address_type === type.value"
|
|
|
clickable
|
|
clickable
|
|
|
color="primary"
|
|
color="primary"
|
|
|
- :outline="form.address_type !== type.value"
|
|
|
|
|
text-color="surface"
|
|
text-color="surface"
|
|
|
- :icon="type.icon"
|
|
|
|
|
- :icon-selected="type.icon"
|
|
|
|
|
@click="form.address_type = type.value"
|
|
@click="form.address_type = type.value"
|
|
|
>
|
|
>
|
|
|
{{ $t(type.label) }}
|
|
{{ $t(type.label) }}
|
|
@@ -93,21 +198,33 @@
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div v-if="missingCoords" class="q-mb-md">
|
|
|
|
|
- <q-banner rounded dense class="bg-orange-1 text-orange-9 q-mb-sm">
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-if="missingCoords"
|
|
|
|
|
+ class="q-mb-md"
|
|
|
|
|
+ >
|
|
|
|
|
+ <q-banner
|
|
|
|
|
+ class="bg-orange-1 text-orange-9 q-mb-sm"
|
|
|
|
|
+ dense
|
|
|
|
|
+ rounded
|
|
|
|
|
+ >
|
|
|
<template #avatar>
|
|
<template #avatar>
|
|
|
- <q-icon name="mdi-map-marker-off" color="orange-7" />
|
|
|
|
|
|
|
+ <q-icon
|
|
|
|
|
+ color="orange-7"
|
|
|
|
|
+ name="mdi-map-marker-off"
|
|
|
|
|
+ />
|
|
|
</template>
|
|
</template>
|
|
|
- {{ $t('profile.address.missing_coords') }}
|
|
|
|
|
|
|
+
|
|
|
|
|
+ {{ $t("profile.address.missing_coords") }}
|
|
|
</q-banner>
|
|
</q-banner>
|
|
|
|
|
+
|
|
|
<q-btn
|
|
<q-btn
|
|
|
- unelevated
|
|
|
|
|
- rounded
|
|
|
|
|
- no-caps
|
|
|
|
|
- outline
|
|
|
|
|
|
|
+ class="full-width"
|
|
|
color="primary"
|
|
color="primary"
|
|
|
icon="mdi-map-marker"
|
|
icon="mdi-map-marker"
|
|
|
- class="full-width"
|
|
|
|
|
|
|
+ no-caps
|
|
|
|
|
+ outline
|
|
|
|
|
+ rounded
|
|
|
|
|
+ unelevated
|
|
|
:label="$t('profile.address.update_on_map')"
|
|
:label="$t('profile.address.update_on_map')"
|
|
|
:loading="geocodingCep"
|
|
:loading="geocodingCep"
|
|
|
@click="openMapDialog"
|
|
@click="openMapDialog"
|
|
@@ -115,19 +232,20 @@
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<q-btn
|
|
<q-btn
|
|
|
- unelevated
|
|
|
|
|
- rounded
|
|
|
|
|
- no-caps
|
|
|
|
|
- color="primary"
|
|
|
|
|
class="full-width q-py-md"
|
|
class="full-width q-py-md"
|
|
|
|
|
+ color="primary"
|
|
|
|
|
+ no-caps
|
|
|
padding="8px 12px"
|
|
padding="8px 12px"
|
|
|
|
|
+ rounded
|
|
|
|
|
+ unelevated
|
|
|
|
|
+ :disable="!hasUpdatedFields"
|
|
|
:label="$t('common.actions.save')"
|
|
:label="$t('common.actions.save')"
|
|
|
:loading="saving"
|
|
:loading="saving"
|
|
|
- :disable="!hasUpdatedFields"
|
|
|
|
|
@click="save"
|
|
@click="save"
|
|
|
/>
|
|
/>
|
|
|
</q-card>
|
|
</q-card>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+
|
|
|
<div class="q-pb-xl"></div>
|
|
<div class="q-pb-xl"></div>
|
|
|
</q-card-section>
|
|
</q-card-section>
|
|
|
</div>
|
|
</div>
|
|
@@ -135,90 +253,128 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { ref, computed, onMounted } from 'vue';
|
|
|
|
|
-import { useDialogPluginComponent, useQuasar } from 'quasar';
|
|
|
|
|
-import { searchAddressByCEP, updateAddress, createAddress } from 'src/api/address';
|
|
|
|
|
-import { userStore } from 'src/stores/user';
|
|
|
|
|
-import { useFormUpdateTracker } from 'src/composables/useFormUpdateTracker';
|
|
|
|
|
-import { useGeocodingApi } from 'src/composables/useGeocodingApi';
|
|
|
|
|
-import { useI18n } from 'vue-i18n';
|
|
|
|
|
-import LocationMapDialog from 'src/components/shared/LocationMapDialog.vue';
|
|
|
|
|
|
|
+import { computed, onMounted, ref } from "vue";
|
|
|
|
|
+
|
|
|
|
|
+import {
|
|
|
|
|
+ createAddress,
|
|
|
|
|
+ searchAddressByCEP,
|
|
|
|
|
+ updateAddress,
|
|
|
|
|
+} from "src/api/address";
|
|
|
|
|
+
|
|
|
|
|
+import { useDialogPluginComponent, useQuasar } from "quasar";
|
|
|
|
|
+import { useFormUpdateTracker } from "src/composables/useFormUpdateTracker";
|
|
|
|
|
+import { useGeocodingApi } from "src/composables/useGeocodingApi";
|
|
|
|
|
+import { useGeolocation } from "src/composables/useGeolocation";
|
|
|
|
|
+import { useI18n } from "vue-i18n";
|
|
|
|
|
+import { userStore } from "src/stores/user";
|
|
|
|
|
+
|
|
|
|
|
+import LocationMapDialog from "src/components/shared/LocationMapDialog.vue";
|
|
|
|
|
+
|
|
|
|
|
+defineEmits([...useDialogPluginComponent.emits]);
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
const props = defineProps({
|
|
|
- isEditing: {
|
|
|
|
|
- type: Boolean,
|
|
|
|
|
- default: false,
|
|
|
|
|
- },
|
|
|
|
|
addressData: {
|
|
addressData: {
|
|
|
- type: Object,
|
|
|
|
|
default: null,
|
|
default: null,
|
|
|
|
|
+ type: Object,
|
|
|
|
|
+ },
|
|
|
|
|
+ isEditing: {
|
|
|
|
|
+ default: false,
|
|
|
|
|
+ type: Boolean,
|
|
|
},
|
|
},
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
-defineEmits([...useDialogPluginComponent.emits]);
|
|
|
|
|
-
|
|
|
|
|
-const { dialogRef, onDialogOK } = useDialogPluginComponent();
|
|
|
|
|
const $q = useQuasar();
|
|
const $q = useQuasar();
|
|
|
const { t } = useI18n();
|
|
const { t } = useI18n();
|
|
|
|
|
+const { dialogRef, onDialogOK } = useDialogPluginComponent();
|
|
|
|
|
+const { geocodeFullAddress } = useGeocodingApi();
|
|
|
|
|
+const { getCurrentPosition, requestPermission } = useGeolocation();
|
|
|
|
|
+
|
|
|
const user = userStore();
|
|
const user = userStore();
|
|
|
|
|
+
|
|
|
|
|
+const addressId = ref(null);
|
|
|
|
|
+const geocodingCep = ref(false);
|
|
|
|
|
+const loadingCep = ref(false);
|
|
|
|
|
+const loadingLocation = ref(false);
|
|
|
|
|
+const saving = ref(false);
|
|
|
|
|
+
|
|
|
|
|
+const missingCoords = computed(
|
|
|
|
|
+ () =>
|
|
|
|
|
+ props.isEditing &&
|
|
|
|
|
+ form.latitude == null &&
|
|
|
|
|
+ form.longitude == null,
|
|
|
|
|
+);
|
|
|
|
|
+
|
|
|
const clientId = user.user.client.id;
|
|
const clientId = user.user.client.id;
|
|
|
-const { geocodeFullAddress } = useGeocodingApi();
|
|
|
|
|
|
|
|
|
|
const initialFormData = {
|
|
const initialFormData = {
|
|
|
- zip_code: '',
|
|
|
|
|
- address: '',
|
|
|
|
|
- number: '',
|
|
|
|
|
- complement: '',
|
|
|
|
|
- district: '',
|
|
|
|
|
- city_id: null,
|
|
|
|
|
- state_id: null,
|
|
|
|
|
|
|
+ address: "",
|
|
|
|
|
+ address_type: "home",
|
|
|
city: null,
|
|
city: null,
|
|
|
- state: null,
|
|
|
|
|
- source: 'client',
|
|
|
|
|
- source_id: clientId,
|
|
|
|
|
- address_type: 'home',
|
|
|
|
|
|
|
+ city_id: null,
|
|
|
|
|
+ complement: "",
|
|
|
|
|
+ district: "",
|
|
|
latitude: null,
|
|
latitude: null,
|
|
|
longitude: null,
|
|
longitude: null,
|
|
|
|
|
+ number: "",
|
|
|
|
|
+ source: "client",
|
|
|
|
|
+ source_id: clientId,
|
|
|
|
|
+ state: null,
|
|
|
|
|
+ state_id: null,
|
|
|
|
|
+ zip_code: "",
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-const { form, hasUpdatedFields, getUpdatedFields, setUpdateFormAsOriginal } =
|
|
|
|
|
- useFormUpdateTracker(initialFormData);
|
|
|
|
|
-
|
|
|
|
|
-const loadingCep = ref(false);
|
|
|
|
|
-const saving = ref(false);
|
|
|
|
|
-const addressId = ref(null);
|
|
|
|
|
-const geocodingCep = ref(false);
|
|
|
|
|
-
|
|
|
|
|
-const missingCoords = computed(() =>
|
|
|
|
|
- props.isEditing && form.latitude == null && form.longitude == null
|
|
|
|
|
-);
|
|
|
|
|
|
|
+const {
|
|
|
|
|
+ form,
|
|
|
|
|
+ getUpdatedFields,
|
|
|
|
|
+ hasUpdatedFields,
|
|
|
|
|
+ setUpdateFormAsOriginal,
|
|
|
|
|
+} = useFormUpdateTracker(initialFormData);
|
|
|
|
|
|
|
|
const addressTypes = [
|
|
const addressTypes = [
|
|
|
- { value: 'home', label: 'profile.address.type.home', icon: 'mdi-home-outline' },
|
|
|
|
|
- { value: 'commercial', label: 'profile.address.type.commercial', icon: 'mdi-briefcase-variant-outline' },
|
|
|
|
|
- { value: 'other', label: 'profile.address.type.other', icon: 'mdi-map-marker-outline' },
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ icon: "mdi-home-outline",
|
|
|
|
|
+ label: "profile.address.type.home",
|
|
|
|
|
+ value: "home",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ icon: "mdi-briefcase-variant-outline",
|
|
|
|
|
+ label: "profile.address.type.commercial",
|
|
|
|
|
+ value: "commercial",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ icon: "mdi-map-marker-outline",
|
|
|
|
|
+ label: "profile.address.type.other",
|
|
|
|
|
+ value: "other",
|
|
|
|
|
+ },
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
const onCepChange = async (val) => {
|
|
const onCepChange = async (val) => {
|
|
|
- if (val?.length === 8) {
|
|
|
|
|
- loadingCep.value = true;
|
|
|
|
|
- try {
|
|
|
|
|
- const data = await searchAddressByCEP(val);
|
|
|
|
|
- if (data) {
|
|
|
|
|
- form.address = data.address;
|
|
|
|
|
- form.district = data.district;
|
|
|
|
|
- form.city_id = data.city_id;
|
|
|
|
|
- form.state_id = data.state_id;
|
|
|
|
|
- form.city = data.city;
|
|
|
|
|
- form.state = data.state;
|
|
|
|
|
- form.latitude = null;
|
|
|
|
|
- form.longitude = null;
|
|
|
|
|
- } else {
|
|
|
|
|
- $q.notify({ type: 'negative', message: t('profile.address.cep_not_found') });
|
|
|
|
|
- }
|
|
|
|
|
- } finally {
|
|
|
|
|
- loadingCep.value = false;
|
|
|
|
|
|
|
+ if (val?.length !== 8) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ loadingCep.value = true;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const data = await searchAddressByCEP(val);
|
|
|
|
|
+
|
|
|
|
|
+ if (data) {
|
|
|
|
|
+ form.address = data.address;
|
|
|
|
|
+ form.city = data.city;
|
|
|
|
|
+ form.city_id = data.city_id;
|
|
|
|
|
+ form.district = data.district;
|
|
|
|
|
+ form.latitude = null;
|
|
|
|
|
+ form.longitude = null;
|
|
|
|
|
+ form.state = data.state;
|
|
|
|
|
+ form.state_id = data.state_id;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $q.notify({
|
|
|
|
|
+ message: t("profile.address.cep_not_found"),
|
|
|
|
|
+ type: "negative",
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loadingCep.value = false;
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -228,74 +384,181 @@ const openMapDialog = async () => {
|
|
|
|
|
|
|
|
const hasAddress = form.address || form.zip_code;
|
|
const hasAddress = form.address || form.zip_code;
|
|
|
|
|
|
|
|
- $q.notify({ color: 'indigo-9', textColor: 'white', position: 'top', message: '[ADDR] openMapDialog iniciado', caption: `hasAddress: ${hasAddress}\naddress: ${form.address}\nzip_code: ${form.zip_code}\nlat: ${form.latitude}\nlng: ${form.longitude}`, timeout: 8000, multiLine: true });
|
|
|
|
|
|
|
+ $q.notify({
|
|
|
|
|
+ caption: `hasAddress: ${hasAddress}\naddress: ${form.address}\nzip_code: ${form.zip_code}\nlat: ${form.latitude}\nlng: ${form.longitude}`,
|
|
|
|
|
+ color: "indigo-9",
|
|
|
|
|
+ message: "[ADDR] openMapDialog iniciado",
|
|
|
|
|
+ multiLine: true,
|
|
|
|
|
+ position: "top",
|
|
|
|
|
+ textColor: "white",
|
|
|
|
|
+ timeout: 8000,
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
if (hasAddress) {
|
|
if (hasAddress) {
|
|
|
geocodingCep.value = true;
|
|
geocodingCep.value = true;
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
const geo = await geocodeFullAddress({
|
|
const geo = await geocodeFullAddress({
|
|
|
- address: form.address,
|
|
|
|
|
- number: form.number,
|
|
|
|
|
|
|
+ address: form.address,
|
|
|
|
|
+ city: form.city?.name,
|
|
|
district: form.district,
|
|
district: form.district,
|
|
|
|
|
+ number: form.number,
|
|
|
|
|
+ state: form.state?.name,
|
|
|
zip_code: form.zip_code,
|
|
zip_code: form.zip_code,
|
|
|
- city: form.city?.name,
|
|
|
|
|
- state: form.state?.name,
|
|
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
if (geo) {
|
|
if (geo) {
|
|
|
initialLat = geo.lat;
|
|
initialLat = geo.lat;
|
|
|
initialLng = geo.lng;
|
|
initialLng = geo.lng;
|
|
|
- $q.notify({ color: 'indigo-9', textColor: 'white', position: 'top', message: '[ADDR] geocodeFullAddress OK', caption: `lat: ${geo.lat}\nlng: ${geo.lng}`, timeout: 8000, multiLine: true });
|
|
|
|
|
|
|
+
|
|
|
|
|
+ $q.notify({
|
|
|
|
|
+ caption: `lat: ${geo.lat}\nlng: ${geo.lng}`,
|
|
|
|
|
+ color: "indigo-9",
|
|
|
|
|
+ message: "[ADDR] geocodeFullAddress OK",
|
|
|
|
|
+ multiLine: true,
|
|
|
|
|
+ position: "top",
|
|
|
|
|
+ textColor: "white",
|
|
|
|
|
+ timeout: 8000,
|
|
|
|
|
+ });
|
|
|
} else {
|
|
} else {
|
|
|
- $q.notify({ color: 'indigo-9', textColor: 'white', position: 'top', message: '[ADDR] geocodeFullAddress retornou null — usando coord default', timeout: 6000 });
|
|
|
|
|
|
|
+ $q.notify({
|
|
|
|
|
+ color: "indigo-9",
|
|
|
|
|
+ message:
|
|
|
|
|
+ "[ADDR] geocodeFullAddress retornou null — usando coord default",
|
|
|
|
|
+ position: "top",
|
|
|
|
|
+ textColor: "white",
|
|
|
|
|
+ timeout: 6000,
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
} catch (err) {
|
|
} catch (err) {
|
|
|
- $q.notify({ color: 'indigo-9', textColor: 'white', position: 'top', message: '[ADDR] geocodeFullAddress ERRO — usando coord default', caption: `erro: ${err?.message ?? String(err)}`, timeout: 8000, multiLine: true });
|
|
|
|
|
|
|
+ $q.notify({
|
|
|
|
|
+ caption: `erro: ${err?.message ?? String(err)}`,
|
|
|
|
|
+ color: "indigo-9",
|
|
|
|
|
+ message: "[ADDR] geocodeFullAddress ERRO — usando coord default",
|
|
|
|
|
+ multiLine: true,
|
|
|
|
|
+ position: "top",
|
|
|
|
|
+ textColor: "white",
|
|
|
|
|
+ timeout: 8000,
|
|
|
|
|
+ });
|
|
|
} finally {
|
|
} finally {
|
|
|
geocodingCep.value = false;
|
|
geocodingCep.value = false;
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
- $q.notify({ color: 'indigo-9', textColor: 'white', position: 'top', message: '[ADDR] sem endereço preenchido — abrindo mapa com coord default', timeout: 6000 });
|
|
|
|
|
|
|
+ $q.notify({
|
|
|
|
|
+ color: "indigo-9",
|
|
|
|
|
+ message:
|
|
|
|
|
+ "[ADDR] sem endereço preenchido — abrindo mapa com coord default",
|
|
|
|
|
+ position: "top",
|
|
|
|
|
+ textColor: "white",
|
|
|
|
|
+ timeout: 6000,
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const dialogProps = initialLat !== null
|
|
|
|
|
- ? { initialLat, initialLng }
|
|
|
|
|
- : {};
|
|
|
|
|
|
|
+ const dialogProps =
|
|
|
|
|
+ initialLat !== null
|
|
|
|
|
+ ? {
|
|
|
|
|
+ initialLat,
|
|
|
|
|
+ initialLng,
|
|
|
|
|
+ }
|
|
|
|
|
+ : {};
|
|
|
|
|
+
|
|
|
|
|
+ $q.notify({
|
|
|
|
|
+ caption: `initialLat: ${
|
|
|
|
|
+ dialogProps.initialLat ?? "default"
|
|
|
|
|
+ }\ninitialLng: ${dialogProps.initialLng ?? "default"}`,
|
|
|
|
|
+ color: "indigo-9",
|
|
|
|
|
+ message: "[ADDR] abrindo LocationMapDialog",
|
|
|
|
|
+ multiLine: true,
|
|
|
|
|
+ position: "top",
|
|
|
|
|
+ textColor: "white",
|
|
|
|
|
+ timeout: 8000,
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- $q.notify({ color: 'indigo-9', textColor: 'white', position: 'top', message: '[ADDR] abrindo LocationMapDialog', caption: `initialLat: ${dialogProps.initialLat ?? 'default'}\ninitialLng: ${dialogProps.initialLng ?? 'default'}`, timeout: 8000, multiLine: true });
|
|
|
|
|
|
|
+ showMapDialog(dialogProps);
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
|
|
+const showMapDialog = (dialogProps = {}) => {
|
|
|
$q.dialog({
|
|
$q.dialog({
|
|
|
component: LocationMapDialog,
|
|
component: LocationMapDialog,
|
|
|
componentProps: dialogProps,
|
|
componentProps: dialogProps,
|
|
|
}).onOk(async (geoData) => {
|
|
}).onOk(async (geoData) => {
|
|
|
|
|
+ form.address = geoData.address || form.address;
|
|
|
|
|
+ form.district = geoData.district || form.district;
|
|
|
form.latitude = geoData.lat;
|
|
form.latitude = geoData.lat;
|
|
|
form.longitude = geoData.lng;
|
|
form.longitude = geoData.lng;
|
|
|
- form.address = geoData.address || form.address;
|
|
|
|
|
form.number = geoData.number || form.number;
|
|
form.number = geoData.number || form.number;
|
|
|
- form.district = geoData.district || form.district;
|
|
|
|
|
|
|
|
|
|
- if (geoData.zip_code) {
|
|
|
|
|
- form.zip_code = geoData.zip_code.replace(/\D/g, '');
|
|
|
|
|
- try {
|
|
|
|
|
- const addressData = await searchAddressByCEP(form.zip_code);
|
|
|
|
|
- if (addressData) {
|
|
|
|
|
- form.city_id = addressData.city_id;
|
|
|
|
|
- form.state_id = addressData.state_id;
|
|
|
|
|
- form.city = addressData.city;
|
|
|
|
|
- form.state = addressData.state;
|
|
|
|
|
- }
|
|
|
|
|
- } catch {
|
|
|
|
|
- // mantém cidade/estado atual se lookup falhar
|
|
|
|
|
|
|
+ if (!geoData.zip_code) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ form.zip_code = geoData.zip_code.replace(/\D/g, "");
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const addressData = await searchAddressByCEP(form.zip_code);
|
|
|
|
|
+
|
|
|
|
|
+ if (addressData) {
|
|
|
|
|
+ form.city = addressData.city;
|
|
|
|
|
+ form.city_id = addressData.city_id;
|
|
|
|
|
+ form.state = addressData.state;
|
|
|
|
|
+ form.state_id = addressData.state_id;
|
|
|
}
|
|
}
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ // Mantém cidade e estado atuais caso a busca falhe.
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+const useLocation = async () => {
|
|
|
|
|
+ loadingLocation.value = true;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const granted = await requestPermission();
|
|
|
|
|
+
|
|
|
|
|
+ if (!granted) {
|
|
|
|
|
+ $q.notify({
|
|
|
|
|
+ message: t("auth.location_permission_denied"),
|
|
|
|
|
+ type: "warning",
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const position = await getCurrentPosition();
|
|
|
|
|
+
|
|
|
|
|
+ showMapDialog({
|
|
|
|
|
+ initialLat: position.lat,
|
|
|
|
|
+ initialLng: position.lng,
|
|
|
|
|
+ });
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ const isPermissionError =
|
|
|
|
|
+ err?.code === 1 ||
|
|
|
|
|
+ err?.message?.toLowerCase().includes("denied");
|
|
|
|
|
+
|
|
|
|
|
+ $q.notify({
|
|
|
|
|
+ message: isPermissionError
|
|
|
|
|
+ ? t("auth.location_permission_denied")
|
|
|
|
|
+ : t("auth.location_error"),
|
|
|
|
|
+ type: "warning",
|
|
|
|
|
+ });
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loadingLocation.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+//
|
|
|
|
|
+
|
|
|
const save = async () => {
|
|
const save = async () => {
|
|
|
saving.value = true;
|
|
saving.value = true;
|
|
|
|
|
+
|
|
|
try {
|
|
try {
|
|
|
let response;
|
|
let response;
|
|
|
|
|
+
|
|
|
if (props.isEditing && addressId.value) {
|
|
if (props.isEditing && addressId.value) {
|
|
|
- response = await updateAddress(getUpdatedFields.value, addressId.value);
|
|
|
|
|
|
|
+ response = await updateAddress(
|
|
|
|
|
+ getUpdatedFields.value,
|
|
|
|
|
+ addressId.value,
|
|
|
|
|
+ );
|
|
|
} else {
|
|
} else {
|
|
|
response = await createAddress({ ...form });
|
|
response = await createAddress({ ...form });
|
|
|
}
|
|
}
|
|
@@ -305,39 +568,43 @@ const save = async () => {
|
|
|
onDialogOK(response);
|
|
onDialogOK(response);
|
|
|
}
|
|
}
|
|
|
} catch (error) {
|
|
} catch (error) {
|
|
|
- console.error('Erro ao salvar endereço:', error);
|
|
|
|
|
- $q.notify({ type: 'negative', message: t('profile.address.error_saving') });
|
|
|
|
|
|
|
+ console.error("Erro ao salvar endereço:", error);
|
|
|
|
|
+
|
|
|
|
|
+ $q.notify({
|
|
|
|
|
+ message: t("profile.address.error_saving"),
|
|
|
|
|
+ type: "negative",
|
|
|
|
|
+ });
|
|
|
} finally {
|
|
} finally {
|
|
|
saving.value = false;
|
|
saving.value = false;
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
- if (props.isEditing && props.addressData) {
|
|
|
|
|
- addressId.value = props.addressData.id;
|
|
|
|
|
-
|
|
|
|
|
- const initialData = {
|
|
|
|
|
- zip_code: props.addressData.zip_code || '',
|
|
|
|
|
- address: props.addressData.address || '',
|
|
|
|
|
- number: props.addressData.number || '',
|
|
|
|
|
- complement: props.addressData.complement || '',
|
|
|
|
|
- district: props.addressData.district || '',
|
|
|
|
|
- city_id: props.addressData.city_id || null,
|
|
|
|
|
- state_id: props.addressData.state_id || null,
|
|
|
|
|
- city: props.addressData.city || null,
|
|
|
|
|
- state: props.addressData.state || null,
|
|
|
|
|
- source: 'client',
|
|
|
|
|
- source_id: clientId,
|
|
|
|
|
- address_type: props.addressData.address_type || 'home',
|
|
|
|
|
- latitude: props.addressData.latitude ?? null,
|
|
|
|
|
- longitude: props.addressData.longitude ?? null,
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- Object.assign(form, initialData);
|
|
|
|
|
- setUpdateFormAsOriginal();
|
|
|
|
|
|
|
+ if (!props.isEditing || !props.addressData) {
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
-});
|
|
|
|
|
-</script>
|
|
|
|
|
|
|
|
|
|
-<style scoped>
|
|
|
|
|
-</style>
|
|
|
|
|
|
|
+ addressId.value = props.addressData.id;
|
|
|
|
|
+
|
|
|
|
|
+ const initialData = {
|
|
|
|
|
+ address: props.addressData.address || "",
|
|
|
|
|
+ address_type: props.addressData.address_type || "home",
|
|
|
|
|
+ city: props.addressData.city || null,
|
|
|
|
|
+ city_id: props.addressData.city_id || null,
|
|
|
|
|
+ complement: props.addressData.complement || "",
|
|
|
|
|
+ district: props.addressData.district || "",
|
|
|
|
|
+ latitude: props.addressData.latitude ?? null,
|
|
|
|
|
+ longitude: props.addressData.longitude ?? null,
|
|
|
|
|
+ number: props.addressData.number || "",
|
|
|
|
|
+ source: "client",
|
|
|
|
|
+ source_id: clientId,
|
|
|
|
|
+ state: props.addressData.state || null,
|
|
|
|
|
+ state_id: props.addressData.state_id || null,
|
|
|
|
|
+ zip_code: props.addressData.zip_code || "",
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ Object.assign(form, initialData);
|
|
|
|
|
+
|
|
|
|
|
+ setUpdateFormAsOriginal();
|
|
|
|
|
+});
|
|
|
|
|
+</script>
|