| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468 |
- <template>
- <q-card-section class="no-padding">
- <div>
- <div class="text-text">
- <span class="font14 fontbold">
- {{ $t("auth.full_name") }}
- </span>
- </div>
- <q-input
- v-model="form.name"
- bg-color="surface"
- class="q-mt-sm q-mb-md"
- hide-bottom-space
- input-class="text-text"
- lazy-rules
- no-error-icon
- outlined
- rounded
- :error="!!serverErrors.name"
- :error-message="serverErrors.name"
- :placeholder="$t('auth.full_name')"
- :rules="[inputRules.required]"
- @update:model-value="clearServerError('name')"
- />
- </div>
- <div>
- <div class="text-text">
- <span class="font14 fontbold">
- {{ $t("common.terms.cpf") }}
- </span>
- </div>
- <q-input
- v-model="form.document"
- bg-color="surface"
- class="q-mt-sm q-mb-md"
- hide-bottom-space
- input-class="text-text"
- lazy-rules
- mask="###.###.###-##"
- no-error-icon
- outlined
- placeholder="000.000.000-00"
- rounded
- type="tel"
- unmasked-value
- :error="!!serverErrors.document"
- :error-message="serverErrors.document"
- :rules="[inputRules.required, inputRules.cpf]"
- @update:model-value="clearServerError('document')"
- />
- </div>
- <div>
- <div class="text-text">
- <span class="font14 fontbold">
- {{ $t("common.terms.phone") }}
- </span>
- </div>
- <q-input
- v-model="form.phone"
- bg-color="surface"
- class="q-mt-sm q-mb-md"
- hide-bottom-space
- input-class="text-text"
- lazy-rules
- mask="(##) #####-####"
- no-error-icon
- outlined
- rounded
- :error="!!serverErrors.phone"
- :error-message="serverErrors.phone"
- :placeholder="$t('common.terms.phone')"
- :rules="[inputRules.required, inputRules.phone]"
- @update:model-value="clearServerError('phone')"
- />
- </div>
- <div>
- <div class="text-text">
- <span class="font14 fontbold">
- {{ $t("common.terms.cep") }}
- </span>
- </div>
- <q-input
- v-model="form.zip_code"
- bg-color="surface"
- class="q-mt-sm q-mb-md"
- hide-bottom-space
- input-class="text-text"
- lazy-rules
- mask="#####-###"
- no-error-icon
- outlined
- placeholder="00000-000"
- rounded
- :error="!!serverErrors.zip_code"
- :error-message="serverErrors.zip_code"
- :loading="loadingCep"
- :rules="[inputRules.required, inputRules.cep]"
- @update:model-value="(clearServerError('zip_code'), onCepChange($event))"
- />
- </div>
- <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>
- <div class="text-text">
- <span class="font14 fontbold">
- {{ $t("common.terms.address") }}
- </span>
- </div>
- <q-input
- v-model="form.address"
- bg-color="surface"
- class="q-mt-sm q-mb-md"
- hide-bottom-space
- input-class="text-text"
- lazy-rules
- no-error-icon
- outlined
- readonly
- rounded
- :error="!!serverErrors.address"
- :error-message="serverErrors.address"
- :placeholder="`${$t('common.terms.address')}...`"
- :rules="[inputRules.required]"
- />
- </div>
- <div class="row q-col-gutter-sm">
- <div class="col-4">
- <div class="text-text">
- <span class="font14 fontbold">
- {{ $t("common.terms.address_number") }}
- </span>
- </div>
- <q-input
- v-model="form.number"
- bg-color="surface"
- class="q-mt-sm q-mb-md"
- hide-bottom-space
- input-class="text-text"
- lazy-rules
- no-error-icon
- outlined
- placeholder="0000"
- rounded
- :error="!!serverErrors.number"
- :error-message="serverErrors.number"
- :rules="[inputRules.required]"
- @update:model-value="clearServerError('number')"
- />
- </div>
- <div class="col-8">
- <div class="text-text">
- <span class="font14 fontbold">
- {{ $t("common.terms.district") }}
- </span>
- </div>
- <q-input
- v-model="form.district"
- bg-color="surface"
- class="q-mt-sm q-mb-md"
- hide-bottom-space
- input-class="text-text"
- lazy-rules
- no-error-icon
- outlined
- readonly
- rounded
- :error="!!serverErrors.district"
- :error-message="serverErrors.district"
- :placeholder="`${$t('common.terms.district')}...`"
- :rules="[inputRules.required]"
- />
- </div>
- </div>
- <div class="row q-col-gutter-sm">
- <div class="col-8">
- <div class="text-text">
- <span class="font14 fontbold">
- {{ $t("common.terms.city") }}
- </span>
- </div>
- <q-input
- v-model="form.city"
- bg-color="surface"
- class="q-mt-sm q-mb-md"
- hide-bottom-space
- input-class="text-text"
- lazy-rules
- no-error-icon
- outlined
- readonly
- rounded
- :error="!!serverErrors.city"
- :error-message="serverErrors.city"
- :rules="[inputRules.required]"
- />
- </div>
- <div class="col-4">
- <div class="text-text">
- <span class="font14 fontbold">
- {{ $t("common.terms.state") }}
- </span>
- </div>
- <q-input
- v-model="form.state"
- bg-color="surface"
- class="q-mt-sm q-mb-md"
- hide-bottom-space
- input-class="text-text"
- lazy-rules
- no-error-icon
- outlined
- readonly
- rounded
- :error="!!serverErrors.state"
- :error-message="serverErrors.state"
- :rules="[inputRules.required]"
- />
- </div>
- </div>
- <div>
- <div class="text-text">
- <span class="font14 fontbold">
- {{ $t("common.terms.complement") }}
- </span>
- </div>
- <q-input
- v-model="form.complement"
- bg-color="surface"
- class="q-mt-sm q-mb-md"
- hide-bottom-space
- input-class="text-text"
- lazy-rules
- no-error-icon
- outlined
- rounded
- :error="!!serverErrors.complement"
- :error-message="serverErrors.complement"
- :placeholder="`${$t('common.ui.misc.example')}: Apartamento, Conjunto, Casa`"
- :rules="[inputRules.required]"
- @update:model-value="clearServerError('complement')"
- />
- </div>
- <div>
- <div class="text-text">
- <span class="font14 fontbold">
- {{ $t("auth.address_nickname") }}
- </span>
- </div>
- <q-input
- v-model="form.nickname"
- bg-color="surface"
- class="q-mt-sm q-mb-md"
- hide-bottom-space
- input-class="text-text"
- lazy-rules
- no-error-icon
- outlined
- rounded
- :placeholder="`${$t('common.ui.misc.example')}: Casa`"
- />
- </div>
- <div>
- <div class="row q-gutter-sm q-mt-xs">
- <q-chip
- v-for="type in addressTypes"
- :key="type.value"
- :icon="type.icon"
- :icon-selected="type.icon"
- :outline="form.address_type !== type.value"
- :selected="form.address_type === type.value"
- clickable
- color="primary"
- text-color="surface"
- @click="form.address_type = type.value"
- >
- {{ $t(type.label) }}
- </q-chip>
- </div>
- </div>
- </q-card-section>
- </template>
- <script setup>
- import axios from "axios";
- import { inject, ref } from "vue";
- import { useGeolocation } from "src/composables/useGeolocation";
- import { useI18n } from "vue-i18n";
- import { useInputRules } from "src/composables/useInputRules";
- import { useQuasar } from "quasar";
- import LocationMapDialog from "src/components/shared/LocationMapDialog.vue";
- const form = defineModel({
- required: true,
- type: Object,
- });
- defineProps({
- serverErrors: {
- type: Object,
- default: () => ({}),
- },
- });
- const clearServerError = inject("clearServerError", () => {});
- const { requestPermission, getCurrentPosition } = useGeolocation();
- const { inputRules } = useInputRules();
- const { t } = useI18n();
- const $q = useQuasar();
- const loadingCep = ref(false);
- const loadingLocation = ref(false);
- const addressTypes = [
- {
- icon: "mdi-home-outline",
- label: "auth.address_type_home",
- value: "home",
- },
- {
- icon: "mdi-briefcase-variant-outline",
- label: "auth.address_type_commercial",
- value: "commercial",
- },
- {
- icon: "mdi-map-marker-outline",
- label: "auth.address_type_other",
- value: "other",
- },
- ];
- const fetchCep = async (rawCep) => {
- const cleaned = rawCep.replace(/\D/g, "");
- if (cleaned.length !== 8) {
- return;
- }
- loadingCep.value = true;
- try {
- const { data } = await axios.get(
- `https://viacep.com.br/ws/${cleaned}/json/`,
- );
- if (!data.erro) {
- form.value.address = data.logradouro ?? "";
- form.value.district = data.bairro ?? "";
- form.value.city = data.localidade ?? "";
- form.value.state = data.uf ?? "";
- } else {
- form.value.address = "";
- form.value.district = "";
- form.value.city = "";
- form.value.state = "";
- }
- } catch {
- form.value.address = "";
- form.value.district = "";
- form.value.city = "";
- form.value.state = "";
- } finally {
- loadingCep.value = false;
- }
- };
- const onCepChange = (val) => {
- const cleaned = val ? val.replace(/\D/g, "") : "";
- form.value.latitude = null;
- form.value.longitude = null;
- if (cleaned.length === 8) {
- fetchCep(val);
- } else {
- form.value.address = "";
- form.value.district = "";
- form.value.city = "";
- form.value.state = "";
- }
- };
- const showCurrentLocationOnMap = ({ lat, lng }) => {
- $q.dialog({
- component: LocationMapDialog,
- componentProps: {
- initialLat: lat,
- initialLng: lng,
- },
- }).onOk((geoData) => {
- form.value.zip_code = geoData.zip_code ?? "";
- form.value.address = geoData.address ?? "";
- form.value.number = geoData.number ?? "";
- form.value.district = geoData.district ?? "";
- form.value.city = geoData.city ?? "";
- form.value.state = geoData.state ?? "";
- form.value.latitude = geoData.lat;
- form.value.longitude = geoData.lng;
- });
- };
- 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();
- showCurrentLocationOnMap(position);
- } 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;
- }
- };
- </script>
|