From 6b2cadfcb63f84c4ecdf62d288c63fcccfb9785d Mon Sep 17 00:00:00 2001 From: ilya-bkv Date: Thu, 8 Feb 2024 12:11:52 +0300 Subject: [PATCH] Fix topic subscriptions status --- biome.json | 4 +- .../Author/AuthorBadge/AuthorBadge.tsx | 5 +- .../Author/AuthorCard/AuthorCard.tsx | 8 +- .../Topic/TopicBadge/TopicBadge.module.scss | 40 +++++- .../Topic/TopicBadge/TopicBadge.tsx | 121 ++++++++++-------- .../{ => AllTopics}/AllTopics.module.scss | 39 ------ .../Views/{ => AllTopics}/AllTopics.tsx | 55 ++++---- src/components/Views/AllTopics/index.ts | 1 + src/components/Views/Author/Author.tsx | 1 - src/context/following.tsx | 10 +- src/pages/allTopics.page.tsx | 4 +- src/pages/types.ts | 5 + 12 files changed, 154 insertions(+), 139 deletions(-) rename src/components/Views/{ => AllTopics}/AllTopics.module.scss (67%) rename src/components/Views/{ => AllTopics}/AllTopics.tsx (80%) create mode 100644 src/components/Views/AllTopics/index.ts diff --git a/biome.json b/biome.json index 6861f822..ba7464a5 100644 --- a/biome.json +++ b/biome.json @@ -2,7 +2,7 @@ "$schema": "https://biomejs.dev/schemas/1.5.3/schema.json", "files": { "include": ["*.tsx", "*.ts", "*.js", "*.json"], - "ignore": ["./dist", "./node_modules", ".husky", "docs", "gen"] + "ignore": ["./dist", "./node_modules", ".husky", "docs", "gen", "*.d.ts"] }, "vcs": { "defaultBranch": "dev", @@ -29,7 +29,7 @@ } }, "linter": { - "ignore": ["*.scss", "*.md", ".DS_Store", "*.svg"], + "ignore": ["*.scss", "*.md", ".DS_Store", "*.svg", "*.d.ts"], "enabled": true, "rules": { "all": true, diff --git a/src/components/Author/AuthorBadge/AuthorBadge.tsx b/src/components/Author/AuthorBadge/AuthorBadge.tsx index 35537140..8b7107ef 100644 --- a/src/components/Author/AuthorBadge/AuthorBadge.tsx +++ b/src/components/Author/AuthorBadge/AuthorBadge.tsx @@ -16,13 +16,10 @@ import { ConditionalWrapper } from '../../_shared/ConditionalWrapper' import { Icon } from '../../_shared/Icon' import { Userpic } from '../Userpic' +import { FollowedInfo } from '../../../pages/types' import stylesButton from '../../_shared/Button/Button.module.scss' import styles from './AuthorBadge.module.scss' -type FollowedInfo = { - value?: boolean - loaded?: boolean -} type Props = { author: Author minimizeSubscribeButton?: boolean diff --git a/src/components/Author/AuthorCard/AuthorCard.tsx b/src/components/Author/AuthorCard/AuthorCard.tsx index 9fa25a8e..75f23639 100644 --- a/src/components/Author/AuthorCard/AuthorCard.tsx +++ b/src/components/Author/AuthorCard/AuthorCard.tsx @@ -308,7 +308,13 @@ export const AuthorCard = (props: Props) => { author={subscription} /> ) : ( - + ) } diff --git a/src/components/Topic/TopicBadge/TopicBadge.module.scss b/src/components/Topic/TopicBadge/TopicBadge.module.scss index e5166ef1..3f9d8436 100644 --- a/src/components/Topic/TopicBadge/TopicBadge.module.scss +++ b/src/components/Topic/TopicBadge/TopicBadge.module.scss @@ -1,10 +1,13 @@ .TopicBadge { - display: flex; - flex-direction: row; - align-items: flex-start; margin-bottom: 2rem; gap: 1rem; + .content { + align-items: flex-start; + display: flex; + flex-direction: row; + margin-bottom: .8rem; + } .basicInfo { display: flex; flex-flow: row nowrap; @@ -78,3 +81,34 @@ width: 9em; } } + +.stats { + @include font-size(1.5rem); + + color: var(--secondary-color); + display: flex; + margin: 0 0 1em; + + @include media-breakpoint-down(md) { + flex-wrap: wrap; + } + + @include media-breakpoint-down(sm) { + margin-top: 0.5em; + } + + .statsItem { + @include font-size(1.4rem); + + margin-right: 1.6rem; + white-space: nowrap; + + &:last-child { + margin-right: 0; + } + + &.followers { + word-break: keep-all; + } + } +} diff --git a/src/components/Topic/TopicBadge/TopicBadge.tsx b/src/components/Topic/TopicBadge/TopicBadge.tsx index 3006fb79..a4ccd348 100644 --- a/src/components/Topic/TopicBadge/TopicBadge.tsx +++ b/src/components/Topic/TopicBadge/TopicBadge.tsx @@ -1,5 +1,5 @@ import { clsx } from 'clsx' -import { Show, createEffect, createSignal } from 'solid-js' +import { Show, createEffect, createSignal, on } from 'solid-js' import { useFollowing } from '../../../context/following' import { useLocalize } from '../../../context/localize' @@ -11,11 +11,14 @@ import { getImageUrl } from '../../../utils/getImageUrl' import { Button } from '../../_shared/Button' import { CheckButton } from '../../_shared/CheckButton' +import { FollowedInfo } from '../../../pages/types' import styles from './TopicBadge.module.scss' type Props = { topic: Topic minimizeSubscribeButton?: boolean + isFollowed?: FollowedInfo + showStat?: boolean } export const TopicBadge = (props: Props) => { @@ -24,12 +27,12 @@ export const TopicBadge = (props: Props) => { const [isMobileView, setIsMobileView] = createSignal(false) const { requireAuthentication } = useSession() const { setFollowing, loading: subLoading } = useFollowing() - const [followed, setFollowed] = createSignal() + const [isFollowed, setIsFollowed] = createSignal() const handleFollowClick = () => { - const value = !followed() + const value = !isFollowed() requireAuthentication(() => { - setFollowed(value) + setIsFollowed(value) setFollowing(FollowingEntity.Topic, props.topic.slug, value) }, 'subscribe') } @@ -38,67 +41,85 @@ export const TopicBadge = (props: Props) => { setIsMobileView(!mediaMatches.sm) }) + createEffect( + on( + () => props.isFollowed, + () => { + setIsFollowed(props.isFollowed.value) + }, + ), + ) + const title = () => lang() === 'en' ? capitalize(props.topic.slug.replaceAll('-', ' ')) : props.topic.title return (
- + +
- {t('PublicationsWithCount', { count: props.topic.stat.shouts ?? 0 })} -
+ } > -
{props.topic.body}
- - -
- -
- - } - > - + } + >
+ +
+ {t('shoutsWithCount', { count: props.topic?.stat?.shouts })} + {t('authorsWithCount', { count: props.topic?.stat?.authors })} + + {t('followersWithCount', { count: props.topic?.stat?.followers })} +
) diff --git a/src/components/Views/AllTopics.module.scss b/src/components/Views/AllTopics/AllTopics.module.scss similarity index 67% rename from src/components/Views/AllTopics.module.scss rename to src/components/Views/AllTopics/AllTopics.module.scss index 1793d81b..cb4bb1d5 100644 --- a/src/components/Views/AllTopics.module.scss +++ b/src/components/Views/AllTopics/AllTopics.module.scss @@ -32,45 +32,6 @@ } } -.stats { - @include font-size(1.7rem); - - color: #9fa1a7; - display: flex; - margin: 0 0 1em; - - @include media-breakpoint-down(md) { - flex-wrap: wrap; - } - - @include media-breakpoint-down(sm) { - margin-top: 0.5em; - } - - .statsItem { - @include font-size(1.5rem); - - margin-right: 1.6rem; - white-space: nowrap; - - &:last-child { - margin-right: 0; - } - - &.compact { - font-size: small; - } - - &.followers { - word-break: keep-all; - } - - &.button { - float: right; - } - } -} - .loadMoreContainer { margin-top: 48px; text-align: center; diff --git a/src/components/Views/AllTopics.tsx b/src/components/Views/AllTopics/AllTopics.tsx similarity index 80% rename from src/components/Views/AllTopics.tsx rename to src/components/Views/AllTopics/AllTopics.tsx index bf8f57ee..36548a33 100644 --- a/src/components/Views/AllTopics.tsx +++ b/src/components/Views/AllTopics/AllTopics.tsx @@ -1,21 +1,22 @@ -import type { Topic } from '../../graphql/schema/core.gen' +import type { Topic } from '../../../graphql/schema/core.gen' import { Meta } from '@solidjs/meta' import { clsx } from 'clsx' import { For, Show, createEffect, createMemo, createSignal } from 'solid-js' -import { useFollowing } from '../../context/following' -import { useLocalize } from '../../context/localize' -import { useRouter } from '../../stores/router' -import { setTopicsSort, useTopicsStore } from '../../stores/zine/topics' -import { capitalize } from '../../utils/capitalize' -import { dummyFilter } from '../../utils/dummyFilter' -import { getImageUrl } from '../../utils/getImageUrl' -import { scrollHandler } from '../../utils/scroll' -import { TopicCard } from '../Topic/Card' -import { Loading } from '../_shared/Loading' -import { SearchField } from '../_shared/SearchField' +import { useFollowing } from '../../../context/following' +import { useLocalize } from '../../../context/localize' +import { useRouter } from '../../../stores/router' +import { setTopicsSort, useTopicsStore } from '../../../stores/zine/topics' +import { capitalize } from '../../../utils/capitalize' +import { dummyFilter } from '../../../utils/dummyFilter' +import { getImageUrl } from '../../../utils/getImageUrl' +import { scrollHandler } from '../../../utils/scroll' +import { TopicCard } from '../../Topic/Card' +import { Loading } from '../../_shared/Loading' +import { SearchField } from '../../_shared/SearchField' +import { TopicBadge } from '../../Topic/TopicBadge' import styles from './AllTopics.module.scss' type AllTopicsPageSearchParams = { @@ -29,7 +30,7 @@ type Props = { const PAGE_SIZE = 20 -export const AllTopicsView = (props: Props) => { +export const AllTopics = (props: Props) => { const { t, lang } = useLocalize() const { searchParams, changeSearchParams } = useRouter() const [limit, setLimit] = createSignal(PAGE_SIZE) @@ -41,8 +42,6 @@ export const AllTopicsView = (props: Props) => { sortBy: searchParams().by || 'shouts', }) - const { subscriptions } = useFollowing() - createEffect(() => { if (!searchParams().by) { changeSearchParams({ @@ -76,7 +75,7 @@ export const AllTopicsView = (props: Props) => { return keys }) - const subscribed = (topicSlug: string) => subscriptions.topics.some((topic) => topic.slug === topicSlug) + const { isOwnerSubscribed } = useFollowing() const showMore = () => setLimit((oldLimit) => oldLimit + PAGE_SIZE) const [searchQuery, setSearchQuery] = createSignal('') @@ -186,28 +185,18 @@ export const AllTopicsView = (props: Props) => {
-
+
{(topic) => ( <> - 0, + value: isOwnerSubscribed(topic.slug), + }} + showStat={true} /> -
- - {t('shoutsWithCount', { count: topic.stat.shouts })} - - - {t('authorsWithCount', { count: topic.stat.authors })} - - - {t('followersWithCount', { count: topic.stat.followers })} - -
)}
diff --git a/src/components/Views/AllTopics/index.ts b/src/components/Views/AllTopics/index.ts new file mode 100644 index 00000000..8e3c8f84 --- /dev/null +++ b/src/components/Views/AllTopics/index.ts @@ -0,0 +1 @@ +export { AllTopics } from './AllTopics' diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 1d8d8f7b..bb62322c 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -128,7 +128,6 @@ export const AuthorView = (props: Props) => { const data = await apiClient.getReactionsBy({ by: { comment: false, created_by: commenter.id }, }) - console.debug('[components.Author] fetched comments', data) setCommented(data) } diff --git a/src/context/following.tsx b/src/context/following.tsx index 599b30a0..b7a5ab0d 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -20,7 +20,7 @@ interface FollowingContextType { loadSubscriptions: () => void follow: (what: FollowingEntity, slug: string) => Promise unfollow: (what: FollowingEntity, slug: string) => Promise - isOwnerSubscribed: (userId: number) => boolean + isOwnerSubscribed: (id: number | string) => boolean } const FollowingContext = createContext() @@ -109,9 +109,11 @@ export const FollowingProvider = (props: { children: JSX.Element }) => { } } - const isOwnerSubscribed = (userId: number) => { - if (!author()) return - return !!subscriptions?.authors?.some((authorEntity) => authorEntity.id === userId) + const isOwnerSubscribed = (id?: number | string) => { + if (!author() || !subscriptions) return + const isAuthorSubscribed = subscriptions.authors?.some((authorEntity) => authorEntity.id === id) + const isTopicSubscribed = subscriptions.topics?.some((topicEntity) => topicEntity.slug === id) + return !!isAuthorSubscribed || !!isTopicSubscribed } const value: FollowingContextType = { diff --git a/src/pages/allTopics.page.tsx b/src/pages/allTopics.page.tsx index fa2daa37..49d54626 100644 --- a/src/pages/allTopics.page.tsx +++ b/src/pages/allTopics.page.tsx @@ -2,7 +2,7 @@ import type { PageProps } from './types' import { createSignal, onMount } from 'solid-js' -import { AllTopicsView } from '../components/Views/AllTopics' +import { AllTopics } from '../components/Views/AllTopics' import { PageLayout } from '../components/_shared/PageLayout' import { useLocalize } from '../context/localize' import { loadAllTopics } from '../stores/zine/topics' @@ -23,7 +23,7 @@ export const AllTopicsPage = (props: PageProps) => { return ( - + ) } diff --git a/src/pages/types.ts b/src/pages/types.ts index b36a7612..05fd3f61 100644 --- a/src/pages/types.ts +++ b/src/pages/types.ts @@ -50,4 +50,9 @@ export type UploadedFile = { originalFilename?: string } +export type FollowedInfo = { + value?: boolean + loaded?: boolean +} + export type SubscriptionFilter = 'all' | 'authors' | 'topics' | 'communities'