forget-fix-graphql-client-fix
This commit is contained in:
parent
3353004f48
commit
fce7ffb972
|
@ -259,6 +259,7 @@
|
|||
"Pin": "Закрепить",
|
||||
"Platform Guide": "Гид по дискурсу",
|
||||
"Please check your email address": "Пожалуйста, проверьте введенный адрес почты",
|
||||
"Please check your inbox! We have sent a password reset link.": "Пожалуйста, проверьте ваш адрес почты, мы отправили ссылку для сброса пароля",
|
||||
"Please confirm your email to finish": "Подтвердите почту и действие совершится",
|
||||
"Please enter a name to sign your comments and publication": "Пожалуйста, введите имя, которое будет отображаться на сайте",
|
||||
"Please enter email": "Пожалуйста, введите почту",
|
||||
|
|
|
@ -33,6 +33,7 @@ export const AuthorCard = (props: Props) => {
|
|||
const { t, lang } = useLocalize()
|
||||
const {
|
||||
session,
|
||||
author,
|
||||
subscriptions,
|
||||
isSessionLoaded,
|
||||
actions: { loadSubscriptions, requireAuthentication },
|
||||
|
@ -57,7 +58,7 @@ export const AuthorCard = (props: Props) => {
|
|||
setIsSubscribing(false)
|
||||
}
|
||||
|
||||
const isProfileOwner = createMemo(() => session()?.user?.slug === props.author.slug)
|
||||
const isProfileOwner = createMemo(() => author()?.slug === props.author.slug)
|
||||
|
||||
const name = createMemo(() => {
|
||||
if (lang() !== 'ru') {
|
||||
|
@ -123,7 +124,7 @@ export const AuthorCard = (props: Props) => {
|
|||
<Userpic
|
||||
size={'XL'}
|
||||
name={props.author.name}
|
||||
userpic={props.author.userpic}
|
||||
userpic={props.author.pic}
|
||||
slug={props.author.slug}
|
||||
class={styles.circlewrap}
|
||||
/>
|
||||
|
@ -143,12 +144,7 @@ export const AuthorCard = (props: Props) => {
|
|||
<a href="?modal=followers" class={styles.subscribers}>
|
||||
<For each={props.followers.slice(0, 3)}>
|
||||
{(f) => (
|
||||
<Userpic
|
||||
size={'XS'}
|
||||
name={f.name}
|
||||
userpic={f.userpic}
|
||||
class={styles.subscribersItem}
|
||||
/>
|
||||
<Userpic size={'XS'} name={f.name} userpic={f.pic} class={styles.subscribersItem} />
|
||||
)}
|
||||
</For>
|
||||
<div class={styles.subscribersCounter}>
|
||||
|
@ -166,7 +162,7 @@ export const AuthorCard = (props: Props) => {
|
|||
<Userpic
|
||||
size={'XS'}
|
||||
name={f.name}
|
||||
userpic={f.userpic}
|
||||
userpic={f.pic}
|
||||
class={styles.subscribersItem}
|
||||
/>
|
||||
)
|
||||
|
@ -242,7 +238,7 @@ export const AuthorCard = (props: Props) => {
|
|||
<SharePopup
|
||||
title={props.author.name}
|
||||
description={props.author.bio}
|
||||
imageUrl={props.author.userpic}
|
||||
imageUrl={props.author.pic}
|
||||
shareUrl={getShareUrl({ pathname: `/author/${props.author.slug}` })}
|
||||
trigger={<Button variant="secondary" value={t('Share')} />}
|
||||
/>
|
||||
|
|
|
@ -22,7 +22,7 @@ export const Userpic = (props: Props) => {
|
|||
const letters = () => {
|
||||
if (!props.name) return
|
||||
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(() => {
|
||||
|
|
|
@ -28,7 +28,7 @@ export const EmailConfirm = () => {
|
|||
onMount(async () => {
|
||||
const token = searchParams().token
|
||||
try {
|
||||
await confirmEmail(token)
|
||||
await confirmEmail({ token })
|
||||
} catch (error) {
|
||||
if (error instanceof ApiError) {
|
||||
if (error.code === 'token_expired') {
|
||||
|
|
|
@ -34,6 +34,8 @@ export const ForgotPasswordForm = () => {
|
|||
|
||||
const authFormRef: { current: HTMLFormElement } = { current: null }
|
||||
|
||||
const [message, setMessage] = createSignal<string>('')
|
||||
|
||||
const handleSubmit = async (event: Event) => {
|
||||
event.preventDefault()
|
||||
|
||||
|
@ -61,11 +63,14 @@ export const ForgotPasswordForm = () => {
|
|||
}
|
||||
|
||||
setIsSubmitting(true)
|
||||
|
||||
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) {
|
||||
console.debug(response)
|
||||
if (response.message) setMessage(response.message)
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof ApiError && error.code === 'user_not_found') {
|
||||
|
@ -86,7 +91,9 @@ export const ForgotPasswordForm = () => {
|
|||
>
|
||||
<div>
|
||||
<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
|
||||
class={clsx('pretty-form__item', {
|
||||
|
@ -116,7 +123,6 @@ export const ForgotPasswordForm = () => {
|
|||
|
||||
<Show when={isUserNotFount()}>
|
||||
<div class={styles.authSubtitle}>
|
||||
{/*TODO: text*/}
|
||||
{t("We can't find you, check email or")}{' '}
|
||||
<a
|
||||
href="#"
|
||||
|
|
|
@ -132,6 +132,7 @@ export const RegisterForm = () => {
|
|||
email: cleanEmail,
|
||||
password: password(),
|
||||
confirm_password: password(),
|
||||
redirect_uri: window.location.origin,
|
||||
})
|
||||
|
||||
setIsSuccess(true)
|
||||
|
|
|
@ -1,7 +1,15 @@
|
|||
import type { ParentComponent } from 'solid-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'
|
||||
|
||||
export type AuthorizerState = {
|
||||
|
@ -21,7 +29,7 @@ type AuthorizerContextActions = {
|
|||
}
|
||||
const config: ConfigType = {
|
||||
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?
|
||||
}
|
||||
|
||||
|
@ -56,15 +64,16 @@ export const AuthorizerProvider: ParentComponent<AuthorizerProviderProps> = (pro
|
|||
loading: true,
|
||||
config: {
|
||||
authorizerURL: props.authorizerURL,
|
||||
redirectURL: props.redirectURL,
|
||||
clientID: props.clientID,
|
||||
} as ConfigType,
|
||||
})
|
||||
|
||||
const [redirect, setRedirect] = createSignal<string>()
|
||||
const authorizer = createMemo(
|
||||
() =>
|
||||
new Authorizer({
|
||||
authorizerURL: props.authorizerURL,
|
||||
redirectURL: props.redirectURL,
|
||||
redirectURL: redirect(),
|
||||
clientID: props.clientID,
|
||||
}),
|
||||
)
|
||||
|
@ -148,6 +157,7 @@ export const AuthorizerProvider: ParentComponent<AuthorizerProviderProps> = (pro
|
|||
}
|
||||
|
||||
onMount(() => {
|
||||
setRedirect(window.location.origin)
|
||||
!state.token && getToken()
|
||||
})
|
||||
|
||||
|
|
|
@ -3,9 +3,8 @@ import type { Accessor, JSX } from 'solid-js'
|
|||
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
||||
import { createContext, useContext, createSignal, createEffect } from 'solid-js'
|
||||
|
||||
import { getToken } from '../graphql/privateGraphQLClient'
|
||||
|
||||
import { useSession } from './session'
|
||||
import { useAuthorizer } from './authorizer'
|
||||
|
||||
export interface SSEMessage {
|
||||
id: string
|
||||
|
@ -30,20 +29,22 @@ export const ConnectProvider = (props: { children: JSX.Element }) => {
|
|||
// const [messages, setMessages] = createSignal<Array<SSEMessage>>([]);
|
||||
|
||||
const [connected, setConnected] = createSignal(false)
|
||||
const { isAuthenticated } = useSession()
|
||||
const {
|
||||
isAuthenticated,
|
||||
actions: { getToken },
|
||||
} = useSession()
|
||||
|
||||
const addHandler = (handler: MessageHandler) => {
|
||||
setHandlers((hhh) => [...hhh, handler])
|
||||
}
|
||||
|
||||
const listen = () => {
|
||||
const token = getToken()
|
||||
if (token) {
|
||||
if (isAuthenticated()) {
|
||||
fetchEventSource('https://connect.discours.io', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: token,
|
||||
Authorization: getToken(),
|
||||
},
|
||||
onmessage(event) {
|
||||
const m: SSEMessage = JSON.parse(event.data)
|
||||
|
@ -54,9 +55,11 @@ export const ConnectProvider = (props: { children: JSX.Element }) => {
|
|||
},
|
||||
onclose() {
|
||||
console.log('[context.connect] sse connection closed by server')
|
||||
setConnected(false)
|
||||
},
|
||||
onerror(err) {
|
||||
console.error('[context.connect] sse connection closed by error', err)
|
||||
setConnected(false)
|
||||
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 { 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 { apiClient } from '../graphql/client/core'
|
||||
import { apiClient as coreClient } from '../graphql/client/core'
|
||||
import { ShoutVisibility, Topic, TopicInput } from '../graphql/schema/core.gen'
|
||||
import { router, useRouter } from '../stores/router'
|
||||
import { slugify } from '../utils/slugify'
|
||||
|
@ -84,7 +84,10 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
|
|||
const { t } = useLocalize()
|
||||
|
||||
const { page } = useRouter()
|
||||
|
||||
const apiClient = createMemo(() => {
|
||||
if (!coreClient.private) coreClient.connect()
|
||||
return coreClient
|
||||
})
|
||||
const {
|
||||
actions: { showSnackbar },
|
||||
} = useSnackbar()
|
||||
|
@ -126,7 +129,7 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
|
|||
}
|
||||
|
||||
const updateShout = async (formToUpdate: ShoutForm, { publish }: { publish: boolean }) => {
|
||||
return apiClient.updateArticle({
|
||||
return apiClient().updateArticle({
|
||||
shoutId: formToUpdate.shoutId,
|
||||
shoutInput: {
|
||||
body: formToUpdate.body,
|
||||
|
@ -211,7 +214,7 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
|
|||
|
||||
const publishShoutById = async (shoutId: number) => {
|
||||
try {
|
||||
await apiClient.updateArticle({
|
||||
await apiClient().updateArticle({
|
||||
shoutId,
|
||||
publish: true,
|
||||
})
|
||||
|
@ -225,7 +228,7 @@ export const EditorProvider = (props: { children: JSX.Element }) => {
|
|||
|
||||
const deleteShout = async (shoutId: number) => {
|
||||
try {
|
||||
await apiClient.deleteShout({
|
||||
await apiClient().deleteShout({
|
||||
shoutId,
|
||||
})
|
||||
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 { createContext, createSignal, useContext } from 'solid-js'
|
||||
import { createContext, createMemo, createSignal, useContext } from 'solid-js'
|
||||
|
||||
import { inboxClient } from '../graphql/client/chat'
|
||||
import { loadMessages } from '../stores/inbox'
|
||||
|
@ -15,7 +15,7 @@ type InboxContextType = {
|
|||
createChat: (members: number[], title: string) => Promise<{ chat: Chat }>
|
||||
loadChats: () => 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])
|
||||
}
|
||||
}
|
||||
|
||||
const apiClient = createMemo(() => {
|
||||
if (!inboxClient.private) inboxClient.connect()
|
||||
return inboxClient
|
||||
})
|
||||
const { addHandler } = useConnect()
|
||||
addHandler(handleMessage)
|
||||
|
||||
const loadChats = async () => {
|
||||
try {
|
||||
const newChats = await inboxClient.loadChats({ limit: 50, offset: 0 })
|
||||
const newChats = await apiClient().loadChats({ limit: 50, offset: 0 })
|
||||
setChats(newChats)
|
||||
} catch (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 {
|
||||
const message = await inboxClient.createMessage(args)
|
||||
const message = await apiClient().createMessage(args)
|
||||
setMessages((prev) => [...prev, message])
|
||||
const currentChat = chats().find((chat) => chat.id === args.chat_id)
|
||||
setChats((prev) => [
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Portal } from 'solid-js/web'
|
|||
|
||||
import { ShowIfAuthenticated } from '../components/_shared/ShowIfAuthenticated'
|
||||
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 { SSEMessage, useConnect } from './connect'
|
||||
|
@ -38,9 +38,13 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
|
|||
const [unreadNotificationsCount, setUnreadNotificationsCount] = createSignal(0)
|
||||
const [totalNotificationsCount, setTotalNotificationsCount] = createSignal(0)
|
||||
const [notificationEntities, setNotificationEntities] = createStore<Record<number, Notification>>({})
|
||||
const apiClient = createMemo(() => {
|
||||
if (!notifierClient.private) notifierClient.connect()
|
||||
return notifierClient
|
||||
})
|
||||
const { addHandler } = useConnect()
|
||||
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) => {
|
||||
acc[notification.id] = notification
|
||||
return acc
|
||||
|
@ -69,13 +73,13 @@ export const NotificationsProvider = (props: { children: JSX.Element }) => {
|
|||
})
|
||||
|
||||
const markNotificationAsRead = async (notification: Notification) => {
|
||||
await apiClient.markNotificationAsRead(notification.id)
|
||||
await apiClient().markNotificationAsRead(notification.id)
|
||||
const nnn = new Set([...notification.seen, notification.id])
|
||||
setNotificationEntities(notification.id, 'seen', [...nnn])
|
||||
setUnreadNotificationsCount((oldCount) => oldCount - 1)
|
||||
}
|
||||
const markAllNotificationsAsRead = async () => {
|
||||
await apiClient.markAllNotificationsAsRead()
|
||||
await apiClient().markAllNotificationsAsRead()
|
||||
loadNotifications({ limit: loadedNotificationsCount() })
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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 { apiClient } from '../graphql/client/core'
|
||||
import { apiClient as coreClient } from '../graphql/client/core'
|
||||
import { loadAuthor } from '../stores/zine/authors'
|
||||
|
||||
import { useSession } from './session'
|
||||
|
@ -18,8 +18,13 @@ const useProfileForm = () => {
|
|||
const { author: currentAuthor } = useSession()
|
||||
const [slugError, setSlugError] = createSignal<string>()
|
||||
|
||||
const apiClient = createMemo(() => {
|
||||
if (!coreClient.private) coreClient.connect()
|
||||
return coreClient
|
||||
})
|
||||
|
||||
const submit = async (profile: ProfileInput) => {
|
||||
const response = await apiClient.updateProfile(profile)
|
||||
const response = await apiClient().updateProfile(profile)
|
||||
if (response.error) {
|
||||
setSlugError(response.error)
|
||||
return response.error
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
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 { apiClient } from '../graphql/client/core'
|
||||
import { apiClient as coreClient } from '../graphql/client/core'
|
||||
import { Reaction, ReactionBy, ReactionInput, ReactionKind } from '../graphql/schema/core.gen'
|
||||
|
||||
type ReactionsContextType = {
|
||||
|
@ -33,6 +33,11 @@ export function useReactions() {
|
|||
export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
||||
const [reactionEntities, setReactionEntities] = createStore<Record<number, Reaction>>({})
|
||||
|
||||
const apiClient = createMemo(() => {
|
||||
if (!coreClient.private) coreClient.connect()
|
||||
return coreClient
|
||||
})
|
||||
|
||||
const loadReactionsBy = async ({
|
||||
by,
|
||||
limit,
|
||||
|
@ -42,7 +47,7 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
|||
limit?: number
|
||||
offset?: number
|
||||
}): Promise<Reaction[]> => {
|
||||
const reactions = await apiClient.getReactionsBy({ by, limit, offset })
|
||||
const reactions = await coreClient.getReactionsBy({ by, limit, offset })
|
||||
const newReactionEntities = reactions.reduce((acc, reaction) => {
|
||||
acc[reaction.id] = reaction
|
||||
return acc
|
||||
|
@ -52,7 +57,7 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
|||
}
|
||||
|
||||
const createReaction = async (input: ReactionInput): Promise<void> => {
|
||||
const reaction = await apiClient.createReaction(input)
|
||||
const reaction = await apiClient().createReaction(input)
|
||||
|
||||
const changes = {
|
||||
[reaction.id]: reaction,
|
||||
|
@ -79,14 +84,14 @@ export const ReactionsProvider = (props: { children: JSX.Element }) => {
|
|||
}
|
||||
|
||||
const deleteReaction = async (id: number): Promise<void> => {
|
||||
const reaction = await apiClient.destroyReaction(id)
|
||||
const reaction = await apiClient().destroyReaction(id)
|
||||
setReactionEntities({
|
||||
[reaction.id]: undefined,
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import { showModal } from '../stores/ui'
|
|||
import { useAuthorizer } from './authorizer'
|
||||
import { useLocalize } from './localize'
|
||||
import { useSnackbar } from './snackbar'
|
||||
import { getToken, resetToken, setToken } from '../stores/token'
|
||||
|
||||
export type SessionContextType = {
|
||||
session: Resource<AuthToken>
|
||||
|
@ -21,6 +22,7 @@ export type SessionContextType = {
|
|||
author: Resource<Author | null>
|
||||
isAuthenticated: Accessor<boolean>
|
||||
actions: {
|
||||
getToken: () => string
|
||||
loadSession: () => AuthToken | Promise<AuthToken>
|
||||
loadSubscriptions: () => Promise<void>
|
||||
requireAuthentication: (
|
||||
|
@ -52,15 +54,6 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
|||
actions: { showSnackbar },
|
||||
} = useSnackbar()
|
||||
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 result = await apiClient.getMySubscriptions()
|
||||
|
@ -73,13 +66,13 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
|||
|
||||
const getSession = async (): Promise<AuthToken> => {
|
||||
try {
|
||||
const token = getToken() // FIXME: token in localStorage?
|
||||
const token = getToken()
|
||||
const authResult = await authorizer().getSession({
|
||||
Authorization: token, // authToken()
|
||||
Authorization: token,
|
||||
})
|
||||
if (authResult) {
|
||||
console.log(authResult)
|
||||
setToken(authResult.access_token || authResult.id_token)
|
||||
setToken(authResult.access_token)
|
||||
loadSubscriptions()
|
||||
return authResult
|
||||
} else {
|
||||
|
@ -122,7 +115,7 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
|||
const signIn = async (params: LoginInput) => {
|
||||
const authResult = await authorizer().login(params)
|
||||
if (authResult) {
|
||||
setToken(authResult.access_token || authResult.id_token)
|
||||
setToken(authResult.access_token)
|
||||
mutate(authResult)
|
||||
}
|
||||
loadSubscriptions()
|
||||
|
@ -170,6 +163,7 @@ export const SessionProvider = (props: { children: JSX.Element }) => {
|
|||
signOut,
|
||||
confirmEmail,
|
||||
loadSubscriptions,
|
||||
getToken,
|
||||
}
|
||||
const value: SessionContextType = {
|
||||
session,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// inbox
|
||||
import { createGraphQLClient } from '../createGraphQLClient'
|
||||
import createChat from '../mutation/chat/chat-create'
|
||||
import deleteChat from '../mutation/chat/chat-delete'
|
||||
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 updateChatMessage from '../mutation/chat/chat-message-update'
|
||||
import updateChat from '../mutation/chat/chat-update'
|
||||
import { getPrivateClient } from '../privateGraphQLClient'
|
||||
import chatMessagesLoadBy from '../query/chat/chat-messages-load-by'
|
||||
import loadRecipients from '../query/chat/chat-recipients'
|
||||
import myChats from '../query/chat/chats-load'
|
||||
|
@ -24,55 +24,56 @@ import {
|
|||
QueryLoad_RecipientsArgs,
|
||||
} from '../schema/chat.gen'
|
||||
|
||||
const privateInboxGraphQLClient = getPrivateClient('chat')
|
||||
|
||||
export const inboxClient = {
|
||||
private: null,
|
||||
connect: () => (inboxClient.private = createGraphQLClient('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
|
||||
},
|
||||
|
||||
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
|
||||
},
|
||||
|
||||
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
|
||||
},
|
||||
|
||||
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
|
||||
},
|
||||
|
||||
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
|
||||
},
|
||||
|
||||
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
|
||||
},
|
||||
|
||||
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
|
||||
},
|
||||
|
||||
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
|
||||
},
|
||||
|
||||
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
|
||||
},
|
||||
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
|
||||
},
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import type {
|
|||
QueryLoad_Shouts_SearchArgs,
|
||||
} from '../schema/core.gen'
|
||||
|
||||
import { createGraphQLClient } from '../createGraphQLClient'
|
||||
import createArticle from '../mutation/core/article-create'
|
||||
import deleteShout from '../mutation/core/article-delete'
|
||||
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 unfollowMutation from '../mutation/core/unfollow'
|
||||
import updateProfile from '../mutation/core/update-profile'
|
||||
import { getPrivateClient } from '../privateGraphQLClient'
|
||||
import { getPublicClient } from '../publicGraphQLClient'
|
||||
import shoutLoad from '../query/core/article-load'
|
||||
import shoutsLoadBy from '../query/core/articles-load-by'
|
||||
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 topicsRandomQuery from '../query/core/topics-random'
|
||||
|
||||
export const privateGraphQLClient = getPublicClient('core')
|
||||
export const publicGraphQLClient = getPrivateClient('core')
|
||||
const publicGraphQLClient = createGraphQLClient('core')
|
||||
|
||||
export const apiClient = {
|
||||
private: null,
|
||||
connect: () => (apiClient.private = createGraphQLClient('core')), // NOTE: use it after token appears
|
||||
|
||||
getRandomTopics: async ({ amount }: { amount: number }) => {
|
||||
const response = await publicGraphQLClient.query(topicsRandomQuery, { amount }).toPromise()
|
||||
|
||||
|
@ -56,11 +57,11 @@ export const apiClient = {
|
|||
},
|
||||
|
||||
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
|
||||
},
|
||||
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
|
||||
},
|
||||
|
||||
|
@ -95,7 +96,7 @@ export const apiClient = {
|
|||
return response.data.userFollowedTopics
|
||||
},
|
||||
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
|
||||
},
|
||||
getTopic: async ({ slug }: { slug: string }): Promise<Topic> => {
|
||||
|
@ -103,7 +104,7 @@ export const apiClient = {
|
|||
return response.data.get_topic
|
||||
},
|
||||
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
|
||||
},
|
||||
updateArticle: async ({
|
||||
|
@ -115,33 +116,33 @@ export const apiClient = {
|
|||
shoutInput?: ShoutInput
|
||||
publish: boolean
|
||||
}): Promise<Shout> => {
|
||||
const response = await privateGraphQLClient
|
||||
const response = await apiClient.private
|
||||
.mutation(updateArticle, { shoutId, shoutInput, publish })
|
||||
.toPromise()
|
||||
console.debug('[graphql.client.core] updateArticle:', response.data)
|
||||
return response.data.update_shout.shout
|
||||
},
|
||||
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)
|
||||
},
|
||||
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)
|
||||
return response.data.load_shouts_drafts
|
||||
},
|
||||
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)
|
||||
return response.data.create_reaction.reaction
|
||||
},
|
||||
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)
|
||||
return response.data.delete_reaction.reaction
|
||||
},
|
||||
updateReaction: async (id: number, input: ReactionInput) => {
|
||||
const response = await privateGraphQLClient
|
||||
const response = await apiClient.private
|
||||
.mutation(reactionUpdate, { id: id, reaction: input })
|
||||
.toPromise()
|
||||
console.debug('[graphql.client.core] updateReaction:', response)
|
||||
|
@ -177,7 +178,7 @@ export const apiClient = {
|
|||
},
|
||||
|
||||
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)
|
||||
|
||||
return resp.data.load_shouts_feed
|
||||
|
@ -190,7 +191,7 @@ export const apiClient = {
|
|||
return resp.data.load_reactions_by
|
||||
},
|
||||
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
|
||||
},
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
import markAllNotificationsAsRead from '../mutation/notifier/mark-all-notifications-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 { NotificationsResult, QueryLoad_NotificationsArgs } from '../schema/notifier.gen'
|
||||
|
||||
export const notifierPrivateGraphqlClient = getPrivateClient('notifier')
|
||||
|
||||
export const notifierClient = {
|
||||
private: null,
|
||||
connect: () => (notifierClient.private = createGraphQLClient('notifier')),
|
||||
|
||||
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
|
||||
},
|
||||
markNotificationAsRead: async (notification_id: number): Promise<void> => {
|
||||
await notifierPrivateGraphqlClient
|
||||
await notifierClient.private
|
||||
.mutation(markNotificationAsRead, {
|
||||
notification_id,
|
||||
})
|
||||
|
@ -20,6 +21,6 @@ export const notifierClient = {
|
|||
},
|
||||
|
||||
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