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/pages/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/corals/ts.corals.io/frontend/pages/index.vue
<template>
  <div>
    <div class="row d-none d-md-flex">
      <div class="col-md-6 offset-md-1">
        <div class="ml-1 pb-2 d-flex align-items-center">
          <b-button-group>
            <b-button :disabled="!days.length" @click="goPrev" variant="outline-secondary"
                      v-can="`view entry`">
              <fa icon="chevron-left"/>
            </b-button>
            <b-button :disabled="!days.length" @click="goNext" variant="outline-secondary" v-can="`view entry`">
              <fa icon="chevron-right"/>
            </b-button>
          </b-button-group>

          <h2 class="d-inline-block mb-0 mx-3" v-if="selectedDate && dayViewEnabled">{{ selectedDate.title }}</h2>

          <h2 class="d-inline-block mb-0 mx-2" v-else-if="!dayViewEnabled">
            {{ this.start_week + ' - ' + this.end_week }}</h2>

          <b-skeleton animation="fade" class="d-inline-block mb-0 mx-3 w-25 sk-h2" v-else></b-skeleton>

          <a href="#" @click.prevent="returnToToday" v-if="!isTodayOrWeekSelected" v-can="`view entry`">
            <small>
              <span v-if="dayViewEnabled">Return to today</span>
              <span v-else>Return to current week</span>
            </small>
          </a>
        </div>
      </div>
      <div class="col-md-5 d-flex align-items-center justify-content-end">

        <b-button-group class="mr-2 rounded ">
          <b-button class="btn-light border-secondary" :class="[dayViewEnabled ? 'active' : '']"
                    v-b-tooltip.hover title="Day view"
                    @click.prevent="hideWeekView">
            <fa icon="calendar-week" class="text-dark"/>
            Day
          </b-button>
          <b-button class="btn-light border-secondary" :class="[!dayViewEnabled ? 'active' : '']"
                    v-b-tooltip.hover title="Week view"
                    @click.prevent="showWeekView">
            <fa icon="calendar-week" class="text-dark"/>
            Week
          </b-button>
        </b-button-group>

        <b-button @click.prevent="openFilterModal" class="mr-1" variant="warning" :disabled="!days.length"
                  v-if="$isAdmin()">
          <fa icon="filter"/>
        </b-button>
        <b-form-datepicker v-model="specificDate" button-variant="info" class="mr-1" dropleft button-only
                           :disabled="!days.length"/>
      </div>
    </div>
    <div class="row d-md-none no-gutters">
      <div class="col-10">
        <div class="d-flex align-items-center">
          <b-button-group class="d-inline-block">
            <b-button :disabled="!days.length" @click="goPrev" variant="outline-secondary" class="px-2">
              <fa icon="chevron-left"/>
            </b-button>
            <b-button :disabled="!days.length" @click="goNext" variant="outline-secondary" class="px-2">
              <fa icon="chevron-right"/>
            </b-button>
          </b-button-group>

          <h4 class="d-inline-block mb-0 mx-2 mx-md-3" v-if="selectedDate && dayViewEnabled">
            {{ selectedDate.title }}</h4>

          <h5 class="d-inline-block mb-0 mx-md-3" v-else-if="!dayViewEnabled">
            {{ this.start_week + '-' + this.end_week }}</h5>

          <b-skeleton animation="fade" class="d-inline-block mb-0 mx-2 mx-md-3 w-50 sk-h4" v-else></b-skeleton>
        </div>
        <a href="#" class="d-block text-right mb-1"
           @click.prevent="returnToToday" v-if="!isTodayOrWeekSelected"
           v-can="`view entry`">
          <small>
            <span v-if="dayViewEnabled">Return to today</span>
            <span v-else>Return to current week</span>
          </small>
        </a>
        <div v-else class="mb-1">
          <small>&nbsp;</small>
        </div>
      </div>
      <div class="col-2 text-right">
        <b-form-datepicker v-model="specificDate" dropleft button-variant="info" button-only :disabled="!days.length"/>
      </div>
    </div>
    <div class="row no-gutters">
      <div class="col-md-1 text-md-center d-none d-md-block pt-2">
        <button class="btn btn-success py-1 px-2"
                v-can="`create entry`"
                v-b-tooltip.hover title="New entry" :disabled="!days.length"
                @click.prevent="openModal">
          <fa icon="plus" size="3x"/>
        </button>
        <small class="d-block"><b v-if="dayViewEnabled">New entry</b> <b v-else>New Row</b></small>
      </div>
      <div class="col-12 d-block d-md-none justify-content-between d-flex"
           :class="$isAdmin()?'col-10':'col-12'">
        <b-button class="btn btn-success mb-2" :disabled="!days.length"
                  @click.prevent="openModal">
          <fa icon="plus"/>
          <span v-if="dayViewEnabled">New entry</span>
          <span v-else>New Row</span>
        </b-button>

        <b-button-group class="mb-2 rounded">
          <b-button class="btn-light border-secondary" :class="[dayViewEnabled ? 'active' : '']"
                    v-b-tooltip.hover title="Day view"
                    @click.prevent="hideWeekView">
            <fa icon="calendar-week" class="text-dark"/>
            Day
          </b-button>
          <b-button class="btn-light border-secondary" :class="[!dayViewEnabled ? 'active' : '']"
                    v-b-tooltip.hover title="Week view"
                    @click.prevent="showWeekView">
            <fa icon="calendar-week" class="text-dark"/>
            Week
          </b-button>
        </b-button-group>
        <b-button @click.prevent="openFilterModal" class="mb-2"
                  v-isAdmin :disabled="!days.length"
                  variant="warning">
          <fa icon="filter"/>
        </b-button>
      </div>
      <div class="col-md-11">
        <div class="row d-flex" v-isAdmin v-if="filterForm.initialized">
          <div class="col-md-12">
            <ul class="list-inline m-0">
              <li class="list-inline-item" v-if="filterForm.user_id">
                <small><b>User:</b> {{ selectedUserFilter.label }}</small>
                <sup class="text-danger cursor-pointer">
                  <fa icon="times" @click.prevent="clearFilterItem('user_id')"/>
                </sup>
              </li>
              <li class="list-inline-item" v-if=" filterForm.client_id">
                <small><b>Client:</b> {{ selectedClientFilter }}</small>
                <sup class="text-danger cursor-pointer">
                  <fa icon="times" @click.prevent="clearFilterItem('client_id')"/>
                </sup>
              </li>
              <li class="list-inline-item" v-if="filterForm.project_id">
                <small><b>Project:</b> {{ selectedProjectFilter }}</small>
                <sup class="text-danger cursor-pointer">
                  <fa icon="times" @click.prevent="clearFilterItem('project_id')"/>
                </sup>
              </li>
            </ul>
          </div>
        </div>
        <div v-if="dayViewEnabled">
          <Day :showLoader="showLoader"
               :days="days"
               :selectedDayIndex="selectedDayIndex"
               :evaluationEnabled="evaluationEnabled"
               :showBillable="showBillable"
               :weekTotalBillableTime="weekTotalBillableTime"
               :weekTotalTime="weekTotalTime"
               :form="form"
               :showAddEntryModal="showAddEntryModal"
               :entryModalTitle="entryModalTitle"
          />
        </div>
        <div v-else>
          <Week :showLoader="showLoader"
                :days="days"
                :weekDays="getWeekDays"
                :showCreateRowModal="showCreateRowModal"/>
        </div>
      </div>
    </div>

    <div class="d-flex justify-content-center">
      <div class="text-sm col-md-8">
        <b-alert variant="warning" show fade v-if="membersWithoutEntries.length && $isAdmin()">
          <b>
            Users without entries for {{ selectedDate.title }}:
          </b>
          <br/>
          <div v-for="member in membersWithoutEntries">- {{ member }}</div>
        </b-alert>
      </div>
    </div>

    <template v-if="$isAdmin()">
      <b-modal content-class="shadow" title="Filters"
               no-close-on-backdrop :id="filtersModalId">

        <c-overlay :show="!filterForm.initialized">
          <div>
            <corals-select :form="tempFilterForm" label="User"
                           field="user_id"
                           :options="filterForm.initialized?filterForm.getFormData('users'):[]"/>
          </div>
          <div>
            <corals-select :form="tempFilterForm" label="Project"
                           field="project_id"
                           :options="filterForm.initialized?filterForm.getFormData('projects'):[]"/>
          </div>
          <div>
            <corals-select :form="tempFilterForm" label="Client"
                           field="client_id"
                           :options="filterForm.initialized?filterForm.getFormData('clients'):[]"/>
          </div>
        </c-overlay>
        <template #modal-footer>
          <button class="btn btn-primary" @click.prevent="filter">
            <fa icon="search"></fa>
          </button>
          <button class="btn btn-secondary" @click.prevent="resetFilters">
            <fa icon="eraser"></fa>
          </button>
        </template>
      </b-modal>
    </template>
  </div>
