diff options
author | Rosyid Haryadi <rosyid_haryadi@protonmail.com> | 2023-09-30 18:29:36 +0700 |
---|---|---|
committer | Rosyid Haryadi <rosyid_haryadi@protonmail.com> | 2023-09-30 18:29:36 +0700 |
commit | ca044349cac7434560f2646bc4ea4c27f5783d47 (patch) | |
tree | 91c7f9eb99a9be9d7f6ca5f1bc7e715316f1c65e | |
parent | 63633dcd62e72a6c55533b50949630ed8d554328 (diff) |
cursed state management
-rw-r--r-- | src/App.jsx | 24 | ||||
-rw-r--r-- | src/Entry.jsx | 36 | ||||
-rw-r--r-- | src/Result.jsx | 44 | ||||
-rw-r--r-- | src/SalaryInput.jsx | 11 |
4 files changed, 99 insertions, 16 deletions
diff --git a/src/App.jsx b/src/App.jsx index da2bbc7..8a487e0 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -4,9 +4,11 @@ import Entry from "./Entry.jsx"; import {Button, Container, Typography} from "@mui/material"; import dayjs from "dayjs"; import SalaryInput from "./SalaryInput.jsx"; +import Result from "./Result.jsx"; function App() { + const [baseSalary, setBaseSalary] = useState(0); const [listEntry, setListEntry] = useState( [ {id: 0, date: dayjs(), start: dayjs(), finish: dayjs()}, @@ -24,6 +26,20 @@ function App() { return lastEntry.id; } + const handleEntryChange = (entry, updatedAttr) => { + const updatedEntryList = listEntry.map((entryOnList) => { + if (entryOnList.id === entry.id) { + return {...entryOnList, [updatedAttr]: entry[updatedAttr]} + } + return entryOnList; + }); + setListEntry(updatedEntryList); + } + + const handleBaseSalaryChange = (baseSalaryInput) => { + setBaseSalary(baseSalaryInput); + } + const addToList = () => { const newEntry = { id: getLastId() + 1, @@ -43,19 +59,22 @@ function App() { return ( <Container> <Typography variant='h3' align='center'>Overtime Calculator</Typography> - <Typography variant='overline' display='block' align='center'>🤑🤑 Sudahkah anda lembur hari ini? 🤑🤑</Typography> + <Typography variant='overline' display='block' align='center'>🤑🤑 Sudahkah anda lembur hari ini? + 🤑🤑</Typography> <ul> <li style={{listStyle: 'none', margin: '20px 0'}}> - <SalaryInput/> + <SalaryInput handleBaseSalaryChange={handleBaseSalaryChange}/> </li> {listEntry.map((entry) => { return ( <div key={entry.id} style={{display: 'flex', gap: '10px', marginBottom: '10px'}}> <li style={{listStyle: 'none'}} key={entry.id}> <Entry + propId={entry.id} propDate={entry.date} propStart={entry.start} propFinish={entry.finish} + handleEntryChange={handleEntryChange} /> </li> <Button @@ -75,6 +94,7 @@ function App() { ) })} </ul> + <Result listEntry={listEntry} baseSalary={baseSalary}/> </Container> ) } diff --git a/src/Entry.jsx b/src/Entry.jsx index e554050..c486680 100644 --- a/src/Entry.jsx +++ b/src/Entry.jsx @@ -4,7 +4,7 @@ import {AdapterDayjs} from '@mui/x-date-pickers/AdapterDayjs'; import 'dayjs/locale/id'; -function Entry({propDate, propStart, propFinish}) { +function Entry({propId, propDate, propStart, propFinish, handleEntryChange}) { const [date, setDate] = useState(propDate); const [start, setStart] = useState(propStart); const [finish, setFinish] = useState(propFinish); @@ -12,15 +12,31 @@ function Entry({propDate, propStart, propFinish}) { return ( <LocalizationProvider dateAdapter={AdapterDayjs} adapterLocale='id'> <div style={{display: 'flex', gap: '5px'}}> - <DatePicker label="Tanggal Lembur" value={date} - onAccept={(newDate) => setDate(newDate)}/> - <TimePicker label="Mulai" ampm={false} value={start} maxTime={finish} onAccept={(newStart) => { - setStart(newStart) - }}/> - <TimePicker label="Selesai" ampm={false} value={finish} minTime={start} onAccept={(newFinish) => { - setFinish(newFinish); - console.log(newFinish) - }}/> + <DatePicker label="Tanggal Lembur" + value={date} + onAccept={(newDate) => { + setDate(newDate); + handleEntryChange({id: propId, date: newDate}, 'date') + }} + /> + <TimePicker label="Mulai" + ampm={false} + value={start} + maxTime={finish} + onAccept={(newStart) => { + setStart(newStart); + handleEntryChange({id: propId, start: newStart}, 'start') + }} + /> + <TimePicker label="Selesai" + ampm={false} + value={finish} + minTime={start} + onAccept={(newFinish) => { + setFinish(newFinish); + handleEntryChange({id: propId, finish: newFinish}, 'finish') + }} + /> </div> </LocalizationProvider> ) diff --git a/src/Result.jsx b/src/Result.jsx new file mode 100644 index 0000000..0ea4810 --- /dev/null +++ b/src/Result.jsx @@ -0,0 +1,44 @@ +import {useEffect, useState} from "react"; +import entry from "./Entry.jsx"; + +function Result({listEntry, baseSalary}) { + const [totalOvertimePay, setTotalOvertimePay] = useState(0); + + useEffect(() => { + setTotalOvertimePay(getOvertimePayTotal(listEntry, baseSalary)); + }, [listEntry, baseSalary]); + + return ( + <div> + Totalnye: Rp{totalOvertimePay} + {listEntry.map((entry) => { + return ( + <div key={entry.id}> + <p>{entry.date.format('DD MMMM YYYY')} dapetnya Rp{calculatePerDay(entry, baseSalary)}</p> + </div> + ) + })} + </div> + ) +} + +function calculatePerDay(entry, baseSalary) { + const hourlyPay = baseSalary / 173; + const timeDiff = entry.finish.diff(entry.start, 'hour', true); + let multiplier = 1.5; // Jam pertama + if (timeDiff > 1) { + multiplier += (timeDiff - 1) * 2; // Jam jam berikutnya + } + + return multiplier * hourlyPay; +} + +function getOvertimePayTotal(listEntry, baseSalary) { + let total = 0; + listEntry.forEach((entry) => { + total += calculatePerDay(entry, baseSalary) + }); + return total; +} + +export default Result;
\ No newline at end of file diff --git a/src/SalaryInput.jsx b/src/SalaryInput.jsx index f04c68f..753d457 100644 --- a/src/SalaryInput.jsx +++ b/src/SalaryInput.jsx @@ -2,8 +2,8 @@ import { useState } from "react"; import TextField from "@mui/material/TextField"; import { NumericFormat } from "react-number-format"; -function SalaryInput() { - const [displayValue, setDisplayValue] = useState(''); +function SalaryInput({handleBaseSalaryChange}) { + const [baseSalary, setBaseSalary] = useState(''); return ( <NumericFormat customInput={ TextField } @@ -11,8 +11,11 @@ function SalaryInput() { variant="outlined" valueIsNumericString={true} thousandSeparator={true} - value={displayValue} - onValueChange={(value, sourceInfo) => {setDisplayValue(value.value)}} + value={baseSalary} + onValueChange={(value, sourceInfo) => { + setBaseSalary(value.value); + handleBaseSalaryChange(value.value); + }} InputProps={{ startAdornment: <span>Rp</span> }} |