Kaynağa Gözat

feat: :sparkles: crud prestadores dias trabalho

crud prestadores dias trabalho
Gustavo Zanatta 1 ay önce
ebeveyn
işleme
0ac9907d20

+ 16 - 0
src/api/providerWorkingDay.js

@@ -0,0 +1,16 @@
+import api from 'src/api'
+
+export const getProviderWorkingDays = async (providerId) => {
+    const { data } =  await api.get(`/provider/working-days/${providerId}`)
+    return data.payload;
+}
+
+export const createProviderWorkingDay = async (info) => {
+    const { data } = await api.post('/provider/working-day', info);
+    return data.payload;
+}
+
+export const deleteProviderWorkingDay = async (day, period, providerId) => {
+  const { data } = await api.delete(`/provider/working-day/${providerId}?day=${day}&period=${period}`);
+  return data.payload;
+}

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

@@ -353,6 +353,20 @@
       "savings": "Savings"
     }
   },
+  "provider_working_days": {
+    "header": "Working Days",
+    "morning": "Morning",
+    "afternoon": "Afternoon",
+    "days": {
+      "1": "Sunday",
+      "2": "Monday",
+      "3": "Tuesday",
+      "4": "Wednesday",
+      "5": "Thursday",
+      "6": "Friday",
+      "7": "Saturday"
+    }
+  },
   "orders": {
     "singular": "Order",
     "plural": "Orders",

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

@@ -353,6 +353,20 @@
       "savings": "Ahorro"
     }
   },
+  "provider_working_days": {
+    "header": "Días de Trabajo",
+    "morning": "Mañana",
+    "afternoon": "Tarde",
+    "days": {
+      "1": "Domingo",
+      "2": "Lunes",
+      "3": "Martes",
+      "4": "Miércoles",
+      "5": "Jueves",
+      "6": "Viernes",
+      "7": "Sábado"
+    }
+  },
   "orders": {
     "singular": "Pedido",
     "plural": "Pedidos",

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

@@ -353,6 +353,20 @@
       "savings": "Poupança"
     }
   },
