ng-firebase-table-kxp 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +500 -381
  2. package/esm2020/lib/components/table/table.component.mjs +776 -0
  3. package/esm2020/lib/firebase-table-kxp-lib.component.mjs +19 -0
  4. package/esm2020/lib/firebase-table-kxp-lib.module.mjs +74 -0
  5. package/esm2020/lib/firebase-table-kxp-lib.service.mjs +14 -0
  6. package/esm2020/lib/services/table.service.mjs +908 -0
  7. package/esm2020/lib/types/Table.mjs +2 -0
  8. package/esm2020/ng-firebase-table-kxp.mjs +5 -0
  9. package/esm2020/public-api.mjs +15 -0
  10. package/fesm2015/ng-firebase-table-kxp.mjs +1811 -0
  11. package/fesm2015/ng-firebase-table-kxp.mjs.map +1 -0
  12. package/fesm2020/ng-firebase-table-kxp.mjs +1784 -0
  13. package/fesm2020/ng-firebase-table-kxp.mjs.map +1 -0
  14. package/index.d.ts +5 -0
  15. package/lib/components/table/table.component.d.ts +111 -0
  16. package/lib/firebase-table-kxp-lib.component.d.ts +5 -0
  17. package/lib/firebase-table-kxp-lib.module.d.ts +21 -0
  18. package/lib/firebase-table-kxp-lib.service.d.ts +6 -0
  19. package/lib/services/table.service.d.ts +70 -0
  20. package/{src/lib/types/Table.ts → lib/types/Table.d.ts} +28 -31
  21. package/package.json +23 -3
  22. package/{src/public-api.ts → public-api.d.ts} +0 -13
  23. package/CHANGELOG.md +0 -88
  24. package/ng-package.json +0 -7
  25. package/src/lib/components/table/table.component.html +0 -555
  26. package/src/lib/components/table/table.component.scss +0 -22
  27. package/src/lib/components/table/table.component.spec.ts +0 -24
  28. package/src/lib/components/table/table.component.ts +0 -917
  29. package/src/lib/firebase-table-kxp-lib.component.spec.ts +0 -23
  30. package/src/lib/firebase-table-kxp-lib.component.ts +0 -15
  31. package/src/lib/firebase-table-kxp-lib.module.ts +0 -45
  32. package/src/lib/firebase-table-kxp-lib.service.spec.ts +0 -16
  33. package/src/lib/firebase-table-kxp-lib.service.ts +0 -9
  34. package/src/lib/services/table.service.spec.ts +0 -16
  35. package/src/lib/services/table.service.ts +0 -1235
  36. package/tsconfig.lib.json +0 -14
  37. package/tsconfig.lib.prod.json +0 -10
  38. package/tsconfig.spec.json +0 -14
