Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: v2 of custom feeds #4028

Merged
merged 9 commits into from
Dec 31, 2024
Merged
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
145 changes: 103 additions & 42 deletions packages/shared/src/components/CustomFeedEmptyScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,114 @@
import type { ReactElement } from 'react';
import React from 'react';
import { useRouter } from 'next/router';
import {
EmptyScreenButton,
EmptyScreenContainer,
EmptyScreenDescription,
EmptyScreenIcon,
EmptyScreenTitle,
} from './EmptyScreen';
import { HashtagIcon } from './icons';
import { PageContainer } from './utilities';
import { ButtonSize } from './buttons/common';
import { EmptyScreenIcon } from './EmptyScreen';
import { DevPlusIcon, HashtagIcon } from './icons';
import { PageContainer, SharedFeedPage } from './utilities';
import { ButtonSize, ButtonVariant } from './buttons/common';
import { webappUrl } from '../lib/constants';
import {
DEFAULT_ALGORITHM_INDEX,
DEFAULT_ALGORITHM_KEY,
SearchControlHeader,
} from './layout/common';
import usePersistentContext from '../hooks/usePersistentContext';
import {
Typography,
TypographyColor,
TypographyTag,
TypographyType,
} from './typography/Typography';
import { LogEvent, TargetId } from '../lib/log';
import { Button } from './buttons/Button';
import { usePlusSubscription } from '../hooks';
import { DeleteCustomFeed } from './buttons/DeleteCustomFeed';
import { IconSize } from './Icon';

