Spamworldpro Mini Shell
Spamworldpro


Server : Apache
System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64
User : corals ( 1002)
PHP Version : 7.4.33
Disable Function : exec,passthru,shell_exec,system
Directory :  /home/corals/ts.corals.io/frontend/components/TimesheetCalender/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/corals/ts.corals.io/frontend/components/TimesheetCalender/Week.vue
<template>
  <div>
    <div class="mb-5">
      <div class="d-md-block d-none">
        <c-overlay :show="showLoader">
          <b-card no-body class="card-overflow mb-1">

            <b-card-header header-tag="header">
              <div class="row no-gutters">
                <div class="col-md-3"></div>
                <div class="col-md-9 d-flex">
                  <div v-for="(day,index) in getDays" :key="'day_'+index" class="week-day">
                    {{ day.short_name }}
                    {{ (day.title).split(', ')[1] }}
                  </div>
                </div>
              </div>
            </b-card-header>

            <b-card-body>
              <template v-if="weekDays.length" v-for="(row,index) in weekDays">
                <div class="row no-gutters">
                  <div class="col-md-3">
                    <a href="#" v-if="row.showDeleteAction" @click.prevent="removeRow(index)"
                       class="text-danger clear-item-btn">
                      <fa icon="times"/>
                    </a>
                    <strong class="d-block">{{ row.client_name }} - {{ row.project }}</strong>
                    <small class="d-block" v-if="$isAdmin()">{{ row.user }}</small>
                    <small>{{ row.activity }}</small>
                  </div>
                  <div class="col-md-9 d-flex">
                    <div v-for="(day_times,date) in row.weekRowEntries" class="week-day">
                      <div v-for="(day_time,indexDay) in day_times"
                           class="d-flex justify-content-around align-items-center">
                        <vue-timepicker v-model="day_time.time"
                                        class="d-block p-1"
                                        input-class="form-control"
                                        hour-label="Hours"
                                        minute-label="Minutes" format="HH:mm"
                                        :minute-interval="5"
                                        drop-direction="auto"
                                        input-width="100px"
                                        advanced-keyboard
                                        manual-input
                                        close-on-complete
                                        placeholder="HH:MM"/>
                        <a :id="`description_${index}-${date}-${indexDay}`">
                          <fa v-if="!day_time.description" :icon="['far','sticky-note']"
                              :class="(day_time.time.HH || day_time.time.mm) ? 'text-danger' : 'text-success'"/>
                          <fa v-else icon="sticky-note" class="text-success"/>
                        </a>

                        <b-popover :target="`description_${index}-${date}-${indexDay}`" placement="bottomright">
                          <div class="d-flex">
                            <corals-textarea :form="form" field="" label="Description" v-model="day_time.description"
                                             required/>
                            <a href="#" @click.prevent="closeDescription" class="text-danger ">
                              <fa icon="times"/>
                            </a>
                          </div>
                        </b-popover>
                      </div>
                    </div>
                  </div>
                </div>
                <hr/>
              </template>

              <template v-if="!weekDays.length">
                <div class="p-5">
                  <h4 class="text-center">
                    No Entries yet!
                  </h4>
                </div>
              </template>
            </b-card-body>
          </b-card>
        </c-overlay>
      </div>

      <div class="d-md-none d-block">
        <hr/>
        <div v-for="(day,indexD) in getDays">
          <div>
            <strong>{{ day.title }}</strong>
            <hr style="width:50%;text-align:left;margin-left:0;"/>
          </div>
          <template v-if="weekDays.length" v-for="(row,indexW) in weekDays">
            <div class="row">
              <div class="col-7">
                <a href="#" v-if="row.showDeleteAction" @click.prevent="removeRow(indexW)"
                   class="text-danger clear-item-btn">
                  <fa icon="times"/>
                </a>
                <div>
                  <strong class="d-block">{{ row.client_name }} - {{ row.project }}</strong>
                  <small class="d-block" v-if="$isAdmin()">{{ row.user }}</small>
                  <small>{{ row.activity }}</small>
                </div>
              </div>
              <div class="col-5">
                <div v-for="(day_time,indexDay) in row.weekRowEntries[day.date]"
                     class="d-flex justify-content-around align-items-center">
                  <vue-timepicker v-model="day_time.time"
                                  class="d-block p-1"
                                  input-class="form-control"
                                  hour-label="Hours"
                                  minute-label="Minutes" format="HH:mm"
                                  :minute-interval="5"
                                  drop-direction="auto"
                                  input-width="100px"
                                  advanced-keyboard
                                  manual-input
                                  close-on-complete
                                  placeholder="HH:MM"/>
                  <a :id="`description_${indexD}-${indexW}-${day_time.date}-${indexDay}`">
                    <fa v-if="!day_time.description" :icon="['far','sticky-note']"
                        :class="(day_time.time.HH || day_time.time.mm) ? 'text-danger' : 'text-success'"/>
                    <fa v-else icon="sticky-note" class="text-success"/>
                  </a>

                  <b-popover :target="`description_${indexD}-${indexW}-${day_time.date}-${indexDay}`"
                             placement="bottomleft">
                    <div class="d-flex">
                      <corals-textarea :form="form" field="" label="Description" v-model="day_time.description"
                                       required/>
                      <a href="#" @click.prevent="closeDescription" class="text-danger ">
                        <fa icon="times"/>
                      </a>
                    </div>
                  </b-popover>
                </div>
              </div>
            </div>
            <hr/>
          </template>
        </div>
      </div>

      <div class="row mt-3">
        <div class="col-md-12">
          <button :disabled="weekDays.length === 0" class="btn btn-success" @click.prevent="saveWeek">
            <fa icon="save"/>
            Save
          </button>
        </div>
      </div>
    </div>
    <template v-if="showCreateRowModal">
      <b-modal hide-footer
               visible
               content-class="shadow"
               :title-html="modalTitle"
               @hidden="onModalHidden"
               no-close-on-backdrop
               :id="rowModalId"
               size="md">
        <div class="row">
          <div class="col-md-12">
            <c-overlay :show="!form.isReady">
              <div class="row">
                <div class="col-md-10">
                  <corals-select :form="form" required label="Project" field="project_id"
                                 :options="getProjectOptions"
                                 @input="loadProjectRelatedFormData(form.project_id)"/>

                  <corals-select :form="form" required label="Activity" field="activity_id"
                                 :options="getActivitiesOptions"/>

                  <corals-select v-if="$isAdmin()" :form="form" label="User" field="user_id"
                                 :options="getUsersOptions"
                                 required/>
                </div>
              </div>
              <div class="text-right">
                <button type="submit" class="btn btn-sm btn-primary" @click.prevent="submitRow"
                        :disabled="!form.isReady">
                  {{ modalTitle }}
                </button>
                <button @click.prevent="$bvModal.hide(rowModalId)" class="btn btn-sm btn-secondary"
                        :disabled="!form.isReady">Close
                </button>
              </div>
            </c-overlay>
          </div>
        </div>
      </b-modal>
    </template>
  </div>
