Skip to content

Commit

Permalink
library sync
Browse files Browse the repository at this point in the history
  • Loading branch information
Last-Order committed Dec 16, 2021
1 parent bc834a7 commit 5cc4b31
Show file tree
Hide file tree
Showing 17 changed files with 969 additions and 148 deletions.
5 changes: 0 additions & 5 deletions .eslintrc

This file was deleted.

28 changes: 28 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["react", "@typescript-eslint"],
"rules": {},
"settings": {
"react": {
"version": "detect"
}
}
}
16 changes: 16 additions & 0 deletions mock/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,22 @@ export const credentialsMocks = [
};
},
},
{
url: "/api/credential",
method: "post",
response: () => {
return {
status: 0,
data: {
id: "c002a816-7aa2-48e7-8281-c8c44c574dbd",
name: "Test Library",
url: "https://annil.mmf.moe",
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjAsInR5cGUiOiJ1c2VyIiwidXNlcm5hbWUiOiJ0ZXN0IiwiYWxsb3dTaGFyZSI6dHJ1ZX0.7CH27OBvUnJhKxBdtZbJSXA-JIwQ4MWqI5JsZ46NoKk",
priority: 1,
},
};
},
},
{
url: "/api/credential",
method: "delete",
Expand Down
120 changes: 62 additions & 58 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,60 +1,64 @@
{
"name": "anniw",
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.4.0",
"@emotion/styled": "^11.3.0",
"@material-ui/core": "^5.0.0-beta.1",
"@material-ui/icons": "^5.0.0-beta.1",
"@mui/lab": "^5.0.0-alpha.59",
"@mui/material": "^5.2.3",
"axios": "^0.24.0",
"i18next": "^20.3.5",
"idb": "^7.0.0",
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-i18next": "^11.11.4",
"react-router-dom": "^5.2.0",
"recoil": "^0.5.2",
"workbox-background-sync": "^5.1.3",
"workbox-broadcast-update": "^5.1.3",
"workbox-cacheable-response": "^5.1.3",
"workbox-core": "^5.1.3",
"workbox-expiration": "^5.1.3",
"workbox-google-analytics": "^5.1.3",
"workbox-navigation-preload": "^5.1.3",
"workbox-precaching": "^5.1.3",
"workbox-range-requests": "^5.1.3",
"workbox-routing": "^5.1.3",
"workbox-strategies": "^5.1.3",
"workbox-streams": "^5.1.3"
},
"scripts": {
"start": "vite",
"build": "tsc && vite build",
"format": "prettier --write ./src/**/*"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@types/jest": "^26.0.15",
"@types/lodash": "^4.14.177",
"@types/material-ui": "^0.21.8",
"@types/node": "^16.11.12",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-router-dom": "^5.1.7",
"@vitejs/plugin-react-refresh": "^1.3.6",
"eslint": "^8.3.0",
"eslint-config-prettier": "^8.3.0",
"mockjs": "^1.1.0",
"prettier": "^2.5.0",
"sass": "^1.45.0",
"typescript": "^4.5.4",
"vite": "^2.7.2",
"vite-plugin-mock": "^2.9.6"
}
"name": "anniw",
"version": "0.1.0",
"private": true,
"dependencies": {
"@emotion/react": "^11.4.0",
"@emotion/styled": "^11.3.0",
"@material-ui/core": "^5.0.0-beta.1",
"@material-ui/icons": "^5.0.0-beta.1",
"@mui/lab": "^5.0.0-alpha.59",
"@mui/material": "^5.2.3",
"axios": "^0.24.0",
"i18next": "^20.3.5",
"idb": "^7.0.0",
"lodash": "^4.17.21",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-i18next": "^11.11.4",
"react-router-dom": "^5.2.0",
"recoil": "^0.5.2",
"workbox-background-sync": "^5.1.3",
"workbox-broadcast-update": "^5.1.3",
"workbox-cacheable-response": "^5.1.3",
"workbox-core": "^5.1.3",
"workbox-expiration": "^5.1.3",
"workbox-google-analytics": "^5.1.3",
"workbox-navigation-preload": "^5.1.3",
"workbox-precaching": "^5.1.3",
"workbox-range-requests": "^5.1.3",
"workbox-routing": "^5.1.3",
"workbox-strategies": "^5.1.3",
"workbox-streams": "^5.1.3"
},
"scripts": {
"start": "vite",
"build": "tsc && vite build",
"format": "prettier --write ./src/**/*"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@types/jest": "^26.0.15",
"@types/lodash": "^4.14.177",
"@types/material-ui": "^0.21.8",
"@types/node": "^16.11.12",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-router-dom": "^5.1.7",
"@typescript-eslint/eslint-plugin": "^5.7.0",
"@typescript-eslint/parser": "^5.7.0",
"@vitejs/plugin-react-refresh": "^1.3.6",
"eslint": "^8.3.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-react": "^7.27.1",
"eslint-plugin-react-hooks": "^4.3.0",
"mockjs": "^1.1.0",
"prettier": "^2.5.0",
"sass": "^1.45.0",
"typescript": "^4.5.4",
"vite": "^2.7.2",
"vite-plugin-mock": "^2.9.6"
}
}
65 changes: 30 additions & 35 deletions src/api/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ export class AnniwBusinessError extends Error {
}
}

export interface RequestOptions {
/** 是否从 Anniv 返回格式中直接取出 data 字段 */
unwrapResponse?: boolean;
}

type HttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";

