File "PreferencesSetting-20250318162335.vue"

Full Path: /home/pulsehostuk9/public_html/invoicer.pulsehost.co.uk/resources/scripts/admin/views/settings/PreferencesSetting-20250318162335.vue
File size: 9.29 KB
MIME-type: text/plain
Charset: utf-8

<template>
  <form action="" class="relative" @submit.prevent="updatePreferencesData">
    <BaseSettingCard
      :title="$t('settings.menu_title.preferences')"
      :description="$t('settings.preferences.general_settings')"
    >
      <BaseInputGrid class="mt-5">
        <BaseInputGroup
          :content-loading="isFetchingInitialData"
          :label="$t('settings.preferences.currency')"
          :help-text="$t('settings.preferences.company_currency_unchangeable')"
          :error="v$.currency.$error && v$.currency.$errors[0].$message"
          required
        >
          <BaseMultiselect
            v-model="settingsForm.currency"
            :content-loading="isFetchingInitialData"
            :options="globalStore.currencies"
            label="name"
            value-prop="id"
            :searchable="true"
            track-by="name"
            :invalid="v$.currency.$error"
            disabled
            class="w-full"
          >
          </BaseMultiselect>
        </BaseInputGroup>

        <BaseInputGroup
          :label="$t('settings.preferences.default_language')"
          :content-loading="isFetchingInitialData"
          :error="v$.language.$error && v$.language.$errors[0].$message"
          required
        >
          <BaseMultiselect
            v-model="settingsForm.language"
            :content-loading="isFetchingInitialData"
            :options="globalStore.config.languages"
            label="name"
            value-prop="code"
            class="w-full"
            track-by="name"
            :searchable="true"
            :invalid="v$.language.$error"
          />
        </BaseInputGroup>

        <BaseInputGroup
          :label="$t('settings.preferences.time_zone')"
          :content-loading="isFetchingInitialData"
          :error="v$.time_zone.$error && v$.time_zone.$errors[0].$message"
          required
        >
          <BaseMultiselect
            v-model="settingsForm.time_zone"
            :content-loading="isFetchingInitialData"
            :options="globalStore.timeZones"
            label="key"
            value-prop="value"
            track-by="key"
            :searchable="true"
            :invalid="v$.time_zone.$error"
          />
        </BaseInputGroup>

        <BaseInputGroup
          :label="$t('settings.preferences.date_format')"
          :content-loading="isFetchingInitialData"
          :error="
            v$.carbon_date_format.$error &&
            v$.carbon_date_format.$errors[0].$message
          "
          required
        >
          <BaseMultiselect
            v-model="settingsForm.carbon_date_format"
            :content-loading="isFetchingInitialData"
            :options="globalStore.dateFormats"
            label="display_date"
            value-prop="carbon_format_value"
            track-by="display_date"
            searchable
            :invalid="v$.carbon_date_format.$error"
            class="w-full"
          />
        </BaseInputGroup>

        <BaseInputGroup
          :content-loading="isFetchingInitialData"
          :error="v$.fiscal_year.$error && v$.fiscal_year.$errors[0].$message"
          :label="$t('settings.preferences.fiscal_year')"
          required
        >
          <BaseMultiselect
            v-model="settingsForm.fiscal_year"
            :content-loading="isFetchingInitialData"
            :options="fiscalYearsList"
            label="key"
            value-prop="value"
            :invalid="v$.fiscal_year.$error"
            track-by="key"
            :searchable="true"
            class="w-full"
          />
        </BaseInputGroup>
      </BaseInputGrid>

      <BaseButton
        :content-loading="isFetchingInitialData"
        :disabled="isSaving"
        :loading="isSaving"
        type="submit"
        class="mt-6"
      >
        <template #left="slotProps">
          <BaseIcon name="SaveIcon" :class="slotProps.class" />
        </template>
        {{ $t('settings.company_info.save') }}
      </BaseButton>

      <BaseDivider class="mt-6 mb-2" />

      <ul>
        <form @submit.prevent="submitData">
          <BaseSwitchSection
            v-model="expirePdfField"
            :title="$t('settings.preferences.expire_public_links')"
            :description="$t('settings.preferences.expire_setting_description')"
          />

          <!--pdf_link_expiry_days -->
          <BaseInputGroup
            v-if="expirePdfField"
            :content-loading="isFetchingInitialData"
            :label="$t('settings.preferences.expire_public_links')"
            class="mt-2 mb-4"
          >
            <BaseInput
              v-model="settingsForm.link_expiry_days"
              :disabled="
                settingsForm.automatically_expire_public_links === 'NO'
              "
              :content-loading="isFetchingInitialData"
              type="number"
            />
          </BaseInputGroup>

          <BaseButton
            :content-loading="isFetchingInitialData"
            :disabled="isDataSaving"
            :loading="isDataSaving"
            type="submit"
            class="mt-6"
          >
            <template #left="slotProps">
              <BaseIcon name="SaveIcon" :class="slotProps.class" />
            </template>
            {{ $t('general.save') }}
          </BaseButton>
        </form>

        <BaseDivider class="mt-6 mb-2" />

        <BaseSwitchSection
          v-model="discountPerItemField"
          :title="$t('settings.preferences.discount_per_item')"
          :description="$t('settings.preferences.discount_setting_description')"
        />
      </ul>
    </BaseSettingCard>
  </form>
