From 8686078ae801fdc15df5a40ee158a43373d37c1c Mon Sep 17 00:00:00 2001 From: bndw Date: Wed, 26 Apr 2023 17:49:25 -0700 Subject: Initial commit --- app/api/hello/route.ts | 3 + app/components/bitcoin-price.module.css | 2 + app/components/bitcoin-price.tsx | 26 ++++++++ app/components/calculator.module.css | 15 +++++ app/components/calculator.tsx | 113 ++++++++++++++++++++++++++++++++ app/favicon.ico | Bin 0 -> 25931 bytes app/globals.css | 3 + app/layout.tsx | 21 ++++++ app/page.tsx | 15 +++++ app/utils/bitcoin-price.tsx | 16 +++++ 10 files changed, 214 insertions(+) create mode 100644 app/api/hello/route.ts create mode 100644 app/components/bitcoin-price.module.css create mode 100644 app/components/bitcoin-price.tsx create mode 100644 app/components/calculator.module.css create mode 100644 app/components/calculator.tsx create mode 100644 app/favicon.ico create mode 100644 app/globals.css create mode 100644 app/layout.tsx create mode 100644 app/page.tsx create mode 100644 app/utils/bitcoin-price.tsx (limited to 'app') diff --git a/app/api/hello/route.ts b/app/api/hello/route.ts new file mode 100644 index 0000000..d1cc6ee --- /dev/null +++ b/app/api/hello/route.ts @@ -0,0 +1,3 @@ +export async function GET(request: Request) { + return new Response('Hello, Next.js!') +} diff --git a/app/components/bitcoin-price.module.css b/app/components/bitcoin-price.module.css new file mode 100644 index 0000000..fd52c7e --- /dev/null +++ b/app/components/bitcoin-price.module.css @@ -0,0 +1,2 @@ +.price { +} diff --git a/app/components/bitcoin-price.tsx b/app/components/bitcoin-price.tsx new file mode 100644 index 0000000..af837d9 --- /dev/null +++ b/app/components/bitcoin-price.tsx @@ -0,0 +1,26 @@ +"use client"; + +import { useEffect, useState } from "react"; +import { BitcoinPrice as btcPrice } from "../utils/bitcoin-price"; + +export const BitcoinPrice = () => { + const [isLoading, setLoading] = useState(false); + const bitcoinPrice = btcPrice(); + + const formatCurrency = (val: string) => { + const n = parseFloat(val); + const formatter = new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + maximumFractionDigits: 0, + }); + + return formatter.format(n); + }; + + useEffect(() => setLoading(!bitcoinPrice), [bitcoinPrice]); + + if (isLoading || !bitcoinPrice) return

Loading...

; + + return
Bitcoin price: {formatCurrency(bitcoinPrice)}
; +}; diff --git a/app/components/calculator.module.css b/app/components/calculator.module.css new file mode 100644 index 0000000..265760d --- /dev/null +++ b/app/components/calculator.module.css @@ -0,0 +1,15 @@ +.form { +} + +.input { + border-bottom: solid 1px #eee; + box-sizing: border-box; + font-size: 3em; + margin: 8px 0; + padding: 12px 20px; + width: 100%; +} + +.input:focus { + outline: none; +} diff --git a/app/components/calculator.tsx b/app/components/calculator.tsx new file mode 100644 index 0000000..006a755 --- /dev/null +++ b/app/components/calculator.tsx @@ -0,0 +1,113 @@ +"use client"; + +import { useEffect, useState } from "react"; +import styles from "./calculator.module.css"; +import { BitcoinPrice } from "../utils/bitcoin-price"; + +export const Calculator = () => { + const [sats, setSats] = useState(""); + const [btc, setBtc] = useState(""); + const [usd, setUsd] = useState(""); + + const formatCurrency = (val: string) => { + const formatter = new Intl.NumberFormat("en-US", { + style: "currency", + currency: "USD", + maximumFractionDigits: 2, + }); + return formatter.format(parseNumber(val)); + }; + + const formatDecimal = (val: any) => { + return val.toLocaleString("fullwide", { + useGrouping: true, + maximumSignificantDigits: 6, + }); + }; + + const parseNumber = (val: string) => { + return parseFloat(val.replace(/[^0-9|.]/g, "")); + }; + + const btcPrice = parseNumber(BitcoinPrice()); + + const handleUpdate = (type: string, v: string) => { + const val = parseNumber(v); + + let newbtc: number; + switch (type) { + case "sats": + setSats(v); + + if (isNaN(val) || v.endsWith(".")) { + return; + } + setSats(formatDecimal(val)); + + newbtc = val / 100000000; + setBtc(formatDecimal(newbtc)); + setUsd(formatCurrency(formatDecimal(newbtc * btcPrice))); + break; + case "btc": + setBtc(v); + + if (isNaN(val) || v.endsWith(".")) { + return; + } + setBtc(formatDecimal(val)); + + setSats(formatDecimal(val * 100000000)); + setUsd(formatCurrency(formatDecimal(val * btcPrice))); + break; + case "usd": + setUsd(formatCurrency(v)); + if (isNaN(val)) { + return; + } + + newbtc = val / btcPrice; + setBtc(formatDecimal(newbtc)); + setSats(formatDecimal(newbtc * 100000000)); + break; + } + }; + + useEffect(() => { + // Initialize the calculator with some numbers + handleUpdate("sats", "1000"); + }, [btcPrice]); + + return ( +
+ + handleUpdate("sats", e.target.value)} + value={sats} + type="text" + id="sats" + name="sats" + /> + + + handleUpdate("btc", e.target.value)} + value={btc} + type="text" + id="btc" + name="btc" + /> + + + handleUpdate("usd", e.target.value)} + value={usd} + type="text" + id="usd" + name="usd" + /> +
+ ); +}; diff --git a/app/favicon.ico b/app/favicon.ico new file mode 100644 index 0000000..718d6fe Binary files /dev/null and b/app/favicon.ico differ diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..b5c61c9 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..821a80a --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,21 @@ +import "./globals.css"; +import { Inter } from "next/font/google"; + +const inter = Inter({ subsets: ["latin"] }); + +export const metadata = { + title: "Sats calculator", + description: "Satoshi calculator", +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..d0ac564 --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,15 @@ +import { BitcoinPrice } from "./components/bitcoin-price"; +import { Calculator } from "./components/calculator"; + +export default function Home() { + return ( +
+
+ +
+
+ +
+
+ ); +} diff --git a/app/utils/bitcoin-price.tsx b/app/utils/bitcoin-price.tsx new file mode 100644 index 0000000..06d8fce --- /dev/null +++ b/app/utils/bitcoin-price.tsx @@ -0,0 +1,16 @@ +import { useEffect, useState } from "react"; + +export const BitcoinPrice = () => { + const [bitcoinPrice, setBitcoinPrice] = useState(""); + + useEffect(() => { + fetch("https://api.kraken.com/0/public/Ticker?pair=xbtusd") + .then((res) => res.json()) + .then((data) => { + const rawPrice = data.result.XXBTZUSD.c[0]; + setBitcoinPrice(rawPrice); + }); + }, []); + + return bitcoinPrice; +}; -- cgit v1.2.3