Browse Source

feat: :sparkles: feat (favorito) adiciona funcao de favoritar no modal de contratacao

adicionada funcao de favoritar o prestador na tela de contratacao

fase:staging | origin:escopo
Gustavo Zanatta 3 tuần trước cách đây
mục cha
commit
e4b81dae2d

+ 3 - 0
src/i18n/locales/en.json

@@ -722,6 +722,9 @@
     "title": "Scheduling",
     "about_provider": "About the professional",
     "schedule_service": "Schedule a service",
+    "favorite_added": "Professional added to favorites!",
+    "favorite_removed": "Professional removed from favorites.",
+    "favorite_error": "Could not update favorites.",
     "reviews_title": "Reviews",
     "see_all": "see all",
     "no_reviews": "No reviews found.",

+ 3 - 0
src/i18n/locales/es.json

@@ -718,6 +718,9 @@
     "title": "Agendamiento",
     "about_provider": "Sobre el profesional",
     "schedule_service": "Agendar un servicio",
+    "favorite_added": "¡Profesional agregado a favoritos!",
+    "favorite_removed": "Profesional eliminado de favoritos.",
+    "favorite_error": "No se pudieron actualizar los favoritos.",
     "reviews_title": "Reseñas",
     "see_all": "ver todas",
     "no_reviews": "No se encontraron reseñas.",

+ 3 - 0
src/i18n/locales/pt.json

@@ -730,6 +730,9 @@
     "title": "Agendamento",
     "about_provider": "Sobre o profissional",
     "schedule_service": "Agende um serviço",
+    "favorite_added": "Diarista adicionado aos favoritos!",
+    "favorite_removed": "Diarista removido dos favoritos.",
+    "favorite_error": "Não foi possível atualizar os favoritos.",
     "reviews_title": "Avaliações",
     "see_all": "ver todas",
     "no_reviews": "Nenhuma avaliação encontrada.",

+ 65 - 1
src/pages/search/components/SchedulingDialog.vue

@@ -81,9 +81,11 @@
                     color="pink-4"
                     dense
                     flat
-                    icon="mdi-heart-outline"
+                    :icon="isFavorite ? 'mdi-heart' : 'mdi-heart-outline'"
+                    :loading="favoriteLoading"
                     round
                     size="sm"
+                    @click="toggleFavorite"
                   />
 
                   <q-btn
@@ -203,6 +205,11 @@ import { date } from 'quasar';
 import { getClientProviderBlocks } from 'src/api/schedule';
 import { getProviderBlockedDays, getProviderWorkingDays } from 'src/api/providerAvailability';
 import { getProviderReceivedReviews } from 'src/api/review';
+import {
+  createClientFavoriteProvider,
+  deleteClientFavoriteProvider,
+  getClientFavoriteProviders,
+} from 'src/api/clientFavoriteProvider';
 import { useDialogPluginComponent, useQuasar } from 'quasar';
 import { useI18n } from 'vue-i18n';
 import { useScheduleCartStore } from 'src/stores/scheduleCart';
@@ -232,6 +239,9 @@ const blockedDays         = ref([]);
 const loadingAvailability = ref(true);
 const reviews             = ref([]);
 const loadingReviews      = ref(true);
+const isFavorite          = ref(false);
+const favoriteId          = ref(null);
+const favoriteLoading     = ref(false);
 
 const avatarColors = [
   { background: '#ffd5df', color: '#932e57' },
@@ -361,6 +371,59 @@ const loadReviews = async () => {
   }
 };
 
+const loadFavoriteState = async () => {
+  const clientId = store.user?.client?.id;
+  if (!clientId) return;
+
+  try {
+    const favorites = await getClientFavoriteProviders(clientId);
+    const match = (favorites ?? []).find(
+      (f) => Number(f.provider_id) === Number(props.provider.provider_id)
+    );
+
+    isFavorite.value = !!match;
+    favoriteId.value = match?.id ?? null;
+  } catch {
+    isFavorite.value = false;
+    favoriteId.value = null;
+  }
+};
+
+const toggleFavorite = async () => {
+  if (favoriteLoading.value) return;
+
+  const clientId = store.user?.client?.id;
+  if (!clientId) {
+    $q.notify({ type: 'negative', message: t('scheduling_page.favorite_error') });
+    return;
+  }
+
+  favoriteLoading.value = true;
+
+  try {
+    if (isFavorite.value) {
+      if (favoriteId.value) {
+        await deleteClientFavoriteProvider(favoriteId.value);
+      }
+      isFavorite.value = false;
+      favoriteId.value = null;
+      $q.notify({ type: 'positive', message: t('scheduling_page.favorite_removed') });
+    } else {
+      const created = await createClientFavoriteProvider({
+        client_id: clientId,
+        provider_id: props.provider.provider_id,
+      });
+      isFavorite.value = true;
+      favoriteId.value = created?.id ?? null;
+      $q.notify({ type: 'positive', message: t('scheduling_page.favorite_added') });
+    }
+  } catch {
+    $q.notify({ type: 'negative', message: t('scheduling_page.favorite_error') });
+  } finally {
+    favoriteLoading.value = false;
+  }
+};
+
 const normalizeDate = (dateStr) => (dateStr ?? '').replace(/\//g, '-');
 
 const onDateSelected = (val) => {
@@ -468,6 +531,7 @@ const wouldExceedWeekLimit = (selectedDate) => {
 onMounted(() => {
   loadAvailability();
   loadReviews();
+  loadFavoriteState();
 });
 </script>