File "GlobalSearchBar.vue"

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

<template>
  <div ref="searchBar" class="hidden rounded md:block relative">
    <div>
      <BaseInput
        v-model="name"
        :placeholder="$t('global_search.search')"
        container-class="!rounded"
        class="h-8 md:h-9 !rounded"
        @input="onSearch"
      >
        <template #left>
          <BaseIcon name="SearchIcon" class="text-gray-400" />
        </template>
        <template #right>
          <SpinnerIcon v-if="isSearching" class="h-5 text-primary-500" />
        </template>
      </BaseInput>
    </div>
    <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="isShow"
        class="
          scrollbar-thin
          scrollbar-thumb-rounded-full
          scrollbar-thumb-gray-300
          scrollbar-track-gray-100
          overflow-y-auto
          bg-white
          rounded-md
          mt-2
          shadow-lg
          p-3
          absolute
          w-[300px]
          h-[200px]
          right-0
        "
      >
        <div
          v-if="
            usersStore.userList.length < 1 && usersStore.customerList.length < 1
          "
          class="
            flex
            items-center
            justify-center
            text-gray-400 text-base
            flex-col
            mt-4
          "
        >
          <BaseIcon name="ExclamationCircleIcon" class="text-gray-400" />

          {{ $t('global_search.no_results_found') }}
        </div>
        <div v-else>
          <div v-if="usersStore.customerList.length > 0">
            <label class="text-sm text-gray-400 mb-0.5 block px-2 uppercase">
              {{ $t('global_search.customers') }}
            </label>
            <div
              v-for="(customer, index) in usersStore.customerList"
              :key="index"
              class="p-2 hover:bg-gray-100 cursor-pointer rounded-md"
            >
              <router-link
                :to="{ path: `/admin/customers/${customer.id}/view` }"
                class="flex items-center"
              >
                <span
                  class="
                    flex
                    items-center
                    justify-center
                    w-9
                    h-9
                    mr-3
                    text-base
                    font-semibold
                    bg-gray-200
                    rounded-full
                    text-primary-500
                  "
                >
                  {{ initGenerator(customer.name) }}
                </span>
                <div class="flex flex-col">
                  <span class="text-sm">{{ customer.name }}</span>
                  <span
                    v-if="customer.contact_name"
                    class="text-xs text-gray-400"
                  >
                    {{ customer.contact_name }}
                  </span>
                  <span v-else class="text-xs text-gray-400">{{
                    customer.email
                  }}</span>
                </div>
              </router-link>
            </div>
          </div>

          <div v-if="usersStore.userList.length > 0" class="mt-2">
            <label
              class="text-sm text-gray-400 mb-2 block px-2 mb-0.5 uppercase"
            >
              {{ $t('global_search.users') }}
            </label>
            <div
              v-for="(user, index) in usersStore.userList"
              :key="index"
              class="p-2 hover:bg-gray-100 cursor-pointer rounded-md"
            >
              <router-link
                :to="{ path: `/admin/users/${user.id}/edit` }"
                class="flex items-center"
              >
                <span
                  class="
                    flex
                    items-center
                    justify-center
                    w-9
                    h-9
                    mr-3
                    text-base
                    font-semibold
                    bg-gray-200
                    rounded-full
                    text-primary-500
                  "
                >
                  {{ initGenerator(user.name) }}
                </span>
                <div class="flex flex-col">
                  <span class="text-sm">{{ user.name }}</span>
                  <span class="text-xs text-gray-400">{{ user.email }}</span>
                </div>
              </router-link>
            </div>
          </div>
        </div>
      </div>
    </transition>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue'
import { useUsersStore } from '@/scripts/admin/stores/users'
import { onClickOutside } from '@vueuse/core'
import { useRoute } from 'vue-router'
import SpinnerIcon from '@/scripts/components/icons/SpinnerIcon.vue'
import { debounce } from 'lodash'

const usersStore = useUsersStore()

const isShow = ref(false)
const name = ref('')
const searchBar = ref(null)
const isSearching = ref(false)
const route = useRoute()

watch(route, () => {
  isShow.value = false
  name.value = ''
})

onSearch = debounce(onSearch, 500)

onClickOutside(searchBar, () => {
  isShow.value = false
  name.value = ''
})

function onSearch() {
  let data = {
    search: name.value,
  }

  if (name.value) {
    isSearching.value = true
    usersStore.searchUsers(data).then(() => {
      isShow.value = true
    })
    isSearching.value = false
  }
  if (name.value === '') {
    isShow.value = false
  }
}

function initGenerator(name) {
  if (name) {
    const nameSplit = name.split(' ')
    const initials = nameSplit[0].charAt(0).toUpperCase()
    return initials
  }
}
</script>