Quellcode durchsuchen

multi datas no agendamento

Gustavo Zanatta vor 3 Wochen
Ursprung
Commit
830acfb269

+ 9 - 3
src/components/defaults/DefaultInputDatePicker.vue

@@ -16,11 +16,11 @@
           :name="time ? 'mdi-calendar-clock' : 'mdi-calendar'"
           class="cursor-pointer"
         >
-          <q-popup-proxy cover transition-show="scale" transition-hide="scale">
+          <q-popup-proxy cover transition-show="scale" transition-hide="scale" @hide="handlePopupClose">
             <template v-if="!time">
               <q-date v-model="date" mask="YYYY-MM-DD">
                 <div class="row items-center justify-end">
-                  <q-btn v-close-popup label="Close" color="primary" flat />
+                  <q-btn v-close-popup :label="$t('common.messages.confirm')" color="primary" flat />
                 </div>
               </q-date>
             </template>
@@ -86,7 +86,7 @@ const { label, rules, time, dense } = defineProps({
 });
 
 const qInputRef = useTemplateRef("inputRef", { type: String });
-
+const emit = defineEmits(["confirmed"]);
 const treatedDate = defineModel({ type: String });
 const untreatedDate = defineModel("untreatedDate", { type: String });
 
@@ -126,6 +126,12 @@ const inputMask = computed(() => {
   return masks.Brasil.date;
 });
 
