Untitled

 avatar
unknown
plain_text
10 months ago
16 kB
16
Indexable
<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import {
  DocumentIcon,
  CalendarIcon,
  EyeIcon,
  PencilSquareIcon,
  MapPinIcon,
} from '@heroicons/vue/24/outline'
import Pagination from '@/components/ui/pagination/Pagination.vue'
import DocumentTimelineTracker from '@/components/Dashboard/TimelineTracker/DocumentTimelineTracker.vue'
import EditdocumentDrawer from '@/components/Dashboard/IncomingDocuments/IncomingDocument(ForEdit)/EditDocumentDrawer.vue'
import { useAuthStore } from '@/components/store/authStore'
import apiClient from '@/services/api'

// Component state
const allDocuments = ref([])
const currentPage = ref(1)
const itemsPerPage = ref(10)
const totalItems = ref(0)
const isTimelineOpen = ref(false)
const selectedDocumentId = ref<number | null>(null)
const selectedDocumentNo = ref<string | null>(null)
const isLoading = ref(true)

// State for managing the edit drawer
const isEditDrawerOpen = ref(false)
const documentToEdit = ref(null)

// Auth store and permissions
const authStore = useAuthStore()
const isGuest = computed(() => authStore.user.value?.role === 'guest')

// šŸ”§ NEW: Helper function to format referred office array
const formatReferredOffice = (referredOffice: any) => {
  if (!referredOffice) return '—'
  
  // If it's already a string and looks clean, return it
  if (typeof referredOffice === 'string' && !referredOffice.includes('[') && !referredOffice.includes('"')) {
    return referredOffice
  }
  
  let offices = []
  
  try {
    // If it's a string that looks like JSON, parse it
    if (typeof referredOffice === 'string') {
      if (referredOffice.startsWith('[') && referredOffice.endsWith(']')) {
        offices = JSON.parse(referredOffice)
      } else {
        // Handle comma-separated values
        offices = referredOffice.split(',').map(item => item.trim())
      }
    } else if (Array.isArray(referredOffice)) {
      offices = referredOffice
    }
    
    // Filter out empty values and join with commas
    const cleanOffices = offices.filter(office => office && office.trim() !== '')
    return cleanOffices.length > 0 ? cleanOffices.join(', ') : '—'
    
  } catch (error) {
    console.warn('Error parsing referred office:', error)
    return referredOffice || '—'
  }
}

// Data fetching
const fetchAllDocuments = async () => {
  try {
    isLoading.value = true
    const response = await apiClient.get('/dms/documents', {
      params: {
        page: currentPage.value,
        per_page: itemsPerPage.value,
        sort_by: 'created_at',
        sort_order: 'desc',
      },
    })

    allDocuments.value = response.data.data
    totalItems.value = response.data.total
    currentPage.value = response.data.current_page
  } catch (error) {
    console.error('Failed to fetch documents:', error)
  } finally {
    isLoading.value = false
  }
}

// Watch for page changes to refetch data
watch([currentPage, itemsPerPage], () => {
  fetchAllDocuments()
})

onMounted(() => {
  fetchAllDocuments()
})

// Function to open the edit drawer and set the selected document
const openEditDrawer = (doc: any) => {
  documentToEdit.value = doc
  isEditDrawerOpen.value = true
}

// Function to close the edit drawer and refresh the document list
const closeEditDrawer = () => {
  isEditDrawerOpen.value = false
  documentToEdit.value = null
  fetchAllDocuments()
}

// Timeline actions
const openTimeline = (documentId: number, documentNo: string) => {
  selectedDocumentId.value = documentId
  selectedDocumentNo.value = documentNo
  isTimelineOpen.value = true
}

const closeTimeline = () => {
  isTimelineOpen.value = false
  selectedDocumentId.value = null
  selectedDocumentNo.value = null
}

// Pagination logic
const handlePageChange = (page: number) => {
  currentPage.value = page
}

const handleItemsPerPageChange = (items: number) => {
  itemsPerPage.value = items
  currentPage.value = 1
}
</script>

