Skip to content

Commit d3a6488

Browse files
committed
feat(onboarding): fallback for tags in case none were resolved
1 parent b85e117 commit d3a6488

File tree

2 files changed

+97
-12
lines changed

2 files changed

+97
-12
lines changed

packages/shared/src/components/onboarding/EditTag.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ interface EditTagProps {
2020
userId: string;
2121
headline?: string;
2222
requiredTags?: number;
23+
hidePreview?: boolean;
2324
}
2425
export const EditTag = ({
2526
feedSettings,
2627
userId,
2728
headline,
2829
requiredTags = REQUIRED_TAGS_THRESHOLD,
30+
hidePreview,
2931
}: EditTagProps): ReactElement => {
3032
const isMobile = useViewSize(ViewSize.MobileL);
3133
const [isPreviewVisible, setPreviewVisible] = useState(false);
@@ -63,15 +65,17 @@ export const EditTag = ({
6365
searchQuery={searchQuery}
6466
searchTags={searchTags}
6567
/>
66-
<FeedPreviewControls
67-
isOpen={isPreviewVisible}
68-
isDisabled={!isPreviewEnabled}
69-
textDisabled={`${tagsCount}/${requiredTags} to show feed preview`}
70-
origin={Origin.EditTag}
71-
onClick={setPreviewVisible}
72-
data-funnel-track={FunnelTargetId.FeedPreview}
73-
/>
74-
{isPreviewEnabled && isPreviewVisible && (
68+
{!hidePreview && (
69+
<FeedPreviewControls
70+
isOpen={isPreviewVisible}
71+
isDisabled={!isPreviewEnabled}
72+
textDisabled={`${tagsCount}/${requiredTags} to show feed preview`}
73+
origin={Origin.EditTag}
74+
onClick={setPreviewVisible}
75+
data-funnel-track={FunnelTargetId.FeedPreview}
76+
/>
77+
)}
78+
{!hidePreview && isPreviewEnabled && isPreviewVisible && (
7579
<FeedLayoutProvider>
7680
<p className="-mb-4 mt-6 text-center text-text-secondary typo-body">
7781
Change your tag selection until you&apos;re happy with your feed

packages/webapp/components/onboarding/OnboardingV2.tsx

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ import { GoogleIcon } from '@dailydotdev/shared/src/components/icons/Google';
3131
import { MiniCloseIcon } from '@dailydotdev/shared/src/components/icons/MiniClose';
3232
import { PhoneIcon } from '@dailydotdev/shared/src/components/icons/Phone';
3333
import { ArrowIcon } from '@dailydotdev/shared/src/components/icons/Arrow';
34+
import { EditTag } from '@dailydotdev/shared/src/components/onboarding/EditTag';
35+
import { REQUIRED_TAGS_THRESHOLD } from '@dailydotdev/shared/src/components/onboarding/common';
36+
import useFeedSettings from '@dailydotdev/shared/src/hooks/useFeedSettings';
3437
import {
3538
useViewSize,
3639
ViewSize,
@@ -145,6 +148,7 @@ export type OnboardingStep =
145148
| 'chooser'
146149
| 'auth'
147150
| 'importing'
151+
| 'tags'
148152
| 'extension'
149153
| 'complete';
150154

@@ -204,13 +208,15 @@ const FINISHING_ANIMATION_MS = 1500;
204208

205209
export const OnboardingV2 = (): ReactElement => {
206210
const router = useRouter();
207-
const { showLogin, isLoggedIn, isAuthReady, isAndroidApp } = useAuthContext();
211+
const { showLogin, isLoggedIn, isAuthReady, isAndroidApp, user } =
212+
useAuthContext();
208213
const { applyThemeMode } = useSettingsContext();
209214
const { completeAction } = useActions();
210215
const { isOnboardingComplete, isOnboardingActionsReady } =
211216
useOnboardingActions();
212217
const [step, setStep] = useState<OnboardingStep>('hero');
213218
const { onEnablePush } = usePushNotificationMutation();
219+
const { feedSettings } = useFeedSettings();
214220
const isLaptop = useViewSize(ViewSize.Laptop);
215221
const isNativeApp = isIOSNative() || !!isAndroidApp;
216222
const mobileStoreUrl = useMemo(() => {
@@ -318,10 +324,24 @@ export const OnboardingV2 = (): ReactElement => {
318324
setSignupContext(null);
319325
}
320326

327+
const hasNoTags =
328+
apiResult.status !== 'fulfilled' || !apiResult.value?.length;
329+
330+
if (hasNoTags) {
331+
setAiPrompt('');
332+
setSignupContext(null);
333+
router.replace({
334+
pathname: `${webappUrl}onboarding`,
335+
query: { step: 'tags' },
336+
});
337+
setStep('tags');
338+
return;
339+
}
340+
321341
setImportProgress(68);
322342
setImportPhase('awaitingSeniority');
323343
},
324-
[clearImportTimers, aiPrompt, setAiPrompt, setSignupContext],
344+
[clearImportTimers, aiPrompt, setAiPrompt, setSignupContext, router],
325345
);
326346

327347
const startImportFlowGithub = useCallback(() => {
@@ -415,14 +435,29 @@ export const OnboardingV2 = (): ReactElement => {
415435
if (
416436
!isAuthReady ||
417437
(
418-
['auth', 'importing', 'extension', 'complete'] as OnboardingStep[]
438+
[
439+
'auth',
440+
'importing',
441+
'tags',
442+
'extension',
443+
'complete',
444+
] as OnboardingStep[]
419445
).includes(step)
420446
) {
421447
return;
422448
}
423449

424450
const urlStep = router.query.step as string | undefined;
425451

452+
if (urlStep === 'tags') {
453+
if (!isLoggedIn) {
454+
router.replace(`${webappUrl}onboarding`);
455+
return;
456+
}
457+
setStep('tags');
458+
return;
459+
}
460+
426461
if (urlStep === 'complete') {
427462
if (!isLoggedIn) {
428463
router.replace(`${webappUrl}onboarding`);
@@ -1567,6 +1602,52 @@ export const OnboardingV2 = (): ReactElement => {
15671602
</div>
15681603
)}
15691604

1605+
{/* ── Tag Selection Fallback ── */}
1606+
{step === 'tags' && (
1607+
<div
1608+
className="fixed inset-0 z-modal flex items-end tablet:items-center tablet:justify-center tablet:p-4"
1609+
role="dialog"
1610+
aria-modal="true"
1611+
aria-label="Select your tags"
1612+
>
1613+
<div className="bg-black/70 absolute inset-0 backdrop-blur-sm" />
1614+
<div className="relative z-1 flex max-h-[90dvh] w-full flex-col overflow-y-auto rounded-t-24 border border-white/[0.08] bg-background-default p-6 shadow-[0_32px_90px_rgba(0,0,0,0.58)] tablet:max-w-2xl tablet:rounded-24">
1615+
<EditTag
1616+
feedSettings={feedSettings}
1617+
userId={user?.id || ''}
1618+
headline="Pick tags that are relevant to you"
1619+
hidePreview
1620+
/>
1621+
<button
1622+
type="button"
1623+
disabled={
1624+
(feedSettings?.includeTags?.length || 0) <
1625+
REQUIRED_TAGS_THRESHOLD
1626+
}
1627+
onClick={() => {
1628+
completeAction(ActionType.CompletedOnboarding);
1629+
completeAction(ActionType.EditTag);
1630+
completeAction(ActionType.ContentTypes);
1631+
router.replace({
1632+
pathname: `${webappUrl}onboarding`,
1633+
query: { step: 'complete' },
1634+
});
1635+
setStep(showExtensionCta ? 'extension' : 'complete');
1636+
}}
1637+
className="mx-auto mt-6 rounded-14 bg-white px-8 py-3 font-bold text-black transition-all duration-200 typo-callout hover:-translate-y-0.5 hover:shadow-[0_8px_28px_rgba(255,255,255,0.12)] disabled:cursor-not-allowed disabled:opacity-40"
1638+
>
1639+
{(feedSettings?.includeTags?.length || 0) >=
1640+
REQUIRED_TAGS_THRESHOLD
1641+
? 'Continue'
1642+
: `Select ${
1643+
REQUIRED_TAGS_THRESHOLD -
1644+
(feedSettings?.includeTags?.length || 0)
1645+
} more tags`}
1646+
</button>
1647+
</div>
1648+
</div>
1649+
)}
1650+
15701651
{/* ── Extension Promotion Overlay ── */}
15711652
{step === 'extension' && (
15721653
<div

0 commit comments

Comments
 (0)