mirror of
https://github.com/usememos/memos.git
synced 2024-12-21 10:11:42 +03:00
chore: update store types
This commit is contained in:
parent
bc22f69ac5
commit
6fe1db42b5
@ -38,7 +38,7 @@ const AboutSiteDialog: React.FC<Props> = ({ destroy }: Props) => {
|
||||
</div>
|
||||
<div className="dialog-content-container">
|
||||
<p>
|
||||
Memos is an open source, quickly self-hosted alternative to <a href="https://flomoapp.com">flomo</a>.
|
||||
Memos is an <i>open source</i>, <i>self-hosted</i> knowledge base that works with local SQLite.
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
|
@ -44,7 +44,7 @@ const ConfirmResetOpenIdDialog: React.FC<Props> = ({ destroy }: Props) => {
|
||||
</div>
|
||||
<div className="dialog-content-container">
|
||||
<p className="warn-text">
|
||||
⚠️ The existing API will be invalidated and a new one will be generated, are you sure you want to reset?
|
||||
❗️The existing API will be invalidated and a new one will be generated, are you sure you want to reset?
|
||||
</p>
|
||||
<div className="btns-container">
|
||||
<span className="btn cancel-btn" onClick={handleCloseBtnClick}>
|
||||
|
@ -4,20 +4,21 @@ import { formatMemoContent } from "./Memo";
|
||||
import Only from "./common/OnlyWhen";
|
||||
import "../less/daily-memo.less";
|
||||
|
||||
interface DailyMemo extends FormattedMemo {
|
||||
interface DailyMemo extends Memo {
|
||||
createdAtStr: string;
|
||||
timeStr: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
memo: Model.Memo;
|
||||
memo: Memo;
|
||||
}
|
||||
|
||||
const DailyMemo: React.FC<Props> = (props: Props) => {
|
||||
const { memo: propsMemo } = props;
|
||||
const memo: DailyMemo = {
|
||||
...propsMemo,
|
||||
createdAtStr: utils.getDateTimeString(propsMemo.createdAt),
|
||||
timeStr: utils.getTimeString(propsMemo.createdAt),
|
||||
createdAtStr: utils.getDateTimeString(propsMemo.createdTs),
|
||||
timeStr: utils.getTimeString(propsMemo.createdTs),
|
||||
};
|
||||
const imageUrls = Array.from(memo.content.match(IMAGE_URL_REG) ?? []);
|
||||
|
||||
|
@ -20,7 +20,7 @@ const weekdayChineseStrArray = ["周日", "周一", "周二", "周三", "周四"
|
||||
|
||||
const DailyMemoDiaryDialog: React.FC<Props> = (props: Props) => {
|
||||
const loadingState = useLoading();
|
||||
const [memos, setMemos] = useState<Model.Memo[]>([]);
|
||||
const [memos, setMemos] = useState<Memo[]>([]);
|
||||
const [currentDateStamp, setCurrentDateStamp] = useState(utils.getDateStampByDate(utils.getDateString(props.currentDateStamp)));
|
||||
const [showDatePicker, toggleShowDatePicker] = useToggle(false);
|
||||
const memosElRef = useRef<HTMLDivElement>(null);
|
||||
@ -32,10 +32,10 @@ const DailyMemoDiaryDialog: React.FC<Props> = (props: Props) => {
|
||||
.getState()
|
||||
.memos.filter(
|
||||
(a) =>
|
||||
utils.getTimeStampByDate(a.createdAt) >= currentDateStamp &&
|
||||
utils.getTimeStampByDate(a.createdAt) < currentDateStamp + DAILY_TIMESTAMP
|
||||
utils.getTimeStampByDate(a.createdTs) >= currentDateStamp &&
|
||||
utils.getTimeStampByDate(a.createdTs) < currentDateStamp + DAILY_TIMESTAMP
|
||||
)
|
||||
.sort((a, b) => utils.getTimeStampByDate(a.createdAt) - utils.getTimeStampByDate(b.createdAt));
|
||||
.sort((a, b) => utils.getTimeStampByDate(a.createdTs) - utils.getTimeStampByDate(b.createdTs));
|
||||
setMemos(dailyMemos);
|
||||
loadingState.setFinish();
|
||||
};
|
||||
@ -115,7 +115,7 @@ const DailyMemoDiaryDialog: React.FC<Props> = (props: Props) => {
|
||||
) : (
|
||||
<div className="dailymemos-wrapper">
|
||||
{memos.map((memo) => (
|
||||
<DailyMemo key={`${memo.id}-${memo.updatedAt}`} memo={memo} />
|
||||
<DailyMemo key={`${memo.id}-${memo.updatedTs}`} memo={memo} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
@ -9,16 +9,16 @@ import { formatMemoContent } from "./Memo";
|
||||
import "../less/memo.less";
|
||||
|
||||
interface Props {
|
||||
memo: Model.Memo;
|
||||
handleDeletedMemoAction: (memoId: string) => void;
|
||||
memo: Memo;
|
||||
handleDeletedMemoAction: (memoId: MemoId) => void;
|
||||
}
|
||||
|
||||
const DeletedMemo: React.FC<Props> = (props: Props) => {
|
||||
const { memo: propsMemo, handleDeletedMemoAction } = props;
|
||||
const memo: FormattedMemo = {
|
||||
const memo = {
|
||||
...propsMemo,
|
||||
createdAtStr: utils.getDateTimeString(propsMemo.createdAt),
|
||||
deletedAtStr: utils.getDateTimeString(propsMemo.updatedAt ?? Date.now()),
|
||||
createdAtStr: utils.getDateTimeString(propsMemo.createdTs),
|
||||
deletedAtStr: utils.getDateTimeString(propsMemo.updatedTs ?? Date.now()),
|
||||
};
|
||||
const [showConfirmDeleteBtn, toggleConfirmDeleteBtn] = useToggle(false);
|
||||
const imageUrls = Array.from(memo.content.match(IMAGE_URL_REG) ?? []);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { memo } from "react";
|
||||
import { escape } from "lodash-es";
|
||||
import { IMAGE_URL_REG, LINK_REG, MEMO_LINK_REG, TAG_REG } from "../helpers/consts";
|
||||
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 useToggle from "../hooks/useToggle";
|
||||
@ -13,14 +13,14 @@ import toastHelper from "./Toast";
|
||||
import "../less/memo.less";
|
||||
|
||||
interface Props {
|
||||
memo: Model.Memo;
|
||||
memo: Memo;
|
||||
}
|
||||
|
||||
const Memo: React.FC<Props> = (props: Props) => {
|
||||
const { memo: propsMemo } = props;
|
||||
const memo: FormattedMemo = {
|
||||
const memo = {
|
||||
...propsMemo,
|
||||
createdAtStr: utils.getDateTimeString(propsMemo.createdAt),
|
||||
createdAtStr: utils.getDateTimeString(propsMemo.createdTs),
|
||||
};
|
||||
const [showConfirmDeleteBtn, toggleConfirmDeleteBtn] = useToggle(false);
|
||||
const imageUrls = Array.from(memo.content.match(IMAGE_URL_REG) ?? []);
|
||||
@ -31,17 +31,17 @@ const Memo: React.FC<Props> = (props: Props) => {
|
||||
|
||||
const handleTogglePinMemoBtnClick = async () => {
|
||||
try {
|
||||
if (memo.rowStatus === "ARCHIVED") {
|
||||
if (memo.pinned) {
|
||||
await memoService.unpinMemo(memo.id);
|
||||
memoService.editMemo({
|
||||
...memo,
|
||||
rowStatus: "NORMAL",
|
||||
pinned: false,
|
||||
});
|
||||
} else {
|
||||
await memoService.pinMemo(memo.id);
|
||||
memoService.editMemo({
|
||||
...memo,
|
||||
rowStatus: "ARCHIVED",
|
||||
pinned: true,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@ -66,7 +66,7 @@ const Memo: React.FC<Props> = (props: Props) => {
|
||||
}
|
||||
|
||||
if (globalStateService.getState().editMemoId === memo.id) {
|
||||
globalStateService.setEditMemoId("");
|
||||
globalStateService.setEditMemoId(UNKNOWN_ID);
|
||||
}
|
||||
} else {
|
||||
toggleConfirmDeleteBtn();
|
||||
@ -88,7 +88,7 @@ const Memo: React.FC<Props> = (props: Props) => {
|
||||
|
||||
if (targetEl.className === "memo-link-text") {
|
||||
const memoId = targetEl.dataset?.value;
|
||||
const memoTemp = memoService.getMemoById(memoId ?? "");
|
||||
const memoTemp = memoService.getMemoById(Number(memoId) ?? UNKNOWN_ID);
|
||||
|
||||
if (memoTemp) {
|
||||
showMemoCardDialog(memoTemp);
|
||||
@ -102,11 +102,11 @@ const Memo: React.FC<Props> = (props: Props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`memo-wrapper ${"memos-" + memo.id} ${memo.rowStatus}`} onMouseLeave={handleMouseLeaveMemoWrapper}>
|
||||
<div className={`memo-wrapper ${"memos-" + memo.id} ${memo.pinned ? "pinned" : ""}`} onMouseLeave={handleMouseLeaveMemoWrapper}>
|
||||
<div className="memo-top-wrapper">
|
||||
<span className="time-text" onClick={handleShowMemoStoryDialog}>
|
||||
{memo.createdAtStr}
|
||||
<Only when={memo.rowStatus === "ARCHIVED"}>
|
||||
<Only when={memo.pinned}>
|
||||
<span className="ml-2">PINNED</span>
|
||||
</Only>
|
||||
</span>
|
||||
@ -120,7 +120,7 @@ const Memo: React.FC<Props> = (props: Props) => {
|
||||
View Story
|
||||
</span>
|
||||
<span className="btn" onClick={handleTogglePinMemoBtnClick}>
|
||||
{memo.rowStatus === "NORMAL" ? "Pin" : "Unpin"}
|
||||
{memo.pinned ? "Unpin" : "Pin"}
|
||||
</span>
|
||||
<span className="btn" onClick={handleMarkMemoClick}>
|
||||
Mark
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { IMAGE_URL_REG, MEMO_LINK_REG } from "../helpers/consts";
|
||||
import { IMAGE_URL_REG, MEMO_LINK_REG, UNKNOWN_ID } from "../helpers/consts";
|
||||
import utils from "../helpers/utils";
|
||||
import { globalStateService, memoService } from "../services";
|
||||
import { parseHtmlToRawText } from "../helpers/marked";
|
||||
@ -11,18 +11,18 @@ import Image from "./Image";
|
||||
import "../less/memo-card-dialog.less";
|
||||
import "../less/memo-content.less";
|
||||
|
||||
interface LinkedMemo extends FormattedMemo {
|
||||
interface LinkedMemo extends Memo {
|
||||
createdAtStr: string;
|
||||
dateStr: string;
|
||||
}
|
||||
|
||||
interface Props extends DialogProps {
|
||||
memo: Model.Memo;
|
||||
memo: Memo;
|
||||
}
|
||||
|
||||
const MemoCardDialog: React.FC<Props> = (props: Props) => {
|
||||
const [memo, setMemo] = useState<FormattedMemo>({
|
||||
const [memo, setMemo] = useState<Memo>({
|
||||
...props.memo,
|
||||
createdAtStr: utils.getDateTimeString(props.memo.createdAt),
|
||||
});
|
||||
const [linkMemos, setLinkMemos] = useState<LinkedMemo[]>([]);
|
||||
const [linkedMemos, setLinkedMemos] = useState<LinkedMemo[]>([]);
|
||||
@ -36,12 +36,12 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
|
||||
for (const matchRes of matchedArr) {
|
||||
if (matchRes && matchRes.length === 3) {
|
||||
const id = matchRes[2];
|
||||
const memoTemp = memoService.getMemoById(id);
|
||||
const memoTemp = memoService.getMemoById(Number(id));
|
||||
if (memoTemp) {
|
||||
linkMemos.push({
|
||||
...memoTemp,
|
||||
createdAtStr: utils.getDateTimeString(memoTemp.createdAt),
|
||||
dateStr: utils.getDateString(memoTemp.createdAt),
|
||||
createdAtStr: utils.getDateTimeString(memoTemp.createdTs),
|
||||
dateStr: utils.getDateString(memoTemp.createdTs),
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -51,11 +51,11 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
|
||||
const linkedMemos = await memoService.getLinkedMemos(memo.id);
|
||||
setLinkedMemos(
|
||||
linkedMemos
|
||||
.sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt))
|
||||
.sort((a, b) => utils.getTimeStampByDate(b.createdTs) - utils.getTimeStampByDate(a.createdTs))
|
||||
.map((m) => ({
|
||||
...m,
|
||||
createdAtStr: utils.getDateTimeString(m.createdAt),
|
||||
dateStr: utils.getDateString(m.createdAt),
|
||||
createdAtStr: utils.getDateTimeString(m.createdTs),
|
||||
dateStr: utils.getDateString(m.createdTs),
|
||||
}))
|
||||
);
|
||||
} catch (error) {
|
||||
@ -71,12 +71,12 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
|
||||
|
||||
if (targetEl.className === "memo-link-text") {
|
||||
const nextMemoId = targetEl.dataset?.value;
|
||||
const memoTemp = memoService.getMemoById(nextMemoId ?? "");
|
||||
const memoTemp = memoService.getMemoById(Number(nextMemoId) ?? UNKNOWN_ID);
|
||||
|
||||
if (memoTemp) {
|
||||
const nextMemo = {
|
||||
...memoTemp,
|
||||
createdAtStr: utils.getDateTimeString(memoTemp.createdAt),
|
||||
createdAtStr: utils.getDateTimeString(memoTemp.createdTs),
|
||||
};
|
||||
setLinkMemos([]);
|
||||
setLinkedMemos([]);
|
||||
@ -88,7 +88,7 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleLinkedMemoClick = useCallback((memo: FormattedMemo) => {
|
||||
const handleLinkedMemoClick = useCallback((memo: Memo) => {
|
||||
setLinkMemos([]);
|
||||
setLinkedMemos([]);
|
||||
setMemo(memo);
|
||||
@ -103,7 +103,7 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
|
||||
<>
|
||||
<div className="memo-card-container">
|
||||
<div className="header-container">
|
||||
<p className="time-text">{memo.createdAtStr}</p>
|
||||
<p className="time-text">{utils.getDateTimeString(memo.createdTs)}</p>
|
||||
<div className="btns-container">
|
||||
<button className="btn edit-btn" onClick={handleEditMemoBtnClick}>
|
||||
<img className="icon-img" src="/icons/edit.svg" />
|
||||
@ -179,7 +179,7 @@ const MemoCardDialog: React.FC<Props> = (props: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default function showMemoCardDialog(memo: Model.Memo): void {
|
||||
export default function showMemoCardDialog(memo: Memo): void {
|
||||
showDialog(
|
||||
{
|
||||
className: "memo-card-dialog",
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useCallback, useContext, useEffect, useMemo, useRef } from "react";
|
||||
import appContext from "../stores/appContext";
|
||||
import { globalStateService, locationService, memoService, resourceService } from "../services";
|
||||
import utils from "../helpers/utils";
|
||||
import { UNKNOWN_ID } from "../helpers/consts";
|
||||
import { storage } from "../helpers/storage";
|
||||
import useToggle from "../hooks/useToggle";
|
||||
import toastHelper from "./Toast";
|
||||
@ -53,14 +53,14 @@ const MemoEditor: React.FC<Props> = () => {
|
||||
const tagSeletorRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (globalState.markMemoId) {
|
||||
if (globalState.markMemoId !== UNKNOWN_ID) {
|
||||
const editorCurrentValue = editorRef.current?.getContent();
|
||||
const memoLinkText = `${editorCurrentValue ? "\n" : ""}Mark: [@MEMO](${globalState.markMemoId})`;
|
||||
editorRef.current?.insertText(memoLinkText);
|
||||
globalStateService.setMarkMemoId("");
|
||||
globalStateService.setMarkMemoId(UNKNOWN_ID);
|
||||
}
|
||||
|
||||
if (globalState.editMemoId && globalState.editMemoId !== prevGlobalStateRef.current.editMemoId) {
|
||||
if (globalState.editMemoId !== UNKNOWN_ID && globalState.editMemoId !== prevGlobalStateRef.current.editMemoId) {
|
||||
const editMemo = memoService.getMemoById(globalState.editMemoId);
|
||||
if (editMemo) {
|
||||
editorRef.current?.setContent(editMemo.content ?? "");
|
||||
@ -147,15 +147,15 @@ const MemoEditor: React.FC<Props> = () => {
|
||||
const { editMemoId } = globalStateService.getState();
|
||||
|
||||
try {
|
||||
if (editMemoId) {
|
||||
if (editMemoId !== UNKNOWN_ID) {
|
||||
const prevMemo = memoService.getMemoById(editMemoId);
|
||||
|
||||
if (prevMemo && prevMemo.content !== content) {
|
||||
const editedMemo = await memoService.updateMemo(prevMemo.id, content);
|
||||
editedMemo.updatedAt = utils.getDateTimeString(Date.now());
|
||||
editedMemo.createdTs = Date.now();
|
||||
memoService.editMemo(editedMemo);
|
||||
}
|
||||
globalStateService.setEditMemoId("");
|
||||
globalStateService.setEditMemoId(UNKNOWN_ID);
|
||||
} else {
|
||||
const newMemo = await memoService.createMemo(content);
|
||||
memoService.pushMemo(newMemo);
|
||||
@ -169,7 +169,7 @@ const MemoEditor: React.FC<Props> = () => {
|
||||
}, []);
|
||||
|
||||
const handleCancelBtnClick = useCallback(() => {
|
||||
globalStateService.setEditMemoId("");
|
||||
globalStateService.setEditMemoId(UNKNOWN_ID);
|
||||
editorRef.current?.setContent("");
|
||||
setEditorContentCache("");
|
||||
}, []);
|
||||
@ -259,7 +259,7 @@ const MemoEditor: React.FC<Props> = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const isEditing = Boolean(globalState.editMemoId);
|
||||
const isEditing = globalState.editMemoId !== UNKNOWN_ID;
|
||||
|
||||
const editorConfig = useMemo(
|
||||
() => ({
|
||||
|
@ -53,7 +53,7 @@ const MemoList: React.FC<Props> = () => {
|
||||
if (
|
||||
duration &&
|
||||
duration.from < duration.to &&
|
||||
(utils.getTimeStampByDate(memo.createdAt) < duration.from || utils.getTimeStampByDate(memo.createdAt) > duration.to)
|
||||
(utils.getTimeStampByDate(memo.createdTs) < duration.from || utils.getTimeStampByDate(memo.createdTs) > duration.to)
|
||||
) {
|
||||
shouldShow = false;
|
||||
}
|
||||
@ -76,8 +76,8 @@ const MemoList: React.FC<Props> = () => {
|
||||
})
|
||||
: memos;
|
||||
|
||||
const pinnedMemos = shownMemos.filter((m) => m.rowStatus === "ARCHIVED");
|
||||
const unpinnedMemos = shownMemos.filter((m) => m.rowStatus === "NORMAL");
|
||||
const pinnedMemos = shownMemos.filter((m) => m.pinned);
|
||||
const unpinnedMemos = shownMemos.filter((m) => !m.pinned);
|
||||
const sortedMemos = pinnedMemos.concat(unpinnedMemos);
|
||||
|
||||
useEffect(() => {
|
||||
@ -112,7 +112,7 @@ const MemoList: React.FC<Props> = () => {
|
||||
return (
|
||||
<div className={`memo-list-container ${isFetching ? "" : "completed"}`} onClick={handleMemoListClick} ref={wrapperElement}>
|
||||
{sortedMemos.map((memo) => (
|
||||
<Memo key={`${memo.id}-${memo.updatedAt}`} memo={memo} />
|
||||
<Memo key={`${memo.id}-${memo.updatedTs}`} memo={memo} />
|
||||
))}
|
||||
<div className="status-text-container">
|
||||
<p className="status-text">
|
||||
|
@ -11,7 +11,7 @@ interface Props extends DialogProps {}
|
||||
const MemoTrashDialog: React.FC<Props> = (props: Props) => {
|
||||
const { destroy } = props;
|
||||
const loadingState = useLoading();
|
||||
const [deletedMemos, setDeletedMemos] = useState<Model.Memo[]>([]);
|
||||
const [deletedMemos, setDeletedMemos] = useState<Memo[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
memoService.fetchAllMemos();
|
||||
@ -31,7 +31,7 @@ const MemoTrashDialog: React.FC<Props> = (props: Props) => {
|
||||
locationService.clearQuery();
|
||||
}, []);
|
||||
|
||||
const handleDeletedMemoAction = useCallback((memoId: string) => {
|
||||
const handleDeletedMemoAction = useCallback((memoId: MemoId) => {
|
||||
setDeletedMemos((deletedMemos) => deletedMemos.filter((memo) => memo.id !== memoId));
|
||||
}, []);
|
||||
|
||||
@ -58,7 +58,7 @@ const MemoTrashDialog: React.FC<Props> = (props: Props) => {
|
||||
) : (
|
||||
<div className="deleted-memos-container">
|
||||
{deletedMemos.map((memo) => (
|
||||
<DeletedMemo key={`${memo.id}-${memo.updatedAt}`} memo={memo} handleDeletedMemoAction={handleDeletedMemoAction} />
|
||||
<DeletedMemo key={`${memo.id}-${memo.updatedTs}`} memo={memo} handleDeletedMemoAction={handleDeletedMemoAction} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
@ -16,7 +16,7 @@ const PreferencesSection: React.FC<Props> = () => {
|
||||
createUserEmail: "",
|
||||
createUserPassword: "",
|
||||
});
|
||||
const [userList, setUserList] = useState<Model.User[]>([]);
|
||||
const [userList, setUserList] = useState<User[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchUserList();
|
||||
@ -47,7 +47,7 @@ const PreferencesSection: React.FC<Props> = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const userCreate: API.UserCreate = {
|
||||
const userCreate: UserCreate = {
|
||||
email: state.createUserEmail,
|
||||
password: state.createUserPassword,
|
||||
role: "USER",
|
||||
@ -83,10 +83,18 @@ const PreferencesSection: React.FC<Props> = () => {
|
||||
</div>
|
||||
</div>
|
||||
<p className="title-text">Member list</p>
|
||||
<div className="member-container field-container">
|
||||
<span className="field-text">ID</span>
|
||||
<span className="field-text">EMAIL</span>
|
||||
</div>
|
||||
{userList.map((user) => (
|
||||
<div key={user.id} className="user-container">
|
||||
<div key={user.id} className="member-container">
|
||||
<span className="field-text id-text">{user.id}</span>
|
||||
<span className="field-text">{user.email}</span>
|
||||
<span className="field-text email-text">{user.email}</span>
|
||||
{/* TODO */}
|
||||
{/* <div className="buttons-container">
|
||||
<span>delete</span>
|
||||
</div> */}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { useContext, useState } from "react";
|
||||
import appContext from "../../stores/appContext";
|
||||
import { userService } from "../../services";
|
||||
import utils from "../../helpers/utils";
|
||||
import { validate, ValidatorConfig } from "../../helpers/validator";
|
||||
import toastHelper from "../Toast";
|
||||
import showChangePasswordDialog from "../ChangePasswordDialog";
|
||||
@ -19,7 +18,7 @@ interface Props {}
|
||||
|
||||
const MyAccountSection: React.FC<Props> = () => {
|
||||
const { userState } = useContext(appContext);
|
||||
const user = userState.user as Model.User;
|
||||
const user = userState.user as User;
|
||||
const [username, setUsername] = useState<string>(user.name);
|
||||
const openAPIRoute = `${window.location.origin}/h/${user.openId}/memo`;
|
||||
|
||||
@ -69,10 +68,6 @@ const MyAccountSection: React.FC<Props> = () => {
|
||||
<span className="normal-text">Email:</span>
|
||||
<span className="normal-text">{user.email}</span>
|
||||
</label>
|
||||
<label className="form-label">
|
||||
<span className="normal-text">Created at:</span>
|
||||
<span className="normal-text">{utils.getDateString(user.createdAt)}</span>
|
||||
</label>
|
||||
<label className="form-label input-form-label username-label">
|
||||
<span className="normal-text">Username:</span>
|
||||
<input type="text" value={username} onChange={handleUsernameChanged} />
|
||||
|
@ -10,7 +10,7 @@ const PreferencesSection: React.FC<Props> = () => {
|
||||
const formatedMemos = memoService.getState().memos.map((m) => {
|
||||
return {
|
||||
content: m.content,
|
||||
createdAt: m.createdAt,
|
||||
createdTs: m.createdTs,
|
||||
};
|
||||
});
|
||||
|
||||
@ -33,7 +33,7 @@ const PreferencesSection: React.FC<Props> = () => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsText(fileInputEl.files[0]);
|
||||
reader.onload = async (event) => {
|
||||
const memoList = JSON.parse(event.target?.result as string) as Model.Memo[];
|
||||
const memoList = JSON.parse(event.target?.result as string) as Memo[];
|
||||
if (!Array.isArray(memoList)) {
|
||||
toastHelper.error("Unexpected data type.");
|
||||
}
|
||||
@ -42,7 +42,7 @@ const PreferencesSection: React.FC<Props> = () => {
|
||||
|
||||
for (const memo of memoList) {
|
||||
const content = memo.content || "";
|
||||
const createdAt = memo.createdAt || utils.getDateTimeString(Date.now());
|
||||
const createdAt = utils.getDateTimeString(memo.createdTs || Date.now());
|
||||
|
||||
try {
|
||||
await memoService.importMemo(content, createdAt);
|
||||
|
@ -10,15 +10,15 @@ import toastHelper from "./Toast";
|
||||
import "../less/share-memo-image-dialog.less";
|
||||
|
||||
interface Props extends DialogProps {
|
||||
memo: Model.Memo;
|
||||
memo: Memo;
|
||||
}
|
||||
|
||||
const ShareMemoImageDialog: React.FC<Props> = (props: Props) => {
|
||||
const { memo: propsMemo, destroy } = props;
|
||||
const { user: userinfo } = userService.getState();
|
||||
const memo: FormattedMemo = {
|
||||
const memo = {
|
||||
...propsMemo,
|
||||
createdAtStr: utils.getDateTimeString(propsMemo.createdAt),
|
||||
createdAtStr: utils.getDateTimeString(propsMemo.createdTs),
|
||||
};
|
||||
const memoImgUrls = Array.from(memo.content.match(IMAGE_URL_REG) ?? []);
|
||||
|
||||
@ -106,7 +106,7 @@ const ShareMemoImageDialog: React.FC<Props> = (props: Props) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default function showShareMemoImageDialog(memo: Model.Memo): void {
|
||||
export default function showShareMemoImageDialog(memo: Memo): void {
|
||||
showDialog(
|
||||
{
|
||||
className: "share-memo-image-dialog",
|
||||
|
@ -20,10 +20,10 @@ const ShortcutList: React.FC<Props> = () => {
|
||||
const loadingState = useLoading();
|
||||
const pinnedShortcuts = shortcuts
|
||||
.filter((s) => s.rowStatus === "ARCHIVED")
|
||||
.sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt));
|
||||
.sort((a, b) => utils.getTimeStampByDate(b.createdTs) - utils.getTimeStampByDate(a.createdTs));
|
||||
const unpinnedShortcuts = shortcuts
|
||||
.filter((s) => s.rowStatus === "NORMAL")
|
||||
.sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt));
|
||||
.sort((a, b) => utils.getTimeStampByDate(b.createdTs) - utils.getTimeStampByDate(a.createdTs));
|
||||
const sortedShortcuts = pinnedShortcuts.concat(unpinnedShortcuts);
|
||||
|
||||
useEffect(() => {
|
||||
@ -55,7 +55,7 @@ const ShortcutList: React.FC<Props> = () => {
|
||||
};
|
||||
|
||||
interface ShortcutContainerProps {
|
||||
shortcut: Model.Shortcut;
|
||||
shortcut: Shortcut;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ const Sidebar: React.FC<Props> = () => {
|
||||
memoState: { memos, tags },
|
||||
userState: { user },
|
||||
} = useContext(appContext);
|
||||
const createdDays = user ? Math.ceil((Date.now() - utils.getTimeStampByDate(user.createdAt)) / 1000 / 3600 / 24) : 0;
|
||||
const createdDays = user ? Math.ceil((Date.now() - utils.getTimeStampByDate(user.createdTs)) / 1000 / 3600 / 24) : 0;
|
||||
|
||||
const handleMyAccountBtnClick = () => {
|
||||
showSettingDialog();
|
||||
|
@ -77,7 +77,7 @@ const TagList: React.FC<Props> = () => {
|
||||
))}
|
||||
<Only when={tags.length < 5 && memoService.initialized}>
|
||||
<p className="tag-tip-container">
|
||||
Enter <span className="code-text">#Tag </span> to create a tag
|
||||
Enter <span className="code-text">#tag </span> to create a tag
|
||||
</p>
|
||||
</Only>
|
||||
</div>
|
||||
|
@ -1,5 +1,3 @@
|
||||
import utils from "./utils";
|
||||
|
||||
type ResponseObject<T> = {
|
||||
data: T;
|
||||
error?: string;
|
||||
@ -42,29 +40,14 @@ async function request<T>(config: RequestConfig): Promise<T> {
|
||||
|
||||
namespace api {
|
||||
export function getSystemStatus() {
|
||||
return request<API.SystemStatus>({
|
||||
return request<SystemStatus>({
|
||||
method: "GET",
|
||||
url: "/api/status",
|
||||
});
|
||||
}
|
||||
|
||||
export function getUserList() {
|
||||
return request<Model.User[]>({
|
||||
method: "GET",
|
||||
url: "/api/user",
|
||||
});
|
||||
}
|
||||
|
||||
export function createUser(userCreate: API.UserCreate) {
|
||||
return request<Model.User[]>({
|
||||
method: "POST",
|
||||
url: "/api/user",
|
||||
data: userCreate,
|
||||
});
|
||||
}
|
||||
|
||||
export function login(email: string, password: string) {
|
||||
return request<Model.User>({
|
||||
return request<User>({
|
||||
method: "POST",
|
||||
url: "/api/auth/login",
|
||||
data: {
|
||||
@ -75,7 +58,7 @@ namespace api {
|
||||
}
|
||||
|
||||
export function signup(email: string, password: string, role: UserRole) {
|
||||
return request<Model.User>({
|
||||
return request<User>({
|
||||
method: "POST",
|
||||
url: "/api/auth/signup",
|
||||
data: {
|
||||
@ -94,70 +77,89 @@ namespace api {
|
||||
});
|
||||
}
|
||||
|
||||
export function getUserInfo() {
|
||||
return request<Model.User>({
|
||||
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 updateUserinfo(userinfo: Partial<{ name: string; password: string; resetOpenId: boolean }>) {
|
||||
return request<Model.User>({
|
||||
method: "PATCH",
|
||||
url: "/api/user/me",
|
||||
data: userinfo,
|
||||
export function getUserList() {
|
||||
return request<User[]>({
|
||||
method: "GET",
|
||||
url: "/api/user",
|
||||
});
|
||||
}
|
||||
|
||||
export function resetOpenId() {
|
||||
return request<string>({
|
||||
method: "POST",
|
||||
url: "/api/user/open_id/new",
|
||||
export function patchUser(userPatch: UserPatch) {
|
||||
return request<User>({
|
||||
method: "PATCH",
|
||||
url: "/api/user/me",
|
||||
data: userPatch,
|
||||
});
|
||||
}
|
||||
|
||||
export function getMyMemos() {
|
||||
return request<Model.Memo[]>({
|
||||
return request<Memo[]>({
|
||||
method: "GET",
|
||||
url: "/api/memo",
|
||||
});
|
||||
}
|
||||
|
||||
export function getMyDeletedMemos() {
|
||||
return request<Model.Memo[]>({
|
||||
export function getMyArchivedMemos() {
|
||||
return request<Memo[]>({
|
||||
method: "GET",
|
||||
url: "/api/memo?rowStatus=HIDDEN",
|
||||
url: "/api/memo?rowStatus=ARCHIVED",
|
||||
});
|
||||
}
|
||||
|
||||
export function createMemo(content: string, createdAt?: string) {
|
||||
const data: any = {
|
||||
content,
|
||||
};
|
||||
|
||||
if (createdAt) {
|
||||
const createdTms = utils.getTimeStampByDate(createdAt);
|
||||
data.createdTs = Math.floor(createdTms / 1000);
|
||||
}
|
||||
|
||||
return request<Model.Memo>({
|
||||
export function createMemo(memoCreate: MemoCreate) {
|
||||
return request<Memo>({
|
||||
method: "POST",
|
||||
url: "/api/memo",
|
||||
data: data,
|
||||
data: memoCreate,
|
||||
});
|
||||
}
|
||||
|
||||
export function updateMemo(memoId: string, content: string) {
|
||||
return request<Model.Memo>({
|
||||
export function patchMemo(memoPatch: MemoPatch) {
|
||||
return request<Memo>({
|
||||
method: "PATCH",
|
||||
url: `/api/memo/${memoId}`,
|
||||
url: `/api/memo/${memoPatch.id}`,
|
||||
data: {
|
||||
content,
|
||||
memoPatch,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function pinMemo(memoId: string) {
|
||||
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 archiveMemo(memoId: MemoId) {
|
||||
return request({
|
||||
method: "PATCH",
|
||||
url: `/api/memo/${memoId}`,
|
||||
@ -167,27 +169,7 @@ namespace api {
|
||||
});
|
||||
}
|
||||
|
||||
export function unpinMemo(shortcutId: string) {
|
||||
return request({
|
||||
method: "PATCH",
|
||||
url: `/api/memo/${shortcutId}`,
|
||||
data: {
|
||||
rowStatus: "NORMAL",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function hideMemo(memoId: string) {
|
||||
return request({
|
||||
method: "PATCH",
|
||||
url: `/api/memo/${memoId}`,
|
||||
data: {
|
||||
rowStatus: "HIDDEN",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function restoreMemo(memoId: string) {
|
||||
export function restoreMemo(memoId: MemoId) {
|
||||
return request({
|
||||
method: "PATCH",
|
||||
url: `/api/memo/${memoId}`,
|
||||
@ -197,7 +179,7 @@ namespace api {
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteMemo(memoId: string) {
|
||||
export function deleteMemo(memoId: MemoId) {
|
||||
return request({
|
||||
method: "DELETE",
|
||||
url: `/api/memo/${memoId}`,
|
||||
@ -205,14 +187,14 @@ namespace api {
|
||||
}
|
||||
|
||||
export function getMyShortcuts() {
|
||||
return request<Model.Shortcut[]>({
|
||||
return request<Shortcut[]>({
|
||||
method: "GET",
|
||||
url: "/api/shortcut",
|
||||
});
|
||||
}
|
||||
|
||||
export function createShortcut(title: string, payload: string) {
|
||||
return request<Model.Shortcut>({
|
||||
return request<Shortcut>({
|
||||
method: "POST",
|
||||
url: "/api/shortcut",
|
||||
data: {
|
||||
@ -223,7 +205,7 @@ namespace api {
|
||||
}
|
||||
|
||||
export function updateShortcut(shortcutId: string, title: string, payload: string) {
|
||||
return request<Model.Shortcut>({
|
||||
return request<Shortcut>({
|
||||
method: "PATCH",
|
||||
url: `/api/shortcut/${shortcutId}`,
|
||||
data: {
|
||||
@ -261,7 +243,7 @@ namespace api {
|
||||
}
|
||||
|
||||
export function uploadFile(formData: FormData) {
|
||||
return request<Model.Resource>({
|
||||
return request<Resource>({
|
||||
method: "POST",
|
||||
url: "/api/resource",
|
||||
data: formData,
|
||||
|
@ -1,3 +1,6 @@
|
||||
// UNKNOWN_ID is the symbol for unknown id
|
||||
export const UNKNOWN_ID = -1;
|
||||
|
||||
// default animation duration
|
||||
export const ANIMATION_DURATION = 200;
|
||||
|
||||
|
@ -90,7 +90,7 @@ export const getDefaultFilter = (): BaseFilter => {
|
||||
};
|
||||
};
|
||||
|
||||
export const checkShouldShowMemoWithFilters = (memo: Model.Memo, filters: Filter[]) => {
|
||||
export const checkShouldShowMemoWithFilters = (memo: Memo, filters: Filter[]) => {
|
||||
let shouldShow = true;
|
||||
|
||||
for (const f of filters) {
|
||||
@ -106,7 +106,7 @@ export const checkShouldShowMemoWithFilters = (memo: Model.Memo, filters: Filter
|
||||
return shouldShow;
|
||||
};
|
||||
|
||||
export const checkShouldShowMemo = (memo: Model.Memo, filter: Filter) => {
|
||||
export const checkShouldShowMemo = (memo: Memo, filter: Filter) => {
|
||||
const {
|
||||
type,
|
||||
value: { operator, value },
|
||||
|
@ -83,8 +83,8 @@ namespace utils {
|
||||
return Array.from(new Set(data));
|
||||
}
|
||||
|
||||
export function dedupeObjectWithId<T extends { id: string }>(data: T[]): T[] {
|
||||
const idSet = new Set<string>();
|
||||
export function dedupeObjectWithId<T extends { id: string | number }>(data: T[]): T[] {
|
||||
const idSet = new Set<string | number>();
|
||||
const result = [];
|
||||
|
||||
for (const d of data) {
|
||||
|
@ -9,7 +9,7 @@
|
||||
@apply border-gray-200;
|
||||
}
|
||||
|
||||
&.ARCHIVED {
|
||||
&.pinned {
|
||||
@apply border-gray-200 border-2;
|
||||
}
|
||||
|
||||
|
@ -25,15 +25,29 @@
|
||||
}
|
||||
}
|
||||
|
||||
> .user-container {
|
||||
@apply w-full mb-4 grid grid-cols-5;
|
||||
> .field-container {
|
||||
> .field-text {
|
||||
@apply text-gray-400 text-sm;
|
||||
}
|
||||
}
|
||||
|
||||
> .member-container {
|
||||
@apply w-full grid grid-cols-5 border-b py-2;
|
||||
|
||||
> .field-text {
|
||||
@apply text-base mr-4 w-16;
|
||||
@apply text-base pl-2 mr-4 w-16;
|
||||
|
||||
&.id-text {
|
||||
@apply font-mono;
|
||||
@apply font-mono text-gray-600;
|
||||
}
|
||||
|
||||
&.email-text {
|
||||
@apply col-span-3;
|
||||
}
|
||||
}
|
||||
|
||||
> .buttons-container {
|
||||
@apply col-span-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||
> .shortcut-container {
|
||||
.flex(row, space-between, center);
|
||||
@apply w-full h-10 py-0 px-4 mt-1 rounded-lg text-sm cursor-pointer select-none shrink-0;
|
||||
@apply w-full h-10 py-0 px-4 mt-2 rounded-lg text-base cursor-pointer select-none shrink-0;
|
||||
|
||||
&:hover {
|
||||
background-color: @bg-gray;
|
||||
|
@ -5,14 +5,21 @@
|
||||
@apply w-full h-full bg-white;
|
||||
|
||||
> .page-container {
|
||||
@apply w-80 max-w-full p-4 -mt-16;
|
||||
@apply w-80 max-w-full py-4 -mt-16;
|
||||
|
||||
> .page-header-container {
|
||||
.flex(row, space-between, center);
|
||||
@apply w-full mb-4;
|
||||
@apply flex flex-col justify-start items-start w-full mb-4;
|
||||
|
||||
> .title-text {
|
||||
@apply text-2xl;
|
||||
|
||||
> .icon-text {
|
||||
@apply text-4xl;
|
||||
}
|
||||
}
|
||||
|
||||
> .slogan-text {
|
||||
@apply mt-2 text-sm text-gray-600;
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,7 +29,7 @@
|
||||
|
||||
> .form-item-container {
|
||||
.flex(column, flex-start, flex-start);
|
||||
@apply relative w-full text-base my-2;
|
||||
@apply relative w-full text-base mt-2;
|
||||
|
||||
> .normal-text {
|
||||
@apply absolute top-3 left-3 px-1 leading-10 flex-shrink-0 text-base cursor-text text-gray-400 bg-transparent transition-all select-none;
|
||||
@ -36,7 +43,7 @@
|
||||
@apply py-2;
|
||||
|
||||
> input {
|
||||
@apply w-full py-3 px-3 text-base rounded-lg border border-solid border-gray-400;
|
||||
@apply w-full py-3 px-3 text-base shadow-inner rounded-lg border border-solid border-gray-400;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@ -51,22 +58,14 @@
|
||||
@apply w-full mt-2;
|
||||
|
||||
> .btn {
|
||||
@apply px-1 py-2 text-sm rounded;
|
||||
|
||||
&:hover {
|
||||
@apply opacity-80;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
@apply text-gray-400 cursor-not-allowed;
|
||||
}
|
||||
@apply px-1 py-2 text-sm rounded hover:opacity-80;
|
||||
|
||||
&.signin-btn {
|
||||
@apply bg-green-600 text-white px-3;
|
||||
@apply bg-green-600 text-white px-3 shadow;
|
||||
}
|
||||
|
||||
&.requesting {
|
||||
@apply cursor-wait opacity-80;
|
||||
}
|
||||
&.requesting {
|
||||
@apply cursor-wait opacity-80;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
.tag-item-container {
|
||||
.flex(row, space-between, center);
|
||||
@apply w-full h-10 py-0 px-4 rounded-lg text-sm shrink-0 select-none cursor-pointer;
|
||||
@apply w-full h-10 py-0 px-4 rounded-lg text-base shrink-0 select-none cursor-pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: @bg-gray;
|
||||
|
@ -17,7 +17,7 @@ const validateConfig: ValidatorConfig = {
|
||||
|
||||
const Signin: React.FC<Props> = () => {
|
||||
const pageLoadingState = useLoading(true);
|
||||
const [siteOwner, setSiteOwner] = useState<Model.User>();
|
||||
const [siteOwner, setSiteOwner] = useState<User>();
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const actionBtnLoadingState = useLoading(false);
|
||||
@ -128,12 +128,15 @@ const Signin: React.FC<Props> = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="page-wrapper signin">
|
||||
<div className={`page-wrapper signin ${pageLoadingState.isLoading ? "hidden" : ""}`}>
|
||||
<div className="page-container">
|
||||
<div className="page-header-container">
|
||||
<p className="title-text">
|
||||
<span className="icon-text">✍️</span> Memos
|
||||
</p>
|
||||
<p className="slogan-text">
|
||||
An <i>open source</i>, <i>self-hosted</i> knowledge base that works with local SQLite.
|
||||
</p>
|
||||
</div>
|
||||
<div className="page-content-container">
|
||||
<div className="form-item-container input-form-container">
|
||||
@ -150,7 +153,7 @@ const Signin: React.FC<Props> = () => {
|
||||
Login as Guest
|
||||
</button>
|
||||
<span className="split-text">/</span>
|
||||
{siteOwner || pageLoadingState.isLoading ? (
|
||||
{siteOwner ? (
|
||||
<button
|
||||
className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
|
||||
onClick={() => handleSigninBtnsClick()}
|
||||
@ -167,7 +170,7 @@ const Signin: React.FC<Props> = () => {
|
||||
)}
|
||||
</div>
|
||||
<p className="tip-text">
|
||||
{siteOwner || pageLoadingState.isLoading
|
||||
{siteOwner
|
||||
? "If you don't have an account, please contact the site owner or login as guest."
|
||||
: "You are registering as the site owner."}
|
||||
</p>
|
||||
|
@ -18,7 +18,7 @@ class GlobalStateService {
|
||||
return appStore.getState().globalState;
|
||||
};
|
||||
|
||||
public setEditMemoId = (editMemoId: string) => {
|
||||
public setEditMemoId = (editMemoId: MemoId) => {
|
||||
appStore.dispatch({
|
||||
type: "SET_EDIT_MEMO_ID",
|
||||
payload: {
|
||||
@ -27,7 +27,7 @@ class GlobalStateService {
|
||||
});
|
||||
};
|
||||
|
||||
public setMarkMemoId = (markMemoId: string) => {
|
||||
public setMarkMemoId = (markMemoId: MemoId) => {
|
||||
appStore.dispatch({
|
||||
type: "SET_MARK_MEMO_ID",
|
||||
payload: {
|
||||
|
@ -17,7 +17,7 @@ class MemoService {
|
||||
}
|
||||
|
||||
const data = await api.getMyMemos();
|
||||
const memos: Model.Memo[] = data.filter((m) => m.rowStatus !== "HIDDEN").map((m) => this.convertResponseModelMemo(m));
|
||||
const memos: Memo[] = data.filter((m) => m.rowStatus !== "ARCHIVED").map((m) => this.convertResponseModelMemo(m));
|
||||
appStore.dispatch({
|
||||
type: "SET_MEMOS",
|
||||
payload: {
|
||||
@ -37,14 +37,14 @@ class MemoService {
|
||||
return false;
|
||||
}
|
||||
|
||||
const data = await api.getMyDeletedMemos();
|
||||
const deletedMemos: Model.Memo[] = data.map((m) => {
|
||||
const data = await api.getMyArchivedMemos();
|
||||
const deletedMemos: Memo[] = data.map((m) => {
|
||||
return this.convertResponseModelMemo(m);
|
||||
});
|
||||
return deletedMemos;
|
||||
}
|
||||
|
||||
public pushMemo(memo: Model.Memo) {
|
||||
public pushMemo(memo: Memo) {
|
||||
appStore.dispatch({
|
||||
type: "INSERT_MEMO",
|
||||
payload: {
|
||||
@ -55,7 +55,7 @@ class MemoService {
|
||||
});
|
||||
}
|
||||
|
||||
public getMemoById(id: string) {
|
||||
public getMemoById(id: MemoId) {
|
||||
for (const m of this.getState().memos) {
|
||||
if (m.id === id) {
|
||||
return m;
|
||||
@ -65,8 +65,8 @@ class MemoService {
|
||||
return null;
|
||||
}
|
||||
|
||||
public async hideMemoById(id: string) {
|
||||
await api.hideMemo(id);
|
||||
public async hideMemoById(id: MemoId) {
|
||||
await api.archiveMemo(id);
|
||||
appStore.dispatch({
|
||||
type: "DELETE_MEMO_BY_ID",
|
||||
payload: {
|
||||
@ -75,17 +75,17 @@ class MemoService {
|
||||
});
|
||||
}
|
||||
|
||||
public async restoreMemoById(id: string) {
|
||||
public async restoreMemoById(id: MemoId) {
|
||||
await api.restoreMemo(id);
|
||||
memoService.clearMemos();
|
||||
memoService.fetchAllMemos();
|
||||
}
|
||||
|
||||
public async deleteMemoById(id: string) {
|
||||
public async deleteMemoById(id: MemoId) {
|
||||
await api.deleteMemo(id);
|
||||
}
|
||||
|
||||
public editMemo(memo: Model.Memo) {
|
||||
public editMemo(memo: Memo) {
|
||||
appStore.dispatch({
|
||||
type: "EDIT_MEMO",
|
||||
payload: memo,
|
||||
@ -118,39 +118,48 @@ class MemoService {
|
||||
});
|
||||
}
|
||||
|
||||
public async getLinkedMemos(memoId: string): Promise<Model.Memo[]> {
|
||||
public async getLinkedMemos(memoId: MemoId): Promise<Memo[]> {
|
||||
const { memos } = this.getState();
|
||||
return memos.filter((m) => m.content.includes(memoId));
|
||||
return memos.filter((m) => m.content.includes(`${memoId}`));
|
||||
}
|
||||
|
||||
public async createMemo(content: string): Promise<Model.Memo> {
|
||||
const memo = await api.createMemo(content);
|
||||
public async createMemo(content: string): Promise<Memo> {
|
||||
const memo = await api.createMemo({
|
||||
content,
|
||||
});
|
||||
return this.convertResponseModelMemo(memo);
|
||||
}
|
||||
|
||||
public async updateMemo(memoId: string, content: string): Promise<Model.Memo> {
|
||||
const memo = await api.updateMemo(memoId, content);
|
||||
public async updateMemo(memoId: MemoId, content: string): Promise<Memo> {
|
||||
const memo = await api.patchMemo({
|
||||
id: memoId,
|
||||
content,
|
||||
});
|
||||
return this.convertResponseModelMemo(memo);
|
||||
}
|
||||
|
||||
public async pinMemo(memoId: string) {
|
||||
public async pinMemo(memoId: MemoId) {
|
||||
await api.pinMemo(memoId);
|
||||
}
|
||||
|
||||
public async unpinMemo(memoId: string) {
|
||||
public async unpinMemo(memoId: MemoId) {
|
||||
await api.unpinMemo(memoId);
|
||||
}
|
||||
|
||||
public async importMemo(content: string, createdAt: string) {
|
||||
await api.createMemo(content, createdAt);
|
||||
const createdTs = Math.floor(utils.getTimeStampByDate(createdAt) / 1000);
|
||||
|
||||
await api.createMemo({
|
||||
content,
|
||||
createdTs,
|
||||
});
|
||||
}
|
||||
|
||||
private convertResponseModelMemo(memo: Model.Memo): Model.Memo {
|
||||
private convertResponseModelMemo(memo: Memo): Memo {
|
||||
return {
|
||||
...memo,
|
||||
id: String(memo.id),
|
||||
createdAt: utils.getDataStringWithTs(memo.createdTs),
|
||||
updatedAt: utils.getDataStringWithTs(memo.updatedTs),
|
||||
createdTs: memo.createdTs * 1000,
|
||||
updatedTs: memo.updatedTs * 1000,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import userService from "./userService";
|
||||
import api from "../helpers/api";
|
||||
import appStore from "../stores/appStore";
|
||||
import utils from "../helpers/utils";
|
||||
|
||||
class ShortcutService {
|
||||
public getState() {
|
||||
@ -33,7 +32,7 @@ class ShortcutService {
|
||||
return null;
|
||||
}
|
||||
|
||||
public pushShortcut(shortcut: Model.Shortcut) {
|
||||
public pushShortcut(shortcut: Shortcut) {
|
||||
appStore.dispatch({
|
||||
type: "INSERT_SHORTCUT",
|
||||
payload: {
|
||||
@ -44,7 +43,7 @@ class ShortcutService {
|
||||
});
|
||||
}
|
||||
|
||||
public editShortcut(shortcut: Model.Shortcut) {
|
||||
public editShortcut(shortcut: Shortcut) {
|
||||
appStore.dispatch({
|
||||
type: "UPDATE_SHORTCUT",
|
||||
payload: shortcut,
|
||||
@ -79,12 +78,11 @@ class ShortcutService {
|
||||
await api.unpinShortcut(shortcutId);
|
||||
}
|
||||
|
||||
public convertResponseModelShortcut(shortcut: Model.Shortcut): Model.Shortcut {
|
||||
public convertResponseModelShortcut(shortcut: Shortcut): Shortcut {
|
||||
return {
|
||||
...shortcut,
|
||||
id: String(shortcut.id),
|
||||
createdAt: utils.getDataStringWithTs(shortcut.createdTs),
|
||||
updatedAt: utils.getDataStringWithTs(shortcut.updatedTs),
|
||||
createdTs: shortcut.createdTs * 1000,
|
||||
updatedTs: shortcut.updatedTs * 1000,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
import api from "../helpers/api";
|
||||
import utils from "../helpers/utils";
|
||||
import appStore from "../stores/appStore";
|
||||
|
||||
class UserService {
|
||||
@ -8,7 +7,7 @@ class UserService {
|
||||
}
|
||||
|
||||
public async doSignIn() {
|
||||
const user = await api.getUserInfo();
|
||||
const user = await api.getUser();
|
||||
if (user) {
|
||||
appStore.dispatch({
|
||||
type: "LOGIN",
|
||||
@ -33,19 +32,19 @@ class UserService {
|
||||
}
|
||||
|
||||
public async updateUsername(name: string): Promise<void> {
|
||||
await api.updateUserinfo({
|
||||
await api.patchUser({
|
||||
name,
|
||||
});
|
||||
}
|
||||
|
||||
public async updatePassword(password: string): Promise<void> {
|
||||
await api.updateUserinfo({
|
||||
await api.patchUser({
|
||||
password,
|
||||
});
|
||||
}
|
||||
|
||||
public async resetOpenId(): Promise<string> {
|
||||
const user = await api.updateUserinfo({
|
||||
const user = await api.patchUser({
|
||||
resetOpenId: true,
|
||||
});
|
||||
appStore.dispatch({
|
||||
@ -55,11 +54,11 @@ class UserService {
|
||||
return user.openId;
|
||||
}
|
||||
|
||||
private convertResponseModelUser(user: Model.User): Model.User {
|
||||
private convertResponseModelUser(user: User): User {
|
||||
return {
|
||||
...user,
|
||||
createdAt: utils.getDataStringWithTs(user.createdTs),
|
||||
updatedAt: utils.getDataStringWithTs(user.updatedTs),
|
||||
createdTs: user.createdTs * 1000,
|
||||
updatedTs: user.updatedTs * 1000,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { UNKNOWN_ID } from "../helpers/consts";
|
||||
|
||||
export interface AppSetting {
|
||||
shouldSplitMemoWord: boolean;
|
||||
shouldHideImageUrl: boolean;
|
||||
@ -5,21 +7,21 @@ export interface AppSetting {
|
||||
}
|
||||
|
||||
export interface State extends AppSetting {
|
||||
markMemoId: string;
|
||||
editMemoId: string;
|
||||
markMemoId: MemoId;
|
||||
editMemoId: MemoId;
|
||||
}
|
||||
|
||||
interface SetMarkMemoIdAction {
|
||||
type: "SET_MARK_MEMO_ID";
|
||||
payload: {
|
||||
markMemoId: string;
|
||||
markMemoId: MemoId;
|
||||
};
|
||||
}
|
||||
|
||||
interface SetEditMemoIdAction {
|
||||
type: "SET_EDIT_MEMO_ID";
|
||||
payload: {
|
||||
editMemoId: string;
|
||||
editMemoId: MemoId;
|
||||
};
|
||||
}
|
||||
|
||||
@ -65,8 +67,8 @@ export function reducer(state: State, action: Actions) {
|
||||
}
|
||||
|
||||
export const defaultState: State = {
|
||||
markMemoId: "",
|
||||
editMemoId: "",
|
||||
markMemoId: UNKNOWN_ID,
|
||||
editMemoId: UNKNOWN_ID,
|
||||
shouldSplitMemoWord: true,
|
||||
shouldHideImageUrl: true,
|
||||
shouldUseMarkdownParser: true,
|
||||
|
@ -1,14 +1,14 @@
|
||||
import utils from "../helpers/utils";
|
||||
|
||||
export interface State {
|
||||
memos: Model.Memo[];
|
||||
memos: Memo[];
|
||||
tags: string[];
|
||||
}
|
||||
|
||||
interface SetMemosAction {
|
||||
type: "SET_MEMOS";
|
||||
payload: {
|
||||
memos: Model.Memo[];
|
||||
memos: Memo[];
|
||||
};
|
||||
}
|
||||
|
||||
@ -22,20 +22,20 @@ interface SetTagsAction {
|
||||
interface InsertMemoAction {
|
||||
type: "INSERT_MEMO";
|
||||
payload: {
|
||||
memo: Model.Memo;
|
||||
memo: Memo;
|
||||
};
|
||||
}
|
||||
|
||||
interface DeleteMemoByIdAction {
|
||||
type: "DELETE_MEMO_BY_ID";
|
||||
payload: {
|
||||
id: string;
|
||||
id: MemoId;
|
||||
};
|
||||
}
|
||||
|
||||
interface EditMemoByIdAction {
|
||||
type: "EDIT_MEMO";
|
||||
payload: Model.Memo;
|
||||
payload: Memo;
|
||||
}
|
||||
|
||||
export type Actions = SetMemosAction | SetTagsAction | InsertMemoAction | DeleteMemoByIdAction | EditMemoByIdAction;
|
||||
@ -43,9 +43,7 @@ export type Actions = SetMemosAction | SetTagsAction | InsertMemoAction | Delete
|
||||
export function reducer(state: State, action: Actions): State {
|
||||
switch (action.type) {
|
||||
case "SET_MEMOS": {
|
||||
const memos = utils.dedupeObjectWithId(
|
||||
action.payload.memos.sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt))
|
||||
);
|
||||
const memos = utils.dedupeObjectWithId(action.payload.memos.sort((a, b) => b.createdTs - a.createdTs));
|
||||
|
||||
return {
|
||||
...state,
|
||||
@ -59,10 +57,7 @@ export function reducer(state: State, action: Actions): State {
|
||||
};
|
||||
}
|
||||
case "INSERT_MEMO": {
|
||||
const memos = utils.dedupeObjectWithId(
|
||||
[action.payload.memo, ...state.memos].sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt))
|
||||
);
|
||||
|
||||
const memos = utils.dedupeObjectWithId([action.payload.memo, ...state.memos].sort((a, b) => b.createdTs - a.createdTs));
|
||||
return {
|
||||
...state,
|
||||
memos,
|
||||
|
@ -1,20 +1,20 @@
|
||||
import utils from "../helpers/utils";
|
||||
|
||||
export interface State {
|
||||
shortcuts: Model.Shortcut[];
|
||||
shortcuts: Shortcut[];
|
||||
}
|
||||
|
||||
interface SetShortcutsAction {
|
||||
type: "SET_SHORTCUTS";
|
||||
payload: {
|
||||
shortcuts: Model.Shortcut[];
|
||||
shortcuts: Shortcut[];
|
||||
};
|
||||
}
|
||||
|
||||
interface InsertShortcutAction {
|
||||
type: "INSERT_SHORTCUT";
|
||||
payload: {
|
||||
shortcut: Model.Shortcut;
|
||||
shortcut: Shortcut;
|
||||
};
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ interface DeleteShortcutByIdAction {
|
||||
|
||||
interface UpdateShortcutAction {
|
||||
type: "UPDATE_SHORTCUT";
|
||||
payload: Model.Shortcut;
|
||||
payload: Shortcut;
|
||||
}
|
||||
|
||||
export type Actions = SetShortcutsAction | InsertShortcutAction | DeleteShortcutByIdAction | UpdateShortcutAction;
|
||||
@ -37,8 +37,8 @@ export function reducer(state: State, action: Actions): State {
|
||||
case "SET_SHORTCUTS": {
|
||||
const shortcuts = utils.dedupeObjectWithId(
|
||||
action.payload.shortcuts
|
||||
.sort((a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt))
|
||||
.sort((a, b) => utils.getTimeStampByDate(b.updatedAt) - utils.getTimeStampByDate(a.updatedAt))
|
||||
.sort((a, b) => utils.getTimeStampByDate(b.createdTs) - utils.getTimeStampByDate(a.createdTs))
|
||||
.sort((a, b) => utils.getTimeStampByDate(b.updatedTs) - utils.getTimeStampByDate(a.updatedTs))
|
||||
);
|
||||
|
||||
return {
|
||||
@ -49,7 +49,7 @@ export function reducer(state: State, action: Actions): State {
|
||||
case "INSERT_SHORTCUT": {
|
||||
const shortcuts = utils.dedupeObjectWithId(
|
||||
[action.payload.shortcut, ...state.shortcuts].sort(
|
||||
(a, b) => utils.getTimeStampByDate(b.createdAt) - utils.getTimeStampByDate(a.createdAt)
|
||||
(a, b) => utils.getTimeStampByDate(b.createdTs) - utils.getTimeStampByDate(a.createdTs)
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
export interface State {
|
||||
user: Model.User | null;
|
||||
user: User | null;
|
||||
}
|
||||
|
||||
interface SignInAction {
|
||||
|
13
web/src/types/api.d.ts
vendored
13
web/src/types/api.d.ts
vendored
@ -1,13 +0,0 @@
|
||||
declare namespace API {
|
||||
interface SystemStatus {
|
||||
owner: Model.User;
|
||||
profile: Profile;
|
||||
}
|
||||
|
||||
interface UserCreate {
|
||||
email: string;
|
||||
password: string;
|
||||
name: string;
|
||||
role: UserRole;
|
||||
}
|
||||
}
|
37
web/src/types/models.d.ts
vendored
37
web/src/types/models.d.ts
vendored
@ -1,37 +0,0 @@
|
||||
type UserRole = "OWNER" | "USER";
|
||||
|
||||
declare namespace Model {
|
||||
interface BaseModel {
|
||||
id: string;
|
||||
createdTs: number;
|
||||
updatedTs: number;
|
||||
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
interface User extends BaseModel {
|
||||
role: UserRole;
|
||||
email: string;
|
||||
name: string;
|
||||
openId: string;
|
||||
}
|
||||
|
||||
interface Memo extends BaseModel {
|
||||
content: string;
|
||||
rowStatus: "NORMAL" | "ARCHIVED" | "HIDDEN";
|
||||
}
|
||||
|
||||
interface Shortcut extends BaseModel {
|
||||
title: string;
|
||||
payload: string;
|
||||
rowStatus: "NORMAL" | "ARCHIVED";
|
||||
}
|
||||
|
||||
interface Resource extends BaseModel {
|
||||
filename: string;
|
||||
type: string;
|
||||
size: string;
|
||||
createdAt: string;
|
||||
}
|
||||
}
|
4
web/src/types/module/system.d.ts
vendored
4
web/src/types/module/system.d.ts
vendored
@ -1,4 +0,0 @@
|
||||
interface Profile {
|
||||
mode: string;
|
||||
version: string;
|
||||
}
|
1
web/src/types/modules/common.d.ts
vendored
Normal file
1
web/src/types/modules/common.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
type RowStatus = "NORMAL" | "ARCHIVED";
|
24
web/src/types/modules/memo.d.ts
vendored
Normal file
24
web/src/types/modules/memo.d.ts
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
type MemoId = number;
|
||||
|
||||
interface Memo {
|
||||
id: MemoId;
|
||||
|
||||
creatorId: UserId;
|
||||
createdTs: TimeStamp;
|
||||
updatedTs: TimeStamp;
|
||||
rowStatus: RowStatus;
|
||||
|
||||
content: string;
|
||||
pinned: boolean;
|
||||
}
|
||||
|
||||
interface MemoCreate {
|
||||
content: string;
|
||||
createdTs?: TimeStamp;
|
||||
}
|
||||
|
||||
interface MemoPatch {
|
||||
id: MemoId;
|
||||
content?: string;
|
||||
rowStatus?: RowStatus;
|
||||
}
|
12
web/src/types/modules/resource.d.ts
vendored
Normal file
12
web/src/types/modules/resource.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
type ResourceId = number;
|
||||
|
||||
interface Resource {
|
||||
id: string;
|
||||
|
||||
createdTs: TimeStamp;
|
||||
updatedTs: TimeStamp;
|
||||
|
||||
filename: string;
|
||||
type: string;
|
||||
size: string;
|
||||
}
|
12
web/src/types/modules/shortcut.d.ts
vendored
Normal file
12
web/src/types/modules/shortcut.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
type ShortcutId = number;
|
||||
|
||||
interface Shortcut {
|
||||
id: string;
|
||||
|
||||
rowStatus: RowStatus;
|
||||
createdTs: TimeStamp;
|
||||
updatedTs: TimeStamp;
|
||||
|
||||
title: string;
|
||||
payload: string;
|
||||
}
|
9
web/src/types/modules/system.d.ts
vendored
Normal file
9
web/src/types/modules/system.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
interface Profile {
|
||||
mode: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
interface SystemStatus {
|
||||
owner: User;
|
||||
profile: Profile;
|
||||
}
|
28
web/src/types/modules/user.d.ts
vendored
Normal file
28
web/src/types/modules/user.d.ts
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
type UserId = number;
|
||||
type UserRole = "OWNER" | "USER";
|
||||
|
||||
interface User {
|
||||
id: UserId;
|
||||
|
||||
createdTs: TimeStamp;
|
||||
updatedTs: TimeStamp;
|
||||
rowStatus: RowStatus;
|
||||
|
||||
role: UserRole;
|
||||
email: string;
|
||||
name: string;
|
||||
openId: string;
|
||||
}
|
||||
|
||||
interface UserCreate {
|
||||
email: string;
|
||||
password: string;
|
||||
name: string;
|
||||
role: UserRole;
|
||||
}
|
||||
|
||||
interface UserPatch {
|
||||
name?: string;
|
||||
password?: string;
|
||||
resetOpenId?: boolean;
|
||||
}
|
5
web/src/types/view.d.ts
vendored
5
web/src/types/view.d.ts
vendored
@ -5,8 +5,3 @@ interface DialogProps {
|
||||
interface DialogCallback {
|
||||
destroy: FunctionType;
|
||||
}
|
||||
|
||||
interface FormattedMemo extends Model.Memo {
|
||||
createdAtStr: string;
|
||||
deletedAtStr?: string;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user