Code Snippets
Production-ready TypeScript code examples for common Vertical Template patterns. Copy and adapt these snippets to accelerate your development.
Configuration
Minimal Tenant Config
The simplest possible tenant configuration to get started.
import { TenantConfig } from '@/config/types';
export const minimalConfig: TenantConfig = {
id: 'my-app',
name: 'My Application',
theme: {
primaryColor: '#3b82f6',
},
sections: [
{
id: 'home',
title: 'Home',
path: '/',
icon: 'home',
components: [
{
type: 'heading',
text: 'Welcome to My Application',
},
],
},
],
};
When to use: Starting a new vertical or prototyping quickly.
Full-Featured Tenant Config
Complete configuration with Object Types, multiple sections, and custom branding.
import { TenantConfig } from '@/config/types';
export const fullConfig: TenantConfig = {
id: 'property-mgmt',
name: 'Property Management Portal',
description: 'Manage properties, tenants, and maintenance requests',
theme: {
primaryColor: '#2563eb',
secondaryColor: '#7c3aed',
logo: '/logos/property-mgmt.svg',
favicon: '/favicons/property-mgmt.ico',
font: {
family: 'Inter, sans-serif',
url: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap',
},
},
auth: {
enabled: true,
allowAnonymous: false,
roles: ['admin', 'manager', 'tenant'],
},
objectTypes: [
{
name: 'Property',
apiName: 'property',
pluralName: 'Properties',
fields: [
{ name: 'address', type: 'text', required: true },
{ name: 'units', type: 'number', required: true },
{ name: 'monthlyRent', type: 'currency', required: true },
],
actions: ['view', 'edit', 'delete'],
permissions: {
create: ['admin', 'manager'],
view: ['admin', 'manager', 'tenant'],
edit: ['admin', 'manager'],
delete: ['admin'],
},
},
],
sections: [
{
id: 'dashboard',
title: 'Dashboard',
path: '/',
icon: 'home',
components: [
{
type: 'metric-grid',
metrics: [
{ label: 'Total Properties', value: '{{count:property}}' },
{ label: 'Occupied Units', value: '{{sum:property.occupiedUnits}}' },
],
},
],
},
{
id: 'properties',
title: 'Properties',
path: '/properties',
icon: 'building',
roles: ['admin', 'manager'],
components: [
{
type: 'resource-list',
objectType: 'property',
columns: ['address', 'units', 'monthlyRent'],
searchable: true,
sortable: true,
},
],
},
],
navigation: {
primary: ['dashboard', 'properties'],
footer: [
{ label: 'Privacy Policy', href: '/privacy' },
{ label: 'Terms of Service', href: '/terms' },
],
},
};
When to use: Production applications with full feature set.
Store Slice with Persistence
Define a store slice that persists to localStorage.
import { StoreSlice } from '@/lib/store/types';
export const dashboardSlice: StoreSlice<DashboardState> = {
name: 'dashboard',
persist: true, // Saves to localStorage
initialState: {
filters: {
status: 'active',
dateRange: 'last-30-days',
},
viewMode: 'grid',
selectedProperty: null,
},
actions: {
setFilter: (state, filter: { key: string; value: string }) => {
state.filters[filter.key] = filter.value;
},
setViewMode: (state, mode: 'grid' | 'list') => {
state.viewMode = mode;
},
selectProperty: (state, propertyId: string | null) => {
state.selectedProperty = propertyId;
},
resetFilters: (state) => {
state.filters = { status: 'active', dateRange: 'last-30-days' };
},
},
};
interface DashboardState {
filters: Record<string, string>;
viewMode: 'grid' | 'list';
selectedProperty: string | null;
}
When to use: Persisting user preferences or filter state across sessions.
Conditional Visibility
Show/hide components based on user role or state.
import { ComponentConfig } from '@/config/types';
const conditionalComponents: ComponentConfig[] = [
{
type: 'button',
label: 'Create Property',
action: 'create-property',
// Only visible to admins and managers
visible: {
roles: ['admin', 'manager'],
},
},
{
type: 'banner',
text: 'Your account is pending approval',
variant: 'warning',
// Only visible when user status is pending
visible: {
condition: '{{user.status}} === "pending"',
},
},
{
type: 'resource-list',
objectType: 'property',
// Show all properties to admins, only assigned properties to others
filters: {
condition: '{{user.role}} === "admin" ? {} : { assignedTo: {{user.id}} }',
},
},
];
When to use: Role-based access control or dynamic UI based on state.
Components
Custom Component with Store Bindings
React component that reads from and writes to the VT store.
import React from 'react';
import { useStoreValue, useSetStore } from '@/lib/store';
import { Card } from '@/components/ui/Card';
import { Button } from '@/components/ui/Button';
interface PropertyFiltersProps {
className?: string;
}
export const PropertyFilters: React.FC<PropertyFiltersProps> = ({ className }) => {
const filters = useStoreValue('dashboard.filters');
const setFilter = useSetStore('dashboard.setFilter');
const resetFilters = useSetStore('dashboard.resetFilters');
const statuses = ['active', 'inactive', 'maintenance'];
const dateRanges = [
{ value: 'last-7-days', label: 'Last 7 Days' },
{ value: 'last-30-days', label: 'Last 30 Days' },
{ value: 'last-90-days', label: 'Last 90 Days' },
];
return (
<Card className={className}>
<div className="space-y-4">
<h3 className="text-lg font-semibold">Filters</h3>
<div>
<label className="block text-sm font-medium mb-2">Status</label>
<div className="space-x-2">
{statuses.map((status) => (
<Button
key={status}
variant={filters.status === status ? 'primary' : 'secondary'}
size="sm"
onClick={() => setFilter({ key: 'status', value: status })}
>
{status}
</Button>
))}
</div>
</div>
<div>
<label className="block text-sm font-medium mb-2">Date Range</label>
<select
value={filters.dateRange}
onChange={(e) => setFilter({ key: 'dateRange', value: e.target.value })}
className="w-full px-3 py-2 border rounded"
>
{dateRanges.map((range) => (
<option key={range.value} value={range.value}>
{range.label}
</option>
))}
</select>
</div>
<Button variant="outline" onClick={resetFilters} className="w-full">
Reset Filters
</Button>
</div>
</Card>
);
};
When to use: Building custom UI that needs to read/write global state.
Conditional Rendering Component
Component that renders different content based on authentication and roles.
import React from 'react';
import { useAuth } from '@eai/platform-sdk/react';
interface ConditionalProps {
roles?: string[];
requireAuth?: boolean;
children: React.ReactNode;
fallback?: React.ReactNode;
}
export const Conditional: React.FC<ConditionalProps> = ({
roles,
requireAuth = true,
children,
fallback = null,
}) => {
const { user, isAuthenticated } = useAuth();
// Check authentication
if (requireAuth && !isAuthenticated) {
return <>{fallback}</>;
}
// Check roles if specified
if (roles && roles.length > 0) {
const hasRole = roles.some((role) => user?.roles?.includes(role));
if (!hasRole) {
return <>{fallback}</>;
}
}
return <>{children}</>;
};
// Usage examples:
// <Conditional roles={['admin']}>
// <AdminPanel />
// </Conditional>
//
// <Conditional requireAuth fallback={<LoginPrompt />}>
// <ProtectedContent />
// </Conditional>
When to use: Protecting UI elements based on auth or roles.
Form Component with Validation
Complete form with field validation and error handling.
import React, { useState } from 'react';
import { sdk } from '@eai/platform-sdk';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { Textarea } from '@/components/ui/Textarea';
interface PropertyFormData {
address: string;
units: number;
monthlyRent: number;
description: string;
}
interface PropertyFormProps {
initialData?: Partial<PropertyFormData>;
onSuccess?: (data: PropertyFormData) => void;
}
export const PropertyForm: React.FC<PropertyFormProps> = ({
initialData,
onSuccess,
}) => {
const [formData, setFormData] = useState<PropertyFormData>({
address: initialData?.address || '',
units: initialData?.units || 1,
monthlyRent: initialData?.monthlyRent || 0,
description: initialData?.description || '',
});
const [errors, setErrors] = useState<Partial<Record<keyof PropertyFormData, string>>>({});
const [isSubmitting, setIsSubmitting] = useState(false);
const [submitError, setSubmitError] = useState<string | null>(null);
const validate = (): boolean => {
const newErrors: Partial<Record<keyof PropertyFormData, string>> = {};
if (!formData.address.trim()) {
newErrors.address = 'Address is required';
}
if (formData.units < 1) {
newErrors.units = 'Must have at least 1 unit';
}
if (formData.monthlyRent <= 0) {
newErrors.monthlyRent = 'Monthly rent must be greater than 0';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setSubmitError(null);
if (!validate()) {
return;
}
setIsSubmitting(true);
try {
await sdk.resources.create('property', formData);
onSuccess?.(formData);
} catch (error) {
setSubmitError(error instanceof Error ? error.message : 'Failed to create property');
} finally {
setIsSubmitting(false);
}
};
const handleChange = <K extends keyof PropertyFormData>(
field: K,
value: PropertyFormData[K]
) => {
setFormData((prev) => ({ ...prev, [field]: value }));
// Clear error when field is edited
if (errors[field]) {
setErrors((prev) => ({ ...prev, [field]: undefined }));
}
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
<Input
label="Address"
value={formData.address}
onChange={(e) => handleChange('address', e.target.value)}
error={errors.address}
required
/>
<Input
label="Number of Units"
type="number"
value={formData.units}
onChange={(e) => handleChange('units', parseInt(e.target.value, 10))}
error={errors.units}
min={1}
required
/>
<Input
label="Monthly Rent"
type="number"
value={formData.monthlyRent}
onChange={(e) => handleChange('monthlyRent', parseFloat(e.target.value))}
error={errors.monthlyRent}
min={0}
step={0.01}
prefix="$"
required
/>
<Textarea
label="Description"
value={formData.description}
onChange={(e) => handleChange('description', e.target.value)}
rows={4}
/>
{submitError && (
<div className="p-3 bg-red-50 text-red-700 rounded">
{submitError}
</div>
)}
<Button
type="submit"
disabled={isSubmitting}
className="w-full"
>
{isSubmitting ? 'Creating...' : 'Create Property'}
</Button>
</form>
);
};
When to use: Creating or editing resources with validation.
API Integration
Fetch Resources via BFF Proxy
Use the Platform SDK to fetch resources through the BFF proxy (tokens injected server-side).
import React from 'react';
import { useResources } from '@eai/platform-sdk/react';
interface Property {
id: string;
address: string;
units: number;
occupancyRate: number;
}
export const PropertyList: React.FC = () => {
const {
resources: properties,
isLoading,
error,
refresh,
} = useResources<Property>({
objectType: 'property',
filters: {
status: 'active',
},
sort: {
field: 'address',
order: 'asc',
},
});
if (isLoading) {
return <div>Loading properties...</div>;
}
if (error) {
return (
<div className="text-red-600">
<p>Error loading properties: {error.message}</p>
<button onClick={refresh} className="underline">
Try Again
</button>
</div>
);
}
return (
<div className="space-y-4">
{properties.map((property) => (
<div key={property.id} className="p-4 border rounded">
<h3 className="font-semibold">{property.address}</h3>
<p>Units: {property.units}</p>
<p>Occupancy: {property.occupancyRate}%</p>
</div>
))}
</div>
);
};
When to use: Fetching resources from the platform with automatic auth token handling.
SSE Streaming Chat
Real-time AI chat with Server-Sent Events (SSE) streaming.
import React, { useState, useRef, useEffect } from 'react';
import { useChat } from '@eai/platform-sdk/react';
interface Message {
id: string;
role: 'user' | 'assistant';
content: string;
timestamp: Date;
}
export const ChatComponent: React.FC = () => {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState('');
const messagesEndRef = useRef<HTMLDivElement>(null);
const { sendMessage, isStreaming, error } = useChat({
onMessageChunk: (chunk) => {
setMessages((prev) => {
const lastMessage = prev[prev.length - 1];
if (lastMessage?.role === 'assistant' && lastMessage.id === chunk.messageId) {
// Append to existing message
return [
...prev.slice(0, -1),
{
...lastMessage,
content: lastMessage.content + chunk.content,
},
];
} else {
// New message
return [
...prev,
{
id: chunk.messageId,
role: 'assistant',
content: chunk.content,
timestamp: new Date(),
},
];
}
});
},
onError: (err) => {
console.error('Chat error:', err);
},
});
const handleSend = async () => {
if (!input.trim() || isStreaming) return;
const userMessage: Message = {
id: crypto.randomUUID(),
role: 'user',
content: input,
timestamp: new Date(),
};
setMessages((prev) => [...prev, userMessage]);
setInput('');
await sendMessage({
content: input,
context: {
conversationHistory: messages.map((m) => ({
role: m.role,
content: m.content,
})),
},
});
};
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
return (
<div className="flex flex-col h-full">
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.map((message) => (
<div
key={message.id}
className={`p-3 rounded ${
message.role === 'user'
? 'bg-blue-100 ml-auto max-w-[80%]'
: 'bg-gray-100 mr-auto max-w-[80%]'
}`}
>
<div className="text-sm font-semibold mb-1">
{message.role === 'user' ? 'You' : 'Assistant'}
</div>
<div className="whitespace-pre-wrap">{message.content}</div>
</div>
))}
{isStreaming && (
<div className="text-sm text-gray-500">Assistant is typing...</div>
)}
<div ref={messagesEndRef} />
</div>
{error && (
<div className="p-3 bg-red-50 text-red-700">
Error: {error.message}
</div>
)}
<div className="border-t p-4">
<div className="flex space-x-2">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSend()}
placeholder="Type your message..."
disabled={isStreaming}
className="flex-1 px-3 py-2 border rounded"
/>
<button
onClick={handleSend}
disabled={!input.trim() || isStreaming}
className="px-4 py-2 bg-blue-600 text-white rounded disabled:opacity-50"
>
Send
</button>
</div>
</div>
</div>
);
};
When to use: Building AI chat interfaces with real-time streaming.
Document Upload with Progress
Upload documents with progress tracking and error handling.
import React, { useState } from 'react';
import { useDocuments } from '@eai/platform-sdk/react';
export const DocumentUpload: React.FC = () => {
const [progress, setProgress] = useState(0);
const [isUploading, setIsUploading] = useState(false);
const [error, setError] = useState<string | null>(null);
const { upload } = useDocuments();
const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
setIsUploading(true);
setError(null);
setProgress(0);
try {
await upload(file, {
onProgress: (percent) => {
setProgress(percent);
},
metadata: {
category: 'property-documents',
uploadedBy: 'user-id',
},
});
// Success
setProgress(100);
setTimeout(() => {
setIsUploading(false);
setProgress(0);
}, 1000);
} catch (err) {
setError(err instanceof Error ? err.message : 'Upload failed');
setIsUploading(false);
setProgress(0);
}
};
return (
<div className="space-y-4">
<div>
<label className="block">
<span className="sr-only">Choose file</span>
<input
type="file"
onChange={handleFileSelect}
disabled={isUploading}
className="block w-full text-sm text-gray-500
file:mr-4 file:py-2 file:px-4
file:rounded file:border-0
file:text-sm file:font-semibold
file:bg-blue-50 file:text-blue-700
hover:file:bg-blue-100
disabled:opacity-50"
/>
</label>
</div>
{isUploading && (
<div>
<div className="w-full bg-gray-200 rounded-full h-2">
<div
className="bg-blue-600 h-2 rounded-full transition-all duration-300"
style={{ width: `${progress}%` }}
/>
</div>
<p className="text-sm text-gray-600 mt-2">
Uploading... {progress}%
</p>
</div>
)}
{error && (
<div className="p-3 bg-red-50 text-red-700 rounded">
{error}
</div>
)}
</div>
);
};
When to use: Uploading files with visual progress feedback.
State Management
useStoreValue Examples
Read values from the VT store.
import { useStoreValue } from '@/lib/store';
export const StoreValueExamples = () => {
// Get entire slice
const dashboard = useStoreValue('dashboard');
// Get nested value
const statusFilter = useStoreValue('dashboard.filters.status');
// Get with default
const viewMode = useStoreValue('dashboard.viewMode', 'grid');
// Get user info
const user = useStoreValue('auth.user');
const isAdmin = user?.roles?.includes('admin');
return (
<div>
<p>Status: {statusFilter}</p>
<p>View: {viewMode}</p>
{isAdmin && <p>Admin controls</p>}
</div>
);
};
When to use: Reading global state in components.
useSetStore Patterns
Update store values.
import { useSetStore } from '@/lib/store';
export const StoreUpdateExamples = () => {
// Call action from slice
const setFilter = useSetStore('dashboard.setFilter');
const resetFilters = useSetStore('dashboard.resetFilters');
// Direct state update (if no action defined)
const setViewMode = useSetStore('dashboard.viewMode');
const handleStatusChange = (status: string) => {
setFilter({ key: 'status', value: status });
};
const handleReset = () => {
resetFilters();
};
const handleViewToggle = () => {
setViewMode((prev: string) => prev === 'grid' ? 'list' : 'grid');
};
return (
<div className="space-x-2">
<button onClick={() => handleStatusChange('active')}>
Active
</button>
<button onClick={handleReset}>
Reset
</button>
<button onClick={handleViewToggle}>
Toggle View
</button>
</div>
);
};
When to use: Updating global state from components.
Computed Selectors
Derive state from store values.
import { useMemo } from 'react';
import { useStoreValue } from '@/lib/store';
export const PropertyStats = () => {
const properties = useStoreValue('resources.properties', []);
// Compute derived values
const stats = useMemo(() => {
const total = properties.length;
const occupied = properties.filter((p) => p.occupancyRate === 100).length;
const totalUnits = properties.reduce((sum, p) => sum + p.units, 0);
const occupiedUnits = properties.reduce((sum, p) => sum + p.occupiedUnits, 0);
return {
total,
occupied,
occupancyRate: totalUnits > 0 ? (occupiedUnits / totalUnits) * 100 : 0,
};
}, [properties]);
return (
<div>
<p>Total Properties: {stats.total}</p>
<p>Fully Occupied: {stats.occupied}</p>
<p>Overall Occupancy: {stats.occupancyRate.toFixed(1)}%</p>
</div>
);
};
When to use: Computing derived values from store state.
Slice Reset
Clear store state on logout or navigation.
import { useSetStore } from '@/lib/store';
import { useCallback } from 'react';
export const useLogout = () => {
const resetDashboard = useSetStore('dashboard.reset');
const resetFilters = useSetStore('filters.reset');
const clearAuth = useSetStore('auth.clear');
const logout = useCallback(async () => {
// Clear all store slices
resetDashboard();
resetFilters();
clearAuth();
// Additional logout logic
await fetch('/api/auth/logout', { method: 'POST' });
// Redirect
window.location.href = '/login';
}, [resetDashboard, resetFilters, clearAuth]);
return { logout };
};
When to use: Cleaning up state on logout or route changes.
Authentication
Protected Route Check
Protect routes based on authentication.
import { useAuth } from '@eai/platform-sdk/react';
import { useRouter } from 'next/router';
import { useEffect } from 'react';
export const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const { isAuthenticated, isLoading } = useAuth();
const router = useRouter();
useEffect(() => {
if (!isLoading && !isAuthenticated) {
router.push(`/login?redirect=${encodeURIComponent(router.asPath)}`);
}
}, [isAuthenticated, isLoading, router]);
if (isLoading) {
return <div>Loading...</div>;
}
if (!isAuthenticated) {
return null;
}
return <>{children}</>;
};
When to use: Protecting pages that require authentication.
Role-Based UI
Show/hide UI elements based on user roles.
import { useAuth } from '@eai/platform-sdk/react';
export const RoleBasedUI = () => {
const { user } = useAuth();
const hasRole = (role: string) => user?.roles?.includes(role);
const hasAnyRole = (roles: string[]) => roles.some(hasRole);
return (
<div>
<h1>Dashboard</h1>
{hasRole('admin') && (
<section>
<h2>Admin Controls</h2>
<button>Manage Users</button>
<button>System Settings</button>
</section>
)}
{hasAnyRole(['admin', 'manager']) && (
<section>
<h2>Management</h2>
<button>View Reports</button>
<button>Create Property</button>
</section>
)}
<section>
<h2>Your Properties</h2>
{/* Always visible */}
</section>
</div>
);
};
When to use: Conditionally rendering UI based on user permissions.
Anonymous User Detection
Handle anonymous/unauthenticated users.
import { useAuth } from '@eai/platform-sdk/react';
export const AnonymousDetection = () => {
const { isAuthenticated, user } = useAuth();
if (!isAuthenticated) {
return (
<div className="p-4 bg-blue-50 border border-blue-200 rounded">
<h3 className="font-semibold">Welcome, Guest!</h3>
<p>Sign in to access all features.</p>
<a href="/login" className="text-blue-600 underline">
Sign In
</a>
</div>
);
}
return (
<div>
<h3>Welcome back, {user?.name}!</h3>
<p>Role: {user?.roles?.join(', ')}</p>
</div>
);
};
When to use: Supporting both authenticated and anonymous users.
Next Steps
- Explore Industry Scenarios for complete vertical examples
- Review AI Workflow Patterns for AI-assisted development
- Check Component Patterns for advanced UI patterns
- Read Platform SDK Reference for complete API documentation