From 6fe1db42b5e6024717e0dbb25ac152085b555024 Mon Sep 17 00:00:00 2001 From: boojack Date: Thu, 19 May 2022 18:32:49 +0800 Subject: [PATCH] chore: update store types --- web/src/components/AboutSiteDialog.tsx | 2 +- .../components/ConfirmResetOpenIdDialog.tsx | 2 +- web/src/components/DailyMemo.tsx | 9 +- web/src/components/DailyMemoDiaryDialog.tsx | 10 +- web/src/components/DeletedMemo.tsx | 10 +- web/src/components/Memo.tsx | 24 +-- web/src/components/MemoCardDialog.tsx | 32 ++-- web/src/components/MemoEditor.tsx | 18 +-- web/src/components/MemoList.tsx | 8 +- web/src/components/MemoTrashDialog.tsx | 6 +- web/src/components/Settings/MemberSection.tsx | 16 +- .../components/Settings/MyAccountSection.tsx | 7 +- .../Settings/PreferencesSection.tsx | 6 +- web/src/components/ShareMemoImageDialog.tsx | 8 +- web/src/components/ShortcutList.tsx | 6 +- web/src/components/Sidebar.tsx | 2 +- web/src/components/TagList.tsx | 2 +- web/src/helpers/api.ts | 138 ++++++++---------- web/src/helpers/consts.ts | 3 + web/src/helpers/filter.ts | 4 +- web/src/helpers/utils.ts | 4 +- web/src/less/memo.less | 2 +- web/src/less/settings/member-section.less | 22 ++- web/src/less/shortcut-list.less | 2 +- web/src/less/signin.less | 35 +++-- web/src/less/tag-list.less | 2 +- web/src/pages/Signin.tsx | 11 +- web/src/services/globalStateService.ts | 4 +- web/src/services/memoService.ts | 55 ++++--- web/src/services/shortcutService.ts | 12 +- web/src/services/userService.ts | 15 +- web/src/stores/globalStateStore.ts | 14 +- web/src/stores/memoStore.ts | 19 +-- web/src/stores/shortcutStore.ts | 14 +- web/src/stores/userStore.ts | 2 +- web/src/types/api.d.ts | 13 -- web/src/types/{basic.d.ts => common.d.ts} | 0 web/src/types/models.d.ts | 37 ----- web/src/types/module/system.d.ts | 4 - web/src/types/modules/common.d.ts | 1 + web/src/types/modules/memo.d.ts | 24 +++ web/src/types/modules/resource.d.ts | 12 ++ web/src/types/modules/shortcut.d.ts | 12 ++ web/src/types/modules/system.d.ts | 9 ++ web/src/types/modules/user.d.ts | 28 ++++ web/src/types/view.d.ts | 5 - 46 files changed, 353 insertions(+), 318 deletions(-) delete mode 100644 web/src/types/api.d.ts rename web/src/types/{basic.d.ts => common.d.ts} (100%) delete mode 100644 web/src/types/models.d.ts delete mode 100644 web/src/types/module/system.d.ts create mode 100644 web/src/types/modules/common.d.ts create mode 100644 web/src/types/modules/memo.d.ts create mode 100644 web/src/types/modules/resource.d.ts create mode 100644 web/src/types/modules/shortcut.d.ts create mode 100644 web/src/types/modules/system.d.ts create mode 100644 web/src/types/modules/user.d.ts diff --git a/web/src/components/AboutSiteDialog.tsx b/web/src/components/AboutSiteDialog.tsx index 047f0f38..30a14e08 100644 --- a/web/src/components/AboutSiteDialog.tsx +++ b/web/src/components/AboutSiteDialog.tsx @@ -38,7 +38,7 @@ const AboutSiteDialog: React.FC = ({ destroy }: Props) => {

- Memos is an open source, quickly self-hosted alternative to flomo. + Memos is an open source, self-hosted knowledge base that works with local SQLite.


diff --git a/web/src/components/ConfirmResetOpenIdDialog.tsx b/web/src/components/ConfirmResetOpenIdDialog.tsx index ffdc942d..e301d696 100644 --- a/web/src/components/ConfirmResetOpenIdDialog.tsx +++ b/web/src/components/ConfirmResetOpenIdDialog.tsx @@ -44,7 +44,7 @@ const ConfirmResetOpenIdDialog: React.FC = ({ destroy }: Props) => {

- ⚠️ 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?

diff --git a/web/src/components/DailyMemo.tsx b/web/src/components/DailyMemo.tsx index 9fb8efed..a412a19f 100644 --- a/web/src/components/DailyMemo.tsx +++ b/web/src/components/DailyMemo.tsx @@ -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) => { 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) ?? []); diff --git a/web/src/components/DailyMemoDiaryDialog.tsx b/web/src/components/DailyMemoDiaryDialog.tsx index c8ac6215..3c4d533b 100644 --- a/web/src/components/DailyMemoDiaryDialog.tsx +++ b/web/src/components/DailyMemoDiaryDialog.tsx @@ -20,7 +20,7 @@ const weekdayChineseStrArray = ["周日", "周一", "周二", "周三", "周四" const DailyMemoDiaryDialog: React.FC = (props: Props) => { const loadingState = useLoading(); - const [memos, setMemos] = useState([]); + const [memos, setMemos] = useState([]); const [currentDateStamp, setCurrentDateStamp] = useState(utils.getDateStampByDate(utils.getDateString(props.currentDateStamp))); const [showDatePicker, toggleShowDatePicker] = useToggle(false); const memosElRef = useRef(null); @@ -32,10 +32,10 @@ const DailyMemoDiaryDialog: React.FC = (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) => { ) : (
{memos.map((memo) => ( - + ))}
)} diff --git a/web/src/components/DeletedMemo.tsx b/web/src/components/DeletedMemo.tsx index a7cac670..957c3805 100644 --- a/web/src/components/DeletedMemo.tsx +++ b/web/src/components/DeletedMemo.tsx @@ -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) => { 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) ?? []); diff --git a/web/src/components/Memo.tsx b/web/src/components/Memo.tsx index 0397ee70..83860988 100644 --- a/web/src/components/Memo.tsx +++ b/web/src/components/Memo.tsx @@ -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) => { 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) => { 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) => { } if (globalStateService.getState().editMemoId === memo.id) { - globalStateService.setEditMemoId(""); + globalStateService.setEditMemoId(UNKNOWN_ID); } } else { toggleConfirmDeleteBtn(); @@ -88,7 +88,7 @@ const Memo: React.FC = (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) => { }; return ( -
+
{memo.createdAtStr} - + PINNED @@ -120,7 +120,7 @@ const Memo: React.FC = (props: Props) => { View Story - {memo.rowStatus === "NORMAL" ? "Pin" : "Unpin"} + {memo.pinned ? "Unpin" : "Pin"} Mark diff --git a/web/src/components/MemoCardDialog.tsx b/web/src/components/MemoCardDialog.tsx index c21cd16a..361d1329 100644 --- a/web/src/components/MemoCardDialog.tsx +++ b/web/src/components/MemoCardDialog.tsx @@ -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) => { - const [memo, setMemo] = useState({ + const [memo, setMemo] = useState({ ...props.memo, - createdAtStr: utils.getDateTimeString(props.memo.createdAt), }); const [linkMemos, setLinkMemos] = useState([]); const [linkedMemos, setLinkedMemos] = useState([]); @@ -36,12 +36,12 @@ const MemoCardDialog: React.FC = (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) => { 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) => { 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) => { } }, []); - const handleLinkedMemoClick = useCallback((memo: FormattedMemo) => { + const handleLinkedMemoClick = useCallback((memo: Memo) => { setLinkMemos([]); setLinkedMemos([]); setMemo(memo); @@ -103,7 +103,7 @@ const MemoCardDialog: React.FC = (props: Props) => { <>
-

{memo.createdAtStr}

+

{utils.getDateTimeString(memo.createdTs)}

diff --git a/web/src/helpers/api.ts b/web/src/helpers/api.ts index 43b395f1..18e519c0 100644 --- a/web/src/helpers/api.ts +++ b/web/src/helpers/api.ts @@ -1,5 +1,3 @@ -import utils from "./utils"; - type ResponseObject = { data: T; error?: string; @@ -42,29 +40,14 @@ async function request(config: RequestConfig): Promise { namespace api { export function getSystemStatus() { - return request({ + return request({ method: "GET", url: "/api/status", }); } - export function getUserList() { - return request({ - method: "GET", - url: "/api/user", - }); - } - - export function createUser(userCreate: API.UserCreate) { - return request({ - method: "POST", - url: "/api/user", - data: userCreate, - }); - } - export function login(email: string, password: string) { - return request({ + return request({ method: "POST", url: "/api/auth/login", data: { @@ -75,7 +58,7 @@ namespace api { } export function signup(email: string, password: string, role: UserRole) { - return request({ + return request({ method: "POST", url: "/api/auth/signup", data: { @@ -94,70 +77,89 @@ namespace api { }); } - export function getUserInfo() { - return request({ + export function createUser(userCreate: UserCreate) { + return request({ + method: "POST", + url: "/api/user", + data: userCreate, + }); + } + + export function getUser() { + return request({ method: "GET", url: "/api/user/me", }); } - export function updateUserinfo(userinfo: Partial<{ name: string; password: string; resetOpenId: boolean }>) { - return request({ - method: "PATCH", - url: "/api/user/me", - data: userinfo, + export function getUserList() { + return request({ + method: "GET", + url: "/api/user", }); } - export function resetOpenId() { - return request({ - method: "POST", - url: "/api/user/open_id/new", + export function patchUser(userPatch: UserPatch) { + return request({ + method: "PATCH", + url: "/api/user/me", + data: userPatch, }); } export function getMyMemos() { - return request({ + return request({ method: "GET", url: "/api/memo", }); } - export function getMyDeletedMemos() { - return request({ + export function getMyArchivedMemos() { + return request({ 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({ + export function createMemo(memoCreate: MemoCreate) { + return request({ method: "POST", url: "/api/memo", - data: data, + data: memoCreate, }); } - export function updateMemo(memoId: string, content: string) { - return request({ + export function patchMemo(memoPatch: MemoPatch) { + return request({ 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({ + return request({ method: "GET", url: "/api/shortcut", }); } export function createShortcut(title: string, payload: string) { - return request({ + return request({ method: "POST", url: "/api/shortcut", data: { @@ -223,7 +205,7 @@ namespace api { } export function updateShortcut(shortcutId: string, title: string, payload: string) { - return request({ + return request({ method: "PATCH", url: `/api/shortcut/${shortcutId}`, data: { @@ -261,7 +243,7 @@ namespace api { } export function uploadFile(formData: FormData) { - return request({ + return request({ method: "POST", url: "/api/resource", data: formData, diff --git a/web/src/helpers/consts.ts b/web/src/helpers/consts.ts index 95c40d34..a990a91f 100644 --- a/web/src/helpers/consts.ts +++ b/web/src/helpers/consts.ts @@ -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; diff --git a/web/src/helpers/filter.ts b/web/src/helpers/filter.ts index 5fe0b10c..b9290e5e 100644 --- a/web/src/helpers/filter.ts +++ b/web/src/helpers/filter.ts @@ -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 }, diff --git a/web/src/helpers/utils.ts b/web/src/helpers/utils.ts index 3bdd3887..35061057 100644 --- a/web/src/helpers/utils.ts +++ b/web/src/helpers/utils.ts @@ -83,8 +83,8 @@ namespace utils { return Array.from(new Set(data)); } - export function dedupeObjectWithId(data: T[]): T[] { - const idSet = new Set(); + export function dedupeObjectWithId(data: T[]): T[] { + const idSet = new Set(); const result = []; for (const d of data) { diff --git a/web/src/less/memo.less b/web/src/less/memo.less index 4972bec2..98b7487f 100644 --- a/web/src/less/memo.less +++ b/web/src/less/memo.less @@ -9,7 +9,7 @@ @apply border-gray-200; } - &.ARCHIVED { + &.pinned { @apply border-gray-200 border-2; } diff --git a/web/src/less/settings/member-section.less b/web/src/less/settings/member-section.less index bad99134..8cde12c4 100644 --- a/web/src/less/settings/member-section.less +++ b/web/src/less/settings/member-section.less @@ -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; } } } diff --git a/web/src/less/shortcut-list.less b/web/src/less/shortcut-list.less index 79cae72c..3ff54118 100644 --- a/web/src/less/shortcut-list.less +++ b/web/src/less/shortcut-list.less @@ -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; diff --git a/web/src/less/signin.less b/web/src/less/signin.less index 5f76ab17..2808cf56 100644 --- a/web/src/less/signin.less +++ b/web/src/less/signin.less @@ -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; } } diff --git a/web/src/less/tag-list.less b/web/src/less/tag-list.less index 26769aee..3d20d19a 100644 --- a/web/src/less/tag-list.less +++ b/web/src/less/tag-list.less @@ -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; diff --git a/web/src/pages/Signin.tsx b/web/src/pages/Signin.tsx index 10ae6304..af777c81 100644 --- a/web/src/pages/Signin.tsx +++ b/web/src/pages/Signin.tsx @@ -17,7 +17,7 @@ const validateConfig: ValidatorConfig = { const Signin: React.FC = () => { const pageLoadingState = useLoading(true); - const [siteOwner, setSiteOwner] = useState(); + const [siteOwner, setSiteOwner] = useState(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const actionBtnLoadingState = useLoading(false); @@ -128,12 +128,15 @@ const Signin: React.FC = () => { }; return ( -
+

✍️ Memos

+

+ An open source, self-hosted knowledge base that works with local SQLite. +

@@ -150,7 +153,7 @@ const Signin: React.FC = () => { Login as Guest / - {siteOwner || pageLoadingState.isLoading ? ( + {siteOwner ? (

- {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."}

diff --git a/web/src/services/globalStateService.ts b/web/src/services/globalStateService.ts index 80ca3ace..b7ab054a 100644 --- a/web/src/services/globalStateService.ts +++ b/web/src/services/globalStateService.ts @@ -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: { diff --git a/web/src/services/memoService.ts b/web/src/services/memoService.ts index 2579fdbd..c22c1f63 100644 --- a/web/src/services/memoService.ts +++ b/web/src/services/memoService.ts @@ -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 { + public async getLinkedMemos(memoId: MemoId): Promise { 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 { - const memo = await api.createMemo(content); + public async createMemo(content: string): Promise { + const memo = await api.createMemo({ + content, + }); return this.convertResponseModelMemo(memo); } - public async updateMemo(memoId: string, content: string): Promise { - const memo = await api.updateMemo(memoId, content); + public async updateMemo(memoId: MemoId, content: string): Promise { + 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, }; } } diff --git a/web/src/services/shortcutService.ts b/web/src/services/shortcutService.ts index c2397149..96b9156c 100644 --- a/web/src/services/shortcutService.ts +++ b/web/src/services/shortcutService.ts @@ -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, }; } } diff --git a/web/src/services/userService.ts b/web/src/services/userService.ts index a9616c37..fe3eb2f3 100644 --- a/web/src/services/userService.ts +++ b/web/src/services/userService.ts @@ -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 { - await api.updateUserinfo({ + await api.patchUser({ name, }); } public async updatePassword(password: string): Promise { - await api.updateUserinfo({ + await api.patchUser({ password, }); } public async resetOpenId(): Promise { - 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, }; } } diff --git a/web/src/stores/globalStateStore.ts b/web/src/stores/globalStateStore.ts index ac386d90..671b0f7f 100644 --- a/web/src/stores/globalStateStore.ts +++ b/web/src/stores/globalStateStore.ts @@ -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, diff --git a/web/src/stores/memoStore.ts b/web/src/stores/memoStore.ts index 13aae349..6d2e0714 100644 --- a/web/src/stores/memoStore.ts +++ b/web/src/stores/memoStore.ts @@ -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, diff --git a/web/src/stores/shortcutStore.ts b/web/src/stores/shortcutStore.ts index ca6d974c..1a9b6187 100644 --- a/web/src/stores/shortcutStore.ts +++ b/web/src/stores/shortcutStore.ts @@ -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) ) ); diff --git a/web/src/stores/userStore.ts b/web/src/stores/userStore.ts index 71c29c3d..18f0125b 100644 --- a/web/src/stores/userStore.ts +++ b/web/src/stores/userStore.ts @@ -1,5 +1,5 @@ export interface State { - user: Model.User | null; + user: User | null; } interface SignInAction { diff --git a/web/src/types/api.d.ts b/web/src/types/api.d.ts deleted file mode 100644 index 7dff4451..00000000 --- a/web/src/types/api.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -declare namespace API { - interface SystemStatus { - owner: Model.User; - profile: Profile; - } - - interface UserCreate { - email: string; - password: string; - name: string; - role: UserRole; - } -} diff --git a/web/src/types/basic.d.ts b/web/src/types/common.d.ts similarity index 100% rename from web/src/types/basic.d.ts rename to web/src/types/common.d.ts diff --git a/web/src/types/models.d.ts b/web/src/types/models.d.ts deleted file mode 100644 index fef2bb74..00000000 --- a/web/src/types/models.d.ts +++ /dev/null @@ -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; - } -} diff --git a/web/src/types/module/system.d.ts b/web/src/types/module/system.d.ts deleted file mode 100644 index b039a4d5..00000000 --- a/web/src/types/module/system.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -interface Profile { - mode: string; - version: string; -} diff --git a/web/src/types/modules/common.d.ts b/web/src/types/modules/common.d.ts new file mode 100644 index 00000000..4089da3f --- /dev/null +++ b/web/src/types/modules/common.d.ts @@ -0,0 +1 @@ +type RowStatus = "NORMAL" | "ARCHIVED"; diff --git a/web/src/types/modules/memo.d.ts b/web/src/types/modules/memo.d.ts new file mode 100644 index 00000000..63fbf979 --- /dev/null +++ b/web/src/types/modules/memo.d.ts @@ -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; +} diff --git a/web/src/types/modules/resource.d.ts b/web/src/types/modules/resource.d.ts new file mode 100644 index 00000000..1a8edd0f --- /dev/null +++ b/web/src/types/modules/resource.d.ts @@ -0,0 +1,12 @@ +type ResourceId = number; + +interface Resource { + id: string; + + createdTs: TimeStamp; + updatedTs: TimeStamp; + + filename: string; + type: string; + size: string; +} diff --git a/web/src/types/modules/shortcut.d.ts b/web/src/types/modules/shortcut.d.ts new file mode 100644 index 00000000..06b89a62 --- /dev/null +++ b/web/src/types/modules/shortcut.d.ts @@ -0,0 +1,12 @@ +type ShortcutId = number; + +interface Shortcut { + id: string; + + rowStatus: RowStatus; + createdTs: TimeStamp; + updatedTs: TimeStamp; + + title: string; + payload: string; +} diff --git a/web/src/types/modules/system.d.ts b/web/src/types/modules/system.d.ts new file mode 100644 index 00000000..2f5195e8 --- /dev/null +++ b/web/src/types/modules/system.d.ts @@ -0,0 +1,9 @@ +interface Profile { + mode: string; + version: string; +} + +interface SystemStatus { + owner: User; + profile: Profile; +} diff --git a/web/src/types/modules/user.d.ts b/web/src/types/modules/user.d.ts new file mode 100644 index 00000000..05813709 --- /dev/null +++ b/web/src/types/modules/user.d.ts @@ -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; +} diff --git a/web/src/types/view.d.ts b/web/src/types/view.d.ts index 6309a030..32df3eac 100644 --- a/web/src/types/view.d.ts +++ b/web/src/types/view.d.ts @@ -5,8 +5,3 @@ interface DialogProps { interface DialogCallback { destroy: FunctionType; } - -interface FormattedMemo extends Model.Memo { - createdAtStr: string; - deletedAtStr?: string; -}