+22
-2
@@ -1,6 +1,6 @@
|
||||
import { siteId, url } from './settings';
|
||||
import { BASE_URL } from './constants';
|
||||
import { Config, Comment, Tree, User, BlockedUser, Sorting, AuthProvider, BlockTTL } from './types';
|
||||
import { BASE_URL, API_BASE } from './constants';
|
||||
import { Config, Comment, Tree, User, BlockedUser, Sorting, AuthProvider, BlockTTL, Image } from './types';
|
||||
import fetcher from './fetcher';
|
||||
|
||||
/* common */
|
||||
@@ -234,6 +234,25 @@ export const enableComments = (): Promise<void> =>
|
||||
withCredentials: true,
|
||||
});
|
||||
|
||||
export const uploadImage = (image: File): Promise<Image> => {
|
||||
const data = new FormData();
|
||||
data.append('file', image);
|
||||
|
||||
return fetcher
|
||||
.post<{ id: string }>({
|
||||
url: `/picture`,
|
||||
withCredentials: true,
|
||||
contentType: 'multipart/form-data',
|
||||
body: data,
|
||||
})
|
||||
.then(resp => ({
|
||||
name: image.name,
|
||||
size: image.size,
|
||||
type: image.type,
|
||||
url: BASE_URL + API_BASE + '/picture/' + resp.id,
|
||||
}));
|
||||
};
|
||||
|
||||
export default {
|
||||
logIn,
|
||||
logOut,
|
||||
@@ -260,4 +279,5 @@ export default {
|
||||
getBlocked,
|
||||
disableComments,
|
||||
enableComments,
|
||||
uploadImage,
|
||||
};
|
||||
|
||||
+31
-12
@@ -6,29 +6,46 @@ import { getCookie } from './cookies';
|
||||
export type FetcherMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head';
|
||||
const methods: FetcherMethod[] = ['get', 'post', 'put', 'patch', 'delete', 'head'];
|
||||
|
||||
type FetcherInit =
|
||||
| string
|
||||
| {
|
||||
url: string;
|
||||
body?: string | object | Blob | ArrayBuffer;
|
||||
overriddenApiBase?: string;
|
||||
withCredentials?: boolean;
|
||||
};
|
||||
interface FetcherInitBase {
|
||||
url: string;
|
||||
overriddenApiBase?: string;
|
||||
withCredentials?: boolean;
|
||||
}
|
||||
|
||||
interface FetcherInitJSON extends FetcherInitBase {
|
||||
contentType?: 'application/json';
|
||||
body?: string | object | Blob | ArrayBuffer;
|
||||
}
|
||||
|
||||
interface FetcherInitMultipart extends FetcherInitBase {
|
||||
contentType: 'multipart/form-data';
|
||||
body: FormData;
|
||||
}
|
||||
|
||||
type FetcherInit = string | FetcherInitJSON | FetcherInitMultipart;
|
||||
|
||||
type FetcherObject = { [K in FetcherMethod]: <T = unknown>(data: FetcherInit) => Promise<T> };
|
||||
|
||||
const fetcher = methods.reduce<Partial<FetcherObject>>((acc, method) => {
|
||||
acc[method] = <T = unknown>(data: FetcherInit): Promise<T> => {
|
||||
const { url, body = undefined, withCredentials = false, overriddenApiBase = API_BASE } =
|
||||
typeof data === 'string' ? { url: data } : data;
|
||||
const {
|
||||
url,
|
||||
body = undefined,
|
||||
withCredentials = false,
|
||||
overriddenApiBase = API_BASE,
|
||||
contentType = 'application/json',
|
||||
} = typeof data === 'string' ? { url: data } : data;
|
||||
const basename = `${BASE_URL}${overriddenApiBase}`;
|
||||
|
||||
const headers = new Headers({
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'X-XSRF-TOKEN': getCookie('XSRF-TOKEN') || '',
|
||||
});
|
||||
|
||||
if (contentType !== 'multipart/form-data') {
|
||||
headers.append('Content-Type', contentType);
|
||||
}
|
||||
|
||||
let rurl = `${basename}${url}`;
|
||||
|
||||
const parameters: RequestInit = {
|
||||
@@ -39,7 +56,9 @@ const fetcher = methods.reduce<Partial<FetcherObject>>((acc, method) => {
|
||||
};
|
||||
|
||||
if (body) {
|
||||
if (typeof body === 'object') {
|
||||
if (contentType === 'multipart/form-data') {
|
||||
parameters.body = body as FormData;
|
||||
} else if (typeof body === 'object' && !(body instanceof Blob) && !(body instanceof ArrayBuffer)) {
|
||||
parameters.body = JSON.stringify(body);
|
||||
} else {
|
||||
parameters.body = body;
|
||||
|
||||
@@ -25,6 +25,7 @@ export const StaticStore: StaticStoreType = {
|
||||
low_score: 0,
|
||||
positive_score: false,
|
||||
readonly_age: 0,
|
||||
max_image_size: 0,
|
||||
},
|
||||
query: querySettings as QuerySettingsType,
|
||||
};
|
||||
|
||||
@@ -101,6 +101,7 @@ export interface Config {
|
||||
critical_score: number;
|
||||
positive_score: boolean;
|
||||
readonly_age: number;
|
||||
max_image_size: number;
|
||||
}
|
||||
|
||||
export interface RemarkConfig {
|
||||
@@ -138,3 +139,23 @@ export enum CommentMode {
|
||||
Reply,
|
||||
Edit,
|
||||
}
|
||||
|
||||
/**
|
||||
* Used as api.uploadImage response type
|
||||
*/
|
||||
export interface Image {
|
||||
name: string;
|
||||
size: number;
|
||||
/** mime type of an image */
|
||||
type: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
/** error struct returned in case of api call error */
|
||||
export interface ApiError {
|
||||
code: number;
|
||||
/** simple explanation */
|
||||
details: string;
|
||||
/** in-depth explanation */
|
||||
error: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user