<template>
  <div class="bg-white rounded-lg shadow p-4 md:p-6 font-sans">
    <div
      class="flex flex-col sm:flex-row sm:items-center justify-between mb-4 md:mb-6"
    >
      <h2 class="text-lg md:text-xl font-medium text-gray-900 mb-2 sm:mb-0">
        Incoming Documents
      </h2>
    </div>

    <div v-if="isLoading">
      <div class="hidden lg:block overflow-x-auto rounded-lg">
        <table class="min-w-full divide-y divide-gray-200">
          <thead class="bg-gray-50">
            <tr>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider rounded-tl-lg"
              >
                Document No.
              </th>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider"
              >
                Subject
              </th>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider"
              >
                Document Deadline
              </th>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider"
              >
                ARTA Deadline
              </th>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider"
              >
                Referred To
              </th>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider rounded-tr-lg"
              >
                Actions
              </th>
            </tr>
          </thead>
          <tbody class="bg-white divide-y divide-gray-100 animate-pulse">
            <tr v-for="n in 5" :key="n" class="hover:bg-gray-50 transition-colors">
              <td class="px-4 py-3 whitespace-nowrap text-sm text-center">
                <div class="h-4 bg-gray-200 rounded w-24 mx-auto"></div>
              </td>
              <td class="px-4 py-3 text-sm text-center max-w-xs">
                <div class="h-4 bg-gray-200 rounded w-32 mx-auto"></div>
              </td>
              <td class="px-4 py-3 text-sm text-center">
                <div class="h-4 bg-gray-200 rounded w-20 mx-auto"></div>
              </td>
              <td class="px-4 py-3 text-sm text-center">
                <div class="h-4 bg-gray-200 rounded w-20 mx-auto"></div>
              </td>
              <td class="px-4 py-3 text-sm text-center">
                <div class="h-4 bg-gray-200 rounded w-16 mx-auto"></div>
              </td>
              <td class="px-4 py-3 text-sm text-center">
                <div class="flex justify-center space-x-2">
                  <div class="w-8 h-8 bg-gray-200 rounded-full"></div>
                  <div class="w-8 h-8 bg-gray-200 rounded-full"></div>
                  <div class="w-8 h-8 bg-gray-200 rounded-full"></div>
                </div>
              </td>
            </tr>
          </tbody>
        </table>
      </div>

      <div class="block lg:hidden space-y-3">
        <div v-for="n in 5" :key="n"
          class="bg-white border border-gray-200 rounded-lg p-4 shadow-sm animate-pulse"
        >
          <div class="flex items-start justify-between mb-3">
            <div class="flex items-center space-x-2 min-w-0 flex-1">
              <div class="w-5 h-5 bg-gray-200 rounded-full"></div>
              <div class="min-w-0 flex-1">
                <div class="h-4 bg-gray-200 rounded w-24 mb-1"></div>
                <div class="h-3 bg-gray-200 rounded w-16"></div>
              </div>
            </div>
            <div class="h-4 bg-gray-200 rounded w-12"></div>
          </div>
          <div class="mb-3">
            <div class="h-4 bg-gray-200 rounded w-20 mb-1"></div>
            <div class="h-4 bg-gray-200 rounded w-full"></div>
          </div>
          <div class="flex justify-end space-x-2 pt-3 border-t border-gray-100">
            <div class="w-8 h-8 bg-gray-200 rounded-full"></div>
            <div class="w-8 h-8 bg-gray-200 rounded-full"></div>
            <div class="w-8 h-8 bg-gray-200 rounded-full"></div>
          </div>
        </div>
      </div>
    </div>

    <div v-else>
      <div class="hidden lg:block overflow-x-auto rounded-lg">
        <table class="min-w-full divide-y divide-gray-200">
          <thead class="bg-gray-50">
            <tr>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider rounded-tl-lg"
              >
                Document No.
              </th>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider"
              >
                Subject
              </th>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider"
              >
                Document Deadline
              </th>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider"
              >
                ARTA Deadline
              </th>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider"
              >
                Referred To
              </th>
              <th
                class="px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider rounded-tr-lg"
              >
                Actions
              </th>
            </tr>
          </thead>
          <tbody class="bg-white divide-y divide-gray-100">
            <tr
              v-for="doc in allDocuments"
              :key="doc.incoming_initial_id"
              class="hover:bg-gray-50 transition-colors"
            >
              <td
                class="px-4 py-3 whitespace-nowrap text-sm text-gray-700 text-center"
              >
                <span class="inline-flex items-center">
                  <DocumentIcon class="w-4 h-4 mr-1 text-gray-400" />
                  {{ doc.document_no }}
                </span>
              </td>
              <td
                class="px-4 py-3 text-sm text-gray-700 text-center max-w-xs"
              >
                <div class="truncate" :title="doc.subject">{{ doc.subject }}</div>
              </td>
              <td class="px-4 py-3 text-sm text-gray-700 text-center">
                <span v-if="doc.document_deadline" class="inline-flex items-center">
                  <CalendarIcon class="w-4 h-4 mr-1 text-gray-400" />
                  {{ doc.document_deadline }}
                </span>
                <span v-else>—</span>
              </td>
              <td class="px-4 py-3 text-sm text-gray-700 text-center">
                <span v-if="doc.arta_deadline" class="inline-flex items-center">
                  <CalendarIcon class="w-4 h-4 mr-1 text-gray-400" />
                  {{ doc.arta_deadline }}
                </span>
                <span v-else>—</span>
              </td>
              <!-- šŸ”§ FIXED: Use the helper function to format referred office -->
              <td class="px-4 py-3 text-sm text-gray-700 text-center">
{{ formatReferredOffice(doc.current_office) }}
              </td>
              <td class="px-4 py-3 text-sm text-center">
                <div class="flex justify-center space-x-2">
                  <button
                    class="text-gray-500 hover:text-blue-600 p-2 rounded-full hover:bg-gray-100 transition-colors duration-200"
                    title="View"
                  >
                    <EyeIcon class="w-5 h-5" />
                  </button>
                  <button
                    :disabled="isGuest"
                    :class="{
                      'text-gray-500 hover:text-blue-600 p-2 rounded-full hover:bg-gray-100 transition-colors duration-200':
                        !isGuest,
                      'opacity-50 cursor-not-allowed': isGuest,
                    }"
                    title="Edit Document"
                    @click="openEditDrawer(doc)"
                  >
                    <PencilSquareIcon class="w-5 h-5" />
                  </button>
                  <button
                    class="text-red-500 hover:text-red-600 p-2 rounded-full hover:bg-gray-100 transition-colors duration-200"
                    title="Track Location"
                    @click="openTimeline(doc.incoming_initial_id, doc.document_no)"
                  >
                    <MapPinIcon class="w-5 h-5" />
                  </button>
                </div>
              </td>
            </tr>
          </tbody>
        </table>
      </div>

      <div class="block lg:hidden space-y-3">
        <div
          v-for="doc in allDocuments"
          :key="doc.incoming_initial_id"
          class="bg-white border border-gray-200 rounded-lg p-4 shadow-sm hover:shadow-md transition-shadow duration-200"
        >
          <div class="flex items-start justify-between mb-3">
            <div class="flex items-center space-x-2 min-w-0 flex-1">
              <DocumentIcon class="w-5 h-5 text-gray-400 flex-shrink-0" />
              <div class="min-w-0 flex-1">
                <div class="text-sm font-semibold text-gray-900">
                  {{ doc.document_no }}
                </div>
                <div class="text-xs text-gray-500">Document Number</div>
              </div>
            </div>
            <!-- šŸ”§ FIXED: Use the helper function for mobile view too -->
            <span class="text-xs font-semibold text-gray-800">
              {{ formatReferredOffice(doc.referred_office) }}
            </span>
          </div>

          <div class="mb-3">
            <div class="text-sm font-medium text-gray-700 mb-1">Subject</div>
            <div class="text-sm text-gray-600 leading-relaxed">
              {{ doc.subject }}
            </div>
          </div>

          <div class="flex justify-end space-x-2 pt-3 border-t border-gray-100">
            <button
              class="flex items-center justify-center text-gray-500 hover:text-blue-600 p-3 rounded-lg hover:bg-blue-50 transition-all duration-200 min-w-[44px]"
              title="View Document"
            >
              <EyeIcon class="w-5 h-5" />
            </button>
            <button
              :disabled="isGuest"
              :class="{
                'flex items-center justify-center text-gray-500 hover:text-blue-600 p-3 rounded-lg hover:bg-blue-50 transition-all duration-200 min-w-[44px]':
                  !isGuest,
                'opacity-50 cursor-not-allowed': isGuest,
              }"
              title="Edit Document"
              @click="openEditDrawer(doc)"
            >
              <PencilSquareIcon class="w-5 h-5" />
            </button>
            <button
              class="flex items-center justify-center text-red-500 hover:text-red-600 p-3 rounded-lg hover:bg-red-50 transition-all duration-200 min-w-[44px]"
              title="Track Location"
              @click="openTimeline(doc.incoming_initial_id, doc.document_no)"
            >
              <MapPinIcon class="w-5 h-5" />
            </button>
          </div>
        </div>
      </div>

      <div class="mt-8 border-gray-200 pt-6 overflow-x-auto">
        <Pagination
          :total-items="totalItems"
          :initial-page="currentPage"
          :initial-items-per-page="itemsPerPage"
          @page-change="handlePageChange"
          @items-per-page-change="handleItemsPerPageChange"
        />
      </div>
    </div>

    <EditdocumentDrawer
      :is-open="isEditDrawerOpen"
      :document="documentToEdit"
      @close="closeEditDrawer"
    />

    <DocumentTimelineTracker
      :is-open="isTimelineOpen"
      :document-no="selectedDocumentNo"
      document-type="incoming"
      @close="closeTimeline"
    />
  </div>
</template>
Editor is loading...
Leave a Comment