Aller au contenu principal

TableManager Organism - Usage Examples

A fully generic, reusable table management component that handles common CRUD operations, search, sorting, pagination, and more.

Features

  • Pagination - Built-in paginator with customizable rows per page
  • Search - Optional search functionality with input field
  • Sorting - Column sorting with reset on reorder mode
  • Row Selection - Multi-select with checkboxes
  • Row Reordering - Drag-and-drop reordering
  • Delete Mode - Bulk delete with selection
  • Publish/Toggle Mode - Bulk publish/unpublish
  • Custom Actions - Add your own action buttons
  • Internationalization - Customizable labels
  • Feature Flags - Enable/disable features as needed
  • Type Safe - Full TypeScript support with generics

Important Note

All data items must have an id field (string or number). This is required for row selection, reordering, and internal tracking.

// ✅ Good - has id field
const data = [
{ id: 1, name: "Item 1" },
{ id: 2, name: "Item 2" },
];

// ❌ Bad - missing id field
const data = [
{ name: "Item 1" },
{ name: "Item 2" },
];

Basic Usage

Minimal Example (Read-only table)

import TableManager from "~/components/organisms/tableManager.organism";

<TableManager
data={items}
columns={[
{ field: "name", header: "Name", sortable: true },
{ field: "email", header: "Email", sortable: true },
]}
currentPage={currentPage}
itemsPerPage={itemsPerPage}
totalRecords={totalRecords}
onPageChange={handlePageChange}
features={{
enableSearch: false,
enableReorder: false,
enablePublish: false,
enableDelete: false,
}}
/>
<TableManager
data={transformedData}
columns={[
{ field: "title", header: "Titre de l'actualité", sortable: true },
{ field: "categories", header: "Catégorie(s)", sortable: true },
{ field: "active", header: "Publication", sortable: true },
{ field: "publicationDate", header: "Date de publication", sortable: true },
{ field: "actions", header: "" },
]}
currentPage={currentPage}
itemsPerPage={itemsPerPage}
totalRecords={data?.total || 0}
onPageChange={handlePageChange}
selectedItems={selectedNews}
onSelectionChange={setSelectedNews}
primaryAction={{
id: "add-news",
icon: "add",
label: "Ajouter une actualité",
onClick: () => navigate(`/modules/${moduleSlug}/créer`),
variant: "primary",
}}
deleteAction={{
icon: "delete",
label: "Supprimer",
onClick: handleDelete,
variant: "danger",
showCount: true,
}}
publishAction={{
icon: "publish",
label: "Publier/Masquer",
onClick: handlePublish,
variant: "danger",
}}
reorderAction={{
onReorder: handleReorder,
onSortOrderChange: setSortOrder,
defaultSortOrder: ["createdAt:asc"],
}}
searchAction={{
onSearchSubmit: handleSearchSubmit,
}}
onCancel={handleCancel}
labels={{
emptyMessage: "Aucune actualité trouvée",
}}
/>

Use Cases

1. Simple Product List (with search and delete only)

<TableManager
data={products}
columns={[
{ field: "name", header: "Product Name", sortable: true },
{ field: "price", header: "Price", sortable: true },
{ field: "stock", header: "Stock", sortable: true },
]}
currentPage={currentPage}
itemsPerPage={itemsPerPage}
totalRecords={totalRecords}
onPageChange={handlePageChange}
selectedItems={selectedProducts}
onSelectionChange={setSelectedProducts}
primaryAction={{
id: "add-product",
icon: "add",
label: "Add Product",
onClick: () => navigate("/products/new"),
}}
deleteAction={{
icon: "delete",
label: "Delete",
onClick: handledeleteMany,
showCount: true,
}}
searchAction={{
onSearchSubmit: handleSearch,
}}
features={{
enableReorder: false,
enablePublish: false,
}}
labels={{
searchPlaceholder: "Search products...",
emptyMessage: "No products found",
}}
/>

2. User Management (with custom actions)

<TableManager
data={users}
columns={[
{ field: "name", header: "Name", sortable: true },
{ field: "email", header: "Email", sortable: true },
{ field: "role", header: "Role", sortable: true },
{ field: "status", header: "Status", sortable: true },
]}
currentPage={currentPage}
itemsPerPage={itemsPerPage}
totalRecords={totalRecords}
onPageChange={handlePageChange}
selectedItems={selectedUsers}
onSelectionChange={setSelectedUsers}
primaryAction={{
id: "invite-user",
icon: "person_add",
label: "Invite User",
onClick: handleInviteUser,
}}
customActions={[
{
id: "export",
icon: "download",
label: "Export",
onClick: handleExport,
},
{
id: "import",
icon: "upload",
label: "Import",
onClick: handleImport,
},
]}
deleteAction={{
icon: "delete",
label: "Delete Users",
onClick: handledeleteMany,
showCount: true,
}}
searchAction={{
onSearchSubmit: handleSearch,
}}
features={{
enableReorder: false,
enablePublish: false,
}}
/>

