'use client' import type { ExampleLayoutProps } from '../example-layout' const instanceId = Math.random().toString(36).substring(2, 9) const appJsCode = `import { useEffect, useState } from 'react'; import './styles.css'; import { createClient } from '@supabase/supabase-js'; // Initialize Supabase client const supabaseUrl = '${process.env.NEXT_PUBLIC_EXAMPLES_SUPABASE_URL}'; const supabaseKey = '${process.env.NEXT_PUBLIC_EXAMPLES_SUPABASE_ANON_KEY}'; const supabase = createClient(supabaseUrl, supabaseKey); // Generate a unique instance ID for this session const instanceId = '${instanceId}'; // Channel name for the todos in this instance const CHANNEL = \`todos:\${instanceId}\`; const TABLE = 'todos'; export default function App() { const [todos, setTodos] = useState([]); const [newTodo, setNewTodo] = useState(''); const [username, setUsername] = useState(''); const [isConnected, setIsConnected] = useState(false); const [onlineUsers, setOnlineUsers] = useState([]); const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(true); // Sign in anonymously and store instanceId in user metadata useEffect(() => { const signInAnonymously = async () => { try { const { data, error } = await supabase.auth.signInAnonymously({ options: { data: { instanceId } } }); if (error) { console.error('Error signing in anonymously:', error.message); return; } setUser(data.user); console.log('Signed in anonymously with user ID:', data.user.id); } catch (error) { console.error('Unexpected error during sign in:', error.message); } }; signInAnonymously(); }, []); // Fetch todos from the database when user is authenticated useEffect(() => { if (!user) return; const fetchTodos = async () => { try { const { data, error } = await supabase .from(TABLE) .select('*') .eq('channel', instanceId) if (error) { console.error('Error fetching todos:', error.message); return; } setTodos(data || []); setIsLoading(false); } catch (error) { console.error('Unexpected error fetching todos:', error.message); } }; fetchTodos(); const setupRealtimeChannel = async () => { await supabase.realtime.setAuth(); // Needed for Realtime Authorization const changes = supabase .channel(CHANNEL, { config: { private: true }, }) .on('broadcast', { event: 'INSERT' }, (payload) => { const { record: todo } = payload.payload; setTodos(prev => [...prev, todo]); }) .on('broadcast', { event: 'UPDATE' }, (payload) => { const { record: todo } = payload.payload; setTodos(prev => prev.map(t => t.id === todo.id ? todo : t) ); }) .on('broadcast', { event: 'DELETE' }, (payload) => { console.log('DELETE', payload); const { old_record: todo } = payload.payload; setTodos(prev => prev.filter(t => t.id !== todo.id)); }) .subscribe(); }; setupRealtimeChannel(); }, [user, instanceId]); useEffect(() => { // Generate a random username const adjectives = ['Happy', 'Clever', 'Brave', 'Bright', 'Kind']; const nouns = ['Panda', 'Tiger', 'Eagle', 'Dolphin', 'Fox']; const randomName = \`\${adjectives[Math.floor(Math.random() * adjectives.length)]}\${ nouns[Math.floor(Math.random() * nouns.length)] }\${Math.floor(Math.random() * 100)}\`; setUsername(randomName); // Subscribe to presence channel const presenceChannel = supabase.channel(\`presence:\${instanceId}\`); // Track presence state presenceChannel.on('presence', { event: 'sync' }, () => { const state = presenceChannel.presenceState(); const presenceList = []; // Convert presence state to array Object.keys(state).forEach(key => { const presences = state[key]; presenceList.push(...presences); }); setOnlineUsers(presenceList); }); presenceChannel .subscribe(async (status) => { if (status === 'SUBSCRIBED') { // Track presence await presenceChannel.track({ user_id: user?.id || 'anonymous', username: randomName, online_at: new Date().getTime(), }); setIsConnected(true); } }); return () => { presenceChannel.unsubscribe(); }; }, [user?.id, instanceId]); const handleAddTodo = async (e) => { e.preventDefault(); if (!newTodo.trim() || !isConnected || !user) return; try { // Insert the todo into the Supabase table // The database trigger will handle broadcasting const { error } = await supabase .from(TABLE) .insert({ text: newTodo.trim(), completed: false, created_by: user.id, channel: instanceId }); if (error) { console.error('Error adding todo:', error.message); return; } // Clear the input setNewTodo(''); } catch (error) { console.error('Unexpected error adding todo:', error.message); } }; const handleToggleTodo = async (todo) => { if (!isConnected || !user) return; try { // Update the todo in the database // The database trigger will handle broadcasting const { error } = await supabase .from(TABLE) .update({ completed: !todo.completed }) .eq('id', todo.id) .eq('channel', instanceId); if (error) { console.error('Error updating todo:', error.message); } } catch (error) { console.error('Unexpected error updating todo:', error.message); } }; const handleDeleteTodo = async (todo) => { if (!isConnected || !user) return; try { // Delete the todo from the database // The database trigger will handle broadcasting const { error } = await supabase .from(TABLE) .delete() .eq('id', todo.id) if (error) { console.error('Error deleting todo:', error.message); } } catch (error) { console.error('Unexpected error deleting todo:', error.message); } }; return (
{/* Header */}

{user ? \`\${todos.filter((todo) => !todo.completed).length} todos to complete\` : 'Connecting...' }

{onlineUsers.map((user, index) => (
{user.username}
))}
{/* Main content */}
{isLoading ? (
Loading todos...
) : ( todos.map((todo) => (
{todo.text}
)) )}
setNewTodo(e.target.value)} placeholder="Add a new todo..." disabled={!isConnected || !user} className="flex-1 px-4 py-2 bg-neutral-800 text-neutral-100 border border-neutral-700 rounded-md focus:outline-hidden focus:ring-2 focus:ring-neutral-600 focus:border-transparent placeholder-neutral-500" />
); }` const todoFiles = { '/App.js': appJsCode, '/styles.css': `/* No custom CSS needed - using Tailwind */`, } const layoutProps: ExampleLayoutProps = { appJsCode, files: todoFiles, title: 'Todo List', description: "A collaborative todo list application that lets multiple users manage tasks in real-time. Features include adding, completing, and deleting tasks, all synchronized instantly across devices. This example showcases real-time database changes and presence indicators showing who's online.", } export default layoutProps