Fix typescript errors

This commit is contained in:
Michael Zhang 2022-10-25 13:26:48 -05:00
parent c9750fdc5f
commit 4be8903816
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
11 changed files with 77 additions and 72 deletions

View file

@ -1,13 +1,9 @@
import { Atom, useAtom } from "jotai"; import { PrimitiveAtom, useAtom } from "jotai";
import { useState } from "react"; import { SyntheticEvent, useState } from "react";
import styled from "styled-components"; import styled from "styled-components";
export interface CanBeConvertedToString { export interface Props<T> {
toString(): string; valueAtom: PrimitiveAtom<T>;
}
export interface Props<T extends CanBeConvertedToString> {
valueAtom: Atom<T>;
formatter?: (arg: T) => string; formatter?: (arg: T) => string;
inputType?: string; inputType?: string;
validator: (arg: string) => T | null; validator: (arg: string) => T | null;
@ -33,7 +29,7 @@ const EditingBox = styled.input`
border-radius: 5px; border-radius: 5px;
`; `;
export default function EditBox<T extends CanBeConvertedToString>({ export default function EditBox<T>({
valueAtom, valueAtom,
formatter, formatter,
inputType, inputType,
@ -44,11 +40,11 @@ export default function EditBox<T extends CanBeConvertedToString>({
const [editing, setEditing] = useState(false); const [editing, setEditing] = useState(false);
const startEditing = (_: any) => { const startEditing = (_: any) => {
setValueInput(value.toString()); setValueInput(String(value));
setEditing(true); setEditing(true);
}; };
const finalize = (e: Event) => { const finalize = (e: SyntheticEvent) => {
e.preventDefault(); e.preventDefault();
const validateResult = validator(valueInput); const validateResult = validator(valueInput);
if (validateResult !== null) { if (validateResult !== null) {
@ -66,14 +62,14 @@ export default function EditBox<T extends CanBeConvertedToString>({
step="0.01" step="0.01"
value={valueInput} value={valueInput}
onBlur={finalize} onBlur={finalize}
onInput={(e) => setValueInput(e.target.value)} onInput={(e) => setValueInput(e.currentTarget.value)}
/> />
</form> </form>
); );
} else { } else {
return ( return (
<ClickableContainer onClick={startEditing}> <ClickableContainer onClick={startEditing}>
{formatter ? formatter(value) : value.toString()} {formatter ? formatter(value) : String(value)}
</ClickableContainer> </ClickableContainer>
); );
} }

View file

@ -1,6 +1,10 @@
import { Container, Navbar } from "react-bootstrap"; import { Container, Navbar } from "react-bootstrap";
export default function Layout({ children }) { export interface Props {
children: JSX.Element;
}
export default function Layout({ children }: Props) {
return ( return (
<> <>
<Navbar bg="dark" variant="dark" expand="lg"> <Navbar bg="dark" variant="dark" expand="lg">
@ -31,6 +35,8 @@ export default function Layout({ children }) {
[license] [license]
</a> </a>
&middot; &middot;
{/* eslint-disable @next/next/no-img-element */}
<a href="https://github.com/iptq/wisesplit/stargazers"> <a href="https://github.com/iptq/wisesplit/stargazers">
<img <img
alt="GitHub stars" alt="GitHub stars"

View file

@ -1,16 +1,16 @@
import { Atom } from "jotai"; import { PrimitiveAtom } from "jotai";
import EditBox from "./EditBox"; import EditBox from "./EditBox";
export interface Props { export interface Props {
valueAtom: Atom<number>; valueAtom: PrimitiveAtom<number>;
formatter?: (arg: number) => string; formatter?: (arg: number) => string;
} }
export default function NumberEditBox({ valueAtom, formatter }: Props) { export default function NumberEditBox({ valueAtom, formatter }: Props) {
const validator = (arg: string) => { const validator = (arg: string): number | null => {
try { try {
const n = parseFloat(arg); const n = parseFloat(arg);
if (isNaN(n) || !isFinite(n)) return; if (isNaN(n) || !isFinite(n)) return null;
return n; return n;
} catch (e) { } catch (e) {
return null; return null;

View file

@ -1,21 +1,21 @@
import { Atom, useAtom, WritableAtom } from "jotai"; import { PrimitiveAtom, useAtom } from "jotai";
import { Badge, ListGroup } from "react-bootstrap"; import { Badge } from "react-bootstrap";
import EditBox from "./EditBox"; import EditBox from "./EditBox";
export interface IPerson { export interface IPerson {
name: Atom<string>; name: PrimitiveAtom<string>;
} }
export interface Props { export interface Props {
personAtom: Atom<IPerson>; personAtom: PrimitiveAtom<IPerson>;
splitBetweenAtom: Atom<Atom<IPerson>[]>; splitBetweenAtom: PrimitiveAtom<PrimitiveAtom<IPerson>[]>;
} }
export default function Person({ personAtom, splitBetweenAtom }: Props) { export default function Person({ personAtom, splitBetweenAtom }: Props) {
const [person] = useAtom(personAtom); const [person] = useAtom(personAtom);
const [splitBetween, setSplitBetween] = useAtom(splitBetweenAtom); const [splitBetween, setSplitBetween] = useAtom(splitBetweenAtom);
const removeSelf = (_) => { const removeSelf = (_: any) => {
setSplitBetween([...splitBetween.filter((x) => x != personAtom)]); setSplitBetween([...splitBetween.filter((x) => x != personAtom)]);
}; };

View file

@ -1,4 +1,4 @@
import { Atom, useAtom } from "jotai"; import { PrimitiveAtom, useAtom } from "jotai";
import { Badge, Card } from "react-bootstrap"; import { Badge, Card } from "react-bootstrap";
import { moneyFormatter } from "../lib/formatter"; import { moneyFormatter } from "../lib/formatter";
import { receiptAtom } from "../lib/state"; import { receiptAtom } from "../lib/state";
@ -7,27 +7,23 @@ import NumberEditBox from "./NumberEditBox";
import { IPerson } from "./Person"; import { IPerson } from "./Person";
import SplitBetween from "./SplitBetween"; import SplitBetween from "./SplitBetween";
export interface IReceiptItem { export type Receipt = PrimitiveAtom<IReceiptItem>[];
name: Atom<string>;
price: Atom<number>;
splitBetween: Atom<Atom<IPerson>[]>;
}
function Price({ priceAtom }) { export interface IReceiptItem {
return ( name: PrimitiveAtom<string>;
<NumberEditBox valueAtom={priceAtom} formatter={moneyFormatter.format} /> price: PrimitiveAtom<number>;
); splitBetween: PrimitiveAtom<PrimitiveAtom<IPerson>[]>;
} }
export interface Props { export interface Props {
itemAtom: Atom<IReceiptItem>; itemAtom: PrimitiveAtom<IReceiptItem>;
} }
export default function ReceiptItem({ itemAtom }: Props) { export default function ReceiptItem({ itemAtom }: Props) {
const [receipt, setReceipt] = useAtom(receiptAtom); const [receipt, setReceipt] = useAtom(receiptAtom);
const [item, _] = useAtom(itemAtom); const [item, _] = useAtom(itemAtom);
const removeSelf = (_) => { const removeSelf = (_: any) => {
setReceipt([...receipt.filter((x) => x != itemAtom)]); setReceipt([...receipt.filter((x) => x != itemAtom)]);
}; };
@ -39,7 +35,10 @@ export default function ReceiptItem({ itemAtom }: Props) {
<EditBox valueAtom={item.name} validator={(s) => s} /> <EditBox valueAtom={item.name} validator={(s) => s} />
</h3> </h3>
<span> <span>
<Price priceAtom={item.price} /> <NumberEditBox
valueAtom={item.price}
formatter={moneyFormatter.format}
/>
<Badge <Badge
bg="danger" bg="danger"
pill pill

View file

@ -1,10 +1,10 @@
import { atom, Atom, useAtom } from "jotai"; import { atom, PrimitiveAtom, useAtom } from "jotai";
import { useState } from "react"; import { SyntheticEvent, useState } from "react";
import { Button, Form, ListGroup } from "react-bootstrap"; import { Button, Form } from "react-bootstrap";
import Person, { IPerson } from "./Person"; import Person, { IPerson } from "./Person";
export interface Props { export interface Props {
splitBetweenAtom: Atom<Atom<IPerson>[]>; splitBetweenAtom: PrimitiveAtom<PrimitiveAtom<IPerson>[]>;
} }
export default function SplitBetween({ splitBetweenAtom }: Props) { export default function SplitBetween({ splitBetweenAtom }: Props) {
@ -12,14 +12,14 @@ export default function SplitBetween({ splitBetweenAtom }: Props) {
const [input, setInput] = useState(""); const [input, setInput] = useState("");
const [editing, setEditing] = useState(false); const [editing, setEditing] = useState(false);
const startEditing = (_) => { const startEditing = (_: any) => {
setInput(""); setInput("");
setEditing(true); setEditing(true);
}; };
const addPerson = (e) => { const addPerson = (e: SyntheticEvent) => {
e.preventDefault(); e.preventDefault();
const person = { name: atom(input) }; const person: IPerson = { name: atom(input) };
setSplitBetween([...splitBetween, atom(person)]); setSplitBetween([...splitBetween, atom(person)]);
setEditing(false); setEditing(false);
}; };
@ -43,7 +43,7 @@ export default function SplitBetween({ splitBetweenAtom }: Props) {
value={input} value={input}
placeholder="Add person to split with..." placeholder="Add person to split with..."
onBlur={(_) => setEditing(false)} onBlur={(_) => setEditing(false)}
onInput={(e) => setInput(e.target.value)} onInput={(e) => setInput(e.currentTarget.value)}
/> />
</Form> </Form>
) : ( ) : (

View file

@ -4,7 +4,11 @@ export interface ParsedInput {
splitBetween: Set<string>; splitBetween: Set<string>;
} }
export function ParsedInputDisplay({ input }) { export interface Props {
input: string;
}
export function ParsedInputDisplay({ input }: Props) {
const parsed = parseInput(input); const parsed = parseInput(input);
const formatter = new Intl.NumberFormat("en-US", { const formatter = new Intl.NumberFormat("en-US", {

View file

@ -1,5 +1,7 @@
import { atom, PrimitiveAtom } from "jotai"; import { atom, PrimitiveAtom } from "jotai";
import { IReceiptItem } from "../components/ReceiptItem"; import { SetAtom } from "jotai/core/atom";
import { IPerson } from "../components/Person";
import { IReceiptItem, Receipt } from "../components/ReceiptItem";
import parseInput from "./parseInput"; import parseInput from "./parseInput";
export const totalAtom = atom(0); export const totalAtom = atom(0);
@ -39,16 +41,23 @@ export const receiptTotalAtom = atom((get) => {
return { subtotal: subtotalSum, totalMap: newTotals }; return { subtotal: subtotalSum, totalMap: newTotals };
}); });
export function addLine(line: string, setReceipt) { export function addLine(
line: string,
receipt: Receipt,
setReceipt: SetAtom<Receipt, void>
) {
let parsed = parseInput(line); let parsed = parseInput(line);
console.log(parsed);
const name = atom(parsed.itemName); const name: PrimitiveAtom<string> = atom(parsed.itemName);
const price = atom(parsed.price || 0); const price: PrimitiveAtom<number> = atom(parsed.price || 0);
const splitBetween = atom( const splitBetween: PrimitiveAtom<PrimitiveAtom<IPerson>[]> = atom<
[...parsed.splitBetween].map((a) => atom({ name: a })) PrimitiveAtom<IPerson>[]
); >([...parsed.splitBetween].map((a) => atom<IPerson>({ name: atom(a) })));
setReceipt((prev) => [
...prev, const newReceiptItem = atom({
atom<IReceiptItem>({ name, price, splitBetween }), name,
]); price,
splitBetween,
});
setReceipt([...receipt, newReceiptItem]);
} }

View file

@ -7,10 +7,7 @@ const nextConfig = {
styledComponents: true, styledComponents: true,
}, },
typescript: { typescript: {},
// TODO: Move fast and break things lmao
ignoreBuildErrors: true,
},
}; };
module.exports = nextConfig; module.exports = nextConfig;

View file

@ -1,6 +1,6 @@
import { useAtom } from "jotai"; import { useAtom } from "jotai";
import type { NextPage } from "next"; import type { NextPage } from "next";
import { useState } from "react"; import { SyntheticEvent, useState } from "react";
import { Form } from "react-bootstrap"; import { Form } from "react-bootstrap";
import NumberEditBox from "../components/NumberEditBox"; import NumberEditBox from "../components/NumberEditBox";
import ReceiptItem from "../components/ReceiptItem"; import ReceiptItem from "../components/ReceiptItem";
@ -24,9 +24,9 @@ const Home: NextPage = () => {
currency: "USD", currency: "USD",
}); });
const add = (e) => { const add = (e: SyntheticEvent) => {
e.preventDefault(); e.preventDefault();
addLine(input, setReceipt); addLine(input, receipt, setReceipt);
setInput(""); setInput("");
return false; return false;
}; };
@ -42,7 +42,7 @@ const Home: NextPage = () => {
autoFocus={true} autoFocus={true}
type="text" type="text"
placeholder="Add item..." placeholder="Add item..."
onInput={(e) => setInput(e.target.value)} onInput={(e) => setInput(e.currentTarget.value)}
value={input} value={input}
style={{ padding: "8px 16px", fontSize: "1.5em" }} style={{ padding: "8px 16px", fontSize: "1.5em" }}
/> />

View file

@ -1,6 +0,0 @@
import solid from "solid-start/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [solid()],
});