Skip to content

Commit 434c010

Browse files
committed
feat: step 1 functionality
1 parent 540fd88 commit 434c010

File tree

6 files changed

+379
-11
lines changed

6 files changed

+379
-11
lines changed

studio/src/components/onboarding/onboarding-navigation.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const OnboardingNavigation = ({
1010
onSkip,
1111
}: {
1212
backHref?: string;
13-
forward: { href: string } | { onClick: () => void; isLoading?: boolean };
13+
forward: { href: string } | { onClick: () => void; isLoading?: boolean; disabled?: boolean };
1414
forwardLabel?: string;
1515
onSkip: () => void;
1616
}) => {
@@ -53,7 +53,7 @@ export const OnboardingNavigation = ({
5353
className="group"
5454
onClick={forward.onClick}
5555
isLoading={forward.isLoading}
56-
disabled={forward.isLoading}
56+
disabled={forward.isLoading || forward.disabled}
5757
>
5858
{forwardLabel}
5959
<ArrowRightIcon className="ml-2 transition-transform group-hover:translate-x-1" />

studio/src/components/onboarding/onboarding-provider.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { useSessionStorage } from '@/hooks/use-session-storage';
1414
type Onboarding = {
1515
finishedAt?: Date;
1616
federatedGraphsCount: number;
17+
slack: boolean;
18+
email: boolean;
1719
};
1820

1921
export interface OnboardingState {

studio/src/components/onboarding/step-1.tsx

Lines changed: 110 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,44 @@ import { createOnboarding } from '@wundergraph/cosmo-connect/dist/platform/v1/pl
77
import { useRouter } from 'next/router';
88
import { EnumStatusCode } from '@wundergraph/cosmo-connect/dist/common/common_pb';
99
import { useToast } from '../ui/use-toast';
10+
import { SubmitHandler, useZodForm } from '@/hooks/use-form';
11+
import { Controller } from 'react-hook-form';
12+
import { z } from 'zod';
13+
import { Form } from '../ui/form';
14+
import { Checkbox } from '../ui/checkbox';
15+
import { TrafficAnimation } from './traffic-animation';
16+
17+
const onboardingSchema = z.object({
18+
channels: z.object({
19+
slack: z.boolean(),
20+
email: z.boolean(),
21+
}),
22+
});
23+
24+
type OnboardingFormValues = z.infer<typeof onboardingSchema>;
25+
26+
const WhyListItem = ({ title, text }: { title: string; text: string }) => (
27+
<li className="flex gap-2">
28+
<span className="mt-2 size-1.5 shrink-0 rounded-full bg-muted-foreground/60" />
29+
<div className="flex flex-col">
30+
<span className="text-sm font-medium">{title}</span>
31+
<span className="text-sm text-muted-foreground">{text}</span>
32+
</div>
33+
</li>
34+
);
1035

1136
export const Step1 = () => {
1237
const router = useRouter();
1338
const { toast } = useToast();
14-
const { setStep, setSkipped, setOnboarding } = useOnboarding();
39+
const { setStep, setSkipped, setOnboarding, onboarding } = useOnboarding();
40+
41+
const form = useZodForm<OnboardingFormValues>({
42+
mode: 'onChange',
43+
schema: onboardingSchema,
44+
defaultValues: {
45+
channels: { slack: onboarding?.slack ?? false, email: onboarding?.email ?? false },
46+
},
47+
});
1548

1649
const { mutate, isPending } = useMutation(createOnboarding, {
1750
onSuccess: (d) => {
@@ -23,9 +56,12 @@ export const Step1 = () => {
2356
return;
2457
}
2558

59+
const formValues = form.getValues();
2660
setOnboarding({
2761
federatedGraphsCount: d.federatedGraphsCount,
2862
finishedAt: d.finishedAt ? new Date(d.finishedAt) : undefined,
63+
slack: formValues.channels.slack,
64+
email: formValues.channels.email,
2965
});
3066
router.push('/onboarding/2');
3167
},
@@ -37,23 +73,88 @@ export const Step1 = () => {
3773
},
3874
});
3975

76+
const onSubmit: SubmitHandler<OnboardingFormValues> = (data) => {
77+
mutate({
78+
slack: data.channels.slack,
79+
email: data.channels.email,
80+
});
81+
};
82+
4083
useEffect(() => {
4184
setStep(1);
4285
}, [setStep]);
4386

4487
return (
4588
<OnboardingContainer>
46-
<h2 className="text-2xl font-semibold tracking-tight">Step 1</h2>
89+
<div className="flex w-full flex-col gap-8 text-left">
90+
<div className="space-y-2">
91+
<p className="text-sm text-muted-foreground">
92+
In ~<span className="font-medium text-foreground">3 minutes</span> you will have a federated GraphQL graph
93+
running locally and serving live traffic into Cosmo Cloud platform.
94+
</p>
95+
</div>
96+
97+
<TrafficAnimation />
98+
99+
<div className="space-y-3">
100+
<p className="text-sm font-semibold">What you will do</p>
101+
<ul className="flex flex-col gap-3">
102+
<WhyListItem
103+
title="Create your first graph"
104+
text="See how the products and reviews subgraphs compose into one supergraph, giving your client a single endpoint to resolve the data it needs."
105+
/>
106+
<WhyListItem
107+
title="Run your services"
108+
text="Run the same router stack you would run in production, locally."
109+
/>
110+
<WhyListItem title="Send a query" text="Watch real request metrics flow through the router." />
111+
</ul>
112+
</div>
113+
114+
<Form {...form}>
115+
<form onSubmit={form.handleSubmit(onSubmit)} className="w-full">
116+
<div className="rounded-md border border-dashed p-4">
117+
<p className="text-sm font-medium">If you get stuck, how can we reach you?</p>
118+
<div className="mt-3 flex flex-col gap-3">
119+
<Controller
120+
control={form.control}
121+
name="channels.slack"
122+
render={({ field }) => (
123+
<label className="flex items-start gap-3">
124+
<Checkbox checked={field.value} onCheckedChange={(checked) => field.onChange(checked === true)} />
125+
<div className="flex flex-col gap-y-1">
126+
<span className="text-sm font-medium leading-none">Slack</span>
127+
<span className="text-[0.8rem] text-muted-foreground">
128+
We automatically create a Slack channel for you.
129+
</span>
130+
</div>
131+
</label>
132+
)}
133+
/>
134+
<Controller
135+
control={form.control}
136+
name="channels.email"
137+
render={({ field }) => (
138+
<label className="flex items-start gap-3">
139+
<Checkbox checked={field.value} onCheckedChange={(checked) => field.onChange(checked === true)} />
140+
<div className="flex flex-col gap-y-1">
141+
<span className="text-sm font-medium leading-none">Email</span>
142+
<span className="text-[0.8rem] text-muted-foreground">Receive updates via email.</span>
143+
</div>
144+
</label>
145+
)}
146+
/>
147+
</div>
148+
</div>
149+
</form>
150+
</Form>
151+
</div>
152+
47153
<OnboardingNavigation
48154
onSkip={setSkipped}
155+
forwardLabel="Start the tour"
49156
forward={{
50-
onClick: () => {
51-
// TODO: replace with real values in form
52-
mutate({
53-
slack: true,
54-
email: false,
55-
});
56-
},
157+
onClick: form.handleSubmit(onSubmit),
57158
isLoading: isPending,
58159
}}
59160
/>

studio/src/components/onboarding/step-3.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export const Step3 = () => {
3131
...prev,
3232
finishedAt: new Date(d.finishedAt),
3333
federatedGraphsCount: d.federatedGraphsCount,
34+
slack: Boolean(prev?.slack),
35+
email: Boolean(prev?.email),
3436
}));
3537

3638
setStep(undefined);

0 commit comments

Comments
 (0)