File size: 9,061 Bytes
be02369
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

import React, { useState, useMemo } from 'react';
import { ShovelIcon, PlusCircleIcon, Trash2Icon } from '../components/icons';

type PotShape = 'rectangular' | 'round';
type Units = 'cm' | 'in';

const SoilVolumeCalculatorView: React.FC = () => {
    const [units, setUnits] = useState<Units>('in');
    const [shape, setShape] = useState<PotShape>('rectangular');
    const [dimensions, setDimensions] = useState({ length: 12, width: 8, depth: 4, diameter: 10 });
    const [recipe, setRecipe] = useState([
        { id: 1, name: 'Akadama', percentage: 40 },
        { id: 2, name: 'Pumice', percentage: 30 },
        { id: 3, name: 'Lava Rock', percentage: 30 },
    ]);

    const totalPercentage = useMemo(() => recipe.reduce((sum, item) => sum + item.percentage, 0), [recipe]);

    const volumeCm3 = useMemo(() => {
        const d = dimensions;
        const toCm = units === 'in' ? 2.54 : 1;
        if (shape === 'rectangular') {
            return (d.length * toCm) * (d.width * toCm) * (d.depth * toCm);
        } else { // round
            const radius = (d.diameter * toCm) / 2;
            return Math.PI * (radius * radius) * (d.depth * toCm);
        }
    }, [dimensions, shape, units]);

    const handleRecipeChange = (id: number, field: 'name' | 'percentage', value: string | number) => {
        setRecipe(prev => prev.map(item => item.id === id ? { ...item, [field]: value } : item));
    };

    const addComponent = () => {
        setRecipe(prev => [...prev, { id: Date.now(), name: 'New Component', percentage: 0 }]);
    };

    const removeComponent = (id: number) => {
        setRecipe(prev => prev.filter(item => item.id !== id));
    };

    const renderVolume = (volumeLiters: number) => (
        <div className="text-sm text-stone-600">
            <span>{volumeLiters.toFixed(2)} L</span> /&nbsp;
            <span>{(volumeLiters * 1.05669).toFixed(2)} qts</span> /&nbsp;
            <span>{(volumeLiters * 0.264172).toFixed(2)} gal</span>
        </div>
    );

    return (
        <div className="space-y-8 max-w-4xl mx-auto">
            <header className="text-center">
                <h2 className="text-3xl font-bold tracking-tight text-stone-900 sm:text-4xl flex items-center justify-center gap-3">
                    <ShovelIcon className="w-8 h-8 text-orange-900" />
                    Soil Mix Calculator
                </h2>
                <p className="mt-4 text-lg leading-8 text-stone-600">
                    Mix the perfect amount of soil for your pot. No more waste or running out halfway through repotting.
                </p>
            </header>

            <div className="grid grid-cols-1 md:grid-cols-2 gap-8 items-start">
                <div className="bg-white p-6 rounded-xl shadow-lg border border-stone-200 space-y-6">
                     <div>
                        <h3 className="font-semibold text-stone-800 mb-2">1. Pot Dimensions</h3>
                         <div className="flex gap-4 mb-4">
                            <div className="flex-1">
                                <label className="text-sm font-medium">Shape</label>
                                <select value={shape} onChange={e => setShape(e.target.value as PotShape)} className="w-full mt-1 p-2 border rounded-md bg-white">
                                    <option value="rectangular">Rectangular</option>
                                    <option value="round">Round</option>
                                </select>
                            </div>
                            <div className="flex-1">
                                <label className="text-sm font-medium">Units</label>
                                <select value={units} onChange={e => setUnits(e.target.value as Units)} className="w-full mt-1 p-2 border rounded-md bg-white">
                                    <option value="cm">Centimeters</option>
                                    <option value="in">Inches</option>
                                </select>
                            </div>
                         </div>
                         <div className="grid grid-cols-2 gap-4">
                            {shape === 'rectangular' ? (
                                <>
                                    <div><label>Length</label><input type="number" value={dimensions.length} onChange={e => setDimensions(d => ({...d, length: Number(e.target.value)}))} className="w-full mt-1 p-2 border rounded-md" /></div>
                                    <div><label>Width</label><input type="number" value={dimensions.width} onChange={e => setDimensions(d => ({...d, width: Number(e.target.value)}))} className="w-full mt-1 p-2 border rounded-md" /></div>
                                </>
                            ) : (
                                <div><label>Diameter</label><input type="number" value={dimensions.diameter} onChange={e => setDimensions(d => ({...d, diameter: Number(e.target.value)}))} className="w-full mt-1 p-2 border rounded-md" /></div>
                            )}
                             <div><label>Depth</label><input type="number" value={dimensions.depth} onChange={e => setDimensions(d => ({...d, depth: Number(e.target.value)}))} className="w-full mt-1 p-2 border rounded-md" /></div>
                         </div>
                    </div>

                    <div>
                        <h3 className="font-semibold text-stone-800 mb-2">2. Soil Recipe</h3>
                        <div className="space-y-2">
                           {recipe.map(item => (
                               <div key={item.id} className="flex items-center gap-2">
                                   <input type="text" value={item.name} onChange={e => handleRecipeChange(item.id, 'name', e.target.value)} className="w-full p-2 border rounded-md" />
                                   <input type="number" value={item.percentage} onChange={e => handleRecipeChange(item.id, 'percentage', Number(e.target.value))} className="w-24 p-2 border rounded-md" />
                                   <span className="font-bold text-stone-500">%</span>
                                   <button onClick={() => removeComponent(item.id)} className="p-2 text-red-500 hover:bg-red-100 rounded-md"><Trash2Icon className="w-5 h-5"/></button>
                               </div>
                           ))}
                        </div>
                        <button onClick={addComponent} className="mt-2 flex items-center gap-2 text-sm font-semibold text-green-700 hover:text-green-600">
                           <PlusCircleIcon className="w-5 h-5"/> Add Component
                        </button>
                        <div className="mt-4 w-full bg-stone-200 rounded-full h-2.5">
                            <div className={`h-2.5 rounded-full ${totalPercentage > 100 ? 'bg-red-500' : 'bg-green-600'}`} style={{ width: `${Math.min(100, totalPercentage)}%` }}></div>
                        </div>
                        <p className={`text-center text-sm mt-1 font-bold ${totalPercentage !== 100 ? 'text-red-600 animate-pulse' : 'text-green-700'}`}>
                           Total: {totalPercentage}%
                        </p>
                    </div>
                </div>

                <div className="bg-white p-6 rounded-xl shadow-lg border-2 border-orange-800 space-y-4">
                    <h3 className="text-xl font-bold text-center text-stone-900">Component Volumes Needed</h3>
                    <div className="text-center">
                         <p className="text-stone-600">Total Pot Volume:</p>
                         <p className="font-bold text-lg text-orange-900">{renderVolume(volumeCm3 / 1000)}</p>
                    </div>
                    <div className="divide-y divide-stone-200 border-t pt-4">
                        {recipe.map(item => {
                            const componentVolumeL = (volumeCm3 / 1000) * (item.percentage / 100);
                            return (
                                <div key={item.id} className="py-3">
                                    <div className="flex justify-between items-center font-bold">
                                        <span className="text-stone-800">{item.name}</span>
                                        <span className="text-orange-900">{item.percentage}%</span>
                                    </div>
                                    <div className="text-right">{renderVolume(componentVolumeL)}</div>
                                </div>
                            )
                        })}
                    </div>
                     {totalPercentage !== 100 && (
                        <p className="text-center text-red-600 text-sm font-semibold p-2 bg-red-50 rounded-md">
                           Your recipe percentages must add up to 100% for an accurate calculation.
                        </p>
                    )}
                </div>
            </div>
        </div>
    );
};

export default SoilVolumeCalculatorView;