</template>

<script>
import COverlay from "@/components/layout/COverlay";
import CoralsSelect from "@/components/CoralsForm/CoralsSelect";
import VueTimepicker from 'vue2-timepicker';

export default {
  name: "week",
  inject: ['fetchNewWeek', 'removeRowWeek', 'onModalHidden'],
  components: {COverlay, CoralsSelect, VueTimepicker},
  props: {
    showLoader: {
      required: true
    },
    days: {
      required: true
    },
    weekDays: {
      required: true
    },
    showCreateRowModal: {
      required: true,
    },
  },
  data() {
    return {
      active_options: 1,
      modalTitle: 'Create row',
      rowModalId: 'row-modal',
      activities: [],
      users: [],
      form: this.$form({
        activity_id: '',
        project_id: '',
        user_id: this.$auth.user.id
      }, {fetchFormDataURL: 'timesheet/entries/get-form-data', model: 'entry'})
    }
  },
  mounted() {
  },
  methods: {
    getActivitiesOrProjectsOptions(arrayData) {
      let resultsData = [];
      let DataGroups = [];
      let activeObjects = [];

      if (!this.active_options) {
        activeObjects = arrayData.filter((object => object['group'] !== true));
        DataGroups = arrayData.filter((group => group['group'] === true));
      } else {
        activeObjects = arrayData.filter((object => (object['is_active'] === 1 || object['status'] === 'active') && object['group'] !== true));
        DataGroups = arrayData.filter((group => group['group'] === true && group['status'] === 'active'));
      }
      DataGroups.forEach(group => {
        group['is_group_empty'] = true;
        resultsData.push(group);
        activeObjects.filter(activeObject => {
          if (group['code'] === activeObject['group']) {
            group['is_group_empty'] = false;
            resultsData.push(activeObject);
          }
        });
      });
      return resultsData;
    },
    loadProjectRelatedFormData(project_id) {
      if (!project_id) {
        this.activities = []
        this.users = []
        return;
      }
      this.form.isReady = false;

      let url = `timesheet/entries/get-form-data?project_id=${project_id}`;

      this.$axios.get(url).then(({data: response}) => {
        this.activities = response.data.activities
        this.users = response.data.users
      }).finally(() => {
        this.form.isReady = true;
      });
    },
    submitRow() {
      let daysTimes = {};

      for (let i = 0; i < this.days.length; i++) {
        let time = {
          HH: '',
          mm: ''
        }
        let day = this.days[i].date;

        daysTimes[day] = [{'entryId': '', 'date': this.days[i].date, 'time': time, 'description': ''}];
      }
      let project = (this.form.getFormData('projects')).filter((project) => {
        return project.value === this.form.project_id
      });
      let activity = this.getActivitiesOptions.filter((activity) => {
        return activity.value === this.form.activity_id
      });
      let user = this.getUsersOptions.filter((user) => {
        return user.id === this.form.user_id
      });

      let record = {
        'activity_id': this.form.activity_id,
        'activity': activity[0].label,
        'project_id': this.form.project_id,
        'project': project[0].label,
        'user_id': this.form.user_id,
        'user': (user[0].label).split(', ')[0],
        'showDeleteAction': true,
        'weekRowEntries': daysTimes,
      };

      this.weekDays.push(record)

      this.$bvModal.hide(this.rowModalId);
    },
    removeRow(rowIndex) {
      let result = [];
      this.weekDays.forEach((arr, index) => {
        if (index != rowIndex) {
          result.push(arr);
        }
      });
      this.removeRowWeek(result);
    },
    saveWeek() {
      let week = this.weekDays;
      let selectedDate = this.$route.query.date;
      let invalid_data = false;

      week.forEach((arr) => {
        for (let day in arr.weekRowEntries) {
          arr.weekRowEntries[day].forEach((entry) => {
            if (!entry.description && (entry.time.HH || entry.time.mm)) {
              invalid_data = true;
            }
          })
        }
      });

      if (invalid_data) {
        this.$toast.error('Please make sure the entries description set');
      } else {

        this.$axios.post(`timesheet/timesheet-calender/save-week`, {
          week: week
        }).then(response => {
          this.fetchNewWeek(selectedDate);
          this.$toast.success(response.data.message);
        })
          .catch(err => {
            console.error(err);
          });
      }
    },
    closeDescription() {
      this.$root.$emit('bv::hide::popover');
    },
  },
  watch: {},
  computed: {
    getDays() {
      return this.days;
    },
    getProjectOptions() {
      return this.getActivitiesOrProjectsOptions(this.form.getFormData('projects'));
    },
    getActivitiesOptions() {
      let activities = this.activities.length ? this.activities : this.form.getFormData('activities');
      return this.getActivitiesOrProjectsOptions(activities);
    },
    getUsersOptions() {
      let users = this.users.length ? this.users : this.form.getFormData('users');
      if (!this.active_options) {
        return users
      }
      return users.filter(user => (user['status'] === 'active'));
    },
  },
}
</script>
<style scoped>
.week-day {
  width: 130px;
}

.clear-item-btn {
  position: absolute;
  top: 0;
  left: -15px;
}
@media (max-width: 768px)  {
  .clear-item-btn {
    top: -15px;
    left: 5px;
  }
}
</style>

Spamworldpro Mini