prefixed-queries

This commit is contained in:
Untone 2023-12-14 02:56:44 +03:00
parent 9d93ee0a6c
commit dfbbb075e8
14 changed files with 81 additions and 54 deletions

View File

@ -25,7 +25,7 @@ type Props = {
export const AuthorBadge = (props: Props) => { export const AuthorBadge = (props: Props) => {
const [isSubscribing, setIsSubscribing] = createSignal(false) const [isSubscribing, setIsSubscribing] = createSignal(false)
const { const {
session, author,
subscriptions, subscriptions,
actions: { loadSubscriptions, requireAuthentication }, actions: { loadSubscriptions, requireAuthentication },
} = useSession() } = useSession()
@ -96,7 +96,7 @@ export const AuthorBadge = (props: Props) => {
</Show> </Show>
</a> </a>
</div> </div>
<Show when={props.author.slug !== session()?.user.slug && !props.nameOnly}> <Show when={props.author.slug !== author()?.slug && !props.nameOnly}>
<div class={styles.actions}> <div class={styles.actions}>
<Show <Show
when={!props.minimizeSubscribeButton} when={!props.minimizeSubscribeButton}

View File

@ -32,7 +32,6 @@ type Props = {
export const AuthorCard = (props: Props) => { export const AuthorCard = (props: Props) => {
const { t, lang } = useLocalize() const { t, lang } = useLocalize()
const { const {
session,
author, author,
subscriptions, subscriptions,
isSessionLoaded, isSessionLoaded,

View File

@ -32,7 +32,7 @@ const MD_WIDTH_BREAKPOINT = 992
export const HeaderAuth = (props: Props) => { export const HeaderAuth = (props: Props) => {
const { t } = useLocalize() const { t } = useLocalize()
const { page } = useRouter() const { page } = useRouter()
const { author, session, isSessionLoaded, isAuthenticated } = useSession() const { author, isAuthenticated, isSessionLoaded } = useSession()
const { const {
unreadNotificationsCount, unreadNotificationsCount,
actions: { showNotificationsPanel }, actions: { showNotificationsPanel },
@ -147,7 +147,7 @@ export const HeaderAuth = (props: Props) => {
</div> </div>
</Show> </Show>
<Show when={!session()}> <Show when={!author()}>
<div class={styles.userControlItem} onClick={handleBellIconClick}> <div class={styles.userControlItem} onClick={handleBellIconClick}>
<div class={styles.button}> <div class={styles.button}>
<Icon name="bell-white" counter={1} class={styles.icon} /> <Icon name="bell-white" counter={1} class={styles.icon} />

View File

@ -13,7 +13,7 @@ type ProfilePopupProps = Omit<PopupProps, 'children'>
export const ProfilePopup = (props: ProfilePopupProps) => { export const ProfilePopup = (props: ProfilePopupProps) => {
const { const {
user, author,
actions: { signOut }, actions: { signOut },
} = useSession() } = useSession()
@ -23,18 +23,18 @@ export const ProfilePopup = (props: ProfilePopupProps) => {
<Popup {...props} horizontalAnchor="right" variant="bordered"> <Popup {...props} horizontalAnchor="right" variant="bordered">
<ul class="nodash"> <ul class="nodash">
<li> <li>
<a href={getPagePath(router, 'author', { slug: user().slug })}>{t('Profile')}</a> <a href={getPagePath(router, 'author', { slug: author().slug })}>{t('Profile')}</a>
</li> </li>
<li> <li>
<a href={getPagePath(router, 'drafts')}>{t('Drafts')}</a> <a href={getPagePath(router, 'drafts')}>{t('Drafts')}</a>
</li> </li>
<li> <li>
<a href={`${getPagePath(router, 'author', { slug: user().slug })}?modal=following`}> <a href={`${getPagePath(router, 'author', { slug: author().slug })}?modal=following`}>
{t('Subscriptions')} {t('Subscriptions')}
</a> </a>
</li> </li>
<li> <li>
<a href={`${getPagePath(router, 'authorComments', { slug: user().slug })}`}>{t('Comments')}</a> <a href={`${getPagePath(router, 'authorComments', { slug: author().slug })}`}>{t('Comments')}</a>
</li> </li>
<li> <li>
<a href="#">{t('Bookmarks')}</a> <a href="#">{t('Bookmarks')}</a>

View File

@ -177,18 +177,18 @@ export const ProfileSettings = () => {
<h4>{t('Userpic')}</h4> <h4>{t('Userpic')}</h4>
<div class="pretty-form__item"> <div class="pretty-form__item">
<div <div
class={clsx(styles.userpic, { [styles.hasControls]: form.userpic })} class={clsx(styles.userpic, { [styles.hasControls]: form.pic })}
onClick={!form.userpic && handleUploadAvatar} onClick={!form.pic && handleUploadAvatar}
> >
<Switch> <Switch>
<Match when={isUserpicUpdating()}> <Match when={isUserpicUpdating()}>
<Loading /> <Loading />
</Match> </Match>
<Match when={form.userpic}> <Match when={form.pic}>
<div <div
class={styles.userpicImage} class={styles.userpicImage}
style={{ style={{
'background-image': `url(${getImageUrl(form.userpic, { 'background-image': `url(${getImageUrl(form.pic, {
width: 180, width: 180,
height: 180, height: 180,
})})`, })})`,
@ -200,7 +200,7 @@ export const ProfileSettings = () => {
<button <button
ref={triggerRef} ref={triggerRef}
class={styles.control} class={styles.control}
onClick={() => updateFormField('userpic', '')} onClick={() => updateFormField('pic', '')}
> >
<Icon name="close" /> <Icon name="close" />
</button> </button>
@ -219,7 +219,7 @@ export const ProfileSettings = () => {
</Popover> </Popover>
</div> </div>
</Match> </Match>
<Match when={!form.userpic}> <Match when={!form.pic}>
<Icon name="user-image-gray" /> <Icon name="user-image-gray" />
{t('Here you can upload your photo')} {t('Here you can upload your photo')}
</Match> </Match>

View File

@ -39,13 +39,14 @@ export const ConnectProvider = (props: { children: JSX.Element }) => {
} }
const [retried, setRetried] = createSignal<number>(0) const [retried, setRetried] = createSignal<number>(0)
const listen = () => { const listen = () => {
if (isAuthenticated() && !connected() && retried() < 4) { const token = getToken()
try { console.log(`[context.connect] token: ${token}`)
if (token && !connected() && retried() < 4) {
fetchEventSource('https://connect.discours.io', { fetchEventSource('https://connect.discours.io', {
method: 'GET', method: 'GET',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
Authorization: getToken(), Authorization: token,
}, },
onmessage(event) { onmessage(event) {
const m: SSEMessage = JSON.parse(event.data) const m: SSEMessage = JSON.parse(event.data)
@ -60,17 +61,11 @@ export const ConnectProvider = (props: { children: JSX.Element }) => {
}, },
onerror(err) { onerror(err) {
console.error('[context.connect] sse connection error', err) console.error('[context.connect] sse connection error', err)
setRetried((r) => r + 1)
setConnected(false) setConnected(false)
throw new Error(err) // NOTE: simple hack to close the connection throw new Error(err) // NOTE: simple hack to close the connection
}, },
}) })
} catch (err) {
if (retried() < 4) {
setRetried((r) => r + 1)
} else {
console.warn('Not trying to reconnect anymore; listen() should be called again.')
}
}
} }
} }

View File

@ -10,6 +10,7 @@ import { notifierClient } from '../graphql/client/notifier'
import { Notification } from '../graphql/schema/notifier.gen' import { Notification } from '../graphql/schema/notifier.gen'
import { SSEMessage, useConnect } from './connect' import { SSEMessage, useConnect } from './connect'
import { useSession } from './session'
type NotificationsContextType = { type NotificationsContextType = {
notificationEntities: Record<number, Notification> notificationEntities: Record<number, Notification>
@ -38,12 +39,13 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
const [unreadNotificationsCount, setUnreadNotificationsCount] = createSignal(0) const [unreadNotificationsCount, setUnreadNotificationsCount] = createSignal(0)
const [totalNotificationsCount, setTotalNotificationsCount] = createSignal(0) const [totalNotificationsCount, setTotalNotificationsCount] = createSignal(0)
const [notificationEntities, setNotificationEntities] = createStore<Record<number, Notification>>({}) const [notificationEntities, setNotificationEntities] = createStore<Record<number, Notification>>({})
const { isAuthenticated } = useSession()
const apiClient = createMemo(() => { const apiClient = createMemo(() => {
if (!notifierClient.private) notifierClient.connect() if (!notifierClient.private && isAuthenticated()) notifierClient.connect()
return notifierClient return notifierClient
}) })
const { addHandler } = useConnect() const { addHandler } = useConnect()
const loadNotifications = async (options: { limit: number; offset?: number }) => { const loadNotifications = async (options: { limit?: number; offset?: number }) => {
const { notifications, unread, total } = await apiClient().getNotifications(options) const { notifications, unread, total } = await apiClient().getNotifications(options)
const newNotificationEntities = notifications.reduce((acc, notification) => { const newNotificationEntities = notifications.reduce((acc, notification) => {
acc[notification.id] = notification acc[notification.id] = notification

View File

@ -101,7 +101,7 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
async () => { async () => {
const u = session()?.user const u = session()?.user
if (u) { if (u) {
return (await apiClient.getAuthor({ user: u.id })) ?? null return (await apiClient.getAuthorId({ user: u.id })) ?? null
} }
return null return null
}, },

View File

@ -29,6 +29,7 @@ import draftsLoad from '../query/core/articles-load-drafts'
import myFeed from '../query/core/articles-load-feed' import myFeed from '../query/core/articles-load-feed'
import shoutsLoadSearch from '../query/core/articles-load-search' import shoutsLoadSearch from '../query/core/articles-load-search'
import authorBy from '../query/core/author-by' import authorBy from '../query/core/author-by'
import authorId from '../query/core/author-id'
import authorFollowers from '../query/core/author-followers' import authorFollowers from '../query/core/author-followers'
import authorsAll from '../query/core/authors-all' import authorsAll from '../query/core/authors-all'
import authorFollowed from '../query/core/authors-followed-by' import authorFollowed from '../query/core/authors-followed-by'
@ -79,10 +80,14 @@ export const apiClient = {
} }
return response.data.load_authors_all return response.data.load_authors_all
}, },
getAuthor: async (params: { slug?: string; author_id?: number; user?: string }): Promise<Author> => { getAuthor: async (params: { slug?: string; author_id?: number }): Promise<Author> => {
const response = await publicGraphQLClient.query(authorBy, params).toPromise() const response = await publicGraphQLClient.query(authorBy, params).toPromise()
return response.data.get_author return response.data.get_author
}, },
getAuthorId: async (params: { user: string }): Promise<Author> => {
const response = await publicGraphQLClient.query(authorId, params).toPromise()
return response.data.get_author_id
},
getAuthorFollowers: async ({ slug }: { slug: string }): Promise<Author[]> => { getAuthorFollowers: async ({ slug }: { slug: string }): Promise<Author[]> => {
const response = await publicGraphQLClient.query(authorFollowers, { slug }).toPromise() const response = await publicGraphQLClient.query(authorFollowers, { slug }).toPromise()
return response.data.get_author_followers return response.data.get_author_followers

View File

@ -1,8 +1,8 @@
import { gql } from '@urql/core' import { gql } from '@urql/core'
export default gql` export default gql`
query GetAuthorBy($slug: String, $author_id: Int, $user: String) { query GetAuthorBy($slug: String, $author_id: Int) {
get_author(slug: $slug, author_id: $author_id, user: $user) { get_author(slug: $slug, author_id: $author_id) {
id id
slug slug
name name

View File

@ -0,0 +1,17 @@
import { gql } from '@urql/core'
export default gql`
query GetAuthorId($user: String!) {
get_author_id(user: $user) {
id
slug
name
bio
about
pic
links
created_at
last_seen
}
}
`

View File

@ -0,0 +1,9 @@
{
"query": "query ValidateToken($params: ValidateJWTTokenInput!) { validate_jwt_token(params: $params) { is_valid claims } }",
"variables": {
"params": {
"token_type": "access_token",
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhbGxvd2VkX3JvbGVzIjpbInJlYWRlciJdLCJhdWQiOiI5YzExMzM3Ny01ZWVhLTRjODktOThlMS02OTMwMjQ2MmZjMDgiLCJleHAiOjE3MDI1MDM3NDksImlhdCI6MTcwMjUwMTk0OSwiaXNzIjoiaHR0cHM6Ly9hdXRoLmRpc2NvdXJzLmlvIiwibG9naW5fbWV0aG9kIjoiYmFzaWNfYXV0aCIsIm5vbmNlIjoiNTNhZmE1NzMtMWZhMC00NDNhLTk4NzktNWE0ZDk3YTQ1OWEzIiwicm9sZXMiOlsicmVhZGVyIl0sInNjb3BlIjpbIm9wZW5pZCIsImVtYWlsIiwicHJvZmlsZSJdLCJzdWIiOiIyNDU3NTc5Yi0yNTk3LTQzNjMtOGU1MC00YWM5ZjY5YzgyMWQiLCJ0b2tlbl90eXBlIjoiYWNjZXNzX3Rva2VuIn0.ImAmAFXkwReYhLvLR1GG3g0mDllQaj7NVWw5q9D7EFUHtpjuNOanlVfzoaqqB6CXkc_uSRlrfiaLkbfCzhbXAWpi49vOI9P2fvLv-41Y0p8FJZnruZDi1c8psyPU5gpCLp3nqtBTTIR2IP-Uu_1oYo2Hl02xdOFjVHw19f-WEf73L6APBPppNeE21IJJy8aU5uXBHv12Y--kH5tEzn83BNBKPm5yWay-k4DVuBnAJt_ODENqm5NAaiG-q2eG3GnXWpjgpDXf0cxVXdtJbvFcPIv-pH7Dm6ae8m4xM7MmVmpzCE5f-Qc1lwcfX51Cr6IMXUjHx0N3n54sKk91CPa_ug"
}
}
}

View File

@ -1,13 +1,13 @@
import { gql } from '@urql/core' import { gql } from '@urql/core'
export default gql` export default gql`
query LoadNotificationsQuery($params: NotificationsQueryParams!) { query LoadNotificationsQuery($limit: Int, $offset: Int) {
load_notifications(params: $params) { load_notifications(limit: $limit, offset: $offset) {
notifications { notifications {
id id
entity entity
action action
paylaod payload
created_at created_at
seen seen
} }