add some more data manipulation buttons

This commit is contained in:
Michael Zhang 2022-10-24 03:49:22 -05:00
parent e3c6f6ec92
commit 0d30b03b93
4 changed files with 123 additions and 38 deletions

View file

@ -8,11 +8,27 @@ export interface Props {
}
const ClickableContainer = styled.span`
display: inline-block;
padding: 4px 10px;
margin: 4px;
border: 1px solid #eee;
border-radius: 5px;
width: 120px;
&:hover {
background-color: #eee;
}
`;
const EditingBox = styled.input`
display: inline-block;
padding: 4px 10px;
margin: 4px;
border: 1px solid #eee;
border-radius: 5px;
width: 120px;
`;
export default function EditBox({ valueAtom }: Props) {
const [value, setValue] = useAtom(valueAtom);
const [valueInput, setValueInput] = useState("");
@ -32,6 +48,7 @@ export default function EditBox({ valueAtom }: Props) {
e.preventDefault();
try {
const n = parseFloat(valueInput);
if (isNaN(n) || !isFinite(n)) return;
setValue(n);
setEditing(false);
} catch (e) {
@ -42,7 +59,7 @@ export default function EditBox({ valueAtom }: Props) {
if (editing) {
return (
<form onSubmit={finalize} style={{ display: "inline" }}>
<input
<EditingBox
autoFocus={true}
type="number"
step="0.01"

View file

@ -1,4 +1,5 @@
import { Atom, useAtom } from "jotai";
import { Badge, ListGroup } from "react-bootstrap";
export interface IPerson {
name: string;
@ -8,7 +9,25 @@ export interface Props {
personAtom: Atom<IPerson>;
}
export default function Person({ personAtom }: Props) {
const [person, _] = useAtom(personAtom);
return <span style={{ marginInline: "5px" }}>{person.name}</span>;
export default function Person({ personAtom, splitBetweenAtom }: Props) {
const [person] = useAtom(personAtom);
const [splitBetween, setSplitBetween] = useAtom(splitBetweenAtom);
const removeSelf = (_) => {
setSplitBetween([...splitBetween.filter((x) => x != personAtom)]);
};
return (
<ListGroup.Item>
{person.name}
<Badge
bg="danger"
pill
onClick={removeSelf}
style={{ cursor: "pointer" }}
>
&times;
</Badge>
</ListGroup.Item>
);
}

View file

@ -1,4 +1,7 @@
import { Atom, useAtom } from "jotai";
import { atom, Atom, useAtom, useAtomValue } from "jotai";
import { useState } from "react";
import { Badge, Card, ListGroup } from "react-bootstrap";
import { receiptAtom } from "../lib/state";
import EditBox from "./EditBox";
import Person, { IPerson } from "./Person";
@ -13,16 +16,49 @@ export interface Props {
}
function SplitBetween({ splitBetweenAtom }) {
const [splitBetween, _] = useAtom(splitBetweenAtom);
return splitBetween.length > 0 ? (
const [splitBetween, setSplitBetween] = useAtom(splitBetweenAtom);
const [input, setInput] = useState("");
const [editing, setEditing] = useState(false);
const startEditing = (_) => {
setInput("");
setEditing(true);
};
const addPerson = (e) => {
e.preventDefault();
setSplitBetween([...splitBetween, atom({ name: input })]);
setEditing(false);
};
return (
<div>
Split between ({splitBetween.length}):
{splitBetween.map((a, i) => (
<Person personAtom={a} key={`split-${i}`} />
))}
<ListGroup horizontal>
{splitBetween.map((a, i) => (
<Person
personAtom={a}
key={`split-${i}`}
splitBetweenAtom={splitBetweenAtom}
/>
))}
<ListGroup.Item onClick={startEditing}>
{editing ? (
<form onSubmit={addPerson}>
<input
autoFocus={true}
type="text"
value={input}
onBlur={(_) => setEditing(false)}
onInput={(e) => setInput(e.target.value)}
/>
</form>
) : (
"[+]"
)}
</ListGroup.Item>
</ListGroup>
</div>
) : (
<></>
);
}
@ -31,14 +67,28 @@ function Price({ priceAtom }) {
}
export default function ReceiptItem({ itemAtom }: Props) {
const [receipt, setReceipt] = useAtom(receiptAtom);
const [item, _] = useAtom(itemAtom);
const removeSelf = (_) => {
setReceipt([...receipt.filter((x) => x != itemAtom)]);
};
return (
<>
<span>
<b>{item.name}</b>
</span>
(<Price priceAtom={item.price} />)
<SplitBetween splitBetweenAtom={item.splitBetween} />
</>
<Card>
<Card.Body>
<Card.Title>{item.name}</Card.Title>
Item price: <Price priceAtom={item.price} />
<Badge
bg="danger"
pill
onClick={removeSelf}
style={{ cursor: "pointer" }}
>
&times;
</Badge>
<SplitBetween splitBetweenAtom={item.splitBetween} />
</Card.Body>
</Card>
);
}

View file

@ -51,26 +51,25 @@ const Home: NextPage = () => {
<EditBox valueAtom={totalAtom} />
</div>
<ul>
{receipt.map((itemAtom, i) => {
return (
<li key={`receiptItem-${i}`}>
<ReceiptItem itemAtom={itemAtom} />
</li>
);
})}
</ul>
{receipt.map((itemAtom, i) => {
return <ReceiptItem itemAtom={itemAtom} key={`receiptItem-${i}`} />;
})}
<div>
Total breakdown:
<ul>
{[...total.entries()].map(([person, value], i) => (
<li key={`breakdown-${i}`}>
<b>{person}</b>: {formatter.format(value)}
</li>
))}
</ul>
</div>
{total.size > 0 && (
<>
<h3>Weighted Breakdown</h3>
<div>
<ul>
{[...total.entries()].map(([person, value], i) => (
<li key={`breakdown-${i}`}>
<b>{person}</b>: {formatter.format(value)}
</li>
))}
</ul>
</div>
</>
)}
<small>
<a href="https://github.com/iptq/wisesplit/">[source]</a>