SimpleBoost.tsx raw
1 import { CopyIcon } from "lucide-react";
2 import React from "react";
3 import { toast } from "sonner";
4 import { AppDetailConnectedApps } from "src/components/connections/AppDetailConnectedApps";
5 import { AppStoreDetailHeader } from "src/components/connections/AppStoreDetailHeader";
6 import { appStoreApps } from "src/components/connections/SuggestedAppData";
7 import ExternalLink from "src/components/ExternalLink";
8 import { Button } from "src/components/ui/button";
9 import {
10 Card,
11 CardContent,
12 CardHeader,
13 CardTitle,
14 } from "src/components/ui/card";
15 import { LoadingButton } from "src/components/ui/custom/loading-button";
16 import { Input } from "src/components/ui/input";
17 import { Label } from "src/components/ui/label";
18 import { Textarea } from "src/components/ui/textarea";
19 import { copyToClipboard } from "src/lib/clipboard";
20 import { createApp } from "src/requests/createApp";
21 import { handleRequestError } from "src/utils/handleRequestError";
22
23 export function SimpleBoost() {
24 const [name, setName] = React.useState("");
25 const [isLoading, setLoading] = React.useState(false);
26 const [nwcUri, setNwcUri] = React.useState("");
27 const [scriptContent, setScriptContent] = React.useState("");
28
29 React.useEffect(() => {
30 if (nwcUri) {
31 setScriptContent(`<script type="module" src="https://esm.sh/simple-boost@latest"></script>
32 <simple-boost currency="usd" amount="1.0" nwc="${nwcUri}">Boost $1.00</simple-boost>`);
33 }
34 }, [nwcUri]);
35
36 const appStoreApp = appStoreApps.find((app) => app.id === "simpleboost");
37 if (!appStoreApp) {
38 return null;
39 }
40
41 const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
42 event.preventDefault();
43 setLoading(true);
44 (async () => {
45 try {
46 const createAppResponse = await createApp({
47 name,
48 scopes: ["lookup_invoice", "make_invoice"],
49 isolated: true,
50 metadata: {
51 app_store_app_id: "simpleboost",
52 },
53 });
54
55 setNwcUri(createAppResponse.pairingUri);
56
57 toast("Simple Boost connection created");
58 } catch (error) {
59 handleRequestError("Failed to create connection", error);
60 }
61 setLoading(false);
62 })();
63 };
64
65 return (
66 <div className="grid gap-5">
67 <AppStoreDetailHeader appStoreApp={appStoreApp} contentRight={null} />
68 {nwcUri && (
69 <Card>
70 <CardHeader>
71 <CardTitle>How to Add Widget</CardTitle>
72 </CardHeader>
73 <CardContent className="flex flex-col">
74 <p className="text-foreground">
75 Paste the following code into an HTML block on your website.
76 </p>
77 <div className="flex gap-2 mt-4">
78 <Textarea
79 className="h-36 font-mono"
80 value={scriptContent}
81 onChange={(e) => setScriptContent(e.target.value)}
82 />
83 <Button
84 onClick={() => copyToClipboard(scriptContent)}
85 variant="outline"
86 >
87 <CopyIcon />
88 Copy
89 </Button>
90 </div>
91 <p className="text-sm text-muted-foreground mt-3">
92 By default the SimpleBoost widget is loaded from a CDN. See other
93 options{" "}
94 <ExternalLink
95 to="https://getalby.github.io/simple-boost/install/"
96 className="font-medium text-foreground underline"
97 >
98 here
99 </ExternalLink>
100 </p>
101 </CardContent>
102 </Card>
103 )}
104 {!nwcUri && (
105 <>
106 <div className="max-w-lg flex flex-col gap-5">
107 <p className="text-muted-foreground">
108 SimpleBoost is a donation button for your website. Add the widget
109 to your website and allow your visitors to send sats with the
110 click of a button.
111 </p>
112 <ul className="text-muted-foreground">
113 <li>⚡ Lightning fast transactions directly to your Alby Hub</li>
114 <li>🔗 Set amounts in Bitcoin or any other currency</li>
115 <li>
116 🔒 No lightning address required, secure read-only connection
117 </li>
118 <li>🤙 Can be paid from any lightning wallet</li>
119 </ul>
120 <form
121 onSubmit={handleSubmit}
122 className="flex flex-col items-start gap-5 max-w-lg"
123 >
124 <div className="w-full grid gap-1.5">
125 <Label htmlFor="name">Website name</Label>
126 <Input
127 autoFocus
128 type="text"
129 name="name"
130 value={name}
131 id="name"
132 onChange={(e) => setName(e.target.value)}
133 required
134 autoComplete="off"
135 />
136 </div>
137 <LoadingButton loading={isLoading} type="submit">
138 Next
139 </LoadingButton>
140 </form>
141 </div>
142 <AppDetailConnectedApps appStoreApp={appStoreApp} showTitle />
143 </>
144 )}
145 </div>
146 );
147 }
148