Skip to Content
FrontendBundlesCRUDEntity Management Components

Entity Management Components

The CRUD bundle provides a comprehensive set of components for managing entity lifecycle operations including creation, editing, viewing, and deletion. These components work seamlessly with the DetailShowContext and form handling systems.


Core Architecture

DetailShowContext

Entity management components rely on the DetailShowContext for state management:

interface DetailShowContextProps { // Data Management data: any; // Current entity data loading: boolean; // Loading state fetchData: () => void; // Data fetching function // Page Management managingPage: boolean; // Page customization mode setManagingPage: (value: boolean) => void; // Toggle page management // Translations managingTranslations: boolean; // Translation management mode setManagingTranslations: (value: boolean) => void; // Toggle translation mode // UI Configuration fieldsConfiguration: any[]; // Field display configuration sectionsConfiguration: any[]; // Section layout configuration }

Component Overview

1. AddEntityForm

Form component for creating new entities with comprehensive validation and field rendering.

Props

type AddEntityFormProps = { formInputs: FormInput[]; // Form field definitions fqcn_bui: IFQCN_BUI; // Component configuration resource: string; // API resource name translatable: boolean; // Enable multi-language support kvs: { // Key-Value Store integration createKVS: any; // Create KVS function kvs: any[]; // KVS data array creatingKVS: boolean; // KVS creation loading state loading: boolean; // KVS loading state updateKVS: any; // Update KVS function }; form: any; // React Hook Form instance user: User | null; // Current user csrfJwt: string; // CSRF token tenant: string; // Tenant identifier locale: string; // Locale for translations };

Form Input Configuration

interface FormInput { title: string; // Section title fields: FilterField[]; // Array of fields in this section }

Features

  • Dynamic Field Rendering: Supports 15+ field types
  • Real-time Validation: Zod schema validation with live feedback
  • Form State Persistence: Auto-save form values to KVS
  • Multi-language Support: Translatable field values
  • Keyboard Shortcuts: Ctrl+S to save, Esc to cancel
  • Dependent Fields: Fields that change based on other field values
  • Conditional Display: Show/hide fields based on conditions
  • File Upload: Integrated file upload with preview

Usage Example

import { AddEntityForm, ContextualAddPageFooter, } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; const formInputs: FormInput[] = [ { title: "General", fields: [ { title: "Username", key: "username", type: ColumnTypeEnum.TEXT, placeholder: "Input the Username", required: true, }, { title: "Email", key: "email", type: ColumnTypeEnum.TEXT, placeholder: "Input the Email", required: true, }, { title: "Last Login", key: "lastLogin", type: ColumnTypeEnum.DATETIME, placeholder: "Input the Last Login", required: false, }, { title: "Landing Page Url", key: "landingPageUrl", type: ColumnTypeEnum.TEXT, placeholder: "Input the Landing Page Url", required: false, }, { title: "Email Auth Code Enabled", key: "emailAuthCodeEnabled", type: ColumnTypeEnum.BOOLEAN, placeholder: "Select the Email Auth Code Enabled", required: true, }, { title: "Is Verified", key: "isVerified", type: ColumnTypeEnum.BOOLEAN, placeholder: "Select the Is Verified", required: true, }, { title: "First Name", key: "firstName", type: ColumnTypeEnum.TEXT, placeholder: "Input the First Name", required: false, }, { title: "Last Name", key: "lastName", type: ColumnTypeEnum.TEXT, placeholder: "Input the Last Name", required: true, }, { title: "Phone Number", key: "phoneNumber", type: ColumnTypeEnum.TEXT, placeholder: "Input the Phone Number", required: false, }, ], }, ]; function CreateUserPage() { const form = useForm({ resolver: zodResolver(validationSchema), defaultValues: { name: "", email: "", department_id: null, avatar: null, bio: "", }, }); const handleSuccess = (data: any) => { toast.success("User created successfully!"); router.push(`/users/${data.id}`); }; return ( <div className="max-w-4xl mx-auto p-6"> <div className="bg-white rounded-lg shadow-md p-6"> <h1 className="text-2xl font-bold mb-6">Create New User</h1> <AddEntityForm formInputs={formInputs} fqcn_bui={{ Bundle: "user", Unit: "management", Interface: "create" }} resource="users" translatable={true} kvs={useKVS} form={form} kvsKey="user_create_form" user={user} tenant={tenant} csrfJwt={csrfToken} locale="en" onSuccess={handleSuccess} /> <ContextualAddPageFooter fqcn_bui={fqcn_bui} resource="users" kvs={useKVS} form={form} kvsKey="user_create_form" user={user} locale="en" /> </div> </div> ); }

2. EditEntityForm

Form component for editing existing entities with pre-populated data and update functionality.

Props

type EditEntityFormProps = { formInputs: FormInput[]; // Form field definitions fqcn_bui: IFQCN_BUI; // Component configuration resource: string; // API resource name data: Record<string, any>; // Pre-populated entity data translatable?: boolean; // Enable multi-language support qField: string; // Query field for updates (usually "id") csrfJwt: string; // CSRF token tenant: string; // Tenant identifier locale: string; // Locale for translations };

Features

  • Pre-populated Fields: Automatically fills form with existing data
  • Patch Updates: Only sends changed fields to API
  • Optimistic Updates: UI updates before API confirmation
  • Keyboard Shortcuts: Alt+Enter to save, Esc to cancel
  • Dirty Field Tracking: Highlights modified fields
  • Auto-save Draft: Periodically saves changes to prevent data loss

Usage Example

import { EditEntityForm } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; function EditUserPage({ userId }: { userId: string }) { const [userData, setUserData] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { // Fetch user data fetchUserData(userId).then((data) => { setUserData(data); setLoading(false); }); }, [userId]); if (loading) return <div>Loading...</div>; return ( <div className="max-w-4xl mx-auto p-6"> <div className="bg-white rounded-lg shadow-md p-6"> <h1 className="text-2xl font-bold mb-6">Edit User</h1> <EditEntityForm formInputs={formInputs} fqcn_bui={{ Bundle: "user", Unit: "management", Interface: "edit" }} resource="users" data={userData} translatable={true} qField="id" csrfJwt={csrfToken} tenant={tenant} locale="en" onSuccess={() => { toast.success("User updated successfully!"); router.push(`/users/${userId}`); }} /> </div> </div> ); }

3. GeneralDetails

Component for displaying entity details in a structured, customizable layout with translation support.

Props

type GeneralDetailsProps = { detailsInfo: { [key: string]: string }[]; // Details data array resource: string; // API resource name sectionTitle: string; // Section title id?: number; // Entity ID handleRemoveSection: (section: string) => void; // Remove section callback handleRemoveField: (sectionTitle: string, field: string) => void; // Remove field callback loadingKVS?: boolean; // KVS loading state fqcn_bui: IFQCN_BUI; // Component configuration locale: string; // Locale for translations updateTranslations: (translations: { key?: string; value: string }) => void; // Update translations user: User | null; // Current user };

Field Display Configuration

interface DetailField { field: string; // Data field path (supports nested: "user.name") label: string; // Display label type: ColumnTypeEnum; // Display type format?: string; // Format string (for dates, numbers) render?: (value: any, data: any) => ReactNode; // Custom renderer translatable?: boolean; // Can be translated editable?: boolean; // Inline editing copyable?: boolean; // Show copy button linkable?: boolean; // Make clickable link conditional?: { // Conditional display field: string; value: any; }; }

Features

  • Nested Field Support: Display nested object properties
  • Custom Renderers: Custom display logic for specific fields
  • Inline Translation: Edit translations directly from view
  • Copy to Clipboard: Copy field values with single click
  • Anchor Links: Automatic anchor links for sections
  • Responsive Layout: Adapts to different screen sizes
  • Field Management: Add/remove fields in management mode

Usage Example

import { GeneralDetails, DetailedShowContextProvider, } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; const detailsConfig = [ { field: "id", label: "User ID", type: ColumnTypeEnum.NUMBER, }, { field: "name", label: "Full Name", type: ColumnTypeEnum.TEXT, translatable: true, }, { field: "email", label: "Email Address", type: ColumnTypeEnum.EMAIL, }, { field: "created_at", label: "Created Date", type: ColumnTypeEnum.DATE, }, ]; function UserDetailsSection() { const handleRemoveSection = (section: string) => { // Handle section removal }; const handleRemoveField = (sectionTitle: string, field: string) => { // Handle field removal }; const updateTranslations = (translations: any) => { // Handle translation updates }; return ( <DetailedShowContextProvider> <GeneralDetails detailsInfo={detailsConfig} resource="users" sectionTitle="General Information" id={1} handleRemoveSection={handleRemoveSection} handleRemoveField={handleRemoveField} fqcn_bui={fqcn_bui} locale="en" updateTranslations={updateTranslations} user={user} /> </DetailedShowContextProvider> ); }

4. DetailShowHeader

Simple header component displaying entity title with loading state.

Props

interface DetailShowHeaderProps { // Uses DetailShowContext automatically - no props needed }

Features

  • Auto Title: Displays entity’s toString field
  • Loading State: Shows skeleton while data loads
  • Responsive Design: Adapts to container width

Usage Example

import { DetailShowHeader } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; function UserDetailPage() { return ( <DetailedShowContextProvider> <div className="bg-white rounded-lg shadow-md"> <div className="p-6 border-b"> <DetailShowHeader /> </div> {/* Rest of detail view */} </div> </DetailedShowContextProvider> ); }

5. ShowHeaderActions

Comprehensive action buttons for entity detail views with customizable actions.

Props

type ShowHeaderActionsProps = { fqcn_bui: IFQCN_BUI; // Component configuration resource: string; // API resource name defaultActions: string[]; // Default enabled actions fields?: DisplayField[]; // Field configuration for actions user: User | null; // Current user locale: string; // Locale for translations tenant: string; // Tenant identifier csrfJwt: string; // CSRF token // Customization Options customActions?: ActionButtonConfig[]; // Additional custom actions customDropdowns?: ActionDropdownConfig[]; // Custom dropdown menus hiddenActions?: ActionType[]; // Actions to hide visibleActions?: ActionType[]; // Only show these actions onCustomAction?: (actionType: string, id?: number) => void; // Custom action handler showTooltips?: boolean; // Show action tooltips containerClass?: string; // Custom container CSS buttonSize?: "sm" | "md" | "lg"; // Button size showDropdown?: boolean; // Show actions dropdown };

Available Actions

  • Edit: Navigate to edit form
  • Delete: Delete entity with confirmation
  • Duplicate: Create copy of entity
  • Print: Print current view
  • Export: Export entity data
  • Share: Share entity link
  • Archive: Archive/unarchive entity
  • Flag: Mark as featured/default

Custom Action Configuration

interface ActionButtonConfig { type: string; // Action identifier label: string; // Button label icon: ReactNode; // Button icon variant?: ButtonVariant; // Button style onClick: (id?: number) => void; // Click handler condition?: (data: any) => boolean; // Show condition tooltip?: string; // Tooltip text } interface ActionDropdownConfig { label: string; // Dropdown label items: ActionButtonConfig[]; // Dropdown items }

Usage Example

import { ShowHeaderActions } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; import { FiArchive, FiSend } from "react-icons/fi"; function UserDetailActions() { const customActions: ActionButtonConfig[] = [ { type: "archive", label: "Archive User", icon: <FiArchive />, variant: "outline", onClick: (id) => handleArchiveUser(id), condition: (data) => data.status === "active", tooltip: "Archive this user account", }, { type: "send_email", label: "Send Email", icon: <FiSend />, variant: "default", onClick: (id) => handleSendEmail(id), tooltip: "Send email to user", }, ]; const customDropdowns: ActionDropdownConfig[] = [ { label: "Admin Actions", items: [ { type: "reset_password", label: "Reset Password", icon: <FiKey />, onClick: (id) => handleResetPassword(id), }, { type: "impersonate", label: "Impersonate User", icon: <FiUser />, onClick: (id) => handleImpersonate(id), }, ], }, ]; return ( <ShowHeaderActions fqcn_bui={fqcn_bui} resource="users" defaultActions={["edit", "delete", "duplicate"]} user={user} locale="en" tenant={tenant} csrfJwt={csrfToken} customActions={customActions} customDropdowns={customDropdowns} hiddenActions={["archive"]} // Hide if using custom archive action showTooltips={true} buttonSize="md" showDropdown={true} onCustomAction={handleCustomAction} /> ); }

6. ContextualAddPageFooter

Footer component for add/edit forms with save functionality and form state management.

Props

interface ContextualAddPageFooterProps { fqcn_bui: IFQCN_BUI; // Component configuration resource: string; // API resource name kvs: { // Key-Value Store integration createKVS: any; // Create KVS function kvs: any[]; // KVS data array creatingKVS: boolean; // KVS creation loading state loading: boolean; // KVS loading state updateKVS: any; // Update KVS function }; form: any; // React Hook Form instance kvsKey: string; // KVS key for form persistence user: User | null; // Current user locale: string; // Locale for translations }

Features

  • Auto-save: Automatically saves form values to KVS
  • Print Support: Print current form state
  • Settings Integration: Save form layout preferences
  • Loading States: Visual feedback during operations

Complete Implementation Example

Here’s a complete example showing how to build a full entity management interface:

import React from 'react'; import { useRouter } from 'next/navigation'; import { DetailedShowContextProvider, DetailShowHeader, ShowHeaderActions, GeneralDetails, AddEntityForm, EditEntityForm, ContextualAddPageFooter } from "@phpcreation/frontend-crud-react-nextjs-bundle/components"; interface UserCRUDProps { mode: 'create' | 'edit' | 'view'; userId?: string; user: User | null; tenant: string; csrfJwt: string; } export default function UserCRUD({ mode, userId, user, tenant, csrfJwt }: UserCRUDProps) { const router = useRouter(); const [userData, setUserData] = useState(null); const [loading, setLoading] = useState(mode !== 'create'); const fqcn_bui = { Bundle: "user", Unit: "management", Interface: mode }; // Fetch user data for edit/view modes useEffect(() => { if (mode !== 'create' && userId) { fetchUserData(userId).then(data => { setUserData(data); setLoading(false); }); } }, [mode, userId]); const formInputs: FormInput[] = [ { key: "name", label: "Full Name", type: ColumnTypeEnum.TEXT, required: true, grid: { xs: 12, md: 6 } }, { key: "email", label: "Email", type: ColumnTypeEnum.EMAIL, required: true, grid: { xs: 12, md: 6 } }, { key: "department_id", label: "Department", type: ColumnTypeEnum.SELECT_ASYNC, apiEndpoint: "/api/departments/dropdown", grid: { xs: 12, md: 6 } }, { key: "status", label: "Status", type: ColumnTypeEnum.SELECT, options: [ {label: "Active", value: "active"}, {label: "Inactive", value: "inactive"} ], grid: { xs: 12, md: 6 } } ]; const detailsConfig = [ { field: "id", label: "User ID", type: ColumnTypeEnum.NUMBER }, { field: "name", label: "Full Name", type: ColumnTypeEnum.TEXT }, { field: "email", label: "Email", type: ColumnTypeEnum.EMAIL }, { field: "department.name", label: "Department", type: ColumnTypeEnum.TEXT }, { field: "status", label: "Status", type: ColumnTypeEnum.SELECT }, { field: "created_at", label: "Created", type: ColumnTypeEnum.DATETIME } ]; if (loading) return <div>Loading...</div>; return ( <div className="max-w-6xl mx-auto p-6"> <div className="bg-white rounded-lg shadow-md"> {/* Header */} <div className="p-6 border-b flex justify-between items-center"> {mode === 'create' ? ( <h1 className="text-2xl font-bold">Create New User</h1> ) : ( <DetailedShowContextProvider> <DetailShowHeader /> {mode === 'view' && ( <ShowHeaderActions fqcn_bui={fqcn_bui} resource="users" defaultActions={["edit", "delete", "duplicate"]} user={user} locale="en" tenant={tenant} csrfJwt={csrfJwt} /> )} </DetailedShowContextProvider> )} </div> {/* Content */} <div className="p-6"> {mode === 'create' && ( <> <AddEntityForm formInputs={formInputs} fqcn_bui={fqcn_bui} resource="users" translatable={true} kvs={useKVS} form={form} kvsKey="user_create_form" user={user} tenant={tenant} csrfJwt={csrfJwt} locale="en" onSuccess={(data) => { toast.success("User created successfully!"); router.push(`/users/${data.id}`); }} /> <ContextualAddPageFooter fqcn_bui={fqcn_bui} resource="users" kvs={useKVS} form={form} kvsKey="user_create_form" user={user} locale="en" /> </> )} {mode === 'edit' && userData && ( <EditEntityForm formInputs={formInputs} fqcn_bui={fqcn_bui} resource="users" data={userData} translatable={true} qField="id" csrfJwt={csrfJwt} tenant={tenant} locale="en" onSuccess={() => { toast.success("User updated successfully!"); router.push(`/users/${userId}`); }} /> )} {mode === 'view' && ( <DetailedShowContextProvider> <GeneralDetails detailsInfo={detailsConfig} resource="users" sectionTitle="User Information" handleRemoveSection={() => {}} handleRemoveField={() => {}} fqcn_bui={fqcn_bui} locale="en" updateTranslations={() => {}} user={user} /> </DetailedShowContextProvider> )} </div> </div> </div> ); }

Best Practices

Form Handling - Always use React Hook Form with Zod validation - Implement

proper error handling and user feedback - Use KVS for form state persistence in long forms - Provide keyboard shortcuts for better UX

Data Management - Always validate data before submission - Handle loading

states appropriately - Implement optimistic updates for better UX - Use proper error boundaries


Advanced Customization

Custom Field Types

// Register custom field renderer const customFieldRenderer = (field: FormInput, form: any) => { if (field.type === "color_picker") { return ( <ColorPicker value={form.watch(field.key)} onChange={(color) => form.setValue(field.key, color)} /> ); } return null; };

Custom Validation

const customValidationSchema = z.object({ name: z.string().min(2, "Name must be at least 2 characters"), email: z.string().email("Invalid email format"), department_id: z.number().min(1, "Department is required"), custom_field: z .string() .refine((value) => validateCustomField(value), "Custom validation failed"), });

This comprehensive documentation covers all entity management components with detailed props, usage examples, and advanced customization options.

Last updated on