HEX
Server: Microsoft-IIS/10.0
System: Windows NT ITPWINWEBSVR22 10.0 build 20348 (Windows Server 2022) AMD64
User: www.conferencesearch.co.uk (0)
PHP: 8.3.30
Disabled: NONE
Upload Files
File: D:/web/matomo.circ/plugins/ScheduledReports/vue/src/AddReport/AddReport.vue
<!--
  Matomo - free/libre analytics platform

  @link    https://matomo.org
  @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
-->

<template>
  <ContentBlock
    class="entityAddContainer"
    :content-title="contentTitle"
  >
    <div class="clear" />
    <form
      id="addEditReport"
      @submit="$emit('submit')"
      v-form
    >
      <div>
        <Field
          uicontrol="text"
          name="website"
          :title="translate('General_Website')"
          :disabled="true"
          :model-value="siteName"
        >
        </Field>
      </div>
      <div>
        <Field
          uicontrol="textarea"
          name="report_description"
          :title="translate('General_Description')"
          :model-value="report.description"
          @update:model-value="$emit('change', { prop: 'description', value: $event })"
          :inline-help="translate('ScheduledReports_DescriptionOnFirstPage')"
        >
        </Field>
      </div>
      <div v-if="segmentEditorActivated">
        <Field
          uicontrol="select"
          name="report_segment"
          :title="translate('SegmentEditor_ChooseASegment')"
          :model-value="report.idsegment"
          @update:model-value="$emit('change', { prop: 'idsegment', value: $event })"
          :options="savedSegmentsById"
        >
          <template v-slot:inline-help>
            <div
              id="reportSegmentInlineHelp"
              class="inline-help-node"
              v-if="segmentEditorActivated"
              v-html="$sanitize(reportSegmentInlineHelp)"
            />
          </template>
        </Field>
      </div>
      <div>
        <Field
          uicontrol="select"
          name="report_schedule"
          :model-value="report.period"
          @update:model-value="$emit('change', { prop: 'period', value: $event });
            $emit('change', {
              prop: 'periodParam',
              value: report.period === 'never' ? null : report.period,
            })"
          :title="translate('ScheduledReports_EmailSchedule')"
          :options="periods"
        >
          <template v-slot:inline-help>
            <div
              id="emailScheduleInlineHelp"
              class="inline-help-node"
            >
              {{ translate('ScheduledReports_WeeklyScheduleHelp') }}
              <br />
              {{ translate('ScheduledReports_MonthlyScheduleHelp') }}
            </div>
          </template>
        </Field>
      </div>
      <div>
        <Field
          uicontrol="select"
          name="report_period"
          :model-value="report.periodParam"
          @update:model-value="$emit('change', { prop: 'periodParam', value: $event })"
          :options="paramPeriods"
          :title="translate('ScheduledReports_ReportPeriod')"
        >
          <template v-slot:inline-help>
            <div
              id="emailReportPeriodInlineHelp"
              class="inline-help-node"
            >
              {{ translate('ScheduledReports_ReportPeriodHelp') }}
              <br /><br />
              {{ translate('ScheduledReports_ReportPeriodHelp2') }}
            </div>
          </template>
        </Field>
      </div>
      <div>
        <Field
          uicontrol="select"
          name="report_hour"
          :model-value="report.hour"
          @update:model-value="$emit('change', { prop: 'hour', value: $event })"
          :title="translate('ScheduledReports_ReportHour', 'X')"
          :options="reportHours"
        >
          <template v-slot:inline-help>
            <div
              id="reportHourHelpText"
              class="inline-help-node"
              v-if="timezoneOffset !== 0 && timezoneOffset !== '0'"
            >
              <span v-text="reportHourUtc" />
            </div>
          </template>
        </Field>
      </div>
      <div>
        <Field
          uicontrol="select"
          name="report_type"
          :disabled="reportTypes.length === 1"
          :model-value="report.type"
          @update:model-value="$emit('change', { prop: 'type', value: $event })"
          :title="translate('ScheduledReports_ReportType')"
          :options="reportTypeOptions"
        >
        </Field>
      </div>
      <div
        v-for="(reportFormats, reportType) in reportFormatsByReportTypeOptions"
        :key="reportType"
      >
        <Field
          uicontrol="select"
          name="report_format"
          :title="translate('ScheduledReports_ReportFormat')"
          :class="reportType"
          v-show="report.type === reportType"
          :model-value="report[`format${reportType}`]"
          @update:model-value="$emit('change', { prop: `format${reportType}`, value: $event })"
          :options="reportFormats"
        >
        </Field>
      </div>
      <div ref="reportParameters">
        <slot name="report-parameters"></slot>
      </div>
      <div
        v-show="report.type === 'email'
              && report.formatemail !== 'csv'
              && report.formatemail !== 'tsv'"
      >
        <div class="email">
          <Field
            uicontrol="select"
            name="display_format"
            :model-value="report.displayFormat"
            @update:model-value="$emit('change', { prop: 'displayFormat', value: $event })"
            :options="displayFormats"
            :introduction="translate('ScheduledReports_AggregateReportsFormat')"
          >
          </Field>
        </div>
        <div class="report_evolution_graph">
          <Field
            uicontrol="checkbox"
            name="report_evolution_graph"
            :title="translate('ScheduledReports_EvolutionGraph', 5)"
            v-show="[2, '2', 3, '3'].indexOf(report.displayFormat) !== -1"
            :model-value="report.evolutionGraph"
            @update:model-value="$emit('change', { prop: 'evolutionGraph', value: $event })"
          >
          </Field>
        </div>
        <div
          class="row evolution-graph-period"
          v-show="[1, '1', 2, '2', 3, '3'].indexOf(report.displayFormat) !== -1"
        >
          <div class="col s12">
            <label for="report_evolution_period_for_each">
              <input
                id="report_evolution_period_for_each"
                name="report_evolution_period_for"
                type="radio"
                value="each"
                :checked="report.evolutionPeriodFor === 'each'"
                @change="$emit(
                  'change',
                  { prop: 'evolutionPeriodFor', value: $event.target.value },
                )"
              />
              <span v-html="$sanitize(evolutionGraphsShowForEachInPeriod)"></span>
            </label>
          </div>
          <div class="col s12">
            <label for="report_evolution_period_for_prev">
              <input
                id="report_evolution_period_for_prev"
                name="report_evolution_period_for"
                type="radio"
                value="prev"
                :checked="report.evolutionPeriodFor === 'prev'"
                @change="$emit(
                  'change',
                  { prop: 'evolutionPeriodFor', value: $event.target.value },
                )"
              />
              <span>{{ translate(
                'ScheduledReports_EvolutionGraphsShowForPreviousN',
                frequencyPeriodPlural,
              ) }}:
                <input
                  type="number"
                  name="report_evolution_period_n"
                  :value="report.evolutionPeriodN"
                  @keydown="onEvolutionPeriodN($event)"
                  @change="onEvolutionPeriodN($event)"
                />
              </span>
            </label>
          </div>
        </div>
      </div>
      <div class="row">
        <h3 class="col s12">{{ translate('ScheduledReports_ReportsIncluded') }}</h3>
      </div>
      <div
        name="reportsList"
        :class="`row ${reportType}`"
        v-show="report.type === reportType"
        v-for="(reportColumns, reportType) in reportsByCategoryByReportTypeInColumns"
        :key="reportType"
      >
        <div class="col s12 m6" v-for="(reportsByCategory, index) in reportColumns" :key="index">
          <div v-for="(reports, category) in reportsByCategory" :key="category">
            <h3 class="reportCategory">{{ category }}</h3>
            <ul class="listReports">
              <li v-for="report in reports" :key="report.uniqueId">
                <label>
                  <input
                    :name="`${reportType}Reports`"
                    :type="allowMultipleReportsByReportType[reportType] ? 'checkbox' : 'radio'"
                    :id="`${reportType}${report.uniqueId}`"
                    :checked="selectedReports[reportType]?.[report.uniqueId]"
                    @change="$emit('toggleSelectedReport', {
                      reportType,
                      uniqueId: report.uniqueId,
                    })"
                  />
                  <span>{{ decode(report.name) }}</span>
                  <div class="entityInlineHelp" v-if="report.uniqueId === 'MultiSites_getAll'">
                    {{ translate('ScheduledReports_ReportIncludeNWebsites', countWebsites) }}
                  </div>
                </label>
              </li>
            </ul>
            <br />
          </div>
        </div>
      </div>
      <SaveButton
        :value="saveButtonTitle"
        @confirm="$emit('submit')"
      />
      <div
        class="entityCancel"
        v-html="$sanitize(entityCancelText)"
      >
      </div>
    </form>
  </ContentBlock>