package/README.md CHANGED
@@ -1,84 +1,64 @@
1
- # Firebase Table KXP Lib
2
-
3
- Uma biblioteca Angular poderosa para criar tabelas dinâmicas com integração completa ao Firebase Firestore. Inclui paginação avançada, filtros personalizáveis, ordenação e fallback client-side para queries sem índices.
4
-
5
- ## ✨ Características
6
-
7
- - 🔥 **Integração completa com Firebase/Firestore**
8
- - 📊 **Paginação otimizada** (client-side e server-side)
9
- - 🔍 **Sistema de filtros avançado** (texto, data, equals)
10
- - **Fallback automático** quando índices compostos não existem
11
- - 🎨 **Interface Material Design** com Angular Material
12
- - 📱 **Responsivo** e adaptável
13
- - 🔗 **Suporte a relações** entre collections
14
- - 📥 **Exportação de dados**
15
- - 🎯 **Altamente configurável**
16
-
17
- ## 📦 Instalação
18
-
19
- ### Instalação Simples (npm 7+ / Node 15+)
1
+ # Firebase Table KXP Library
2
+
3
+ [![npm version](https://badge.fury.io/js/%40adryanmmm%2Ffirebase-table-kxp-lib.svg)](https://www.npmjs.com/package/@adryanmmm/firebase-table-kxp-lib)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Firebase Table KXP Library is a production-ready Angular data table created by **KXP Tech** to power enterprise dashboards backed by Firebase Firestore. It wraps complex Firestore querying, pagination, filtering, and material design styling into a plug-and-play module so teams can ship data-rich experiences faster.
7
+
8
+ ## Table of Contents
9
+ - [Why Firebase Table KXP](#why-firebase-table-kxp)
10
+ - [Core Features](#core-features)
11
+ - [Installation & Setup](#installation--setup)
12
+ - [Configuration Overview](#configuration-overview)
13
+ - [API Reference](#api-reference)
14
+ - [TableData](#tabledata)
15
+ - [Column](#column)
16
+ - [Tab & TabData](#tab--tabdata)
17
+ - [FilterableOption](#filterableoption)
18
+ - [Condition](#condition)
19
+ - [Arrange](#arrange)
20
+ - [Image](#image)
21
+ - [Data Export (Download)](#data-export-download)
22
+ - [Powered by KXP Tech](#powered-by-kxp-tech)
23
+ - [Contributing & License](#contributing--license)
24
+ - [Support the Project](#support-the-project)
25
+
26
+ ## Why Firebase Table KXP
27
+
28
+ - Built and battle-tested at **KXP Tech** across projects with thousands of active users
29
+ - Eliminates weeks of custom table work; drop it in and configure
30
+ - Handles Firestore quirks (pagination, missing indexes, fallbacks) automatically
31
+ - Provides a strongly typed API that scales with project complexity
32
+ - Plays nicely with Angular Material, Firebase, and Angular Fire
33
+
34
+ ## Core Features
35
+
36
+ - Full Firestore integration with server-side and client-side pagination
37
+ - Text, date, and custom filters with automatic index fallback when needed
38
+ - Configurable columns for relations, custom renderers, actions, and exports
39
+ - Built-in CSV export hooks and actionable buttons per row
40
+ - Pagination, sorting, and filter state shared between tabs
41
+ - Optional color theming, tabbed datasets, and custom navigation per row
42
+ - Works seamlessly with Angular 15, Angular Material, Angular Fire, and RxJS
43
+
44
+ ## Installation & Setup
20
45
 
21
46
  ```bash
22
- npm install ng-firebase-table-kxp
47
+ npm install @adryanmmm/firebase-table-kxp-lib
23
48
  ```
24
49
 
25
- **Pronto!** Todas as dependências necessárias serão instaladas automaticamente pelo npm 7+.
26
-
27
- ### Se você usa npm 6 ou anterior
50
+ The host application should already depend on:
28
51
 
29
- Caso esteja usando npm 6 ou anterior (raro hoje em dia), você precisará instalar as peer dependencies manualmente:
30
-
31
- ```bash
32
- npm install ng-firebase-table-kxp
33
- npm install @angular/fire@^15.0.0 firebase@^9.0.0 @angular/material@^15.0.0 @angular/cdk@^15.0.0 ngx-toastr@^16.0.0 moment@^2.29.0 ngx-mask@^15.0.0
34
- ```
35
-
36
- **Como verificar sua versão do npm:**
37
- ```bash
38
- npm --version
39
- # Se retornar 7.x ou superior, está tudo certo!
40
- ```
52
+ - Angular 15 packages: `@angular/common`, `@angular/core`, `@angular/forms`, `@angular/router`, `@angular/cdk`, `@angular/material`
53
+ - Firebase stack: `@angular/fire` (7.x) and `firebase` (9.x)
54
+ - Utilities: `ngx-toastr` (16.x), `moment` (2.29.x), `ngx-mask` (15.x)
41
55
 
42
- ## 🔧 Dependências
43
-
44
- A biblioteca usa as seguintes peer dependencies (instaladas automaticamente):
45
-
46
- - `@angular/fire` ^15.0.0 - Integração com Firebase
47
- - `firebase` ^9.0.0 - SDK do Firebase
48
- - `@angular/material` ^15.0.0 - Componentes Material
49
- - `@angular/cdk` ^15.0.0 - Component Dev Kit
50
- - `ngx-toastr` ^16.0.0 - Notificações toast
51
- - `moment` ^2.29.0 - Manipulação de datas
52
- - `ngx-mask` ^15.0.0 - Máscaras de input
53
-
54
- ## 🚀 Configuração
55
-
56
- ### 1. Importe o módulo no seu `app.module.ts`:
57
56
 
57
+ 1. **Import the module**
58
58
  ```typescript
59
- import { NgModule } from '@angular/core';
60
- import { BrowserModule } from '@angular/platform-browser';
61
- import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
62
-
63
- // Firebase
64
- import { AngularFireModule } from '@angular/fire/compat';
65
- import { AngularFirestoreModule } from '@angular/fire/compat/firestore';
66
-
67
- // Toastr
68
- import { ToastrModule } from 'ngx-toastr';
69
-
70
- // Firebase Table KXP Lib
71
- import { FirebaseTableKxpLibModule } from 'ng-firebase-table-kxp';
72
-
73
- // Mask
74
- import { NgxMaskModule } from 'ngx-mask';
75
-
76
- import { environment } from '../environments/environment';
59
+ import { FirebaseTableKxpLibModule } from '@adryanmmm/firebase-table-kxp-lib';
77
60
 
78
61
  @NgModule({
79
- declarations: [
80
- AppComponent
81
- ],
82
62
  imports: [
83
63
  BrowserModule,
84
64
  BrowserAnimationsModule,
@@ -87,390 +67,529 @@ import { environment } from '../environments/environment';
87
67
  ToastrModule.forRoot(),
88
68
  NgxMaskModule.forRoot(),
89
69
  FirebaseTableKxpLibModule
90
- ],
91
- providers: [],
92
- bootstrap: [AppComponent]
70
+ ]
93
71
  })
94
- export class AppModule { }
95
- ```
96
-
97
- ### 2. Configure o Firebase no `environment.ts`:
98
-
99
- ```typescript
100
- export const environment = {
101
- production: false,
102
- firebase: {
103
- apiKey: "sua-api-key",
104
- authDomain: "seu-projeto.firebaseapp.com",
105
- projectId: "seu-projeto-id",
106
- storageBucket: "seu-projeto.appspot.com",
107
- messagingSenderId: "123456789",
108
- appId: "seu-app-id"
109
- }
110
- };
111
- ```
112
-
113
- ### 3. Importe os estilos do Angular Material no `styles.scss`:
114
-
115
- ```scss
116
- @import '@angular/material/prebuilt-themes/indigo-pink.css';
117
- @import 'ngx-toastr/toastr';
118
-
119
- // Se estiver usando Tailwind CSS, adicione também:
120
- @tailwind base;
121
- @tailwind components;
122
- @tailwind utilities;
72
+ export class AppModule {}
123
73
  ```
124
74
 
125
- ## 💻 Uso Básico
126
-
127
- ### No seu componente TypeScript:
128
-
75
+ 2. **Drop the component**
129
76
  ```typescript
130
- import { Component, OnInit } from '@angular/core';
131
- import { AngularFirestore } from '@angular/fire/compat/firestore';
132
- import { TableData, Column } from 'ng-firebase-table-kxp';
133
-
134
77
  @Component({
135
78
  selector: 'app-users',
136
79
  template: `
137
- <lib-table
138
- [data]="tableData"
80
+ <lib-table
81
+ [data]="table"
139
82
  [downloadTable]="downloadTable">
140
83
  </lib-table>
141
84
  `
142
85
  })
143
- export class UsersComponent implements OnInit {
144
- tableData: TableData;
145
-
146
- constructor(private firestore: AngularFirestore) {}
147
-
148
- ngOnInit() {
149
- this.tableData = {
150
- name: 'users',
151
- collection: 'users',
152
- collectionRef: this.firestore.collection('users').ref,
153
- pagination: true,
154
- download: true,
155
- sortBy: {
156
- field: 'createdAt',
157
- order: 'desc'
158
- },
159
- displayedColumns: [
160
- {
161
- property: 'name',
162
- title: 'Nome',
163
- isFilterable: true,
164
- isSortable: true
165
- },
166
- {
167
- property: 'email',
168
- title: 'E-mail',
169
- isFilterable: true
170
- },
171
- {
172
- property: 'createdAt',
173
- title: 'Data de Criação',
174
- isFilterableByDate: true,
175
- isSortable: true,
176
- pipe: new DatePipe('pt-BR')
177
- }
178
- ]
179
- };
180
- }
181
-
182
- downloadTable = (arrange, conditions) => {
183
- // Lógica para exportar a tabela
184
- console.log('Exportando tabela...', arrange, conditions);
185
- }
186
- }
187
- ```
188
-
189
- ## 📖 API Completa
190
-
191
- ### TableData Interface
192
-
193
- ```typescript
194
- interface TableData {
195
- // Configurações básicas
196
- name: string; // Nome da tabela
197
- collection: string; // Nome da collection no Firestore
198
- collectionRef: CollectionReference; // Referência da collection
199
- pagination: boolean; // Habilitar paginação
200
- download: boolean; // Habilitar exportação
201
-
202
- // Colunas
203
- displayedColumns: Column[]; // Array de colunas a exibir
204
-
205
- // Ordenação
206
- sortBy?: {
207
- field: string;
208
- order: 'asc' | 'desc';
209
- };
210
-
211
- // Filtros e condições
212
- conditions?: Condition[]; // Condições where do Firestore
213
- filterFn?: (item: any) => boolean; // Função de filtro customizada
214
- filterableOptions?: FilterableOption[]; // Opções de filtro personalizadas
215
-
216
- // Aparência
217
- color?: {
218
- bg: string; // Classe CSS para fundo
219
- text: string; // Classe CSS para texto
220
- };
221
-
222
- // Navegação
223
- isNotClickable?: boolean; // Desabilitar clique nas linhas
224
- url?: string; // URL base para navegação
225
-
226
- // Totalizadores
227
- totalRef?: {
228
- ref: DocumentReference;
229
- field: string;
230
- }[];
231
-
232
- // Botão de ação
233
- actionButton?: {
234
- label: string;
235
- routerLink: string;
236
- icon?: string;
237
- colorClass?: string;
238
- method?: (row: any, event?: any) => any;
239
- condition?: (row: any) => boolean;
240
- };
241
-
242
- // Tabs
243
- tabs?: {
244
- method: (tab: any, event?: any) => any;
245
- tabsData: TabData[];
86
+ export class UsersComponent {
87
+ table: TableData = {
88
+ name: 'users',
89
+ collection: 'users',
90
+ collectionRef: this.firestore.collection('users').ref,
91
+ pagination: true,
92
+ download: true,
93
+ displayedColumns: [
94
+ { property: 'name', title: 'Name', isFilterable: true, isSortable: true },
95
+ { property: 'email', title: 'Email', isFilterable: true }
96
+ ]
246
97
  };
247
- }
248
- ```
249
-
250
- ### Column Interface
251
98
 
252
- ```typescript
253
- interface Column {
254
- property: string; // Propriedade do objeto
255
- title?: string; // Título da coluna
256
- charLimit?: number; // Limite de caracteres (com tooltip)
257
-
258
- // Formatação
259
- pipe?: PipeTransform; // Pipe do Angular para formatação
260
- calculateValue?: (row: any) => any; // Função para calcular valor
261
-
262
- // Filtros e ordenação
263
- isFilterable?: boolean; // Permite filtrar por texto
264
- isSortable?: boolean; // Permite ordenação
265
- isFilterableByDate?: boolean; // Permite filtro por data
266
- filterPredicates?: string[]; // Predicados customizados
267
-
268
- // Links e downloads
269
- hasLink?: boolean | string; // Tornar valor um link
270
- hasDownload?: boolean | string; // Habilitar download
271
-
272
- // Imagens
273
- image?: {
274
- class: string;
275
- path?: string;
276
- url?: boolean;
277
- default?: string;
278
- };
279
-
280
- // Ícones e botões
281
- iconClass?: {
282
- text?: string;
283
- class?: string;
284
- condition?: (row: any) => any;
285
- buttonMethod?: (row: any, event?: any) => any;
286
- }[];
287
-
288
- // Relações com outras collections
289
- relation?: {
290
- collection: string;
291
- property: string;
292
- newProperty: string;
293
- };
294
-
295
- // Query lengths
296
- queryLength?: {
297
- collection: string;
298
- property: string;
299
- operator: WhereFilterOp;
300
- value: string;
99
+ downloadTable = (arrange: any, conditions: any[]) => {
100
+ // export logic
301
101
  };
302
-
303
- // Arrays
304
- arrayField?: string; // Campo para exibir de arrays de objetos
305
-
306
- // Métodos customizados
307
- method?: (row: any, event?: any) => any;
102
+
103
+ constructor(private firestore: AngularFirestore) {}
308
104
  }
309
105
  ```
310
106
 
311
- ## 🎯 Exemplos Avançados
312
-
313
- ### Exemplo com Filtros Personalizados
107
+ 3. **Make sure global styles include**
108
+ ```scss
109
+ @import '@angular/material/prebuilt-themes/indigo-pink.css';
110
+ @import 'ngx-toastr/toastr';
111
+ ```
314
112
 
113
+ ## Configuration Overview
114
+
115
+ - `TableData` defines the table behavior: source collection, pagination, sorting, tabs, exported totals, and custom navigation.
116
+ - `Column` describes each displayed column: filters, relations, custom templates, icon actions, download buttons, and data formatting.
117
+ - `Condition` lets you predefine Firestore `where` clauses applied before any user filters.
118
+ - Optional hooks like `filterFn`, `actionButton`, and `tabs` enable richer UX without duplicating logic.
119
+ - Automatic client-side fallback when Firestore reports missing composite indexes, plus logging of the index link to a `missingIndexes` collection.
120
+ - Support for joining related collections, counting related documents per row, and managing dialog-driven actions via `iconClass` or `actionButton` handlers.
121
+ - Compatible with SSR, lazy-loaded modules, and Angular standalone components.
122
+
123
+ ## API Reference
124
+
125
+ This section provides detailed documentation for all configuration interfaces available in the library.
126
+
127
+ ### TableData
128
+
129
+ The main configuration object that defines the entire table behavior.
130
+
131
+ | Property | Type | Required | Description |
132
+ |----------|------|----------|-------------|
133
+ | `name` | `string` | ✅ | Unique identifier for the table. Used internally for caching and state management. |
134
+ | `collection` | `string` | ✅ | Name of the Firestore collection to query. |
135
+ | `collectionRef` | `CollectionReference` | ✅ | Reference to the Firestore collection. Use `firestore.collection('name').ref`. |
136
+ | `displayedColumns` | `Column[]` | ✅ | Array of column definitions. Defines what data to display and how. See [Column](#column). |
137
+ | `pagination` | `boolean` | ✅ | Enable or disable pagination. When `true`, data is loaded in batches. |
138
+ | `download` | `boolean` | ✅ | Enable or disable the export/download functionality. |
139
+ | `sortBy` | `{field: string, order: OrderByDirection}` | ❌ | Default sorting configuration. `order` can be `'asc'` or `'desc'`. |
140
+ | `conditions` | `Condition[]` | ❌ | Array of Firestore where clauses applied before user filters. See [Condition](#condition). |
141
+ | `filterFn` | `(item: any) => boolean` | ❌ | Custom client-side filter function. Applied after Firestore queries. |
142
+ | `filterableOptions` | `FilterableOption[]` | ❌ | Predefined filter options displayed as buttons. See [FilterableOption](#filterableoption). |
143
+ | `url` | `string` | ❌ | Base URL for row navigation. Row clicks navigate to `{url}/{row.id}`. |
144
+ | `isNotClickable` | `boolean` | ❌ | When `true`, disables row click navigation. |
145
+ | `color` | `{bg: string, text: string}` | ❌ | CSS classes for custom table theming. `bg` for background, `text` for text color. |
146
+ | `totalRef` | `{ref: DocumentReference, field: string}[]` | ❌ | References to documents containing total counts. Displayed in the table footer. |
147
+ | `actionButton` | `ActionButton` | ❌ | Configuration for a primary action button (e.g., "Add New"). |
148
+ | `tabs` | `Tab` | ❌ | Configuration for tabbed data views. See [Tab & TabData](#tab--tabdata). |
149
+
150
+ **ActionButton Properties:**
151
+ - `label` (string): Button text
152
+ - `routerLink` (string): Navigation route
153
+ - `icon` (string): CSS class for icon (e.g., FontAwesome)
154
+ - `colorClass` (string): CSS class for button styling
155
+ - `method` ((row, event) => any): Custom click handler
156
+ - `condition` ((row) => boolean): Function to conditionally show the button
157
+
158
+ **Example:**
315
159
  ```typescript
316
- this.tableData = {
160
+ const tableData: TableData = {
317
161
  name: 'products',
318
162
  collection: 'products',
319
163
  collectionRef: this.firestore.collection('products').ref,
320
164
  pagination: true,
321
165
  download: true,
322
- displayedColumns: [
323
- {
324
- property: 'name',
325
- title: 'Produto',
326
- isFilterable: true
327
- },
328
- {
329
- property: 'price',
330
- title: 'Preço',
331
- pipe: new CurrencyPipe('pt-BR'),
332
- isSortable: true
333
- },
334
- {
335
- property: 'category',
336
- title: 'Categoria',
337
- isFilterable: true
338
- }
166
+ sortBy: { field: 'createdAt', order: 'desc' },
167
+ conditions: [
168
+ { operator: '==', firestoreProperty: 'active', dashProperty: true }
339
169
  ],
340
- filterableOptions: [
341
- {
342
- title: 'Status',
343
- items: [
344
- { property: 'status', value: 'active', label: 'Ativo' },
345
- { property: 'status', value: 'inactive', label: 'Inativo' }
346
- ]
347
- }
348
- ]
170
+ displayedColumns: [/* ... */],
171
+ actionButton: {
172
+ label: 'Add Product',
173
+ routerLink: '/products/new',
174
+ icon: 'fa fa-plus',
175
+ colorClass: 'bg-blue-500'
176
+ }
349
177
  };
350
178
  ```
351
179
 
352
- ### Exemplo com Relações
353
-
180
+ ---
181
+
182
+ ### Column
183
+
184
+ Defines how each column is displayed, filtered, and interacted with.
185
+
186
+ | Property | Type | Required | Description |
187
+ |----------|------|----------|-------------|
188
+ | `property` | `string` | ✅ | Name of the property in the data object to display. |
189
+ | `title` | `string` | ❌ | Column header text. Defaults to `property` if not provided. |
190
+ | `charLimit` | `number` | ❌ | Maximum characters to display. Shows tooltip with full text on hover. |
191
+ | `pipe` | `PipeTransform` | ❌ | Angular pipe for formatting values (e.g., `DatePipe`, `CurrencyPipe`). |
192
+ | `calculateValue` | `(row: any) => any` | ❌ | Function to compute the display value from the row data. |
193
+ | `isSortable` | `boolean` | ❌ | Enable sorting for this column. |
194
+ | `isFilterable` | `boolean` | ❌ | Enable text-based filtering for this column. |
195
+ | `isFilterableByDate` | `boolean` | ❌ | Enable date range filtering. Shows date picker inputs. |
196
+ | `filterPredicates` | `string[]` | ❌ | Additional properties to include when filtering this column. |
197
+ | `hasLink` | `boolean \| string` | ❌ | Make the cell value a clickable link. If string, uses as the navigation path. |
198
+ | `hasDownload` | `boolean \| string` | ❌ | Add download icon to the cell. If string, uses as the download URL property. |
199
+ | `arrayField` | `string` | ❌ | When data is an array of objects, specify which field to display. |
200
+ | `method` | `(row: any, event?: any) => any` | ❌ | Custom click handler for the cell. |
201
+ | `image` | `Image` | ❌ | Configuration for displaying images. See [Image](#image). |
202
+ | `iconClass` | `IconClass[]` | ❌ | Array of icon/button configurations for action buttons in the cell. |
203
+ | `relation` | `Relation` | ❌ | Configuration for joining related collection data. |
204
+ | `queryLength` | `QueryLength` | ❌ | Configuration for counting related documents. |
205
+
206
+ **IconClass Properties:**
207
+ - `class` (string): CSS classes for the icon/button
208
+ - `text` (string): Text to display alongside icon
209
+ - `condition` ((row) => any): Function to conditionally show the icon
210
+ - `buttonMethod` ((row, event) => any): Click handler for the icon
211
+
212
+ **Relation Properties:**
213
+ - `collection` (string): Name of the related collection
214
+ - `property` (string): Property in current row containing the related document ID
215
+ - `newProperty` (string): Property from related document to fetch and display
216
+
217
+ **QueryLength Properties:**
218
+ - `collection` (string): Collection to count documents from
219
+ - `property` (string): Field to match in the query
220
+ - `operator` (WhereFilterOp): Firestore operator (e.g., `'=='`, `'>'`)
221
+ - `value` (string): Property from current row to use as query value
222
+
223
+ **Example:**
354
224
  ```typescript
355
- displayedColumns: [
225
+ const columns: Column[] = [
226
+ {
227
+ property: 'name',
228
+ title: 'Product Name',
229
+ isFilterable: true,
230
+ isSortable: true,
231
+ charLimit: 50
232
+ },
233
+ {
234
+ property: 'price',
235
+ title: 'Price',
236
+ pipe: new CurrencyPipe('en-US'),
237
+ isSortable: true
238
+ },
356
239
  {
357
- property: 'userName',
358
- title: 'Usuário',
240
+ property: 'createdAt',
241
+ title: 'Created',
242
+ pipe: new DatePipe('en-US'),
243
+ isFilterableByDate: true
244
+ },
245
+ {
246
+ property: 'categoryName',
247
+ title: 'Category',
359
248
  relation: {
360
- collection: 'users',
361
- property: 'userId', // Campo na collection atual
362
- newProperty: 'name' // Campo a buscar na collection relacionada
249
+ collection: 'categories',
250
+ property: 'categoryId',
251
+ newProperty: 'name'
363
252
  }
364
- }
365
- ]
366
- ```
367
-
368
- ### Exemplo com Botões Customizados
369
-
370
- ```typescript
371
- displayedColumns: [
253
+ },
372
254
  {
373
255
  property: 'actions',
374
- title: 'Ações',
256
+ title: 'Actions',
375
257
  iconClass: [
376
258
  {
377
259
  class: 'fa fa-edit text-blue-500 cursor-pointer',
378
- buttonMethod: (row, event) => {
379
- event.stopPropagation();
380
- this.editItem(row);
381
- },
382
- condition: (row) => row.canEdit === true
260
+ buttonMethod: (row) => this.editProduct(row)
383
261
  },
384
262
  {
385
- class: 'fa fa-trash text-red-500 cursor-pointer ml-2',
386
- buttonMethod: (row, event) => {
387
- event.stopPropagation();
388
- this.deleteItem(row);
389
- }
263
+ class: 'fa fa-trash text-red-500 cursor-pointer',
264
+ buttonMethod: (row) => this.deleteProduct(row),
265
+ condition: (row) => row.canDelete === true
390
266
  }
391
267
  ]
392
268
  }
393
- ]
269
+ ];
394
270
  ```
395
271
 
396
- ### Exemplo com Condições (Where Clauses)
272
+ ---
273
+
274
+ ### Tab & TabData
275
+
276
+ Configure tabbed views for switching between different data sets within the same table.
397
277
 
278
+ **Tab Interface:**
279
+
280
+ | Property | Type | Required | Description |
281
+ |----------|------|----------|-------------|
282
+ | `method` | `(tab: any, event?: any) => any` | ✅ | Function called when a tab is clicked. Use to switch data or apply filters. |
283
+ | `tabsData` | `TabData[]` | ✅ | Array of tab configurations. |
284
+
285
+ **TabData Interface:**
286
+
287
+ | Property | Type | Required | Description |
288
+ |----------|------|----------|-------------|
289
+ | `label` | `string` | ✅ | Text displayed on the tab. |
290
+ | `counter` | `number` | ❌ | Optional counter badge displayed next to the label. |
291
+ | `counterClass` | `string` | ❌ | CSS class for styling the counter badge. |
292
+
293
+ **Example:**
398
294
  ```typescript
399
- this.tableData = {
400
- // ... outras configurações
401
- conditions: [
402
- {
403
- operator: '==',
404
- firestoreProperty: 'status',
405
- dashProperty: 'active'
295
+ const tableData: TableData = {
296
+ // ... other config
297
+ tabs: {
298
+ method: (tab, event) => {
299
+ if (tab.label === 'Active') {
300
+ this.loadActiveProducts();
301
+ } else if (tab.label === 'Inactive') {
302
+ this.loadInactiveProducts();
303
+ }
406
304
  },
407
- {
408
- operator: '>=',
409
- firestoreProperty: 'createdAt',
410
- dashProperty: new Date('2024-01-01')
411
- }
412
- ]
305
+ tabsData: [
306
+ { label: 'Active', counter: 42, counterClass: 'bg-green-500' },
307
+ { label: 'Inactive', counter: 8, counterClass: 'bg-gray-500' },
308
+ { label: 'All' }
309
+ ]
310
+ }
413
311
  };
414
312
  ```
415
313
 
416
- ### Exemplo com Filtro Customizado (filterFn)
314
+ ---
315
+
316
+ ### FilterableOption
317
+
318
+ Predefined filter buttons that users can click to apply common filters.
319
+
320
+ | Property | Type | Required | Description |
321
+ |----------|------|----------|-------------|
322
+ | `title` | `string` | ✅ | Label for the filter group. |
323
+ | `items` | `FilterItem[]` | ✅ | Array of individual filter options. |
324
+
325
+ **FilterItem Properties:**
326
+ - `property` (string): Property to filter on
327
+ - `value` (string \| boolean): Value to filter by
328
+ - `label` (string): Text displayed on the filter button
329
+
330
+ **Example:**
331
+ ```typescript
332
+ const filterableOptions: FilterableOption[] = [
333
+ {
334
+ title: 'Status',
335
+ items: [
336
+ { property: 'status', value: 'active', label: 'Active' },
337
+ { property: 'status', value: 'pending', label: 'Pending' },
338
+ { property: 'status', value: 'archived', label: 'Archived' }
339
+ ]
340
+ },
341
+ {
342
+ title: 'Category',
343
+ items: [
344
+ { property: 'category', value: 'electronics', label: 'Electronics' },
345
+ { property: 'category', value: 'clothing', label: 'Clothing' }
346
+ ]
347
+ }
348
+ ];
349
+ ```
350
+
351
+ ---
352
+
353
+ ### Condition
354
+
355
+ Firestore `where` clauses that are always applied to queries, before any user filters.
356
+
357
+ | Property | Type | Required | Description |
358
+ |----------|------|----------|-------------|
359
+ | `operator` | `WhereFilterOp` | ✅ | Firestore comparison operator: `'=='`, `'!='`, `'<'`, `'<='`, `'>'`, `'>='`, `'array-contains'`, `'in'`, `'array-contains-any'`, `'not-in'`. |
360
+ | `firestoreProperty` | `string` | ✅ | Name of the field in Firestore to filter on. |
361
+ | `dashProperty` | `string \| string[]` | ✅ | Value or array of values to compare against. Can be a static value or a property name from your component. |
362
+
363
+ **Example:**
364
+ ```typescript
365
+ const conditions: Condition[] = [
366
+ {
367
+ operator: '==',
368
+ firestoreProperty: 'tenantId',
369
+ dashProperty: this.currentTenantId
370
+ },
371
+ {
372
+ operator: '>=',
373
+ firestoreProperty: 'createdAt',
374
+ dashProperty: this.startDate
375
+ },
376
+ {
377
+ operator: 'in',
378
+ firestoreProperty: 'status',
379
+ dashProperty: ['active', 'pending']
380
+ }
381
+ ];
382
+ ```
383
+
384
+ ---
385
+
386
+ ### Arrange
387
+
388
+ Internal interface used for managing sort and filter state. Automatically handled by the table component.
389
+
390
+ | Property | Type | Description |
391
+ |----------|------|-------------|
392
+ | `filters` | `FilterState[]` | Array of active filters per column. |
393
+ | `sortBy` | `{field: string, order: OrderByDirection}` | Current sort configuration. |
394
+ | `elementId` | `{property: string, value: string}` | Optional identifier for highlighting a specific row. |
395
+
396
+ **FilterState Properties:**
397
+ - `arrange` ('ascending' \| 'descending' \| 'filter' \| 'filterByDate' \| 'equals' \| ''): Type of filter/sort applied
398
+ - `filter` ({property: string, filtering: string}): Text filter configuration
399
+ - `dateFilter` ({initial: Date, final: Date}): Date range filter
417
400
 
401
+ ---
402
+
403
+ ### Image
404
+
405
+ Configuration for displaying images in table cells.
406
+
407
+ | Property | Type | Required | Description |
408
+ |----------|------|----------|-------------|
409
+ | `class` | `string` | ✅ | CSS classes for styling the image element. |
410
+ | `path` | `string` | ❌ | Property name containing the image path/URL in the row data. |
411
+ | `url` | `boolean` | ❌ | If `true`, treats the value as a complete URL. Otherwise, constructs path from storage. |
412
+ | `default` | `string` | ❌ | Default image URL if the actual image is missing or fails to load. |
413
+
414
+ **Example:**
418
415
  ```typescript
419
- this.tableData = {
420
- // ... outras configurações
421
- filterFn: (item) => {
422
- // Filtro customizado no lado do cliente
423
- return item.age >= 18 && item.status === 'active';
416
+ const column: Column = {
417
+ property: 'avatar',
418
+ title: 'Photo',
419
+ image: {
420
+ class: 'w-10 h-10 rounded-full object-cover',
421
+ path: 'photoURL',
422
+ url: true,
423
+ default: '/assets/default-avatar.png'
424
424
  }
425
425
  };
426
426
  ```
427
427
 
428
- ## 🎨 Customização de Estilos
428
+ ---
429
429
 
430
- A biblioteca usa Tailwind CSS e Angular Material. Você pode customizar os estilos no seu `styles.scss`:
430
+ ### Data Export (Download)
431
431
 
432
- ```scss
433
- // Customizar cores da tabela
434
- .mat-elevation-z8 {
435
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1) !important;
432
+ The library provides a flexible export system that allows you to download table data with the currently applied filters, sorting, and conditions.
433
+
434
+ #### How It Works
435
+
436
+ 1. **Pass a download handler** to the table component via the `[downloadTable]` input
437
+ 2. **User clicks** the download button in the table UI
438
+ 3. **Library calls your handler** with current `arrange` (filters/sort state) and `conditions` (where clauses)
439
+ 4. **Your handler** fetches all data using `TableService.getItemsData()`, transforms it, and generates the file
440
+
441
+ #### Basic Example
442
+
443
+ ```typescript
444
+ import { TableService } from '@adryanmmm/firebase-table-kxp-lib';
445
+ import * as XLSX from 'xlsx';
446
+ import moment from 'moment';
447
+
448
+ export class UsersComponent {
449
+ constructor(private tableService: TableService) {}
450
+
451
+ // Pass this method to [downloadTable]
452
+ downloadTable = async (arrange: Arrange, conditions: Condition[]) => {
453
+ // 1. Fetch all data with current filters
454
+ const rawData = await this.tableService.getItemsData(
455
+ 'users', // collection name
456
+ arrange, // current sort/filter state
457
+ conditions // optional where conditions
458
+ );
459
+
460
+ // 2. Transform data to desired format
461
+ const xlsxData = rawData.map(user => ({
462
+ 'Name': user.fullName,
463
+ 'Email': user.email,
464
+ 'Phone': user.phoneNumber,
465
+ 'Created': new Date(user.createdAt.seconds * 1000).toLocaleDateString()
466
+ }));
467
+
468
+ // 3. Generate Excel file
469
+ const worksheet = XLSX.utils.json_to_sheet(xlsxData);
470
+ const workbook = XLSX.utils.book_new();
471
+ XLSX.utils.book_append_sheet(workbook, worksheet, 'Users');
472
+
473
+ // 4. Download file
474
+ const fileName = `Users_${moment().format('DD-MM-YYYY-HH-mm-ss')}.xlsx`;
475
+ XLSX.writeFile(workbook, fileName);
476
+ }
436
477
  }
478
+ ```
479
+
480
+ #### Advanced Example with Totals
437
481
 
438
- // Customizar header da tabela
439
- .bg-primary {
440
- background-color: #your-color !important;
482
+ ```typescript
483
+ downloadOrdersTable = async (arrange: Arrange, conditions: Condition[]) => {
484
+ const rawData = await this.tableService.getItemsData(
485
+ 'orders',
486
+ arrange,
487
+ conditions
488
+ );
489
+
490
+ let totalAmount = 0;
491
+
492
+ // Map data and calculate totals
493
+ const xlsxData = rawData.map(order => {
494
+ totalAmount += order.amount;
495
+ return {
496
+ 'Order ID': order.id,
497
+ 'Customer': order.customerName,
498
+ 'Amount': order.amount,
499
+ 'Date': new Date(order.createdAt.seconds * 1000).toLocaleDateString(),
500
+ 'Status': order.status
501
+ };
502
+ });
503
+
504
+ // Add totals row
505
+ xlsxData.push({
506
+ 'Order ID': '',
507
+ 'Customer': '',
508
+ 'Amount': totalAmount,
509
+ 'Date': 'TOTAL',
510
+ 'Status': ''
511
+ });
512
+
513
+ const worksheet = XLSX.utils.json_to_sheet(xlsxData);
514
+ const workbook = XLSX.utils.book_new();
515
+ XLSX.utils.book_append_sheet(workbook, worksheet, 'Orders');
516
+
517
+ const fileName = `Orders_${moment().format('DD-MM-YYYY-HH-mm-ss')}.xlsx`;
518
+ XLSX.writeFile(workbook, fileName);
441
519
  }
520
+ ```
521
+
522
+ #### Filtering Data Before Export
523
+
524
+ You can apply additional client-side filters based on user permissions:
525
+
526
+ ```typescript
527
+ downloadTable = async (arrange: Arrange, conditions: Condition[]) => {
528
+ const rawData = await this.tableService.getItemsData('orders', arrange, conditions);
529
+
530
+ // Filter based on user permissions
531
+ const filteredData = rawData.filter(order => {
532
+ if (this.currentUser.role === 'Admin') return true;
533
+ if (this.currentUser.storeId === order.storeId) return true;
534
+ return false;
535
+ });
442
536
 
443
- // Customizar paginador
444
- .mat-mdc-paginator {
445
- background-color: #f9fafb;
537
+ // ... continue with export
446
538
  }
447
539
  ```
448
540
 
449
- ## Performance e Otimização
541
+ #### Using Custom Pipes for Formatting
450
542
 
451
- ### Fallback Client-Side
543
+ Apply Angular pipes to format data in the export:
452
544
 
453
- A biblioteca detecta automaticamente quando uma query necessita de índices compostos no Firestore e usa um fallback client-side para evitar erros. Isso significa que sua aplicação continuará funcionando mesmo sem todos os índices criados.
545
+ ```typescript
546
+ import { DatePipe, CurrencyPipe } from '@angular/common';
547
+
548
+ downloadTable = async (arrange: Arrange, conditions: Condition[]) => {
549
+ const rawData = await this.tableService.getItemsData('products', arrange);
550
+
551
+ const datePipe = new DatePipe('en-US');
552
+ const currencyPipe = new CurrencyPipe('en-US');
454
553
 
455
- ### Rastreamento de Índices Ausentes
554
+ const xlsxData = rawData.map(product => ({
555
+ 'Product': product.name,
556
+ 'Price': currencyPipe.transform(product.price),
557
+ 'Created': datePipe.transform(product.createdAt.toDate(), 'short'),
558
+ 'Status': product.active ? 'Active' : 'Inactive'
559
+ }));
560
+
561
+ // ... continue with export
562
+ }
563
+ ```
564
+
565
+ #### CSV vs XLSX Format
566
+
567
+ ```typescript
568
+ // Export as XLSX (default)
569
+ XLSX.writeFile(workbook, 'data.xlsx');
570
+
571
+ // Export as CSV
572
+ XLSX.writeFile(workbook, 'data.csv', { bookType: 'csv', type: 'binary' });
573
+ ```
456
574
 
457
- O serviço `TableService` rastreia automaticamente queries que precisam de índices e salva as informações na collection `missingIndexes` do Firestore, incluindo:
458
- - Link direto para criar o índice no Firebase Console
459
- - Instruções passo a passo
460
- - Estrutura da query
575
+ #### Important Notes
461
576
 
462
- ## 🤝 Contribuindo
577
+ - The `download` property in `TableData` must be `true` to show the download button
578
+ - `TableService.getItemsData()` returns **all** data matching filters (ignores pagination)
579
+ - The method is `async` because it fetches data from Firestore
580
+ - You control the final file format, column names, and data transformations
581
+ - The library provides the current filter/sort state; you handle the actual file generation
463
582
 
464
- Contribuições são bem-vindas! Por favor, sinta-se à vontade para submeter pull requests.
583
+ ## Powered by KXP Tech
465
584
 
466
- ## 📝 Licença
585
+ Firebase Table KXP was designed inside **KXP Tech** to accelerate data-heavy application development. If you are looking for expert consultancy on Firebase, Angular, or enterprise dashboards, reach out at [kxptech.com](https://kxptech.com).
467
586
 
468
- MIT
587
+ ## Contributing & License
469
588
 
470
- ## 👨‍💻 Autor
589
+ Contributions, feedback, and feature requests are welcome. Fork the repository, open a pull request, or start a discussion on GitHub.
471
590
 
472
- Adryan - [@adryanmmm](https://github.com/adryanmmm)
591
+ This project is released under the MIT License. See the [LICENSE](LICENSE) file for details.
473
592
 
474
- ## 🐛 Reportar Bugs
593
+ ## Support the Project
475
594
 
476
- Se encontrar algum bug, por favor abra uma issue no GitHub.
595
+ If this library saves you time, please star the repository and share it with your team.