// DEPLOY_CONFIG: {"cron": [{"name": "friday_evening_weekend_plan", "schedule": "0 18 * * 5", "action": "event", "config": {"event_type": "send_weekend_plan_email"}}], "triggers": [{"name": "send_weekend_plan_email_on_event", "on": "event.send_weekend_plan_email", "actions": [{"type": "email", "to": "{{user.email}}", "subject": "Your Friday Evening Weekend Plan", "body": "Hi {{user.name}}, here\u2019s your weekend plan for Friday evening. Enjoy your weekend!"}]}]} import { useEffect, useMemo, useState } from 'react'; import { useAI, useAuth, useCollection, renderChart } from '@deplixo/sdk'; import { WeekView } from './components/WeekView.jsx'; import { Favorites } from './components/Favorites.jsx'; function ActivityWeatherChart({ historyItems }) { const canvasRef = useState(null)[0]; const [canvasElement, setCanvasElement] = useState(null); const aggregatedData = useMemo(() => { const map = new Map(); historyItems.forEach((item) => { const key = String(item?.weatherType || item?.weather_type || item?.weather || 'Unknown'); map.set(key, (map.get(key) || 0) + 1); }); return Array.from(map.entries()) .sort((a, b) => b[1] - a[1]) .map(([label, value]) => ({ label, value })); }, [historyItems]); useEffect(() => { if (canvasElement && aggregatedData.length > 0) { renderChart(canvasElement, { type: 'bar', data: { labels: aggregatedData.map((d) => d.label), datasets: [ { label: 'Activities Completed', data: aggregatedData.map((d) => d.value), }, ], }, }); } }, [aggregatedData, canvasElement]); return (

Activities by Weather Type

See which weather conditions led to the most completed activities.

{aggregatedData.length > 0 ? (
) : (
๐Ÿ“Š

No activity history yet

Complete activities on different weather days to build your chart here.

)}
); } function App() { const { user, loading, logout } = useAuth(); const { items: historyItems } = useCollection('activity_history', { personal: true }); const [activeTab, setActiveTab] = useState('planner'); if (loading) { return (
โ˜๏ธ

Signing you in...

Setting up your personalized activity history.

); } return (
๐ŸŒค๏ธ

Activity Planner

Weather-smart activity suggestions for your week

{user ? ( <>
{user.avatar ? {user.name} : ๐Ÿ‘ค} {user.name}
) : (
Google sign-in enabled
)}
{!user ? (
๐Ÿ”

Sign in to save favorites

Google authentication is required for personal activity history, saved favorites, and syncing your recommendations across devices.

) : ( <> {activeTab === 'planner' && } {activeTab === 'favorites' && } )}
); } function WeekendActivityPlan({ historyItems }) { const { generate, loading, error } = useAI(); const [plan, setPlan] = useState(null); const [planLoading, setPlanLoading] = useState(false); const [planError, setPlanError] = useState(''); const [refreshKey, setRefreshKey] = useState(0); const historySummary = useMemo(() => { const weatherCounts = new Map(); const activityCounts = new Map(); historyItems.forEach((item) => { const weather = String(item?.weatherType || item?.weather_type || item?.weather || 'Unknown'); const activity = String(item?.activityType || item?.activity_type || item?.activity || item?.title || 'Activity'); weatherCounts.set(weather, (weatherCounts.get(weather) || 0) + 1); activityCounts.set(activity, (activityCounts.get(activity) || 0) + 1); }); return { total: historyItems.length, topWeather: Array.from(weatherCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 3), topActivities: Array.from(activityCounts.entries()).sort((a, b) => b[1] - a[1]).slice(0, 5), }; }, [historyItems]); useEffect(() => { let cancelled = false; async function buildPlan() { setPlanLoading(true); setPlanError(''); try { const system = 'You are an expert weekend activity planner. Create concise, personalized Saturday and Sunday activity suggestions using weather forecast and user history. Return valid JSON only.'; const userPrompt = JSON.stringify({ request: 'Generate a personalized weekend activity plan for Saturday and Sunday.', userHistory: historySummary, weatherForecast: 'Use the current forecast data available in the app context to recommend weather-appropriate activities.', instructions: [ 'Include a title, short overview, Saturday plan, Sunday plan, and 3 quick tips.', 'Base recommendations on the user\'s past preferences from history items.', 'Make the plan practical, upbeat, and specific to the forecast.', 'Return JSON with keys: title, overview, saturday, sunday, tips.', 'For saturday and sunday, include keys: weatherFit, morning, afternoon, evening.', 'For tips, return an array of 3 strings.' ], }); const result = await generate({ system, user: userPrompt, json: true }); if (!cancelled && result) { setPlan(result); } } catch (err) { if (!cancelled) { setPlanError('Could not generate a weekend plan right now.'); } } finally { if (!cancelled) { setPlanLoading(false); } } } buildPlan(); return () => { cancelled = true; }; }, [generate, refreshKey, historySummary]); const fallbackTips = [ 'Try activities that match the best weather window.', 'Use your most common activity types as a starting point.', 'Keep one flexible indoor backup plan ready.' ]; return (

AI Weekend Plan

Personalized Saturday and Sunday ideas based on your forecast and activity history.

{planLoading || loading ? (
๐Ÿค–

Generating your weekend plan...

Analyzing your activity history and the forecast to tailor suggestions.

) : planError || error ? (
โš ๏ธ

Weekend plan unavailable

{planError || 'AI planning is temporarily unavailable.'}

) : (
AI Personalized

{plan?.title || 'Your Weekend Activity Plan'}

{plan?.overview || 'A weekend plan tailored to the weather forecast and your most common activity preferences.'}

Your recent patterns

{historySummary.total > 0 ? `Top weather match: ${historySummary.topWeather[0]?.[0] || 'Unknown'} ยท Favorite activities: ${historySummary.topActivities.map((item) => item[0]).join(', ')}` : 'No activity history yet, so this plan uses the forecast with general weekend suggestions.'}

Saturday

{plan?.saturday?.weatherFit || 'Weather-fit recommendations for Saturday.'}

  • Morning: {plan?.saturday?.morning || 'Start with a flexible morning activity.'}
  • Afternoon: {plan?.saturday?.afternoon || 'Choose an activity that matches the best weather window.'}
  • Evening: {plan?.saturday?.evening || 'Wind down with a low-effort evening plan.'}

Sunday

{plan?.sunday?.weatherFit || 'Weather-fit recommendations for Sunday.'}

  • Morning: {plan?.sunday?.morning || 'Start the day with one of your favorite activity types.'}
  • Afternoon: {plan?.sunday?.afternoon || 'Use the forecast to pick an outdoor or indoor backup.'}
  • Evening: {plan?.sunday?.evening || 'End with something restorative and simple.'}

Quick tips

    {(Array.isArray(plan?.tips) && plan.tips.length > 0 ? plan.tips : fallbackTips).map((tip, index) => (
  • {tip}
  • ))}
)}
); } ReactDOM.createRoot(document.getElementById('root')).render();