add Sonner (and have some fun)

This commit is contained in:
osmannyildiz 2024-04-20 19:51:19 +03:00
parent f985906395
commit 545bdf7bae
8 changed files with 174 additions and 42 deletions

View File

@ -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": {

View File

@ -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'}

View File

@ -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 */

View File

@ -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>
</>
);

View File

@ -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

View File

@ -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>
);
}

View File

@ -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>
);
}

21
frontend/src/utils.ts Normal file
View File

@ -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",
});
}
}