Skip to content

Commit a2f843e

Browse files
authored
feat: add signup widget to post page sidebar (#5876)
1 parent bc3148a commit a2f843e

File tree

10 files changed

+121
-15
lines changed

10 files changed

+121
-15
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ function AuthOptionsInner({
159159
simplified = false,
160160
ignoreMessages = false,
161161
onboardingSignupButton,
162+
hideLoginLink,
163+
compact,
162164
autoTriggerProvider,
163165
socialProviderScopes,
164166
acceptedMarketing,
@@ -684,7 +686,7 @@ function AuthOptionsInner({
684686
className={classNames(
685687
'z-1 flex w-full max-w-[26.25rem] flex-col overflow-y-auto rounded-16',
686688
!simplified && 'bg-accent-pepper-subtlest',
687-
defaultDisplay === AuthDisplay.OnboardingSignup
689+
defaultDisplay === AuthDisplay.OnboardingSignup && !compact
688690
? 'min-h-[21.25rem]'
689691
: undefined,
690692
className?.container,
@@ -789,6 +791,8 @@ function AuthOptionsInner({
789791
targetId={targetId}
790792
className={className}
791793
onboardingSignupButton={onboardingSignupButton}
794+
hideLoginLink={hideLoginLink}
795+
compact={compact}
792796
/>
793797
</Tab>
794798
<Tab label={AuthDisplay.SignBack}>

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

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ interface OnboardingRegistrationFormProps extends AuthFormProps {
3636
isSocialAuthLoading?: boolean;
3737
className?: ClassName;
3838
onboardingSignupButton?: ButtonProps<'button'>;
39+
hideLoginLink?: boolean;
40+
compact?: boolean;
3941
}
4042

4143
export const isWebView = (): boolean => {
@@ -105,6 +107,9 @@ export const OnboardingRegistrationForm = ({
105107
onProviderClick,
106108
targetId,
107109
trigger,
110+
onboardingSignupButton,
111+
hideLoginLink,
112+
compact,
108113
}: OnboardingRegistrationFormProps): ReactElement => {
109114
const { logEvent } = useLogContext();
110115
const { value: isOnboardingV2 } = useConditionalFeature({
@@ -144,9 +149,9 @@ export const OnboardingRegistrationForm = ({
144149
icon={provider.icon}
145150
loading={!isReady || isSocialAuthLoading}
146151
onClick={() => onProviderClick?.(provider.value, false)}
147-
size={ButtonSize.Large}
152+
size={onboardingSignupButton?.size ?? ButtonSize.Large}
148153
type="button"
149-
variant={ButtonVariant.Primary}
154+
variant={onboardingSignupButton?.variant ?? ButtonVariant.Primary}
150155
>
151156
Continue with {provider.label}
152157
</Button>
@@ -160,26 +165,28 @@ export const OnboardingRegistrationForm = ({
160165
label="OR"
161166
/>
162167
<div className="flex flex-col-reverse text-center">
163-
<MemberAlready
164-
onLogin={() => onExistingEmail?.('')}
165-
className={{
166-
container: isOnboardingV2
167-
? 'mx-auto mt-6 w-full justify-center border-t border-border-subtlest-tertiary pt-6 text-center text-text-secondary typo-callout'
168-
: 'mx-auto mt-6 text-center text-text-secondary typo-callout',
169-
login: '!text-inherit',
170-
}}
171-
/>
168+
{!hideLoginLink && (
169+
<MemberAlready
170+
onLogin={() => onExistingEmail?.('')}
171+
className={{
172+
container: isOnboardingV2
173+
? 'mx-auto mt-6 w-full justify-center border-t border-border-subtlest-tertiary pt-6 text-center text-text-secondary typo-callout'
174+
: 'mx-auto mt-6 text-center text-text-secondary typo-callout',
175+
login: '!text-inherit',
176+
}}
177+
/>
178+
)}
172179
<SignupDisclaimer className="!text-text-tertiary tablet:!typo-footnote" />
173180
<Button
174181
aria-label="Signup using email"
175-
className="mb-8"
182+
className={compact ? 'mb-4' : 'mb-8'}
176183
data-funnel-track={FunnelTargetId.SignupProvider}
177184
disabled={isSocialAuthLoading}
178185
onClick={() => {
179186
trackOpenSignup();
180187
onContinueWithEmail?.();
181188
}}
182-
size={ButtonSize.Large}
189+
size={onboardingSignupButton?.size ?? ButtonSize.Large}
183190
type="button"
184191
variant={ButtonVariant.Float}
185192
>

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ export interface AuthOptionsProps {
130130
targetId?: string;
131131
ignoreMessages?: boolean;
132132
onboardingSignupButton?: ButtonProps<'button'>;
133+
hideLoginLink?: boolean;
134+
compact?: boolean;
133135
autoTriggerProvider?: string;
134136
socialProviderScopes?: string[];
135137
acceptedMarketing?: boolean;
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import type { ReactElement } from 'react';
2+
import React from 'react';
3+
import { useAuthContext } from '../../contexts/AuthContext';
4+
import { useConditionalFeature } from '../../hooks/useConditionalFeature';
5+
import { featurePostSignupWidget } from '../../lib/featureManagement';
6+
import { AuthTriggers } from '../../lib/auth';
7+
import { ButtonSize, ButtonVariant } from '../buttons/Button';
8+
import AuthOptions from '../auth/AuthOptions';
9+
import { AuthDisplay } from '../auth/common';
10+
11+
const gradientStyle: React.CSSProperties = {
12+
backgroundImage:
13+
'linear-gradient(90deg, var(--theme-accent-cabbage-default) 0%, var(--theme-accent-onion-default) 30%, var(--theme-accent-water-default) 60%, var(--theme-accent-cabbage-default) 100%)',
14+
backgroundSize: '200% auto',
15+
animation: 'post-signup-gradient-shift 10s ease-in-out infinite',
16+
WebkitBackgroundClip: 'text',
17+
backgroundClip: 'text',
18+
color: 'transparent',
19+
};
20+
21+
export function PostSignupWidget(): ReactElement | null {
22+
const { user, isAuthReady, showLogin } = useAuthContext();
23+
const shouldEvaluate = isAuthReady && !user;
24+
const { value: isEnabled } = useConditionalFeature({
25+
feature: featurePostSignupWidget,
26+
shouldEvaluate,
27+
});
28+
29+
if (!shouldEvaluate || !isEnabled) {
30+
return null;
31+
}
32+
33+
return (
34+
<div className="flex flex-col rounded-16 border border-border-subtlest-tertiary p-4">
35+
<style>
36+
{`@keyframes post-signup-gradient-shift {
37+
0% { background-position: 0% 50%; }
38+
50% { background-position: 100% 50%; }
39+
100% { background-position: 0% 50%; }
40+
}`}
41+
</style>
42+
<h3 className="font-bold typo-title3" style={gradientStyle}>
43+
Want your personalized dev feed?
44+
</h3>
45+
<p className="mt-2 text-text-tertiary typo-footnote">
46+
Millions of developers rely on daily.dev for tech news, tools, and
47+
discussions that actually matter.
48+
</p>
49+
<div className="mt-4">
50+
<AuthOptions
51+
ignoreMessages
52+
formRef={null as unknown as React.MutableRefObject<HTMLFormElement>}
53+
trigger={AuthTriggers.PostPage}
54+
simplified
55+
defaultDisplay={AuthDisplay.OnboardingSignup}
56+
forceDefaultDisplay
57+
className={{
58+
onboardingSignup: '!gap-3',
59+
}}
60+
onAuthStateUpdate={(props) => {
61+
showLogin({
62+
trigger: AuthTriggers.Onboarding,
63+
options: { isLogin: true, formValues: props },
64+
});
65+
}}
66+
onboardingSignupButton={{
67+
variant: ButtonVariant.Primary,
68+
size: ButtonSize.Medium,
69+
}}
70+
hideLoginLink
71+
compact
72+
/>
73+
</div>
74+
</div>
75+
);
76+
}

packages/shared/src/components/post/PostWidgets.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { SourceType } from '../../graphql/sources';
1515
import EntityCardSkeleton from '../cards/entity/EntityCardSkeleton';
1616
import { PostSidebarAdWidget } from './PostSidebarAdWidget';
1717
import { FeaturedArchives } from '../widgets/FeaturedArchives';
18+
import { PostSignupWidget } from './PostSignupWidget';
1819

1920
const UserEntityCard = dynamic(
2021
/* webpackChunkName: "userEntityCard" */ () =>
@@ -81,6 +82,7 @@ export function PostWidgets({
8182

8283
return (
8384
<PageWidgets className={className}>
85+
<PostSignupWidget />
8486
{sourceCard}
8587
{creator && (
8688
<UserEntityCard

packages/shared/src/components/post/SquadPostWidgets.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import UserEntityCard from '../cards/entity/UserEntityCard';
1616
import type { UserShortProfile } from '../../lib/user';
1717
import { PostSidebarAdWidget } from './PostSidebarAdWidget';
1818
import { FeaturedArchives } from '../widgets/FeaturedArchives';
19+
import { PostSignupWidget } from './PostSignupWidget';
1920

2021
export function SquadPostWidgets({
2122
onCopyPostLink,
@@ -34,6 +35,7 @@ export function SquadPostWidgets({
3435

3536
return (
3637
<PageWidgets className={className}>
38+
<PostSignupWidget />
3739
{!isUserSource &&
3840
(isSquadSource ? (
3941
<SquadEntityCard

packages/shared/src/components/post/collection/CollectionPostWidgets.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { PostWidgetsProps } from '../PostWidgets';
1010
import { FooterLinks } from '../../footer';
1111
import { PostSidebarAdWidget } from '../PostSidebarAdWidget';
1212
import { FeaturedArchives } from '../../widgets/FeaturedArchives';
13+
import { PostSignupWidget } from '../PostSignupWidget';
1314

1415
export const CollectionPostWidgets = ({
1516
onCopyPostLink,
@@ -19,6 +20,7 @@ export const CollectionPostWidgets = ({
1920
}: PostWidgetsProps): ReactElement => {
2021
return (
2122
<PageWidgets className={className}>
23+
<PostSignupWidget />
2224
<CollectionsIntro className="hidden laptop:flex" />
2325
<RelatedPostsWidget
2426
post={post}

packages/shared/src/lib/auth.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export enum AuthTriggers {
7575
RecruiterSelfServe = 'recruiter self serve',
7676
AiFluencyQuiz = 'ai fluency quiz',
7777
Gear = 'gear',
78+
PostPage = 'post page',
7879
}
7980

8081
export type AuthTriggersType =

packages/shared/src/lib/featureManagement.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,5 @@ export const sharedPostPreviewFeature = new Feature(
153153
);
154154

155155
export const featureOnboardingV2 = new Feature('onboarding_v2', false);
156+
157+
export const featurePostSignupWidget = new Feature('post_signup_widget', false);

packages/webapp/pages/posts/[id]/index.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ import classNames from 'classnames';
3939
import { useOnboardingActions } from '@dailydotdev/shared/src/hooks/auth/useOnboardingActions';
4040
import { webappUrl } from '@dailydotdev/shared/src/lib/constants';
4141
import { useFeatureTheme } from '@dailydotdev/shared/src/hooks/utils/useFeatureTheme';
42+
import { useConditionalFeature } from '@dailydotdev/shared/src/hooks/useConditionalFeature';
43+
import { featurePostSignupWidget } from '@dailydotdev/shared/src/lib/featureManagement';
4244
import CustomAuthBanner from '@dailydotdev/shared/src/components/auth/CustomAuthBanner';
4345
import { isSourceUserSource } from '@dailydotdev/shared/src/graphql/sources';
4446
import { usePostReferrerContext } from '@dailydotdev/shared/src/contexts/PostReferrerContext';
@@ -183,6 +185,10 @@ export const PostPage = ({
183185
const isFallback = false;
184186
const { shouldShowAuthBanner } = useOnboardingActions();
185187
const isLaptop = useViewSize(ViewSize.Laptop);
188+
const { value: isPostSignupWidget } = useConditionalFeature({
189+
feature: featurePostSignupWidget,
190+
shouldEvaluate: shouldShowAuthBanner,
191+
});
186192
const { post, isError, isLoading } = usePostById({
187193
id,
188194
options: {
@@ -282,7 +288,9 @@ export const PostPage = ({
282288
},
283289
}}
284290
/>
285-
{shouldShowAuthBanner && isLaptop && <PostAuthBanner />}
291+
{shouldShowAuthBanner && isLaptop && !isPostSignupWidget && (
292+
<PostAuthBanner />
293+
)}
286294
</FooterNavBarLayout>
287295
</LogExtraContextProvider>
288296
</ActivePostContextProvider>

0 commit comments

Comments
 (0)