+  "provider_working_days": {
+    "header": "Dias de Trabalho",
+    "morning": "Manhã",
+    "afternoon": "Tarde",
+    "days": {
+      "1": "Domingo",
+      "2": "Segunda",
+      "3": "Terça",
+      "4": "Quarta",
+      "5": "Quinta",
+      "6": "Sexta",
+      "7": "Sábado"
+    }
+  },
   "orders": {
     "singular": "Pedido",
     "plural": "Pedidos",

+ 148 - 141
src/pages/provider/components/AddEditProviderDialog.vue

@@ -1,171 +1,177 @@
 <template>
   <q-dialog ref="dialogRef" @hide="onDialogHide">
-    <q-card class="q-dialog-plugin overflow-hidden" style="width: 1000px; max-width: 90vw">
-      <DefaultDialogHeader :title="title" @close="onDialogCancel" />
+    <q-card class="q-dialog-plugin column full-width" style="width: 900px; max-width: 80vw;height: 90vh;">
+      <DefaultDialogHeader :title="title" class="col-12" @close="onDialogCancel"/>
 
       <q-tabs v-model="tab" dense class="text-grey" active-color="primary" indicator-color="primary" align="justify">
         <q-tab name="data" label="Dados" />
         <q-tab v-if="provider" name="addresses" :label="$t('address.tab')" />
         <q-tab v-if="provider" name="payment_methods" :label="$t('provider_payment_methods.header')" />
+        <q-tab v-if="provider" name="working_days" :label="$t('provider_working_days.header')" />
       </q-tabs>
 
       <q-separator v-if="provider" />
+      <div class="col no-padding scroll">
+        <q-tab-panels v-model="tab" animated>
+          <q-tab-panel name="data">
+            <q-form ref="formRef" @submit="onOKClick">
+              <q-card-section class="row q-col-gutter-sm no-padding scroll">
+                <UserSelect
+                  v-model="selectedUser"
+                  :label="$t('common.terms.user')"
+                  :rules="[inputRules.required]"
+                  :error="!!serverErrors?.user_id"
+                  :error-message="serverErrors?.user_id"
+                  :initial-id="provider ? provider.user_id : null"
+                  class="col-md-6 col-12"
+                />
 
-      <q-tab-panels v-model="tab" animated>
-        <q-tab-panel name="data">
-          <q-form ref="formRef" @submit="onOKClick">
-            <q-card-section class="row q-col-gutter-sm">
-              <UserSelect
-                v-model="selectedUser"
-                :label="$t('common.terms.user')"
-                :rules="[inputRules.required]"
-                :error="!!serverErrors?.user_id"
-                :error-message="serverErrors?.user_id"
-                :initial-id="provider ? provider.user_id : null"
-                class="col-md-6 col-12"
-              />
-
-              <q-input
-                v-model="form.document"
-                :mask="documentMask"
-                fill-mask
-                unmasked-value
-                :label="$t('provider.fields.document')"
-                :rules="[inputRules.required, validateDocument]"
-                :error="!!serverErrors?.document"
-                :error-message="serverErrors?.document"
-                class="col-md-6 col-12"
-              />
-
-              <q-input
-                v-model="form.rg"
-                mask="##.###.###-#"
-                fill-mask
-                :label="$t('provider.fields.rg')"
-                :error="!!serverErrors?.rg"
-                :error-message="serverErrors?.rg"
-                class="col-md-6 col-12"
-              />
-              <DefaultInputDatePicker
-                v-model:untreated-date="form.birth_date"
-                :label="$t('provider.fields.birth_date')"
-                :error="serverErrors?.birth_date"
-                :error-message="serverErrors?.birth_date"
-                class="col-md-6 col-12"
-              />
-
-              <DefaultCurrencyInput
-                v-model="form.daily_price_8h"
-                :label="$t('provider.fields.daily_price_8h')"
-                :error="!!serverErrors?.daily_price_8h"
-                :error-message="serverErrors?.daily_price_8h"
-                :hint="$t('provider.hints.daily_price')"
-                lazy-rules
-                class="col-md-3 col-6"
-              />
-
-              <DefaultCurrencyInput
-                v-model="form.daily_price_6h"
-                :label="$t('provider.fields.daily_price_6h')"
-                :error="!!serverErrors?.daily_price_6h"
-                :error-message="serverErrors?.daily_price_6h"
-                disable
-                class="col-md-3 col-6"
-              />
-
-              <DefaultCurrencyInput
-                v-model="form.daily_price_4h"
-                :label="$t('provider.fields.daily_price_4h')"
-                :error="!!serverErrors?.daily_price_4h"
-                :error-message="serverErrors?.daily_price_4h"
-                disable
-                class="col-md-3 col-6"
-              />
-
-              <DefaultCurrencyInput
-                v-model="form.daily_price_2h"
-                :label="$t('provider.fields.daily_price_2h')"
-                :error="!!serverErrors?.daily_price_2h"
-                :error-message="serverErrors?.daily_price_2h"
-                disable
-                class="col-md-3 col-6"
-              />
-
-              <div class="col-12">
-                <q-checkbox
-                  v-model="form.is_approved"
-                  :label="$t('provider.fields.is_approved')"
+                <q-input
+                  v-model="form.document"
+                  :mask="documentMask"
+                  fill-mask
+                  unmasked-value
+                  :label="$t('provider.fields.document')"
+                  :rules="[inputRules.required, validateDocument]"
+                  :error="!!serverErrors?.document"
+                  :error-message="serverErrors?.document"
+                  class="col-md-6 col-12"
                 />
-              </div>
 
-              <ProviderSpecialitiesPanel v-if="provider" :provider-id="provider.id" />
+                <q-input
+                  v-model="form.rg"
+                  mask="##.###.###-#"
+                  fill-mask
+                  :label="$t('provider.fields.rg')"
+                  :error="!!serverErrors?.rg"
+                  :error-message="serverErrors?.rg"
+                  class="col-md-6 col-12"
+                />
+                <DefaultInputDatePicker
+                  v-model:untreated-date="form.birth_date"
+                  :label="$t('provider.fields.birth_date')"
+                  :error="serverErrors?.birth_date"
+                  :error-message="serverErrors?.birth_date"
+                  class="col-md-6 col-12"
+                />
 
-              <ProviderServicesTypesPanel v-if="provider" :provider-id="provider.id" />
+                <DefaultCurrencyInput
+                  v-model="form.daily_price_8h"
+                  :label="$t('provider.fields.daily_price_8h')"
+                  :error="!!serverErrors?.daily_price_8h"
+                  :error-message="serverErrors?.daily_price_8h"
+                  :hint="$t('provider.hints.daily_price')"
+                  lazy-rules
+                  class="col-md-3 col-6"
+                />
 
-              <div class="col-12 q-mt-md">
-                <div class="row q-col-gutter-md">
-                  <div class="col-auto flex items-center">
-                    <q-avatar size="80px" color="grey-3">
-                      <q-icon name="mdi-account" size="50px" color="grey-6" />
-                    </q-avatar>
-                  </div>
+                <DefaultCurrencyInput
+                  v-model="form.daily_price_6h"
+                  :label="$t('provider.fields.daily_price_6h')"
+                  :error="!!serverErrors?.daily_price_6h"
+                  :error-message="serverErrors?.daily_price_6h"
+                  disable
+                  class="col-md-3 col-6"
+                />
 
-                  <div class="col row q-col-gutter-sm">
-                    <div class="col-md-6 col-12">
-                      <div class="text-subtitle2 text-grey-7">
-                        {{ $t('provider.fields.average_rating') }}
-                      </div>
-                      <div class="text-body1 text-weight-medium">
-                        {{ provider?.average_rating || '-' }}
-                      </div>
-                    </div>
+                <DefaultCurrencyInput
+                  v-model="form.daily_price_4h"
+                  :label="$t('provider.fields.daily_price_4h')"
+                  :error="!!serverErrors?.daily_price_4h"
+                  :error-message="serverErrors?.daily_price_4h"
+                  disable
+                  class="col-md-3 col-6"
+                />
 
-                    <div class="col-md-6 col-12">
-                      <div class="text-subtitle2 text-grey-7">
-                        {{ $t('provider.fields.total_services') }}
-                      </div>
-                      <div class="text-body1 text-weight-medium">
-                        {{ provider?.total_services || '0' }}
-                      </div>
+                <DefaultCurrencyInput
+                  v-model="form.daily_price_2h"
+                  :label="$t('provider.fields.daily_price_2h')"
+                  :error="!!serverErrors?.daily_price_2h"
+                  :error-message="serverErrors?.daily_price_2h"
+                  disable
+                  class="col-md-3 col-6"
+                />
+
+                <div class="col-12">
+                  <q-checkbox
+                    v-model="form.is_approved"
+                    :label="$t('provider.fields.is_approved')"
+                  />
+                </div>
+
+                <ProviderSpecialitiesPanel v-if="provider" :provider-id="provider.id" />
+
+                <ProviderServicesTypesPanel v-if="provider" :provider-id="provider.id" />
+
+                <div class="col-12 q-mt-md">
+                  <div class="row q-col-gutter-md">
+                    <div class="col-auto flex items-center">
+                      <q-avatar size="80px" color="grey-3">
+                        <q-icon name="mdi-account" size="50px" color="grey-6" />
+                      </q-avatar>
                     </div>
 
-                    <div class="col-md-6 col-12">
-                      <div class="text-subtitle2 text-grey-7">
-                        {{ $t('provider.fields.selfie_verified') }}
+                    <div class="col row q-col-gutter-sm">
+                      <div class="col-md-6 col-12">
+                        <div class="text-subtitle2 text-grey-7">
+                          {{ $t('provider.fields.average_rating') }}
+                        </div>
+                        <div class="text-body1 text-weight-medium">
+                          {{ provider?.average_rating || '-' }}
+                        </div>
                       </div>
-                      <div class="text-body1 text-weight-medium">
-                        {{ provider?.selfie_verified ? $t('common.status.yes') : $t('common.status.no') }}
+
+                      <div class="col-md-6 col-12">
+                        <div class="text-subtitle2 text-grey-7">
+                          {{ $t('provider.fields.total_services') }}
+                        </div>
+                        <div class="text-body1 text-weight-medium">
+                          {{ provider?.total_services || '0' }}
+                        </div>
                       </div>
-                    </div>
 
-                    <div class="col-md-6 col-12">
-                      <div class="text-subtitle2 text-grey-7">
-                        {{ $t('provider.fields.document_verified') }}
+                      <div class="col-md-6 col-12">
+                        <div class="text-subtitle2 text-grey-7">
+                          {{ $t('provider.fields.selfie_verified') }}
+                        </div>
+                        <div class="text-body1 text-weight-medium">
+                          {{ provider?.selfie_verified ? $t('common.status.yes') : $t('common.status.no') }}
+                        </div>
                       </div>
-                      <div class="text-body1 text-weight-medium">
-                        {{ provider?.document_verified ? $t('common.status.yes') : $t('common.status.no') }}
+
+                      <div class="col-md-6 col-12">
+                        <div class="text-subtitle2 text-grey-7">
+                          {{ $t('provider.fields.document_verified') }}
+                        </div>
+                        <div class="text-body1 text-weight-medium">
+                          {{ provider?.document_verified ? $t('common.status.yes') : $t('common.status.no') }}
+                        </div>
                       </div>
                     </div>
                   </div>
                 </div>
-              </div>
-            </q-card-section>
-            <q-card-actions align="center">
-              <q-btn color="primary" label="Cancel" @click="onDialogCancel" />
-              <q-space />
-              <q-btn color="primary" label="OK" :type="'submit'" :loading="loading" :disable="!hasUpdatedFields" />
-            </q-card-actions>
-          </q-form>
-        </q-tab-panel>
-
-        <q-tab-panel v-if="provider" name="addresses">
-          <AddressesPanel :source="'provider'" :source-id="provider.id" />
-        </q-tab-panel>
-
-        <q-tab-panel v-if="provider" name="payment_methods">
-          <ProviderPaymentMethodsPanel :provider-id="provider.id" />
-        </q-tab-panel>
-      </q-tab-panels>
+              </q-card-section>
+            </q-form>
+          </q-tab-panel>
+
+          <q-tab-panel v-if="provider" name="addresses">
+            <AddressesPanel :source="'provider'" :source-id="provider.id" />
+          </q-tab-panel>
+
+          <q-tab-panel v-if="provider" name="payment_methods">
+            <ProviderPaymentMethodsPanel :provider-id="provider.id" />
+          </q-tab-panel>
+
+          <q-tab-panel v-if="provider" name="working_days">
+            <ProviderWorkingDaysPanel :provider-id="provider.id" />
+          </q-tab-panel>
+        </q-tab-panels>
+      </div>
+      <q-card-actions align="center" class="">
+        <q-btn color="primary" label="Cancel" @click="onDialogCancel" />
+        <q-space />
+        <q-btn color="primary" label="OK" :type="'submit'" :loading="loading" :disable="!hasUpdatedFields" />
+      </q-card-actions>
     </q-card>
   </q-dialog>
 </template>
@@ -186,6 +192,7 @@ import AddressesPanel from "src/pages/address/components/AddressesPanel.vue";
 import ProviderSpecialitiesPanel from "./ProviderSpecialitiesPanel.vue";
 import ProviderServicesTypesPanel from "./ProviderServicesTypesPanel.vue";
 import ProviderPaymentMethodsPanel from "./ProviderPaymentMethodsPanel.vue";
+import ProviderWorkingDaysPanel from "./ProviderWorkingDaysPanel.vue";
 
 defineEmits([
   ...useDialogPluginComponent.emits,

+ 199 - 0
src/pages/provider/components/ProviderWorkingDaysPanel.vue

@@ -0,0 +1,199 @@
+<template>
+  <div class="q-pa-md">
+    <div class="row q-col-gutter-md">
+      <div
+        v-for="day in daysOfWeek"
+        :key="day.value"
+        class="col-12 col-sm-6 col-md-4 col-lg-3"
+      >
+        <div class="column q-gutter-sm">
+          <div class="text-center text-weight-medium q-mb-xs">
+            {{ $t(`provider_working_days.days.${day.value}`) }}
+          </div>
+          <q-card
+            class="working-day-card cursor-pointer"
+            :class="isSelected(day.value, 'morning') ? 'selected' : 'unselected'"
+            @click="togglePeriod(day.value, 'morning')"
+          >
+            <q-card-section class="text-center">
+              <q-icon
+                :name="isSelected(day.value, 'morning') ? 'mdi-check-circle' : 'mdi-circle-outline'"
+                :color="isSelected(day.value, 'morning') ? 'white' : 'grey-6'"
+                size="24px"
+              />
+              <div class="text-subtitle2 q-mt-xs text-text">
+                {{ $t('provider_working_days.morning') }}
+              </div>
+            </q-card-section>
+          </q-card>
+
+          <q-card
+            class="working-day-card cursor-pointer"
+            :class="isSelected(day.value, 'afternoon') ? 'selected' : 'unselected'"
+            @click="togglePeriod(day.value, 'afternoon')"
+          >
+            <q-card-section class="text-center">
+              <q-icon
+                :name="isSelected(day.value, 'afternoon') ? 'mdi-check-circle' : 'mdi-circle-outline'"
+                :color="isSelected(day.value, 'afternoon') ? 'white' : 'grey-6'"
+                size="24px"
+              />
+              <div class="text-subtitle2 q-mt-xs text-text">
+                {{ $t('provider_working_days.afternoon') }}
+              </div>
+            </q-card-section>
+          </q-card>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+import { useQuasar } from 'quasar'
+import { useI18n } from 'vue-i18n'
+import {
+  getProviderWorkingDays,
+  createProviderWorkingDay,
+  deleteProviderWorkingDay
+} from 'src/api/providerWorkingDay'
+import { permissionStore } from 'src/stores/permission'
+
+const props = defineProps({
+  providerId: {
+    type: Number,
+    required: true
+  }
+})
+
+const { t } = useI18n()
+const $q = useQuasar()
+const permission_store = permissionStore()
+
+const workingDays = ref([])
+const loading = ref(false)
+
+const daysOfWeek = [
+  { value: 1 },
+  { value: 2 },
+  { value: 3 },
+  { value: 4 },
+  { value: 5 },
+  { value: 6 },
+  { value: 7 }
+]
+
+const isSelected = (day, period) => {
+  return workingDays.value.some(
+    (wd) => wd.day === day && wd.period === period
+  )
+};
+
+const loadWorkingDays = async () => {
+  try {
+    loading.value = true
+    const response = await getProviderWorkingDays(props.providerId)
+    workingDays.value = response
+  } catch {
+    $q.notify({
+      type: 'negative',
+      message: t('http.errors.failed')
+    })
+  } finally {
+    loading.value = false
+  }
+};
+
+const togglePeriod = async (day, period) => {
+  const selected = isSelected(day, period)
+
+  if (selected) {
+    if (!permission_store.getAccess('config.provider_working_day', 'delete')) {
+      $q.notify({
+        type: 'negative',
+        message: t('validation.permissions.delete')
+      })
+      return
+    }
+
+    try {
+      loading.value = true
+      await deleteProviderWorkingDay(day, period, props.providerId)
+      await loadWorkingDays()
+      $q.notify({
+        type: 'positive',
+        message: t('http.success')
+      })
+    } catch {
+      $q.notify({
+        type: 'negative',
+        message: t('http.errors.failed')
+      })
+    } finally {
+      loading.value = false
+    }
+  } else {
+    if (!permission_store.getAccess('config.provider_working_day', 'add')) {
+      $q.notify({
+        type: 'negative',
+        message: t('validation.permissions.add')
+      })
+      return
+    }
+
+    try {
+      loading.value = true
+      await createProviderWorkingDay({
+        provider_id: props.providerId,
+        day: day,
+        period: period
+      })
+      await loadWorkingDays()
+      $q.notify({
+        type: 'positive',
+        message: t('http.success')
+      })
+    } catch {
+      $q.notify({
+        type: 'negative',
+        message: t('http.errors.failed')
+      })
+    } finally {
+      loading.value = false
+    }
+  }
+};
+
+onMounted(() => {
+  loadWorkingDays()
+});
+</script>
+
+<style scoped lang="scss">
+.working-day-card {
+  transition: all 0.3s ease;
+  min-height: 80px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+
+  &.selected {
+    background-color: $positive;
+    color: white;
+
+    &:hover {
+      background-color: darken($positive, 5%);
+    }
+  }
+
+  &.unselected {
+    background-color: #6b6b6b;
+    color: #757575;
+
+    &:hover {
+      background-color: #2e7d32;
+    }
+  }
+}
+</style>