export const CustomFeedEmptyScreen = (): ReactElement => {
const { isPlus } = usePlusSubscription();
const router = useRouter();

const { logSubscriptionEvent, showPlusSubscription, isPlus } =
usePlusSubscription();
const [selectedAlgo, setSelectedAlgo] = usePersistentContext(
DEFAULT_ALGORITHM_KEY,
DEFAULT_ALGORITHM_INDEX,
[0, 1],
DEFAULT_ALGORITHM_INDEX,
);
return (
<PageContainer className="mx-auto">
<EmptyScreenContainer>
<HashtagIcon
className={EmptyScreenIcon.className}
style={EmptyScreenIcon.style}
<div className="flex w-full flex-col">
<div className="mr-auto mt-0 flex gap-3 tablet:mr-0 tablet:mt-2 laptop:mr-auto laptop:w-auto">
<SearchControlHeader
algoState={[selectedAlgo, setSelectedAlgo]}
feedName={SharedFeedPage.Custom}
/>
<EmptyScreenTitle>Let&apos;s set up your feed!</EmptyScreenTitle>
<EmptyScreenDescription>
Start by configuring your feed settings to tailor content to your
interests. Add tags, filters, and sources to make it truly yours.
</EmptyScreenDescription>
<div className="flex flex-col items-center gap-4 tablet:flex-row">
<EmptyScreenButton
onClick={() => {
router.push(`${webappUrl}feeds/${router.query.slugOrId}/edit`);
}}
size={ButtonSize.Large}
>
Set up feed
</EmptyScreenButton>
{!isPlus ? (
<DeleteCustomFeed
className="mt-10"
feedId={router.query.slugOrId as string}
/>
) : null}
</div>
<PageContainer className="mx-auto">
<div className="mt-16 flex max-h-full w-full max-w-screen-tablet flex-col items-center justify-center gap-4 px-6 text-center">
<HashtagIcon
className={EmptyScreenIcon.className}
style={EmptyScreenIcon.style}
/>
{showPlusSubscription && !isPlus ? (
<>
<Typography
tag={TypographyTag.Span}
type={TypographyType.Caption1}
className="flex gap-0.5 rounded-4 bg-action-plus-float p-0.5 pr-1"
color={TypographyColor.Plus}
>
<DevPlusIcon size={IconSize.Size16} /> Plus
</Typography>
<Typography
type={TypographyType.Title1}
color={TypographyColor.Primary}
bold
>
Custom feeds got a massive upgrade!
</Typography>
<Typography
type={TypographyType.Callout}
color={TypographyColor.Tertiary}
>
Custom Feeds is now more powerful than ever before, with
advanced filters, extensive customization options, and complete
feed control. Upgrade to Plus to unlock this ultimate tool for
tailoring your content.
</Typography>
<Button
className="mt-10"
tag="a"
type="button"
variant={ButtonVariant.Primary}
size={ButtonSize.Medium}
href={`${webappUrl}plus`}
icon={<DevPlusIcon className="text-action-plus-default" />}
onClick={() => {
logSubscriptionEvent({
event_name: LogEvent.UpgradeSubscription,
target_id: TargetId.CustomFeed,
});
}}
>
Upgrade to Plus
</Button>
</>
) : (
<>
<Typography
type={TypographyType.Title1}
color={TypographyColor.Primary}
bold
>
Your feed filters are too specific.
</Typography>
<Typography
type={TypographyType.Callout}
color={TypographyColor.Tertiary}
>
We couldn&apos;t fetch enough posts based on your selected tags.
Try adding more tags using the feed settings.
</Typography>
</>
)}
</div>
</EmptyScreenContainer>
</PageContainer>
</PageContainer>
</div>
);
};
7 changes: 1 addition & 6 deletions packages/shared/src/components/CustomFeedOptionsMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const CustomFeedOptionsMenu = ({
onUndo,
onCreateNewFeed,
}: CustomFeedOptionsMenuProps): ReactElement => {
const { showPlusSubscription, isPlus } = usePlusSubscription();
const { showPlusSubscription } = usePlusSubscription();
const { openModal } = useLazyModal();
const [, onShareOrCopyLink] = useShareOrCopyLink(shareProps);
const { isOpen, onMenuClick } = useContextMenu({
Expand All @@ -38,11 +38,6 @@ const CustomFeedOptionsMenu = ({
const { feeds } = useFeeds();

const handleOpenModal = () => {
if (!isPlus) {
return openModal({
type: LazyModal.AdvancedCustomFeedSoon,
});
}
if (feeds?.edges?.length > 0) {
return openModal({
type: LazyModal.AddToCustomFeed,
Expand Down
48 changes: 2 additions & 46 deletions packages/shared/src/components/feeds/FeedNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@ import dynamic from 'next/dynamic';
import { Tab, TabContainer } from '../tabs/TabContainer';
import { useActiveFeedNameContext } from '../../contexts';
import useActiveNav from '../../hooks/useActiveNav';
import {
useFeeds,
usePlusSubscription,
useViewSize,
ViewSize,
} from '../../hooks';
import { useFeeds, useViewSize, ViewSize } from '../../hooks';
import usePersistentContext from '../../hooks/usePersistentContext';
import {
algorithmsList,
Expand All @@ -26,14 +21,12 @@ import { PlusIcon, SortIcon } from '../icons';
import { ButtonSize, ButtonVariant } from '../buttons/common';
import { useScrollTopClassName } from '../../hooks/useScrollTopClassName';
import { useFeatureTheme } from '../../hooks/utils/useFeatureTheme';
import { customFeedsPlusDate, webappUrl } from '../../lib/constants';
import { webappUrl } from '../../lib/constants';
import NotificationsBell from '../notifications/NotificationsBell';
import classed from '../../lib/classed';
import { useAuthContext } from '../../contexts/AuthContext';
import { OtherFeedPage } from '../../lib/query';
import { ChecklistViewState } from '../../lib/checklist';
import { LazyModal } from '../modals/common/types';
import { useLazyModal } from '../../hooks/useLazyModal';
import useCustomDefaultFeed from '../../hooks/feed/useCustomDefaultFeed';

const OnboardingChecklistBar = dynamic(
Expand Down Expand Up @@ -80,8 +73,6 @@ function FeedNav(): ReactElement {
const scrollClassName = useScrollTopClassName({ enabled: !!featureTheme });
const { feeds } = useFeeds();
const { isCustomDefaultFeed, defaultFeedId } = useCustomDefaultFeed();
const { showPlusSubscription, isPlus } = usePlusSubscription();
const { openModal } = useLazyModal();

const isHiddenOnboardingChecklistView =
onboardingChecklistView === ChecklistViewState.Hidden;
Expand Down Expand Up @@ -180,41 +171,6 @@ function FeedNav(): ReactElement {

return null;
}}
onActiveChange={(label, event) => {
if (
showPlusSubscription &&
label === FeedNavTab.NewFeed &&
!isPlus
) {
event.preventDefault();

openModal({ type: LazyModal.AdvancedCustomFeedSoon, props: {} });

return false;
}

const feedNavItem = feeds?.edges?.find(
({ node }) => node.flags.name === label,
);

if (
showPlusSubscription &&
!isPlus &&
feedNavItem &&
new Date(feedNavItem.node.createdAt) > customFeedsPlusDate
) {
event.preventDefault();

openModal({
type: LazyModal.AdvancedCustomFeedSoon,
props: {},
});

return false;
}

return true;
}}
>
{Object.entries(urlToTab).map(([url, label]) => (
<Tab key={`${label}-${url}`} label={label} url={url} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ export const FeedSettingsCreate = (): ReactElement => {
const queryClient = useQueryClient();
const { displayToast } = useToastNotification();
const { logEvent } = useLogContext();
const { showPlusSubscription } = usePlusSubscription();
const [data, setData] = useState<CreateFeedProps>(() => ({
icon: '',
}));
const { createFeed } = useFeeds();
const { follow } = useContentPreference({ showToastOnSuccess: false });
const { isPlus } = usePlusSubscription();

const { onFinished, delayedRedirect, isAnimating } = useProgressAnimation({
animationMs: 1000,
Expand Down Expand Up @@ -140,16 +140,6 @@ export const FeedSettingsCreate = (): ReactElement => {
router.replace(webappUrl);
};

useEffect(() => {
if (!isPlus) {
router.replace(webappUrl);
}
}, [isPlus, router]);

if (!isPlus) {
return null;
}

return (
<Modal
isOpen
Expand All @@ -174,7 +164,7 @@ export const FeedSettingsCreate = (): ReactElement => {
>
New custom feed
</Typography>
<PlusUser />
{showPlusSubscription && <PlusUser />}
</div>
<div className="flex w-full items-center justify-between gap-2 tablet:hidden">
<Button
Expand Down
Loading
Loading