chore: use axios instead of fetch

This commit is contained in:
boojack 2022-05-22 12:02:58 +08:00
parent a580df5c9f
commit b52c16c43f
30 changed files with 417 additions and 478 deletions

View File

@ -23,7 +23,6 @@
],
"@typescript-eslint/no-empty-interface": ["off"],
"@typescript-eslint/no-explicit-any": ["off"],
"react/react-in-jsx-scope": "off",
"@typescript-eslint/no-namespace": "off"
"react/react-in-jsx-scope": "off"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "memos",
"version": "2.0.6",
"version": "0.0.1",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
@ -9,6 +9,7 @@
},
"dependencies": {
"@reduxjs/toolkit": "^1.8.1",
"axios": "^0.27.2",
"lodash-es": "^4.17.21",
"react": "^18.1.0",
"react-dom": "^18.1.0",

View File

@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import api from "../helpers/api";
import * as api from "../helpers/api";
import Only from "./common/OnlyWhen";
import { showDialog } from "./Dialog";
import "../less/about-site-dialog.less";
@ -11,7 +11,10 @@ const AboutSiteDialog: React.FC<Props> = ({ destroy }: Props) => {
useEffect(() => {
try {
api.getSystemStatus().then(({ profile }) => {
api.getSystemStatus().then(({ data }) => {
const {
data: { profile },
} = data;
setProfile(profile);
});
} catch (error) {

View File

@ -1,5 +1,5 @@
import { IMAGE_URL_REG } from "../helpers/consts";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import { formatMemoContent } from "./Memo";
import Only from "./common/OnlyWhen";
import "../less/daily-memo.less";

View File

@ -4,7 +4,7 @@ import toImage from "../labs/html2image";
import useToggle from "../hooks/useToggle";
import useLoading from "../hooks/useLoading";
import { DAILY_TIMESTAMP } from "../helpers/consts";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import { showDialog } from "./Dialog";
import showPreviewImageDialog from "./PreviewImageDialog";
import DailyMemo from "./DailyMemo";

View File

@ -1,5 +1,5 @@
import { IMAGE_URL_REG } from "../helpers/consts";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import useToggle from "../hooks/useToggle";
import { memoService } from "../services";
import Only from "./common/OnlyWhen";

View File

@ -2,7 +2,7 @@ import { memo } from "react";
import { escape } from "lodash-es";
import { IMAGE_URL_REG, LINK_REG, MEMO_LINK_REG, TAG_REG, UNKNOWN_ID } from "../helpers/consts";
import { parseMarkedToHtml, parseRawTextToHtml } from "../helpers/marked";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import useToggle from "../hooks/useToggle";
import { editorStateService, memoService } from "../services";
import Only from "./common/OnlyWhen";

View File

@ -1,6 +1,6 @@
import { useState, useEffect, useCallback } from "react";
import { IMAGE_URL_REG, MEMO_LINK_REG, UNKNOWN_ID } from "../helpers/consts";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import { editorStateService, memoService } from "../services";
import { parseHtmlToRawText } from "../helpers/marked";
import { formatMemoContent } from "./Memo";

View File

@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef } from "react";
import { editorStateService, locationService, memoService, resourceService } from "../services";
import { useAppSelector } from "../store";
import { UNKNOWN_ID } from "../helpers/consts";
import { storage } from "../helpers/storage";
import * as storage from "../helpers/storage";
import useToggle from "../hooks/useToggle";
import toastHelper from "./Toast";
import Editor, { EditorRefActions } from "./Editor/Editor";

View File

@ -1,6 +1,6 @@
import { useAppSelector } from "../store";
import { locationService, shortcutService } from "../services";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import { getTextWithMemoType } from "../helpers/filter";
import "../less/memo-filter.less";

View File

@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
import { locationService, memoService, shortcutService } from "../services";
import { useAppSelector } from "../store";
import { IMAGE_URL_REG, LINK_REG, MEMO_LINK_REG, TAG_REG } from "../helpers/consts";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import { checkShouldShowMemoWithFilters } from "../helpers/filter";
import Memo from "./Memo";
import toastHelper from "./Toast";
@ -79,6 +79,7 @@ const MemoList: React.FC<Props> = () => {
const pinnedMemos = shownMemos.filter((m) => m.pinned);
const unpinnedMemos = shownMemos.filter((m) => !m.pinned);
const sortedMemos = pinnedMemos.concat(unpinnedMemos).filter((m) => m.rowStatus === "NORMAL");
console.log(memos.length, sortedMemos.length);
useEffect(() => {
memoService

View File

@ -14,7 +14,6 @@ const MemoTrashDialog: React.FC<Props> = (props: Props) => {
const [deletedMemos, setDeletedMemos] = useState<Memo[]>([]);
useEffect(() => {
memoService.fetchAllMemos();
memoService
.fetchDeletedMemos()
.then((result) => {

View File

@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from "react";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import { showDialog } from "./Dialog";
import "../less/preview-image-dialog.less";

View File

@ -1,6 +1,6 @@
import React, { useEffect, useState } from "react";
import { isEmpty } from "lodash-es";
import api from "../../helpers/api";
import * as api from "../../helpers/api";
import toastHelper from "../Toast";
import "../../less/settings/member-section.less";
@ -23,7 +23,7 @@ const PreferencesSection: React.FC<Props> = () => {
}, []);
const fetchUserList = async () => {
const data = await api.getUserList();
const { data } = (await api.getUserList()).data;
setUserList(data);
};

View File

@ -1,5 +1,5 @@
import { memoService } from "../../services";
import utils from "../../helpers/utils";
import * as utils from "../../helpers/utils";
import toastHelper from "../Toast";
import "../../less/settings/preferences-section.less";

View File

@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from "react";
import { userService } from "../services";
import toImage from "../labs/html2image";
import { ANIMATION_DURATION, IMAGE_URL_REG } from "../helpers/consts";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import { showDialog } from "./Dialog";
import { formatMemoContent } from "./Memo";
import Only from "./common/OnlyWhen";

View File

@ -2,7 +2,7 @@ import { useEffect } from "react";
import { locationService, shortcutService } from "../services";
import { useAppSelector } from "../store";
import { UNKNOWN_ID } from "../helpers/consts";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import useToggle from "../hooks/useToggle";
import useLoading from "../hooks/useLoading";
import toastHelper from "./Toast";

View File

@ -1,5 +1,5 @@
import { useAppSelector } from "../store";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import showDailyMemoDiaryDialog from "./DailyMemoDiaryDialog";
import showSettingDialog from "./SettingDialog";
import showMemoTrashDialog from "./MemoTrashDialog";

View File

@ -3,7 +3,7 @@ import { useAppSelector } from "../store";
import { locationService, memoService } from "../services";
import useToggle from "../hooks/useToggle";
import Only from "./common/OnlyWhen";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import "../less/tag-list.less";
interface Tag {

View File

@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
import { useAppSelector } from "../store";
import { locationService } from "../services";
import { DAILY_TIMESTAMP } from "../helpers/consts";
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import "../less/usage-heat-map.less";
const tableConfig = {

View File

@ -1,209 +1,99 @@
import axios from "axios";
type ResponseObject<T> = {
data: T;
error?: string;
message?: string;
};
type RequestConfig = {
method: string;
url: string;
data?: any;
dataType?: "json" | "file";
};
async function request<T>(config: RequestConfig): Promise<T> {
const { method, url, data, dataType } = config;
const requestConfig: RequestInit = {
method,
};
if (data !== undefined) {
if (dataType === "file") {
requestConfig.body = data;
} else {
requestConfig.headers = {
"Content-Type": "application/json",
};
requestConfig.body = JSON.stringify(data);
}
}
const response = await fetch(url, requestConfig);
const responseData = (await response.json()) as ResponseObject<T>;
if (responseData.error || responseData.message) {
throw new Error(responseData.error || responseData.message);
}
return responseData.data;
export function getSystemStatus() {
return axios.get<ResponseObject<SystemStatus>>("/api/status");
}
namespace api {
export function getSystemStatus() {
return request<SystemStatus>({
method: "GET",
url: "/api/status",
});
}
export function login(email: string, password: string) {
return request<User>({
method: "POST",
url: "/api/auth/login",
data: {
email,
password,
},
});
}
export function signup(email: string, password: string, role: UserRole) {
return request<User>({
method: "POST",
url: "/api/auth/signup",
data: {
email,
password,
role,
name: email,
},
});
}
export function signout() {
return request({
method: "POST",
url: "/api/auth/logout",
});
}
export function createUser(userCreate: UserCreate) {
return request<User[]>({
method: "POST",
url: "/api/user",
data: userCreate,
});
}
export function getUser() {
return request<User>({
method: "GET",
url: "/api/user/me",
});
}
export function getUserList() {
return request<User[]>({
method: "GET",
url: "/api/user",
});
}
export function patchUser(userPatch: UserPatch) {
return request<User>({
method: "PATCH",
url: "/api/user/me",
data: userPatch,
});
}
export function getMyMemos() {
return request<Memo[]>({
method: "GET",
url: "/api/memo",
});
}
export function getMyArchivedMemos() {
return request<Memo[]>({
method: "GET",
url: "/api/memo?rowStatus=ARCHIVED",
});
}
export function createMemo(memoCreate: MemoCreate) {
return request<Memo>({
method: "POST",
url: "/api/memo",
data: memoCreate,
});
}
export function patchMemo(memoPatch: MemoPatch) {
return request<Memo>({
method: "PATCH",
url: `/api/memo/${memoPatch.id}`,
data: {
memoPatch,
},
});
}
export function pinMemo(memoId: MemoId) {
return request({
method: "POST",
url: `/api/memo/${memoId}/organizer`,
data: {
pinned: true,
},
});
}
export function unpinMemo(memoId: MemoId) {
return request({
method: "POST",
url: `/api/memo/${memoId}/organizer`,
data: {
pinned: false,
},
});
}
export function deleteMemo(memoId: MemoId) {
return request({
method: "DELETE",
url: `/api/memo/${memoId}`,
});
}
export function getMyShortcuts() {
return request<Shortcut[]>({
method: "GET",
url: "/api/shortcut",
});
}
export function createShortcut(shortcutCreate: ShortcutCreate) {
return request<Shortcut>({
method: "POST",
url: "/api/shortcut",
data: shortcutCreate,
});
}
export function patchShortcut(shortcutPatch: ShortcutPatch) {
return request<Shortcut>({
method: "PATCH",
url: `/api/shortcut/${shortcutPatch.id}`,
data: shortcutPatch,
});
}
export function deleteShortcutById(shortcutId: ShortcutId) {
return request({
method: "DELETE",
url: `/api/shortcut/${shortcutId}`,
});
}
export function uploadFile(formData: FormData) {
return request<Resource>({
method: "POST",
url: "/api/resource",
data: formData,
dataType: "file",
});
}
export function login(email: string, password: string) {
return axios.post<ResponseObject<User>>("/api/auth/login", {
email,
password,
});
}
export default api;
export function signup(email: string, password: string, role: UserRole) {
return axios.post<ResponseObject<User>>("/api/auth/signup", {
email,
password,
role,
name: email,
});
}
export function signout() {
return axios.post("/api/auth/logout");
}
export function createUser(userCreate: UserCreate) {
return axios.post<ResponseObject<User>>("/api/user", userCreate);
}
export function getUser() {
return axios.get<ResponseObject<User>>("/api/user/me");
}
export function getUserList() {
return axios.get<ResponseObject<User[]>>("/api/user");
}
export function patchUser(userPatch: UserPatch) {
return axios.patch<ResponseObject<User>>("/api/user/me", userPatch);
}
export function getMyMemos() {
return axios.get<ResponseObject<Memo[]>>("/api/memo");
}
export function getMyArchivedMemos() {
return axios.get<ResponseObject<Memo[]>>("/api/memo?rowStatus=ARCHIVED");
}
export function createMemo(memoCreate: MemoCreate) {
return axios.post<ResponseObject<Memo>>("/api/memo", memoCreate);
}
export function patchMemo(memoPatch: MemoPatch) {
return axios.patch<ResponseObject<Memo>>(`/api/memo/${memoPatch.id}`, memoPatch);
}
export function pinMemo(memoId: MemoId) {
return axios.post(`/api/memo/${memoId}/organizer`, {
pinned: true,
});
}
export function unpinMemo(memoId: MemoId) {
return axios.post(`/api/memo/${memoId}/organizer`, {
pinned: false,
});
}
export function deleteMemo(memoId: MemoId) {
return axios.delete(`/api/memo/${memoId}`);
}
export function getMyShortcuts() {
return axios.get<ResponseObject<Shortcut[]>>("/api/shortcut");
}
export function createShortcut(shortcutCreate: ShortcutCreate) {
return axios.post<ResponseObject<Shortcut>>("/api/shortcut", shortcutCreate);
}
export function patchShortcut(shortcutPatch: ShortcutPatch) {
return axios.patch<ResponseObject<Shortcut>>(`/api/shortcut/${shortcutPatch.id}`, shortcutPatch);
}
export function deleteShortcutById(shortcutId: ShortcutId) {
return axios.delete(`/api/shortcut/${shortcutId}`);
}
export function uploadFile(formData: FormData) {
return axios.post<ResponseObject<Resource>>("/api/resource", formData);
}

View File

@ -14,52 +14,50 @@ type StorageKey = keyof StorageData;
/**
* storage helper
*/
export namespace storage {
export function get(keys: StorageKey[]): Partial<StorageData> {
const data: Partial<StorageData> = {};
export function get(keys: StorageKey[]): Partial<StorageData> {
const data: Partial<StorageData> = {};
for (const key of keys) {
try {
const stringifyValue = localStorage.getItem(key);
if (stringifyValue !== null) {
const val = JSON.parse(stringifyValue);
data[key] = val;
}
} catch (error: any) {
console.error("Get storage failed in ", key, error);
}
}
return data;
}
export function set(data: Partial<StorageData>) {
for (const key in data) {
try {
const stringifyValue = JSON.stringify(data[key as StorageKey]);
localStorage.setItem(key, stringifyValue);
} catch (error: any) {
console.error("Save storage failed in ", key, error);
for (const key of keys) {
try {
const stringifyValue = localStorage.getItem(key);
if (stringifyValue !== null) {
const val = JSON.parse(stringifyValue);
data[key] = val;
}
} catch (error: any) {
console.error("Get storage failed in ", key, error);
}
}
export function remove(keys: StorageKey[]) {
for (const key of keys) {
try {
localStorage.removeItem(key);
} catch (error: any) {
console.error("Remove storage failed in ", key, error);
}
return data;
}
export function set(data: Partial<StorageData>) {
for (const key in data) {
try {
const stringifyValue = JSON.stringify(data[key as StorageKey]);
localStorage.setItem(key, stringifyValue);
} catch (error: any) {
console.error("Save storage failed in ", key, error);
}
}
export function emitStorageChangedEvent() {
const iframeEl = document.createElement("iframe");
iframeEl.style.display = "none";
document.body.appendChild(iframeEl);
iframeEl.contentWindow?.localStorage.setItem("t", Date.now().toString());
iframeEl.remove();
}
}
export function remove(keys: StorageKey[]) {
for (const key of keys) {
try {
localStorage.removeItem(key);
} catch (error: any) {
console.error("Remove storage failed in ", key, error);
}
}
}
export function emitStorageChangedEvent() {
const iframeEl = document.createElement("iframe");
iframeEl.style.display = "none";
document.body.appendChild(iframeEl);
iframeEl.contentWindow?.localStorage.setItem("t", Date.now().toString());
iframeEl.remove();
}

View File

@ -1,223 +1,219 @@
namespace utils {
export function getNowTimeStamp(): number {
return Date.now();
export function getNowTimeStamp(): number {
return Date.now();
}
export function getOSVersion(): "Windows" | "MacOS" | "Linux" | "Unknown" {
const appVersion = navigator.userAgent;
let detectedOS: "Windows" | "MacOS" | "Linux" | "Unknown" = "Unknown";
if (appVersion.indexOf("Win") != -1) {
detectedOS = "Windows";
} else if (appVersion.indexOf("Mac") != -1) {
detectedOS = "MacOS";
} else if (appVersion.indexOf("Linux") != -1) {
detectedOS = "Linux";
}
export function getOSVersion(): "Windows" | "MacOS" | "Linux" | "Unknown" {
const appVersion = navigator.userAgent;
let detectedOS: "Windows" | "MacOS" | "Linux" | "Unknown" = "Unknown";
return detectedOS;
}
if (appVersion.indexOf("Win") != -1) {
detectedOS = "Windows";
} else if (appVersion.indexOf("Mac") != -1) {
detectedOS = "MacOS";
} else if (appVersion.indexOf("Linux") != -1) {
detectedOS = "Linux";
export function getTimeStampByDate(t: Date | number | string): number {
if (typeof t === "string") {
t = t.replaceAll("-", "/");
}
const d = new Date(t);
return d.getTime();
}
export function getDateStampByDate(t: Date | number | string): number {
const d = new Date(getTimeStampByDate(t));
return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
}
export function getDateString(t: Date | number | string): string {
const d = new Date(getTimeStampByDate(t));
const year = d.getFullYear();
const month = d.getMonth() + 1;
const date = d.getDate();
return `${year}/${month}/${date}`;
}
export function getDataStringWithTs(ts: number): string {
return getDateTimeString(ts * 1000);
}
export function getTimeString(t: Date | number | string): string {
const d = new Date(getTimeStampByDate(t));
const hours = d.getHours();
const mins = d.getMinutes();
const hoursStr = hours < 10 ? "0" + hours : hours;
const minsStr = mins < 10 ? "0" + mins : mins;
return `${hoursStr}:${minsStr}`;
}
// For example: 2021-4-8 17:52:17
export function getDateTimeString(t: Date | number | string): string {
const d = new Date(getTimeStampByDate(t));
const year = d.getFullYear();
const month = d.getMonth() + 1;
const date = d.getDate();
const hours = d.getHours();
const mins = d.getMinutes();
const secs = d.getSeconds();
const monthStr = month < 10 ? "0" + month : month;
const dateStr = date < 10 ? "0" + date : date;
const hoursStr = hours < 10 ? "0" + hours : hours;
const minsStr = mins < 10 ? "0" + mins : mins;
const secsStr = secs < 10 ? "0" + secs : secs;
return `${year}/${monthStr}/${dateStr} ${hoursStr}:${minsStr}:${secsStr}`;
}
export function dedupe<T>(data: T[]): T[] {
return Array.from(new Set(data));
}
export function dedupeObjectWithId<T extends { id: string | number }>(data: T[]): T[] {
const idSet = new Set<string | number>();
const result = [];
for (const d of data) {
if (!idSet.has(d.id)) {
idSet.add(d.id);
result.push(d);
}
return detectedOS;
}
export function getTimeStampByDate(t: Date | number | string): number {
if (typeof t === "string") {
t = t.replaceAll("-", "/");
return result;
}
export function debounce(fn: FunctionType, delay: number) {
let timer: number | null = null;
return () => {
if (timer) {
clearTimeout(timer);
timer = setTimeout(fn, delay);
} else {
timer = setTimeout(fn, delay);
}
const d = new Date(t);
};
}
return d.getTime();
}
export function throttle(fn: FunctionType, delay: number) {
let valid = true;
export function getDateStampByDate(t: Date | number | string): number {
const d = new Date(getTimeStampByDate(t));
return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();
}
export function getDateString(t: Date | number | string): string {
const d = new Date(getTimeStampByDate(t));
const year = d.getFullYear();
const month = d.getMonth() + 1;
const date = d.getDate();
return `${year}/${month}/${date}`;
}
export function getDataStringWithTs(ts: number): string {
return getDateTimeString(ts * 1000);
}
export function getTimeString(t: Date | number | string): string {
const d = new Date(getTimeStampByDate(t));
const hours = d.getHours();
const mins = d.getMinutes();
const hoursStr = hours < 10 ? "0" + hours : hours;
const minsStr = mins < 10 ? "0" + mins : mins;
return `${hoursStr}:${minsStr}`;
}
// For example: 2021-4-8 17:52:17
export function getDateTimeString(t: Date | number | string): string {
const d = new Date(getTimeStampByDate(t));
const year = d.getFullYear();
const month = d.getMonth() + 1;
const date = d.getDate();
const hours = d.getHours();
const mins = d.getMinutes();
const secs = d.getSeconds();
const monthStr = month < 10 ? "0" + month : month;
const dateStr = date < 10 ? "0" + date : date;
const hoursStr = hours < 10 ? "0" + hours : hours;
const minsStr = mins < 10 ? "0" + mins : mins;
const secsStr = secs < 10 ? "0" + secs : secs;
return `${year}/${monthStr}/${dateStr} ${hoursStr}:${minsStr}:${secsStr}`;
}
export function dedupe<T>(data: T[]): T[] {
return Array.from(new Set(data));
}
export function dedupeObjectWithId<T extends { id: string | number }>(data: T[]): T[] {
const idSet = new Set<string | number>();
const result = [];
for (const d of data) {
if (!idSet.has(d.id)) {
idSet.add(d.id);
result.push(d);
}
return () => {
if (!valid) {
return false;
}
valid = false;
setTimeout(() => {
fn();
valid = true;
}, delay);
};
}
return result;
}
export function transformObjectToParamsString(object: KVObject): string {
const params = [];
const keys = Object.keys(object).sort();
export function debounce(fn: FunctionType, delay: number) {
let timer: number | null = null;
return () => {
if (timer) {
clearTimeout(timer);
timer = setTimeout(fn, delay);
} else {
timer = setTimeout(fn, delay);
}
};
}
export function throttle(fn: FunctionType, delay: number) {
let valid = true;
return () => {
if (!valid) {
return false;
}
valid = false;
setTimeout(() => {
fn();
valid = true;
}, delay);
};
}
export function transformObjectToParamsString(object: KVObject): string {
const params = [];
const keys = Object.keys(object).sort();
for (const key of keys) {
const val = object[key];
if (val) {
if (typeof val === "object") {
params.push(...transformObjectToParamsString(val).split("&"));
} else {
params.push(`${key}=${val}`);
}
}
}
return params.join("&");
}
export function transformParamsStringToObject(paramsString: string): KVObject {
const object: KVObject = {};
const params = paramsString.split("&");
for (const p of params) {
const [key, val] = p.split("=");
if (key && val) {
object[key] = val;
}
}
return object;
}
export function filterObjectNullKeys(object: KVObject): KVObject {
if (!object) {
return {};
}
const finalObject: KVObject = {};
const keys = Object.keys(object).sort();
for (const key of keys) {
const val = object[key];
for (const key of keys) {
const val = object[key];
if (val) {
if (typeof val === "object") {
const temp = filterObjectNullKeys(JSON.parse(JSON.stringify(val)));
if (temp && Object.keys(temp).length > 0) {
finalObject[key] = temp;
}
params.push(...transformObjectToParamsString(val).split("&"));
} else {
if (val) {
finalObject[key] = val;
}
params.push(`${key}=${val}`);
}
}
return finalObject;
}
export async function copyTextToClipboard(text: string) {
if (navigator.clipboard && navigator.clipboard.writeText) {
try {
await navigator.clipboard.writeText(text);
} catch (error: unknown) {
console.warn("Copy to clipboard failed.", error);
return params.join("&");
}
export function transformParamsStringToObject(paramsString: string): KVObject {
const object: KVObject = {};
const params = paramsString.split("&");
for (const p of params) {
const [key, val] = p.split("=");
if (key && val) {
object[key] = val;
}
}
return object;
}
export function filterObjectNullKeys(object: KVObject): KVObject {
if (!object) {
return {};
}
const finalObject: KVObject = {};
const keys = Object.keys(object).sort();
for (const key of keys) {
const val = object[key];
if (typeof val === "object") {
const temp = filterObjectNullKeys(JSON.parse(JSON.stringify(val)));
if (temp && Object.keys(temp).length > 0) {
finalObject[key] = temp;
}
} else {
console.warn("Copy to clipboard failed, methods not supports.");
if (val) {
finalObject[key] = val;
}
}
}
export function getImageSize(src: string): Promise<{ width: number; height: number }> {
return new Promise((resolve) => {
const imgEl = new Image();
return finalObject;
}
imgEl.onload = () => {
const { width, height } = imgEl;
if (width > 0 && height > 0) {
resolve({ width, height });
} else {
resolve({ width: 0, height: 0 });
}
};
imgEl.onerror = () => {
resolve({ width: 0, height: 0 });
};
imgEl.className = "hidden";
imgEl.src = src;
document.body.appendChild(imgEl);
imgEl.remove();
});
export async function copyTextToClipboard(text: string) {
if (navigator.clipboard && navigator.clipboard.writeText) {
try {
await navigator.clipboard.writeText(text);
} catch (error: unknown) {
console.warn("Copy to clipboard failed.", error);
}
} else {
console.warn("Copy to clipboard failed, methods not supports.");
}
}
export default utils;
export function getImageSize(src: string): Promise<{ width: number; height: number }> {
return new Promise((resolve) => {
const imgEl = new Image();
imgEl.onload = () => {
const { width, height } = imgEl;
if (width > 0 && height > 0) {
resolve({ width, height });
} else {
resolve({ width: 0, height: 0 });
}
};
imgEl.onerror = () => {
resolve({ width: 0, height: 0 });
};
imgEl.className = "hidden";
imgEl.src = src;
document.body.appendChild(imgEl);
imgEl.remove();
});
}

View File

@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import api from "../helpers/api";
import * as api from "../helpers/api";
import { validate, ValidatorConfig } from "../helpers/validator";
import useLoading from "../hooks/useLoading";
import { locationService, userService } from "../services";
@ -23,7 +23,8 @@ const Signin: React.FC<Props> = () => {
const actionBtnLoadingState = useLoading(false);
useEffect(() => {
api.getSystemStatus().then((status) => {
api.getSystemStatus().then(({ data }) => {
const { data: status } = data;
setSiteOwner(status.owner);
if (status.profile.mode === "dev") {
setEmail("demo@usememos.com");

View File

@ -1,4 +1,4 @@
import utils from "../helpers/utils";
import * as utils from "../helpers/utils";
import store from "../store";
import { setQuery, setPathname, Query } from "../store/modules/location";

View File

@ -1,4 +1,4 @@
import api from "../helpers/api";
import * as api from "../helpers/api";
import { TAG_REG } from "../helpers/consts";
import { createMemo, patchMemo, setMemos, setTags } from "../store/modules/memo";
import store from "../store";
@ -17,7 +17,7 @@ const memoService = {
},
fetchAllMemos: async () => {
const data = await api.getMyMemos();
const { data } = (await api.getMyMemos()).data;
const memos = data.filter((m) => m.rowStatus !== "ARCHIVED").map((m) => convertResponseModelMemo(m));
store.dispatch(setMemos(memos));
@ -25,7 +25,7 @@ const memoService = {
},
fetchDeletedMemos: async () => {
const data = await api.getMyArchivedMemos();
const { data } = (await api.getMyArchivedMemos()).data;
const deletedMemos = data.map((m) => {
return convertResponseModelMemo(m);
});
@ -60,13 +60,13 @@ const memoService = {
},
createMemo: async (memoCreate: MemoCreate) => {
const data = await api.createMemo(memoCreate);
const { data } = (await api.createMemo(memoCreate)).data;
const memo = convertResponseModelMemo(data);
store.dispatch(createMemo(memo));
},
patchMemo: async (memoPatch: MemoPatch): Promise<Memo> => {
const data = await api.patchMemo(memoPatch);
const { data } = (await api.patchMemo(memoPatch)).data;
const memo = convertResponseModelMemo(data);
store.dispatch(patchMemo(memo));
return memo;

View File

@ -1,4 +1,4 @@
import api from "../helpers/api";
import * as api from "../helpers/api";
const resourceService = {
/**
@ -6,7 +6,7 @@ const resourceService = {
* @param file file
* @returns resource: id, filename
*/
async upload(file: File) {
async upload(file: File): Promise<Resource> {
const { name: filename, size } = file;
if (size > 64 << 20) {
@ -15,7 +15,7 @@ const resourceService = {
const formData = new FormData();
formData.append("file", file, filename);
const data = await api.uploadFile(formData);
const { data } = (await api.uploadFile(formData)).data;
return data;
},

View File

@ -1,4 +1,4 @@
import api from "../helpers/api";
import * as api from "../helpers/api";
import store from "../store/";
import { createShortcut, deleteShortcut, patchShortcut, setShortcuts } from "../store/modules/shortcut";
@ -16,8 +16,8 @@ const shortcutService = {
},
getMyAllShortcuts: async () => {
const rawData = await api.getMyShortcuts();
const shortcuts = rawData.map((s) => convertResponseModelShortcut(s));
const { data } = (await api.getMyShortcuts()).data;
const shortcuts = data.map((s) => convertResponseModelShortcut(s));
store.dispatch(setShortcuts(shortcuts));
},
@ -32,13 +32,13 @@ const shortcutService = {
},
createShortcut: async (shortcutCreate: ShortcutCreate) => {
const data = await api.createShortcut(shortcutCreate);
const { data } = (await api.createShortcut(shortcutCreate)).data;
const shortcut = convertResponseModelShortcut(data);
store.dispatch(createShortcut(shortcut));
},
patchShortcut: async (shortcutPatch: ShortcutPatch) => {
const data = await api.patchShortcut(shortcutPatch);
const { data } = (await api.patchShortcut(shortcutPatch)).data;
const shortcut = convertResponseModelShortcut(data);
store.dispatch(patchShortcut(shortcut));
},

View File

@ -1,4 +1,4 @@
import api from "../helpers/api";
import * as api from "../helpers/api";
import store from "../store";
import { setUser, patchUser } from "../store/modules/user";
@ -16,7 +16,7 @@ const userService = {
},
doSignIn: async () => {
const user = await api.getUser();
const { data: user } = (await api.getUser()).data;
if (user) {
store.dispatch(setUser(convertResponseModelUser(user)));
} else {
@ -31,7 +31,7 @@ const userService = {
},
patchUser: async (userPatch: UserPatch): Promise<void> => {
const data = await api.patchUser(userPatch);
const { data } = (await api.patchUser(userPatch)).data;
const user = convertResponseModelUser(data);
store.dispatch(patchUser(user));
},

View File

@ -589,6 +589,11 @@ array.prototype.flatmap@^1.2.5:
es-abstract "^1.19.2"
es-shim-unscopables "^1.0.0"
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
autoprefixer@^10.4.2:
version "10.4.4"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e"
@ -601,6 +606,14 @@ autoprefixer@^10.4.2:
picocolors "^1.0.0"
postcss-value-parser "^4.2.0"
axios@^0.27.2:
version "0.27.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
dependencies:
follow-redirects "^1.14.9"
form-data "^4.0.0"
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
@ -716,6 +729,13 @@ color-name@^1.1.4, color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
dependencies:
delayed-stream "~1.0.0"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -785,6 +805,11 @@ defined@^1.0.0:
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
detective@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b"
@ -1234,6 +1259,20 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3"
integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==
follow-redirects@^1.14.9:
version "1.15.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.0.tgz#06441868281c86d0dda4ad8bdaead2d02dca89d4"
integrity sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
fraction.js@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
@ -1665,6 +1704,18 @@ micromatch@^4.0.4:
braces "^3.0.2"
picomatch "^2.3.1"
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
mime@^1.4.1:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"