Skip to Content
✨ Special Features

Special Features

Dynamic Form State Management with ID Assignment

Overview

Sitepins implements a sophisticated form state management system that uses unique ID assignment to handle complex, dynamic forms with nested objects, arrays, and real-time updates. This system ensures React’s reconciliation works correctly while maintaining clean data for persistence.

The ID Assignment System

Core Functions:

  • assignUniqueId(): Adds unique IDs to form data for UI operations
  • revertToOriginal(): Removes IDs before saving to backend/Git
  • uuid(): Generates cryptographically secure unique identifiers

Why We Add IDs

1. React Key Management

// Each dynamic form field needs a stable key for React's reconciliation { formFields.map((field) => <FormField key={field.id} {...field} />); }

2. Dynamic Array Operations

  • Users can add/remove/reorder array items in real-time
  • Each array item needs a unique identifier for tracking changes
  • Enables smooth animations and state preservation during operations

3. Complex Nested State

// Example: Blog post with dynamic tags array const blogPost = { title: { id: "uuid-1", value: "My Blog Post" }, tags: [ { id: "uuid-2", value: "react" }, { id: "uuid-3", value: "typescript" }, ], author: { id: "uuid-4", value: { name: { id: "uuid-5", value: "John Doe" }, email: { id: "uuid-6", value: "john@example.com" }, }, }, };

4. Optimistic Updates

  • IDs allow tracking which specific fields are being updated
  • Enables optimistic UI updates before server confirmation
  • Maintains form state during async operations

Why We Remove IDs

1. Clean Data Persistence

// Before saving to Git/backend, remove UI-specific IDs const cleanData = revertToOriginal(formData); // Result: { title: "My Blog Post", tags: ["react", "typescript"] }

2. Data Integrity

  • Ensures consistent data structure across environments
  • Prevents conflicts when multiple users edit same content
  • Maintains backward compatibility with existing content

Complete Workflow

Step-by-Step Process:

  1. Load Phase
// Load content from Git/API const rawContent = await fetchContent(); // Add IDs for UI operations const formData = assignUniqueId(rawContent);
  1. Edit Phase
// User interacts with form fields // React uses IDs for efficient reconciliation // State updates maintain component focus and animations
  1. Save Phase
// Remove IDs before persistence const cleanData = revertToOriginal(formData); // Save to backend/Git await saveContent(cleanData);

Implementation Details

ID Assignment Logic:

export function assignUniqueId(input: any): any { if (Array.isArray(input)) { return input.map((item) => { if (typeof item === "object") { return { id: uuid(), value: assignUniqueId(item), }; } return assignUniqueId(item); }); } if (typeof input === "object" && input !== null) { return Object.keys(input).reduce((acc, key) => { const value = input[key]; if (value instanceof Date) { return { ...acc, [key]: { id: uuid(), value: new ISODate(value.toISOString()), }, }; } return { ...acc, [key]: { value: typeof value === "object" ? assignUniqueId(value) : value, id: uuid(), }, }; }, {}); } return { value: input, id: uuid(), }; }

ID Removal Logic:

export function revertToOriginal(input: any): any { if (Array.isArray(input)) { return input.map((item) => revertToOriginal(item)); } if (typeof input === "object" && input !== null) { // Check if object has ID wrapper structure if ("id" in input && "value" in input && Object.keys(input).length === 2) { return revertToOriginal(input.value); } // Process regular object return Object.entries(input).reduce((acc, [key, value]) => { acc[key] = revertToOriginal(value); return acc; }, {} as Record<string, any>); } return input; }

Performance Considerations

Memory Efficiency:

  • IDs are temporary and cleaned up during save operations
  • Minimal memory overhead for enhanced UX
  • Garbage collection handles cleanup automatically

React Performance:

  • Stable keys prevent unnecessary re-renders
  • Smooth animations during array operations
  • Preserved component state during updates

Bundle Size:

  • UUID generation uses crypto API (minimal size impact)
  • Helper functions are tree-shakeable
  • No external dependencies required

Usage in Sitepins Components

Editor Wrapper:

// src/app/(protected)/(site)/[orgId]/[projectId]/files/[...file]/_components/editor-wrapper.tsx const [state, setState] = useState<State | undefined>({ data: assignUniqueId(data), // Add IDs for form operations page_content: content ?? "", }); // On save, IDs are removed in commit logic const cleanData = revertToOriginal(state.data);

Preview Data Component:

// src/app/(protected)/(site)/[orgId]/[projectId]/files/[...file]/_components/preview-data.tsx const createNewItem = (fields: Field[]) => { return fields.reduce((acc, field) => { acc[field.name] = { value: "", id: uuid() }; // New items get IDs return acc; }, {} as any); };

This system enables Sitepins to provide a smooth, responsive content editing experience while maintaining clean, portable content that works across different environments and platforms.

AI-Powered Content Generation

// AI content generation endpoint export async function POST(request: Request) { const { prompt, type, context } = await request.json(); const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); const response = await openai.chat.completions.create({ model: "gpt-4", messages: [ { role: "system", content: getSystemPrompt(type) }, { role: "user", content: prompt }, ], max_tokens: 2000, temperature: 0.7, }); return NextResponse.json({ content: response.choices[0]?.message?.content, usage: response.usage, }); }

Advanced Editor Features

  1. Monaco Editor: Code editing with syntax highlighting
  2. Plate Editor: Rich text editing with markdown support
  3. Live Preview: Real-time content preview
  4. Collaboration: Multi-user editing capabilities
  5. Object Visual Editor (preview-data.tsx):
  • This is the main component responsible for rendering the entire object visual editor in Sitepins.
  • Dynamically renders all fields, nested objects, and arrays based on a provided schema.
  • Manages breadcrumb navigation for deep/nested editing and user-friendly navigation.
  • Handles updates, additions, and deletions of data visually, supporting all field types (string, number, date, media, gallery, array, object, boolean).
  • Ensures each field/item has a unique ID for React reconciliation and state management.
  • Provides UI controls for editing, adding, and removing items, enabling users to visually edit complex, nested data structures.
  • Core logic for dynamic forms and content editing is implemented here; extend or customize this file to change editor behavior.
Last updated on