mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
619 restructure local storage (#628)
* To MMKV migration working * POC migrated font size settings * Moved settings to mmkv * Fix typos * Migrated contexts slice * Migrated app slice * POC instance emoji update * Migrated drafts * Migrated simple instance properties * All migrated! * Re-structure files * Tolerant of undefined settings * Can properly logging in and out including empty state
This commit is contained in:
78
src/utils/api/general.ts
Normal file
78
src/utils/api/general.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import axios from 'axios'
|
||||
import { ctx, handleError, PagedResponse, userAgent } from './helpers'
|
||||
|
||||
export type Params = {
|
||||
method: 'get' | 'post' | 'put' | 'delete'
|
||||
domain: string
|
||||
url: string
|
||||
params?: {
|
||||
[key: string]: string | number | boolean | string[] | number[] | boolean[]
|
||||
}
|
||||
headers?: { [key: string]: string }
|
||||
body?: FormData | Object
|
||||
}
|
||||
|
||||
const apiGeneral = async <T = unknown>({
|
||||
method,
|
||||
domain,
|
||||
url,
|
||||
params,
|
||||
headers,
|
||||
body
|
||||
}: Params): Promise<PagedResponse<T>> => {
|
||||
console.log(
|
||||
ctx.bgGreen.bold(' API general ') +
|
||||
' ' +
|
||||
domain +
|
||||
' ' +
|
||||
method +
|
||||
ctx.green(' -> ') +
|
||||
`/${url}` +
|
||||
(params ? ctx.green(' -> ') : ''),
|
||||
params ? params : ''
|
||||
)
|
||||
|
||||
return axios({
|
||||
timeout: method === 'post' ? 1000 * 60 : 1000 * 15,
|
||||
method,
|
||||
baseURL: `https://${domain}/`,
|
||||
url,
|
||||
params,
|
||||
headers: {
|
||||
'Content-Type': body && body instanceof FormData ? 'multipart/form-data' : 'application/json',
|
||||
Accept: '*/*',
|
||||
...userAgent,
|
||||
...headers
|
||||
},
|
||||
...(body &&
|
||||
(body instanceof FormData
|
||||
? (body as (FormData & { _parts: [][] }) | undefined)?._parts?.length
|
||||
: Object.keys(body).length) && { data: body })
|
||||
})
|
||||
.then(response => {
|
||||
let links: {
|
||||
prev?: { id: string; isOffset: boolean }
|
||||
next?: { id: string; isOffset: boolean }
|
||||
} = {}
|
||||
|
||||
if (response.headers?.link) {
|
||||
const linksParsed = response.headers.link.matchAll(
|
||||
new RegExp('[?&](.*?_id|offset)=(.*?)>; *rel="(.*?)"', 'gi')
|
||||
)
|
||||
for (const link of linksParsed) {
|
||||
switch (link[3]) {
|
||||
case 'prev':
|
||||
links.prev = { id: link[2], isOffset: link[1].includes('offset') }
|
||||
break
|
||||
case 'next':
|
||||
links.next = { id: link[2], isOffset: link[1].includes('offset') }
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.resolve({ body: response.data, links })
|
||||
})
|
||||
.catch(handleError())
|
||||
}
|
||||
|
||||
export default apiGeneral
|
73
src/utils/api/helpers/index.ts
Normal file
73
src/utils/api/helpers/index.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import * as Sentry from '@sentry/react-native'
|
||||
import chalk from 'chalk'
|
||||
import Constants from 'expo-constants'
|
||||
import { Platform } from 'react-native'
|
||||
|
||||
const userAgent = {
|
||||
'User-Agent': `tooot/${Constants.expoConfig?.version} ${Platform.OS}/${Platform.Version}`
|
||||
}
|
||||
|
||||
const ctx = new chalk.Instance({ level: 3 })
|
||||
const handleError =
|
||||
(
|
||||
config: {
|
||||
message: string
|
||||
captureRequest?: { url: string; params: any; body: any }
|
||||
captureResponse?: boolean
|
||||
} | void
|
||||
) =>
|
||||
(error: any) => {
|
||||
const shouldReportToSentry = config && (config.captureRequest || config.captureResponse)
|
||||
shouldReportToSentry && Sentry.setContext('Error object', error)
|
||||
|
||||
if (config?.captureRequest) {
|
||||
Sentry.setContext('Error request', config.captureRequest)
|
||||
}
|
||||
|
||||
if (error?.response) {
|
||||
if (config?.captureResponse) {
|
||||
Sentry.setContext('Error response', {
|
||||
data: error.response.data,
|
||||
status: error.response.status,
|
||||
headers: error.response.headers
|
||||
})
|
||||
}
|
||||
|
||||
// The request was made and the server responded with a status code
|
||||
// that falls out of the range of 2xx
|
||||
console.error(
|
||||
ctx.bold(' API '),
|
||||
ctx.bold('response'),
|
||||
error.response.status,
|
||||
error.request._url,
|
||||
error?.response.data?.error || error?.response.message || 'Unknown error'
|
||||
)
|
||||
|
||||
shouldReportToSentry && Sentry.captureMessage(config.message)
|
||||
return Promise.reject({
|
||||
status: error?.response.status,
|
||||
message: error?.response.data?.error || error?.response.message || 'Unknown error'
|
||||
})
|
||||
} else if (error?.request) {
|
||||
// The request was made but no response was received
|
||||
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
||||
// http.ClientRequest in node.js
|
||||
console.error(ctx.bold(' API '), ctx.bold('request'), error)
|
||||
|
||||
shouldReportToSentry && Sentry.captureMessage(config.message)
|
||||
return Promise.reject(error)
|
||||
} else {
|
||||
console.error(ctx.bold(' API '), ctx.bold('internal'), error?.message)
|
||||
|
||||
shouldReportToSentry && Sentry.captureMessage(config.message)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
}
|
||||
|
||||
type LinkFormat = { id: string; isOffset: boolean }
|
||||
export type PagedResponse<T = unknown> = {
|
||||
body: T
|
||||
links: { prev?: LinkFormat; next?: LinkFormat }
|
||||
}
|
||||
|
||||
export { ctx, handleError, userAgent }
|
86
src/utils/api/instance.ts
Normal file
86
src/utils/api/instance.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { getAccountDetails } from '@utils/storage/actions'
|
||||
import axios, { AxiosRequestConfig } from 'axios'
|
||||
import { ctx, handleError, PagedResponse, userAgent } from './helpers'
|
||||
|
||||
export type Params = {
|
||||
method: 'get' | 'post' | 'put' | 'delete' | 'patch'
|
||||
version?: 'v1' | 'v2'
|
||||
url: string
|
||||
params?: {
|
||||
[key: string]: string | number | boolean | string[] | number[] | boolean[]
|
||||
}
|
||||
headers?: { [key: string]: string }
|
||||
body?: FormData
|
||||
extras?: Omit<AxiosRequestConfig, 'method' | 'url' | 'params' | 'headers' | 'data'>
|
||||
}
|
||||
|
||||
const apiInstance = async <T = unknown>({
|
||||
method,
|
||||
version = 'v1',
|
||||
url,
|
||||
params,
|
||||
headers,
|
||||
body,
|
||||
extras
|
||||
}: Params): Promise<PagedResponse<T>> => {
|
||||
const accountDetails = getAccountDetails(['auth.domain', 'auth.token'])
|
||||
if (!accountDetails) {
|
||||
console.warn(ctx.bgRed.white.bold(' API instance '), 'No account detail available')
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
if (!accountDetails['auth.domain'] || !accountDetails['auth.token']) {
|
||||
console.warn(ctx.bgRed.white.bold(' API ') + ' ' + 'No domain or token available')
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
console.log(
|
||||
ctx.bgGreen.bold(' API instance '),
|
||||
accountDetails['auth.domain'],
|
||||
method + ctx.green(' -> ') + `/${url}` + (params ? ctx.green(' -> ') : ''),
|
||||
params ? params : ''
|
||||
)
|
||||
|
||||
return axios({
|
||||
timeout: method === 'post' ? 1000 * 60 : 1000 * 15,
|
||||
method,
|
||||
baseURL: `https://${accountDetails['auth.domain']}/api/${version}/`,
|
||||
url,
|
||||
params,
|
||||
headers: {
|
||||
'Content-Type': body && body instanceof FormData ? 'multipart/form-data' : 'application/json',
|
||||
Accept: '*/*',
|
||||
...userAgent,
|
||||
...headers,
|
||||
Authorization: `Bearer ${accountDetails['auth.token']}`
|
||||
},
|
||||
...((body as (FormData & { _parts: [][] }) | undefined)?._parts.length && { data: body }),
|
||||
...extras
|
||||
})
|
||||
.then(response => {
|
||||
let links: {
|
||||
prev?: { id: string; isOffset: boolean }
|
||||
next?: { id: string; isOffset: boolean }
|
||||
} = {}
|
||||
|
||||
if (response.headers?.link) {
|
||||
const linksParsed = response.headers.link.matchAll(
|
||||
new RegExp('[?&](.*?_id|offset)=(.*?)>; *rel="(.*?)"', 'gi')
|
||||
)
|
||||
for (const link of linksParsed) {
|
||||
switch (link[3]) {
|
||||
case 'prev':
|
||||
links.prev = { id: link[2], isOffset: link[1].includes('offset') }
|
||||
break
|
||||
case 'next':
|
||||
links.next = { id: link[2], isOffset: link[1].includes('offset') }
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.resolve({ body: response.data, links })
|
||||
})
|
||||
.catch(handleError())
|
||||
}
|
||||
|
||||
export default apiInstance
|
69
src/utils/api/tooot.ts
Normal file
69
src/utils/api/tooot.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import { mapEnvironment } from '@utils/helpers/checkEnvironment'
|
||||
import axios from 'axios'
|
||||
import { ctx, handleError, userAgent } from './helpers'
|
||||
|
||||
export type Params = {
|
||||
method: 'get' | 'post' | 'put' | 'delete'
|
||||
url: string
|
||||
params?: {
|
||||
[key: string]: string | number | boolean | string[] | number[] | boolean[]
|
||||
}
|
||||
headers?: { [key: string]: string }
|
||||
body?: FormData | Object
|
||||
}
|
||||
|
||||
export const TOOOT_API_DOMAIN = mapEnvironment({
|
||||
release: 'api.tooot.app',
|
||||
candidate: 'api-candidate.tooot.app',
|
||||
development: 'api-development.tooot.app'
|
||||
})
|
||||
|
||||
const apiTooot = async <T = unknown>({
|
||||
method,
|
||||
url,
|
||||
params,
|
||||
headers,
|
||||
body
|
||||
}: Params): Promise<{ body: T }> => {
|
||||
console.log(
|
||||
ctx.bgGreen.bold(' API tooot ') +
|
||||
' ' +
|
||||
method +
|
||||
ctx.green(' -> ') +
|
||||
`/${url}` +
|
||||
(params ? ctx.green(' -> ') : ''),
|
||||
params ? params : ''
|
||||
)
|
||||
|
||||
return axios({
|
||||
timeout: method === 'post' ? 1000 * 60 : 1000 * 30,
|
||||
method,
|
||||
baseURL: `https://${TOOOT_API_DOMAIN}/`,
|
||||
url: `${url}`,
|
||||
params,
|
||||
headers: {
|
||||
'Content-Type': body && body instanceof FormData ? 'multipart/form-data' : 'application/json',
|
||||
Accept: '*/*',
|
||||
...userAgent,
|
||||
...headers
|
||||
},
|
||||
...(body &&
|
||||
(body instanceof FormData
|
||||
? (body as (FormData & { _parts: [][] }) | undefined)?._parts?.length
|
||||
: Object.keys(body).length) && { data: body })
|
||||
})
|
||||
.then(response => {
|
||||
return Promise.resolve({
|
||||
body: response.data
|
||||
})
|
||||
})
|
||||
.catch(
|
||||
handleError({
|
||||
message: 'API error',
|
||||
captureRequest: { url, params, body },
|
||||
captureResponse: true
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
export default apiTooot
|
Reference in New Issue
Block a user