Files
psp_panel/src/app/shared/components/pageDataList/page-data-list.component.ts
T

232 lines
5.8 KiB
TypeScript
Raw Normal View History

2026-04-23 01:22:44 +03:30
import { Maybe } from '@/core';
2026-05-04 20:02:10 +03:30
import { PaginatorComponent, UikitEmptyStateComponent } from '@/uikit';
import { jalaliDiff } from '@/utils';
2025-12-04 21:07:18 +03:30
import { CommonModule } from '@angular/common';
import {
Component,
computed,
2025-12-04 21:07:18 +03:30
ContentChild,
2026-03-10 13:36:45 +03:30
ElementRef,
2025-12-04 21:07:18 +03:30
EventEmitter,
2026-05-04 20:02:10 +03:30
HostListener,
2025-12-04 21:07:18 +03:30
Input,
Output,
2026-03-10 13:36:45 +03:30
Renderer2,
2025-12-04 21:07:18 +03:30
signal,
TemplateRef,
} from '@angular/core';
import { RouterLink } from '@angular/router';
2025-12-04 21:07:18 +03:30
import { ButtonModule } from 'primeng/button';
import { DrawerModule } from 'primeng/drawer';
import { PaginatorModule } from 'primeng/paginator';
import { SkeletonModule } from 'primeng/skeleton';
import { TableModule } from 'primeng/table';
2026-05-04 20:02:10 +03:30
import { AppPageDataListGridView } from './page-data-list-grid-view.component';
import { AppPageDataListTableView } from './page-data-list-table-view.component';
export type TDataType =
2026-05-04 20:02:10 +03:30
| 'simple'
| 'price'
| 'boolean'
| 'date'
| 'nested'
| 'index'
| 'id'
| 'thumbnail'
| 'badge'
| 'number'
| 'dateTime'
| 'duration'
| 'active'
| 'has';
export interface IColumn<T = any> {
field: T extends object ? keyof T | string : string;
2025-12-04 21:07:18 +03:30
header: string;
width?: string;
minWidth?: string;
canCopy?: boolean;
type?: TDataType;
variant?: 'text' | 'tag';
tagOptions?: {
severity?: 'success' | 'secondary' | 'info' | 'warn' | 'danger' | 'contrast';
};
nestedOption?: {
path: string;
type?: TDataType;
};
thumbnailOptions?: {
editable: boolean;
deletable: boolean;
showPreview: boolean;
};
dateOption?: {
expiredMode?: boolean;
dateTime?: boolean;
onlyTime?: boolean;
};
customDataModel?: TemplateRef<any> | ((item: T) => string | number | boolean);
2025-12-04 21:07:18 +03:30
}
@Component({
selector: 'app-page-data-list',
templateUrl: './page-data-list.component.html',
2026-03-16 00:35:34 +03:30
host: {
class: 'block w-full h-full overflow-hidden',
2026-03-16 00:35:34 +03:30
},
2025-12-04 21:07:18 +03:30
imports: [
CommonModule,
TableModule,
ButtonModule,
SkeletonModule,
PaginatorModule,
DrawerModule,
PaginatorComponent,
2026-05-04 20:02:10 +03:30
AppPageDataListTableView,
AppPageDataListGridView,
UikitEmptyStateComponent,
RouterLink,
2025-12-04 21:07:18 +03:30
],
})
2026-05-04 20:02:10 +03:30
export class PageDataListComponent<I = any> {
2026-03-10 13:36:45 +03:30
constructor(
private host: ElementRef,
private renderer: Renderer2
2026-03-10 13:36:45 +03:30
) {}
2025-12-04 21:07:18 +03:30
2026-03-16 00:35:34 +03:30
@Input({ required: true }) pageTitle!: string;
2025-12-04 21:07:18 +03:30
@Input() addNewCtaLabel?: string;
2026-03-16 00:35:34 +03:30
@Input({ required: true }) columns!: IColumn[];
2026-05-04 20:02:10 +03:30
@Input({ required: true }) items!: any[];
2026-03-16 00:35:34 +03:30
@Input({ required: true }) loading!: boolean;
2025-12-04 21:07:18 +03:30
@Input() emptyPlaceholderTitle: string = 'موردی برای نمایش وجود ندارد';
@Input() emptyPlaceholderDescription?: string = '';
@Input() emptyPlaceholderCtaLabel?: string;
2026-05-30 19:05:23 +03:30
@Input() totalPages?: number = 1;
2025-12-04 21:07:18 +03:30
@Input() perPage?: number = 10;
@Input() currentPage?: number = 1;
@Input() showEdit: boolean = false;
@Input() showDelete: boolean = false;
@Input() showDetails: boolean = false;
@Input() showAdd: boolean = false;
@Input() showRefresh: boolean = true;
2025-12-04 21:07:18 +03:30
@Input() isFiltered: boolean = false;
2026-03-10 13:36:45 +03:30
@Input() fullHeight?: boolean = false;
2026-03-16 00:35:34 +03:30
@Input() height: string = '';
2026-04-23 01:22:44 +03:30
@Input() expandable?: boolean = false;
@Input() expandableItemKey?: string = '';
@Input() expandColumns?: Maybe<IColumn[]> = null;
@Input() dataKey?: string = 'items';
@Input() showIndex?: boolean = true;
@Input() showAll?: boolean = false;
@Input() allItemsPageRoute?: string;
2025-12-04 21:07:18 +03:30
@ContentChild('filter', { static: true }) filter!: TemplateRef<any> | null;
@ContentChild('caption', { static: true }) caption!: TemplateRef<any> | null;
@ContentChild('moreActions', { static: true }) moreActions!: TemplateRef<any> | null;
2026-04-23 01:22:44 +03:30
@ContentChild('expandableTemp', { static: false }) expandableTemp!: TemplateRef<any> | null;
2025-12-04 21:07:18 +03:30
@Output() onEdit = new EventEmitter<I>();
@Output() onDelete = new EventEmitter<I>();
@Output() onDetails = new EventEmitter<I>();
@Output() onAdd = new EventEmitter<void>();
@Output() onChangePage = new EventEmitter<any>();
@Output() onThumbnailClick = new EventEmitter<I>();
@Output() onRefresh = new EventEmitter();
2025-12-04 21:07:18 +03:30
filterDrawerVisible = signal<boolean>(false);
2026-04-23 01:22:44 +03:30
expandedRows: { [key: string]: boolean } = {};
2025-12-04 21:07:18 +03:30
hasCaption = computed(
() => !!(this.pageTitle || this.showAdd || this.filter || this.showRefresh || this.moreActions)
);
2025-12-04 21:07:18 +03:30
ngOnInit() {
2026-03-16 00:35:34 +03:30
if (this.height)
this.renderer.setStyle(
this.host.nativeElement,
'height',
this.fullHeight ? '100cqmin' : this.height
2026-03-16 00:35:34 +03:30
);
// if (this.fullHeight) {
// }
2026-05-04 20:02:10 +03:30
this.updateViewportMode();
2025-12-04 21:07:18 +03:30
}
2026-05-04 20:02:10 +03:30
edit = (item: any) => {
2025-12-04 21:07:18 +03:30
this.onEdit.emit(item);
};
2026-05-04 20:02:10 +03:30
remove = (item: any) => {
2025-12-04 21:07:18 +03:30
this.onDelete.emit(item);
};
2026-05-04 20:02:10 +03:30
details = (item: any) => {
2025-12-04 21:07:18 +03:30
this.onDetails.emit(item);
};
openAddForm = () => {
this.onAdd.emit();
};
openFilter = () => {
this.filterDrawerVisible.set(true);
};
closeFilter = () => {
this.filterDrawerVisible.set(false);
};
onPage = ($event: any) => {
this.onChangePage.emit($event);
2025-12-04 21:07:18 +03:30
};
openThumbnailModal = (item: I) => {
// this.
};
2025-12-04 21:07:18 +03:30
get showPaginator() {
2026-05-30 19:05:23 +03:30
return !!(this.totalPages && this.perPage && this.totalPages > this.perPage);
2025-12-04 21:07:18 +03:30
}
getPreviewClasses(item: Record<string, any>, column: IColumn): any {
if (!item || !column || column.customDataModel) return '';
try {
const { field } = column;
const data = item[String(field)];
switch (column.type) {
case 'date':
if (column.dateOption?.expiredMode) {
if (jalaliDiff(new Date(), data) > 0) {
return 'text-error';
}
}
return '';
default:
return;
}
} catch (e) {
return '';
}
}
2026-05-04 20:02:10 +03:30
refresh() {
this.onRefresh.emit();
2025-12-04 21:07:18 +03:30
}
2026-05-04 20:02:10 +03:30
isMobile = false;
2025-12-04 21:07:18 +03:30
2026-05-04 20:02:10 +03:30
@HostListener('window:resize')
onResize() {
this.updateViewportMode();
2025-12-04 21:07:18 +03:30
}
2026-05-04 20:02:10 +03:30
private updateViewportMode() {
this.isMobile = typeof window !== 'undefined' && window.innerWidth <= 768;
}
2025-12-04 21:07:18 +03:30
}