</template>

<script setup>
import { ref, computed, watch, reactive } from 'vue'
import { useGlobalStore } from '@/scripts/admin/stores/global'
import { useCompanyStore } from '@/scripts/admin/stores/company'
import { useI18n } from 'vue-i18n'
import { required, helpers } from '@vuelidate/validators'
import useVuelidate from '@vuelidate/core'

const companyStore = useCompanyStore()
const globalStore = useGlobalStore()
const { t, tm } = useI18n()

let isSaving = ref(false)
let isDataSaving = ref(false)
let isFetchingInitialData = ref(false)

const settingsForm = reactive({ ...companyStore.selectedCompanySettings })

const retrospectiveEditOptions = computed(() => {
  return globalStore.config.retrospective_edits.map((option) => {
    option.title = t(option.key)
    return option
  })
})

const fiscalYearsList = computed(() => {
  return globalStore.config.fiscal_years.map((item) => {
    return Object.assign({}, item, {
      key: t(item.key),
    })
  })
})

watch(
  () => settingsForm.carbon_date_format,
  (val) => {
    if (val) {
      const dateFormatObject = globalStore.dateFormats.find((d) => {
        return d.carbon_format_value === val
      })

      settingsForm.moment_date_format = dateFormatObject.moment_format_value
    }
  }
)

const discountPerItemField = computed({
  get: () => {
    return settingsForm.discount_per_item === 'YES'
  },
  set: async (newValue) => {
    const value = newValue ? 'YES' : 'NO'

    let data = {
      settings: {
        discount_per_item: value,
      },
    }

    settingsForm.discount_per_item = value

    await companyStore.updateCompanySettings({
      data,
      message: 'general.setting_updated',
    })
  },
})

const expirePdfField = computed({
  get: () => {
    return settingsForm.automatically_expire_public_links === 'YES'
  },
  set: async (newValue) => {
    const value = newValue ? 'YES' : 'NO'

    let data = {
      settings: {
        automatically_expire_public_links: value,
      },
    }

    settingsForm.automatically_expire_public_links = value
  },
})

const rules = computed(() => {
  return {
    currency: {
      required: helpers.withMessage(t('validation.required'), required),
    },
    language: {
      required: helpers.withMessage(t('validation.required'), required),
    },
    carbon_date_format: {
      required: helpers.withMessage(t('validation.required'), required),
    },
    moment_date_format: {
      required: helpers.withMessage(t('validation.required'), required),
    },
    time_zone: {
      required: helpers.withMessage(t('validation.required'), required),
    },
    fiscal_year: {
      required: helpers.withMessage(t('validation.required'), required),
    },
  }
})

const v$ = useVuelidate(
  rules,
  computed(() => settingsForm)
)

setInitialData()

async function setInitialData() {
  isFetchingInitialData.value = true
  Promise.all([
    globalStore.fetchCurrencies(),
    globalStore.fetchDateFormats(),
    globalStore.fetchTimeZones(),
  ]).then(([res1]) => {
    isFetchingInitialData.value = false
  })
}

async function updatePreferencesData() {
  v$.value.$touch()
  if (v$.value.$invalid) {
    return
  }

  let data = {
    settings: {
      ...settingsForm,
    },
  }

  isSaving.value = true
  delete data.settings.link_expiry_days
  let res = await companyStore.updateCompanySettings({
    data: data,
    message: 'settings.preferences.updated_message',
  })

  isSaving.value = false
}

async function submitData() {
  isDataSaving.value = true

  let res = await companyStore.updateCompanySettings({
    data: {
      settings: {
        link_expiry_days: settingsForm.link_expiry_days,
        automatically_expire_public_links:
          settingsForm.automatically_expire_public_links,
      },
    },
    message: 'settings.preferences.updated_message',
  })

  isDataSaving.value = false
}
</script>