class Request {
private base: string = "";
private base = "";
private instance: AxiosInstance;
constructor() {
this.instance = axios.create({
Expand All @@ -32,11 +37,11 @@ class Request {
* @param path
* @param payload
*/
request<T>(
async request<T>(
method: HttpMethod = "GET",
path: string = "/",
path = "/",
payload: Record<string, unknown> = {},
config?: AxiosRequestConfig
requestOptions?: RequestOptions
): Promise<T> {
console.log(`[${new Date().toISOString()}] ${method} ${path}`);
const options: AxiosRequestConfig = {
Expand All @@ -47,49 +52,47 @@ class Request {
: `${this.base}${path}`,
params: {},
data: {},
...config,
};
const { unwrapResponse = true } = requestOptions || {};
if (method === "GET") {
options.params = formatRequest(payload);
} else {
options.data = formatRequest(payload);
}
return new Promise(async (resolve, reject) => {
try {
const response = await this.instance.request(options);
const data = response.data;
try {
const response = await this.instance.request(options);
const data = response.data;
if (unwrapResponse) {
if (data.status !== 0) {
reject(new AnniwBusinessError(data.status, data.message));
throw new AnniwBusinessError(data.status, data.message);
} else {
resolve(formatResponse(data.data));
return formatResponse(data.data);
}
} catch (e) {
// Network Error
reject(this.parseError(e as any));
} else {
return formatResponse(data);
}
});
} catch (e) {
// Network Error
throw this.parseError(e as any);
}
}

/**
* HTTP GET
* @param path
* @param payload
*/
get<T>(path: string = "/", payload: Record<string, unknown> = {}, config?: AxiosRequestConfig) {
return this.request<T>("GET", path, payload, config);
get<T>(path = "/", payload: Record<string, unknown> = {}, requestOptions?: RequestOptions) {
return this.request<T>("GET", path, payload, requestOptions);
}

/**
* HTTP POST
* @param path
* @param payload
*/
post<T>(
path: string = "/",
payload: Record<string, unknown> = {},
config?: AxiosRequestConfig
) {
return this.request<T>("POST", path, payload, config);
post<T>(path = "/", payload: Record<string, unknown> = {}, requestOptions?: RequestOptions) {
return this.request<T>("POST", path, payload, requestOptions);
}

/**
Expand All @@ -98,12 +101,8 @@ class Request {
* @param payload
* @returns
*/
patch<T>(
path: string = "/",
payload: Record<string, unknown> = {},
config?: AxiosRequestConfig
) {
return this.request<T>("PATCH", path, payload, config);
patch<T>(path = "/", payload: Record<string, unknown> = {}, requestOptions?: RequestOptions) {
return this.request<T>("PATCH", path, payload, requestOptions);
}

/**
Expand All @@ -112,12 +111,8 @@ class Request {
* @param payload
* @returns
*/
delete<T>(
path: string = "/",
payload: Record<string, unknown> = {},
config?: AxiosRequestConfig
) {
return this.request<T>("DELETE", path, payload, config);
delete<T>(path = "/", payload: Record<string, unknown> = {}, requestOptions?: RequestOptions) {
return this.request<T>("DELETE", path, payload, requestOptions);
}

parseError(e: AxiosError): AnniwRequestError {
Expand Down
11 changes: 8 additions & 3 deletions src/components/Loading/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import React from "react";
import { CircularProgress } from "@material-ui/core";
import "./index.scss";

function Loading() {
return <div className="loading-container">Loading...</div>;
}
const Loading = () => {
return (
<div className="loading-container">
<CircularProgress />
</div>
);
};

export default Loading;
64 changes: 64 additions & 0 deletions src/db/album.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { openDB, deleteDB } from "idb";
import type { DBSchema, IDBPDatabase } from "idb";

const DB_VERSION = 1;
const DB_NAME = "anniw_album";

enum AlbumStoreNames {
AlbumLibraryMap = "album_library_map",
}

interface AlbumLibraryMapItem {
albumId: string;
availableLibraries: string[];
}

interface AlbumDB extends DBSchema {
[AlbumStoreNames.AlbumLibraryMap]: {
key: string;
value: AlbumLibraryMapItem;
};
}

class Album {
db: Promise<IDBPDatabase<AlbumDB>>;

constructor() {
this.db = openDB<AlbumDB>(DB_NAME, DB_VERSION, {
upgrade(db, oldVersion) {
// if (oldVersion) {
// db.deleteObjectStore(TABLE_NAME);
// }
db.createObjectStore(AlbumStoreNames.AlbumLibraryMap, {
keyPath: "albumId",
});
},
});
}

async get(storeName: AlbumStoreNames, albumId: string) {
return (await this.db).get(storeName, albumId);
}

async set(storeName: AlbumStoreNames, payload: AlbumLibraryMapItem) {
return (await this.db).put(storeName, payload);
}

async addAvailableLibrary(albumId: string, libraryUrl: string) {
const currentAvailableLibraryUrls =
(await this.get(AlbumStoreNames.AlbumLibraryMap, albumId))?.availableLibraries || [];
if (!currentAvailableLibraryUrls.includes(libraryUrl)) {
const newAvailableLibraryUrls = [...currentAvailableLibraryUrls, libraryUrl];
return this.set(AlbumStoreNames.AlbumLibraryMap, {
albumId,
availableLibraries: newAvailableLibraryUrls,
});
}
}

async dropAllStores() {
return await deleteDB(DB_NAME);
}
}

export default new Album();
Loading

0 comments on commit 5cc4b31

Please sign in to comment.