</template>

<script lang="ts">
import {
  defineComponent,
  onMounted,
  ref,
  watch,
} from 'vue';
import {
  ContentBlock,
  Matomo,
  translate,
  debounce,
} from 'CoreHome';
import { Field, Form, SaveButton } from 'CorePluginsAdmin';
import { adjustHourToTimezone } from '../utilities';

interface Option {
  key: string;
  value: string;
}

const { $ } = window;

export default defineComponent({
  props: {
    report: {
      type: Object,
      required: true,
    },
    selectedReports: Object,
    paramPeriods: {
      type: Object,
      required: true,
    },
    reportTypeOptions: {
      type: Object,
      required: true,
    },
    reportFormatsByReportTypeOptions: {
      type: Object,
      required: true,
    },
    displayFormats: {
      type: Object,
      required: true,
    },
    reportsByCategoryByReportType: {
      type: Object,
      required: true,
    },
    allowMultipleReportsByReportType: {
      type: Object,
      required: true,
    },
    countWebsites: {
      type: Number,
      required: true,
    },
    siteName: {
      type: String,
      required: true,
    },
    reportTypes: {
      type: Object,
      required: true,
    },
    segmentEditorActivated: Boolean,
    savedSegmentsById: Object,
    periods: {
      type: Object,
      required: true,
    },
  },
  emits: ['submit', 'change', 'toggleSelectedReport'],
  components: {
    ContentBlock,
    Field,
    SaveButton,
  },
  directives: {
    Form,
  },
  created() {
    this.onEvolutionPeriodN = debounce(this.onEvolutionPeriodN, 50);
  },
  methods: {
    onEvolutionPeriodN(event: Event) {
      this.$emit('change', {
        prop: 'evolutionPeriodN',
        value: (event.target as HTMLInputElement).value,
      });
    },
    decode(s: string) {
      // report names can be encoded (mainly goals)
      return Matomo.helper.htmlDecode(s);
    },
  },
  setup(props, ctx) {
    const reportParameters = ref<HTMLElement|null>(null);

    watch(() => props.report, (newValue) => {
      const reportParametersElement = reportParameters.value as HTMLElement;
      reportParametersElement.querySelectorAll('[vue-entry]').forEach((node) => {
        // eslint-disable-next-line no-underscore-dangle
        $(node).data('vueAppInstance').report_ = newValue;
      });
    });

    onMounted(() => {
      const reportParametersElement = reportParameters.value as HTMLElement;
      Matomo.helper.compileVueEntryComponents(reportParametersElement, {
        report: props.report,
        onChange(prop: string, value: unknown) {
          ctx.emit('change', { prop, value });
        },
      });
    });

    return {
      reportParameters,
    };
  },
  beforeUnmount() {
    const reportParameters = this.$refs.reportParameters as HTMLElement;
    Matomo.helper.destroyVueComponent(reportParameters);
  },
  computed: {
    reportsByCategoryByReportTypeInColumns() {
      const reportsByCategoryByReportType = this.reportsByCategoryByReportType as
        Record<string, Record<string, unknown[]>>;

      const inColumns = Object.entries(reportsByCategoryByReportType).map(
        ([key, reportsByCategory]) => {
          const newColumnAfter = Math.floor((Object.keys(reportsByCategory).length + 1) / 2);

          const column1: Record<string, unknown[]> = {};
          const column2: Record<string, unknown[]> = {};

          let currentColumn = column1;
          Object.entries(reportsByCategory).forEach(([category, reports]) => {
            currentColumn[category] = reports;

            if (Object.keys(currentColumn).length >= newColumnAfter) {
              currentColumn = column2;
            }
          });

          return [key, [column1, column2]];
        },
      );

      return Object.fromEntries(inColumns);
    },
    entityCancelText() {
      return translate(
        'General_OrCancel',
        '<a class="entityCancelLink">',
        '</a>',
      );
    },
    frequencyPeriodSingle() {
      if (!this.report || !this.report.period) {
        return '';
      }

      const { ReportPlugin } = window;

      let translation = ReportPlugin.periodTranslations[this.report.period];
      if (!translation) {
        translation = ReportPlugin.periodTranslations.day;
      }
      return translation.single;
    },
    frequencyPeriodPlural() {
      if (!this.report || !this.report.period) {
        return '';
      }

      const { ReportPlugin } = window;

      let translation = ReportPlugin.periodTranslations[this.report.period];
      if (!translation) {
        translation = ReportPlugin.periodTranslations.day;
      }
      return translation.plural;
    },
    evolutionGraphsShowForEachInPeriod() {
      return translate(
        'ScheduledReports_EvolutionGraphsShowForEachInPeriod',
        '<strong>',
        '</strong>',
        this.frequencyPeriodSingle,
      );
    },
    reportSegmentInlineHelp() {
      return translate(
        'ScheduledReports_Segment_Help',
        '<a href="./" rel="noreferrer noopener" target="_blank">',
        '</a>',
        translate('SegmentEditor_DefaultAllVisits'),
        translate('SegmentEditor_AddNewSegment'),
      );
    },
    timezoneOffset() {
      return Matomo.timezoneOffset;
    },
    timeZoneDifferenceInHours() {
      return Matomo.timezoneOffset / 3600;
    },
    reportHours() {
      const hours: Option[] = [];
      for (let i = 0; i < 24; i += 1) {
        if ((this.timeZoneDifferenceInHours * 2) % 2 !== 0) {
          hours.push({
            key: `${i}.5`,
            value: `${i}:30`,
          });
        } else {
          hours.push({
            key: `${i}`,
            value: `${i}`,
          });
        }
      }
      return hours;
    },
    reportHourUtc() {
      const reportHour = adjustHourToTimezone(
        this.report.hour as string,
        -this.timeZoneDifferenceInHours,
      );
      return translate('ScheduledReports_ReportHourWithUTC', [reportHour]);
    },
    saveButtonTitle() {
      const { ReportPlugin } = window;

      const isEditing = this.report.idreport > 0;
      return isEditing ? ReportPlugin.updateReportString : ReportPlugin.createReportString;
    },
    contentTitle() {
      const { ReportPlugin } = window;

      const isEditing = this.report.idreport > 0;
      return isEditing ? ReportPlugin.updateReportString : translate('ScheduledReports_CreateAndScheduleReport');
    },
  },
});
</script>