Files
My-KOPKB/fe/src/modules/external-system/pages/ExternalSystemList.vue
T
ismailmasseran b05e074456 Feature/phone register (#11)
Co-authored-by: ISMAIL MASSERAN <topaz@ISMAILs-Macbook.local>
Co-authored-by: ISMAIL MASSERAN <topaz@Mac.dlinkrouter.local>
Reviewed-on: #11
2026-07-14 12:03:22 +08:00

112 lines
4.3 KiB
Vue

<script lang="ts" setup>
import { useRouter } from 'vue-router'
import { AlertRoot, AlertTitle, AlertDescription } from '@/components/ui/alert'
import { Badge } from '@/components/ui/badge'
import { Box } from '@/components/ui/box'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Lucide } from '@/components/ui/lucide'
import { useExternalSystemList } from '../composables/useExternalSystemList'
import { useExternalSystemLaunch } from '../composables/useExternalSystemLaunch'
import {
externalSystemStatusLabel,
externalSystemStatusVariant,
formatExternalSystemDateTime,
getExternalSystemStatus,
} from '../utils/external-system.utils'
import type { ExternalSystem } from '../types/external-system.types'
const router = useRouter()
const { systems, search, loading, error, availableCount } = useExternalSystemList()
const { launching, launchExternalSystem } = useExternalSystemLaunch()
function goToDetail(system: ExternalSystem) {
router.push({ name: 'view-external-system', params: { id: system.id } })
}
function handleOpen(system: ExternalSystem) {
launchExternalSystem(system)
}
</script>
<template>
<div>
<div class="flex flex-wrap items-start justify-between gap-4">
<div>
<h2 class="text-lg font-medium">Sistem Luaran</h2>
</div>
<Badge look="outline" variant="primary">
{{ availableCount }} tersedia
</Badge>
</div>
<AlertRoot v-if="error" class="mb-6" variant="danger">
<AlertTitle>Ralat</AlertTitle>
<AlertDescription>{{ error }}</AlertDescription>
</AlertRoot>
<div class="mt-5 grid grid-cols-12 gap-x-6 gap-y-8">
<div class="col-span-12 mt-2 flex flex-wrap items-center sm:flex-nowrap">
<div class="w-full sm:w-auto">
<div class="relative w-56">
<Input v-model="search" class="w-56 pr-10" type="search" placeholder="Cari sistem..." :disabled="loading" />
<Lucide class="absolute inset-y-0 right-0 my-auto mr-3 h-4 w-4" icon="Search" />
</div>
</div>
</div>
<template v-if="systems.length">
<Box v-for="system in systems" :key="system.id"
class="col-span-12 flex h-full flex-col p-5 md:col-span-6 xl:col-span-4">
<div class="mb-4 flex items-start justify-between gap-3">
<div class="flex size-10 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary">
<Lucide :icon="system.icon" class="size-5" />
</div>
<Badge look="outline" :variant="externalSystemStatusVariant(getExternalSystemStatus(system))">
{{ externalSystemStatusLabel(getExternalSystemStatus(system)) }}
</Badge>
</div>
<div class="text-base font-medium">{{ system.name }}</div>
<div class="mt-1 text-xs font-medium uppercase tracking-wide text-primary/80">
{{ system.code }}
</div>
<p class="mt-2 flex-1 text-sm leading-relaxed opacity-70">
{{ system.description }}
</p>
<div class="mt-4 space-y-1 text-xs opacity-70">
<div>
<span class="font-medium">Mula:</span>
{{ formatExternalSystemDateTime(system.starts_at) }}
</div>
<div>
<span class="font-medium">Tamat:</span>
{{ formatExternalSystemDateTime(system.ends_at) }}
</div>
</div>
<div class="mt-5 flex flex-col gap-2 sm:flex-row">
<Button class="w-full sm:flex-1" look="outline" variant="primary"
:disabled="getExternalSystemStatus(system) !== 'available' || launching"
@click="handleOpen(system)">
Buka Sistem
<Lucide icon="ExternalLink" class="size-4" />
</Button>
<Button class="w-full sm:flex-1" variant="ghost" @click="goToDetail(system)">
Butiran
<Lucide icon="ArrowRight" class="size-4" />
</Button>
</div>
</Box>
</template>
<Box v-else-if="!loading" class="col-span-12 p-8 text-center">
<Lucide icon="SearchX" class="mx-auto size-8 opacity-40" />
<div class="mt-3 text-base font-medium">Tiada sistem dijumpai</div>
<p class="mt-1 text-sm opacity-70">Cuba istilah carian yang berbeza.</p>
</Box>
</div>
</div>
</template>