File "BaseCustomerSelectPopup.vue"

Full Path: /home/pulsehostuk9/public_html/invoicer.pulsehost.co.uk/resources/scripts/components/base/BaseCustomerSelectPopup.vue
File size: 14.7 KB
MIME-type: text/plain
Charset: utf-8

<template>
  <BaseContentPlaceholders v-if="contentLoading">
    <BaseContentPlaceholdersBox
      :rounded="true"
      class="w-full"
      style="min-height: 170px"
    />
  </BaseContentPlaceholders>

  <div v-else class="max-h-[173px]">
    <CustomerModal />
    <!-- <SalesTax :type="type" /> -->

    <div
      v-if="selectedCustomer"
      class="
        flex flex-col
        p-4
        bg-white
        border border-gray-200 border-solid
        min-h-[170px]
        rounded-md
      "
      @click.stop
    >
      <div class="flex relative justify-between mb-2">
        <BaseText
          :text="selectedCustomer.name"
          class="flex-1 text-base font-medium text-left text-gray-900"
        />
        <div class="flex">
          <a
            class="
              relative
              my-0
              ml-6
              text-sm
              font-medium
              cursor-pointer
              text-primary-500
              items-center
              flex
            "
            @click.stop="editCustomer"
          >
            <BaseIcon name="PencilIcon" class="text-gray-500 h-4 w-4 mr-1" />

            {{ $t('general.edit') }}
          </a>
          <a
            class="
              relative
              my-0
              ml-6
              text-sm
              flex
              items-center
              font-medium
              cursor-pointer
              text-primary-500
            "
            @click="resetSelectedCustomer"
          >
            <BaseIcon name="XCircleIcon" class="text-gray-500 h-4 w-4 mr-1" />
            {{ $t('general.deselect') }}
          </a>
        </div>
      </div>
      <div class="grid grid-cols-2 gap-8 mt-2">
        <div v-if="selectedCustomer.billing" class="flex flex-col">
          <label
            class="
              mb-1
              text-sm
              font-medium
              text-left text-gray-400
              uppercase
              whitespace-nowrap
            "
          >
            {{ $t('general.bill_to') }}
          </label>

          <div
            v-if="selectedCustomer.billing"
            class="flex flex-col flex-1 p-0 text-left"
          >
            <label
              v-if="selectedCustomer.billing.name"
              class="relative w-11/12 text-sm truncate"
            >
              {{ selectedCustomer.billing.name }}
            </label>

            <label class="relative w-11/12 text-sm truncate">
              <span v-if="selectedCustomer.billing.city">
                {{ selectedCustomer.billing.city }}
              </span>
              <span
                v-if="
                  selectedCustomer.billing.city &&
                  selectedCustomer.billing.state
                "
              >
                ,
              </span>
              <span v-if="selectedCustomer.billing.state">
                {{ selectedCustomer.billing.state }}
              </span>
            </label>
            <label
              v-if="selectedCustomer.billing.zip"
              class="relative w-11/12 text-sm truncate"
            >
              {{ selectedCustomer.billing.zip }}
            </label>
          </div>
        </div>

        <div v-if="selectedCustomer.shipping" class="flex flex-col">
          <label
            class="
              mb-1
              text-sm
              font-medium
              text-left text-gray-400
              uppercase
              whitespace-nowrap
            "
          >
            {{ $t('general.ship_to') }}
          </label>

          <div
            v-if="selectedCustomer.shipping"
            class="flex flex-col flex-1 p-0 text-left"
          >
            <label
              v-if="selectedCustomer.shipping.name"
              class="relative w-11/12 text-sm truncate"
            >
              {{ selectedCustomer.shipping.name }}
            </label>

            <label class="relative w-11/12 text-sm truncate">
              <span v-if="selectedCustomer.shipping.city">
                {{ selectedCustomer.shipping.city }}
              </span>
              <span
                v-if="
                  selectedCustomer.shipping.city &&
                  selectedCustomer.shipping.state
                "
              >
                ,
              </span>
              <span v-if="selectedCustomer.shipping.state">
                {{ selectedCustomer.shipping.state }}
              </span>
            </label>
            <label
              v-if="selectedCustomer.shipping.zip"
              class="relative w-11/12 text-sm truncate"
            >
              {{ selectedCustomer.shipping.zip }}
            </label>
          </div>
        </div>
      </div>
    </div>

    <Popover v-else v-slot="{ open }" class="relative flex flex-col rounded-md">
      <PopoverButton
        :class="{
          'text-opacity-90': open,
          'border border-solid border-red-500 focus:ring-red-500 rounded':
            valid.$error,
          'focus:ring-2 focus:ring-primary-400': !valid.$error,
        }"
        class="w-full outline-none rounded-md"
      >
        <div
          class="
            relative
            flex
            justify-center
            px-0
            p-0
            py-16
            bg-white
            border border-gray-200 border-solid
            rounded-md
            min-h-[170px]
          "
        >
          <BaseIcon
            name="UserIcon"
            class="
              flex
              justify-center
              !w-10
              !h-10
              p-2
              mr-5
              text-sm text-white
              bg-gray-200
              rounded-full
              font-base
            "
          />

          <div class="mt-1">
            <label class="text-lg font-medium text-gray-900">
              {{ $t('customers.new_customer') }}
              <span class="text-red-500"> * </span>
            </label>

            <p
              v-if="valid.$error && valid.$errors[0].$message"
              class="text-red-500 text-sm absolute right-3 bottom-3"
            >
              {{ $t('estimates.errors.required') }}
            </p>
          </div>
        </div>
      </PopoverButton>

      <!-- Customer Select Popup -->
      <transition
        enter-active-class="transition duration-200 ease-out"
        enter-from-class="translate-y-1 opacity-0"
        enter-to-class="translate-y-0 opacity-100"
        leave-active-class="transition duration-150 ease-in"
        leave-from-class="translate-y-0 opacity-100"
        leave-to-class="translate-y-1 opacity-0"
      >
        <div v-if="open" class="absolute min-w-full z-10">
          <PopoverPanel
            v-slot="{ close }"
            focus
            static
            class="
              overflow-hidden
              rounded-md
              shadow-lg
              ring-1 ring-black ring-opacity-5
              bg-white
            "
          >
            <div class="relative">
              <BaseInput
                v-model="search"
                container-class="m-4"
                :placeholder="$t('general.search')"
                type="text"
                icon="search"
                @update:modelValue="(val) => debounceSearchCustomer(val)"
              />

              <ul
                class="
                  max-h-80
                  flex flex-col
                  overflow-auto
                  list
                  border-t border-gray-200
                "
              >
                <li
                  v-for="(customer, index) in customerStore.customers"
                  :key="index"
                  href="#"
                  class="
                    flex
                    px-6
                    py-2
                    border-b border-gray-200 border-solid
                    cursor-pointer
                    hover:cursor-pointer hover:bg-gray-100
                    focus:outline-none focus:bg-gray-100
                    last:border-b-0
                  "
                  @click="selectNewCustomer(customer.id, close)"
                >
                  <span
                    class="
                      flex
                      items-center
                      content-center
                      justify-center
                      w-10
                      h-10
                      mr-4
                      text-xl
                      font-semibold
                      leading-9
                      text-white
                      bg-gray-300
                      rounded-full
                      avatar
                    "
                  >
                    {{ initGenerator(customer.name) }}
                  </span>

                  <div class="flex flex-col justify-center text-left">
                    <BaseText
                      v-if="customer.name"
                      :text="customer.name"
                      class="
                        m-0
                        text-base
                        font-normal
                        leading-tight
                        cursor-pointer
                      "
                    />
                    <BaseText
                      v-if="customer.contact_name"
                      :text="customer.contact_name"
                      class="
                        m-0
                        text-sm
                        font-medium
                        text-gray-400
                        cursor-pointer
                      "
                    />
                  </div>
                </li>
                <div
                  v-if="customerStore.customers.length === 0"
                  class="flex justify-center p-5 text-gray-400"
                >
                  <label class="text-base text-gray-500 cursor-pointer">
                    {{ $t('customers.no_customers_found') }}
                  </label>
                </div>
              </ul>
            </div>

            <button
              v-if="userStore.hasAbilities(abilities.CREATE_CUSTOMER)"
              type="button"
              class="
                h-10
                flex
                items-center
                justify-center
                w-full
                px-2
                py-3
                bg-gray-200
                border-none
                outline-none
                focus:bg-gray-300
              "
              @click="openCustomerModal"
            >
              <BaseIcon name="UserAddIcon" class="text-primary-400" />

              <label
                class="
                  m-0
                  ml-3
                  text-sm
                  leading-none
                  cursor-pointer
                  font-base
                  text-primary-400
                "
              >
                {{ $t('customers.add_new_customer') }}
              </label>
            </button>
          </PopoverPanel>
        </div>
      </transition>
    </Popover>
  </div>
