Changes
This commit is contained in:
parent
0d30b03b93
commit
90924073ed
6 changed files with 102 additions and 74 deletions
|
@ -1,6 +1,5 @@
|
|||
import { Atom, useAtom } from "jotai";
|
||||
import { useState } from "react";
|
||||
import { Form } from "react-bootstrap";
|
||||
import styled from "styled-components";
|
||||
|
||||
export interface Props {
|
||||
|
|
|
@ -12,6 +12,25 @@ export default function Layout({ children }) {
|
|||
<Container>
|
||||
<main>{children}</main>
|
||||
</Container>
|
||||
|
||||
<footer style={{ textAlign: "center" }}>
|
||||
<small>
|
||||
<a href="https://github.com/iptq/wisesplit/" target="_blank">
|
||||
[source]
|
||||
</a>
|
||||
·
|
||||
<a href="https://www.gnu.org/licenses/agpl-3.0.txt" target="_blank">
|
||||
[license]
|
||||
</a>
|
||||
·
|
||||
<a href="https://github.com/iptq/wisesplit/stargazers">
|
||||
<img
|
||||
alt="GitHub stars"
|
||||
src="https://img.shields.io/github/stars/iptq/wisesplit?style=social"
|
||||
/>
|
||||
</a>
|
||||
</small>
|
||||
</footer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Atom, useAtom } from "jotai";
|
||||
import { Atom, useAtom, WritableAtom } from "jotai";
|
||||
import { Badge, ListGroup } from "react-bootstrap";
|
||||
|
||||
export interface IPerson {
|
||||
|
@ -7,6 +7,7 @@ export interface IPerson {
|
|||
|
||||
export interface Props {
|
||||
personAtom: Atom<IPerson>;
|
||||
splitBetweenAtom: WritableAtom<Atom<IPerson>[]>;
|
||||
}
|
||||
|
||||
export default function Person({ personAtom, splitBetweenAtom }: Props) {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { atom, Atom, useAtom, useAtomValue } from "jotai";
|
||||
import { useState } from "react";
|
||||
import { Badge, Card, ListGroup } from "react-bootstrap";
|
||||
import { Atom, useAtom } from "jotai";
|
||||
import { Badge, Card } from "react-bootstrap";
|
||||
import { receiptAtom } from "../lib/state";
|
||||
import EditBox from "./EditBox";
|
||||
import Person, { IPerson } from "./Person";
|
||||
import { IPerson } from "./Person";
|
||||
import SplitBetween from "./SplitBetween";
|
||||
|
||||
export interface IReceiptItem {
|
||||
name: string;
|
||||
|
@ -11,61 +11,14 @@ export interface IReceiptItem {
|
|||
splitBetween: Atom<Atom<IPerson>[]>;
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
itemAtom: Atom<IReceiptItem>;
|
||||
}
|
||||
|
||||
function SplitBetween({ splitBetweenAtom }) {
|
||||
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}):
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
function Price({ priceAtom }) {
|
||||
return <EditBox valueAtom={priceAtom} />;
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
itemAtom: Atom<IReceiptItem>;
|
||||
}
|
||||
|
||||
export default function ReceiptItem({ itemAtom }: Props) {
|
||||
const [receipt, setReceipt] = useAtom(receiptAtom);
|
||||
const [item, _] = useAtom(itemAtom);
|
||||
|
@ -76,17 +29,24 @@ export default function ReceiptItem({ itemAtom }: Props) {
|
|||
|
||||
return (
|
||||
<Card>
|
||||
<Card.Header>
|
||||
<Card.Title className="d-flex justify-content-between align-items-center">
|
||||
<h3>{item.name}</h3>
|
||||
<span>
|
||||
<Price priceAtom={item.price} />
|
||||
<Badge
|
||||
bg="danger"
|
||||
pill
|
||||
onClick={removeSelf}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
×
|
||||
</Badge>
|
||||
</span>
|
||||
</Card.Title>
|
||||
</Card.Header>
|
||||
|
||||
<Card.Body>
|
||||
<Card.Title>{item.name}</Card.Title>
|
||||
Item price: <Price priceAtom={item.price} />
|
||||
<Badge
|
||||
bg="danger"
|
||||
pill
|
||||
onClick={removeSelf}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
×
|
||||
</Badge>
|
||||
<SplitBetween splitBetweenAtom={item.splitBetween} />
|
||||
</Card.Body>
|
||||
</Card>
|
||||
|
|
55
components/SplitBetween.tsx
Normal file
55
components/SplitBetween.tsx
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { atom, Atom, useAtom } from "jotai";
|
||||
import { useState } from "react";
|
||||
import { ListGroup } from "react-bootstrap";
|
||||
import Person, { IPerson } from "./Person";
|
||||
|
||||
export interface Props {
|
||||
splitBetweenAtom: Atom<Atom<IPerson>[]>;
|
||||
}
|
||||
|
||||
export default function SplitBetween({ splitBetweenAtom }: Props) {
|
||||
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}):
|
||||
<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>
|
||||
);
|
||||
}
|
|
@ -42,7 +42,7 @@ const Home: NextPage = () => {
|
|||
placeholder="Add item..."
|
||||
onInput={(e) => setInput(e.target.value)}
|
||||
value={input}
|
||||
style={{ padding: "8px", fontSize: "1.5em" }}
|
||||
style={{ padding: "8px 16px", fontSize: "1.5em" }}
|
||||
/>
|
||||
</Form>
|
||||
|
||||
|
@ -70,12 +70,6 @@ const Home: NextPage = () => {
|
|||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
<small>
|
||||
<a href="https://github.com/iptq/wisesplit/">[source]</a>
|
||||
·
|
||||
<a href="https://www.gnu.org/licenses/agpl-3.0.txt">[license]</a>
|
||||
</small>
|
||||
</main>
|
||||
);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue