Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@
"@trpc/client": "^11.12.0",
"@trpc/server": "^11.12.0",
"@trpc/tanstack-react-query": "^11.12.0",
"@tsparticles/react": "^3.0.0",
"@tsparticles/slim": "^3.9.1",
"@xterm/addon-fit": "^0.10.0",
"@xterm/addon-serialize": "^0.13.0",
"@xterm/addon-web-links": "^0.11.0",
Expand Down
18 changes: 9 additions & 9 deletions apps/code/src/renderer/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,16 @@ function App() {
);
}

// Four-phase rendering: auth → access gate → onboarding → main app
// Rendering: onboarding → auth → access gate → main app
const renderContent = () => {
if (!hasCompletedOnboarding) {
return (
<motion.div key="onboarding" initial={{ opacity: 1 }}>
<OnboardingFlow />
</motion.div>
);
}

if (!isAuthenticated) {
return (
<motion.div key="auth" initial={{ opacity: 1 }}>
Expand Down Expand Up @@ -185,14 +193,6 @@ function App() {
);
}

if (!hasCompletedOnboarding) {
return (
<motion.div key="onboarding">
<OnboardingFlow />
</motion.div>
);
}

return (
<motion.div
key="main"
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
220 changes: 3 additions & 217 deletions apps/code/src/renderer/features/auth/components/AuthScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,89 +1,10 @@
import { DraggableTitleBar } from "@components/DraggableTitleBar";
import { ZenHedgehog } from "@components/ZenHedgehog";
import { useAuthStore } from "@features/auth/stores/authStore";
import { Callout, Flex, Spinner, Text, Theme } from "@radix-ui/themes";
import posthogIcon from "@renderer/assets/images/posthog-icon.svg";
import { Flex, Theme } from "@radix-ui/themes";
import phWordmark from "@renderer/assets/images/wordmark-alt.png";
import { trpcClient } from "@renderer/trpc/client";
import { REGION_LABELS } from "@shared/constants/oauth";
import type { CloudRegion } from "@shared/types/oauth";
import { useMutation } from "@tanstack/react-query";
import { useState } from "react";
import { RegionSelect } from "./RegionSelect";

export const getErrorMessage = (error: unknown) => {
if (!error) {
return null;
}
if (!(error instanceof Error)) {
return "Failed to authenticate";
}
const message = error.message;

if (message === "2FA_REQUIRED") {
return null; // 2FA dialog will handle this
}

if (message.includes("access_denied")) {
return "Authorization cancelled.";
}

if (message.includes("timed out")) {
return "Authorization timed out. Please try again.";
}

if (message.includes("SSO login required")) {
return message;
}

return message;
};

type AuthMode = "login" | "signup";
import { OAuthControls } from "./OAuthControls";

export function AuthScreen() {
const staleRegion = useAuthStore((s) => s.staleTokens?.cloudRegion);
const [region, setRegion] = useState<CloudRegion>(staleRegion ?? "us");
const [authMode, setAuthMode] = useState<AuthMode>("login");
const { loginWithOAuth, signupWithOAuth } = useAuthStore();

const loginMutation = useMutation({
mutationFn: async () => {
await loginWithOAuth(region);
},
});

const signupMutation = useMutation({
mutationFn: async () => {
await signupWithOAuth(region);
},
});

const handleAuth = () => {
if (authMode === "login") {
loginMutation.mutate();
} else {
signupMutation.mutate();
}
};

const handleRegionChange = (value: CloudRegion) => {
setRegion(value);
loginMutation.reset();
signupMutation.reset();
};

const handleCancel = async () => {
loginMutation.reset();
signupMutation.reset();
await trpcClient.oauth.cancelFlow.mutate();
};

const isPending = loginMutation.isPending || signupMutation.isPending;
const isLoading = isPending;
const error = loginMutation.error || signupMutation.error;
const errorMessage = getErrorMessage(error);

return (
<Theme appearance="light" accentColor="orange">
<Flex height="100vh" style={{ position: "relative", overflow: "hidden" }}>
Expand Down Expand Up @@ -147,142 +68,7 @@ export function AuthScreen() {
}}
/>

{/* Error */}
{errorMessage && (
<Callout.Root color="red" size="1">
<Callout.Text>{errorMessage}</Callout.Text>
</Callout.Root>
)}

{/* Pending state */}
{isPending && (
<Callout.Root color="blue" size="1">
<Callout.Text>Waiting for authorization...</Callout.Text>
</Callout.Root>
)}

{/* Primary CTA */}
<Flex direction="column" gap="2">
<button
type="button"
onClick={isPending ? handleCancel : handleAuth}
disabled={isLoading && !isPending}
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: "8px",
width: "100%",
height: "44px",
border: isPending
? "1.5px solid var(--gray-6)"
: "1.5px solid var(--accent-8)",
borderRadius: "6px",
fontSize: "15px",
fontWeight: 500,
cursor: isLoading && !isPending ? "not-allowed" : "pointer",
backgroundColor: isPending
? "var(--gray-3)"
: "var(--accent-9)",
color: isPending
? "var(--gray-11)"
: "var(--accent-contrast)",
boxShadow: isPending
? "none"
: "0 3px 0 -1px var(--accent-8)",
opacity: isLoading && !isPending ? 0.5 : 1,
transition: "opacity 150ms ease, box-shadow 100ms ease",
}}
>
{isPending ? (
<Spinner size="1" />
) : (
<img
src={posthogIcon}
alt=""
style={{ width: "20px", height: "20px" }}
/>
)}
{isPending
? "Cancel"
: authMode === "login"
? "Sign in with PostHog"
: "Sign up with PostHog"}
</button>
<Text
size="1"
align="center"
style={{ color: "var(--gray-12)", opacity: 0.5 }}
>
Redirects to PostHog.com
</Text>
</Flex>

{/* Region + secondary links */}
<Flex direction="column" gap="3" align="center">
<RegionSelect
region={region}
regionLabel={REGION_LABELS[region]}
onRegionChange={handleRegionChange}
disabled={isLoading}
/>

<Text size="2">
{authMode === "login" ? (
<>
<span
style={{
color: "var(--gray-12)",
opacity: 0.5,
}}
>
Don&apos;t have an account?{" "}
</span>
<button
type="button"
onClick={() => setAuthMode("signup")}
style={{
background: "none",
border: "none",
padding: 0,
color: "var(--accent-9)",
cursor: "pointer",
fontWeight: 500,
fontSize: "inherit",
}}
>
create one
</button>
</>
) : (
<>
<span
style={{
color: "var(--gray-12)",
opacity: 0.5,
}}
>
Already have an account?{" "}
</span>
<button
type="button"
onClick={() => setAuthMode("login")}
style={{
background: "none",
border: "none",
padding: 0,
color: "var(--accent-9)",
cursor: "pointer",
fontWeight: 500,
fontSize: "inherit",
}}
>
sign in
</button>
</>
)}
</Text>
</Flex>
<OAuthControls />
</Flex>
</Flex>

Expand Down
Loading