LightningMessageboard.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 LightningMessageboard() {
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/@getalby/lightning-messageboard@latest"></script>
32 <lightning-messageboard nwc-url="${nwcUri}"></lightning-messageboard>`);
33 }
34 }, [nwcUri]);
35
36 const appStoreApp = appStoreApps.find(
37 (app) => app.id === "lightning-messageboard"
38 );
39 if (!appStoreApp) {
40 return null;
41 }
42
43 const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
44 event.preventDefault();
45 setLoading(true);
46 (async () => {
47 try {
48 const createAppResponse = await createApp({
49 name,
50 scopes: ["lookup_invoice", "make_invoice", "list_transactions"],
51 isolated: true,
52 metadata: {
53 app_store_app_id: "lightning-messageboard",
54 },
55 });
56
57 setNwcUri(createAppResponse.pairingUri);
58
59 toast("Lightning Messageboard connection created");
60 } catch (error) {
61 handleRequestError("Failed to create connection", error);
62 }
63 setLoading(false);
64 })();
65 };
66
67 return (
68 <div className="grid gap-5">
69 <AppStoreDetailHeader appStoreApp={appStoreApp} contentRight={null} />
70 {nwcUri && (
71 <Card>
72 <CardHeader>
73 <CardTitle>How to Add Widget</CardTitle>
74 </CardHeader>
75 <CardContent className="flex flex-col">
76 <p className="text-foreground">
77 Paste the following code into an HTML block on your website.
78 </p>
79 <div className="flex gap-2 mt-4">
80 <Textarea
81 className="h-36 font-mono"
82 value={scriptContent}
83 onChange={(e) => setScriptContent(e.target.value)}
84 />
85 <Button
86 onClick={() => copyToClipboard(scriptContent)}
87 variant="outline"
88 >
89 <CopyIcon />
90 Copy
91 </Button>
92 </div>
93 </CardContent>
94 </Card>
95 )}
96 {!nwcUri && (
97 <>
98 <div className="max-w-lg flex flex-col gap-5">
99 <p className="text-muted-foreground">
100 Lightning Messageboard is a simple messageboard widget for your
101 website. Add the widget to your website and allow your visitors to
102 pay to send messages.{" "}
103 <ExternalLink
104 to="https://getalby.github.io/lightning-messageboard/demo.html"
105 className="underline"
106 >
107 See Demo
108 </ExternalLink>
109 </p>
110 <ul className="text-muted-foreground">
111 <li>⚡ Lightning fast transactions directly to your Alby Hub</li>
112 <li>
113 🎮 Visitors can pay more to ensure their comment shows at the
114 top of the message board
115 </li>
116 <li>
117 🔒 No lightning address required, secure read-only connection
118 </li>
119 <li>🤙 Can be paid from any lightning wallet</li>
120 </ul>
121 <form
122 onSubmit={handleSubmit}
123 className="flex flex-col items-start gap-5 max-w-lg"
124 >
125 <div className="w-full grid gap-1.5">
126 <Label htmlFor="name">Website name</Label>
127 <Input
128 autoFocus
129 type="text"
130 name="name"
131 value={name}
132 id="name"
133 onChange={(e) => setName(e.target.value)}
134 required
135 autoComplete="off"
136 />
137 </div>
138 <LoadingButton loading={isLoading} type="submit">
139 Next
140 </LoadingButton>
141 </form>
142 </div>
143 <AppDetailConnectedApps appStoreApp={appStoreApp} showTitle />
144 </>
145 )}
146 </div>
147 );
148 }
149