2022-11-09 17:57:35 +00:00
|
|
|
import type { Reaction, Shout, FollowingEntity, AuthResult, ShoutInput } from '../graphql/types.gen'
|
2022-09-09 11:53:35 +00:00
|
|
|
import { publicGraphQLClient } from '../graphql/publicGraphQLClient'
|
2022-10-05 08:55:26 +00:00
|
|
|
import { privateGraphQLClient } from '../graphql/privateGraphQLClient'
|
2022-09-09 11:53:35 +00:00
|
|
|
import articleBySlug from '../graphql/query/article-by-slug'
|
|
|
|
import articlesRecentAll from '../graphql/query/articles-recent-all'
|
|
|
|
import articlesRecentPublished from '../graphql/query/articles-recent-published'
|
|
|
|
import topicsAll from '../graphql/query/topics-all'
|
|
|
|
import reactionsForShouts from '../graphql/query/reactions-for-shouts'
|
|
|
|
import mySession from '../graphql/mutation/my-session'
|
2022-09-17 18:23:30 +00:00
|
|
|
import authLogoutQuery from '../graphql/mutation/auth-logout'
|
|
|
|
import authLoginQuery from '../graphql/query/auth-login'
|
|
|
|
import authRegisterMutation from '../graphql/mutation/auth-register'
|
|
|
|
import authCheckEmailQuery from '../graphql/query/auth-check-email'
|
2022-10-21 18:17:04 +00:00
|
|
|
import authConfirmEmailMutation from '../graphql/mutation/auth-confirm-email'
|
2022-09-17 18:23:30 +00:00
|
|
|
import authSendLinkMutation from '../graphql/mutation/auth-send-link'
|
2022-09-09 11:53:35 +00:00
|
|
|
import followMutation from '../graphql/mutation/follow'
|
|
|
|
import unfollowMutation from '../graphql/mutation/unfollow'
|
|
|
|
import articlesForAuthors from '../graphql/query/articles-for-authors'
|
|
|
|
import articlesForTopics from '../graphql/query/articles-for-topics'
|
|
|
|
import searchResults from '../graphql/query/search-results'
|
|
|
|
import topicsRandomQuery from '../graphql/query/topics-random'
|
|
|
|
import articlesTopMonth from '../graphql/query/articles-top-month'
|
|
|
|
import articlesTopRated from '../graphql/query/articles-top-rated'
|
|
|
|
import authorsAll from '../graphql/query/authors-all'
|
|
|
|
import reactionCreate from '../graphql/mutation/reaction-create'
|
|
|
|
import reactionDestroy from '../graphql/mutation/reaction-destroy'
|
|
|
|
import reactionUpdate from '../graphql/mutation/reaction-update'
|
2022-09-13 09:59:04 +00:00
|
|
|
import authorsBySlugs from '../graphql/query/authors-by-slugs'
|
2022-09-14 11:28:43 +00:00
|
|
|
import incrementView from '../graphql/mutation/increment-view'
|
2022-11-09 17:57:35 +00:00
|
|
|
import createArticle from '../graphql/mutation/article-create'
|
2022-10-04 09:26:47 +00:00
|
|
|
import myChats from '../graphql/query/my-chats'
|
2022-11-13 09:25:31 +00:00
|
|
|
import getRecentByLayout from '../graphql/query/layout-recent'
|
|
|
|
import getTopByLayout from '../graphql/query/layout-top'
|
|
|
|
import getTopMonthByLayout from '../graphql/query/layout-top-month'
|
|
|
|
import type { LayoutType } from '../components/Views/LayoutView'
|
2022-09-09 11:53:35 +00:00
|
|
|
|
2022-09-14 11:05:48 +00:00
|
|
|
const FEED_SIZE = 50
|
2022-09-09 11:53:35 +00:00
|
|
|
|
2022-10-21 18:17:04 +00:00
|
|
|
type ApiErrorCode = 'unknown' | 'email_not_confirmed' | 'user_not_found' | 'user_already_exists'
|
2022-09-30 14:22:33 +00:00
|
|
|
|
|
|
|
export class ApiError extends Error {
|
|
|
|
code: ApiErrorCode
|
|
|
|
|
|
|
|
constructor(code: ApiErrorCode, message?: string) {
|
|
|
|
super(message)
|
|
|
|
this.code = code
|
|
|
|
}
|
|
|
|
}
|
2022-09-17 18:23:30 +00:00
|
|
|
|
2022-09-30 14:22:33 +00:00
|
|
|
export const apiClient = {
|
|
|
|
authLogin: async ({ email, password }): Promise<AuthResult> => {
|
2022-09-17 18:23:30 +00:00
|
|
|
const response = await publicGraphQLClient.query(authLoginQuery, { email, password }).toPromise()
|
2022-10-08 16:40:58 +00:00
|
|
|
// console.debug('[api-client] authLogin', { response })
|
2022-09-30 14:22:33 +00:00
|
|
|
if (response.error) {
|
|
|
|
if (response.error.message === '[GraphQL] User not found') {
|
|
|
|
throw new ApiError('user_not_found')
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new ApiError('unknown', response.error.message)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (response.data.signIn.error) {
|
|
|
|
if (response.data.signIn.error === 'please, confirm email') {
|
|
|
|
throw new ApiError('email_not_confirmed')
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new ApiError('unknown', response.data.signIn.error)
|
|
|
|
}
|
|
|
|
|
2022-09-17 18:23:30 +00:00
|
|
|
return response.data.signIn
|
|
|
|
},
|
2022-10-21 18:17:04 +00:00
|
|
|
authRegister: async ({
|
|
|
|
email,
|
|
|
|
password,
|
|
|
|
name
|
|
|
|
}: {
|
|
|
|
email: string
|
|
|
|
password: string
|
|
|
|
name: string
|
|
|
|
}): Promise<void> => {
|
2022-09-30 14:22:33 +00:00
|
|
|
const response = await publicGraphQLClient
|
2022-10-22 09:18:12 +00:00
|
|
|
.mutation(authRegisterMutation, { email, password, name })
|
2022-09-30 14:22:33 +00:00
|
|
|
.toPromise()
|
2022-10-21 18:17:04 +00:00
|
|
|
|
|
|
|
if (response.error) {
|
|
|
|
if (response.error.message === '[GraphQL] User already exist') {
|
|
|
|
throw new ApiError('user_already_exists', response.error.message)
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new ApiError('unknown', response.error.message)
|
|
|
|
}
|
2022-09-17 18:23:30 +00:00
|
|
|
},
|
|
|
|
authSignOut: async () => {
|
|
|
|
const response = await publicGraphQLClient.query(authLogoutQuery, {}).toPromise()
|
|
|
|
return response.data.signOut
|
|
|
|
},
|
|
|
|
authCheckEmail: async ({ email }) => {
|
|
|
|
// check if email is used
|
|
|
|
const response = await publicGraphQLClient.query(authCheckEmailQuery, { email }).toPromise()
|
|
|
|
return response.data.isEmailUsed
|
|
|
|
},
|
2022-11-01 22:25:18 +00:00
|
|
|
authSendLink: async ({ email, lang }) => {
|
2022-09-17 18:23:30 +00:00
|
|
|
// send link with code on email
|
2022-11-01 22:25:18 +00:00
|
|
|
const response = await publicGraphQLClient.mutation(authSendLinkMutation, { email, lang }).toPromise()
|
2022-11-02 06:56:01 +00:00
|
|
|
return response.data.sendLink
|
2022-09-17 18:23:30 +00:00
|
|
|
},
|
2022-10-21 18:17:04 +00:00
|
|
|
confirmEmail: async ({ token }: { token: string }) => {
|
2022-09-17 18:23:30 +00:00
|
|
|
// confirm email with code from link
|
2022-10-25 16:25:42 +00:00
|
|
|
const response = await publicGraphQLClient.mutation(authConfirmEmailMutation, { token }).toPromise()
|
2022-10-21 18:17:04 +00:00
|
|
|
|
|
|
|
if (response.error) {
|
|
|
|
throw new ApiError('unknown', response.error.message)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (response.data?.confirmEmail?.error) {
|
|
|
|
throw new ApiError('unknown', response.data?.confirmEmail?.error)
|
|
|
|
}
|
|
|
|
|
|
|
|
return response.data.confirmEmail
|
2022-09-17 18:23:30 +00:00
|
|
|
},
|
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
getTopArticles: async () => {
|
2022-09-14 11:05:48 +00:00
|
|
|
const response = await publicGraphQLClient.query(articlesTopRated, { limit: 10, offset: 0 }).toPromise()
|
2022-09-09 11:53:35 +00:00
|
|
|
return response.data.topOverall
|
|
|
|
},
|
|
|
|
getTopMonthArticles: async () => {
|
2022-09-14 11:05:48 +00:00
|
|
|
const response = await publicGraphQLClient.query(articlesTopMonth, { limit: 10, offset: 0 }).toPromise()
|
2022-09-13 08:05:11 +00:00
|
|
|
return response.data.topMonth
|
2022-09-09 11:53:35 +00:00
|
|
|
},
|
2022-09-13 09:59:04 +00:00
|
|
|
getRecentPublishedArticles: async ({
|
2022-09-14 11:05:48 +00:00
|
|
|
limit = FEED_SIZE,
|
|
|
|
offset = 0
|
2022-09-13 09:59:04 +00:00
|
|
|
}: {
|
2022-09-14 11:05:48 +00:00
|
|
|
limit?: number
|
|
|
|
offset?: number
|
2022-09-13 09:59:04 +00:00
|
|
|
}) => {
|
2022-09-14 11:05:48 +00:00
|
|
|
const response = await publicGraphQLClient.query(articlesRecentPublished, { limit, offset }).toPromise()
|
2022-09-13 09:59:04 +00:00
|
|
|
|
|
|
|
return response.data.recentPublished
|
|
|
|
},
|
2022-09-22 09:37:49 +00:00
|
|
|
getRandomTopics: async ({ amount }: { amount: number }) => {
|
|
|
|
const response = await publicGraphQLClient.query(topicsRandomQuery, { amount }).toPromise()
|
2022-09-09 11:53:35 +00:00
|
|
|
|
2022-09-30 14:22:33 +00:00
|
|
|
if (!response.data) {
|
2022-10-08 16:40:58 +00:00
|
|
|
console.error('[api-client] getRandomTopics', response.error)
|
2022-09-30 14:22:33 +00:00
|
|
|
}
|
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
return response.data.topicsRandom
|
|
|
|
},
|
|
|
|
getSearchResults: async ({
|
|
|
|
query,
|
2022-09-14 11:05:48 +00:00
|
|
|
limit = FEED_SIZE,
|
2022-11-13 09:25:31 +00:00
|
|
|
offset = 0,
|
|
|
|
layout = 'literature'
|
2022-09-09 11:53:35 +00:00
|
|
|
}: {
|
|
|
|
query: string
|
2022-09-14 11:05:48 +00:00
|
|
|
limit: number
|
2022-09-22 09:37:49 +00:00
|
|
|
offset?: number
|
2022-11-13 09:25:31 +00:00
|
|
|
layout?: LayoutType
|
2022-09-09 11:53:35 +00:00
|
|
|
}): Promise<Shout[]> => {
|
|
|
|
const response = await publicGraphQLClient
|
|
|
|
.query(searchResults, {
|
|
|
|
q: query,
|
2022-09-14 11:05:48 +00:00
|
|
|
limit,
|
|
|
|
offset
|
2022-09-09 11:53:35 +00:00
|
|
|
})
|
|
|
|
.toPromise()
|
|
|
|
|
2022-09-14 11:28:43 +00:00
|
|
|
return response.data?.searchQuery || []
|
2022-09-09 11:53:35 +00:00
|
|
|
},
|
2022-09-13 09:59:04 +00:00
|
|
|
getRecentArticles: async ({
|
2022-09-14 11:05:48 +00:00
|
|
|
limit = FEED_SIZE,
|
|
|
|
offset = 0
|
2022-09-09 12:18:09 +00:00
|
|
|
}: {
|
2022-09-14 11:05:48 +00:00
|
|
|
limit: number
|
2022-09-22 09:37:49 +00:00
|
|
|
offset?: number
|
2022-09-09 12:18:09 +00:00
|
|
|
}): Promise<Shout[]> => {
|
|
|
|
const response = await publicGraphQLClient
|
2022-09-13 09:59:04 +00:00
|
|
|
.query(articlesRecentAll, {
|
2022-09-14 11:05:48 +00:00
|
|
|
limit,
|
|
|
|
offset
|
2022-09-09 12:18:09 +00:00
|
|
|
})
|
|
|
|
.toPromise()
|
|
|
|
|
2022-09-13 09:59:04 +00:00
|
|
|
return response.data.recentAll
|
2022-09-09 12:18:09 +00:00
|
|
|
},
|
2022-09-09 11:53:35 +00:00
|
|
|
getArticlesForTopics: async ({
|
|
|
|
topicSlugs,
|
2022-10-28 21:21:47 +00:00
|
|
|
limit,
|
2022-09-14 11:05:48 +00:00
|
|
|
offset = 0
|
2022-09-09 11:53:35 +00:00
|
|
|
}: {
|
|
|
|
topicSlugs: string[]
|
2022-09-14 11:05:48 +00:00
|
|
|
limit: number
|
2022-09-22 09:37:49 +00:00
|
|
|
offset?: number
|
2022-09-09 11:53:35 +00:00
|
|
|
}): Promise<Shout[]> => {
|
|
|
|
const response = await publicGraphQLClient
|
|
|
|
.query(articlesForTopics, {
|
|
|
|
slugs: topicSlugs,
|
2022-09-14 11:05:48 +00:00
|
|
|
limit,
|
|
|
|
offset
|
2022-09-09 11:53:35 +00:00
|
|
|
})
|
|
|
|
.toPromise()
|
|
|
|
|
2022-10-05 12:32:23 +00:00
|
|
|
if (response.error) {
|
2022-10-08 16:40:58 +00:00
|
|
|
console.error('[api-client] getArticlesForTopics', response.error)
|
2022-10-05 12:32:23 +00:00
|
|
|
}
|
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
return response.data.shoutsByTopics
|
|
|
|
},
|
|
|
|
getArticlesForAuthors: async ({
|
|
|
|
authorSlugs,
|
2022-10-28 21:21:47 +00:00
|
|
|
limit,
|
2022-09-14 11:05:48 +00:00
|
|
|
offset = 0
|
2022-09-09 11:53:35 +00:00
|
|
|
}: {
|
|
|
|
authorSlugs: string[]
|
2022-09-14 11:05:48 +00:00
|
|
|
limit: number
|
2022-09-22 09:37:49 +00:00
|
|
|
offset?: number
|
2022-09-09 11:53:35 +00:00
|
|
|
}): Promise<Shout[]> => {
|
2022-10-18 04:40:05 +00:00
|
|
|
const vars = {
|
|
|
|
slugs: authorSlugs,
|
|
|
|
limit,
|
|
|
|
offset
|
|
|
|
}
|
|
|
|
console.debug(vars)
|
|
|
|
const response = await publicGraphQLClient.query(articlesForAuthors, vars).toPromise()
|
2022-09-09 11:53:35 +00:00
|
|
|
|
2022-10-05 12:32:23 +00:00
|
|
|
if (response.error) {
|
2022-10-08 16:40:58 +00:00
|
|
|
console.error('[api-client] getArticlesForAuthors', response.error)
|
2022-10-05 12:32:23 +00:00
|
|
|
}
|
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
return response.data.shoutsByAuthors
|
|
|
|
},
|
|
|
|
|
|
|
|
// subscribe
|
|
|
|
|
|
|
|
follow: async ({ what, slug }: { what: FollowingEntity; slug: string }) => {
|
|
|
|
const response = await privateGraphQLClient.query(followMutation, { what, slug }).toPromise()
|
|
|
|
return response.data.follow
|
|
|
|
},
|
|
|
|
unfollow: async ({ what, slug }: { what: FollowingEntity; slug: string }) => {
|
|
|
|
const response = await privateGraphQLClient.query(unfollowMutation, { what, slug }).toPromise()
|
|
|
|
return response.data.unfollow
|
|
|
|
},
|
|
|
|
|
2022-09-30 14:22:33 +00:00
|
|
|
getSession: async (): Promise<AuthResult> => {
|
2022-09-09 11:53:35 +00:00
|
|
|
// renew session with auth token in header (!)
|
|
|
|
const response = await privateGraphQLClient.mutation(mySession, {}).toPromise()
|
2022-10-21 18:17:04 +00:00
|
|
|
|
|
|
|
if (response.error) {
|
|
|
|
// TODO
|
|
|
|
throw new ApiError('unknown', response.error.message)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (response.data?.refreshSession?.error) {
|
|
|
|
throw new ApiError('unknown', response.data.refreshSession.error)
|
|
|
|
}
|
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
return response.data.refreshSession
|
|
|
|
},
|
2022-09-14 11:05:48 +00:00
|
|
|
getPublishedArticles: async ({ limit = FEED_SIZE, offset }: { limit?: number; offset?: number }) => {
|
|
|
|
const response = await publicGraphQLClient.query(articlesRecentPublished, { limit, offset }).toPromise()
|
2022-09-09 11:53:35 +00:00
|
|
|
|
2022-10-05 15:11:14 +00:00
|
|
|
if (response.error) {
|
2022-10-08 16:40:58 +00:00
|
|
|
console.error('[api-client] getPublishedArticles', response.error)
|
2022-10-05 15:11:14 +00:00
|
|
|
}
|
|
|
|
|
2022-09-13 09:59:04 +00:00
|
|
|
return response.data.recentPublished
|
|
|
|
},
|
2022-09-09 11:53:35 +00:00
|
|
|
getAllTopics: async () => {
|
|
|
|
const response = await publicGraphQLClient.query(topicsAll, {}).toPromise()
|
2022-10-04 12:42:11 +00:00
|
|
|
if (response.error) {
|
2022-10-08 16:40:58 +00:00
|
|
|
console.debug('[api-client] getAllTopics', response.error)
|
2022-10-04 12:42:11 +00:00
|
|
|
}
|
2022-09-09 11:53:35 +00:00
|
|
|
return response.data.topicsAll
|
|
|
|
},
|
|
|
|
getAllAuthors: async () => {
|
2022-10-04 09:26:47 +00:00
|
|
|
const response = await publicGraphQLClient.query(authorsAll, {}).toPromise()
|
2022-10-04 12:42:11 +00:00
|
|
|
if (response.error) {
|
2022-10-08 16:40:58 +00:00
|
|
|
console.debug('[api-client] getAllAuthors', response.error)
|
2022-10-04 12:42:11 +00:00
|
|
|
}
|
2022-09-09 11:53:35 +00:00
|
|
|
return response.data.authorsAll
|
|
|
|
},
|
2022-10-04 12:42:11 +00:00
|
|
|
getAuthor: async ({ slug }: { slug: string }) => {
|
|
|
|
const response = await publicGraphQLClient.query(authorsBySlugs, { slugs: [slug] }).toPromise()
|
|
|
|
return response.data.getUsersBySlugs
|
|
|
|
},
|
2022-09-09 11:53:35 +00:00
|
|
|
getArticle: async ({ slug }: { slug: string }): Promise<Shout> => {
|
|
|
|
const response = await publicGraphQLClient.query(articleBySlug, { slug }).toPromise()
|
|
|
|
return response.data?.getShoutBySlug
|
|
|
|
},
|
2022-09-09 12:18:09 +00:00
|
|
|
|
|
|
|
// reactions
|
|
|
|
|
2022-09-09 11:53:35 +00:00
|
|
|
getReactionsForShouts: async ({
|
|
|
|
shoutSlugs,
|
2022-09-14 11:05:48 +00:00
|
|
|
limit = FEED_SIZE,
|
|
|
|
offset = 0
|
2022-09-09 11:53:35 +00:00
|
|
|
}: {
|
|
|
|
shoutSlugs: string[]
|
2022-09-14 11:05:48 +00:00
|
|
|
limit?: number
|
|
|
|
offset?: number
|
2022-09-09 11:53:35 +00:00
|
|
|
}): Promise<Reaction[]> => {
|
|
|
|
const response = await publicGraphQLClient
|
|
|
|
.query(reactionsForShouts, {
|
|
|
|
shouts: shoutSlugs,
|
2022-09-14 11:05:48 +00:00
|
|
|
limit,
|
|
|
|
offset
|
2022-09-09 11:53:35 +00:00
|
|
|
})
|
|
|
|
.toPromise()
|
|
|
|
|
2022-09-20 08:26:12 +00:00
|
|
|
return response.data.reactionsForShouts
|
2022-09-09 11:53:35 +00:00
|
|
|
},
|
2022-09-13 09:59:04 +00:00
|
|
|
getAuthorsBySlugs: async ({ slugs }) => {
|
|
|
|
const response = await publicGraphQLClient.query(authorsBySlugs, { slugs }).toPromise()
|
|
|
|
return response.data.getUsersBySlugs
|
|
|
|
},
|
2022-11-09 17:57:35 +00:00
|
|
|
createArticle: async ({ article }: { article: ShoutInput }) => {
|
|
|
|
const response = await privateGraphQLClient.mutation(createArticle, { shout: article }).toPromise()
|
|
|
|
console.debug('createArticle response:', response)
|
|
|
|
return response.data.createShout
|
|
|
|
},
|
2022-09-09 11:53:35 +00:00
|
|
|
createReaction: async ({ reaction }) => {
|
2022-09-09 14:08:17 +00:00
|
|
|
const response = await privateGraphQLClient.mutation(reactionCreate, { reaction }).toPromise()
|
2022-10-08 16:40:58 +00:00
|
|
|
console.debug('[api-client] [api] create reaction mutation called')
|
2022-09-09 11:53:35 +00:00
|
|
|
return response.data.createReaction
|
|
|
|
},
|
|
|
|
updateReaction: async ({ reaction }) => {
|
2022-09-09 14:08:17 +00:00
|
|
|
const response = await privateGraphQLClient.mutation(reactionUpdate, { reaction }).toPromise()
|
2022-09-09 11:53:35 +00:00
|
|
|
|
|
|
|
return response.data.createReaction
|
|
|
|
},
|
|
|
|
destroyReaction: async ({ id }) => {
|
2022-09-09 14:08:17 +00:00
|
|
|
const response = await privateGraphQLClient.mutation(reactionDestroy, { id }).toPromise()
|
2022-09-09 11:53:35 +00:00
|
|
|
|
|
|
|
return response.data.deleteReaction
|
2022-09-14 11:28:43 +00:00
|
|
|
},
|
|
|
|
incrementView: async ({ articleSlug }) => {
|
|
|
|
await privateGraphQLClient.mutation(incrementView, { shout: articleSlug })
|
2022-10-04 09:26:47 +00:00
|
|
|
},
|
|
|
|
getInboxes: async (payload = {}) => {
|
2022-10-09 05:08:38 +00:00
|
|
|
const resp = await privateGraphQLClient.query(myChats, payload).toPromise()
|
|
|
|
return resp.data.myChats
|
2022-11-12 18:14:20 +00:00
|
|
|
},
|
2022-11-13 09:25:31 +00:00
|
|
|
getRecentLayoutShouts: async ({ layout = 'article', amount = 50, offset = 0 }) => {
|
|
|
|
const resp = await publicGraphQLClient.query(getRecentByLayout, { amount, offset, layout }).toPromise()
|
|
|
|
return resp.data.recentLayoutShouts
|
|
|
|
},
|
|
|
|
getTopLayoutShouts: async ({ layout = 'article', amount = 50, offset = 0 }) => {
|
|
|
|
const resp = await publicGraphQLClient.query(getTopByLayout, { amount, offset, layout }).toPromise()
|
|
|
|
return resp.data.topLayoutShouts
|
|
|
|
},
|
|
|
|
getTopMonthLayoutShouts: async ({ layout = 'article', amount = 50, offset = 0 }) => {
|
|
|
|
const resp = await publicGraphQLClient
|
|
|
|
.query(getTopMonthByLayout, { amount, offset, layout })
|
|
|
|
.toPromise()
|
|
|
|
return resp.data.topMonthLayoutShouts
|
2022-09-09 11:53:35 +00:00
|
|
|
}
|
|
|
|
}
|