|
@@ -3,28 +3,28 @@
|
|
|
ref="dialogRef"
|
|
ref="dialogRef"
|
|
|
@hide="onDialogHide"
|
|
@hide="onDialogHide"
|
|
|
>
|
|
>
|
|
|
- <q-card class="provider-dialog">
|
|
|
|
|
|
|
+ <q-card class="provider-dialog card-border shadow-card bg-surface text-text">
|
|
|
|
|
|
|
|
<q-btn
|
|
<q-btn
|
|
|
- flat
|
|
|
|
|
- round
|
|
|
|
|
|
|
+ class="close-btn"
|
|
|
|
|
+ color="grey-7"
|
|
|
dense
|
|
dense
|
|
|
|
|
+ flat
|
|
|
icon="close"
|
|
icon="close"
|
|
|
- class="close-btn"
|
|
|
|
|
|
|
+ round
|
|
|
@click="closeDialog"
|
|
@click="closeDialog"
|
|
|
/>
|
|
/>
|
|
|
|
|
|
|
|
<q-card-section class="provider-header">
|
|
<q-card-section class="provider-header">
|
|
|
|
|
|
|
|
<q-avatar
|
|
<q-avatar
|
|
|
- size="72px"
|
|
|
|
|
- color="primary"
|
|
|
|
|
- text-color="white"
|
|
|
|
|
class="provider-avatar"
|
|
class="provider-avatar"
|
|
|
|
|
+ size="72px"
|
|
|
|
|
+ :style="avatarColors[(info.provider_id ?? 0) % avatarColors.length]"
|
|
|
>
|
|
>
|
|
|
<img
|
|
<img
|
|
|
- v-if="props.provider.provider_photo"
|
|
|
|
|
- :src="props.provider.provider_photo"
|
|
|
|
|
|
|
+ v-if="photoUrl"
|
|
|
|
|
+ :src="photoUrl"
|
|
|
>
|
|
>
|
|
|
|
|
|
|
|
<span
|
|
<span
|
|
@@ -37,45 +37,55 @@
|
|
|
|
|
|
|
|
<div class="provider-info">
|
|
<div class="provider-info">
|
|
|
|
|
|
|
|
- <div class="text-h6 text-weight-bold">
|
|
|
|
|
- {{ props.provider.provider_name }}
|
|
|
|
|
|
|
+ <div class="font16 fontbold text-text">
|
|
|
|
|
+ {{ firstName }}
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <div v-if="props.provider.age" class="text-grey-6 text-body2">
|
|
|
|
|
- {{ `${props.provider.age}` }}
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ <div class="font10 fontmedium text-grey-7">
|
|
|
|
|
+ {{ info.district ?? "—" }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-if="info.age"
|
|
|
|
|
+ class="font10 fontmedium text-grey-7"
|
|
|
|
|
+ >
|
|
|
|
|
+ <span>
|
|
|
|
|
+ {{ $t("scheduling_page.provider_info.age", { value: info.age }) }}
|
|
|
|
|
+ </span>
|
|
|
|
|
|
|
|
- <div class="text-grey-6">
|
|
|
|
|
- {{ props.provider.district }}
|
|
|
|
|
|
|
+ <span class="q-ml-md">
|
|
|
|
|
+ {{ $t("scheduling_page.provider_info.gender", { value: genderLabel }) }}
|
|
|
|
|
+ </span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
+
|
|
|
<div class="provider-stats">
|
|
<div class="provider-stats">
|
|
|
|
|
|
|
|
<div class="row items-center">
|
|
<div class="row items-center">
|
|
|
<q-icon
|
|
<q-icon
|
|
|
- color="amber"
|
|
|
|
|
|
|
+ color="warning"
|
|
|
name="mdi-star"
|
|
name="mdi-star"
|
|
|
- size="18px"
|
|
|
|
|
|
|
+ size="16px"
|
|
|
/>
|
|
/>
|
|
|
|
|
|
|
|
- <span class="q-ml-xs">
|
|
|
|
|
- {{ props.provider.average_rating }}
|
|
|
|
|
|
|
+ <span class="font10 fontmedium q-ml-xs">
|
|
|
|
|
+ {{ ratingLabel }}
|
|
|
</span>
|
|
</span>
|
|
|
|
|
|
|
|
- <span class="text-grey q-ml-xs">
|
|
|
|
|
- {{ `(${props.provider.total_reviews})` }}
|
|
|
|
|
|
|
+ <span class="font10 fontmedium text-grey-7 q-ml-xs">
|
|
|
|
|
+ {{ `(${info.total_reviews ?? 0})` }}
|
|
|
</span>
|
|
</span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
<div class="row items-center">
|
|
<div class="row items-center">
|
|
|
<q-icon
|
|
<q-icon
|
|
|
- color="deep-purple"
|
|
|
|
|
|
|
+ color="secondary"
|
|
|
name="mdi-broom"
|
|
name="mdi-broom"
|
|
|
- size="18px"
|
|
|
|
|
|
|
+ size="16px"
|
|
|
/>
|
|
/>
|
|
|
|
|
|
|
|
- <span class="q-ml-xs">
|
|
|
|
|
- {{ `(${props.provider.total_services})` }}
|
|
|
|
|
|
|
+ <span class="font10 fontmedium q-ml-xs">
|
|
|
|
|
+ {{ `(${info.total_services ?? 0})` }}
|
|
|
</span>
|
|
</span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
@@ -87,36 +97,57 @@
|
|
|
|
|
|
|
|
<q-separator />
|
|
<q-separator />
|
|
|
|
|
|
|
|
- <!-- Especialidades -->
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-if="loading"
|
|
|
|
|
+ class="row items-center justify-center q-py-md"
|
|
|
|
|
+ >
|
|
|
|
|
+ <q-spinner-dots
|
|
|
|
|
+ color="primary"
|
|
|
|
|
+ size="32px"
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
<q-list
|
|
<q-list
|
|
|
- v-if="props.provider.specialities?.length"
|
|
|
|
|
- dense
|
|
|
|
|
|
|
+ v-else-if="serviceTypes.length"
|
|
|
class="q-pa-sm"
|
|
class="q-pa-sm"
|
|
|
|
|
+ dense
|
|
|
>
|
|
>
|
|
|
<q-item
|
|
<q-item
|
|
|
- v-for="speciality in props.provider.specialities"
|
|
|
|
|
- :key="speciality.id"
|
|
|
|
|
|
|
+ v-for="serviceType in serviceTypes"
|
|
|
|
|
+ :key="serviceType.id"
|
|
|
>
|
|
>
|
|
|
<q-item-section avatar>
|
|
<q-item-section avatar>
|
|
|
<q-icon
|
|
<q-icon
|
|
|
- name="mdi-check-circle"
|
|
|
|
|
- color="positive"
|
|
|
|
|
|
|
+ color="primary"
|
|
|
|
|
+ name="mdi-check"
|
|
|
/>
|
|
/>
|
|
|
</q-item-section>
|
|
</q-item-section>
|
|
|
|
|
|
|
|
- <q-item-section>
|
|
|
|
|
- {{ speciality.description }}
|
|
|
|
|
|
|
+ <q-item-section class="font12 fontmedium text-text">
|
|
|
|
|
+ {{ serviceType.description }}
|
|
|
</q-item-section>
|
|
</q-item-section>
|
|
|
</q-item>
|
|
</q-item>
|
|
|
</q-list>
|
|
</q-list>
|
|
|
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-else
|
|
|
|
|
+ class="text-center text-grey-6 font10 fontmedium q-pa-md"
|
|
|
|
|
+ >
|
|
|
|
|
+ {{ $t("scheduling_page.provider_info.no_service_types") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
</q-card>
|
|
</q-card>
|
|
|
</q-dialog>
|
|
</q-dialog>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { computed } from "vue";
|
|
|
|
|
|
|
+import { computed, onMounted, ref } from "vue";
|
|
|
import { useDialogPluginComponent } from "quasar";
|
|
import { useDialogPluginComponent } from "quasar";
|
|
|
|
|
+import { avatarColors } from "src/helpers/avatarColors";
|
|
|
|
|
+import { getFirstName } from "src/helpers/utils";
|
|
|
|
|
+import { getPerfilPrestador } from "src/api/dashboard";
|
|
|
|
|
+import { getProfileMediaUrl } from "src/helpers/profileMedia";
|
|
|
|
|
+import { useI18n } from "vue-i18n";
|
|
|
|
|
|
|
|
const props = defineProps({
|
|
const props = defineProps({
|
|
|
provider: {
|
|
provider: {
|
|
@@ -132,21 +163,57 @@ const {
|
|
|
onDialogHide,
|
|
onDialogHide,
|
|
|
} = useDialogPluginComponent();
|
|
} = useDialogPluginComponent();
|
|
|
|
|
|
|
|
|
|
+const { t } = useI18n();
|
|
|
|
|
+
|
|
|
|
|
+const loading = ref(false);
|
|
|
|
|
+const info = ref({ ...props.provider });
|
|
|
|
|
+
|
|
|
const closeDialog = () => {
|
|
const closeDialog = () => {
|
|
|
dialogRef.value.hide();
|
|
dialogRef.value.hide();
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-const initials = computed(() => {
|
|
|
|
|
- if (!props.provider.provider_name) {
|
|
|
|
|
- return "?";
|
|
|
|
|
- }
|
|
|
|
|
|
|
+const firstName = computed(
|
|
|
|
|
+ () => getFirstName(info.value.provider_name) || "—"
|
|
|
|
|
+);
|
|
|
|
|
+
|
|
|
|
|
+const photoUrl = computed(() => getProfileMediaUrl(info.value));
|
|
|
|
|
+
|
|
|
|
|
+const serviceTypes = computed(() => info.value.service_types ?? []);
|
|
|
|
|
+
|
|
|
|
|
+const ratingLabel = computed(
|
|
|
|
|
+ () => Number(info.value.average_rating ?? 0).toFixed(1)
|
|
|
|
|
+);
|
|
|
|
|
+
|
|
|
|
|
+const genderLabel = computed(() => {
|
|
|
|
|
+ if (info.value.gender_label) return info.value.gender_label;
|
|
|
|
|
+
|
|
|
|
|
+ const gender = info.value.gender;
|
|
|
|
|
+ if (!gender) return null;
|
|
|
|
|
|
|
|
- return props.provider.provider_name
|
|
|
|
|
- .trim()
|
|
|
|
|
- .split(" ")
|
|
|
|
|
- .slice(0, 2)
|
|
|
|
|
- .map(name => name[0].toUpperCase())
|
|
|
|
|
- .join("");
|
|
|
|
|
|
|
+ const key = `genders.${gender}`;
|
|
|
|
|
+ const label = t(key);
|
|
|
|
|
+
|
|
|
|
|
+ return label === key ? null : label;
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const initials = computed(
|
|
|
|
|
+ () => firstName.value.slice(0, 2).toUpperCase() || "?"
|
|
|
|
|
+);
|
|
|
|
|
+
|
|
|
|
|
+onMounted(async () => {
|
|
|
|
|
+ const providerId = props.provider?.provider_id ?? props.provider?.id;
|
|
|
|
|
+ if (!providerId) return;
|
|
|
|
|
+
|
|
|
|
|
+ loading.value = true;
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const payload = await getPerfilPrestador(providerId);
|
|
|
|
|
+ info.value = { ...props.provider, ...payload };
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error(error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false;
|
|
|
|
|
+ }
|
|
|
});
|
|
});
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
@@ -154,7 +221,6 @@ const initials = computed(() => {
|
|
|
.provider-dialog {
|
|
.provider-dialog {
|
|
|
width: 380px;
|
|
width: 380px;
|
|
|
max-width: 95vw;
|
|
max-width: 95vw;
|
|
|
- border-radius: 14px;
|
|
|
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -162,7 +228,9 @@ const initials = computed(() => {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
gap: 18px;
|
|
gap: 18px;
|
|
|
- padding: 20px;
|
|
|
|
|
|
|
+ padding-top: 20px;
|
|
|
|
|
+ padding-right: 20px;
|
|
|
|
|
+ padding-left: 20px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
.provider-avatar {
|
|
.provider-avatar {
|
|
@@ -179,14 +247,10 @@ const initials = computed(() => {
|
|
|
flex: 1;
|
|
flex: 1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-.provider-info .text-h6 {
|
|
|
|
|
- line-height: 1.2;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
.provider-stats {
|
|
.provider-stats {
|
|
|
display: flex;
|
|
display: flex;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
|
- gap: 6px;
|
|
|
|
|
|
|
+ gap: 10px;
|
|
|
margin-top: 8px;
|
|
margin-top: 8px;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -200,4 +264,4 @@ const initials = computed(() => {
|
|
|
.q-list .q-item {
|
|
.q-list .q-item {
|
|
|
min-height: 38px;
|
|
min-height: 38px;
|
|
|
}
|
|
}
|
|
|
-</style>
|
|
|
|
|
|
|
+</style>
|