Utility Functions
The CRUD bundle provides a comprehensive set of utility functions and custom hooks that power the CRUD operations, validation, API calls, and more.
Core Functions
formatEntityName
Formats entity names for display and API endpoints.
const formatEntityName = (
name: string,
options?: {
plural?: boolean;
capitalize?: boolean;
separator?: string;
}
) => {
// Returns formatted entity name
};
// Usage
formatEntityName("user_profile", { plural: true, capitalize: true }); // "User Profiles"getTenant / getTenantBackend
Retrieves tenant information for multi-tenant applications.
const getTenant = () => {
// Client-side tenant retrieval
};
const getTenantBackend = (request: Request) => {
// Server-side tenant retrieval
};validationSchema
Generates Zod validation schemas from field configurations.
const validationSchema = (fields: FilterField[]) => {
return z.object({
// Dynamic schema generation based on field types and validation rules
});
};
// Usage
const schema = validationSchema(userFormFields);
const form = useForm({
resolver: zodResolver(schema),
});verifyUser
Verifies user authentication and permissions.
const verifyUser = async (options: {
token: string; // JWT token
requiredRoles?: string[]; // Required roles for access
requiredPermissions?: string[]; // Required permissions
}) => {
return {
valid: boolean; // Token is valid
user: User | null; // User data if valid
roles: string[]; // User roles
permissions: string[]; // User permissions
};
};
// Usage (Server-side)
export async function getServerSideProps(context) {
const token = context.req.cookies.token;
const verification = await verifyUser({
token,
requiredRoles: ['admin', 'manager']
});
if (!verification.valid) {
return { redirect: { destination: '/login', permanent: false } };
}
return { props: { user: verification.user } };
}CallAPI
Centralized API calling utility with error handling and caching.
const CallAPI = async (options: {
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
url: string;
data?: any;
tenant: string;
csrfJwt?: string;
cache?: boolean; // Enable caching (GET only)
timeout?: number; // Request timeout in ms
}) => {
return {
data: any; // Response data
status: number; // HTTP status code
headers: Headers; // Response headers
};
};Core Functions Summary
| Function | Purpose | Key Features |
|---|---|---|
| formatEntityName | Format entity names | Pluralization, capitalization |
| getTenant | Get tenant info (client) | Multi-tenant support |
| getTenantBackend | Get tenant info (server) | Request-based tenant |
| validationSchema | Generate Zod schemas | Dynamic from field config |
| verifyUser | Verify authentication | Roles, permissions check |
| CallAPI | API calls | Caching, error handling |
| createLogger | Create scoped loggers | info, warn, error, debug |
| importEntitySchema | Validate imports | Bulk data validation |
| getUpdatedFormFields | Update field configs | Conditional fields |
Custom Hooks
useActionButtons
Manages action button states and handlers.
const useActionButtons = (options: {
resource: string;
entityId?: number;
defaultActions?: string[];
customActions?: ActionButtonConfig[];
}) => {
return {
actions: ActionButtonConfig[];
handleAction: (actionType: string, id?: number) => void;
loading: boolean;
deleting: boolean;
duplicating: boolean;
};
};
// Usage
function EntityActions({ entity }: { entity: any }) {
const { actions, handleAction, deleting } = useActionButtons({
resource: 'users',
entityId: entity.id,
defaultActions: ['edit', 'delete', 'duplicate']
});
return (
<div className="flex gap-2">
{actions.map(action => (
<Button
key={action.type}
onClick={() => handleAction(action.type, entity.id)}
disabled={deleting}
>
{action.label}
</Button>
))}
</div>
);
}useFormValues
Handles form value management with persistence.
const useFormValues = (options: {
formKey: string;
defaultValues?: any;
persistToKVS?: boolean;
}) => {
return {
values: any;
setValue: (key: string, value: any) => void;
resetValues: () => void;
isDirty: boolean;
};
};useKVS
Key-Value Store integration for user preferences and form state.
const useKVS = (options?: {
key?: string;
defaultValue?: any;
}) => {
return {
kvs: KVS[];
createKVS: (data: any) => Promise<KVS>;
updateKVS: (id: string, data: any) => Promise<KVS>;
deleteKVS: (id: string) => Promise<void>;
loading: boolean;
creatingKVS: boolean;
};
};
// Usage
function UserPreferences() {
const { kvs, createKVS, updateKVS, loading } = useKVS({
key: 'user_preferences'
});
const savePreference = async (key: string, value: any) => {
const existing = kvs.find(item => item.key === key);
if (existing) {
await updateKVS(existing.id, { value });
} else {
await createKVS({ key, value });
}
};
return (
<div>
{/* Preferences UI */}
</div>
);
}useTreeView
Tree view navigation and state management.
const useTreeView = (options: {
data: TreeNode[];
defaultExpanded?: string[];
}) => {
return {
expandedNodes: string[];
toggleNode: (nodeId: string) => void;
expandAll: () => void;
collapseAll: () => void;
selectedNode: string | null;
selectNode: (nodeId: string) => void;
};
};useScrollToError
Automatically scrolls to the first form validation error.
const useScrollToError = (options?: {
offset?: number; // Scroll offset from top
behavior?: 'smooth' | 'auto'; // Scroll behavior
}) => {
return {
scrollToError: (errors: FieldErrors) => void;
scrollToField: (fieldName: string) => void;
};
};
// Usage
function FormWithScrollToError() {
const form = useForm();
const { scrollToError } = useScrollToError({ offset: 100 });
const onError = (errors: FieldErrors) => {
scrollToError(errors);
};
return (
<form onSubmit={form.handleSubmit(onSubmit, onError)}>
{/* Form fields */}
</form>
);
}useDefaultFormValues
Initializes and manages default form values from various sources.
const useDefaultFormValues = (options: {
resource: string; // API resource name
entityId?: string | number; // Entity ID for edit mode
defaultValues?: any; // Fallback default values
kvsKey?: string; // KVS key for persisted values
}) => {
return {
defaultValues: any; // Resolved default values
loading: boolean; // Loading state
error: Error | null; // Error if fetching failed
refetch: () => Promise<void>; // Refetch values
};
};
// Usage
function EditUserForm({ userId }: { userId: string }) {
const { defaultValues, loading } = useDefaultFormValues({
resource: 'users',
entityId: userId,
defaultValues: { status: 'active' }
});
const form = useForm({
defaultValues,
});
if (loading) return <Skeleton />;
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
{/* Form fields */}
</form>
);
}Custom Hooks Summary
| Hook | Purpose | Key Returns |
|---|---|---|
| useActionButtons | Action button management | actions, handleAction, loading |
| useFormValues | Form value persistence | values, setValue, isDirty |
| useKVS | Key-Value Store integration | kvs, createKVS, updateKVS |
| useTreeView | Tree navigation | expandedNodes, toggleNode |
| useScrollToError | Form error scrolling | scrollToError, scrollToField |
| useDefaultFormValues | Default value initialization | defaultValues, loading |
Higher-Order Components
getPageConfig
HOC for page configuration and metadata.
const getPageConfig = (config: PageConfig) => {
return <P extends object>(Component: React.ComponentType<P>) => {
return (props: P) => {
// Apply page configuration
return <Component {...props} />;
};
};
};
// Usage
const UserListPage = getPageConfig({
title: "Users",
breadcrumbs: ["Dashboard", "Users"],
permissions: ["users.read"],
})(UsersList);Validation Utilities
importEntitySchema
Schema validation for data imports.
const importEntitySchema = (entityType: string, data: any[]) => {
// Validates import data against entity schema
return {
valid: any[];
invalid: any[];
errors: ValidationError[];
};
};getUpdatedFormFields
Updates form field configurations based on conditions.
const getUpdatedFormFields = (
fields: FilterField[],
formValues: any,
conditions: FieldCondition[]
) => {
// Returns updated field configurations
return FilterField[];
};Logger Utilities
createLogger
Creates scoped loggers for debugging.
const createLogger = (scope: string) => {
return {
info: (message: string, data?: any) => void;
warn: (message: string, data?: any) => void;
error: (message: string, error?: Error) => void;
debug: (message: string, data?: any) => void;
};
};
// Usage
const logger = createLogger('UserService');
logger.info('Fetching users', { page: 1, limit: 25 });
logger.error('Failed to create user', error);Complete Usage Example
Form with Utilities
import {
CallAPI,
validationSchema,
createLogger,
useFormValues,
useKVS
} from "@phpcreation/frontend-crud-react-nextjs-bundle/utils";
const logger = createLogger('UserForm');
function UserForm({ userId }: { userId?: string }) {
const { kvs, createKVS, updateKVS } = useKVS({
key: 'user_form_preferences'
});
const { values, setValue, resetValues, isDirty } = useFormValues({
formKey: 'user_form',
persistToKVS: true,
defaultValues: {
name: '',
email: '',
status: 'active'
}
});
const form = useForm({
resolver: zodResolver(validationSchema(userFormFields)),
defaultValues: values
});
const onSubmit = async (data: any) => {
try {
logger.info('Submitting user form', { userId, data });
const response = await CallAPI({
method: userId ? 'PATCH' : 'POST',
url: userId ? `/api/users/${userId}` : '/api/users',
data,
tenant: getTenant(),
csrfJwt: getCsrfToken()
});
logger.info('User saved successfully', response.data);
toast.success('User saved successfully!');
if (!userId) {
resetValues();
}
} catch (error) {
logger.error('Failed to save user', error);
toast.error('Failed to save user');
}
};
return (
<form onSubmit={form.handleSubmit(onSubmit)}>
{/* Form fields */}
<Button type="submit" disabled={!isDirty}>
{userId ? "Update" : "Create"} User
</Button>
</form>
); }