1
1
import { ChatBubbleLeftRightIcon } from "@heroicons/react/20/solid" ;
2
- import { Link , useSearchParams } from "@remix-run/react" ;
2
+ import { Link , useRevalidator } from "@remix-run/react" ;
3
+ import { useEffect , useState } from "react" ;
4
+ import { useEventSource } from "remix-utils" ;
3
5
import invariant from "tiny-invariant" ;
6
+ import gradientBackground from "~/assets/images/gradient-background.png" ;
4
7
import { Paragraph } from "~/components/primitives/Paragraph" ;
5
8
import { StepNumber } from "~/components/primitives/StepNumber" ;
6
9
import { useAppOrigin } from "~/hooks/useAppOrigin" ;
@@ -9,7 +12,7 @@ import { useJob } from "~/hooks/useJob";
9
12
import { useOrganization } from "~/hooks/useOrganizations" ;
10
13
import { useProject } from "~/hooks/useProject" ;
11
14
import { IntegrationIcon } from "~/routes/_app.orgs.$organizationSlug.projects.$projectParam.integrations/route" ;
12
- import { jobTestPath } from "~/utils/pathBuilder" ;
15
+ import { jobTestPath , projectStreamingPath } from "~/utils/pathBuilder" ;
13
16
import { Feedback } from "../Feedback" ;
14
17
import { CodeBlock } from "../code/CodeBlock" ;
15
18
import { InlineCode } from "../code/InlineCode" ;
@@ -33,20 +36,60 @@ import { TextLink } from "../primitives/TextLink";
33
36
import integrationButton from "./integration-button.png" ;
34
37
import selectEnvironment from "./select-environment.png" ;
35
38
import selectExample from "./select-example.png" ;
36
- import gradientBackground from "~/assets/images/gradient-background.png" ;
37
39
38
- const existingProjectValue = "use-existing-project" ;
39
- const newProjectValue = "create-new-next-app" ;
40
+ type SelectionChoices = "use-existing-project" | "create-new-next-app" ;
40
41
41
42
export function HowToSetupYourProject ( ) {
43
+ const project = useProject ( ) ;
42
44
const devEnvironment = useDevEnvironment ( ) ;
43
45
const appOrigin = useAppOrigin ( ) ;
44
46
45
- const [ searchQuery , setSearchQuery ] = useSearchParams ( ) ;
46
- const selectedValue = searchQuery . get ( "selectedValue" ) ;
47
+ const [ selectedValue , setSelectedValue ] = useState < SelectionChoices | null > ( null ) ;
47
48
48
49
invariant ( devEnvironment , "devEnvironment is required" ) ;
49
50
51
+ const revalidator = useRevalidator ( ) ;
52
+ const events = useEventSource ( projectStreamingPath ( project . id ) , {
53
+ event : "message" ,
54
+ } ) ;
55
+
56
+ useEffect ( ( ) => {
57
+ if ( events !== null ) {
58
+ // This uses https://www.npmjs.com/package/canvas-confetti
59
+ if ( "confetti" in window && typeof window . confetti !== "undefined" ) {
60
+ var duration = 2.5 * 1000 ;
61
+ var end = Date . now ( ) + duration ;
62
+
63
+ ( function frame ( ) {
64
+ // launch a few confetti from the left edge
65
+ // @ts -ignore
66
+ window . confetti ( {
67
+ particleCount : 7 ,
68
+ angle : 60 ,
69
+ spread : 55 ,
70
+ origin : { x : 0 } ,
71
+ } ) ;
72
+ // and launch a few from the right edge
73
+ // @ts -ignore
74
+ window . confetti ( {
75
+ particleCount : 7 ,
76
+ angle : 120 ,
77
+ spread : 55 ,
78
+ origin : { x : 1 } ,
79
+ } ) ;
80
+
81
+ // keep going until we are out of time
82
+ if ( Date . now ( ) < end ) {
83
+ requestAnimationFrame ( frame ) ;
84
+ }
85
+ } ) ( ) ;
86
+ }
87
+
88
+ revalidator . revalidate ( ) ;
89
+ }
90
+ // WARNING Don't put the revalidator in the useEffect deps array or bad things will happen
91
+ } , [ events ] ) ; // eslint-disable-line react-hooks/exhaustive-deps
92
+
50
93
return (
51
94
< div
52
95
className = "-ml-4 -mt-4 h-full w-[calc(100%+32px)] bg-cover bg-no-repeat pt-20"
@@ -55,7 +98,7 @@ export function HowToSetupYourProject() {
55
98
< div className = "mx-auto max-w-3xl" >
56
99
< div className = "flex items-center justify-between" >
57
100
< Header1 spacing className = "text-bright" >
58
- Get setup in { selectedValue === newProjectValue ? "5" : "2" } minutes
101
+ Get setup in { selectedValue === "create-new-next-app" ? "5" : "2" } minutes
59
102
</ Header1 >
60
103
< Feedback
61
104
button = {
@@ -68,30 +111,30 @@ export function HowToSetupYourProject() {
68
111
</ div >
69
112
< RadioGroup
70
113
className = "mb-4 flex gap-x-2"
71
- onValueChange = { ( value ) => setSearchQuery ( { selectedValue : value } ) }
114
+ onValueChange = { ( value ) => setSelectedValue ( value as SelectionChoices ) }
72
115
>
73
116
< RadioGroupItem
74
117
label = "Use an existing Next.js project"
75
118
description = "Use Trigger.dev in an existing Next.js project in less than 2 mins."
76
- value = { existingProjectValue }
77
- checked = { selectedValue === existingProjectValue }
119
+ value = "use-existing-project"
120
+ checked = { selectedValue === "use-existing-project" }
78
121
variant = "icon"
79
- data-action = { existingProjectValue }
122
+ data-action = "use-existing-project"
80
123
icon = { < NamedIcon className = "h-12 w-12 text-green-600" name = { "tree" } /> }
81
124
/>
82
125
< RadioGroupItem
83
126
label = "Create a new Next.js project"
84
127
description = "This is the quickest way to try out Trigger.dev in a new Next.js project and takes 5 mins."
85
- value = { newProjectValue }
86
- checked = { selectedValue === newProjectValue }
128
+ value = "create-new-next-app"
129
+ checked = { selectedValue === "create-new-next-app" }
87
130
variant = "icon"
88
- data-action = { newProjectValue }
131
+ data-action = "create-new-next-app"
89
132
icon = { < NamedIcon className = "h-8 w-8 text-green-600" name = { "sapling" } /> }
90
133
/>
91
134
</ RadioGroup >
92
135
{ selectedValue && (
93
136
< >
94
- { selectedValue === newProjectValue ? (
137
+ { selectedValue === "create-new-next-app" ? (
95
138
< >
96
139
< StepNumber stepNumber = "1" title = "Create a new Next.js project" />
97
140
< StepContentContainer >
@@ -159,20 +202,9 @@ export function HowToSetupYourProject() {
159
202
< StepContentContainer >
160
203
< TriggerDevStep />
161
204
</ StepContentContainer >
162
- < StepNumber stepNumber = "6" title = "Check for Jobs" />
205
+ < StepNumber stepNumber = "6" title = "Wait for Jobs" displaySpinner />
163
206
< StepContentContainer >
164
- < Paragraph >
165
- Once you've run the CLI command, click Refresh to view your example Job in the
166
- list.
167
- </ Paragraph >
168
- < Button
169
- variant = "primary/medium"
170
- className = "mt-4"
171
- LeadingIcon = "refresh"
172
- onClick = { ( ) => window . location . reload ( ) }
173
- >
174
- Refresh
175
- </ Button >
207
+ < Paragraph > This page will automatically refresh.</ Paragraph >
176
208
</ StepContentContainer >
177
209
</ >
178
210
) : (
@@ -198,20 +230,9 @@ export function HowToSetupYourProject() {
198
230
< StepContentContainer >
199
231
< TriggerDevStep />
200
232
</ StepContentContainer >
201
- < StepNumber stepNumber = "4" title = "Check for Jobs" />
233
+ < StepNumber stepNumber = "4" title = "Wait for Jobs" displaySpinner />
202
234
< StepContentContainer >
203
- < Paragraph >
204
- Once you've run the CLI command, click Refresh to view your example Job in the
205
- list.
206
- </ Paragraph >
207
- < Button
208
- variant = "primary/medium"
209
- className = "mt-4"
210
- LeadingIcon = "refresh"
211
- onClick = { ( ) => window . location . reload ( ) }
212
- >
213
- Refresh
214
- </ Button >
235
+ < Paragraph > This page will automatically refresh.</ Paragraph >
215
236
</ StepContentContainer >
216
237
</ >
217
238
) }
0 commit comments