From 58c4d6eae7748cadcc1ab14747c5bf49ed349513 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 15:49:40 +0300 Subject: [PATCH 1/6] app-data-author --- src/components/Views/Author/Author.tsx | 26 +++++++++++----- .../ProfileSubscriptions.tsx | 30 ++++++++----------- src/context/following.tsx | 15 ++++++++-- src/context/session.tsx | 14 +++++++-- 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index a21cebcc..efd1bb73 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -38,26 +38,36 @@ const LOAD_MORE_PAGE_SIZE = 9 export const AuthorView = (props: Props) => { const { t } = useLocalize() - const { loadSubscriptions } = useFollowing() + const { subscriptions, followers } = 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 [followers, setFollowers] = createSignal([]) + const [author, setAuthor] = createSignal() const [following, setFollowing] = createSignal>([]) const [showExpandBioControl, setShowExpandBioControl] = createSignal(false) const [commented, setCommented] = createSignal() const modal = MODALS[searchParams().m] // current author - const [author, setAuthor] = createSignal() createEffect(() => { - try { - const a = authorEntities()[props.authorSlug] - setAuthor(a) - } catch (error) { - console.debug(error) + 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]) + } + } else { + try { + const a = authorEntities()[props.authorSlug] + setAuthor(a) + console.debug('[Author] expecting following data fetched') + } catch (error) { + console.debug(error) + } } }) diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index 6e1b4d8d..82fe575a 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -1,6 +1,7 @@ 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' @@ -20,23 +21,20 @@ import stylesSettings from '../../../styles/FeedSettings.module.scss' export const ProfileSubscriptions = () => { const { t, lang } = useLocalize() - const { author } = useSession() - const [following, setFollowing] = createSignal>([]) - const [filtered, setFiltered] = createSignal>([]) - const [subscriptionFilter, setSubscriptionFilter] = createSignal('all') + const { author, session } = useSession() + const { subscriptions } = useFollowing() + const [following, setFollowing] = (createSignal < Array < Author) | (Topic >> []) + const [filtered, setFiltered] = (createSignal < Array < Author) | (Topic >> []) + const [subscriptionFilter, setSubscriptionFilter] = createSignal < SubscriptionFilter > 'all' const [searchQuery, setSearchQuery] = createSignal('') - const fetchSubscriptions = async () => { - try { - const slug = author()?.slug - const authorFollows = await apiClient.getAuthorFollows({ slug }) - setFollowing([...authorFollows['authors']]) - setFiltered([...authorFollows['authors'], ...authorFollows['topics']]) - } catch (error) { - console.error('[fetchSubscriptions] :', error) - throw error + createEffect(() => { + if (subscriptions()) { + const { authors, topics } = subscriptions() + setFollowing([...authors, ...topics]) + setFiltered([...authors, ...topics]) } - } + }) createEffect(() => { if (following()) { @@ -53,10 +51,6 @@ export const ProfileSubscriptions = () => { } }) - onMount(async () => { - await fetchSubscriptions() - }) - return (
diff --git a/src/context/following.tsx b/src/context/following.tsx index f3208ca9..6ee4621e 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -2,12 +2,13 @@ import { Accessor, JSX, createContext, createEffect, createSignal, useContext } import { createStore } from 'solid-js/store' import { apiClient } from '../graphql/client/core' -import { AuthorFollows, FollowingEntity } from '../graphql/schema/core.gen' +import { AuthorFollows, FollowingEntity, Author } from '../graphql/schema/core.gen' import { useSession } from './session' interface FollowingContextType { loading: Accessor + followers: Accessor> subscriptions: AuthorFollows setSubscriptions: (subscriptions: AuthorFollows) => void setFollowing: (what: FollowingEntity, slug: string, value: boolean) => void @@ -31,6 +32,7 @@ const EMPTY_SUBSCRIPTIONS: AuthorFollows = { export const FollowingProvider = (props: { children: JSX.Element }) => { const [loading, setLoading] = createSignal(false) + const [followers, setFollowers] = createSignal>([]) const [subscriptions, setSubscriptions] = createStore(EMPTY_SUBSCRIPTIONS) const { author, session } = useSession() @@ -77,8 +79,14 @@ export const FollowingProvider = (props: { children: JSX.Element }) => { createEffect(() => { if (author()) { - console.debug('[context.following] author update detect') - fetchData() + try { + const { authors, followers, topics } = session().user.app_data + setSubscriptions({ authors, topics }) + setFollowers(followers) + if(!authors) fetchData() + } catch(e) { + console.error(e) + } } }) @@ -116,6 +124,7 @@ export const FollowingProvider = (props: { children: JSX.Element }) => { setSubscriptions, isOwnerSubscribed, setFollowing, + followers, loadSubscriptions: fetchData, follow, unfollow, diff --git a/src/context/session.tsx b/src/context/session.tsx index 73659a6c..aba1ace5 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -199,6 +199,7 @@ export const SessionProvider = (props: { } onCleanup(() => clearTimeout(minuteLater)) + const authorData = async () => { const u = session()?.user return u ? (await apiClient.getAuthorId({ user: u.id.trim() })) || null : null @@ -217,7 +218,15 @@ export const SessionProvider = (props: { apiClient.connect(token) inboxClient.connect(token) } - if (!author()) loadAuthor() + + try { + const { profile } = session().user.app_data + setAuthor(profile) + addAuthors([profile]) + if(!profile) loadAuthor() + } catch(e) { + console.error(e) + } setIsSessionLoaded(true) } @@ -262,8 +271,7 @@ export const SessionProvider = (props: { () => props.onStateChangeCallback, () => { props.onStateChangeCallback(session()) - }, - { defer: true }, + } ), ) From 6d12b01d561b80a02a26c8f942152d5098d8e20e Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 15:54:01 +0300 Subject: [PATCH 2/6] author-type-fix --- src/components/Views/Author/Author.tsx | 4 ++-- .../ProfileSubscriptions.tsx | 6 +++--- src/context/following.tsx | 6 +++--- src/context/session.tsx | 6 +++--- src/utils/getImageUrl.ts | 20 +++++++++---------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index efd1bb73..e2de6c1f 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -53,10 +53,10 @@ export const AuthorView = (props: Props) => { // current author createEffect(() => { - if(props.authorSlug) { + 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 + const { profile, authors, topics } = session().user.app_data setAuthor(profile) setFollowing([...authors, ...topics]) } diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index 82fe575a..cab28884 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -5,7 +5,7 @@ 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 { Author as AuthorType, Topic } from '../../../graphql/schema/core.gen' import { SubscriptionFilter } from '../../../pages/types' import { dummyFilter } from '../../../utils/dummyFilter' // TODO: refactor styles @@ -23,8 +23,8 @@ export const ProfileSubscriptions = () => { const { t, lang } = useLocalize() const { author, session } = useSession() const { subscriptions } = useFollowing() - const [following, setFollowing] = (createSignal < Array < Author) | (Topic >> []) - const [filtered, setFiltered] = (createSignal < Array < Author) | (Topic >> []) + const [following, setFollowing] = (createSignal < Array < AuthorType) | (Topic >> []) + const [filtered, setFiltered] = (createSignal < Array < AuthorType) | (Topic >> []) const [subscriptionFilter, setSubscriptionFilter] = createSignal < SubscriptionFilter > 'all' const [searchQuery, setSearchQuery] = createSignal('') diff --git a/src/context/following.tsx b/src/context/following.tsx index 6ee4621e..3371a010 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -2,7 +2,7 @@ import { Accessor, JSX, createContext, createEffect, createSignal, useContext } import { createStore } from 'solid-js/store' import { apiClient } from '../graphql/client/core' -import { AuthorFollows, FollowingEntity, Author } from '../graphql/schema/core.gen' +import { Author, AuthorFollows, FollowingEntity } from '../graphql/schema/core.gen' import { useSession } from './session' @@ -83,8 +83,8 @@ export const FollowingProvider = (props: { children: JSX.Element }) => { const { authors, followers, topics } = session().user.app_data setSubscriptions({ authors, topics }) setFollowers(followers) - if(!authors) fetchData() - } catch(e) { + if (!authors) fetchData() + } catch (e) { console.error(e) } } diff --git a/src/context/session.tsx b/src/context/session.tsx index aba1ace5..67bd5a93 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -223,8 +223,8 @@ export const SessionProvider = (props: { const { profile } = session().user.app_data setAuthor(profile) addAuthors([profile]) - if(!profile) loadAuthor() - } catch(e) { + if (!profile) loadAuthor() + } catch (e) { console.error(e) } @@ -271,7 +271,7 @@ export const SessionProvider = (props: { () => props.onStateChangeCallback, () => { props.onStateChangeCallback(session()) - } + }, ), ) diff --git a/src/utils/getImageUrl.ts b/src/utils/getImageUrl.ts index 7b8b56dc..bc3c9073 100644 --- a/src/utils/getImageUrl.ts +++ b/src/utils/getImageUrl.ts @@ -15,17 +15,17 @@ export const getImageUrl = ( src: string, options: { width?: number; height?: number; noSizeUrlPart?: boolean } = {}, ) => { - if (!src.includes('discours.io') && src.includes('http')) { - return src - } - const filename = src.toLowerCase().split('/').pop() - const ext = filename.split('.').pop() - const isAudio = ext in ['wav', 'mp3', 'ogg', 'aif', 'flac'] - const base = isAudio ? cdnUrl : `${thumborUrl}/unsafe/` - const suffix = isAudio || options.noSizeUrlPart ? '' : getSizeUrlPart(options) - const subfolder = isAudio ? 'audio' : 'image' + if (!src.includes('discours.io') && src.includes('http')) { + return src + } + const filename = src.toLowerCase().split('/').pop() + const ext = filename.split('.').pop() + const isAudio = ext in ['wav', 'mp3', 'ogg', 'aif', 'flac'] + const base = isAudio ? cdnUrl : `${thumborUrl}/unsafe/` + const suffix = isAudio || options.noSizeUrlPart ? '' : getSizeUrlPart(options) + const subfolder = isAudio ? 'audio' : 'image' - return `${base}${suffix}production/${subfolder}/${filename}` + return `${base}${suffix}production/${subfolder}/${filename}` } export const getOpenGraphImageUrl = ( From 79961b7f47785873bedb0882979d85e28471c7df Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 16:04:10 +0300 Subject: [PATCH 3/6] fdata-fix --- .../ProfileSubscriptions.tsx | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index cab28884..f43445f7 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -31,21 +31,21 @@ export const ProfileSubscriptions = () => { createEffect(() => { if (subscriptions()) { const { authors, topics } = subscriptions() - setFollowing([...authors, ...topics]) - setFiltered([...authors, ...topics]) + const fdata = [...authors, ...topics] + if (fdata) { + 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) + } + } } }) createEffect(() => { - if (following()) { - if (subscriptionFilter() === 'authors') { - setFiltered(following().filter((s) => 'name' in s)) - } else if (subscriptionFilter() === 'topics') { - setFiltered(following().filter((s) => 'title' in s)) - } else { - setFiltered(following()) - } - } if (searchQuery()) { setFiltered(dummyFilter(following(), searchQuery(), lang())) } From aeb42de90879a0ec6e669080bcff461a63fc85b6 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 16:14:19 +0300 Subject: [PATCH 4/6] use-following-data --- .../ProfileSubscriptions.tsx | 22 +++++++++---------- src/context/following.tsx | 4 ++-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index f43445f7..083e7978 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -29,18 +29,16 @@ export const ProfileSubscriptions = () => { const [searchQuery, setSearchQuery] = createSignal('') createEffect(() => { - if (subscriptions()) { - const { authors, topics } = subscriptions() - const fdata = [...authors, ...topics] - if (fdata) { - 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) - } + 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)) + } else { + setFiltered(fdata) } } }) diff --git a/src/context/following.tsx b/src/context/following.tsx index 6200c681..ad93eaaf 100644 --- a/src/context/following.tsx +++ b/src/context/following.tsx @@ -10,7 +10,7 @@ interface FollowingContextType { loading: Accessor followers: Accessor> subscriptions: AuthorFollowsResult - setSubscriptions: (subscriptions: AuthorFollows) => void + setSubscriptions: (subscriptions: AuthorFollowsResult) => void setFollowing: (what: FollowingEntity, slug: string, value: boolean) => void loadSubscriptions: () => void follow: (what: FollowingEntity, slug: string) => Promise @@ -33,7 +33,7 @@ const EMPTY_SUBSCRIPTIONS: AuthorFollowsResult = { export const FollowingProvider = (props: { children: JSX.Element }) => { const [loading, setLoading] = createSignal(false) const [followers, setFollowers] = createSignal>([]) - const [subscriptions, setSubscriptions] = createStore(EMPTY_SUBSCRIPTIONS) + const [subscriptions, setSubscriptions] = createStore(EMPTY_SUBSCRIPTIONS) const { author, session } = useSession() const fetchData = async () => { From cf0214563d94f0bc80ef0fb17eb8791463d88e74 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 17:48:58 +0300 Subject: [PATCH 5/6] 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 = () => {
- ) -} + ); +}; From 455006f6277be3a4e67c05ebfdf4a1e7dec663a0 Mon Sep 17 00:00:00 2001 From: Untone Date: Mon, 8 Apr 2024 18:19:43 +0300 Subject: [PATCH 6/6] fmt --- .../Author/AuthorCard/AuthorCard.tsx | 269 ++++++-------- src/components/Views/Author/Author.tsx | 336 +++++++----------- .../ProfileSubscriptions.tsx | 129 +++---- 3 files changed, 292 insertions(+), 442 deletions(-) diff --git a/src/components/Author/AuthorCard/AuthorCard.tsx b/src/components/Author/AuthorCard/AuthorCard.tsx index b6054a58..5fedd3e5 100644 --- a/src/components/Author/AuthorCard/AuthorCard.tsx +++ b/src/components/Author/AuthorCard/AuthorCard.tsx @@ -1,133 +1,119 @@ -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< - Array - >([]); - 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>([]) + 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()}
@@ -144,16 +130,11 @@ export const AuthorCard = (props: Props) => { {(f) => ( - + )}
- {t("SubscriberWithCount", { + {t('SubscriberWithCount', { count: props.followers.length ?? 0, })}
@@ -164,33 +145,33 @@ 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", { + {t('SubscriptionWithCount', { count: props?.following.length ?? 0, })}
@@ -207,12 +188,12 @@ export const AuthorCard = (props: Props) => { {(link) => (
- {link.startsWith("http") ? link : `https://${link}`} + {link.startsWith('http') ? link : `https://${link}`} )} @@ -234,8 +215,8 @@ export const AuthorCard = (props: Props) => { />
- + <> -

{t("Followers")}

+

{t('Followers')}

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

{t("Subscriptions")}

+

{t('Subscriptions')}

  • - + {props.following.length} +
  • +
  • + - {props.following.length} + {props.following.filter((s) => 'name' in s).length}
  • - - {props.following.filter((s) => "name" in s).length} - -
  • -
  • - - - {props.following.filter((s) => "title" in s).length} + {props.following.filter((s) => 'title' in s).length}
@@ -391,5 +344,5 @@ export const AuthorCard = (props: Props) => {
- ); -}; + ) +} diff --git a/src/components/Views/Author/Author.tsx b/src/components/Views/Author/Author.tsx index 9a6c12fd..0c6a958a 100644 --- a/src/components/Views/Author/Author.tsx +++ b/src/components/Views/Author/Author.tsx @@ -1,197 +1,168 @@ -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 { 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 { 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; - shouts?: Shout[]; - author?: Author; -}; -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: 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]; + 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; - setFollowers(myFollowers); - 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); + const a = authorEntities()[props.authorSlug] + setAuthor(a) // TODO: add following data retrieval - console.debug("[Author] expecting following data fetched"); + 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 (
@@ -211,80 +182,64 @@ export const AuthorView = (props: Props) => { }> <>
- +
-
+
-
- +
+
- {t("All posts rating")} - + {t('All posts rating')} +
@@ -294,7 +249,7 @@ export const AuthorView = (props: Props) => {
- +
@@ -303,28 +258,22 @@ export const AuthorView = (props: Props) => { class={styles.longBio} classList={{ [styles.longBioExpanded]: isBioExpanded() }} > -
(bioContainerRef.current = el)} - innerHTML={author().about} - /> +
(bioContainerRef.current = el)} innerHTML={author().about} />
- +
@@ -344,18 +293,13 @@ export const AuthorView = (props: Props) => {
- + - + @@ -364,45 +308,21 @@ export const AuthorView = (props: Props) => { 3}> - + - + - + {(page) => ( <> - + - + - + )} @@ -411,12 +331,12 @@ export const AuthorView = (props: Props) => {

- ); -}; + ) +} diff --git a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx index d4db7857..51f27325 100644 --- a/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx +++ b/src/components/Views/ProfileSubscriptions/ProfileSubscriptions.tsx @@ -1,60 +1,59 @@ -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, 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>([]); - const [filtered, setFiltered] = createSignal>([]); - const [subscriptionFilter, setSubscriptionFilter] = - createSignal("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 (
-
+
@@ -62,54 +61,40 @@ 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} @@ -117,22 +102,14 @@ export const ProfileSubscriptions = () => { />
-
+
{(followingItem) => (
{isAuthor(followingItem) ? ( - + ) : ( - + )}
)} @@ -144,5 +121,5 @@ export const ProfileSubscriptions = () => {
- ); -}; + ) +}