Skip to content

Commit d33b7d2

Browse files
Merge pull request #42 from CivicTechAtlanta/steve-calc-flow
save
2 parents 98d3582 + 54b547c commit d33b7d2

30 files changed

+1128
-104
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
'use client';
2+
3+
import React, { useState } from 'react';
4+
import { useTranslation } from "react-i18next";
5+
6+
import Input from '../../chlorine-weight/components/Input';
7+
import Modal from '../../components/Modal/Modal';
8+
9+
import {
10+
CalculatorFlowSharedStateData
11+
} from "./Interfaces";
12+
13+
export default function ChlorineWeightFormula({ onCalculate, sharedState }: { onCalculate: (data: any) => void, sharedState: CalculatorFlowSharedStateData }) {
14+
const { t } = useTranslation();
15+
16+
const [showText, setShowText] = useState(false);
17+
const [errorMessage, setErrorMessage] = useState('');
18+
19+
const [showModal, setShowModal] = useState(null as string | null);
20+
21+
console.log('ChlorineWeightFormula sharedState', sharedState);
22+
23+
const [formData, setFormData] = useState({
24+
motherSolution: sharedState.msVolume || '',
25+
waterIngress: sharedState.reservoirIngress || '',
26+
desiredConcentration: sharedState.desiredConcentration || '',
27+
dripRate: sharedState.desiredDripRate || '',
28+
chlorinePercentage: sharedState.chlorinePercentage || '',
29+
});
30+
31+
//Calculate the weight of chlorine needed
32+
const chlorineWeight = .36 * ((Number(formData.motherSolution) * Number(formData.waterIngress) * Number(formData.desiredConcentration)) / (Number(formData.dripRate) * Number(formData.chlorinePercentage)))
33+
34+
const handleClick = () => {
35+
if (
36+
formData.motherSolution === '' ||
37+
formData.waterIngress === '' ||
38+
formData.desiredConcentration === '' ||
39+
formData.dripRate === '' ||
40+
formData.chlorinePercentage === ''
41+
) {
42+
setErrorMessage('Please fill all inputs');
43+
setShowText(false);
44+
} else {
45+
setErrorMessage('');
46+
setShowText(true);
47+
onCalculate({
48+
chlorineWeight: chlorineWeight,
49+
msVolume: formData.motherSolution,
50+
waterIngress: formData.waterIngress,
51+
desiredConcentration: formData.desiredConcentration,
52+
dripRate: formData.dripRate,
53+
chlorinePercentage: formData.chlorinePercentage
54+
});
55+
}
56+
};
57+
58+
const handleClear = () => {
59+
Object.keys(formData).forEach(key => {
60+
setFormData({
61+
...formData,
62+
[key]: '',
63+
});
64+
});
65+
66+
setShowText(false);
67+
setErrorMessage('')
68+
};
69+
70+
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
71+
const { name, value } = event.target;
72+
setFormData((prev) => ({
73+
...prev,
74+
[name]: parseFloat(value) || 0,
75+
}));
76+
};
77+
78+
return (
79+
<div className="center">
80+
<div className="pageHeader">
81+
<h1>{t('Chlorine Weight Formula')}
82+
<svg onClick={() => setShowModal('info')} fill="#288DCE" viewBox="0 0 50 50"><path d="M 25 2 C 12.309295 2 2 12.309295 2 25 C 2 37.690705 12.309295 48 25 48 C 37.690705 48 48 37.690705 48 25 C 48 12.309295 37.690705 2 25 2 z M 25 4 C 36.609824 4 46 13.390176 46 25 C 46 36.609824 36.609824 46 25 46 C 13.390176 46 4 36.609824 4 25 C 4 13.390176 13.390176 4 25 4 z M 25 11 A 3 3 0 0 0 22 14 A 3 3 0 0 0 25 17 A 3 3 0 0 0 28 14 A 3 3 0 0 0 25 11 z M 21 21 L 21 23 L 22 23 L 23 23 L 23 36 L 22 36 L 21 36 L 21 38 L 22 38 L 23 38 L 27 38 L 28 38 L 29 38 L 29 36 L 28 36 L 27 36 L 27 21 L 26 21 L 22 21 L 21 21 z" /></svg>
83+
</h1>
84+
</div>
85+
86+
<div className="input-wrapper">
87+
<Input
88+
label={`${t('Mother Solution')} (${t('liters')})`}
89+
name='motherSolution'
90+
value={formData.motherSolution}
91+
placeholder='600'
92+
handleChange={handleChange}
93+
/>
94+
<Input
95+
label={`${t('Water Ingress')} (${t('liters')}/${'second'})`}
96+
name='waterIngress'
97+
value={formData.waterIngress}
98+
placeholder='20'
99+
handleChange={handleChange}
100+
/>
101+
<Input
102+
label={`${t('Desired Concentration')} (${t('miligrams')}/${'liter'})`}
103+
name='desiredConcentration'
104+
value={formData.desiredConcentration}
105+
placeholder='1'
106+
handleChange={handleChange}
107+
/>
108+
<Input
109+
label={`${t('Drip Rate')} (${t('liters')}/${'hour'})`}
110+
name='dripRate'
111+
value={formData.dripRate}
112+
placeholder='2'
113+
handleChange={handleChange}
114+
/>
115+
<Input
116+
label={`${t('Chlorine Percentage')}`}
117+
name='chlorinePercentage'
118+
value={formData.chlorinePercentage}
119+
placeholder='0.7'
120+
handleChange={handleChange}
121+
/>
122+
123+
{errorMessage && <p style={{ color: 'red' }}>{errorMessage}</p>}
124+
125+
<button className="button" onClick={handleClear}>{t('Clear')}</button>
126+
127+
{showText ? (
128+
<p>{`${t('The weight of chlorine needed is')}: ${chlorineWeight} ${t('grams')}`}</p>
129+
) : (
130+
<button className="button primary" onClick={handleClick}>{t('Submit')}</button>
131+
)}
132+
</div>
133+
134+
<Modal
135+
show={showModal === 'info'}
136+
closeModal={() => setShowModal(null)}
137+
headerText='How to Determine Chlorine Weight Formula'
138+
imageKey='CHLORINE_WEIGHT'/>
139+
140+
</div>
141+
);
142+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
"use client";
2+
3+
import { useEffect, useState } from "react";
4+
import { useTranslation } from "react-i18next";
5+
import Modal from '../../components/Modal/Modal';
6+
7+
import '../../drip-rate/DripRate.scss';
8+
9+
import {
10+
CalculatorFlowSharedStateData
11+
} from "./Interfaces";
12+
13+
export default function DripRateFormula({ onCalculate, sharedState }: {
14+
onCalculate: (data: any) => void,
15+
sharedState: CalculatorFlowSharedStateData
16+
}) {
17+
const { t } = useTranslation();
18+
19+
const [motherSolutionVolume, setMotherSolutionVolume] = useState<number>(sharedState.msVolume || 0)
20+
const [dripRate, setDripRate] = useState<number>(sharedState.desiredDripRate || 0)
21+
const [refillTime, setRefillTime] = useState<number>(0)
22+
23+
const [showModal, setShowModal] = useState(null as string | null);
24+
25+
const handleSubmit = () => {
26+
const calculatedDripRate = refillTime > 0 ? (motherSolutionVolume * 1000) / (refillTime * 1440) : 0
27+
setDripRate(calculatedDripRate)
28+
onCalculate({
29+
msVolume: motherSolutionVolume,
30+
refillTime: refillTime,
31+
dripRate: calculatedDripRate
32+
})
33+
}
34+
35+
return (
36+
<div className="center">
37+
<div className="pageHeader">
38+
<h1>{t('Recharge Time Formula')}
39+
<svg onClick={() => setShowModal('info')} fill="#288DCE" viewBox="0 0 50 50"><path d="M 25 2 C 12.309295 2 2 12.309295 2 25 C 2 37.690705 12.309295 48 25 48 C 37.690705 48 48 37.690705 48 25 C 48 12.309295 37.690705 2 25 2 z M 25 4 C 36.609824 4 46 13.390176 46 25 C 46 36.609824 36.609824 46 25 46 C 13.390176 46 4 36.609824 4 25 C 4 13.390176 13.390176 4 25 4 z M 25 11 A 3 3 0 0 0 22 14 A 3 3 0 0 0 25 17 A 3 3 0 0 0 28 14 A 3 3 0 0 0 25 11 z M 21 21 L 21 23 L 22 23 L 23 23 L 23 36 L 22 36 L 21 36 L 21 38 L 22 38 L 23 38 L 27 38 L 28 38 L 29 38 L 29 36 L 28 36 L 27 36 L 27 21 L 26 21 L 22 21 L 21 21 z" /></svg>
40+
</h1>
41+
</div>
42+
43+
<div className="input-wrapper">
44+
45+
<div className="input-group">
46+
<label>{`${t('Mother Solution Volume')} (${t('L')})`}</label>
47+
<input type="number" value={motherSolutionVolume} onChange={(event) => { setMotherSolutionVolume(Number(event.target.value)) }} />
48+
</div>
49+
50+
<div className="input-group">
51+
<label>{`${t('Refill time')} (${t('days')})`}</label>
52+
<input type="number" value={refillTime} onChange={(event) => { setRefillTime(Number(event.target.value)) }} />
53+
</div>
54+
55+
<button className="button" onClick={() => {
56+
setMotherSolutionVolume(0)
57+
setRefillTime(0)
58+
setDripRate(0)
59+
}}>{t('Clear')}</button>
60+
61+
<button type="submit" className="primary button" onClick={() => {
62+
handleSubmit() // Simulate form submission
63+
}}>
64+
{t('Submit')}
65+
</button>
66+
67+
<h2>{`${t('Drip Rate is')}: ${dripRate.toFixed(2)} ${t('milliliters')}/${t('minute')}`}</h2>
68+
</div>
69+
70+
<Modal
71+
show={showModal === 'info'}
72+
closeModal={() => setShowModal(null)}
73+
headerText={['Drip Rate']}
74+
modalText={[t('RechargeText1')]}
75+
imageKey={[null, 'CHLORINE_WEIGHT']}
76+
/>
77+
</div>
78+
);
79+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import "../styles/Input.css"
2+
3+
type InputProps = {
4+
label: string;
5+
name: string;
6+
handleChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
7+
min?: string;
8+
};
9+
10+
export default function Input({ label, name, min, handleChange }: InputProps) {
11+
return (
12+
<div className="input-group">
13+
<p>{label}</p>
14+
<input name={name} min={min} type="number" onChange={handleChange} step="0.01"></input>
15+
</div>
16+
);
17+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
export interface DripRateData {
2+
msVolume: number | null,
3+
refillTime: number | null,
4+
dripRate: number | null
5+
}
6+
7+
export interface ChlorineWeightData {
8+
weight: number | null,
9+
concentration: number | null
10+
}
11+
12+
export interface IngressData {
13+
flowRate: number | null,
14+
}
15+
16+
export interface MotherSolutionConcentrationData {
17+
volume: number | null,
18+
concentration: number | null
19+
}
20+
21+
export interface MotherSolutionTankMaxWeightData {
22+
weight: number | null,
23+
concentration: number | null
24+
}
25+
26+
export interface CalculatorFlowSharedStateData {
27+
msVolume: number | null,
28+
chlorinePercentage: number | null,
29+
reservoirIngress: number | null,
30+
chlorineWeight: number | null,
31+
desiredDripRate: number | null,
32+
msConcentration: number | null
33+
desiredConcentration: number | null
34+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
"use client";
2+
3+
import { useState } from "react";
4+
import { useTranslation } from "react-i18next";
5+
import Modal from '../../components/Modal/Modal';
6+
7+
import Form from "../../mother-solution-concentration/components/Form";
8+
9+
import "../../mother-solution-concentration/styles/Main.css";
10+
11+
export default function MotherSolutionConcentrationFormula({ onCalculate, sharedState }: { onCalculate: (data: any) => void, sharedState: object }) {
12+
const { t } = useTranslation();
13+
14+
const [concentratedMotherSolution, setConcentratedMotherSolution] =
15+
useState(0);
16+
17+
const [showModal, setShowModal] = useState(null as string | null);
18+
const handleCalculate = (calculatedValue: number) => {
19+
setConcentratedMotherSolution(calculatedValue);
20+
onCalculate(calculatedValue);
21+
};
22+
23+
return (
24+
<div className="center">
25+
<div className="pageHeader">
26+
<h1>{t('Mother Solution Concentration Formula')}
27+
<svg onClick={() => setShowModal('info')} fill="#288DCE" viewBox="0 0 50 50"><path d="M 25 2 C 12.309295 2 2 12.309295 2 25 C 2 37.690705 12.309295 48 25 48 C 37.690705 48 48 37.690705 48 25 C 48 12.309295 37.690705 2 25 2 z M 25 4 C 36.609824 4 46 13.390176 46 25 C 46 36.609824 36.609824 46 25 46 C 13.390176 46 4 36.609824 4 25 C 4 13.390176 13.390176 4 25 4 z M 25 11 A 3 3 0 0 0 22 14 A 3 3 0 0 0 25 17 A 3 3 0 0 0 28 14 A 3 3 0 0 0 25 11 z M 21 21 L 21 23 L 22 23 L 23 23 L 23 36 L 22 36 L 21 36 L 21 38 L 22 38 L 23 38 L 27 38 L 28 38 L 29 38 L 29 36 L 28 36 L 27 36 L 27 21 L 26 21 L 22 21 L 21 21 z" /></svg>
28+
</h1>
29+
</div>
30+
31+
<Form onCalculate={handleCalculate} sharedState={sharedState} />
32+
33+
<div className="result-wrapper">
34+
<h2>{`${t('The concentration of the mother solution is')}:`}</h2>
35+
36+
<p className="answer">
37+
{`${concentratedMotherSolution.toFixed(2)} ${t('mg')}/${t('L')}`}
38+
</p>
39+
</div>
40+
<Modal
41+
show={showModal === 'info'}
42+
closeModal={() => setShowModal(null)}
43+
headerText='How to Determine Chlorine Weight Formula'
44+
imageKey='CHLORINE_WEIGHT'/>
45+
</div>
46+
47+
);
48+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"use client";
2+
3+
import { useState } from "react";
4+
import { useTranslation } from "react-i18next";
5+
6+
import Form from "../../mother-tank-maximum-weight/components/Form";
7+
import Modal from '../../components/Modal/Modal';
8+
9+
import "../styles/Main.css";
10+
11+
import {
12+
CalculatorFlowSharedStateData
13+
} from "./Interfaces";
14+
15+
export default function MotherTankMaximumWeightFormula({ onCalculate, sharedState }: { onCalculate: (data: any) => void, sharedState: CalculatorFlowSharedStateData }) {
16+
const { t } = useTranslation();
17+
18+
const [motherWeightMaximumWeightSolution, setMotherWeightMaximumWeightSolution] = useState(0);
19+
const [showModal, setShowModal] = useState(null as string | null);
20+
21+
22+
const handleCalculate = (calculatedValue: any) => {
23+
setMotherWeightMaximumWeightSolution(calculatedValue.msMaximumWeight);
24+
onCalculate({
25+
motherWeightMaximumWeightSolution: calculatedValue.msMaximumWeight,
26+
msVolume: calculatedValue.msVolume,
27+
chlorinePercentage: calculatedValue.chlorinePercentage
28+
});
29+
};
30+
31+
return (
32+
<div className="center">
33+
<div className="pageHeader">
34+
<h1>{t('Mother Tank Maximum Weight Formula')}
35+
<svg onClick={() => setShowModal('info')} fill="#288DCE" viewBox="0 0 50 50"><path d="M 25 2 C 12.309295 2 2 12.309295 2 25 C 2 37.690705 12.309295 48 25 48 C 37.690705 48 48 37.690705 48 25 C 48 12.309295 37.690705 2 25 2 z M 25 4 C 36.609824 4 46 13.390176 46 25 C 46 36.609824 36.609824 46 25 46 C 13.390176 46 4 36.609824 4 25 C 4 13.390176 13.390176 4 25 4 z M 25 11 A 3 3 0 0 0 22 14 A 3 3 0 0 0 25 17 A 3 3 0 0 0 28 14 A 3 3 0 0 0 25 11 z M 21 21 L 21 23 L 22 23 L 23 23 L 23 36 L 22 36 L 21 36 L 21 38 L 22 38 L 23 38 L 27 38 L 28 38 L 29 38 L 29 36 L 28 36 L 27 36 L 27 21 L 26 21 L 22 21 L 21 21 z" /></svg>
36+
</h1>
37+
</div>
38+
39+
<Form onCalculate={handleCalculate} sharedState={sharedState} />
40+
41+
<div className="result-wrapper">
42+
<h2>{`${t('The maximum weight of the mother tank is')}:`}</h2>
43+
<p className="answer">
44+
{`${Math.trunc(motherWeightMaximumWeightSolution)} ${t('grams')}`} {`(${(motherWeightMaximumWeightSolution / 1000).toFixed(1)} ${t('kilograms')})`}
45+
</p>
46+
</div>
47+
48+
<Modal
49+
show={showModal === 'info'}
50+
closeModal={() => setShowModal(null)}
51+
headerText='How to Determine Maximum Mother Tank Weight'
52+
imageKey='CHLORINE_WEIGHT'></Modal>
53+
</div>
54+
);
55+
}

0 commit comments

Comments
 (0)