+const handlePopupClose = () => {
+  if (date.value) {
+    emit("confirmed", untreatedDate.value);
+  }
+};
+
 watch(date, (value) => {
   if (!value) return;
 

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

@@ -5,11 +5,13 @@
       "cancel": "Cancel",
       "edit": "Edit",
       "add": "Add",
+      "update": "Update",
       "search": "Search",
       "delete": "Delete",
       "view": "View",
       "back": "Back",
       "next": "Next",
+      "title": "Actions",
       "resend_email": "Resend email",
       "download_certificate": "Download certificate",
       "download_boleto": "Download Boleto",
@@ -95,6 +97,9 @@
       "no": "No",
       "no_results": "No results found"
     },
+    "validations": {
+      "required": "Required field"
+    },
     "ui": {
       "file": {
         "choose": "Choose a file",
@@ -431,6 +436,8 @@
     "add_button": "New Schedule",
     "edit_button": "Edit Schedule",
     "empty_state": "No schedules registered",
+    "schedule_info": "Schedule Information",
+    "schedule_details": "Schedule Details",
     "client": "Client",
     "provider": "Provider",
     "address": "Address",
@@ -445,6 +452,12 @@
     "code": "Code",
     "code_verified": "Code Verified",
     "hours": "hours",
+    "add_date": "Add Date",
+    "selected_dates": "Selected Dates",
+    "schedule_dates": "Schedule Dates",
+    "no_dates_added": "No dates added",
+    "date_already_added": "This date has already been added",
+    "at_least_one_date_required": "Add at least one date",
     "period_types": {
       "2": "2 hours",
       "4": "4 hours",

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

@@ -5,11 +5,13 @@
       "cancel": "Cancelar",
       "edit": "Editar",
       "add": "Añadir",
+      "update": "Actualizar",
       "search": "Buscar",
       "delete": "Eliminar",
       "view": "Ver",
       "back": "Volver",
       "next": "Siguiente",
+      "title": "Acciones",
       "resend_email": "Reenviar correo electrónico",
       "download_certificate": "Descargar certificado",
       "download_boleto": "Descargar Boleto",
@@ -95,6 +97,9 @@
       "no": "No",
       "no_results": "No se encontraron resultados"
     },
+    "validations": {
+      "required": "Campo obligatorio"
+    },
     "ui": {
       "file": {
         "choose": "Elegir un archivo",
@@ -431,6 +436,8 @@
     "add_button": "Nueva Agenda",
     "edit_button": "Editar Agenda",
     "empty_state": "No hay agendas registradas",
+    "schedule_info": "Información de la Agenda",
+    "schedule_details": "Detalles de la Agenda",
     "client": "Cliente",
     "provider": "Proveedor",
     "address": "Dirección",
@@ -445,6 +452,12 @@
     "code": "Código",
     "code_verified": "Código Verificado",
     "hours": "horas",
+    "add_date": "Agregar Fecha",
+    "selected_dates": "Fechas Seleccionadas",
+    "schedule_dates": "Fechas de las Agendas",
+    "no_dates_added": "No se han agregado fechas",
+    "date_already_added": "Esta fecha ya ha sido agregada",
+    "at_least_one_date_required": "Agregue al menos una fecha",
     "period_types": {
       "2": "2 horas",
       "4": "4 horas",

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

@@ -5,11 +5,13 @@
       "cancel": "Cancelar",
       "edit": "Editar",
       "add": "Adicionar",
+      "update": "Atualizar",
       "search": "Buscar",
       "delete": "Excluir",
       "view": "Visualizar",
       "back": "Voltar",
       "next": "Próximo",
+      "title": "Ações",
       "resend_email": "Reenviar e-mail",
       "download_certificate": "Baixar certificado",
       "download_boleto": "Baixar Boleto",
@@ -95,6 +97,9 @@
       "no": "Não",
       "no_results": "Nenhum resultado encontrado"
     },
+    "validations": {
+      "required": "Campo obrigatório"
+    },
     "ui": {
       "file": {
         "choose": "Escolha um arquivo",
@@ -431,6 +436,8 @@
     "add_button": "Novo Agendamento",
     "edit_button": "Editar Agendamento",
     "empty_state": "Nenhum agendamento cadastrado",
+    "schedule_info": "Informações do Agendamento",
+    "schedule_details": "Detalhes do Agendamento",
     "client": "Cliente",
     "provider": "Prestador",
     "address": "Endereço",
@@ -445,6 +452,12 @@
     "code": "Código",
     "code_verified": "Código Verificado",
     "hours": "horas",
+    "add_date": "Adicionar Data",
+    "selected_dates": "Datas Selecionadas",
+    "schedule_dates": "Datas dos Agendamentos",
+    "no_dates_added": "Nenhuma data adicionada",
+    "date_already_added": "Esta data já foi adicionada",
+    "at_least_one_date_required": "Adicione pelo menos uma data",
     "period_types": {
       "2": "2 horas",
       "4": "4 horas",

+ 445 - 160
src/pages/schedule/components/AddEditScheduleDialog.vue

@@ -1,119 +1,270 @@
 <template>
   <q-dialog ref="dialogRef" @hide="onDialogHide">
-    <q-card class="q-dialog-plugin" style="width: 800px; max-width: 90vw">
+    <q-card class="q-dialog-plugin" style="width: 900px; max-width: 90vw">
       <DefaultDialogHeader :title="title" @close="onDialogCancel" />
       <q-form ref="formRef" @submit="onOKClick">
-        <q-card-section class="row q-col-gutter-sm">
-          <ClientSelect
-            v-model="selectedClient"
-            :label="$t('schedules.client')"
-            :rules="[inputRules.required]"
-            :error="!!serverErrors?.client_id"
-            :error-message="serverErrors?.client_id"
-            :initial-id="schedule ? schedule.client_id : null"
-            class="col-12 col-md-6"
-            @update:model-value="onClientChange"
-          />
+        <q-card-section class="row q-col-gutter-md">
+          <div class="col-12">
+            <div class="text-subtitle1 text-weight-bold q-mb-md">
+              {{ $t('schedules.schedule_info') }}
+            </div>
+            <div class="row q-col-gutter-sm">
+              <ClientSelect
+                v-model="selectedClient"
+                :label="$t('schedules.client')"
+                :rules="[inputRules.required]"
+                :error="!!serverErrors?.client_id"
+                :error-message="serverErrors?.client_id"
+                :initial-id="schedule ? schedule.client_id : null"
+                class="col-12 col-md-6"
+                @update:model-value="onClientChange"
+              />
 
-          <ProviderSelect
-            v-model="selectedProvider"
-            :label="$t('schedules.provider')"
-            :rules="[inputRules.required]"
-            :error="!!serverErrors?.provider_id"
-            :error-message="serverErrors?.provider_id"
-            :initial-id="schedule ? schedule.provider_id : null"
-            class="col-12 col-md-6"
-            @update:model-value="onProviderChange"
-          />
+              <ProviderSelect
+                v-model="selectedProvider"
+                :label="$t('schedules.provider')"
+                :rules="[inputRules.required]"
+                :error="!!serverErrors?.provider_id"
+                :error-message="serverErrors?.provider_id"
+                :initial-id="schedule ? schedule.provider_id : null"
+                class="col-12 col-md-6"
+                @update:model-value="onProviderChange"
+              />
 
-          <AddressSelect
-            v-model="selectedAddress"
-            :label="$t('schedules.address')"
-            :rules="[inputRules.required]"
-            :error="!!serverErrors?.address_id"
-            :error-message="serverErrors?.address_id"
-            :initial-id="schedule ? schedule.address_id : null"
-            :client-id="form.client_id"
-            :disabled="!form.client_id"
-            class="col-12"
-            @update:model-value="serverErrors.address_id = null"
-          />
+              <AddressSelect
+                v-model="selectedAddress"
+                :label="$t('schedules.address')"
+                :rules="[inputRules.required]"
+                :error="!!serverErrors?.address_id"
+                :error-message="serverErrors?.address_id"
+                :initial-id="schedule ? schedule.address_id : null"
+                :client-id="form.client_id"
+                :disabled="!form.client_id"
+                class="col-12"
+                @update:model-value="serverErrors.address_id = null"
+              />
+            </div>
+          </div>
 
-          <DefaultInputDatePicker
-            v-model:untreated-date="form.date"
-            :label="$t('schedules.date')"
-            :rules="[inputRules.required]"
-            :error="!!serverErrors?.date"
-            :error-message="serverErrors?.date"
-            class="col-12 col-md-6"
-            @update:untreated-date="serverErrors.date = null"
-          />
+          <template v-if="schedule">
+            <q-separator class="col-12" />
+            
+            <div class="col-12">
+              <div class="text-subtitle1 text-weight-bold q-mb-md">
+                {{ $t('schedules.schedule_details') }}
+              </div>
+              <div class="row q-col-gutter-sm">
+                <DefaultInputDatePicker
+                  v-model:untreated-date="form.date"
+                  :label="$t('schedules.date')"
+                  :rules="[inputRules.required]"
+                  :error="!!serverErrors?.date"
+                  :error-message="serverErrors?.date"
+                  class="col-12 col-md-6"
+                  @update:untreated-date="serverErrors.date = null"
+                />
 
-          <q-select
-            v-model="form.period_type"
-            :label="$t('schedules.period_type')"
-            :options="periodOptions"
-            :rules="[inputRules.required]"
-            :error="!!serverErrors?.period_type"
-            :error-message="serverErrors?.period_type"
-            emit-value
-            map-options
-            class="col-12 col-md-6"
-            @update:model-value="onPeriodChange"
-          />
+                <q-select
+                  v-model="form.period_type"
+                  :label="$t('schedules.period_type')"
+                  :options="periodOptions"
+                  :rules="[inputRules.required]"
+                  :error="!!serverErrors?.period_type"
+                  :error-message="serverErrors?.period_type"
+                  emit-value
+                  map-options
+                  class="col-12 col-md-6"
+                  @update:model-value="onPeriodChange"
+                />
 
-          <DefaultInputTimePicker
-            v-model:untreated-time="form.start_time"
-            :label="$t('schedules.start_time')"
-            :rules="[inputRules.required]"
-            :error="!!serverErrors?.start_time"
-            :error-message="serverErrors?.start_time"
-            class="col-12 col-md-6"
-            @update:untreated-time="onStartTimeChange"
-          />
+                <DefaultInputTimePicker
+                  v-model:untreated-time="form.start_time"
+                  :label="$t('schedules.start_time')"
+                  :rules="[inputRules.required]"
+                  :error="!!serverErrors?.start_time"
+                  :error-message="serverErrors?.start_time"
+                  class="col-12 col-md-6"
+                  @update:untreated-time="onStartTimeChange"
+                />
 
-          <DefaultInputTimePicker
-            v-model:untreated-time="form.end_time"
-            :label="$t('schedules.end_time')"
-            :rules="[inputRules.required]"
-            :error="!!serverErrors?.end_time"
-            :error-message="serverErrors?.end_time"
-            :disabled="true"
-            class="col-12 col-md-6"
-            @update:untreated-time="serverErrors.end_time = null"
-          />
+                <DefaultInputTimePicker
+                  v-model:untreated-time="form.end_time"
+                  :label="$t('schedules.end_time')"
+                  :rules="[inputRules.required]"
+                  :error="!!serverErrors?.end_time"
+                  :error-message="serverErrors?.end_time"
+                  :disabled="true"
+                  class="col-12 col-md-6"
+                  @update:untreated-time="serverErrors.end_time = null"
+                />
 
-          <q-select
-            v-model="form.status"
-            :label="$t('schedules.status')"
-            :options="statusOptions"
-            :rules="[inputRules.required]"
-            :error="!!serverErrors?.status"
-            :error-message="serverErrors?.status"
-            :disable="!schedule"
-            emit-value
-            map-options
-            class="col-12 col-md-6"
-            @update:model-value="serverErrors.status = null"
-          />
+                <q-input
+                  v-model="form.total_amount"
+                  :label="$t('schedules.total_amount')"
+                  :prefix="'R$'"
+                  :readonly="true"
+                  class="col-12 col-md-6"
+                />
 
-          <q-input
-            v-model="form.total_amount"
-            :label="$t('schedules.total_amount')"
-            :prefix="'R$'"
-            :readonly="true"
-            class="col-12 col-md-6"
-          />
+                <q-select
+                  v-model="form.status"
+                  :label="$t('schedules.status')"
+                  :options="statusOptions"
+                  :rules="[inputRules.required]"
+                  :error="!!serverErrors?.status"
+                  :error-message="serverErrors?.status"
+                  emit-value
+                  map-options
+                  class="col-12 col-md-6"
+                  @update:model-value="serverErrors.status = null"
+                />
 
-          <q-checkbox
-            v-if="schedule"
-            v-model="form.code_verified"
-            :label="$t('schedules.code_verified')"
-            class="col-12"
-          />
+                <q-checkbox
+                  v-model="form.code_verified"
+                  :label="$t('schedules.code_verified')"
+                  class="col-12"
+                />
+              </div>
+            </div>
+          </template>
+
+          <template v-else>
+            <q-separator class="col-12" />
+            
+            <div class="col-12">
+              <div class="text-subtitle1 text-weight-bold q-mb-md">
+                {{ $t('schedules.schedule_dates') }}
+              </div>
+
+              <div v-if="!showDateForm" class="row justify-center q-py-lg">
+                <q-btn
+                  icon="add"
+                  :label="$t('schedules.add_date')"
+                  color="primary"
+                  size="md"
+                  unelevated
+                  @click="showAddDateForm"
+                />
+              </div>
+
+              <q-slide-transition>
+                <div v-if="showDateForm">
+                  <q-card flat bordered class="q-mb-md">
+                    <q-card-section>
+                      <div class="row q-col-gutter-sm">
+                        <DefaultInputDatePicker
+                          v-model:untreated-date="form.date"
+                          :label="$t('schedules.date')"
+                          :error="!!serverErrors?.date"
+                          :error-message="serverErrors?.date"
+                          class="col-12 col-md-6"
+                          @update:untreated-date="serverErrors.date = null"
+                        />
+
+                        <q-select
+                          v-model="form.period_type"
+                          :label="$t('schedules.period_type')"
+                          :options="periodOptions"
+                          :error="!!serverErrors?.period_type"
+                          :error-message="serverErrors?.period_type"
+                          emit-value
+                          map-options
+                          class="col-12 col-md-6"
+                          @update:model-value="onPeriodChange"
+                        />
+
+                        <DefaultInputTimePicker
+                          v-model:untreated-time="form.start_time"
+                          :label="$t('schedules.start_time')"
+                          :error="!!serverErrors?.start_time"
+                          :error-message="serverErrors?.start_time"
+                          class="col-12 col-md-6"
+                          @update:untreated-time="onStartTimeChange"
+                        />
+
+                        <DefaultInputTimePicker
+                          v-model:untreated-time="form.end_time"
+                          :label="$t('schedules.end_time')"
+                          :disabled="true"
+                          class="col-12 col-md-6"
+                        />
+
+                        <q-input
+                          v-model="form.total_amount"
+                          :label="$t('schedules.total_amount')"
+                          :prefix="'R$'"
+                          :readonly="true"
+                          class="col-12"
+                        />
+                      </div>
+                    </q-card-section>
+
+                    <q-card-actions align="right">
+                      <q-btn
+                        v-if="editingDateIndex !== null"
+                        flat
+                        icon="close"
+                        :label="$t('common.actions.cancel')"
+                        color="negative"
+                        @click="cancelDateEdit"
+                      />
+                      <q-btn
+                        :icon="editingDateIndex === null ? 'save' : 'check'"
+                        :label="editingDateIndex === null ? $t('common.actions.save') : $t('common.actions.update')"
+                        :color="editingDateIndex === null ? 'primary' : 'positive'"
+                        unelevated
+                        @click="addOrUpdateDate"
+                      />
+                    </q-card-actions>
+                  </q-card>
+                </div>
+              </q-slide-transition>
+
+              <q-slide-transition>
+                <div v-if="scheduleDates?.length > 0">
+                  <q-table
+                    :rows="scheduleDates"
+                    :columns="dateColumns"
+                    row-key="date"
+                    :rows-per-page-options="[0]"
+                    flat
+                    bordered
+                    class="q-mt-md"
+                  >
+                    <template #body-cell-actions="slotProps">
+                      <q-td :props="slotProps">
+                        <q-btn
+                          flat
+                          dense
+                          round
+                          icon="edit"
+                          color="primary"
+                          size="sm"
+                          @click="editDate(slotProps.rowIndex)"
+                        >
+                          <q-tooltip>{{ $t('common.actions.edit') }}</q-tooltip>
+                        </q-btn>
+                        <q-btn
+                          flat
+                          dense
+                          round
+                          icon="delete"
+                          color="negative"
+                          size="sm"
+                          @click="removeScheduleDate(slotProps.rowIndex)"
+                        >
+                          <q-tooltip>{{ $t('common.actions.delete') }}</q-tooltip>
+                        </q-btn>
+                      </q-td>
+                    </template>
+                  </q-table>
+                </div>
+              </q-slide-transition>
+            </div>
+          </template>
         </q-card-section>
 
-        <q-card-actions align="right">
+        <q-card-actions align="right" class="q-px-md q-pb-md">
           <q-btn
             flat
             :label="$t('common.actions.cancel')"
@@ -124,8 +275,9 @@
             type="submit"
             :label="$t('common.actions.save')"
             :loading="loading"
-            :disable="!hasUpdatedFields"
+            :disable="isSaveDisabled"
             color="primary"
+            unelevated
           />
         </q-card-actions>
       </q-form>
@@ -134,20 +286,20 @@
 </template>
 
 <script setup>
-import { ref, computed, onMounted } from 'vue'
-import { useDialogPluginComponent } from 'quasar'
-import { useFormUpdateTracker } from 'src/composables/useFormUpdateTracker'
-import { useSubmitHandler } from 'src/composables/useSubmitHandler'
-import { createSchedule, updateSchedule } from 'src/api/schedule'
-import { getProvider } from 'src/api/provider'
-import DefaultDialogHeader from 'src/components/defaults/DefaultDialogHeader.vue'
-import ClientSelect from 'src/components/client/ClientSelect.vue'
-import ProviderSelect from 'src/components/provider/ProviderSelect.vue'
-import AddressSelect from 'src/components/address/AddressSelect.vue'
-import DefaultInputDatePicker from 'src/components/defaults/DefaultInputDatePicker.vue'
-import DefaultInputTimePicker from 'src/components/defaults/DefaultInputTimePicker.vue'
-import { useInputRules } from 'src/composables/useInputRules'
-import { useI18n } from 'vue-i18n'
+import { ref, computed, onMounted } from 'vue';
+import { useDialogPluginComponent } from 'quasar';
+import { useFormUpdateTracker } from 'src/composables/useFormUpdateTracker';
+import { useSubmitHandler } from 'src/composables/useSubmitHandler';
+import { createSchedule, updateSchedule } from 'src/api/schedule';
+import { getProvider } from 'src/api/provider';
+import DefaultDialogHeader from 'src/components/defaults/DefaultDialogHeader.vue';
+import ClientSelect from 'src/components/client/ClientSelect.vue';
+import ProviderSelect from 'src/components/provider/ProviderSelect.vue';
+import AddressSelect from 'src/components/address/AddressSelect.vue';
+import DefaultInputDatePicker from 'src/components/defaults/DefaultInputDatePicker.vue';
+import DefaultInputTimePicker from 'src/components/defaults/DefaultInputTimePicker.vue';
+import { useInputRules } from 'src/composables/useInputRules';
+import { useI18n } from 'vue-i18n';
 
 const props = defineProps({
   schedule: {
@@ -158,31 +310,37 @@ const props = defineProps({
     type: Function,
     default: () => ''
   }
-})
+});
+
+defineEmits([...useDialogPluginComponent.emits]);
+const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent();
+const { inputRules } = useInputRules();
+const { t } = useI18n();
+const formRef = ref(null);
 
-defineEmits([...useDialogPluginComponent.emits])
-const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } = useDialogPluginComponent()
-const { inputRules } = useInputRules()
-const { t } = useI18n()
-const formRef = ref(null)
-const selectedClient = ref(null)
-const selectedProvider = ref(null)
-const selectedAddress = ref(null)
-const providerData = ref(null)
+// Estados
+const selectedClient = ref(null);
+const selectedProvider = ref(null);
+const selectedAddress = ref(null);
+const providerData = ref(null);
+
+const scheduleDates = ref([]);
+const editingDateIndex = ref(null);
+const showDateForm = ref(false);
 
 const { form, getUpdatedFields, hasUpdatedFields } = useFormUpdateTracker({
   client_id: props.schedule ? props.schedule.client_id : null,
   provider_id: props.schedule ? props.schedule.provider_id : null,
   address_id: props.schedule ? props.schedule.address_id : null,
   date: props.schedule ? props.schedule.date : null,
-  period_type: props.schedule ? props.schedule.period_type : '8',
+  period_type: props.schedule ? props.schedule.period_type : null,
   schedule_type: props.schedule ? props.schedule.schedule_type : 'default',
   start_time: props.schedule ? props.schedule.start_time : null,
   end_time: props.schedule ? props.schedule.end_time : null,
   status: props.schedule ? props.schedule.status : 'pending',
   total_amount: props.schedule ? props.schedule.total_amount : 0,
   code_verified: props.schedule ? props.schedule.code_verified : false
-})
+});
 
 const {
   loading,
@@ -191,14 +349,14 @@ const {
 } = useSubmitHandler({
   onSuccess: () => onDialogOK(true),
   formRef: formRef,
-})
+});
 
 const periodOptions = computed(() => [
   { label: t('schedules.period_types.2'), value: '2' },
   { label: t('schedules.period_types.4'), value: '4' },
   { label: t('schedules.period_types.6'), value: '6' },
   { label: t('schedules.period_types.8'), value: '8' }
-])
+]);
 
 const statusOptions = computed(() => [
   { label: t('schedules.statuses.pending'), value: 'pending' },
@@ -208,89 +366,216 @@ const statusOptions = computed(() => [
   { label: t('schedules.statuses.cancelled'), value: 'cancelled' },
   { label: t('schedules.statuses.started'), value: 'started' },
   { label: t('schedules.statuses.finished'), value: 'finished' }
-])
+]);
+
+const dateColumns = computed(() => [
+  { name: 'date', label: t('schedules.date'), field: 'date', align: 'left', format: formatDate },
+  { name: 'period_type', label: t('schedules.period'), field: 'period_type', align: 'center', format: (val) => `${val}h` },
+  { name: 'start_time', label: t('schedules.start_time'), field: 'start_time', align: 'center', format: (val) => val?.substring(0, 5) },
+  { name: 'end_time', label: t('schedules.end_time'), field: 'end_time', align: 'center', format: (val) => val?.substring(0, 5) },
+  { name: 'total_amount', label: t('schedules.total_amount'), field: 'total_amount', align: 'right', format: (val) => `R$ ${Number(val).toFixed(2)}` },
+  { name: 'actions', label: t('common.actions.title'), field: 'actions', align: 'center' }
+]);
+
+const isSaveDisabled = computed(() => {
+  if (props.schedule) {
+    return !hasUpdatedFields.value;
+  }
+  return scheduleDates.value.length === 0;
+})
+
+const formatDate = (date) => {
+  if (!date) return '';
+  const [year, month, day] = date.split('-');
+  return `${day}/${month}/${year}`;
+}
 
 const onClientChange = (client) => {
-  form.client_id = client?.value || null
+  form.client_id = client?.value || null;
   if (!props.schedule) {
-    selectedAddress.value = null
-    form.address_id = null
+    selectedAddress.value = null;
+    form.address_id = null;
   }
-  serverErrors.client_id = null
+  serverErrors.client_id = null;
 }
 
 const onProviderChange = async (provider) => {
-  form.provider_id = provider?.value || null
-  serverErrors.provider_id = null
+  form.provider_id = provider?.value || null;
+  serverErrors.provider_id = null;
   
   if (form.provider_id) {
     try {
-      providerData.value = await getProvider(form.provider_id)
-      calculateTotalAmount()
+      providerData.value = await getProvider(form.provider_id);
+      if (props.schedule) {
+        calculateTotalAmount();
+      }
     } catch (error) {
-      console.error('Error loading provider:', error)
+      console.error('Error loading provider:', error);
     }
   }
 }
 
 const onPeriodChange = () => {
-  serverErrors.period_type = null
-  calculateEndTime()
-  calculateTotalAmount()
+  serverErrors.period_type = null;
+  calculateEndTime();
+  calculateTotalAmount();
 }
 
 const onStartTimeChange = () => {
-  serverErrors.start_time = null
-  calculateEndTime()
+  serverErrors.start_time = null;
+  calculateEndTime();
 }
 
 const calculateEndTime = () => {
-  if (!form.start_time || !form.period_type) return
+  if (!form.start_time || !form.period_type) return;
   
-  const [hours, minutes] = form.start_time.split(':').map(Number)
-  const periodHours = parseInt(form.period_type)
+  const [hours, minutes] = form.start_time.split(':').map(Number);
+  const periodHours = parseInt(form.period_type);
   
-  const endHours = hours + periodHours
-  const endMinutes = minutes
+  const endHours = hours + periodHours;
+  const endMinutes = minutes;
   
-  form.end_time = `${String(endHours).padStart(2, '0')}:${String(endMinutes).padStart(2, '0')}:00`
+  form.end_time = `${String(endHours).padStart(2, '0')}:${String(endMinutes).padStart(2, '0')}`;
 }
 
 const calculateTotalAmount = () => {
-  if (!providerData.value || !form.period_type) return
+  if (!providerData.value || !form.period_type) return;
   const rateMap = {
     '2': providerData.value.daily_price_2h,
     '4': providerData.value.daily_price_4h,
     '6': providerData.value.daily_price_6h,
     '8': providerData.value.daily_price_8h
+  };
+  form.total_amount = rateMap[form.period_type] || 0;
+}
+
+const showAddDateForm = () => {
+  showDateForm.value = true;
+}
+
+const validateAddDate = () => {
+  let isValid = true;
+  
+  if (!form.date) {
+    serverErrors.date = t('common.validations.required');
+    isValid = false;
+  } else {
+    const isDuplicate = scheduleDates.value.some((item, index) => 
+      item.date === form.date && index !== editingDateIndex.value
+    );
+    if (isDuplicate) {
+      serverErrors.date = t('schedules.date_already_added');
+      isValid = false;
+    }
+  }
+  
+  if (!form.period_type) {
+    serverErrors.period_type = t('common.validations.required');
+    isValid = false;
+  }
+  
+  if (!form.start_time) {
+    serverErrors.start_time = t('common.validations.required');
+    isValid = false;
+  }
+  
+  return isValid;
+}
+
+const addOrUpdateDate = () => {
+  if (!validateAddDate()) return;
+  
+  const dateData = {
+    date: form.date,
+    period_type: form.period_type,
+    start_time: form.start_time,
+    end_time: form.end_time,
+    total_amount: form.total_amount
+  };
+  
+  if (editingDateIndex.value !== null) {
+    scheduleDates.value[editingDateIndex.value] = dateData;
+    editingDateIndex.value = null
+  } else {
+    scheduleDates.value.push(dateData);
   }
-  form.total_amount = rateMap[form.period_type] || 0
+  
+  resetDateForm()
+  showDateForm.value = false;
+}
+
+const editDate = (index) => {
+  const item = scheduleDates.value[index];
+  form.date = item.date;
+  form.period_type = item.period_type;
+  form.start_time = item.start_time;
+  form.end_time = item.end_time;
+  form.total_amount = item.total_amount;
+  editingDateIndex.value = index;
+  showDateForm.value = true;
+}
+
+const removeScheduleDate = (index) => {
+  scheduleDates.value.splice(index, 1);
+  if (editingDateIndex.value === index) {
+    cancelDateEdit();
+  }
+}
+
+const cancelDateEdit = () => {
+  editingDateIndex.value = null;
+  resetDateForm();
+  showDateForm.value = false;
+}
+
+const resetDateForm = () => {
+  form.date = null;
+  form.period_type = null;
+  form.start_time = null;
+  form.end_time = null;
+  form.total_amount = 0;
+  serverErrors.date = null;
+  serverErrors.period_type = null;
+  serverErrors.start_time = null;
 }
 
 const onOKClick = async () => {
   if (selectedClient.value?.value) {
-    form.client_id = selectedClient.value.value
+    form.client_id = selectedClient.value.value;
   }
   if (selectedProvider.value?.value) {
-    form.provider_id = selectedProvider.value.value
+    form.provider_id = selectedProvider.value.value;
   }
   if (selectedAddress.value?.value) {
-    form.address_id = selectedAddress.value.value
+    form.address_id = selectedAddress.value.value;
   }
 
   if (props.schedule) {
-    await submitForm(() => updateSchedule(props.schedule.id, getUpdatedFields.value))
+    await submitForm(() => updateSchedule(props.schedule.id, getUpdatedFields.value));
   } else {
-    await submitForm(() => createSchedule({ ...form }))
+    if (scheduleDates.value.length === 0) {
+      return
+    }
+    
+    const formData = {
+      client_id: form.client_id,
+      provider_id: form.provider_id,
+      address_id: form.address_id,
+      schedule_type: form.schedule_type,
+      status: form.status,
+      schedules: scheduleDates.value
+    };
+    
+    await submitForm(() => createSchedule(formData));
   }
 }
 
 onMounted(async () => {
   if (props.schedule?.provider_id) {
     try {
-      providerData.value = await getProvider(props.schedule.provider_id)
+      providerData.value = await getProvider(props.schedule.provider_id);
     } catch (error) {
-      console.error('Error loading provider:', error)
+      console.error('Error loading provider:', error);
     }
   }
 })