diff --git a/src/components/Author/AuthorBadge/AuthorBadge.tsx b/src/components/Author/AuthorBadge/AuthorBadge.tsx index e8730fb3..d5f7bc42 100644 --- a/src/components/Author/AuthorBadge/AuthorBadge.tsx +++ b/src/components/Author/AuthorBadge/AuthorBadge.tsx @@ -17,13 +17,14 @@ export const AuthorBadge = (props: Props) => { const [isSubscribing, setIsSubscribing] = createSignal(false) const { session, - actions: { loadSession, requireAuthentication } + subscriptions, + actions: { loadSubscriptions, requireAuthentication } } = useSession() const { t, formatDate } = useLocalize() - const subscribed = createMemo(() => { - return session()?.news?.authors?.some((u) => u === props.author.slug) || false - }) + const subscribed = createMemo(() => + subscriptions().authors.some((author) => author.slug === props.author.slug) + ) const subscribe = async (really = true) => { setIsSubscribing(true) @@ -32,7 +33,7 @@ export const AuthorBadge = (props: Props) => { ? follow({ what: FollowingEntity.Author, slug: props.author.slug }) : unfollow({ what: FollowingEntity.Author, slug: props.author.slug })) - await loadSession() + await loadSubscriptions() setIsSubscribing(false) } const handleSubscribe = (really: boolean) => { diff --git a/src/components/Author/AuthorCard/AuthorCard.tsx b/src/components/Author/AuthorCard/AuthorCard.tsx index 9ac66a04..f13082b2 100644 --- a/src/components/Author/AuthorCard/AuthorCard.tsx +++ b/src/components/Author/AuthorCard/AuthorCard.tsx @@ -50,8 +50,9 @@ export const AuthorCard = (props: Props) => { const { t, lang } = useLocalize() const { session, + subscriptions, isSessionLoaded, - actions: { loadSession, requireAuthentication } + actions: { loadSubscriptions, requireAuthentication } } = useSession() const [isSubscribing, setIsSubscribing] = createSignal(false) @@ -59,9 +60,9 @@ export const AuthorCard = (props: Props) => { const [subscriptionFilter, setSubscriptionFilter] = createSignal('all') const [userpicUrl, setUserpicUrl] = createSignal() - const subscribed = createMemo(() => { - return session()?.news?.authors?.some((u) => u === props.author.slug) || false - }) + const subscribed = createMemo(() => + subscriptions().authors.some((author) => author.slug === props.author.slug) + ) const subscribe = async (really = true) => { setIsSubscribing(true) @@ -70,7 +71,7 @@ export const AuthorCard = (props: Props) => { ? follow({ what: FollowingEntity.Author, slug: props.author.slug }) : unfollow({ what: FollowingEntity.Author, slug: props.author.slug })) - await loadSession() + await loadSubscriptions() setIsSubscribing(false) } diff --git a/src/components/Feed/Sidebar/Sidebar.tsx b/src/components/Feed/Sidebar/Sidebar.tsx index 070c8c99..21b0bbe7 100644 --- a/src/components/Feed/Sidebar/Sidebar.tsx +++ b/src/components/Feed/Sidebar/Sidebar.tsx @@ -20,7 +20,7 @@ type FeedSidebarProps = { export const Sidebar = (props: FeedSidebarProps) => { const { t } = useLocalize() const { seen } = useSeenStore() - const { session } = useSession() + const { subscriptions } = useSession() const { page } = useRouter() const { authorEntities } = useAuthorsStore({ authors: props.authors }) const { articlesByTopic } = useArticlesStore() @@ -118,7 +118,7 @@ export const Sidebar = (props: FeedSidebarProps) => { - + 0 || subscriptions().topics.length > 0}>

{ @@ -129,39 +129,31 @@ export const Sidebar = (props: FeedSidebarProps) => {

    - - {(authorSlug: string) => ( + + {(author) => (
  • - - - - - - - {authorEntities()[authorSlug]?.name} + + {author.name}
  • )}
    - - {(topicSlug: string) => ( + + {(topic) => (
  • - {topicEntities()[topicSlug]?.title ?? topicSlug} + {topic.title}
  • diff --git a/src/components/Nav/HeaderAuth.tsx b/src/components/Nav/HeaderAuth.tsx index 8668c093..7a6f4d2a 100644 --- a/src/components/Nav/HeaderAuth.tsx +++ b/src/components/Nav/HeaderAuth.tsx @@ -186,12 +186,8 @@ export const HeaderAuth = (props: Props) => { {/*FIXME: replace with route*/}
    - - + +
    diff --git a/src/components/Topic/Card.tsx b/src/components/Topic/Card.tsx index 6f05aac4..4a073238 100644 --- a/src/components/Topic/Card.tsx +++ b/src/components/Topic/Card.tsx @@ -34,19 +34,15 @@ interface TopicProps { export const TopicCard = (props: TopicProps) => { const { t } = useLocalize() const { - session, + subscriptions, isSessionLoaded, - actions: { loadSession, requireAuthentication } + actions: { loadSubscriptions, requireAuthentication } } = useSession() const [isSubscribing, setIsSubscribing] = createSignal(false) const subscribed = createMemo(() => { - if (!session()?.user?.slug || !session()?.news?.topics) { - return false - } - - return session()?.news.topics.includes(props.topic.slug) + return subscriptions().topics.some((topic) => topic.slug === props.topic.slug) }) const subscribe = async (really = true) => { @@ -56,7 +52,7 @@ export const TopicCard = (props: TopicProps) => { ? follow({ what: FollowingEntity.Topic, slug: props.topic.slug }) : unfollow({ what: FollowingEntity.Topic, slug: props.topic.slug })) - await loadSession() + await loadSubscriptions() setIsSubscribing(false) } diff --git a/src/components/Topic/Full.tsx b/src/components/Topic/Full.tsx index 279efe68..0c512497 100644 --- a/src/components/Topic/Full.tsx +++ b/src/components/Topic/Full.tsx @@ -14,11 +14,15 @@ type Props = { export const FullTopic = (props: Props) => { const { - session, + subscriptions, actions: { requireAuthentication } } = useSession() + const { t } = useLocalize() - const subscribed = createMemo(() => session()?.news?.topics?.includes(props.topic?.slug)) + + const subscribed = createMemo(() => + subscriptions().topics.some((topic) => topic.slug === props.topic?.slug) + ) const handleSubscribe = (isFollowed: boolean) => { requireAuthentication(() => { diff --git a/src/components/Topic/TopicBadge/TopicBadge.tsx b/src/components/Topic/TopicBadge/TopicBadge.tsx index b7fc5d66..a96f34e8 100644 --- a/src/components/Topic/TopicBadge/TopicBadge.tsx +++ b/src/components/Topic/TopicBadge/TopicBadge.tsx @@ -19,17 +19,13 @@ export const TopicBadge = (props: Props) => { const { t } = useLocalize() const { isAuthenticated, - session, - actions: { loadSession } + subscriptions, + actions: { loadSubscriptions } } = useSession() - const subscribed = createMemo(() => { - if (!session()?.user?.slug || !session()?.news?.topics) { - return false - } - - return session()?.news.topics.includes(props.topic.slug) - }) + const subscribed = createMemo(() => + subscriptions().topics.some((topic) => topic.slug === props.topic.slug) + ) const subscribe = async (really = true) => { setIsSubscribing(true) @@ -38,7 +34,7 @@ export const TopicBadge = (props: Props) => { ? follow({ what: FollowingEntity.Topic, slug: props.topic.slug }) : unfollow({ what: FollowingEntity.Topic, slug: props.topic.slug })) - await loadSession() + await loadSubscriptions() setIsSubscribing(false) } diff --git a/src/components/Views/AllAuthors.tsx b/src/components/Views/AllAuthors.tsx index 0949167b..b33c1621 100644 --- a/src/components/Views/AllAuthors.tsx +++ b/src/components/Views/AllAuthors.tsx @@ -35,7 +35,7 @@ export const AllAuthorsView = (props: AllAuthorsViewProps) => { const [searchQuery, setSearchQuery] = createSignal('') - const { session } = useSession() + const { session, subscriptions } = useSession() onMount(() => { if (!searchParams().by) { @@ -72,7 +72,8 @@ export const AllAuthorsView = (props: AllAuthorsViewProps) => { return keys }) - const subscribed = (s) => Boolean(session()?.news?.authors && session()?.news?.authors?.includes(s || '')) + const subscribed = (authorSlug: string) => + subscriptions().authors.some((author) => author.slug === authorSlug) const filteredAuthors = createMemo(() => { return dummyFilter(sortedAuthors(), searchQuery(), lang()) diff --git a/src/components/Views/AllTopics.tsx b/src/components/Views/AllTopics.tsx index f9c16bc2..5ef4de47 100644 --- a/src/components/Views/AllTopics.tsx +++ b/src/components/Views/AllTopics.tsx @@ -34,7 +34,7 @@ export const AllTopicsView = (props: AllTopicsViewProps) => { sortBy: searchParams().by || 'shouts' }) - const { session } = useSession() + const { session, subscriptions } = useSession() onMount(() => { if (!searchParams().by) { @@ -68,7 +68,7 @@ export const AllTopicsView = (props: AllTopicsViewProps) => { return keys }) - const subscribed = (s) => Boolean(session()?.news?.topics && session()?.news?.topics?.includes(s || '')) + const subscribed = (topicSlug: string) => subscriptions().topics.some((topic) => topic.slug === topicSlug) const showMore = () => setLimit((oldLimit) => oldLimit + PAGE_SIZE) const [searchQuery, setSearchQuery] = createSignal('') diff --git a/src/context/session.tsx b/src/context/session.tsx index 965ba955..b505613d 100644 --- a/src/context/session.tsx +++ b/src/context/session.tsx @@ -8,7 +8,7 @@ import { onMount, useContext } from 'solid-js' -import type { AuthResult, User } from '../graphql/types.gen' +import type { AuthResult, MySubscriptionsQueryResult, User } from '../graphql/types.gen' import { apiClient } from '../utils/apiClient' import { resetToken, setToken } from '../graphql/privateGraphQLClient' import { useSnackbar } from './snackbar' @@ -19,10 +19,12 @@ import type { AuthModalSource } from '../components/Nav/AuthModal/types' type SessionContextType = { session: Resource isSessionLoaded: Accessor + subscriptions: Accessor user: Accessor isAuthenticated: Accessor actions: { loadSession: () => AuthResult | Promise + loadSubscriptions: () => Promise requireAuthentication: ( callback: (() => Promise) | (() => void), modalSource: AuthModalSource @@ -41,6 +43,10 @@ export function useSession() { export const SessionProvider = (props: { children: JSX.Element }) => { const [isSessionLoaded, setIsSessionLoaded] = createSignal(false) + const [subscriptions, setSubscriptions] = createSignal({ + topics: [], + authors: [] + }) const { t } = useLocalize() const { actions: { showSnackbar } @@ -53,6 +59,7 @@ export const SessionProvider = (props: { children: JSX.Element }) => { return null } setToken(authResult.token) + loadSubscriptions() return authResult } catch (error) { console.error('getSession error:', error) @@ -63,6 +70,11 @@ export const SessionProvider = (props: { children: JSX.Element }) => { } } + const loadSubscriptions = async (): Promise => { + const result = await apiClient.getMySubscriptions() + setSubscriptions(result) + } + const [session, { refetch: loadSession, mutate }] = createResource(getSession, { ssrLoadFrom: 'initial', initialValue: null @@ -76,7 +88,8 @@ export const SessionProvider = (props: { children: JSX.Element }) => { const authResult = await apiClient.authLogin({ email, password }) setToken(authResult.token) mutate(authResult) - console.debug('signed in') + loadSubscriptions() + // console.debug('signed in') } const [isAuthWithCallback, setIsAuthWithCallback] = createSignal(null) @@ -119,10 +132,18 @@ export const SessionProvider = (props: { children: JSX.Element }) => { requireAuthentication, signIn, signOut, - confirmEmail + confirmEmail, + loadSubscriptions } - const value: SessionContextType = { session, isSessionLoaded, user, isAuthenticated, actions } + const value: SessionContextType = { + session, + subscriptions, + isSessionLoaded, + user, + isAuthenticated, + actions + } onMount(() => { loadSession() diff --git a/src/graphql/mutation/auth-confirm-email.ts b/src/graphql/mutation/auth-confirm-email.ts index f2286e3d..2bedd5bb 100644 --- a/src/graphql/mutation/auth-confirm-email.ts +++ b/src/graphql/mutation/auth-confirm-email.ts @@ -14,13 +14,6 @@ export default gql` userpic links } - news { - unread - topics - authors - reactions - communities - } } } ` diff --git a/src/graphql/mutation/my-session.ts b/src/graphql/mutation/my-session.ts index d2972be3..77c5ba48 100644 --- a/src/graphql/mutation/my-session.ts +++ b/src/graphql/mutation/my-session.ts @@ -13,13 +13,6 @@ export default gql` userpic links } - news { - unread - topics - authors - reactions - # communities - } } } ` diff --git a/src/graphql/query/my-subscriptions.ts b/src/graphql/query/my-subscriptions.ts new file mode 100644 index 00000000..589275ed --- /dev/null +++ b/src/graphql/query/my-subscriptions.ts @@ -0,0 +1,21 @@ +import { gql } from '@urql/core' + +export default gql` + query MySubscriptionsQuery { + loadMySubscriptions { + topics { + id + title + body + slug + } + authors { + id + name + slug + userpic + createdAt + } + } + } +` diff --git a/src/graphql/types.gen.ts b/src/graphql/types.gen.ts index 67dcd2ac..dee75532 100644 --- a/src/graphql/types.gen.ts +++ b/src/graphql/types.gen.ts @@ -16,7 +16,6 @@ export type Scalars = { export type AuthResult = { error?: Maybe - news?: Maybe token?: Maybe user?: Maybe } @@ -302,6 +301,11 @@ export type MutationUpdateTopicArgs = { input: TopicInput } +export type MySubscriptionsQueryResult = { + authors: Array> + topics: Array> +} + export type Notification = { createdAt: Scalars['DateTime'] data?: Maybe @@ -357,6 +361,7 @@ export type Query = { loadChats: Result loadDrafts: Array> loadMessagesBy: Result + loadMySubscriptions?: Maybe loadNotifications: NotificationsQueryResult loadReactionsBy: Array> loadRecipients: Result @@ -690,11 +695,3 @@ export type User = { username: Scalars['String'] userpic?: Maybe } - -export type UserFollowings = { - authors?: Maybe>> - communities?: Maybe>> - reactions?: Maybe>> - topics?: Maybe>> - unread?: Maybe -} diff --git a/src/utils/apiClient.ts b/src/utils/apiClient.ts index f639cf24..134d4658 100644 --- a/src/utils/apiClient.ts +++ b/src/utils/apiClient.ts @@ -17,7 +17,8 @@ import type { ReactionBy, Shout, NotificationsQueryParams, - NotificationsQueryResult + NotificationsQueryResult, + MySubscriptionsQueryResult } from '../graphql/types.gen' import { publicGraphQLClient } from '../graphql/publicGraphQLClient' import { getToken, privateGraphQLClient } from '../graphql/privateGraphQLClient' @@ -58,6 +59,7 @@ import updateArticle from '../graphql/mutation/article-update' import deleteShout from '../graphql/mutation/article-delete' import notifications from '../graphql/query/notifications' import markNotificationAsRead from '../graphql/mutation/mark-notification-as-read' +import mySubscriptions from '../graphql/query/my-subscriptions' type ApiErrorCode = | 'unknown' @@ -366,6 +368,12 @@ export const apiClient = { .toPromise() }, + getMySubscriptions: async (): Promise => { + const resp = await privateGraphQLClient.query(mySubscriptions, {}).toPromise() + // console.debug(resp.data) + return resp.data.loadMySubscriptions + }, + // inbox getChats: async (options: QueryLoadChatsArgs): Promise => { const resp = await privateGraphQLClient.query(myChats, options).toPromise()