3. Blog Posts (with reordering and publish)

<TableManager
data={posts}
columns={[
{ field: "title", header: "Title", sortable: true },
{ field: "author", header: "Author", sortable: true },
{ field: "status", header: "Status", sortable: true },
{ field: "date", header: "Date", sortable: true },
]}
currentPage={currentPage}
itemsPerPage={itemsPerPage}
totalRecords={totalRecords}
onPageChange={handlePageChange}
selectedItems={selectedPosts}
onSelectionChange={setSelectedPosts}
primaryAction={{
id: "new-post",
icon: "add",
label: "New Post",
onClick: () => navigate("/posts/new"),
}}
deleteAction={{
icon: "delete",
label: "Delete",
onClick: handleDelete,
showCount: true,
}}
publishAction={{
icon: "publish",
label: "Publish/Unpublish",
onClick: handleTogglePublish,
}}
reorderAction={{
onReorder: handleReorder,
onSortOrderChange: setSortOrder,
defaultSortOrder: ["order:asc"],
}}
searchAction={{
onSearchSubmit: handleSearch,
}}
/>

4. FAQ Management (with custom header/footer content)

<TableManager
data={faqs}
columns={[
{ field: "question", header: "Question", sortable: true },
{ field: "category", header: "Category", sortable: true },
{ field: "active", header: "Active", sortable: true },
]}
currentPage={currentPage}
itemsPerPage={itemsPerPage}
totalRecords={totalRecords}
onPageChange={handlePageChange}
primaryAction={{
id: "add-faq",
icon: "add",
label: "Add FAQ",
onClick: () => navigate("/faqs/new"),
}}
reorderAction={{
onReorder: handleReorder,
onSortOrderChange: setSortOrder,
}}
headerContent={
<div className="flex gap-2">
<select onChange={handleCategoryFilter}>
<option value="">All Categories</option>
<option value="general">General</option>
<option value="technical">Technical</option>
</select>
</div>
}
footerContent={
<div className="text-sm text-gray-600">
Total FAQs: {totalRecords}
</div>
}
/>

Props Reference

Required Props

PropTypeDescription
dataT[]Array of data items to display
columnsColumnConfig[]Column definitions
currentPagenumberCurrent page (1-indexed)
itemsPerPagenumberItems per page
totalRecordsnumberTotal number of records
onPageChangefunctionPage change handler

Optional Props

PropTypeDefaultDescription
selectedItemsRecord<string, boolean>{}Selected items
onSelectionChangefunction-Selection change handler
primaryActionActionButton-Primary action button config
customActionsActionButton[][]Custom action buttons
deleteActionModeAction-Delete action config
publishActionModeAction-Publish action config
reorderActionReorderConfig-Reorder action config
searchActionSearchConfig-Search action config
onCancelfunction-Cancel handler
featuresFeatureFlagsAll enabledFeature toggles
labelsLabelsFrench defaultsCustom labels
stripedRowsbooleantrueStriped row styling
rowsPerPageOptionsnumber[][10,20,50,100]Rows per page options
headerContentReactNode-Custom header content
footerContentReactNode-Custom footer content

Internationalization

<TableManager
// ... other props
labels={{
searchPlaceholder: "Search...",
searchLabel: "Search",
reorderLabel: "Reorder",
publishLabel: "Publish/Unpublish",
deleteLabel: "Delete",
cancelLabel: "Cancel",
emptyMessage: "No data found",
}}
/>

Feature Flags

<TableManager
// ... other props
features={{
enableSearch: true, // Show search button
enableReorder: true, // Show reorder button
enablePublish: true, // Show publish button
enableDelete: true, // Show delete button
enableCustomActions: true, // Show custom actions
}}
/>

Best Practices

  1. Always provide meaningful labels for better UX
  2. Use feature flags to disable unused functionality
  3. Keep data transformation in parent component
  4. Handle errors in action callbacks
  5. Provide confirmation dialogs for destructive actions
  6. Use TypeScript generics for type safety: <TableManager<MyDataType>>