add Sonner (and have some fun)
This commit is contained in:
parent
f985906395
commit
545bdf7bae
|
|
@ -13,6 +13,7 @@
|
|||
"@tanstack/react-router": "^1.28.7",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"sonner": "^1.4.41",
|
||||
"web3": "^4.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ dependencies:
|
|||
react-dom:
|
||||
specifier: ^18.2.0
|
||||
version: 18.2.0(react@18.2.0)
|
||||
sonner:
|
||||
specifier: ^1.4.41
|
||||
version: 1.4.41(react-dom@18.2.0)(react@18.2.0)
|
||||
web3:
|
||||
specifier: ^4.7.0
|
||||
version: 4.7.0(typescript@5.4.5)
|
||||
|
|
@ -2614,6 +2617,16 @@ packages:
|
|||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
/sonner@1.4.41(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-uG511ggnnsw6gcn/X+YKkWPo5ep9il9wYi3QJxHsYe7yTZ4+cOd1wuodOUmOpFuXL+/RE3R04LczdNCDygTDgQ==}
|
||||
peerDependencies:
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/source-map-js@1.2.0:
|
||||
resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
|
|
|||
|
|
@ -16,11 +16,17 @@ import { Route as rootRoute } from './routes/__root'
|
|||
|
||||
// Create Virtual Routes
|
||||
|
||||
const MessageBoxLazyImport = createFileRoute('/message-box')()
|
||||
const AboutLazyImport = createFileRoute('/about')()
|
||||
const IndexLazyImport = createFileRoute('/')()
|
||||
|
||||
// Create/Update Routes
|
||||
|
||||
const MessageBoxLazyRoute = MessageBoxLazyImport.update({
|
||||
path: '/message-box',
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any).lazy(() => import('./routes/message-box.lazy').then((d) => d.Route))
|
||||
|
||||
const AboutLazyRoute = AboutLazyImport.update({
|
||||
path: '/about',
|
||||
getParentRoute: () => rootRoute,
|
||||
|
|
@ -43,11 +49,19 @@ declare module '@tanstack/react-router' {
|
|||
preLoaderRoute: typeof AboutLazyImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/message-box': {
|
||||
preLoaderRoute: typeof MessageBoxLazyImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create and export the route tree
|
||||
|
||||
export const routeTree = rootRoute.addChildren([IndexLazyRoute, AboutLazyRoute])
|
||||
export const routeTree = rootRoute.addChildren([
|
||||
IndexLazyRoute,
|
||||
AboutLazyRoute,
|
||||
MessageBoxLazyRoute,
|
||||
])
|
||||
|
||||
/* prettier-ignore-end */
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { createRootRoute, Link, Outlet } from "@tanstack/react-router";
|
||||
import { Toaster } from "sonner";
|
||||
|
||||
export const Route = createRootRoute({
|
||||
component: RootLayout,
|
||||
|
|
@ -17,10 +18,14 @@ function RootLayout() {
|
|||
<Link to="/about" className="[&.active]:font-bold">
|
||||
About
|
||||
</Link>
|
||||
<Link to="/message-box" className="[&.active]:font-bold">
|
||||
Message Box
|
||||
</Link>
|
||||
</div>
|
||||
</header>
|
||||
<main>
|
||||
<Outlet />
|
||||
<Toaster />
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createLazyFileRoute("/about")({
|
||||
component: About,
|
||||
component: AboutPage,
|
||||
});
|
||||
|
||||
function About() {
|
||||
function AboutPage() {
|
||||
return (
|
||||
<div className="p-4">
|
||||
<h1 className="text-3xl font-bold">About</h1>
|
||||
<div className="container mx-auto p-4">
|
||||
<h1 className="text-3xl font-bold text-center">About</h1>
|
||||
<p>
|
||||
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Nemo nulla
|
||||
neque quo officiis eum quia voluptates ratione, tenetur assumenda ad
|
||||
|
|
|
|||
|
|
@ -1,48 +1,25 @@
|
|||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import { useState } from "react";
|
||||
import { messageBox, web3 } from "../web3";
|
||||
|
||||
export const Route = createLazyFileRoute("/")({
|
||||
component: Index,
|
||||
component: IndexPage,
|
||||
});
|
||||
|
||||
function Index() {
|
||||
const [connectedAccount, setConnectedAccount] = useState("(nothingness)");
|
||||
const [message, setMessage] = useState("(nothingness)");
|
||||
|
||||
// https://docs.web3js.org/guides/getting_started/metamask/#react-app
|
||||
async function connectMetamask() {
|
||||
// Request user to connect accounts (MetaMask will prompt)
|
||||
await window.ethereum.request({ method: "eth_requestAccounts" });
|
||||
|
||||
// Get the connected accounts
|
||||
const accounts = await web3.eth.getAccounts();
|
||||
|
||||
// Show the first connected account in the page
|
||||
setConnectedAccount(accounts[0]);
|
||||
|
||||
const _message: string = await messageBox.methods.getMessage().call();
|
||||
setMessage(_message);
|
||||
}
|
||||
|
||||
function IndexPage() {
|
||||
return (
|
||||
<div className="p-4">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary"
|
||||
onClick={() => connectMetamask()}
|
||||
>
|
||||
Connect to MetaMask
|
||||
</button>
|
||||
|
||||
<div>
|
||||
<span className="font-bold">Connected account address:</span>{" "}
|
||||
{connectedAccount}
|
||||
<div className="container mx-auto p-4 text-center">
|
||||
<div className="my-6">
|
||||
<h1 className="text-7xl font-bold italic">This is a launchpad.</h1>
|
||||
<h2 className="text-3xl font-bold italic">
|
||||
(Don't you dare thinking otherwise.)
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<span className="font-bold">Message:</span> {message}
|
||||
</div>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci
|
||||
nesciunt ipsa possimus sed? Maxime eos iusto facere natus commodi
|
||||
consectetur ad pariatur minima quisquam. Soluta esse minus porro nemo
|
||||
at.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import { useState } from "react";
|
||||
import { tryWithToast } from "../utils";
|
||||
import { messageBox, web3 } from "../web3";
|
||||
|
||||
export const Route = createLazyFileRoute("/message-box")({
|
||||
component: MessageBoxPage,
|
||||
});
|
||||
|
||||
function MessageBoxPage() {
|
||||
const [connectedAccount, setConnectedAccount] = useState("(nothingness)");
|
||||
const [message, setMessage] = useState("(nothingness)");
|
||||
const [newMessage, setNewMessage] = useState("");
|
||||
|
||||
// https://docs.web3js.org/guides/getting_started/metamask/#react-app
|
||||
async function connectMetamask() {
|
||||
await tryWithToast("Connect MetaMask", async () => {
|
||||
// Request user to connect accounts (MetaMask will prompt)
|
||||
await window.ethereum.request({ method: "eth_requestAccounts" });
|
||||
|
||||
// Get the connected accounts
|
||||
const accounts = await web3.eth.getAccounts();
|
||||
|
||||
// Show the first connected account in the page
|
||||
setConnectedAccount(accounts[0]);
|
||||
});
|
||||
}
|
||||
|
||||
async function getMessage() {
|
||||
await tryWithToast("Get Message", async () => {
|
||||
const _message: string = await messageBox.methods.getMessage().call();
|
||||
setMessage(_message);
|
||||
});
|
||||
}
|
||||
|
||||
async function _setMessage() {
|
||||
await tryWithToast("Set Message", async () => {
|
||||
await messageBox.methods
|
||||
.setMessage(newMessage)
|
||||
.send({ from: connectedAccount });
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container mx-auto p-4 grid md:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||
<div className="card bg-base-200">
|
||||
<div className="card-body items-start">
|
||||
<h2 className="text-2xl font-bold">✨Essentials✨</h2>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary"
|
||||
onClick={() => connectMetamask()}
|
||||
>
|
||||
Connect to MetaMask
|
||||
</button>
|
||||
|
||||
<div>
|
||||
<span className="font-bold">Connected account address:</span>{" "}
|
||||
{connectedAccount}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="card bg-base-200">
|
||||
<div className="card-body items-start">
|
||||
<h2 className="text-2xl font-bold">Get Message</h2>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary"
|
||||
onClick={() => getMessage()}
|
||||
>
|
||||
Get
|
||||
</button>
|
||||
<div>
|
||||
<span className="font-bold">Message:</span> {message}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="card bg-base-200">
|
||||
<div className="card-body items-start">
|
||||
<h2 className="text-2xl font-bold">Set Message</h2>
|
||||
<input
|
||||
type="text"
|
||||
className="input"
|
||||
placeholder="New message"
|
||||
value={newMessage}
|
||||
onChange={(event) => setNewMessage(event.target.value)}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary"
|
||||
onClick={() => _setMessage()}
|
||||
>
|
||||
Set
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { toast } from "sonner";
|
||||
|
||||
export async function tryWithToast(
|
||||
taskName: string,
|
||||
taskFn: () => Promise<void>
|
||||
) {
|
||||
try {
|
||||
await taskFn();
|
||||
toast.success(`${taskName}: Success`, {
|
||||
className: "border-none bg-green-100",
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error(error);
|
||||
toast.error(`${taskName}: Error`, {
|
||||
description:
|
||||
error.message ||
|
||||
"No error message. Check the DevTools console for details.",
|
||||
className: "border-none bg-red-100",
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue