forget-fix-graphql-client-fix
This commit is contained in:
parent
3353004f48
commit
fce7ffb972
|
@ -259,6 +259,7 @@
|
||||||
"Pin": "Закрепить",
|
"Pin": "Закрепить",
|
||||||
"Platform Guide": "Гид по дискурсу",
|
"Platform Guide": "Гид по дискурсу",
|
||||||
"Please check your email address": "Пожалуйста, проверьте введенный адрес почты",
|
"Please check your email address": "Пожалуйста, проверьте введенный адрес почты",
|
||||||
|
"Please check your inbox! We have sent a password reset link.": "Пожалуйста, проверьте ваш адрес почты, мы отправили ссылку для сброса пароля",
|
||||||
"Please confirm your email to finish": "Подтвердите почту и действие совершится",
|
"Please confirm your email to finish": "Подтвердите почту и действие совершится",
|
||||||
"Please enter a name to sign your comments and publication": "Пожалуйста, введите имя, которое будет отображаться на сайте",
|
"Please enter a name to sign your comments and publication": "Пожалуйста, введите имя, которое будет отображаться на сайте",
|
||||||
"Please enter email": "Пожалуйста, введите почту",
|
"Please enter email": "Пожалуйста, введите почту",
|
||||||
|
|
|
@ -33,6 +33,7 @@ export const AuthorCard = (props: Props) => {
|
||||||
const { t, lang } = useLocalize()
|
const { t, lang } = useLocalize()
|
||||||
const {
|
const {
|
||||||
session,
|
session,
|
||||||
|
author,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
isSessionLoaded,
|
isSessionLoaded,
|
||||||
actions: { loadSubscriptions, requireAuthentication },
|
actions: { loadSubscriptions, requireAuthentication },
|
||||||
|
@ -57,7 +58,7 @@ export const AuthorCard = (props: Props) => {
|
||||||
setIsSubscribing(false)
|
setIsSubscribing(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const isProfileOwner = createMemo(() => session()?.user?.slug === props.author.slug)
|
const isProfileOwner = createMemo(() => author()?.slug === props.author.slug)
|
||||||
|
|
||||||
const name = createMemo(() => {
|
const name = createMemo(() => {
|
||||||
if (lang() !== 'ru') {
|
if (lang() !== 'ru') {
|
||||||
|
@ -123,7 +124,7 @@ export const AuthorCard = (props: Props) => {
|
||||||
<Userpic
|
<Userpic
|
||||||
size={'XL'}
|
size={'XL'}
|
||||||
name={props.author.name}
|
name={props.author.name}
|
||||||
userpic={props.author.userpic}
|
userpic={props.author.pic}
|
||||||
slug={props.author.slug}
|
slug={props.author.slug}
|
||||||
class={styles.circlewrap}
|
class={styles.circlewrap}
|
||||||
/>
|
/>
|
||||||
|
@ -143,12 +144,7 @@ export const AuthorCard = (props: Props) => {
|
||||||
<a href="?modal=followers" class={styles.subscribers}>
|
<a href="?modal=followers" class={styles.subscribers}>
|
||||||
<For each={props.followers.slice(0, 3)}>
|
<For each={props.followers.slice(0, 3)}>
|
||||||
{(f) => (
|
{(f) => (
|
||||||
<Userpic
|
<Userpic size={'XS'} name={f.name} userpic={f.pic} class={styles.subscribersItem} />
|
||||||
size={'XS'}
|
|
||||||
name={f.name}
|
|
||||||
userpic={f.userpic}
|
|
||||||
class={styles.subscribersItem}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</For>
|
</For>
|
||||||
<div class={styles.subscribersCounter}>
|
<div class={styles.subscribersCounter}>
|
||||||
|
@ -166,7 +162,7 @@ export const AuthorCard = (props: Props) => {
|
||||||
<Userpic
|
<Userpic
|
||||||
size={'XS'}
|
size={'XS'}
|
||||||
name={f.name}
|
name={f.name}
|
||||||
userpic={f.userpic}
|
userpic={f.pic}
|
||||||
class={styles.subscribersItem}
|
class={styles.subscribersItem}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -242,7 +238,7 @@ export const AuthorCard = (props: Props) => {
|
||||||
<SharePopup
|
<SharePopup
|
||||||
title={props.author.name}
|
title={props.author.name}
|
||||||
description={props.author.bio}
|
description={props.author.bio}
|
||||||
imageUrl={props.author.userpic}
|
imageUrl={props.author.pic}
|
||||||
shareUrl={getShareUrl({ pathname: `/author/${props.author.slug}` })}
|
shareUrl={getShareUrl({ pathname: `/author/${props.author.slug}` })}
|
||||||
trigger={<Button variant="secondary" value={t('Share')} />}
|
trigger={<Button variant="secondary" value={t('Share')} />}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -22,7 +22,7 @@ export const Userpic = (props: Props) => {
|
||||||
const letters = () => {
|
const letters = () => {
|
||||||
if (!props.name) return
|
if (!props.name) return
|
||||||
const names = props.name ? props.name.split(' ') : []
|
const names = props.name ? props.name.split(' ') : []
|
||||||
return names[0][0] + '.' + (names.length > 1 ? names[1][0] : '') + '.'
|
return names[0][0 ?? names[0][0]] + '.' + (names.length > 1 ? names[1][0] + '.' : '')
|
||||||
}
|
}
|
||||||
|
|
||||||
const avatarSize = createMemo(() => {
|
const avatarSize = createMemo(() => {
|
||||||
|
|
|
@ -28,7 +28,7 @@ export const EmailConfirm = () => {
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
const token = searchParams().token
|
const token = searchParams().token
|
||||||
try {
|
try {
|
||||||
await confirmEmail(token)
|
await confirmEmail({ token })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof ApiError) {
|
if (error instanceof ApiError) {
|
||||||
if (error.code === 'token_expired') {
|
if (error.code === 'token_expired') {
|
||||||
|
|
|
@ -34,6 +34,8 @@ export const ForgotPasswordForm = () => {
|
||||||
|
|
||||||
const authFormRef: { current: HTMLFormElement } = { current: null }
|
const authFormRef: { current: HTMLFormElement } = { current: null }
|
||||||
|
|
||||||
|
const [message, setMessage] = createSignal<string>('')
|
||||||
|
|
||||||
const handleSubmit = async (event: Event) => {
|
const handleSubmit = async (event: Event) => {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
|
@ -61,11 +63,14 @@ export const ForgotPasswordForm = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsSubmitting(true)
|
setIsSubmitting(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await authorizer().forgotPassword({ email: email() })
|
const response = await authorizer().forgotPassword({
|
||||||
|
email: email(),
|
||||||
|
redirect_uri: window.location.href + '&success=1', // FIXME: redirect to success page accepting confirmation code
|
||||||
|
})
|
||||||
if (response) {
|
if (response) {
|
||||||
console.debug(response)
|
console.debug(response)
|
||||||
|
if (response.message) setMessage(response.message)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof ApiError && error.code === 'user_not_found') {
|
if (error instanceof ApiError && error.code === 'user_not_found') {
|
||||||
|
@ -86,7 +91,9 @@ export const ForgotPasswordForm = () => {
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<h4>{t('Forgot password?')}</h4>
|
<h4>{t('Forgot password?')}</h4>
|
||||||
<div class={styles.authSubtitle}>{t('Everything is ok, please give us your email address')}</div>
|
<div class={styles.authSubtitle}>
|
||||||
|
{t(message()) || t('Everything is ok, please give us your email address')}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class={clsx('pretty-form__item', {
|
class={clsx('pretty-form__item', {
|
||||||
|
@ -116,7 +123,6 @@ export const ForgotPasswordForm = () => {
|
||||||
|
|
||||||
<Show when={isUserNotFount()}>
|
<Show when={isUserNotFount()}>
|
||||||
<div class={styles.authSubtitle}>
|
<div class={styles.authSubtitle}>
|
||||||
{/*TODO: text*/}
|
|
||||||
{t("We can't find you, check email or")}{' '}
|
{t("We can't find you, check email or")}{' '}
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="#"
|
||||||
|
|
|
@ -132,6 +132,7 @@ export const RegisterForm = () => {
|
||||||
email: cleanEmail,
|
email: cleanEmail,
|
||||||
password: password(),
|
password: password(),
|
||||||
confirm_password: password(),
|
confirm_password: password(),
|
||||||
|
redirect_uri: window.location.origin,
|
||||||
})
|
})
|
||||||
|
|
||||||
setIsSuccess(true)
|
setIsSuccess(true)
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
import type { ParentComponent } from 'solid-js'
|
import type { ParentComponent } from 'solid-js'
|
||||||
|
|
||||||
import { Authorizer, User, AuthToken, ConfigType } from '@authorizerdev/authorizer-js'
|
import { Authorizer, User, AuthToken, ConfigType } from '@authorizerdev/authorizer-js'
|
||||||
import { createContext, createEffect, createMemo, onCleanup, onMount, useContext } from 'solid-js'
|
import {
|
||||||
|
createContext,
|
||||||
|
createEffect,
|
||||||
|
createMemo,
|
||||||
|
createSignal,
|
||||||
|
onCleanup,
|
||||||
|
onMount,
|
||||||
|
useContext,
|
||||||
|
} from 'solid-js'
|
||||||
import { createStore } from 'solid-js/store'
|
import { createStore } from 'solid-js/store'
|
||||||
|
|
||||||
export type AuthorizerState = {
|
export type AuthorizerState = {
|
||||||
|
@ -21,7 +29,7 @@ type AuthorizerContextActions = {
|
||||||
}
|
}
|
||||||
const config: ConfigType = {
|
const config: ConfigType = {
|
||||||
authorizerURL: 'https://auth.discours.io',
|
authorizerURL: 'https://auth.discours.io',
|
||||||
redirectURL: 'https://auth.discours.io',
|
redirectURL: 'https://discoursio-webapp.vercel.app',
|
||||||
clientID: '9c113377-5eea-4c89-98e1-69302462fc08', // FIXME: use env?
|
clientID: '9c113377-5eea-4c89-98e1-69302462fc08', // FIXME: use env?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,15 +64,16 @@ export const AuthorizerProvider: ParentComponent<AuthorizerProviderProps> = (pro
|
||||||
loading: true,
|
loading: true,
|
||||||
config: {
|
config: {
|
||||||
authorizerURL: props.authorizerURL,
|
authorizerURL: props.authorizerURL,
|
||||||
|
redirectURL: props.redirectURL,
|
||||||
clientID: props.clientID,
|
clientID: props.clientID,
|
||||||
} as ConfigType,
|
} as ConfigType,
|
||||||
})
|
})
|
||||||
|
const [redirect, setRedirect] = createSignal<string>()
|
||||||
const authorizer = createMemo(
|
const authorizer = createMemo(
|
||||||
() =>
|
() =>
|
||||||
new Authorizer({
|
new Authorizer({
|
||||||
authorizerURL: props.authorizerURL,
|
authorizerURL: props.authorizerURL,
|
||||||
redirectURL: props.redirectURL,
|
redirectURL: redirect(),
|
||||||
clientID: props.clientID,
|
clientID: props.clientID,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -148,6 +157,7 @@ export const AuthorizerProvider: ParentComponent<AuthorizerProviderProps> = (pro
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
setRedirect(window.location.origin)
|
||||||
!state.token && getToken()
|
!state.token && getToken()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,8 @@ import type { Accessor, JSX } from 'solid-js'
|
||||||
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
||||||
import { createContext, useContext, createSignal, createEffect } from 'solid-js'
|
import { createContext, useContext, createSignal, createEffect } from 'solid-js'
|
||||||
|
|
||||||
import { getToken } from '../graphql/privateGraphQLClient'
|
|
||||||
|
|
||||||
import { useSession } from './session'
|
import { useSession } from './session'
|
||||||
|
import { useAuthorizer } from './authorizer'
|
||||||
|
|
||||||
export interface SSEMessage {
|
export interface SSEMessage {
|
||||||
id: string
|
id: string
|
||||||
|
@ -30,20 +29,22 @@ export const ConnectProvider = (props: { children: JSX.Element }) => {
|
||||||
// const [messages, setMessages] = createSignal<Array<SSEMessage>>([]);
|
// const [messages, setMessages] = createSignal<Array<SSEMessage>>([]);
|
||||||
|
|
||||||
const [connected, setConnected] = createSignal(false)
|
const [connected, setConnected] = createSignal(false)
|
||||||
const { isAuthenticated } = useSession()
|
const {
|
||||||
|
isAuthenticated,
|
||||||
|
actions: { getToken },
|
||||||
|
} = useSession()
|
||||||
|
|
||||||
const addHandler = (handler: MessageHandler) => {
|
const addHandler = (handler: MessageHandler) => {
|
||||||
setHandlers((hhh) => [...hhh, handler])
|
setHandlers((hhh) => [...hhh, handler])
|
||||||
}
|
}
|
||||||
|
|
||||||
const listen = () => {
|
const listen = () => {
|
||||||
const token = getToken()
|
if (isAuthenticated()) {
|
||||||
if (token) {
|
|
||||||
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: token,
|
Authorization: getToken(),
|
||||||
},
|
},
|
||||||
onmessage(event) {
|
onmessage(event) {
|
||||||
const m: SSEMessage = JSON.parse(event.data)
|
const m: SSEMessage = JSON.parse(event.data)
|
||||||
|
@ -54,9 +55,11 @@ export const ConnectProvider = (props: { children: JSX.Element }) => {
|
||||||
},
|
},
|
||||||
onclose() {
|
onclose() {
|
||||||
console.log('[context.connect] sse connection closed by server')
|
console.log('[context.connect] sse connection closed by server')
|
||||||
|
setConnected(false)
|
||||||
},
|
},
|
||||||
onerror(err) {
|
onerror(err) {
|
||||||
console.error('[context.connect] sse connection closed by error', err)
|
console.error('[context.connect] sse connection closed by error', err)
|
||||||
|
setConnected(false)
|
||||||
throw new Error(err) // NOTE: simple hack to close the connection
|
throw new Error(err) // NOTE: simple hack to close the connection
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,10 +2,10 @@ import type { JSX } from 'solid-js'
|
||||||
|
|
||||||
import { openPage } from '@nanostores/router'
|
import { openPage } from '@nanostores/router'
|
||||||
import { Editor } from '@tiptap/core'
|
import { Editor } from '@tiptap/core'
|
||||||
import { Accessor, createContext, createSignal, useContext } from 'solid-js'
|
import { Accessor, createContext, createMemo, createSignal, useContext } from 'solid-js'
|
||||||
import { createStore, SetStoreFunction } from 'solid-js/store'
|
import { createStore, SetStoreFunction } from 'solid-js/store'
|
||||||
|
|
||||||
import { apiClient } from '../graphql/client/core'
|
import { apiClient as coreClient } from '../graphql/client/core'
|
||||||
import { ShoutVisibility, Topic, TopicInput } from '../graphql/schema/core.gen'
|
import { ShoutVisibility, Topic, TopicInput } from '../graphql/schema/core.gen'
|
||||||
import { router, useRouter } from '../stores/router'
|
import { router, useRouter } from '../stores/router'
|
||||||
import { slugify } from '../utils/slugify'
|
import { slugify } from '../utils/slugify'
|
||||||
|
@ -84,7 +84,10 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
|
||||||
const { t } = useLocalize()
|
const { t } = useLocalize()
|
||||||
|
|
||||||
const { page } = useRouter()
|
const { page } = useRouter()
|
||||||
|
const apiClient = createMemo(() => {
|
||||||
|
if (!coreClient.private) coreClient.connect()
|
||||||
|
return coreClient
|
||||||
|
})
|
||||||
const {
|
const {
|
||||||
actions: { showSnackbar },
|
actions: { showSnackbar },
|
||||||
} = useSnackbar()
|
} = useSnackbar()
|
||||||
|
@ -126,7 +129,7 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateShout = async (formToUpdate: ShoutForm, { publish }: { publish: boolean }) => {
|
const updateShout = async (formToUpdate: ShoutForm, { publish }: { publish: boolean }) => {
|
||||||
return apiClient.updateArticle({
|
return apiClient().updateArticle({
|
||||||
shoutId: formToUpdate.shoutId,
|
shoutId: formToUpdate.shoutId,
|
||||||
shoutInput: {
|
shoutInput: {
|
||||||
body: formToUpdate.body,
|
body: formToUpdate.body,
|
||||||
|
@ -211,7 +214,7 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
|
||||||
|
|
||||||
const publishShoutById = async (shoutId: number) => {
|
const publishShoutById = async (shoutId: number) => {
|
||||||
try {
|
try {
|
||||||
await apiClient.updateArticle({
|
await apiClient().updateArticle({
|
||||||
shoutId,
|
shoutId,
|
||||||
publish: true,
|
publish: true,
|
||||||
})
|
})
|
||||||
|
@ -225,7 +228,7 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
|
||||||
|
|
||||||
const deleteShout = async (shoutId: number) => {
|
const deleteShout = async (shoutId: number) => {
|
||||||
try {
|
try {
|
||||||
await apiClient.deleteShout({
|
await apiClient().deleteShout({
|
||||||
shoutId,
|
shoutId,
|
||||||
})
|
})
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Chat, Message, MutationCreateMessageArgs } from '../graphql/schema/chat.gen'
|
import type { Chat, Message, MutationCreate_MessageArgs } from '../graphql/schema/chat.gen'
|
||||||
import type { Accessor, JSX } from 'solid-js'
|
import type { Accessor, JSX } from 'solid-js'
|
||||||
|
|
||||||
import { createContext, createSignal, useContext } from 'solid-js'
|
import { createContext, createMemo, createSignal, useContext } from 'solid-js'
|
||||||
|
|
||||||
import { inboxClient } from '../graphql/client/chat'
|
import { inboxClient } from '../graphql/client/chat'
|
||||||
import { loadMessages } from '../stores/inbox'
|
import { loadMessages } from '../stores/inbox'
|
||||||
|
@ -15,7 +15,7 @@ type InboxContextType = {
|
||||||
createChat: (members: number[], title: string) => Promise<{ chat: Chat }>
|
createChat: (members: number[], title: string) => Promise<{ chat: Chat }>
|
||||||
loadChats: () => Promise<void>
|
loadChats: () => Promise<void>
|
||||||
getMessages?: (chatId: string) => Promise<void>
|
getMessages?: (chatId: string) => Promise<void>
|
||||||
sendMessage?: (args: MutationCreateMessageArgs) => void
|
sendMessage?: (args: MutationCreate_MessageArgs) => void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,13 +39,16 @@ export const InboxProvider = (props: { children: JSX.Element }) => {
|
||||||
setChats((prev) => [...prev, relivedChat])
|
setChats((prev) => [...prev, relivedChat])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const apiClient = createMemo(() => {
|
||||||
|
if (!inboxClient.private) inboxClient.connect()
|
||||||
|
return inboxClient
|
||||||
|
})
|
||||||
const { addHandler } = useConnect()
|
const { addHandler } = useConnect()
|
||||||
addHandler(handleMessage)
|
addHandler(handleMessage)
|
||||||
|
|
||||||
const loadChats = async () => {
|
const loadChats = async () => {
|
||||||
try {
|
try {
|
||||||
const newChats = await inboxClient.loadChats({ limit: 50, offset: 0 })
|
const newChats = await apiClient().loadChats({ limit: 50, offset: 0 })
|
||||||
setChats(newChats)
|
setChats(newChats)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('[loadChats]', error)
|
console.log('[loadChats]', error)
|
||||||
|
@ -62,9 +65,9 @@ export const InboxProvider = (props: { children: JSX.Element }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sendMessage = async (args: MutationCreateMessageArgs) => {
|
const sendMessage = async (args: MutationCreate_MessageArgs) => {
|
||||||
try {
|
try {
|
||||||
const message = await inboxClient.createMessage(args)
|
const message = await apiClient().createMessage(args)
|
||||||
setMessages((prev) => [...prev, message])
|
setMessages((prev) => [...prev, message])
|
||||||
const currentChat = chats().find((chat) => chat.id === args.chat_id)
|
const currentChat = chats().find((chat) => chat.id === args.chat_id)
|
||||||
setChats((prev) => [
|
setChats((prev) => [
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Portal } from 'solid-js/web'
|
||||||
|
|
||||||
import { ShowIfAuthenticated } from '../components/_shared/ShowIfAuthenticated'
|
import { ShowIfAuthenticated } from '../components/_shared/ShowIfAuthenticated'
|
||||||
import { NotificationsPanel } from '../components/NotificationsPanel'
|
import { NotificationsPanel } from '../components/NotificationsPanel'
|
||||||
import { notifierClient as apiClient } from '../graphql/client/notifier'
|
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'
|
||||||
|
@ -38,9 +38,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 apiClient = createMemo(() => {
|
||||||
|
if (!notifierClient.private) notifierClient.connect()
|
||||||
|
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
|
||||||
return acc
|
return acc
|
||||||
|
@ -69,13 +73,13 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const markNotificationAsRead = async (notification: Notification) => {
|
const markNotificationAsRead = async (notification: Notification) => {
|
||||||
await apiClient.markNotificationAsRead(notification.id)
|
await apiClient().markNotificationAsRead(notification.id)
|
||||||
const nnn = new Set([...notification.seen, notification.id])
|
const nnn = new Set([...notification.seen, notification.id])
|
||||||
setNotificationEntities(notification.id, 'seen', [...nnn])
|
setNotificationEntities(notification.id, 'seen', [...nnn])
|
||||||
setUnreadNotificationsCount((oldCount) => oldCount - 1)
|
setUnreadNotificationsCount((oldCount) => oldCount - 1)
|
||||||
}
|
}
|
||||||
const markAllNotificationsAsRead = async () => {
|
const markAllNotificationsAsRead = async () => {
|
||||||
await apiClient.markAllNotificationsAsRead()
|
await apiClient().markAllNotificationsAsRead()
|
||||||
loadNotifications({ limit: loadedNotificationsCount() })
|
loadNotifications({ limit: loadedNotificationsCount() })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import type { ProfileInput } from '../graphql/schema/core.gen'
|
import type { ProfileInput } from '../graphql/schema/core.gen'
|
||||||
|
|
||||||
import { createEffect, createSignal } from 'solid-js'
|
import { createEffect, createMemo, createSignal } from 'solid-js'
|
||||||
import { createStore } from 'solid-js/store'
|
import { createStore } from 'solid-js/store'
|
||||||
|
|
||||||
import { apiClient } from '../graphql/client/core'
|
import { apiClient as coreClient } from '../graphql/client/core'
|
||||||
import { loadAuthor } from '../stores/zine/authors'
|
import { loadAuthor } from '../stores/zine/authors'
|
||||||
|
|
||||||
import { useSession } from './session'
|
import { useSession } from './session'
|
||||||
|
@ -18,8 +18,13 @@ const useProfileForm = () => {
|
||||||
const { author: currentAuthor } = useSession()
|
const { author: currentAuthor } = useSession()
|
||||||
const [slugError, setSlugError] = createSignal<string>()
|
const [slugError, setSlugError] = createSignal<string>()
|
||||||
|
|
||||||
|
const apiClient = createMemo(() => {
|
||||||
|
if (!coreClient.private) coreClient.connect()
|
||||||
|
return coreClient
|
||||||
|
})
|
||||||
|
|
||||||
const submit = async (profile: ProfileInput) => {
|
const submit = async (profile: ProfileInput) => {
|
||||||
const response = await apiClient.updateProfile(profile)
|
const response = await apiClient().updateProfile(profile)
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
setSlugError(response.error)
|
setSlugError(response.error)
|
||||||
return response.error
|
return response.error
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import type { JSX } from 'solid-js'
|
import type { JSX } from 'solid-js'
|
||||||
|
|
||||||
import { createContext, onCleanup, useContext } from 'solid-js'
|
import { createContext, createMemo, onCleanup, useContext } from 'solid-js'
|
||||||
import { createStore, reconcile } from 'solid-js/store'
|
import { createStore, reconcile } from 'solid-js/store'
|
||||||
|
|
||||||
import { apiClient } from '../graphql/client/core'
|
import { apiClient as coreClient } from '../graphql/client/core'
|
||||||
import { Reaction, ReactionBy, ReactionInput, ReactionKind } from '../graphql/schema/core.gen'
|
import { Reaction, ReactionBy, ReactionInput, ReactionKind } from '../graphql/schema/core.gen'
|
||||||
|
|
||||||
type ReactionsContextType = {
|
type ReactionsContextType = {
|
||||||
|
@ -33,6 +33,11 @@ export function useReactions() {
|
||||||
export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
||||||
const [reactionEntities, setReactionEntities] = createStore<Record<number, Reaction>>({})
|
const [reactionEntities, setReactionEntities] = createStore<Record<number, Reaction>>({})
|
||||||
|
|
||||||
|
const apiClient = createMemo(() => {
|
||||||
|
if (!coreClient.private) coreClient.connect()
|
||||||
|
return coreClient
|
||||||
|
})
|
||||||
|
|
||||||
const loadReactionsBy = async ({
|
const loadReactionsBy = async ({
|
||||||
by,
|
by,
|
||||||
limit,
|
limit,
|
||||||
|
@ -42,7 +47,7 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
||||||
limit?: number
|
limit?: number
|
||||||
offset?: number
|
offset?: number
|
||||||
}): Promise<Reaction[]> => {
|
}): Promise<Reaction[]> => {
|
||||||
const reactions = await apiClient.getReactionsBy({ by, limit, offset })
|
const reactions = await coreClient.getReactionsBy({ by, limit, offset })
|
||||||
const newReactionEntities = reactions.reduce((acc, reaction) => {
|
const newReactionEntities = reactions.reduce((acc, reaction) => {
|
||||||
acc[reaction.id] = reaction
|
acc[reaction.id] = reaction
|
||||||
return acc
|
return acc
|
||||||
|
@ -52,7 +57,7 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const createReaction = async (input: ReactionInput): Promise<void> => {
|
const createReaction = async (input: ReactionInput): Promise<void> => {
|
||||||
const reaction = await apiClient.createReaction(input)
|
const reaction = await apiClient().createReaction(input)
|
||||||
|
|
||||||
const changes = {
|
const changes = {
|
||||||
[reaction.id]: reaction,
|
[reaction.id]: reaction,
|
||||||
|
@ -79,14 +84,14 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteReaction = async (id: number): Promise<void> => {
|
const deleteReaction = async (id: number): Promise<void> => {
|
||||||
const reaction = await apiClient.destroyReaction(id)
|
const reaction = await apiClient().destroyReaction(id)
|
||||||
setReactionEntities({
|
setReactionEntities({
|
||||||
[reaction.id]: undefined,
|
[reaction.id]: undefined,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateReaction = async (id: number, input: ReactionInput): Promise<void> => {
|
const updateReaction = async (id: number, input: ReactionInput): Promise<void> => {
|
||||||
const reaction = await apiClient.updateReaction(id, input)
|
const reaction = await apiClient().updateReaction(id, input)
|
||||||
setReactionEntities(reaction.id, reaction)
|
setReactionEntities(reaction.id, reaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { showModal } from '../stores/ui'
|
||||||
import { useAuthorizer } from './authorizer'
|
import { useAuthorizer } from './authorizer'
|
||||||
import { useLocalize } from './localize'
|
import { useLocalize } from './localize'
|
||||||
import { useSnackbar } from './snackbar'
|
import { useSnackbar } from './snackbar'
|
||||||
|
import { getToken, resetToken, setToken } from '../stores/token'
|
||||||
|
|
||||||
export type SessionContextType = {
|
export type SessionContextType = {
|
||||||
session: Resource<AuthToken>
|
session: Resource<AuthToken>
|
||||||
|
@ -21,6 +22,7 @@ export type SessionContextType = {
|
||||||
author: Resource<Author | null>
|
author: Resource<Author | null>
|
||||||
isAuthenticated: Accessor<boolean>
|
isAuthenticated: Accessor<boolean>
|
||||||
actions: {
|
actions: {
|
||||||
|
getToken: () => string
|
||||||
loadSession: () => AuthToken | Promise<AuthToken>
|
loadSession: () => AuthToken | Promise<AuthToken>
|
||||||
loadSubscriptions: () => Promise<void>
|
loadSubscriptions: () => Promise<void>
|
||||||
requireAuthentication: (
|
requireAuthentication: (
|
||||||
|
@ -52,15 +54,6 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
||||||
actions: { showSnackbar },
|
actions: { showSnackbar },
|
||||||
} = useSnackbar()
|
} = useSnackbar()
|
||||||
const [, { authorizer }] = useAuthorizer()
|
const [, { authorizer }] = useAuthorizer()
|
||||||
// const [getToken, setToken] = createSignal<string>('')
|
|
||||||
// https://start.solidjs.com/api/createCookieSessionStorage
|
|
||||||
const [store, setStore, { remove, clear, toJSON }] = createStorage({
|
|
||||||
api: cookieStorage,
|
|
||||||
prefix: 'discoursio',
|
|
||||||
})
|
|
||||||
const getToken = () => store.token
|
|
||||||
const setToken = (value) => setStore('token', value)
|
|
||||||
const resetToken = () => remove('token')
|
|
||||||
|
|
||||||
const loadSubscriptions = async (): Promise<void> => {
|
const loadSubscriptions = async (): Promise<void> => {
|
||||||
const result = await apiClient.getMySubscriptions()
|
const result = await apiClient.getMySubscriptions()
|
||||||
|
@ -73,13 +66,13 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
||||||
|
|
||||||
const getSession = async (): Promise<AuthToken> => {
|
const getSession = async (): Promise<AuthToken> => {
|
||||||
try {
|
try {
|
||||||
const token = getToken() // FIXME: token in localStorage?
|
const token = getToken()
|
||||||
const authResult = await authorizer().getSession({
|
const authResult = await authorizer().getSession({
|
||||||
Authorization: token, // authToken()
|
Authorization: token,
|
||||||
})
|
})
|
||||||
if (authResult) {
|
if (authResult) {
|
||||||
console.log(authResult)
|
console.log(authResult)
|
||||||
setToken(authResult.access_token || authResult.id_token)
|
setToken(authResult.access_token)
|
||||||
loadSubscriptions()
|
loadSubscriptions()
|
||||||
return authResult
|
return authResult
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,7 +115,7 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
||||||
const signIn = async (params: LoginInput) => {
|
const signIn = async (params: LoginInput) => {
|
||||||
const authResult = await authorizer().login(params)
|
const authResult = await authorizer().login(params)
|
||||||
if (authResult) {
|
if (authResult) {
|
||||||
setToken(authResult.access_token || authResult.id_token)
|
setToken(authResult.access_token)
|
||||||
mutate(authResult)
|
mutate(authResult)
|
||||||
}
|
}
|
||||||
loadSubscriptions()
|
loadSubscriptions()
|
||||||
|
@ -170,6 +163,7 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
||||||
signOut,
|
signOut,
|
||||||
confirmEmail,
|
confirmEmail,
|
||||||
loadSubscriptions,
|
loadSubscriptions,
|
||||||
|
getToken,
|
||||||
}
|
}
|
||||||
const value: SessionContextType = {
|
const value: SessionContextType = {
|
||||||
session,
|
session,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// inbox
|
// inbox
|
||||||
|
import { createGraphQLClient } from '../createGraphQLClient'
|
||||||
import createChat from '../mutation/chat/chat-create'
|
import createChat from '../mutation/chat/chat-create'
|
||||||
import deleteChat from '../mutation/chat/chat-delete'
|
import deleteChat from '../mutation/chat/chat-delete'
|
||||||
import markAsRead from '../mutation/chat/chat-mark-as-read'
|
import markAsRead from '../mutation/chat/chat-mark-as-read'
|
||||||
|
@ -6,7 +7,6 @@ import createChatMessage from '../mutation/chat/chat-message-create'
|
||||||
import deleteChatMessage from '../mutation/chat/chat-message-delete'
|
import deleteChatMessage from '../mutation/chat/chat-message-delete'
|
||||||
import updateChatMessage from '../mutation/chat/chat-message-update'
|
import updateChatMessage from '../mutation/chat/chat-message-update'
|
||||||
import updateChat from '../mutation/chat/chat-update'
|
import updateChat from '../mutation/chat/chat-update'
|
||||||
import { getPrivateClient } from '../privateGraphQLClient'
|
|
||||||
import chatMessagesLoadBy from '../query/chat/chat-messages-load-by'
|
import chatMessagesLoadBy from '../query/chat/chat-messages-load-by'
|
||||||
import loadRecipients from '../query/chat/chat-recipients'
|
import loadRecipients from '../query/chat/chat-recipients'
|
||||||
import myChats from '../query/chat/chats-load'
|
import myChats from '../query/chat/chats-load'
|
||||||
|
@ -24,55 +24,56 @@ import {
|
||||||
QueryLoad_RecipientsArgs,
|
QueryLoad_RecipientsArgs,
|
||||||
} from '../schema/chat.gen'
|
} from '../schema/chat.gen'
|
||||||
|
|
||||||
const privateInboxGraphQLClient = getPrivateClient('chat')
|
|
||||||
|
|
||||||
export const inboxClient = {
|
export const inboxClient = {
|
||||||
|
private: null,
|
||||||
|
connect: () => (inboxClient.private = createGraphQLClient('chat')),
|
||||||
|
|
||||||
loadChats: async (options: QueryLoad_ChatsArgs): Promise<Chat[]> => {
|
loadChats: async (options: QueryLoad_ChatsArgs): Promise<Chat[]> => {
|
||||||
const resp = await privateInboxGraphQLClient.query(myChats, options).toPromise()
|
const resp = await inboxClient.private.query(myChats, options).toPromise()
|
||||||
return resp.data.load_chats.chats
|
return resp.data.load_chats.chats
|
||||||
},
|
},
|
||||||
|
|
||||||
createChat: async (options: MutationCreate_ChatArgs) => {
|
createChat: async (options: MutationCreate_ChatArgs) => {
|
||||||
const resp = await privateInboxGraphQLClient.mutation(createChat, options).toPromise()
|
const resp = await inboxClient.private.mutation(createChat, options).toPromise()
|
||||||
return resp.data.create_chat
|
return resp.data.create_chat
|
||||||
},
|
},
|
||||||
|
|
||||||
markAsRead: async (options: MutationMark_As_ReadArgs) => {
|
markAsRead: async (options: MutationMark_As_ReadArgs) => {
|
||||||
const resp = await privateInboxGraphQLClient.mutation(markAsRead, options).toPromise()
|
const resp = await inboxClient.private.mutation(markAsRead, options).toPromise()
|
||||||
return resp.data.mark_as_read
|
return resp.data.mark_as_read
|
||||||
},
|
},
|
||||||
|
|
||||||
updateChat: async (options: MutationUpdate_ChatArgs) => {
|
updateChat: async (options: MutationUpdate_ChatArgs) => {
|
||||||
const resp = await privateInboxGraphQLClient.mutation(updateChat, options).toPromise()
|
const resp = await inboxClient.private.mutation(updateChat, options).toPromise()
|
||||||
return resp.data.update_chat
|
return resp.data.update_chat
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteChat: async (options: MutationDelete_ChatArgs) => {
|
deleteChat: async (options: MutationDelete_ChatArgs) => {
|
||||||
const resp = await privateInboxGraphQLClient.mutation(deleteChat, options).toPromise()
|
const resp = await inboxClient.private.mutation(deleteChat, options).toPromise()
|
||||||
return resp.data.delete_chat
|
return resp.data.delete_chat
|
||||||
},
|
},
|
||||||
|
|
||||||
createMessage: async (options: MutationCreate_MessageArgs) => {
|
createMessage: async (options: MutationCreate_MessageArgs) => {
|
||||||
const resp = await privateInboxGraphQLClient.mutation(createChatMessage, options).toPromise()
|
const resp = await inboxClient.private.mutation(createChatMessage, options).toPromise()
|
||||||
return resp.data.create_message.message
|
return resp.data.create_message.message
|
||||||
},
|
},
|
||||||
|
|
||||||
updateMessage: async (options: MutationUpdate_MessageArgs) => {
|
updateMessage: async (options: MutationUpdate_MessageArgs) => {
|
||||||
const resp = await privateInboxGraphQLClient.mutation(updateChatMessage, options).toPromise()
|
const resp = await inboxClient.private.mutation(updateChatMessage, options).toPromise()
|
||||||
return resp.data.update_message.message
|
return resp.data.update_message.message
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteMessage: async (options: MutationDelete_MessageArgs) => {
|
deleteMessage: async (options: MutationDelete_MessageArgs) => {
|
||||||
const resp = await privateInboxGraphQLClient.mutation(deleteChatMessage, options).toPromise()
|
const resp = await inboxClient.private.mutation(deleteChatMessage, options).toPromise()
|
||||||
return resp.data.delete_message
|
return resp.data.delete_message
|
||||||
},
|
},
|
||||||
|
|
||||||
loadChatMessages: async (options: QueryLoad_Messages_ByArgs) => {
|
loadChatMessages: async (options: QueryLoad_Messages_ByArgs) => {
|
||||||
const resp = await privateInboxGraphQLClient.query(chatMessagesLoadBy, options).toPromise()
|
const resp = await inboxClient.private.query(chatMessagesLoadBy, options).toPromise()
|
||||||
return resp.data.load_messages_by.messages
|
return resp.data.load_messages_by.messages
|
||||||
},
|
},
|
||||||
loadRecipients: async (options: QueryLoad_RecipientsArgs) => {
|
loadRecipients: async (options: QueryLoad_RecipientsArgs) => {
|
||||||
const resp = await privateInboxGraphQLClient.query(loadRecipients, options).toPromise()
|
const resp = await inboxClient.private.query(loadRecipients, options).toPromise()
|
||||||
return resp.data.load_recipients.members
|
return resp.data.load_recipients.members
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import type {
|
||||||
QueryLoad_Shouts_SearchArgs,
|
QueryLoad_Shouts_SearchArgs,
|
||||||
} from '../schema/core.gen'
|
} from '../schema/core.gen'
|
||||||
|
|
||||||
|
import { createGraphQLClient } from '../createGraphQLClient'
|
||||||
import createArticle from '../mutation/core/article-create'
|
import createArticle from '../mutation/core/article-create'
|
||||||
import deleteShout from '../mutation/core/article-delete'
|
import deleteShout from '../mutation/core/article-delete'
|
||||||
import updateArticle from '../mutation/core/article-update'
|
import updateArticle from '../mutation/core/article-update'
|
||||||
|
@ -22,8 +23,6 @@ import reactionDestroy from '../mutation/core/reaction-destroy'
|
||||||
import reactionUpdate from '../mutation/core/reaction-update'
|
import reactionUpdate from '../mutation/core/reaction-update'
|
||||||
import unfollowMutation from '../mutation/core/unfollow'
|
import unfollowMutation from '../mutation/core/unfollow'
|
||||||
import updateProfile from '../mutation/core/update-profile'
|
import updateProfile from '../mutation/core/update-profile'
|
||||||
import { getPrivateClient } from '../privateGraphQLClient'
|
|
||||||
import { getPublicClient } from '../publicGraphQLClient'
|
|
||||||
import shoutLoad from '../query/core/article-load'
|
import shoutLoad from '../query/core/article-load'
|
||||||
import shoutsLoadBy from '../query/core/articles-load-by'
|
import shoutsLoadBy from '../query/core/articles-load-by'
|
||||||
import draftsLoad from '../query/core/articles-load-drafts'
|
import draftsLoad from '../query/core/articles-load-drafts'
|
||||||
|
@ -41,10 +40,12 @@ import topicsAll from '../query/core/topics-all'
|
||||||
import userFollowedTopics from '../query/core/topics-by-author'
|
import userFollowedTopics from '../query/core/topics-by-author'
|
||||||
import topicsRandomQuery from '../query/core/topics-random'
|
import topicsRandomQuery from '../query/core/topics-random'
|
||||||
|
|
||||||
export const privateGraphQLClient = getPublicClient('core')
|
const publicGraphQLClient = createGraphQLClient('core')
|
||||||
export const publicGraphQLClient = getPrivateClient('core')
|
|
||||||
|
|
||||||
export const apiClient = {
|
export const apiClient = {
|
||||||
|
private: null,
|
||||||
|
connect: () => (apiClient.private = createGraphQLClient('core')), // NOTE: use it after token appears
|
||||||
|
|
||||||
getRandomTopics: async ({ amount }: { amount: number }) => {
|
getRandomTopics: async ({ amount }: { amount: number }) => {
|
||||||
const response = await publicGraphQLClient.query(topicsRandomQuery, { amount }).toPromise()
|
const response = await publicGraphQLClient.query(topicsRandomQuery, { amount }).toPromise()
|
||||||
|
|
||||||
|
@ -56,11 +57,11 @@ export const apiClient = {
|
||||||
},
|
},
|
||||||
|
|
||||||
follow: async ({ what, slug }: { what: FollowingEntity; slug: string }) => {
|
follow: async ({ what, slug }: { what: FollowingEntity; slug: string }) => {
|
||||||
const response = await privateGraphQLClient.mutation(followMutation, { what, slug }).toPromise()
|
const response = await apiClient.private.mutation(followMutation, { what, slug }).toPromise()
|
||||||
return response.data.follow
|
return response.data.follow
|
||||||
},
|
},
|
||||||
unfollow: async ({ what, slug }: { what: FollowingEntity; slug: string }) => {
|
unfollow: async ({ what, slug }: { what: FollowingEntity; slug: string }) => {
|
||||||
const response = await privateGraphQLClient.mutation(unfollowMutation, { what, slug }).toPromise()
|
const response = await apiClient.private.mutation(unfollowMutation, { what, slug }).toPromise()
|
||||||
return response.data.unfollow
|
return response.data.unfollow
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -95,7 +96,7 @@ export const apiClient = {
|
||||||
return response.data.userFollowedTopics
|
return response.data.userFollowedTopics
|
||||||
},
|
},
|
||||||
updateProfile: async (input: ProfileInput) => {
|
updateProfile: async (input: ProfileInput) => {
|
||||||
const response = await privateGraphQLClient.mutation(updateProfile, { profile: input }).toPromise()
|
const response = await apiClient.private.mutation(updateProfile, { profile: input }).toPromise()
|
||||||
return response.data.update_profile
|
return response.data.update_profile
|
||||||
},
|
},
|
||||||
getTopic: async ({ slug }: { slug: string }): Promise<Topic> => {
|
getTopic: async ({ slug }: { slug: string }): Promise<Topic> => {
|
||||||
|
@ -103,7 +104,7 @@ export const apiClient = {
|
||||||
return response.data.get_topic
|
return response.data.get_topic
|
||||||
},
|
},
|
||||||
createArticle: async ({ article }: { article: ShoutInput }): Promise<Shout> => {
|
createArticle: async ({ article }: { article: ShoutInput }): Promise<Shout> => {
|
||||||
const response = await privateGraphQLClient.mutation(createArticle, { shout: article }).toPromise()
|
const response = await apiClient.private.mutation(createArticle, { shout: article }).toPromise()
|
||||||
return response.data.create_shout.shout
|
return response.data.create_shout.shout
|
||||||
},
|
},
|
||||||
updateArticle: async ({
|
updateArticle: async ({
|
||||||
|
@ -115,33 +116,33 @@ export const apiClient = {
|
||||||
shoutInput?: ShoutInput
|
shoutInput?: ShoutInput
|
||||||
publish: boolean
|
publish: boolean
|
||||||
}): Promise<Shout> => {
|
}): Promise<Shout> => {
|
||||||
const response = await privateGraphQLClient
|
const response = await apiClient.private
|
||||||
.mutation(updateArticle, { shoutId, shoutInput, publish })
|
.mutation(updateArticle, { shoutId, shoutInput, publish })
|
||||||
.toPromise()
|
.toPromise()
|
||||||
console.debug('[graphql.client.core] updateArticle:', response.data)
|
console.debug('[graphql.client.core] updateArticle:', response.data)
|
||||||
return response.data.update_shout.shout
|
return response.data.update_shout.shout
|
||||||
},
|
},
|
||||||
deleteShout: async ({ shoutId }: { shoutId: number }): Promise<void> => {
|
deleteShout: async ({ shoutId }: { shoutId: number }): Promise<void> => {
|
||||||
const response = await privateGraphQLClient.mutation(deleteShout, { shout_id: shoutId }).toPromise()
|
const response = await apiClient.private.mutation(deleteShout, { shout_id: shoutId }).toPromise()
|
||||||
console.debug('[graphql.client.core] deleteShout:', response)
|
console.debug('[graphql.client.core] deleteShout:', response)
|
||||||
},
|
},
|
||||||
getDrafts: async (): Promise<Shout[]> => {
|
getDrafts: async (): Promise<Shout[]> => {
|
||||||
const response = await privateGraphQLClient.query(draftsLoad, {}).toPromise()
|
const response = await apiClient.private.query(draftsLoad, {}).toPromise()
|
||||||
console.debug('[graphql.client.core] getDrafts:', response)
|
console.debug('[graphql.client.core] getDrafts:', response)
|
||||||
return response.data.load_shouts_drafts
|
return response.data.load_shouts_drafts
|
||||||
},
|
},
|
||||||
createReaction: async (input: ReactionInput) => {
|
createReaction: async (input: ReactionInput) => {
|
||||||
const response = await privateGraphQLClient.mutation(reactionCreate, { reaction: input }).toPromise()
|
const response = await apiClient.private.mutation(reactionCreate, { reaction: input }).toPromise()
|
||||||
console.debug('[graphql.client.core] createReaction:', response)
|
console.debug('[graphql.client.core] createReaction:', response)
|
||||||
return response.data.create_reaction.reaction
|
return response.data.create_reaction.reaction
|
||||||
},
|
},
|
||||||
destroyReaction: async (id: number) => {
|
destroyReaction: async (id: number) => {
|
||||||
const response = await privateGraphQLClient.mutation(reactionDestroy, { id: id }).toPromise()
|
const response = await apiClient.private.mutation(reactionDestroy, { id: id }).toPromise()
|
||||||
console.debug('[graphql.client.core] destroyReaction:', response)
|
console.debug('[graphql.client.core] destroyReaction:', response)
|
||||||
return response.data.delete_reaction.reaction
|
return response.data.delete_reaction.reaction
|
||||||
},
|
},
|
||||||
updateReaction: async (id: number, input: ReactionInput) => {
|
updateReaction: async (id: number, input: ReactionInput) => {
|
||||||
const response = await privateGraphQLClient
|
const response = await apiClient.private
|
||||||
.mutation(reactionUpdate, { id: id, reaction: input })
|
.mutation(reactionUpdate, { id: id, reaction: input })
|
||||||
.toPromise()
|
.toPromise()
|
||||||
console.debug('[graphql.client.core] updateReaction:', response)
|
console.debug('[graphql.client.core] updateReaction:', response)
|
||||||
|
@ -177,7 +178,7 @@ export const apiClient = {
|
||||||
},
|
},
|
||||||
|
|
||||||
getMyFeed: async (options: LoadShoutsOptions) => {
|
getMyFeed: async (options: LoadShoutsOptions) => {
|
||||||
const resp = await privateGraphQLClient.query(myFeed, { options }).toPromise()
|
const resp = await apiClient.private.query(myFeed, { options }).toPromise()
|
||||||
if (resp.error) console.error(resp)
|
if (resp.error) console.error(resp)
|
||||||
|
|
||||||
return resp.data.load_shouts_feed
|
return resp.data.load_shouts_feed
|
||||||
|
@ -190,7 +191,7 @@ export const apiClient = {
|
||||||
return resp.data.load_reactions_by
|
return resp.data.load_reactions_by
|
||||||
},
|
},
|
||||||
getMySubscriptions: async (): Promise<Result> => {
|
getMySubscriptions: async (): Promise<Result> => {
|
||||||
const resp = await privateGraphQLClient.query(mySubscriptions, {}).toPromise()
|
const resp = await apiClient.private.query(mySubscriptions, {}).toPromise()
|
||||||
|
|
||||||
return resp.data.get_my_followed
|
return resp.data.get_my_followed
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
import markAllNotificationsAsRead from '../mutation/notifier/mark-all-notifications-as-read'
|
import markAllNotificationsAsRead from '../mutation/notifier/mark-all-notifications-as-read'
|
||||||
import markNotificationAsRead from '../mutation/notifier/mark-notification-as-read'
|
import markNotificationAsRead from '../mutation/notifier/mark-notification-as-read'
|
||||||
import { getPrivateClient } from '../privateGraphQLClient'
|
import { createGraphQLClient } from '../createGraphQLClient'
|
||||||
import loadNotifications from '../query/notifier/notifications-load'
|
import loadNotifications from '../query/notifier/notifications-load'
|
||||||
import { NotificationsResult, QueryLoad_NotificationsArgs } from '../schema/notifier.gen'
|
import { NotificationsResult, QueryLoad_NotificationsArgs } from '../schema/notifier.gen'
|
||||||
|
|
||||||
export const notifierPrivateGraphqlClient = getPrivateClient('notifier')
|
|
||||||
|
|
||||||
export const notifierClient = {
|
export const notifierClient = {
|
||||||
|
private: null,
|
||||||
|
connect: () => (notifierClient.private = createGraphQLClient('notifier')),
|
||||||
|
|
||||||
getNotifications: async (params: QueryLoad_NotificationsArgs): Promise<NotificationsResult> => {
|
getNotifications: async (params: QueryLoad_NotificationsArgs): Promise<NotificationsResult> => {
|
||||||
const resp = await notifierPrivateGraphqlClient.query(loadNotifications, params).toPromise()
|
const resp = await notifierClient.private.query(loadNotifications, params).toPromise()
|
||||||
return resp.data.load_notifications
|
return resp.data.load_notifications
|
||||||
},
|
},
|
||||||
markNotificationAsRead: async (notification_id: number): Promise<void> => {
|
markNotificationAsRead: async (notification_id: number): Promise<void> => {
|
||||||
await notifierPrivateGraphqlClient
|
await notifierClient.private
|
||||||
.mutation(markNotificationAsRead, {
|
.mutation(markNotificationAsRead, {
|
||||||
notification_id,
|
notification_id,
|
||||||
})
|
})
|
||||||
|
@ -20,6 +21,6 @@ export const notifierClient = {
|
||||||
},
|
},
|
||||||
|
|
||||||
markAllNotificationsAsRead: async (): Promise<void> => {
|
markAllNotificationsAsRead: async (): Promise<void> => {
|
||||||
await notifierPrivateGraphqlClient.mutation(markAllNotificationsAsRead, {}).toPromise()
|
await notifierClient.private.mutation(markAllNotificationsAsRead, {}).toPromise()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
23
src/graphql/createGraphQLClient.ts
Normal file
23
src/graphql/createGraphQLClient.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { ClientOptions, dedupExchange, fetchExchange, Exchange, createClient } from '@urql/core'
|
||||||
|
import { devtoolsExchange } from '@urql/devtools'
|
||||||
|
|
||||||
|
import { isDev } from '../utils/config'
|
||||||
|
import { getToken } from '../stores/token'
|
||||||
|
|
||||||
|
const exchanges: Exchange[] = [dedupExchange, fetchExchange]
|
||||||
|
|
||||||
|
if (isDev) {
|
||||||
|
exchanges.unshift(devtoolsExchange)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createGraphQLClient = (serviceName: string) => {
|
||||||
|
const token = getToken()
|
||||||
|
const options: ClientOptions = {
|
||||||
|
url: `https://${serviceName}.discours.io`,
|
||||||
|
maskTypename: true,
|
||||||
|
requestPolicy: 'cache-and-network',
|
||||||
|
fetchOptions: () => (token ? { headers: { Authorization: token } } : {}),
|
||||||
|
exchanges,
|
||||||
|
}
|
||||||
|
return createClient(options)
|
||||||
|
}
|
|
@ -1,55 +0,0 @@
|
||||||
import { ClientOptions, dedupExchange, fetchExchange, Exchange, createClient } from '@urql/core'
|
|
||||||
import { devtoolsExchange } from '@urql/devtools'
|
|
||||||
|
|
||||||
import { isDev } from '../utils/config'
|
|
||||||
|
|
||||||
const TOKEN_LOCAL_STORAGE_KEY = 'token'
|
|
||||||
|
|
||||||
const exchanges: Exchange[] = [dedupExchange, fetchExchange]
|
|
||||||
|
|
||||||
if (isDev) {
|
|
||||||
exchanges.unshift(devtoolsExchange)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getToken = (): string => {
|
|
||||||
return localStorage.getItem(TOKEN_LOCAL_STORAGE_KEY)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const setToken = (token: string) => {
|
|
||||||
if (!token) {
|
|
||||||
console.error('[privateGraphQLClient] setToken: token is null!')
|
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.setItem(TOKEN_LOCAL_STORAGE_KEY, token)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const resetToken = () => {
|
|
||||||
localStorage.removeItem(TOKEN_LOCAL_STORAGE_KEY)
|
|
||||||
}
|
|
||||||
|
|
||||||
const options: ClientOptions = {
|
|
||||||
url: '',
|
|
||||||
maskTypename: true,
|
|
||||||
requestPolicy: 'cache-and-network',
|
|
||||||
fetchOptions: () => {
|
|
||||||
try {
|
|
||||||
// localStorage is the source of truth for now
|
|
||||||
// to change token call setToken, for example after login
|
|
||||||
const token = localStorage.getItem(TOKEN_LOCAL_STORAGE_KEY)
|
|
||||||
if (!token) {
|
|
||||||
console.error('[privateGraphQLClient] fetchOptions: token is null!')
|
|
||||||
}
|
|
||||||
const headers = { Authorization: token }
|
|
||||||
return { headers }
|
|
||||||
} catch {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
exchanges,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getPrivateClient = (name: string) =>
|
|
||||||
createClient({
|
|
||||||
...options,
|
|
||||||
url: `https://${name}.discours.io`,
|
|
||||||
})
|
|
|
@ -1,24 +0,0 @@
|
||||||
import { ClientOptions, dedupExchange, fetchExchange, Exchange, createClient } from '@urql/core'
|
|
||||||
import { devtoolsExchange } from '@urql/devtools'
|
|
||||||
|
|
||||||
import { isDev } from '../utils/config'
|
|
||||||
// import { cache } from './cache'
|
|
||||||
|
|
||||||
const exchanges: Exchange[] = [dedupExchange, fetchExchange] //, cache]
|
|
||||||
|
|
||||||
if (isDev) {
|
|
||||||
exchanges.unshift(devtoolsExchange)
|
|
||||||
}
|
|
||||||
|
|
||||||
const options: ClientOptions = {
|
|
||||||
url: '',
|
|
||||||
maskTypename: true,
|
|
||||||
requestPolicy: 'cache-and-network',
|
|
||||||
exchanges,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getPublicClient = (name: string) =>
|
|
||||||
createClient({
|
|
||||||
...options,
|
|
||||||
url: `https://${name}.discours.io`,
|
|
||||||
})
|
|
10
src/stores/token.ts
Normal file
10
src/stores/token.ts
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import { cookieStorage, createStorage } from '@solid-primitives/storage'
|
||||||
|
|
||||||
|
// https://start.solidjs.com/api/createCookieSessionStorage
|
||||||
|
export const [store, setStore, { remove }] = createStorage({
|
||||||
|
api: cookieStorage,
|
||||||
|
prefix: 'discoursio',
|
||||||
|
})
|
||||||
|
export const getToken = () => store.token
|
||||||
|
export const setToken = (value) => setStore('token', value)
|
||||||
|
export const resetToken = () => remove('token')
|
Loading…
Reference in New Issue
Block a user