</template>

<script setup>
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'
import { useEstimateStore } from '@/scripts/admin/stores/estimate'
import { useInvoiceStore } from '@/scripts/admin/stores/invoice'
import { useRecurringInvoiceStore } from '@/scripts/admin/stores/recurring-invoice'
import { useModalStore } from '@/scripts/stores/modal'
import { useGlobalStore } from '@/scripts/admin/stores/global'
import { useCustomerStore } from '@/scripts/admin/stores/customer'
import { computed, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useDebounceFn } from '@vueuse/core'
import { useUserStore } from '@/scripts/admin/stores/user'
import abilities from '@/scripts/admin/stub/abilities'
import { useRoute } from 'vue-router'
import CustomerModal from '@/scripts/admin/components/modal-components/CustomerModal.vue'

const props = defineProps({
  valid: {
    type: Object,
    default: () => {},
  },
  customerId: {
    type: Number,
    default: null,
  },
  type: {
    type: String,
    default: null,
  },
  contentLoading: {
    type: Boolean,
    default: false,
  },
})

const modalStore = useModalStore()
const estimateStore = useEstimateStore()
const customerStore = useCustomerStore()
const globalStore = useGlobalStore()
const invoiceStore = useInvoiceStore()
const recurringInvoiceStore = useRecurringInvoiceStore()
const userStore = useUserStore()
const routes = useRoute()
const { t } = useI18n()
const search = ref(null)
const isSearchingCustomer = ref(false)

