import { useCollection } from '@deplixo/sdk'; /* @component-map * App — Main container, tab navigation [app.jsx] * ActiveWalk — Start/stop walk timer, notes, behavior rating [components/ActiveWalk.jsx] * WalkHistory — Past walks list with details [components/WalkHistory.jsx] * Stats — Walk statistics and charts [components/Stats.jsx] * WalkerIdentityPanel — Walker identity selector/creator panel that can be reused to pick, create, and rename a dog walker profile. * @end-component-map */ // DEPLOY_CONFIG: {"cron": [{"name": "dog_walk_reminder", "schedule": "0 9 * * 1-5", "action": "event", "config": {"event_type": "dog_walk_reminder"}}]} import { useState } from 'react'; import { ActiveWalk } from './components/ActiveWalk.jsx'; import { WalkHistory } from './components/WalkHistory.jsx'; import { Stats } from './components/Stats.jsx'; function App() { const [activeTab, setActiveTab] = useState('walk'); const { items: storageItems } = useCollection('pawtracker_storage', { personal: true }); const walkerId = storageItems.find(item => item.key === 'pawtracker_walker_id')?.value || ''; const tabs = [ { id: 'walk', label: '🐕 Walk', icon: '🐕' }, { id: 'history', label: '📋 History', icon: '📋' }, { id: 'stats', label: '📊 Stats', icon: '📊' }, ]; const { add: addStorage, update: updateStorage, remove: removeStorage } = useCollection('pawtracker_storage', { personal: true }); function handleWalkerChange(nextWalkerId) { const currentItem = storageItems.find(item => item.key === 'pawtracker_walker_id'); if (nextWalkerId) { if (currentItem) { updateStorage(currentItem.id, { value: nextWalkerId }); } else { addStorage({ key: 'pawtracker_walker_id', value: nextWalkerId }); } } else { if (currentItem) { removeStorage(currentItem.id); } } } return (

Pawtracker

Every walk tells a story

{activeTab === 'walk' && } {activeTab === 'history' && } {activeTab === 'stats' && }
); } function WalkerIdentityPanel({ walkerId, onWalkerChange }) { const { items: walkers, loading, add, update } = useCollection('walkers'); const [selectedWalkerId, setSelectedWalkerId] = useState(walkerId || ''); const [newWalkerName, setNewWalkerName] = useState(''); useEffect(() => { setSelectedWalkerId(walkerId || ''); }, [walkerId]); async function handleSelectChange(e) { const nextId = e.target.value; setSelectedWalkerId(nextId); if (onWalkerChange) onWalkerChange(nextId); } async function handleCreateWalker(e) { e.preventDefault(); const name = newWalkerName.trim(); if (!name) return; const created = await add({ name, createdAt: new Date().toISOString() }); if (created && created.id) { setNewWalkerName(''); setSelectedWalkerId(created.id); if (onWalkerChange) onWalkerChange(created.id); } } async function handleRenameWalker() { const selectedWalker = walkers.find(w => w.id === selectedWalkerId); if (!selectedWalker) return; const nextName = window.prompt('Rename walker', selectedWalker.name || ''); if (nextName && nextName.trim()) { await update(selectedWalker.id, { name: nextName.trim() }); } } const selectedWalker = walkers.find(w => w.id === selectedWalkerId); return (

Walker profile

{loading ? (

Loading walkers...

) : ( <>

Current walker

{selectedWalker ? selectedWalker.name : 'No walker selected'}

setNewWalkerName(e.target.value)} placeholder="Enter walker name" />
{selectedWalker && ( )} )}
); } ReactDOM.createRoot(document.getElementById("root")).render();