</template>

<script>

import COverlay from "@/components/layout/COverlay";
import commonMixin from "@/mixins/commonMixin";
import Week from "@/components/TimesheetCalender/Week";
import Day from "@/components/TimesheetCalender/Day";

export default {
  name: "timesheet-calender",
  components: {COverlay, Week, Day},
  middleware: 'Authorization',
  mixins: [commonMixin],
  provide() {
    return {
      fetchNewWeek: this.fetchNewWeek,
      removeRowWeek: this.removeRowWeek,
      showEditEntryModal: this.showEditEntryModal,
      onModalHidden: this.onModalHidden,
      updateCreateEntry: this.updateCreateEntry,
      updateSelectedDayIndex:this.updateSelectedDayIndex,
      afterFormSubmitted: this.afterFormSubmitted,
    }
  },
  async fetch() {

    if (this.hasFiltersMethod()) {
      await this.initFilterForm()
    }

    let date = this.todayDate;

    if (this.$route.query.date && this.$route.query.date.match(/^\d{4}-\d{2}-\d{2}$/) !== null) {
      date = this.$route.query.date;
    }

    await this.fetchWeekAndSelectDate(date);
  },
  data() {
    return {
      prev_week: null,
      next_week: null,
      start_week: null,
      end_week: null,
      dayViewEnabled: true,
      specificDate: this.selectedDate,
      days: [],
      weekDays: [],
      weekTotalTime: '00:00',
      weekTotalBillableTime: '00:00',
      filtersModalId: 'filter-modal',
      filterForm: {},
      tempFilterForm: this.$form({
        user_id: this.$route.query.user_id || '',
        project_id: this.$route.query.project_id || '',
        client_id: this.$route.query.client_id || ''
      }, {fetchFormDataURL: 'timesheet/timesheet-calender/get-filters-form-data'}),
      showBillable: false,
      showAddEntryModal: false,
      showCreateRowModal: false,
      selectedDayIndex: null,
      showLoader: false,
      selectedEntry: null,
      form: this.$form({
        activity_id: '',
        project_id: '',
        user_id: '',
        spent_at: new Date(),
        spent_from: new Date(),
        spent_to: new Date(),
        hours: '',
        minutes: '',
        tags: [],
        evaluation_hours: '',
        evaluation_minutes: '',
        description: '',
        has_reviewed: 0,
        multiple_entries: 0,
        all_member_users: 0,
      }, {fetchFormDataURL: 'timesheet/entries/get-form-data', model: 'entry'})
    }
  },

  methods: {
    showWeekView() {
      this.dayViewEnabled = false;
    },
    hideWeekView() {
      this.dayViewEnabled = true;
    },
    removeRowWeek(result) {
      this.weekDays = result;
    },
    openFilterModal() {
      if (!this.filterForm.initialized) {
        this.initFilterForm();
      }
      this.$bvModal.show(this.filtersModalId);
    },
    async initFilterForm() {

      this.filterForm = await this.$form({
        user_id: this.$route.query.user_id || '',
        project_id: this.$route.query.project_id || '',
        client_id: this.$route.query.client_id || ''
      }, {fetchFormDataURL: 'timesheet/timesheet-calender/get-filters-form-data'});
    },
    resetFilters() {
      this.filterForm.reset();
      this.tempFilterForm.reset();

      this.filter();
    },
    filter() {
      this.filterForm.replace(this.tempFilterForm);

      this.fetchWeekAndSelectDate(this.selectedDate.date)
      this.$bvModal.hide(this.filtersModalId);
    },
    appendAllFiltersToURLParameters() {
      this.$router.push({
        query: this.getParametersList()
      });
    },
    getParametersList() {

      let selectedDate = this.selectedDate;

      let filters = {},
        date = null;

      if (this.filterForm) {
        filters = {
          user_id: this.filterForm.user_id || '',
          client_id: this.filterForm.client_id || '',
          project_id: this.filterForm.project_id || ''
        };
      }

      if (selectedDate && selectedDate.date) {
        date = selectedDate.date;
      } else if (this.$route.query.date && this.$route.query.date.match(/^\d{4}-\d{2}-\d{2}$/) !== null) {
        date = this.$route.query.date;
      }

      Object.keys(filters).forEach((k) => (!filters[k]) && delete filters[k]);

      return Object.assign(filters, {
        date: date
      });

    },
    clearFilterItem(key) {
      this.tempFilterForm[key] = '';
      this.filter();
    },
    showEditEntryModal(entry) {
      this.selectedEntry = entry;
      this.showAddEntryModal = true;
    },
    onModalHidden() {
      if (this.dayViewEnabled) {
        this.form.replace(this.form.originalData);
        this.form.errors.purge();
        this.selectedEntry = null;
        this.showAddEntryModal = false;
      } else {
        this.showCreateRowModal = false;
      }
    },
    openModal() {
      if (this.$cant('create', 'entry')) {
        return;
      }
      if (this.dayViewEnabled) {
        // this.form.user_id = this.$auth.user.id;
        this.form.id = '';
        this.form.spent_at = this.selectedDate.date;
        this.showAddEntryModal = true;

      } else {
        this.showCreateRowModal = true;
      }
    },
    async updateCreateEntry() {
      if (this.selectedEntry) {
        this.updateSelectedEntry()
      } else {
        this.createNewEntry()
      }
    },
    updateSelectedEntry() {

      if (this.$cant('update', 'entry')) {
        return;
      }

      this.form.put(`timesheet/projects/${this.selectedEntry.project_id}/entries/${this.selectedEntry.id}`)
        .then(this.afterFormSubmitted);
    },
    createNewEntry() {

      if (this.$cant('create', 'entry')) {
        return;
      }

      if (!this.form.project_id) {
        return;
      }
      this.form.post(`timesheet/projects/${this.form.project_id}/entries`)
        .then(async response => {
          await this.afterFormSubmitted();
        })
    },

    async afterFormSubmitted() {
      this.selectedEntry = null;
      // this.form.user_id = this.$auth.user.id;
      this.form.id = '';
      this.form.spent_at = this.selectedDate.date;
      this.form.setDefaults();

      this.showAddEntryModal = false;

      await this.fetchWeekAndSelectDate(this.selectedDate.date);
    },
    returnToToday() {
      if (!this.selectDay(this.todayDate)) {
        this.fetchNewWeek(this.todayDate).then(() => {
          this.selectDay(this.todayDate)
        });
      }
    },
    selectDay(dayDate) {
      let todaySelected = false;

      for (const dayIndex in this.days) {
        if (this.days[dayIndex].date === dayDate) {
          this.selectedDayIndex = Number(dayIndex);
          todaySelected = true;
          break;
        }
      }

      this.appendAllFiltersToURLParameters(dayDate);

      return todaySelected;
    },
    async goNext() {
      if (!this.dayViewEnabled) {
        await this.fetchNewWeek(this.next_week);
        this.selectedDayIndex = 0;
      } else {
        if (!this.days[this.selectedDayIndex + 1]) {
          await this.fetchNewWeek(this.selectedDate.next_day);
          this.selectedDayIndex = 0;
        } else {
          this.selectedDayIndex++;
        }
      }
    },
    async goPrev() {
      if (!this.dayViewEnabled) {
        await this.fetchNewWeek(this.prev_week);
        this.selectedDayIndex = this.days.length - 1;
      } else {
        if (!this.days[this.selectedDayIndex - 1]) {
          await this.fetchNewWeek(this.selectedDate.prev_day);
          this.selectedDayIndex = this.days.length - 1;
        } else {
          this.selectedDayIndex--;
        }
      }
    },
    async fetchNewWeek(startDate) {

      if (this.$cant('view', 'entry')) {
        return;
      }

      this.showLoader = true;

      let url = `timesheet/timesheet-calender/get-week?start_date=${startDate}`,
        getFilterDataAsParameters = this.objectAsQueryString(this.getParametersList());

      if (getFilterDataAsParameters) {
        url += `&${getFilterDataAsParameters}`;
      }

      let response = await this.$axios
        .get(url)
        .then(({data}) => data.data)
        .finally(() => this.showLoader = false)

      this.days = response.days;
      this.weekDays = response.weekDays.week;
      this.prev_week = response.weekDays.prev_week;
      this.next_week = response.weekDays.next_week;
      this.start_week = response.weekDays.start_week;
      this.end_week = response.weekDays.end_week;

      this.weekTotalTime = response.week_total_time;
      this.weekTotalBillableTime = response.week_total_evaluation_time;
    },
    getFilterDataAsParameters() {
      if (!this.filterForm.initialized) {
        return
      }

      this.appendAllFiltersToURLParameters();
    },


    async fetchWeekAndSelectDate(date) {
      if (this.$cant('view', 'entry')) {
        return;
      }
      await this.fetchNewWeek(date)
      this.selectDay(date);
    },
    hasFiltersMethod() {
      return this.hasFilters;
    },
    updateSelectedDayIndex(index){
      this.selectedDayIndex = index;
    }
  },
  computed: {
    evaluationEnabled() {
      return this.$store.getters.settings('evaluation_enabled');
    },
    membersWithoutEntries() {
      if (!this.days.length) {
        return [];
      }

      if (this.selectedDayIndex == null) {
        return [];
      }

      return this.days[this.selectedDayIndex].members_without_entries || [];
    },
    getWeekDays() {
      return this.weekDays;
    },
    hasFilters() {
      for (let f of ['user_id', 'project_id', 'client_id']) {
        if (this.filterForm[f] || this.$route.query[f]) {
          return true;
        }
      }
      return false;
    },
    isTodayOrWeekSelected() {
      if (!this.days.length) {
        return true;
      }
      if (!this.dayViewEnabled) {
        return this.todayDate > this.prev_week && this.todayDate < this.next_week;
      }

      for (let dayIndex in this.days) {
        if (this.days[dayIndex].date === this.todayDate) {
          return this.selectedDayIndex === Number(dayIndex);
        }
      }

      return false;
    },
    selectedDate() {
      let sDate = this.days[this.selectedDayIndex];

      if (sDate) {
        this.specificDate = sDate.date;
      }

      return sDate;
    },
    todayDate() {
      let today = new Date(),
        dd = String(today.getDate()).padStart(2, '0'),
        mm = String(today.getMonth() + 1).padStart(2, '0'),
        yyyy = today.getFullYear();

      return `${yyyy}-${mm}-${dd}`;
    },
    entryModalTitle() {
      return (this.selectedEntry ? `Update` : `Create`) + ' Entry';
    },
    selectedUserFilter() {
      if (this.filterForm.initialized && this.filterForm.user_id) {

        return this.filterForm.getFormData('users').filter((user) => {
          return user.value == this.filterForm.user_id;
        }).shift();
      }

      return '';
    },
    selectedProjectFilter() {
      if (!this.filterForm.initialized || !this.filterForm.project_id) {
        return;
      }

      let projects = this.filterForm.getFormData('projects');
      let client = '';

      for (let i in projects) {
        if (projects[i].group === true) {
          client = projects[i].label
          continue;
        }

        if (projects[i].value == this.filterForm.project_id) {
          return projects[i].label + (client ? `[${client}]` : '');
        }
      }

      return '';
    },
    selectedClientFilter() {
      if (this.filterForm.initialized && this.filterForm.client_id) {
        return this.filterForm.getFormData('clients')[this.filterForm.client_id];
      }
      return '';
    }
  },
  watch: {
    specificDate(targetDate) {
      if (!this.selectDay(targetDate)) {
        this.fetchWeekAndSelectDate(targetDate);
      }
    }
  },
  beforeMount() {
    this.$eventBus.$on('fetch-week-and-select-date', this.fetchWeekAndSelectDate)
  },
  beforeDestroy() {
    this.$eventBus.$off('fetch-week-and-select-date');
  }
}
</script>

<style scoped>
.calendar-week {
  /*background: transparent;*/
}

.calendar-week >>> .card-header {
  padding: .5rem 1rem !important;
}

.calendar-week >>> .card-body {
  padding: 0 1rem !important;
}

.b-skeleton-text {
  height: 20px;
}

.sk-h2 {
  height: 39px;
}

.sk-h4 {
  height: 29px;
}

.b-form-datepicker >>> .btn {
  padding: 6px 10px !important;
}
</style>

Spamworldpro Mini