1
0
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:
xmflsct
2022-12-28 23:41:36 +01:00
committed by GitHub
parent 71ccb4a93c
commit 1ea6aff328
214 changed files with 2151 additions and 3694 deletions

78
src/utils/api/general.ts Normal file
View 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

View 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
View 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
View 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