import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { Save, Loader2, Check, Plus, Plug, AlertTriangle } from 'lucide-react'; import { api } from '../api/client'; import type { AppSettings, SmartPlug } from '../api/client'; import { Card, CardContent, CardHeader } from '../components/Card'; import { Button } from '../components/Button'; import { SmartPlugCard } from '../components/SmartPlugCard'; import { AddSmartPlugModal } from '../components/AddSmartPlugModal'; import { useState, useEffect } from 'react'; export function SettingsPage() { const queryClient = useQueryClient(); const [localSettings, setLocalSettings] = useState(null); const [hasChanges, setHasChanges] = useState(false); const [showSaved, setShowSaved] = useState(false); const [showPlugModal, setShowPlugModal] = useState(false); const [editingPlug, setEditingPlug] = useState(null); const { data: settings, isLoading } = useQuery({ queryKey: ['settings'], queryFn: api.getSettings, }); const { data: smartPlugs, isLoading: plugsLoading } = useQuery({ queryKey: ['smart-plugs'], queryFn: api.getSmartPlugs, }); const { data: ffmpegStatus } = useQuery({ queryKey: ['ffmpeg-status'], queryFn: api.checkFfmpeg, }); // Sync local state when settings load useEffect(() => { if (settings && !localSettings) { setLocalSettings(settings); } }, [settings, localSettings]); // Track changes useEffect(() => { if (settings && localSettings) { const changed = settings.auto_archive !== localSettings.auto_archive || settings.save_thumbnails !== localSettings.save_thumbnails || settings.capture_finish_photo !== localSettings.capture_finish_photo || settings.default_filament_cost !== localSettings.default_filament_cost || settings.currency !== localSettings.currency || settings.energy_cost_per_kwh !== localSettings.energy_cost_per_kwh; setHasChanges(changed); } }, [settings, localSettings]); const updateMutation = useMutation({ mutationFn: api.updateSettings, onSuccess: (data) => { queryClient.setQueryData(['settings'], data); setLocalSettings(data); setHasChanges(false); setShowSaved(true); setTimeout(() => setShowSaved(false), 2000); }, }); const handleSave = () => { if (localSettings) { updateMutation.mutate(localSettings); } }; const updateSetting = (key: K, value: AppSettings[K]) => { if (localSettings) { setLocalSettings({ ...localSettings, [key]: value }); } }; if (isLoading || !localSettings) { return (
); } return (

Settings

Configure Bambusy

{updateMutation.isError && (
Failed to save settings: {(updateMutation.error as Error).message}
)}
{/* Left Column - General Settings */}

Archive Settings

Auto-archive prints

Automatically save 3MF files when prints complete

Save thumbnails

Extract and save preview images from 3MF files

Capture finish photo

Take a photo from printer camera when print completes

{localSettings.capture_finish_photo && ffmpegStatus && !ffmpegStatus.installed && (

ffmpeg not installed

Camera capture requires ffmpeg. Install it via{' '} brew install ffmpeg (macOS) or{' '} apt install ffmpeg (Linux).

)}

Cost Tracking

updateSetting('default_filament_cost', parseFloat(e.target.value) || 0) } className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none" />
updateSetting('energy_cost_per_kwh', parseFloat(e.target.value) || 0) } className="w-full px-3 py-2 bg-bambu-dark border border-bambu-dark-tertiary rounded-lg text-white focus:border-bambu-green focus:outline-none" />

Used for tracking energy costs per print via smart plugs

About

Bambusy v0.1.2

Archive and manage your Bambu Lab 3MF files

Connect to printers via LAN mode (developer mode required)

{/* Right Column - Smart Plugs */}

Smart Plugs

Connect Tasmota-based smart plugs to automate power control for your printers.

{plugsLoading ? (
) : smartPlugs && smartPlugs.length > 0 ? (
{smartPlugs.map((plug) => ( { setEditingPlug(p); setShowPlugModal(true); }} /> ))}
) : (

No smart plugs configured

Add a Tasmota plug to get started

)}
{/* Smart Plug Modal */} {showPlugModal && ( { setShowPlugModal(false); setEditingPlug(null); }} /> )}
); }