1- import Copy from "lucide-react/icons/copy" ;
21import ExternalLink from "lucide-react/icons/external-link" ;
32import { useState } from "react" ;
4- import { toast } from "sonner" ;
53
64import { useAuth } from "@/components/auth-context" ;
75import { Button } from "@/components/ui/button" ;
@@ -17,18 +15,23 @@ import { Spinner } from "@/components/ui/spinner";
1715import { getApiBaseUrl } from "@/config/api" ;
1816import { createSlackBot } from "@/services/bot-service" ;
1917
20- type Step = "credentials" | "setup" ;
18+ import { CopyableValue } from "./copyable-value" ;
19+
20+ type Step = "credentials" | "webhook" | "setup" ;
2121
2222const STEP_TITLES : Record < Step , string > = {
2323 credentials : "Create a Slack Bot" ,
24- setup : "Bot Created" ,
24+ webhook : "Event Subscriptions" ,
25+ setup : "Invite Bot" ,
2526} ;
2627
2728const STEP_DESCRIPTIONS : Record < Step , string > = {
2829 credentials :
2930 "Create a Slack app at api.slack.com/apps, then copy the Bot User OAuth Token and Signing Secret." ,
31+ webhook :
32+ "Copy the webhook URL below and paste it as the Request URL in the Event Subscriptions page of your Slack app." ,
3033 setup :
31- "Your bot is ready. Configure the Event Subscriptions URL in your Slack app settings ." ,
34+ "Verify permissions, invite the bot to a channel, and create a workflow ." ,
3235} ;
3336
3437interface SlackBotCreateDialogProps {
@@ -83,7 +86,7 @@ export function SlackBotCreateDialog({
8386 ( response . metadata as Record < string , string | undefined > | null )
8487 ?. teamName ?? ""
8588 ) ;
86- setStep ( "setup " ) ;
89+ setStep ( "webhook " ) ;
8790 onCreated ( response . id ) ;
8891 } catch ( err ) {
8992 setError ( err instanceof Error ? err . message : "Failed to create bot" ) ;
@@ -93,7 +96,7 @@ export function SlackBotCreateDialog({
9396 } ;
9497
9598 const webhookUrl = createdBotId
96- ? `${ getApiBaseUrl ( ) } /slack/webhook/${ createdBotId } `
99+ ? `${ getApiBaseUrl ( ) . replace ( / \/ $ / , "" ) } /slack/webhook/${ createdBotId } `
97100 : "" ;
98101
99102 return (
@@ -206,7 +209,7 @@ export function SlackBotCreateDialog({
206209 </ div >
207210 ) }
208211
209- { step === "setup " && (
212+ { step === "webhook " && (
210213 < div className = "space-y-4" >
211214 < div className = "flex items-center gap-2 text-sm" >
212215 < span className = "text-xs px-2 py-0.5 bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400 rounded-md font-medium" >
@@ -223,29 +226,12 @@ export function SlackBotCreateDialog({
223226 </ span >
224227 </ div >
225228
226- < div className = "space-y-2" >
227- < Label > Webhook URL</ Label >
228- < div className = "flex items-center gap-2" >
229- < Input
230- value = { webhookUrl }
231- readOnly
232- className = "font-mono text-xs"
233- />
234- < Button
235- variant = "outline"
236- size = "icon"
237- className = "shrink-0"
238- onClick = { ( ) => {
239- navigator . clipboard . writeText ( webhookUrl ) ;
240- toast . success ( "Webhook URL copied" ) ;
241- } }
242- >
243- < Copy className = "h-4 w-4" />
244- </ Button >
245- </ div >
246- < ol className = "text-xs text-muted-foreground list-decimal list-inside space-y-1.5 mt-2" >
247- < li >
248- Go to{ " " }
229+ < div className = "space-y-2 text-sm" >
230+ < div className = "space-y-1" >
231+ < p className = "font-medium text-foreground" > Request URL</ p >
232+ < CopyableValue value = { webhookUrl } />
233+ < p className = "text-muted-foreground text-xs" >
234+ Paste this as the Request URL in the{ " " }
249235 < a
250236 href = "https://api.slack.com/apps"
251237 target = "_blank"
@@ -255,18 +241,24 @@ export function SlackBotCreateDialog({
255241 Event Subscriptions
256242 < ExternalLink className = "w-2.5 h-2.5" />
257243 </ a > { " " }
258- in your Slack app and toggle{ " " }
244+ page of your Slack app. Slack will verify it automatically.
245+ </ p >
246+ </ div >
247+
248+ < ol className = "text-xs text-muted-foreground list-decimal list-inside space-y-1.5 mt-3" >
249+ < li >
250+ Go to{ " " }
251+ < span className = "font-medium text-foreground" >
252+ Event Subscriptions
253+ </ span > { " " }
254+ and toggle{ " " }
259255 < span className = "font-medium text-foreground" >
260256 Enable Events
261257 </ span > { " " }
262258 to On.
263259 </ li >
264260 < li >
265- Paste the Webhook URL above as the{ " " }
266- < span className = "font-medium text-foreground" >
267- Request URL
268- </ span >
269- . Slack will verify it automatically.
261+ Paste the Request URL above and wait for Slack to verify it.
270262 </ li >
271263 < li >
272264 Under{ " " }
@@ -276,17 +268,55 @@ export function SlackBotCreateDialog({
276268 , add < span className = "font-mono" > message.channels</ span > and{ " " }
277269 < span className = "font-mono" > message.groups</ span > , then save.
278270 </ li >
279- < li >
280- Invite the bot to a channel and create a workflow with a{ " " }
281- < span className = "font-medium text-foreground" >
282- Receive Slack Message
283- </ span > { " " }
284- trigger.
285- </ li >
286271 </ ol >
287272 </ div >
288273
289274 < div className = "flex justify-end" >
275+ < Button onClick = { ( ) => setStep ( "setup" ) } > Next</ Button >
276+ </ div >
277+ </ div >
278+ ) }
279+
280+ { step === "setup" && (
281+ < div className = "space-y-4" >
282+ < ol className = "text-xs text-muted-foreground list-decimal list-inside space-y-1.5" >
283+ < li >
284+ Under{ " " }
285+ < a
286+ href = "https://api.slack.com/apps"
287+ target = "_blank"
288+ rel = "noopener noreferrer"
289+ className = "text-primary hover:underline inline-flex items-center gap-0.5"
290+ >
291+ OAuth & Permissions
292+ < ExternalLink className = "w-2.5 h-2.5" />
293+ </ a >
294+ , verify the bot has{ " " }
295+ < span className = "font-mono" > channels:history</ span > ,{ " " }
296+ < span className = "font-mono" > groups:history</ span > , and{ " " }
297+ < span className = "font-mono" > chat:write</ span > scopes.
298+ </ li >
299+ < li >
300+ Invite the bot to a channel with{ " " }
301+ < span className = "font-mono" > /invite @{ name || "botname" } </ span > .
302+ </ li >
303+ < li >
304+ Create a workflow with a{ " " }
305+ < span className = "font-medium text-foreground" >
306+ Receive Slack Message
307+ </ span > { " " }
308+ trigger.
309+ </ li >
310+ </ ol >
311+
312+ < div className = "flex justify-end gap-2 pt-1" >
313+ < Button
314+ type = "button"
315+ variant = "outline"
316+ onClick = { ( ) => setStep ( "webhook" ) }
317+ >
318+ Back
319+ </ Button >
290320 < Button onClick = { handleClose } > Done</ Button >
291321 </ div >
292322 </ div >
0 commit comments