Files
nademitex_user/src/views/catalogs/CatalogListView.vue
T

210 lines
5.7 KiB
Vue

<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useCatalogStore } from '@/stores/catalog'
import PageHeader from '@/components/layout/PageHeader.vue'
import SearchField from '@/components/ui/SearchField.vue'
import EmptyState from '@/components/ui/EmptyState.vue'
import PageSkeleton from '@/components/ui/PageSkeleton.vue'
import IconCatalog from '@/components/icons/IconCatalog.vue'
const route = useRoute()
const router = useRouter()
const catalogStore = useCatalogStore()
const loading = ref(true)
const companyId = computed(() => route.params.companyId as string)
const company = computed(() => catalogStore.getCompany(companyId.value))
const search = ref('')
const catalogs = computed(() => catalogStore.fetchCatalogs(companyId.value, search.value))
async function load() {
loading.value = true
if (!catalogStore.getCompany(companyId.value)) {
await catalogStore.loadCompanies()
}
await catalogStore.loadCatalogs(companyId.value)
loading.value = false
}
onMounted(load)
watch(companyId, load)
function openCatalog(catalogId: string) {
router.push(`/companies/${companyId.value}/catalogs/${catalogId}/products`)
}
function getProductCount(catalogId: string) {
const catalog = catalogStore.getCatalog(catalogId)
if (catalog?.productCount != null) return catalog.productCount
return catalogStore.fetchProducts(catalogId).length
}
</script>
<template>
<!-- Mobile -->
<div class="page catalog-mobile-page mobile-only">
<PageHeader
:title="company?.name ?? 'کالیته‌ها'"
subtitle="کالیته مورد نظر را انتخاب کنید"
show-back
centered
@back="router.push('/')"
/>
<SearchField
v-model="search"
placeholder="جستجو بر اساس کد یا نام کالیته..."
class="catalog-page__search"
/>
<div class="page__scroll page__scroll--with-nav catalog-mobile-scroll">
<PageSkeleton v-if="loading" variant="cards" :rows="5" />
<div v-else-if="catalogs.length > 0" class="catalog-mobile-list">
<button
v-for="catalog in catalogs"
:key="catalog.id"
type="button"
class="catalog-card"
@click="openCatalog(catalog.id)"
>
<span class="catalog-card__icon"><IconCatalog :size="22" /></span>
<div class="catalog-card__info">
<h3>کالیته کد {{ catalog.code }}</h3>
<p>{{ catalog.name }}</p>
</div>
<span class="catalog-card__count">{{ getProductCount(catalog.id) }} محصول</span>
</button>
</div>
<EmptyState
v-else
:variant="search ? 'search' : 'catalogs'"
:message="search ? 'با این جستجو کالیته‌ای پیدا نشد' : 'برای این شرکت هنوز کالیته‌ای ثبت نشده است'"
/>
</div>
</div>
<!-- Desktop -->
<div class="desktop-page catalog-desktop-page desktop-only">
<header class="desktop-page__head">
<h1 class="desktop-page__title">{{ company?.name ?? 'کالیته‌ها' }}</h1>
<p class="desktop-page__subtitle">کالیته مورد نظر را انتخاب کنید</p>
</header>
<SearchField
v-model="search"
placeholder="جستجو بر اساس کد یا نام کالیته..."
class="catalog-page__search"
/>
<div v-if="catalogs.length > 0" class="desktop-grid-3">
<button
v-for="catalog in catalogs"
:key="catalog.id"
type="button"
class="catalog-card catalog-card--desktop"
@click="openCatalog(catalog.id)"
>
<span class="catalog-card__icon"><IconCatalog :size="24" /></span>
<div class="catalog-card__info">
<h3>کالیته کد {{ catalog.code }}</h3>
<p>{{ catalog.name }}</p>
</div>
<span class="catalog-card__count">{{ getProductCount(catalog.id) }} محصول</span>
</button>
</div>
<EmptyState
v-else
:variant="search ? 'search' : 'catalogs'"
:message="search ? 'با این جستجو کالیته‌ای پیدا نشد' : 'برای این شرکت هنوز کالیته‌ای ثبت نشده است'"
/>
</div>
</template>
<style scoped>
.catalog-mobile-page {
background: var(--color-bg);
color: var(--color-text);
padding: 12px 0 0;
}
.catalog-page__search {
margin-bottom: 16px;
}
.catalog-mobile-scroll {
display: flex;
flex-direction: column;
flex: 1;
min-height: 0;
}
.catalog-mobile-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.catalog-card {
display: flex;
align-items: center;
gap: 12px;
width: 100%;
padding: 14px 16px;
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
background: var(--color-elevated);
box-shadow: var(--shadow-sm);
color: var(--color-text);
text-align: right;
cursor: pointer;
}
.catalog-card--desktop {
flex-direction: column;
align-items: flex-start;
min-height: 140px;
padding: 20px;
}
.catalog-card:hover {
border-color: var(--color-primary);
box-shadow: var(--shadow-md);
}
.catalog-card__icon {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
background: var(--color-primary-light);
border-radius: var(--radius-sm);
color: var(--color-primary);
}
.catalog-card__info {
flex: 1;
}
.catalog-card__info h3 {
margin: 0 0 4px;
font-size: 0.9375rem;
color: var(--color-text);
}
.catalog-card__info p {
margin: 0;
font-size: 0.8125rem;
color: var(--color-text-muted);
}
.catalog-card__count {
font-size: 0.8125rem;
font-weight: 600;
color: var(--color-primary);
}
</style>