/* @component-map * App — Main container, tab navigation [app.jsx] * ProjectList — Browse/manage all projects [components/ProjectList.jsx] * ProjectForm — Create/edit project with materials and steps [components/ProjectForm.jsx] * ProjectDetail — View full project details [components/ProjectDetail.jsx] * @end-component-map */ import { useMemo, useState } from 'react'; import { useAuth, useCollection } from '@deplixo/sdk'; import { ProjectList } from './components/ProjectList.jsx'; import { ProjectForm } from './components/ProjectForm.jsx'; import { ProjectDetail } from './components/ProjectDetail.jsx'; function App() { const { user, loading, login, logout } = useAuth(); const [view, setView] = useState('list'); const [editingProject, setEditingProject] = useState(null); const [viewingProject, setViewingProject] = useState(null); const [tutorialProject, setTutorialProject] = useState(null); const [tutorialLinkCopied, setTutorialLinkCopied] = useState(false); const { update: updateProject } = useCollection('projects', { personal: true }); const tutorialUrl = useMemo(() => { if (!tutorialProject) return ''; const baseUrl = typeof window !== 'undefined' ? window.location.origin + window.location.pathname : ''; return `${baseUrl}?tutorial=${encodeURIComponent(tutorialProject.id || tutorialProject._id || tutorialProject.slug || tutorialProject.title || '')}`; }, [tutorialProject]); const handleCreate = () => { setEditingProject(null); setView('form'); }; const handleEdit = (project) => { setEditingProject(project); setView('form'); }; const handleView = (project) => { setViewingProject(project); setView('detail'); }; const handleBack = () => { setView('list'); setEditingProject(null); setViewingProject(null); setTutorialProject(null); setTutorialLinkCopied(false); }; const handleSaved = () => { setView('list'); setEditingProject(null); }; const handleMarkFinished = async (project, finished) => { if (!project) return; const projectId = project.id || project._id; if (!projectId) return; await updateProject(projectId, { ...project, isFinished: finished, publishedAsTutorial: finished ? Boolean(project.publishedAsTutorial) : false, tutorialPublishedAt: finished ? project.tutorialPublishedAt || new Date().toISOString() : null, }); const nextProject = { ...project, isFinished: finished }; if (viewingProject && (viewingProject.id || viewingProject._id) === projectId) { setViewingProject(nextProject); } if (tutorialProject && (tutorialProject.id || tutorialProject._id) === projectId) { setTutorialProject({ ...tutorialProject, isFinished: finished }); } }; const handleOpenTutorial = (project) => { setTutorialProject(project); setTutorialLinkCopied(false); }; const handleCopyTutorialLink = async () => { if (!tutorialUrl) return; try { await navigator.clipboard.writeText(tutorialUrl); setTutorialLinkCopied(true); window.setTimeout(() => setTutorialLinkCopied(false), 1800); } catch { setTutorialLinkCopied(false); } }; const handleShareTutorial = async () => { if (!tutorialProject) return; const text = `Tutorial: ${tutorialProject.title || 'DIY Project'}\n${tutorialUrl}`; if (navigator.share) { try { await navigator.share({ title: `${tutorialProject.title || 'DIY Project'} Tutorial`, text, url: tutorialUrl, }); return; } catch { // fall back to copy link } } await handleCopyTutorialLink(); }; if (loading) { return (
🔨

DIY Planner

Signing you in...

); } if (!user) { return (
🔨

DIY Planner

Sign in with Google to access and manage your personal projects.

); } return (
🔨

DIY Planner

{user.name} {view !== 'list' && ( )} {view === 'list' && ( )}
{view === 'list' && ( )} {view === 'form' && ( )} {view === 'detail' && viewingProject && ( )}
{tutorialProject && (
setTutorialProject(null)}>
e.stopPropagation()}>

Tutorial publishing

{tutorialProject.title || 'Untitled Project'}

Status: {tutorialProject.isFinished ? 'Finished' : 'In progress'}
Public tutorial link
{tutorialUrl || 'Link will appear once the project has an id.'}

Share this link to show the tutorial-style project view with progress, materials, and steps.

)}
); } ReactDOM.createRoot(document.getElementById("root")).render();