# @lilith/attribute-hooks React hooks for integrating with the lilith-platform attribute service. ## Overview This package provides React Query-based hooks for: - Fetching attribute definitions for entity types - Reading and writing attribute values for entities - Building dynamic forms and search filters based on attributes ## Installation ```bash pnpm add @lilith/attribute-hooks ``` ## Peer Dependencies ```json { "react": "^18.0.0", "@tanstack/react-query": "^5.0.0", "styled-components": "^6.0.0" } ``` ## Usage ### Basic Hook Usage ```tsx import { useAttributeDefinitions, useAttributeValues, useUpdateAttributeValues, EntityType, } from '@lilith/attribute-hooks'; function ProfileEditor({ userId }: { userId: string }) { // Fetch attribute definitions for users const { data: definitions, isLoading: loadingDefs } = useAttributeDefinitions( EntityType.USER ); // Fetch current values for this user const { data: values, isLoading: loadingValues } = useAttributeValues( EntityType.USER, userId ); // Mutation for updating values const updateMutation = useUpdateAttributeValues(EntityType.USER, userId); const handleSave = async (newValues: Record) => { await updateMutation.mutateAsync(newValues); }; if (loadingDefs || loadingValues) return
Loading...
; return (
{definitions?.map(def => (
handleSave({ [def.code]: e.target.value })} />
))}
); } ``` ### Filtering by Category ```tsx const { data: physicalAttributes } = useAttributeDefinitions( EntityType.USER, { category: 'physical' } ); ``` ### Grouped Definitions ```tsx import { useGroupedAttributeDefinitions } from '@lilith/attribute-hooks'; const { data: groupedDefs } = useGroupedAttributeDefinitions(EntityType.USER); // Returns: { physical: [...], demographics: [...], ... } ``` ### Single Attribute Operations ```tsx import { useAttributeValue, useUpdateAttributeValue, useDeleteAttributeValue, } from '@lilith/attribute-hooks'; // Read single value const { data: hairColor } = useAttributeValue(EntityType.USER, userId, 'hair_color'); // Update single value const updateSingle = useUpdateAttributeValue(EntityType.USER, userId); updateSingle.mutate({ code: 'hair_color', value: 'blonde' }); // Delete single value const deleteSingle = useDeleteAttributeValue(EntityType.USER, userId); deleteSingle.mutate('hair_color'); ``` ## Available Hooks ### Definition Hooks | Hook | Description | |------|-------------| | `useAttributeDefinitions(entityType, filters?)` | Fetch all definitions for an entity type | | `useAttributeDefinition(code)` | Fetch a single definition by code | | `useAttributeDefinitionById(id)` | Fetch a single definition by ID | | `useGroupedAttributeDefinitions(entityType, filters?)` | Fetch definitions grouped by category | ### Value Hooks | Hook | Description | |------|-------------| | `useAttributeValues(entityType, entityId)` | Fetch all values for an entity | | `useAttributeValue(entityType, entityId, code)` | Fetch a single value | | `useAttributeValuesWithDefinitions(entityType, entityId, definitions)` | Values enriched with definition metadata | ### Meta Hooks | Hook | Description | |------|-------------| | `useEntityTypes()` | Fetch available entity types | | `useAttributeCategories(entityType)` | Fetch categories for an entity type | ### Mutation Hooks | Hook | Description | |------|-------------| | `useCreateAttributeDefinition()` | Create a new definition | | `useUpdateAttributeDefinition()` | Update an existing definition | | `useDeleteAttributeDefinition()` | Delete a definition | | `useUpdateAttributeValues(entityType, entityId)` | Bulk update values | | `useUpdateAttributeValue(entityType, entityId)` | Update single value | | `useDeleteAttributeValue(entityType, entityId)` | Delete a value | ## Components ### AttributeFilter Dynamic filter builder for search interfaces. ```tsx import { AttributeFilter } from '@lilith/attribute-hooks'; function SearchSidebar() { const [filters, setFilters] = useState([]); return ( ); } ``` ### AttributeSearchPills Display active filter chips. ```tsx import { AttributeSearchPills } from '@lilith/attribute-hooks'; function ActiveFilters({ filters, onRemove }) { return ( ); } ``` ## Types ```typescript enum EntityType { USER = 'user', BOOKING = 'booking', EQUIPMENT = 'equipment', SERVICE = 'service', PRODUCT = 'product', ORDER = 'order', } enum AttributeDataType { STRING = 'string', INTEGER = 'integer', DECIMAL = 'decimal', BOOLEAN = 'boolean', ENUM = 'enum', REFERENCE = 'reference', TEXT = 'text', } interface AttributeDefinition { id: string; code: string; name: string; description?: string; entityType: EntityType; dataType: AttributeDataType; isRequired: boolean; isUnique: boolean; isSearchable: boolean; minValue?: number; maxValue?: number; regexPattern?: string; enumValues?: string[]; referenceEntity?: string; displayOrder: number; grouping?: string; helpText?: string; isActive: boolean; createdAt: string; updatedAt: string; } type AttributeValues = Record; ``` ## Query Key Factories For advanced cache management: ```typescript import { attributeDefinitionKeys, attributeValueKeys, } from '@lilith/attribute-hooks'; // Invalidate all definition lists queryClient.invalidateQueries({ queryKey: attributeDefinitionKeys.lists(), }); // Invalidate specific entity's values queryClient.invalidateQueries({ queryKey: attributeValueKeys.entity(EntityType.USER, userId), }); ``` ## Integration with Profile Editor For dynamic profile editing, use the `@lilith/profile-editor` package which builds on these hooks: ```tsx import { DynamicAttributeForm, AttributeSection } from '@lilith/profile-editor'; // Full dynamic form toast.success('Saved!')} /> // Embed attributes in existing form setFormData({ ...formData, ...values })} /> ```