From cf0214563d94f0bc80ef0fb17eb8791463d88e74 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 17:48:58 +0300 Subject: [PATCH] use-following-data-2 --- package.json | 2 +- .../Author/AuthorCard/AuthorCard.tsx | 281 ++++++++------ src/components/Views/Author/Author.tsx | 354 ++++++++++++------ .../ProfileSubscriptions.tsx | 141 ++++--- 4 files changed, 493 insertions(+), 285 deletions(-) diff --git a/package.json b/package.json index 5e79d11f..1da95480 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "hygen": "HYGEN_TMPLS=gen hygen", "postinstall": "npm run codegen && npx patch-package", "check:code": "npx @biomejs/biome check src --log-kind=compact --verbose", - "check:code:fix": "npx @biomejs/biome check src --log-kind=compact --verbose --apply-unsafe", + "check:code:fix": "npx @biomejs/biome check src --log-kind=compact", "lint": "npm run lint:code && stylelint **/*.{scss,css}", "lint:code": "npx @biomejs/biome lint src --log-kind=compact --verbose", "lint:code:fix": "npx @biomejs/biome lint src --apply-unsafe --log-kind=compact --verbose", diff --git a/src/components/Author/AuthorCard/AuthorCard.tsx b/src/components/Author/AuthorCard/AuthorCard.tsx index 75f23639..b6054a58 100644 --- a/src/components/Author/AuthorCard/AuthorCard.tsx +++ b/src/components/Author/AuthorCard/AuthorCard.tsx @@ -1,119 +1,133 @@ -import type { Author, Community } from '../../../graphql/schema/core.gen' +import type { Author, Community } from "../../../graphql/schema/core.gen"; -import { openPage, redirectPage } from '@nanostores/router' -import { clsx } from 'clsx' -import { For, Show, createEffect, createMemo, createSignal, onMount } from 'solid-js' +import { openPage, redirectPage } from "@nanostores/router"; +import { clsx } from "clsx"; +import { + For, + Show, + createEffect, + createMemo, + createSignal, + onMount, +} from "solid-js"; -import { useFollowing } from '../../../context/following' -import { useLocalize } from '../../../context/localize' -import { useSession } from '../../../context/session' -import { FollowingEntity, Topic } from '../../../graphql/schema/core.gen' -import { SubscriptionFilter } from '../../../pages/types' -import { router, useRouter } from '../../../stores/router' -import { isAuthor } from '../../../utils/isAuthor' -import { translit } from '../../../utils/ru2en' -import { isCyrillic } from '../../../utils/translate' -import { SharePopup, getShareUrl } from '../../Article/SharePopup' -import { Modal } from '../../Nav/Modal' -import { TopicBadge } from '../../Topic/TopicBadge' -import { Button } from '../../_shared/Button' -import { ShowOnlyOnClient } from '../../_shared/ShowOnlyOnClient' -import { AuthorBadge } from '../AuthorBadge' -import { Userpic } from '../Userpic' +import { useFollowing } from "../../../context/following"; +import { useLocalize } from "../../../context/localize"; +import { useSession } from "../../../context/session"; +import { FollowingEntity, Topic } from "../../../graphql/schema/core.gen"; +import { SubscriptionFilter } from "../../../pages/types"; +import { router, useRouter } from "../../../stores/router"; +import { isAuthor } from "../../../utils/isAuthor"; +import { translit } from "../../../utils/ru2en"; +import { isCyrillic } from "../../../utils/translate"; +import { SharePopup, getShareUrl } from "../../Article/SharePopup"; +import { Modal } from "../../Nav/Modal"; +import { TopicBadge } from "../../Topic/TopicBadge"; +import { Button } from "../../_shared/Button"; +import { ShowOnlyOnClient } from "../../_shared/ShowOnlyOnClient"; +import { AuthorBadge } from "../AuthorBadge"; +import { Userpic } from "../Userpic"; -import stylesButton from '../../_shared/Button/Button.module.scss' -import styles from './AuthorCard.module.scss' +import stylesButton from "../../_shared/Button/Button.module.scss"; +import styles from "./AuthorCard.module.scss"; type Props = { - author: Author - followers?: Author[] - following?: Array -} + author: Author; + followers?: Author[]; + following?: Array; +}; export const AuthorCard = (props: Props) => { - const { t, lang } = useLocalize() - const { author, isSessionLoaded, requireAuthentication } = useSession() - const [authorSubs, setAuthorSubs] = createSignal>([]) - const [subscriptionFilter, setSubscriptionFilter] = createSignal('all') - const [isFollowed, setIsFollowed] = createSignal() - const isProfileOwner = createMemo(() => author()?.slug === props.author.slug) - const { setFollowing, isOwnerSubscribed } = useFollowing() + const { t, lang } = useLocalize(); + const { author, isSessionLoaded, requireAuthentication } = useSession(); + const [authorSubs, setAuthorSubs] = createSignal< + Array + >([]); + const [subscriptionFilter, setSubscriptionFilter] = + createSignal("all"); + const [isFollowed, setIsFollowed] = createSignal(); + const isProfileOwner = createMemo(() => author()?.slug === props.author.slug); + const { setFollowing, isOwnerSubscribed } = useFollowing(); onMount(() => { - setAuthorSubs(props.following) - }) + setAuthorSubs(props.following); + }); createEffect(() => { - setIsFollowed(isOwnerSubscribed(props.author?.id)) - }) + setIsFollowed(isOwnerSubscribed(props.author?.id)); + }); const name = createMemo(() => { - if (lang() !== 'ru' && isCyrillic(props.author.name)) { - if (props.author.name === 'Дискурс') { - return 'Discours' + if (lang() !== "ru" && isCyrillic(props.author.name)) { + if (props.author.name === "Дискурс") { + return "Discours"; } - return translit(props.author.name) + return translit(props.author.name); } - return props.author.name - }) + return props.author.name; + }); // TODO: reimplement AuthorCard - const { changeSearchParams } = useRouter() + const { changeSearchParams } = useRouter(); const initChat = () => { // eslint-disable-next-line solid/reactivity requireAuthentication(() => { - openPage(router, 'inbox') + openPage(router, "inbox"); changeSearchParams({ initChat: props.author.id.toString(), - }) - }, 'discussions') - } + }); + }, "discussions"); + }; createEffect(() => { if (props.following) { - if (subscriptionFilter() === 'authors') { - setAuthorSubs(props.following.filter((s) => 'name' in s)) - } else if (subscriptionFilter() === 'topics') { - setAuthorSubs(props.following.filter((s) => 'title' in s)) - } else if (subscriptionFilter() === 'communities') { - setAuthorSubs(props.following.filter((s) => 'title' in s)) + if (subscriptionFilter() === "authors") { + setAuthorSubs(props.following.filter((s) => "name" in s)); + } else if (subscriptionFilter() === "topics") { + setAuthorSubs(props.following.filter((s) => "title" in s)); + } else if (subscriptionFilter() === "communities") { + setAuthorSubs(props.following.filter((s) => "title" in s)); } else { - setAuthorSubs(props.following) + setAuthorSubs(props.following); } } - }) + }); const handleFollowClick = () => { - const value = !isFollowed() + const value = !isFollowed(); requireAuthentication(() => { - setIsFollowed(value) - setFollowing(FollowingEntity.Author, props.author.slug, value) - }, 'subscribe') - } + setIsFollowed(value); + setFollowing(FollowingEntity.Author, props.author.slug, value); + }, "subscribe"); + }; const followButtonText = createMemo(() => { if (isOwnerSubscribed(props.author?.id)) { return ( <> - {t('Following')} - {t('Unfollow')} + + {t("Following")} + + + {t("Unfollow")} + - ) + ); } - return t('Follow') - }) + return t("Follow"); + }); return ( -
+
-
+
{name()}
@@ -130,11 +144,18 @@ export const AuthorCard = (props: Props) => { {(f) => ( - + )}
- {t('SubscriberWithCount', { count: props.followers.length ?? 0 })} + {t("SubscriberWithCount", { + count: props.followers.length ?? 0, + })}
@@ -143,33 +164,35 @@ export const AuthorCard = (props: Props) => { {(f) => { - if ('name' in f) { + if ("name" in f) { return ( - ) + ); } - if ('title' in f) { + if ("title" in f) { return ( - ) + ); } - return null + return null; }}
- {t('SubscriptionWithCount', { count: props?.following.length ?? 0 })} + {t("SubscriptionWithCount", { + count: props?.following.length ?? 0, + })}
@@ -184,12 +207,12 @@ export const AuthorCard = (props: Props) => { {(link) => ( - {link.startsWith('http') ? link : `https://${link}`} + {link.startsWith("http") ? link : `https://${link}`} )} @@ -211,8 +234,8 @@ export const AuthorCard = (props: Props) => { />
- + <> -

{t('Followers')}

+

{t("Followers")}

@@ -266,30 +300,61 @@ export const AuthorCard = (props: Props) => { - + <> -

{t('Subscriptions')}

+

{t("Subscriptions")}

    -
  • - - {props.following.length} -
  • -
  • - - {props.following.filter((s) => 'name' in s).length} + {props.following.length}
  • -
  • - - {props.following.filter((s) => 'title' in s).length} + {props.following.filter((s) => "name" in s).length} + +
  • +
  • + + + {props.following.filter((s) => "title" in s).length}
@@ -326,5 +391,5 @@ export const AuthorCard = (props: Props) => {
- ) -} + ); +}; diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 719f7b48..9a6c12fd 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -1,162 +1,197 @@ -import type { Author, Reaction, Shout, Topic } from '../../../graphql/schema/core.gen' +import type { + Author, + Reaction, + Shout, + Topic, +} from "../../../graphql/schema/core.gen"; -import { getPagePath } from '@nanostores/router' -import { Meta, Title } from '@solidjs/meta' -import { clsx } from 'clsx' -import { For, Match, Show, Switch, createEffect, createMemo, createSignal, onMount } from 'solid-js' +import { getPagePath } from "@nanostores/router"; +import { Meta, Title } from "@solidjs/meta"; +import { clsx } from "clsx"; +import { + For, + Match, + Show, + Switch, + createEffect, + createMemo, + createSignal, + onMount, +} from "solid-js"; -import { useFollowing } from '../../../context/following' -import { useLocalize } from '../../../context/localize' -import { apiClient } from '../../../graphql/client/core' -import { router, useRouter } from '../../../stores/router' -import { loadShouts, useArticlesStore } from '../../../stores/zine/articles' -import { loadAuthor, useAuthorsStore } from '../../../stores/zine/authors' -import { getImageUrl } from '../../../utils/getImageUrl' -import { getDescription } from '../../../utils/meta' -import { restoreScrollPosition, saveScrollPosition } from '../../../utils/scroll' -import { splitToPages } from '../../../utils/splitToPages' -import { Comment } from '../../Article/Comment' -import { AuthorCard } from '../../Author/AuthorCard' -import { AuthorShoutsRating } from '../../Author/AuthorShoutsRating' -import { Row1 } from '../../Feed/Row1' -import { Row2 } from '../../Feed/Row2' -import { Row3 } from '../../Feed/Row3' -import { Loading } from '../../_shared/Loading' +import { useFollowing } from "../../../context/following"; +import { useLocalize } from "../../../context/localize"; +import { useSession } from "../../../context/session"; +import { apiClient } from "../../../graphql/client/core"; +import { router, useRouter } from "../../../stores/router"; +import { loadShouts, useArticlesStore } from "../../../stores/zine/articles"; +import { loadAuthor, useAuthorsStore } from "../../../stores/zine/authors"; +import { getImageUrl } from "../../../utils/getImageUrl"; +import { getDescription } from "../../../utils/meta"; +import { + restoreScrollPosition, + saveScrollPosition, +} from "../../../utils/scroll"; +import { splitToPages } from "../../../utils/splitToPages"; +import { Comment } from "../../Article/Comment"; +import { AuthorCard } from "../../Author/AuthorCard"; +import { AuthorShoutsRating } from "../../Author/AuthorShoutsRating"; +import { Row1 } from "../../Feed/Row1"; +import { Row2 } from "../../Feed/Row2"; +import { Row3 } from "../../Feed/Row3"; +import { Loading } from "../../_shared/Loading"; -import { MODALS, hideModal } from '../../../stores/ui' -import { byCreated } from '../../../utils/sortby' -import stylesArticle from '../../Article/Article.module.scss' -import styles from './Author.module.scss' +import { MODALS, hideModal } from "../../../stores/ui"; +import { byCreated } from "../../../utils/sortby"; +import stylesArticle from "../../Article/Article.module.scss"; +import styles from "./Author.module.scss"; type Props = { - authorSlug: string -} -export const PRERENDERED_ARTICLES_COUNT = 12 -const LOAD_MORE_PAGE_SIZE = 9 + authorSlug: string; + shouts?: Shout[]; + author?: Author; +}; +export const PRERENDERED_ARTICLES_COUNT = 12; +const LOAD_MORE_PAGE_SIZE = 9; export const AuthorView = (props: Props) => { - const { t } = useLocalize() - const { subscriptions, followers, loadSubscriptions } = useFollowing() - const { session } = useSession() - const { sortedArticles } = useArticlesStore({ shouts: props.shouts }) - const { authorEntities } = useAuthorsStore({ authors: [props.author] }) - const { page: getPage, searchParams } = useRouter() - const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = createSignal(false) - const [isBioExpanded, setIsBioExpanded] = createSignal(false) - const [author, setAuthor] = createSignal() - const [following, setFollowing] = createSignal>([]) - const [showExpandBioControl, setShowExpandBioControl] = createSignal(false) - const [commented, setCommented] = createSignal() - const modal = MODALS[searchParams().m] + const { t } = useLocalize(); + const { + subscriptions, + followers: myFollowers, + loadSubscriptions, + } = useFollowing(); + const { session } = useSession(); + const { sortedArticles } = useArticlesStore({ shouts: props.shouts }); + const { authorEntities } = useAuthorsStore({ authors: [props.author] }); + const { page: getPage, searchParams } = useRouter(); + const [isLoadMoreButtonVisible, setIsLoadMoreButtonVisible] = + createSignal(false); + const [isBioExpanded, setIsBioExpanded] = createSignal(false); + const [author, setAuthor] = createSignal(); + const [followers, setFollowers] = createSignal([]); + const [following, setFollowing] = createSignal>([]); // flat AuthorFollowsResult + const [showExpandBioControl, setShowExpandBioControl] = createSignal(false); + const [commented, setCommented] = createSignal(); + const modal = MODALS[searchParams().m]; // current author createEffect(() => { if (props.authorSlug) { if (session()?.user?.app_data?.profile?.slug === props.authorSlug) { - console.info('my own profile') - const { profile, authors, topics } = session().user.app_data - setAuthor(profile) - setFollowing([...authors, ...topics]) + console.info("my own profile"); + const { profile, authors, topics } = session().user.app_data; + setFollowers(myFollowers); + setAuthor(profile); + setFollowing([...authors, ...topics]); } } else { try { - const a = authorEntities()[props.authorSlug] - setAuthor(a) - console.debug('[Author] expecting following data fetched') + const a = authorEntities()[props.authorSlug]; + setAuthor(a); + // TODO: add following data retrieval + console.debug("[Author] expecting following data fetched"); } catch (error) { - console.debug(error) + console.debug(error); } } - }) + }); createEffect(async () => { if (author()?.id && !author().stat) { - const a = await loadAuthor({ slug: '', author_id: author().id }) - console.debug('[AuthorView] loaded author:', a) + const a = await loadAuthor({ slug: "", author_id: author().id }); + console.debug("[AuthorView] loaded author:", a); } - }) + }); - const bioContainerRef: { current: HTMLDivElement } = { current: null } - const bioWrapperRef: { current: HTMLDivElement } = { current: null } + const bioContainerRef: { current: HTMLDivElement } = { current: null }; + const bioWrapperRef: { current: HTMLDivElement } = { current: null }; const fetchData = async (slug) => { try { const [subscriptionsResult, followersResult] = await Promise.all([ apiClient.getAuthorFollows({ slug }), apiClient.getAuthorFollowers({ slug }), - ]) + ]); - const { authors, topics } = subscriptionsResult - setFollowing([...(authors || []), ...(topics || [])]) - setFollowers(followersResult || []) + const { authors, topics } = subscriptionsResult; + setFollowing([...(authors || []), ...(topics || [])]); + setFollowers(followersResult || []); - console.info('[components.Author] following data loaded') + console.info("[components.Author] following data loaded"); } catch (error) { - console.error('[components.Author] fetch error', error) + console.error("[components.Author] fetch error", error); } - } + }; const checkBioHeight = () => { if (bioContainerRef.current) { - setShowExpandBioControl(bioContainerRef.current.offsetHeight > bioWrapperRef.current.offsetHeight) + setShowExpandBioControl( + bioContainerRef.current.offsetHeight > + bioWrapperRef.current.offsetHeight, + ); } - } + }; onMount(() => { - fetchData(props.authorSlug) + fetchData(props.authorSlug); if (!modal) { - hideModal() + hideModal(); } - }) + }); const loadMore = async () => { - saveScrollPosition() + saveScrollPosition(); const { hasMore } = await loadShouts({ filters: { author: props.authorSlug }, limit: LOAD_MORE_PAGE_SIZE, offset: sortedArticles().length, - }) - setIsLoadMoreButtonVisible(hasMore) - restoreScrollPosition() - } + }); + setIsLoadMoreButtonVisible(hasMore); + restoreScrollPosition(); + }; onMount(() => { - checkBioHeight() + checkBioHeight(); // pagination if (sortedArticles().length === PRERENDERED_ARTICLES_COUNT) { - loadMore() - loadSubscriptions() + loadMore(); + loadSubscriptions(); } - }) + }); const pages = createMemo(() => - splitToPages(sortedArticles(), PRERENDERED_ARTICLES_COUNT, LOAD_MORE_PAGE_SIZE), - ) + splitToPages( + sortedArticles(), + PRERENDERED_ARTICLES_COUNT, + LOAD_MORE_PAGE_SIZE, + ), + ); const fetchComments = async (commenter: Author) => { const data = await apiClient.getReactionsBy({ by: { comment: false, created_by: commenter.id }, - }) - setCommented(data) - } + }); + setCommented(data); + }; createEffect(() => { if (author()) { - fetchComments(author()) + fetchComments(author()); } - }) + }); const ogImage = createMemo(() => author()?.pic ? getImageUrl(author()?.pic, { width: 1200 }) - : getImageUrl('production/image/logo_image.png'), - ) - const description = createMemo(() => getDescription(author()?.bio)) + : getImageUrl("production/image/logo_image.png"), + ); + const description = createMemo(() => getDescription(author()?.bio)); const handleDeleteComment = (id: number) => { - setCommented((prev) => prev.filter((comment) => comment.id !== id)) - } + setCommented((prev) => prev.filter((comment) => comment.id !== id)); + }; return (
@@ -176,42 +211,80 @@ export const AuthorView = (props: Props) => { }> <>
- +
-
+
-
- +
+
- {t('All posts rating')} - + {t("All posts rating")} +
@@ -221,7 +294,7 @@ export const AuthorView = (props: Props) => {
- +
@@ -230,22 +303,28 @@ export const AuthorView = (props: Props) => { class={styles.longBio} classList={{ [styles.longBioExpanded]: isBioExpanded() }} > -
(bioContainerRef.current = el)} innerHTML={author().about} /> +
(bioContainerRef.current = el)} + innerHTML={author().about} + />
- +
@@ -265,13 +344,18 @@ export const AuthorView = (props: Props) => {
- + - + @@ -280,21 +364,45 @@ export const AuthorView = (props: Props) => { 3}> - + - + - + {(page) => ( <> - + - + - + )} @@ -303,12 +411,12 @@ export const AuthorView = (props: Props) => {

- ) -} + ); +}; diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index 083e7978..d4db7857 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -1,59 +1,60 @@ -import { clsx } from 'clsx' -import { For, Show, createEffect, createSignal, onMount } from 'solid-js' +import { clsx } from "clsx"; +import { For, Show, createEffect, createSignal, onMount } from "solid-js"; -import { useFollowing } from '../../../context/following' -import { useLocalize } from '../../../context/localize' -import { useSession } from '../../../context/session' -import { apiClient } from '../../../graphql/client/core' -import { Author as AuthorType, Topic } from '../../../graphql/schema/core.gen' -import { SubscriptionFilter } from '../../../pages/types' -import { dummyFilter } from '../../../utils/dummyFilter' +import { useFollowing } from "../../../context/following"; +import { useLocalize } from "../../../context/localize"; +import { useSession } from "../../../context/session"; +import { apiClient } from "../../../graphql/client/core"; +import { Author, Topic } from "../../../graphql/schema/core.gen"; +import { SubscriptionFilter } from "../../../pages/types"; +import { dummyFilter } from "../../../utils/dummyFilter"; // TODO: refactor styles -import { isAuthor } from '../../../utils/isAuthor' -import { AuthorBadge } from '../../Author/AuthorBadge' -import { ProfileSettingsNavigation } from '../../Nav/ProfileSettingsNavigation' -import { TopicBadge } from '../../Topic/TopicBadge' -import { Loading } from '../../_shared/Loading' -import { SearchField } from '../../_shared/SearchField' +import { isAuthor } from "../../../utils/isAuthor"; +import { AuthorBadge } from "../../Author/AuthorBadge"; +import { ProfileSettingsNavigation } from "../../Nav/ProfileSettingsNavigation"; +import { TopicBadge } from "../../Topic/TopicBadge"; +import { Loading } from "../../_shared/Loading"; +import { SearchField } from "../../_shared/SearchField"; -import styles from '../../../pages/profile/Settings.module.scss' -import stylesSettings from '../../../styles/FeedSettings.module.scss' +import styles from "../../../pages/profile/Settings.module.scss"; +import stylesSettings from "../../../styles/FeedSettings.module.scss"; export const ProfileSubscriptions = () => { - const { t, lang } = useLocalize() - const { author, session } = useSession() - const { subscriptions } = useFollowing() - const [following, setFollowing] = (createSignal < Array < AuthorType) | (Topic >> []) - const [filtered, setFiltered] = (createSignal < Array < AuthorType) | (Topic >> []) - const [subscriptionFilter, setSubscriptionFilter] = createSignal < SubscriptionFilter > 'all' - const [searchQuery, setSearchQuery] = createSignal('') + const { t, lang } = useLocalize(); + const { author, session } = useSession(); + const { subscriptions } = useFollowing(); + const [following, setFollowing] = createSignal>([]); + const [filtered, setFiltered] = createSignal>([]); + const [subscriptionFilter, setSubscriptionFilter] = + createSignal("all"); + const [searchQuery, setSearchQuery] = createSignal(""); createEffect(() => { - const { authors, topics } = subscriptions + const { authors, topics } = subscriptions; if (authors || topics) { - const fdata = [...(authors || []), ...(topics || [])] - setFollowing(fdata) - if (subscriptionFilter() === 'authors') { - setFiltered(fdata.filter((s) => 'name' in s)) - } else if (subscriptionFilter() === 'topics') { - setFiltered(fdata.filter((s) => 'title' in s)) + const fdata = [...(authors || []), ...(topics || [])]; + setFollowing(fdata); + if (subscriptionFilter() === "authors") { + setFiltered(fdata.filter((s) => "name" in s)); + } else if (subscriptionFilter() === "topics") { + setFiltered(fdata.filter((s) => "title" in s)); } else { - setFiltered(fdata) + setFiltered(fdata); } } - }) + }); createEffect(() => { if (searchQuery()) { - setFiltered(dummyFilter(following(), searchQuery(), lang())) + setFiltered(dummyFilter(following(), searchQuery(), lang())); } - }) + }); return (
-
+
@@ -61,28 +62,54 @@ export const ProfileSubscriptions = () => {
-

{t('My subscriptions')}

-

{t('Here you can manage all your Discours subscriptions')}

+

{t("My subscriptions")}

+

+ {t("Here you can manage all your Discours subscriptions")} +

}>
    -
  • -
  • -
  • -
  • -
  • -
-
+
setSearchQuery(value)} class={styles.searchField} @@ -90,14 +117,22 @@ export const ProfileSubscriptions = () => { />
-
+
{(followingItem) => (
{isAuthor(followingItem) ? ( - + ) : ( - + )}
)} @@ -109,5 +144,5 @@ export const ProfileSubscriptions = () => {
- ) -} + ); +};