Fish Inventory
{fishTotal} total fishNo fish inventory for this tank yet.
Add species and counts to keep track of livestock per tank.Tank Photos
Loading photos...
No photos for this tank yet.
Capture a photo to build a per-tank gallery.// DEPLOY_CONFIG: {"cron": [{"name": "weekly_water_change_reminder", "schedule": "0 9 * * 1", "action": "event", "config": {"event_type": "maintenance.weekly_water_change_reminder"}}, {"name": "monthly_filter_clean_reminder", "schedule": "0 9 1 * *", "action": "event", "config": {"event_type": "maintenance.monthly_filter_clean_reminder"}}], "triggers": [{"name": "water_parameter_danger_zone_alert", "on": "collection.add", "collection": "water_parameters", "actions": [{"type": "notification", "title": "Water parameter danger zone detected", "body": "A water parameter has entered a danger zone. Please review immediately."}, {"type": "email", "to": "alerts@deplixo.com", "subject": "Urgent: Water parameter danger zone detected", "body": "A water parameter has entered a danger zone. Please review the latest water parameter reading immediately."}]}]} import { useState } from 'react'; import { useAuth, useCollection, capturePhoto } from '@deplixo/sdk'; import { Dashboard } from './components/Dashboard.jsx'; import { WaterTests } from './components/WaterTests.jsx'; import { WaterChanges } from './components/WaterChanges.jsx'; import { Equipment } from './components/Equipment.jsx'; function App() { const { user, loading, login, logout } = useAuth(); const [activeTab, setActiveTab] = useState('dashboard'); const [selectedTankId, setSelectedTankId] = useState(''); const [tankName, setTankName] = useState(''); const [capturingTankId, setCapturingTankId] = useState(''); const [photoNotes, setPhotoNotes] = useState(''); const [fishSpecies, setFishSpecies] = useState(''); const [fishCount, setFishCount] = useState(''); const [editingFishId, setEditingFishId] = useState(''); const [editingFishSpecies, setEditingFishSpecies] = useState(''); const [editingFishCount, setEditingFishCount] = useState(''); const { items: tanks = [], add: addTank, update: updateTank, loading: tanksLoading } = useCollection('tanks', { personal: true }); const { items: tests = [] } = useCollection('waterTests', { personal: true }); const { items: changes = [] } = useCollection('waterChanges', { personal: true }); const { items: equipment = [] } = useCollection('equipment', { personal: true }); const { items: photos = [], add: addPhoto, loading: photosLoading } = useCollection('photos', { personal: true }); const { items: fish = [], add: addFish, update: updateFish, remove: removeFish } = useCollection('fish', { personal: true }); const tabs = [ { id: 'dashboard', label: '๐ Dashboard', icon: '๐' }, { id: 'tests', label: '๐งช Water Tests', icon: '๐งช' }, { id: 'changes', label: '๐ง Water Changes', icon: '๐ง' }, { id: 'equipment', label: '๐ง Equipment', icon: '๐ง' }, ]; const handleAddTank = async () => { const name = tankName.trim(); if (!name) return; const newTank = await addTank({ name, createdAt: new Date().toISOString(), isDefault: tanks.length === 0, }); if (newTank?.id) { setSelectedTankId(newTank.id); } setTankName(''); }; const handleSelectTank = async (tank) => { if (!tank?.id) return; setSelectedTankId(tank.id); if (tank?.isDefault) { return; } const defaultTank = tanks.find((item) => item.isDefault); if (defaultTank?.id && defaultTank.id !== tank.id) { await updateTank(defaultTank.id, { isDefault: false }); } }; const handleCaptureTankPhoto = async (tankId) => { if (!tankId) return; setCapturingTankId(tankId); try { const result = await capturePhoto({ facing: 'environment' }); if (result?.url) { await addPhoto({ tankId, url: result.url, notes: photoNotes.trim(), createdAt: new Date().toISOString(), }); setPhotoNotes(''); } } finally { setCapturingTankId(''); } }; const handleAddFish = async () => { const species = fishSpecies.trim(); const count = Number(fishCount); if (!effectiveTankId || !species || !Number.isFinite(count) || count < 0) return; await addFish({ tankId: effectiveTankId, species, count: Math.floor(count), createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }); setFishSpecies(''); setFishCount(''); }; const startEditFish = (item) => { setEditingFishId(item.id); setEditingFishSpecies(item.species || ''); setEditingFishCount(String(item.count ?? 0)); }; const cancelEditFish = () => { setEditingFishId(''); setEditingFishSpecies(''); setEditingFishCount(''); }; const handleSaveFish = async (fishId) => { const species = editingFishSpecies.trim(); const count = Number(editingFishCount); if (!fishId || !species || !Number.isFinite(count) || count < 0) return; await updateFish(fishId, { species, count: Math.floor(count), updatedAt: new Date().toISOString(), }); cancelEditFish(); }; const handleRemoveFish = async (fishId) => { if (!fishId) return; await removeFish(fishId); if (editingFishId === fishId) cancelEditFish(); }; if (loading) return
Aquarium Maintenance Tracker
Use Google sign-in to keep each aquarium and tank scoped to your account.
Aquarium Maintenance Tracker
Signed in as {user.name}
No fish inventory for this tank yet.
Add species and counts to keep track of livestock per tank.Loading photos...
No photos for this tank yet.
Capture a photo to build a per-tank gallery.