Add row selection, bulk delete, row numbers and page size picker to tables; redesign person profile header

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-05 20:00:21 +03:30
co-authored by Cursor
parent 71b3a7255a
commit 48de552f36
15 changed files with 565 additions and 79 deletions
+28 -6
View File
@@ -44,6 +44,7 @@ import type {
import { brand } from '@mento/shared';
import { useAuthStore } from '@/stores/auth';
import { canViewAllRecords } from '@/lib/roles';
import { PAGE_SIZE_OPTIONS, usePageSize } from '@/lib/pageSize';
type TypeFilter = 'all' | ActivityType;
type StatusFilter = 'all' | ActivityStatus;
@@ -78,7 +79,7 @@ const STATUS_FILTERS: Array<{ key: StatusFilter; label: string }> = [
{ key: 'canceled', label: 'لغو شده' },
];
const PAGE_SIZE = 6;
const pageSize = usePageSize('activities', 10);
const route = useRoute();
const router = useRouter();
@@ -179,7 +180,7 @@ const statusIcon: Record<UiStatus, 'check' | 'clock' | 'calendar' | 'warning'> =
const items = computed(() => data.value?.items ?? []);
const total = computed(() => data.value?.total ?? 0);
const pageCount = computed(() => Math.max(1, Math.ceil(total.value / PAGE_SIZE)));
const pageCount = computed(() => Math.max(1, Math.ceil(total.value / pageSize.value)));
const filterLabel = computed(() => TABS.find((t) => t.key === filter.value)?.label ?? 'امروز');
const activeFacetCount = computed(() => {
let n = 0;
@@ -280,7 +281,7 @@ async function load() {
filter: filter.value,
q: q.value || undefined,
page: page.value,
limit: PAGE_SIZE,
limit: pageSize.value,
desk: showDeskTabs.value ? desk.value : undefined,
type: typeFilter.value === 'all' ? undefined : typeFilter.value,
status: statusFilter.value === 'all' ? undefined : statusFilter.value,
@@ -333,6 +334,11 @@ function setPage(next: number) {
});
}
function onPageSize(size: number) {
pageSize.value = size;
if (page.value === 1) void load();
}
function onSearch() {
void router.replace({
name: 'activities',
@@ -691,7 +697,7 @@ onUnmounted(() => {
<template v-else>
<div class="list-head">
<strong>{{ filterLabel }} — {{ toFaDigits(items.length) }} فعالیت</strong>
<strong>{{ filterLabel }} — {{ toFaDigits(total.toLocaleString('en-US')) }} فعالیت</strong>
<RouterLink class="cal-mini" :to="{ name: 'activities-calendar' }" aria-label="تقویم">
<UiIcon name="calendar" :size="16" />
</RouterLink>
@@ -699,6 +705,7 @@ onUnmounted(() => {
<div class="table desktop-only" role="table">
<div class="thead" role="row">
<span class="row-num">#</span>
<span>مشتری / عنوان فعالیت</span>
<span>نوع فعالیت</span>
<span>زمان شروع</span>
@@ -707,11 +714,12 @@ onUnmounted(() => {
<span />
</div>
<article
v-for="item in items"
v-for="(item, idx) in items"
:key="item.id"
class="trow"
role="row"
>
<span class="row-num">{{ toFaDigits((page - 1) * pageSize + idx + 1) }}</span>
<div class="title-cell">
<UiIcon name="star" :size="16" class="star" />
<div>
@@ -846,7 +854,10 @@ onUnmounted(() => {
:page="page"
:total-pages="pageCount"
:total-items="total"
:page-size="pageSize"
:page-size-options="PAGE_SIZE_OPTIONS"
@update:page="setPage"
@update:page-size="onPageSize"
/>
</template>
@@ -1224,7 +1235,7 @@ h1 {
.thead,
.trow {
display: grid;
grid-template-columns: minmax(0, 2.2fr) 7.6rem 7.2rem 8.4rem 8.6rem 2.4rem;
grid-template-columns: 2.4rem minmax(0, 2.2fr) 7.6rem 7.2rem 8.4rem 8.6rem 2.4rem;
gap: 0.8rem;
align-items: center;
padding: 0.95rem 1.1rem;
@@ -1243,6 +1254,13 @@ h1 {
border-bottom: 1px solid #f8fafc;
}
.row-num {
color: #94a3b8;
font-size: 0.78rem;
font-variant-numeric: tabular-nums;
text-align: center;
}
.trow:last-child {
border-bottom: 0;
border-radius: 0 0 var(--radius) var(--radius);
@@ -1590,5 +1608,9 @@ time.note {
.trow {
grid-template-columns: 1fr;
}
.row-num {
display: none;
}
}
</style>