Skip to content

Commit 6a69e20

Browse files
committed
simplify onboarding
1 parent be357c9 commit 6a69e20

File tree

9 files changed

+115
-314
lines changed

9 files changed

+115
-314
lines changed

apps/desktop/src/components/onboarding/calendar.tsx

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,23 @@
11
import { Icon } from "@iconify-icon/react";
2+
import { platform } from "@tauri-apps/plugin-os";
23

3-
import {
4-
Divider,
5-
IntegrationRow,
6-
OnboardingContainer,
7-
type OnboardingNext,
8-
} from "./shared";
4+
import { useAuth } from "../../auth";
5+
import type { OnboardingStepId } from "./config";
6+
import { Divider, IntegrationRow, OnboardingContainer } from "./shared";
97

10-
type CalendarsProps = {
11-
local: boolean;
12-
onNext: OnboardingNext;
13-
onBack?: () => void;
14-
};
8+
export function Calendars({
9+
onNavigate,
10+
}: {
11+
onNavigate: (step: OnboardingStepId | "done") => void;
12+
}) {
13+
const auth = useAuth();
14+
const currentPlatform = platform();
15+
const isLoggedIn = !!auth?.session;
1516

16-
export function Calendars({ local, onNext, onBack }: CalendarsProps) {
1717
return (
18-
<OnboardingContainer
19-
title="Connect your calendars to be reminded every time"
20-
action={{ kind: "skip", onClick: () => onNext() }}
21-
onBack={onBack}
22-
>
18+
<OnboardingContainer title="Connect your calendars to be reminded every time">
2319
<div className="flex flex-col gap-4">
24-
{local ? (
20+
{!isLoggedIn ? (
2521
<>
2622
<IntegrationRow
2723
icon={<Icon icon="logos:google-calendar" size={24} />}
@@ -57,6 +53,15 @@ export function Calendars({ local, onNext, onBack }: CalendarsProps) {
5753
</>
5854
)}
5955
</div>
56+
57+
<button
58+
onClick={() =>
59+
onNavigate(currentPlatform === "macos" ? "permissions" : "done")
60+
}
61+
className="mt-4 text-sm text-neutral-400 transition-colors hover:text-neutral-600"
62+
>
63+
skip
64+
</button>
6065
</OnboardingContainer>
6166
);
6267
}
Lines changed: 9 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
import { useQuery } from "@tanstack/react-query";
2-
import { arch, platform, type Platform } from "@tauri-apps/plugin-os";
31
import type { ComponentType } from "react";
42

5-
import { useAuth } from "../../auth";
63
import { ConfigureNotice } from "./configure-notice";
74
import { Login } from "./login";
85
import { Permissions } from "./permissions";
9-
import type { OnboardingNext } from "./shared";
106
import { Welcome } from "./welcome";
117

128
export type OnboardingStepId =
@@ -15,78 +11,16 @@ export type OnboardingStepId =
1511
| "configure-notice"
1612
| "permissions";
1713

18-
export type OnboardingContext = {
19-
platform: Platform;
20-
isAppleSilicon: boolean;
21-
isLoggedIn: boolean;
22-
local: boolean;
23-
flags: {
24-
calendarReady: boolean;
25-
};
26-
};
27-
28-
export type OnboardingStepConfig = {
14+
type StepConfig = {
2915
id: OnboardingStepId;
30-
shouldShow: (ctx: OnboardingContext) => boolean;
31-
component: ComponentType<{ onNext: OnboardingNext; onBack?: () => void }>;
16+
component: ComponentType<{
17+
onNavigate: (step: OnboardingStepId | "done") => void;
18+
}>;
3219
};
3320

34-
export function getPreviousStep(
35-
ctx: OnboardingContext,
36-
currentStep: OnboardingStepId,
37-
): OnboardingStepId | null {
38-
const visibleSteps = STEP_CONFIGS.filter((s) => s.shouldShow(ctx));
39-
const currentIndex = visibleSteps.findIndex((s) => s.id === currentStep);
40-
return visibleSteps[currentIndex - 1]?.id ?? null;
41-
}
42-
43-
export const STEP_CONFIGS: OnboardingStepConfig[] = [
44-
{
45-
id: "welcome",
46-
shouldShow: () => true,
47-
component: Welcome,
48-
},
49-
{
50-
id: "login",
51-
shouldShow: (ctx) => !ctx.local,
52-
component: Login,
53-
},
54-
{
55-
id: "configure-notice",
56-
shouldShow: (ctx) => ctx.local,
57-
component: ConfigureNotice,
58-
},
59-
{
60-
id: "permissions",
61-
shouldShow: (ctx) => ctx.platform === "macos",
62-
component: Permissions,
63-
},
21+
export const STEP_CONFIGS: StepConfig[] = [
22+
{ id: "welcome", component: Welcome },
23+
{ id: "login", component: Login },
24+
{ id: "configure-notice", component: ConfigureNotice },
25+
{ id: "permissions", component: Permissions },
6426
];
65-
66-
export function useOnboardingContext(
67-
local?: boolean,
68-
): OnboardingContext | null {
69-
const currentPlatform = platform();
70-
const auth = useAuth();
71-
const archQuery = useQuery({
72-
queryKey: ["arch"],
73-
queryFn: () => arch(),
74-
});
75-
76-
if (archQuery.isPending) {
77-
return null;
78-
}
79-
80-
const isAppleSilicon =
81-
currentPlatform === "macos" && archQuery.data === "aarch64";
82-
83-
return {
84-
platform: currentPlatform,
85-
isAppleSilicon,
86-
isLoggedIn: auth?.session !== null,
87-
local: local ?? false,
88-
flags: {
89-
calendarReady: false,
90-
},
91-
};
92-
}

apps/desktop/src/components/onboarding/configure-notice.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
import { OnboardingContainer, type OnboardingNext } from "./shared";
1+
import { platform } from "@tauri-apps/plugin-os";
22

3-
type ConfigureNoticeProps = {
4-
onNext: OnboardingNext;
5-
onBack?: () => void;
6-
};
3+
import type { OnboardingStepId } from "./config";
4+
import { OnboardingContainer } from "./shared";
5+
6+
export function ConfigureNotice({
7+
onNavigate,
8+
}: {
9+
onNavigate: (step: OnboardingStepId | "done") => void;
10+
}) {
11+
const currentPlatform = platform();
712

8-
export function ConfigureNotice({ onNext, onBack }: ConfigureNoticeProps) {
913
return (
1014
<OnboardingContainer
1115
title="AI models are needed for best experience"
12-
onBack={onBack}
16+
onBack={() => onNavigate("welcome")}
1317
>
1418
<div className="flex flex-col gap-4">
1519
<Requirement
@@ -25,7 +29,9 @@ export function ConfigureNotice({ onNext, onBack }: ConfigureNoticeProps) {
2529

2630
<div className="flex flex-col gap-3 mt-4">
2731
<button
28-
onClick={() => onNext()}
32+
onClick={() =>
33+
onNavigate(currentPlatform === "macos" ? "permissions" : "done")
34+
}
2935
className="w-full py-3 rounded-full bg-gradient-to-t from-stone-600 to-stone-500 text-white text-sm font-medium duration-150 hover:scale-[1.01] active:scale-[0.99]"
3036
>
3137
I will configure it later
@@ -35,7 +41,7 @@ export function ConfigureNotice({ onNext, onBack }: ConfigureNoticeProps) {
3541
);
3642
}
3743

38-
export function Requirement({
44+
function Requirement({
3945
title,
4046
description,
4147
required,

apps/desktop/src/components/onboarding/login.tsx

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,22 @@ import { useCallback, useEffect, useState } from "react";
44
import { getRpcCanStartTrial, postBillingStartTrial } from "@hypr/api-client";
55
import { createClient, createConfig } from "@hypr/api-client/client";
66

7+
import { platform } from "@tauri-apps/plugin-os";
8+
79
import { useAuth } from "../../auth";
810
import { getEntitlementsFromToken } from "../../billing";
911
import { env } from "../../env";
1012
import * as settings from "../../store/tinybase/settings";
11-
import { Divider, OnboardingContainer, type OnboardingNext } from "./shared";
13+
import type { OnboardingStepId } from "./config";
14+
import { Divider, OnboardingContainer } from "./shared";
1215

1316
export function Login({
14-
onNext,
15-
onBack,
17+
onNavigate,
1618
}: {
17-
onNext: OnboardingNext;
18-
onBack?: () => void;
19+
onNavigate: (step: OnboardingStepId | "done") => void;
1920
}) {
2021
const auth = useAuth();
22+
const currentPlatform = platform();
2123
const [callbackUrl, setCallbackUrl] = useState("");
2224

2325
const setLlmProvider = settings.UI.useSetValueCallback(
@@ -78,12 +80,14 @@ export function Login({
7880
onSuccess: (isPro) => {
7981
if (isPro) {
8082
setTrialDefaults();
83+
onNavigate(currentPlatform === "macos" ? "permissions" : "done");
84+
} else {
85+
onNavigate("configure-notice");
8186
}
82-
onNext({ local: !isPro });
8387
},
8488
onError: (e) => {
8589
console.error(e);
86-
onNext({ local: true });
90+
onNavigate("configure-notice");
8791
},
8892
});
8993

@@ -103,7 +107,7 @@ export function Login({
103107
<OnboardingContainer
104108
title="Waiting for sign in..."
105109
description="Complete the process in your browser"
106-
onBack={onBack}
110+
onBack={() => onNavigate("welcome")}
107111
>
108112
<button
109113
onClick={() => auth?.signIn()}

apps/desktop/src/components/onboarding/machine.ts

Lines changed: 0 additions & 50 deletions
This file was deleted.

apps/desktop/src/components/onboarding/permissions.tsx

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@ import { AlertCircleIcon, ArrowRightIcon, CheckIcon } from "lucide-react";
22

33
import { cn } from "@hypr/utils";
44

5+
import { useAuth } from "../../auth";
56
import { usePermissions } from "../../hooks/use-permissions";
6-
import { OnboardingContainer, type OnboardingNext } from "./shared";
7-
8-
type PermissionBlockProps = {
9-
name: string;
10-
status: string | undefined;
11-
description: { authorized: string; unauthorized: string };
12-
isPending: boolean;
13-
onAction: () => void;
14-
};
7+
import type { OnboardingStepId } from "./config";
8+
import { OnboardingContainer } from "./shared";
159

1610
function PermissionBlock({
1711
name,
1812
status,
1913
description,
2014
isPending,
2115
onAction,
22-
}: PermissionBlockProps) {
16+
}: {
17+
name: string;
18+
status: string | undefined;
19+
description: { authorized: string; unauthorized: string };
20+
isPending: boolean;
21+
onAction: () => void;
22+
}) {
2323
const isAuthorized = status === "authorized";
2424

2525
return (
@@ -71,12 +71,12 @@ function PermissionBlock({
7171
);
7272
}
7373

74-
type PermissionsProps = {
75-
onNext: OnboardingNext;
76-
onBack?: () => void;
77-
};
78-
79-
export function Permissions({ onNext, onBack }: PermissionsProps) {
74+
export function Permissions({
75+
onNavigate,
76+
}: {
77+
onNavigate: (step: OnboardingStepId | "done") => void;
78+
}) {
79+
const auth = useAuth();
8080
const {
8181
micPermissionStatus,
8282
systemAudioPermissionStatus,
@@ -94,10 +94,12 @@ export function Permissions({ onNext, onBack }: PermissionsProps) {
9494
systemAudioPermissionStatus.data === "authorized" &&
9595
accessibilityPermissionStatus.data === "authorized";
9696

97+
const backStep = auth?.session ? "welcome" : "configure-notice";
98+
9799
return (
98100
<OnboardingContainer
99101
title="Permissions needed for best experience"
100-
onBack={onBack}
102+
onBack={() => onNavigate(backStep)}
101103
>
102104
<div className="flex flex-col gap-4">
103105
<PermissionBlock
@@ -135,7 +137,7 @@ export function Permissions({ onNext, onBack }: PermissionsProps) {
135137
</div>
136138

137139
<button
138-
onClick={() => onNext()}
140+
onClick={() => onNavigate("done")}
139141
disabled={!allPermissionsGranted}
140142
className={cn([
141143
"w-full py-3 rounded-full text-sm font-medium duration-150",

0 commit comments

Comments
 (0)