Skip to content

Commit b3d5d33

Browse files
committed
feat: hero onboardng
1 parent e54d63a commit b3d5d33

17 files changed

Lines changed: 898 additions & 696 deletions

packages/shared/src/components/auth/AuthOptionsInner.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ function AuthOptionsInner({
136136
hideLoginLink,
137137
compact,
138138
splitSignupStyle,
139+
preferGithub,
139140
autoTriggerProvider,
140141
socialProviderScopes,
141142
}: AuthOptionsProps): ReactElement {
@@ -767,6 +768,7 @@ function AuthOptionsInner({
767768
hideLoginLink={hideLoginLink}
768769
compact={compact}
769770
splitSignupStyle={splitSignupStyle}
771+
preferGithub={preferGithub}
770772
/>
771773
</Tab>
772774
<Tab label={AuthDisplay.SignBack}>

packages/shared/src/components/auth/OnboardingRegistrationForm.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ interface OnboardingRegistrationFormProps extends AuthFormProps {
3838
hideLoginLink?: boolean;
3939
compact?: boolean;
4040
splitSignupStyle?: boolean;
41+
preferGithub?: boolean;
4142
}
4243

4344
export const isWebView = (): boolean => {
@@ -114,9 +115,13 @@ export const OnboardingRegistrationForm = ({
114115
hideLoginLink,
115116
compact,
116117
splitSignupStyle = false,
118+
preferGithub,
117119
}: OnboardingRegistrationFormProps): ReactElement => {
118120
const { logEvent } = useLogContext();
119121
const isOnboardingTrigger = trigger === AuthTriggers.Onboarding;
122+
const signupProviders = getSignupProviders(
123+
preferGithub ?? isOnboardingTrigger,
124+
);
120125

121126
const trackOpenSignup = () => {
122127
logEvent({
@@ -220,7 +225,7 @@ export const OnboardingRegistrationForm = ({
220225
return (
221226
<div aria-label="Login/Register options" className="flex flex-col gap-4">
222227
<ul aria-label="Social login buttons" className="flex flex-col gap-4">
223-
{getSignupProviders(isOnboardingTrigger).map((provider) => (
228+
{signupProviders.map((provider) => (
224229
<li key={provider.value}>
225230
<Button
226231
aria-label={

packages/shared/src/components/auth/common.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ export interface AuthOptionsProps {
128128
compact?: boolean;
129129
/** X-style split onboarding: "Sign up with", "Create account", Sign in button */
130130
splitSignupStyle?: boolean;
131+
/** Order GitHub before Google in the OAuth provider list (developer-first). */
132+
preferGithub?: boolean;
131133
autoTriggerProvider?: string;
132134
socialProviderScopes?: string[];
133135
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import { OnboardingSignupHero } from './OnboardingSignupHero';
4+
5+
jest.mock('../../../contexts/SettingsContext', () => ({
6+
ThemeMode: { Dark: 'dark' },
7+
useSettingsContext: () => ({ applyThemeMode: jest.fn() }),
8+
}));
9+
10+
jest.mock('../../../components/Logo', () => ({
11+
__esModule: true,
12+
default: () => <div data-testid="logo" />,
13+
LogoPosition: { Relative: 'relative' },
14+
}));
15+
16+
jest.mock('../../../components/footer/FooterLinks', () => ({
17+
FooterLinks: () => <div data-testid="footer" />,
18+
}));
19+
20+
jest.mock('../../../components/auth/SignupDisclaimer', () => ({
21+
__esModule: true,
22+
default: () => <div data-testid="disclaimer" />,
23+
}));
24+
25+
// Isolate the shell from the (gql/context-heavy) background blocks.
26+
jest.mock('./signupHero/HeroBackgroundLayer', () => ({
27+
HeroBackgroundLayer: ({
28+
background,
29+
imageMode,
30+
}: {
31+
background: string;
32+
imageMode: string;
33+
}) => (
34+
<div
35+
data-testid="bg-layer"
36+
data-background={background}
37+
data-image-mode={imageMode}
38+
/>
39+
),
40+
}));
41+
42+
const renderHero = (
43+
props: Partial<React.ComponentProps<typeof OnboardingSignupHero>> = {},
44+
) =>
45+
render(
46+
<OnboardingSignupHero background="desk" {...props}>
47+
<div data-testid="auth-form" />
48+
</OnboardingSignupHero>,
49+
);
50+
51+
describe('OnboardingSignupHero', () => {
52+
it('passes background and image mode to the background layer', () => {
53+
renderHero({ background: 'desk', imageMode: 'colors' });
54+
const layer = screen.getByTestId('bg-layer');
55+
expect(layer).toHaveAttribute('data-background', 'desk');
56+
expect(layer).toHaveAttribute('data-image-mode', 'colors');
57+
});
58+
59+
it('renders aurora orbs by default', () => {
60+
renderHero();
61+
expect(screen.getByTestId('hero-orbs')).toBeInTheDocument();
62+
});
63+
64+
it('omits aurora orbs when showOrbs is false', () => {
65+
renderHero({ showOrbs: false });
66+
expect(screen.queryByTestId('hero-orbs')).not.toBeInTheDocument();
67+
});
68+
69+
it('renders the halo and vignette as part of the desk background', () => {
70+
renderHero({ background: 'desk' });
71+
expect(screen.getByTestId('hero-halo')).toBeInTheDocument();
72+
});
73+
74+
it('omits the halo for the cards background', () => {
75+
renderHero({ background: 'cards' });
76+
expect(screen.queryByTestId('hero-halo')).not.toBeInTheDocument();
77+
});
78+
79+
it('renders the form and headline', () => {
80+
renderHero({ headline: 'Hello devs' });
81+
expect(screen.getByTestId('auth-form')).toBeInTheDocument();
82+
expect(screen.getByText('Hello devs')).toBeInTheDocument();
83+
});
84+
});

0 commit comments

Comments
 (0)