const selectedCustomer = computed(() => {
  switch (props.type) {
    case 'estimate':
      return estimateStore.newEstimate.customer
    case 'invoice':
      return invoiceStore.newInvoice.customer
    case 'recurring-invoice':
      return recurringInvoiceStore.newRecurringInvoice.customer
    default:
      return ''
  }
})

function resetSelectedCustomer() {
  if (props.type === 'estimate') {
    estimateStore.resetSelectedCustomer()
  } else if (props.type === 'invoice') {
    invoiceStore.resetSelectedCustomer()
  } else {
    recurringInvoiceStore.resetSelectedCustomer()
  }
}

if (props.customerId && props.type === 'estimate') {
  estimateStore.selectCustomer(props.customerId)
} else if (props.customerId && props.type === 'invoice') {
  invoiceStore.selectCustomer(props.customerId)
} else {
  if (props.customerId) recurringInvoiceStore.selectCustomer(props.customerId)
}

async function editCustomer() {
  await customerStore.fetchCustomer(selectedCustomer.value.id)
  modalStore.openModal({
    title: t('customers.edit_customer'),
    componentName: 'CustomerModal',
  })
}

async function fetchInitialCustomers() {
  await customerStore.fetchCustomers({
    filter: {},
    orderByField: '',
    orderBy: '',
    customer_id: props.customerId,
  })
}

const debounceSearchCustomer = useDebounceFn(() => {
  isSearchingCustomer.value = true

  searchCustomer()
}, 500)

async function searchCustomer() {
  let data = {
    display_name: search.value,
    page: 1,
  }

  await customerStore.fetchCustomers(data)
  isSearchingCustomer.value = false
}

function openCustomerModal() {
  modalStore.openModal({
    title: t('customers.add_customer'),
    componentName: 'CustomerModal',
    variant: 'md',
  })
}

function initGenerator(name) {
  if (name) {
    let nameSplit = name.split(' ')
    let initials = nameSplit[0].charAt(0).toUpperCase()
    return initials
  }
}

function selectNewCustomer(id, close) {
  let params = {
    userId: id,
  }
  if (routes.params.id) params.model_id = routes.params.id

  if (props.type === 'estimate') {
    estimateStore.getNextNumber(params, true)
    estimateStore.selectCustomer(id)
  } else if (props.type === 'invoice') {
    invoiceStore.getNextNumber(params, true)
    invoiceStore.selectCustomer(id)
  } else {
    recurringInvoiceStore.selectCustomer(id)
  }
  close()
  search.value = null
}

globalStore.fetchCurrencies()
globalStore.fetchCountries()
fetchInitialCustomers()
</script>