Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
canifa_note
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Vũ Hoàng Anh
canifa_note
Commits
e83d4834
Commit
e83d4834
authored
Dec 01, 2023
by
Steven
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor(frontend): use auth service
parent
b9444182
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
136 additions
and
299 deletions
+136
-299
App.tsx
web/src/App.tsx
+5
-4
ChangeMemberPasswordDialog.tsx
web/src/components/ChangeMemberPasswordDialog.tsx
+2
-2
ChangePasswordDialog.tsx
web/src/components/ChangePasswordDialog.tsx
+6
-6
Memo.tsx
web/src/components/Memo.tsx
+1
-7
index.tsx
web/src/components/MemoEditor/index.tsx
+8
-8
MemberSection.tsx
web/src/components/Settings/MemberSection.tsx
+5
-5
PreferencesSection.tsx
web/src/components/Settings/PreferencesSection.tsx
+32
-19
UpdateAccountDialog.tsx
web/src/components/UpdateAccountDialog.tsx
+14
-15
UserBanner.tsx
web/src/components/UserBanner.tsx
+4
-3
useCurrentUser.ts
web/src/hooks/useCurrentUser.ts
+2
-12
AuthCallback.tsx
web/src/pages/AuthCallback.tsx
+1
-5
SignIn.tsx
web/src/pages/SignIn.tsx
+2
-5
SignUp.tsx
web/src/pages/SignUp.tsx
+2
-5
index.tsx
web/src/router/index.tsx
+2
-26
index.ts
web/src/store/index.ts
+0
-2
index.ts
web/src/store/module/index.ts
+0
-1
user.ts
web/src/store/module/user.ts
+0
-132
user.ts
web/src/store/reducer/user.ts
+0
-40
user.ts
web/src/store/v1/user.ts
+50
-2
No files found.
web/src/App.tsx
View file @
e83d4834
...
@@ -6,7 +6,6 @@ import storage from "./helpers/storage";
...
@@ -6,7 +6,6 @@ import storage from "./helpers/storage";
import
{
getSystemColorScheme
}
from
"./helpers/utils"
;
import
{
getSystemColorScheme
}
from
"./helpers/utils"
;
import
useNavigateTo
from
"./hooks/useNavigateTo"
;
import
useNavigateTo
from
"./hooks/useNavigateTo"
;
import
Loading
from
"./pages/Loading"
;
import
Loading
from
"./pages/Loading"
;
import
store
from
"./store"
;
import
{
useGlobalStore
}
from
"./store/module"
;
import
{
useGlobalStore
}
from
"./store/module"
;
import
{
useUserV1Store
}
from
"./store/v1"
;
import
{
useUserV1Store
}
from
"./store/v1"
;
...
@@ -28,9 +27,11 @@ const App = () => {
...
@@ -28,9 +27,11 @@ const App = () => {
useEffect
(()
=>
{
useEffect
(()
=>
{
const
initialState
=
async
()
=>
{
const
initialState
=
async
()
=>
{
const
{
user
}
=
store
.
getState
().
user
;
try
{
if
(
user
)
{
await
userV1Store
.
fetchCurrentUser
();
await
userV1Store
.
getOrFetchUserByUsername
(
user
.
username
);
console
.
log
(
"here"
);
}
catch
(
error
)
{
// Skip.
}
}
setLoading
(
false
);
setLoading
(
false
);
};
};
...
...
web/src/components/ChangeMemberPasswordDialog.tsx
View file @
e83d4834
...
@@ -12,7 +12,7 @@ interface Props extends DialogProps {
...
@@ -12,7 +12,7 @@ interface Props extends DialogProps {
const
ChangeMemberPasswordDialog
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
ChangeMemberPasswordDialog
:
React
.
FC
<
Props
>
=
(
props
:
Props
)
=>
{
const
{
user
,
destroy
}
=
props
;
const
{
user
,
destroy
}
=
props
;
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
userStore
=
useUserV1Store
();
const
user
V1
Store
=
useUserV1Store
();
const
[
newPassword
,
setNewPassword
]
=
useState
(
""
);
const
[
newPassword
,
setNewPassword
]
=
useState
(
""
);
const
[
newPasswordAgain
,
setNewPasswordAgain
]
=
useState
(
""
);
const
[
newPasswordAgain
,
setNewPasswordAgain
]
=
useState
(
""
);
...
@@ -47,7 +47,7 @@ const ChangeMemberPasswordDialog: React.FC<Props> = (props: Props) => {
...
@@ -47,7 +47,7 @@ const ChangeMemberPasswordDialog: React.FC<Props> = (props: Props) => {
}
}
try
{
try
{
await
userStore
.
updateUser
(
await
user
V1
Store
.
updateUser
(
{
{
name
:
`
${
UserNamePrefix
}${
user
.
username
}
`
,
name
:
`
${
UserNamePrefix
}${
user
.
username
}
`
,
password
:
newPassword
,
password
:
newPassword
,
...
...
web/src/components/ChangePasswordDialog.tsx
View file @
e83d4834
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
useGlobalStore
,
useUserStore
}
from
"@/store/module"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
useUserV1Store
,
UserNamePrefix
}
from
"@/store/v1"
;
import
{
useGlobalStore
}
from
"@/store/module"
;
import
{
useUserV1Store
}
from
"@/store/v1"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
Icon
from
"./Icon"
;
import
Icon
from
"./Icon"
;
...
@@ -10,7 +11,7 @@ type Props = DialogProps;
...
@@ -10,7 +11,7 @@ type Props = DialogProps;
const
ChangePasswordDialog
:
React
.
FC
<
Props
>
=
({
destroy
}:
Props
)
=>
{
const
ChangePasswordDialog
:
React
.
FC
<
Props
>
=
({
destroy
}:
Props
)
=>
{
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
userStore
=
useUserStore
();
const
currentUser
=
useCurrentUser
();
const
userV1Store
=
useUserV1Store
();
const
userV1Store
=
useUserV1Store
();
const
globalStore
=
useGlobalStore
();
const
globalStore
=
useGlobalStore
();
const
profile
=
globalStore
.
state
.
systemStatus
.
profile
;
const
profile
=
globalStore
.
state
.
systemStatus
.
profile
;
...
@@ -18,7 +19,7 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
...
@@ -18,7 +19,7 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
const
[
newPasswordAgain
,
setNewPasswordAgain
]
=
useState
(
""
);
const
[
newPasswordAgain
,
setNewPasswordAgain
]
=
useState
(
""
);
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
profile
.
mode
===
"demo"
&&
userStore
.
state
.
user
?.
id
===
userStore
.
state
.
host
?.
id
)
{
if
(
profile
.
mode
===
"demo"
)
{
toast
.
error
(
"Demo mode does not support this operation."
);
toast
.
error
(
"Demo mode does not support this operation."
);
destroy
();
destroy
();
}
}
...
@@ -51,10 +52,9 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
...
@@ -51,10 +52,9 @@ const ChangePasswordDialog: React.FC<Props> = ({ destroy }: Props) => {
}
}
try
{
try
{
const
user
=
userStore
.
getState
().
user
as
User
;
await
userV1Store
.
updateUser
(
await
userV1Store
.
updateUser
(
{
{
name
:
`
${
UserNamePrefix
}${
user
.
username
}
`
,
name
:
currentUser
.
name
,
password
:
newPassword
,
password
:
newPassword
,
},
},
[
"password"
]
[
"password"
]
...
...
web/src/components/Memo.tsx
View file @
e83d4834
...
@@ -7,7 +7,7 @@ import { UNKNOWN_ID } from "@/helpers/consts";
...
@@ -7,7 +7,7 @@ import { UNKNOWN_ID } from "@/helpers/consts";
import
{
getRelativeTimeString
}
from
"@/helpers/datetime"
;
import
{
getRelativeTimeString
}
from
"@/helpers/datetime"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
{
useFilterStore
,
useMemoStore
,
useUserStore
}
from
"@/store/module"
;
import
{
useFilterStore
,
useMemoStore
}
from
"@/store/module"
;
import
{
useUserV1Store
,
extractUsernameFromName
}
from
"@/store/v1"
;
import
{
useUserV1Store
,
extractUsernameFromName
}
from
"@/store/v1"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
showChangeMemoCreatedTsDialog
from
"./ChangeMemoCreatedTsDialog"
;
import
showChangeMemoCreatedTsDialog
from
"./ChangeMemoCreatedTsDialog"
;
...
@@ -36,7 +36,6 @@ const Memo: React.FC<Props> = (props: Props) => {
...
@@ -36,7 +36,6 @@ const Memo: React.FC<Props> = (props: Props) => {
const
navigateTo
=
useNavigateTo
();
const
navigateTo
=
useNavigateTo
();
const
{
i18n
}
=
useTranslation
();
const
{
i18n
}
=
useTranslation
();
const
filterStore
=
useFilterStore
();
const
filterStore
=
useFilterStore
();
const
userStore
=
useUserStore
();
const
memoStore
=
useMemoStore
();
const
memoStore
=
useMemoStore
();
const
userV1Store
=
useUserV1Store
();
const
userV1Store
=
useUserV1Store
();
const
user
=
useCurrentUser
();
const
user
=
useCurrentUser
();
...
@@ -211,11 +210,6 @@ const Memo: React.FC<Props> = (props: Props) => {
...
@@ -211,11 +210,6 @@ const Memo: React.FC<Props> = (props: Props) => {
if
(
readonly
)
{
if
(
readonly
)
{
return
;
return
;
}
}
const
loginUser
=
userStore
.
state
.
user
;
if
(
loginUser
&&
!
loginUser
.
localSetting
.
enableDoubleClickEditing
)
{
return
;
}
const
targetEl
=
e
.
target
as
HTMLElement
;
const
targetEl
=
e
.
target
as
HTMLElement
;
if
(
targetEl
.
className
===
"tag-span"
)
{
if
(
targetEl
.
className
===
"tag-span"
)
{
...
...
web/src/components/MemoEditor/index.tsx
View file @
e83d4834
...
@@ -8,9 +8,10 @@ import { TAB_SPACE_WIDTH, UNKNOWN_ID, VISIBILITY_SELECTOR_ITEMS } from "@/helper
...
@@ -8,9 +8,10 @@ import { TAB_SPACE_WIDTH, UNKNOWN_ID, VISIBILITY_SELECTOR_ITEMS } from "@/helper
import
{
clearContentQueryParam
}
from
"@/helpers/utils"
;
import
{
clearContentQueryParam
}
from
"@/helpers/utils"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
{
getMatchedNodes
}
from
"@/labs/marked"
;
import
{
getMatchedNodes
}
from
"@/labs/marked"
;
import
{
useFilterStore
,
useGlobalStore
,
useMemoStore
,
useResourceStore
,
useTagStore
,
useUserStore
}
from
"@/store/module"
;
import
{
useFilterStore
,
useGlobalStore
,
useMemoStore
,
useResourceStore
,
useTagStore
}
from
"@/store/module"
;
import
{
useUserV1Store
}
from
"@/store/v1"
;
import
{
Resource
}
from
"@/types/proto/api/v2/resource_service"
;
import
{
Resource
}
from
"@/types/proto/api/v2/resource_service"
;
import
{
User_Role
}
from
"@/types/proto/api/v2/user_service"
;
import
{
User
Setting
,
User
_Role
}
from
"@/types/proto/api/v2/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
showCreateMemoRelationDialog
from
"../CreateMemoRelationDialog"
;
import
showCreateMemoRelationDialog
from
"../CreateMemoRelationDialog"
;
import
showCreateResourceDialog
from
"../CreateResourceDialog"
;
import
showCreateResourceDialog
from
"../CreateResourceDialog"
;
...
@@ -50,7 +51,7 @@ const MemoEditor = (props: Props) => {
...
@@ -50,7 +51,7 @@ const MemoEditor = (props: Props) => {
const
{
const
{
state
:
{
systemStatus
},
state
:
{
systemStatus
},
}
=
useGlobalStore
();
}
=
useGlobalStore
();
const
user
Store
=
useUser
Store
();
const
user
V1Store
=
useUserV1
Store
();
const
filterStore
=
useFilterStore
();
const
filterStore
=
useFilterStore
();
const
memoStore
=
useMemoStore
();
const
memoStore
=
useMemoStore
();
const
tagStore
=
useTagStore
();
const
tagStore
=
useTagStore
();
...
@@ -66,8 +67,7 @@ const MemoEditor = (props: Props) => {
...
@@ -66,8 +67,7 @@ const MemoEditor = (props: Props) => {
const
[
hasContent
,
setHasContent
]
=
useState
<
boolean
>
(
false
);
const
[
hasContent
,
setHasContent
]
=
useState
<
boolean
>
(
false
);
const
[
isInIME
,
setIsInIME
]
=
useState
(
false
);
const
[
isInIME
,
setIsInIME
]
=
useState
(
false
);
const
editorRef
=
useRef
<
EditorRefActions
>
(
null
);
const
editorRef
=
useRef
<
EditorRefActions
>
(
null
);
const
user
=
userStore
.
state
.
user
as
User
;
const
userSetting
=
userV1Store
.
userSetting
as
UserSetting
;
const
setting
=
user
.
setting
;
const
referenceRelations
=
memoId
const
referenceRelations
=
memoId
?
state
.
relationList
.
filter
(
?
state
.
relationList
.
filter
(
(
relation
)
=>
relation
.
memoId
===
memoId
&&
relation
.
relatedMemoId
!==
memoId
&&
relation
.
type
===
"REFERENCE"
(
relation
)
=>
relation
.
memoId
===
memoId
&&
relation
.
relatedMemoId
!==
memoId
&&
relation
.
type
===
"REFERENCE"
...
@@ -80,15 +80,15 @@ const MemoEditor = (props: Props) => {
...
@@ -80,15 +80,15 @@ const MemoEditor = (props: Props) => {
},
[]);
},
[]);
useEffect
(()
=>
{
useEffect
(()
=>
{
let
visibility
=
s
etting
.
memoVisibility
;
let
visibility
=
userS
etting
.
memoVisibility
;
if
(
systemStatus
.
disablePublicMemos
&&
visibility
===
"PUBLIC"
)
{
if
(
systemStatus
.
disablePublicMemos
&&
visibility
===
"PUBLIC"
)
{
visibility
=
"PRIVATE"
;
visibility
=
"PRIVATE"
;
}
}
setState
((
prevState
)
=>
({
setState
((
prevState
)
=>
({
...
prevState
,
...
prevState
,
memoVisibility
:
visibility
,
memoVisibility
:
visibility
as
Visibility
,
}));
}));
},
[
s
etting
.
memoVisibility
,
systemStatus
.
disablePublicMemos
]);
},
[
userS
etting
.
memoVisibility
,
systemStatus
.
disablePublicMemos
]);
useEffect
(()
=>
{
useEffect
(()
=>
{
if
(
memoId
)
{
if
(
memoId
)
{
...
...
web/src/components/Settings/MemberSection.tsx
View file @
e83d4834
...
@@ -3,8 +3,8 @@ import React, { useEffect, useState } from "react";
...
@@ -3,8 +3,8 @@ import React, { useEffect, useState } from "react";
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
userServiceClient
}
from
"@/grpcweb"
;
import
{
userServiceClient
}
from
"@/grpcweb"
;
import
*
as
api
from
"@/helpers/api"
;
import
*
as
api
from
"@/helpers/api"
;
import
{
useUserStore
}
from
"@/store/module
"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser
"
;
import
{
UserNamePrefix
}
from
"@/store/v1"
;
import
{
UserNamePrefix
,
useUserV1Store
}
from
"@/store/v1"
;
import
{
RowStatus
}
from
"@/types/proto/api/v2/common"
;
import
{
RowStatus
}
from
"@/types/proto/api/v2/common"
;
import
{
User_Role
}
from
"@/types/proto/api/v2/user_service"
;
import
{
User_Role
}
from
"@/types/proto/api/v2/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
@@ -19,8 +19,8 @@ interface State {
...
@@ -19,8 +19,8 @@ interface State {
const
MemberSection
=
()
=>
{
const
MemberSection
=
()
=>
{
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
userStore
=
useUserStore
();
const
currentUser
=
useCurrentUser
();
const
currentUser
=
userStore
.
state
.
user
;
const
userV1Store
=
useUserV1Store
()
;
const
[
state
,
setState
]
=
useState
<
State
>
({
const
[
state
,
setState
]
=
useState
<
State
>
({
createUserUsername
:
""
,
createUserUsername
:
""
,
createUserPassword
:
""
,
createUserPassword
:
""
,
...
@@ -115,7 +115,7 @@ const MemberSection = () => {
...
@@ -115,7 +115,7 @@ const MemberSection = () => {
style
:
"danger"
,
style
:
"danger"
,
dialogName
:
"delete-user-dialog"
,
dialogName
:
"delete-user-dialog"
,
onConfirm
:
async
()
=>
{
onConfirm
:
async
()
=>
{
await
userStore
.
deleteUser
(
`
${
UserNamePrefix
}${
user
.
username
}
`
);
await
user
V1
Store
.
deleteUser
(
`
${
UserNamePrefix
}${
user
.
username
}
`
);
fetchUserList
();
fetchUserList
();
},
},
});
});
...
...
web/src/components/Settings/PreferencesSection.tsx
View file @
e83d4834
import
{
Button
,
Divider
,
Input
,
Option
,
Select
,
Switch
}
from
"@mui/joy"
;
import
{
Button
,
Divider
,
Input
,
Option
,
Select
}
from
"@mui/joy"
;
import
React
,
{
useState
}
from
"react"
;
import
{
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
VISIBILITY_SELECTOR_ITEMS
}
from
"@/helpers/consts"
;
import
{
VISIBILITY_SELECTOR_ITEMS
}
from
"@/helpers/consts"
;
import
{
useGlobalStore
,
useUserStore
}
from
"@/store/module"
;
import
{
useGlobalStore
}
from
"@/store/module"
;
import
{
useUserV1Store
}
from
"@/store/v1"
;
import
{
UserSetting
}
from
"@/types/proto/api/v2/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
AppearanceSelect
from
"../AppearanceSelect"
;
import
AppearanceSelect
from
"../AppearanceSelect"
;
import
LearnMore
from
"../LearnMore"
;
import
LearnMore
from
"../LearnMore"
;
...
@@ -14,32 +16,48 @@ import "@/less/settings/preferences-section.less";
...
@@ -14,32 +16,48 @@ import "@/less/settings/preferences-section.less";
const
PreferencesSection
=
()
=>
{
const
PreferencesSection
=
()
=>
{
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
globalStore
=
useGlobalStore
();
const
globalStore
=
useGlobalStore
();
const
user
Store
=
useUser
Store
();
const
user
V1Store
=
useUserV1
Store
();
const
{
appearance
,
locale
}
=
globalStore
.
state
;
const
{
appearance
,
locale
}
=
globalStore
.
state
;
const
{
setting
,
localSetting
}
=
userStore
.
state
.
user
as
User
;
const
setting
=
userV1Store
.
userSetting
as
UserSetting
;
const
[
telegramUserId
,
setTelegramUserId
]
=
useState
<
string
>
(
setting
.
telegramUserId
);
const
[
telegramUserId
,
setTelegramUserId
]
=
useState
<
string
>
(
setting
.
telegramUserId
);
const
handleLocaleSelectChange
=
async
(
locale
:
Locale
)
=>
{
const
handleLocaleSelectChange
=
async
(
locale
:
Locale
)
=>
{
await
userStore
.
upsertUserSetting
(
"locale"
,
locale
);
await
userV1Store
.
updateUserSetting
(
{
locale
,
},
[
"locale"
]
);
globalStore
.
setLocale
(
locale
);
globalStore
.
setLocale
(
locale
);
};
};
const
handleAppearanceSelectChange
=
async
(
appearance
:
Appearance
)
=>
{
const
handleAppearanceSelectChange
=
async
(
appearance
:
Appearance
)
=>
{
await
userStore
.
upsertUserSetting
(
"appearance"
,
appearance
);
await
userV1Store
.
updateUserSetting
(
{
appearance
,
},
[
"appearance"
]
);
globalStore
.
setAppearance
(
appearance
);
globalStore
.
setAppearance
(
appearance
);
};
};
const
handleDefaultMemoVisibilityChanged
=
async
(
value
:
string
)
=>
{
const
handleDefaultMemoVisibilityChanged
=
async
(
value
:
string
)
=>
{
await
userStore
.
upsertUserSetting
(
"memo-visibility"
,
value
);
await
userV1Store
.
updateUserSetting
(
};
{
memoVisibility
:
value
,
const
handleDoubleClickEnabledChanged
=
(
event
:
React
.
ChangeEvent
<
HTMLInputElement
>
)
=>
{
},
userStore
.
upsertLocalSetting
({
...
localSetting
,
enableDoubleClickEditing
:
event
.
target
.
checked
});
[
"memo_visibility"
]
);
};
};
const
handleSaveTelegramUserId
=
async
()
=>
{
const
handleSaveTelegramUserId
=
async
()
=>
{
try
{
try
{
await
userStore
.
upsertUserSetting
(
"telegram-user-id"
,
telegramUserId
);
await
userV1Store
.
updateUserSetting
(
{
telegramUserId
:
telegramUserId
,
},
[
"telegram_user_id"
]
);
toast
.
success
(
t
(
"message.update-succeed"
));
toast
.
success
(
t
(
"message.update-succeed"
));
}
catch
(
error
:
any
)
{
}
catch
(
error
:
any
)
{
console
.
error
(
error
);
console
.
error
(
error
);
...
@@ -68,7 +86,7 @@ const PreferencesSection = () => {
...
@@ -68,7 +86,7 @@ const PreferencesSection = () => {
<
Select
<
Select
className=
"!min-w-fit"
className=
"!min-w-fit"
value=
{
setting
.
memoVisibility
}
value=
{
setting
.
memoVisibility
}
startDecorator=
{
<
VisibilityIcon
visibility=
{
setting
.
memoVisibility
}
/>
}
startDecorator=
{
<
VisibilityIcon
visibility=
{
setting
.
memoVisibility
as
Visibility
}
/>
}
onChange=
{
(
_
,
visibility
)
=>
{
onChange=
{
(
_
,
visibility
)
=>
{
if
(
visibility
)
{
if
(
visibility
)
{
handleDefaultMemoVisibilityChanged
(
visibility
);
handleDefaultMemoVisibilityChanged
(
visibility
);
...
@@ -83,11 +101,6 @@ const PreferencesSection = () => {
...
@@ -83,11 +101,6 @@ const PreferencesSection = () => {
</
Select
>
</
Select
>
</
div
>
</
div
>
<
label
className=
"form-label selector"
>
<
span
className=
"text-sm break-keep"
>
{
t
(
"setting.preference-section.enable-double-click"
)
}
</
span
>
<
Switch
className=
"ml-2"
checked=
{
localSetting
.
enableDoubleClickEditing
}
onChange=
{
handleDoubleClickEnabledChanged
}
/>
</
label
>
<
Divider
className=
"!mt-3 !my-4"
/>
<
Divider
className=
"!mt-3 !my-4"
/>
<
div
className=
"mb-2 w-full flex flex-row justify-between items-center"
>
<
div
className=
"mb-2 w-full flex flex-row justify-between items-center"
>
...
...
web/src/components/UpdateAccountDialog.tsx
View file @
e83d4834
...
@@ -2,8 +2,8 @@ import { isEqual } from "lodash-es";
...
@@ -2,8 +2,8 @@ import { isEqual } from "lodash-es";
import
{
useEffect
,
useState
}
from
"react"
;
import
{
useEffect
,
useState
}
from
"react"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
toast
}
from
"react-hot-toast"
;
import
{
convertFileToBase64
}
from
"@/helpers/utils"
;
import
{
convertFileToBase64
}
from
"@/helpers/utils"
;
import
{
useUserStore
}
from
"@/store/module
"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser
"
;
import
{
UserNamePrefix
}
from
"@/store/v1"
;
import
{
UserNamePrefix
,
useUserV1Store
}
from
"@/store/v1"
;
import
{
User
as
UserPb
}
from
"@/types/proto/api/v2/user_service"
;
import
{
User
as
UserPb
}
from
"@/types/proto/api/v2/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
generateDialog
}
from
"./Dialog"
;
import
{
generateDialog
}
from
"./Dialog"
;
...
@@ -21,13 +21,13 @@ interface State {
...
@@ -21,13 +21,13 @@ interface State {
const
UpdateAccountDialog
:
React
.
FC
<
Props
>
=
({
destroy
}:
Props
)
=>
{
const
UpdateAccountDialog
:
React
.
FC
<
Props
>
=
({
destroy
}:
Props
)
=>
{
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
userStore
=
useUserStore
();
const
currentUser
=
useCurrentUser
();
const
user
=
userStore
.
state
.
user
as
User
;
const
user
V1Store
=
useUserV1Store
()
;
const
[
state
,
setState
]
=
useState
<
State
>
({
const
[
state
,
setState
]
=
useState
<
State
>
({
avatarUrl
:
u
ser
.
avatarUrl
,
avatarUrl
:
currentU
ser
.
avatarUrl
,
username
:
user
.
username
,
username
:
currentUser
.
name
.
replace
(
UserNamePrefix
,
""
)
,
nickname
:
u
ser
.
nickname
,
nickname
:
currentU
ser
.
nickname
,
email
:
u
ser
.
email
,
email
:
currentU
ser
.
email
,
});
});
useEffect
(()
=>
{
useEffect
(()
=>
{
...
@@ -95,24 +95,23 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => {
...
@@ -95,24 +95,23 @@ const UpdateAccountDialog: React.FC<Props> = ({ destroy }: Props) => {
}
}
try
{
try
{
const
user
=
userStore
.
getState
().
user
as
User
;
const
updateMask
=
[];
const
updateMask
=
[];
if
(
!
isEqual
(
u
ser
.
avatarUrl
,
state
.
avatarUrl
))
{
if
(
!
isEqual
(
currentU
ser
.
avatarUrl
,
state
.
avatarUrl
))
{
updateMask
.
push
(
"avatar_url"
);
updateMask
.
push
(
"avatar_url"
);
}
}
if
(
!
isEqual
(
u
ser
.
nickname
,
state
.
nickname
))
{
if
(
!
isEqual
(
currentU
ser
.
nickname
,
state
.
nickname
))
{
updateMask
.
push
(
"nickname"
);
updateMask
.
push
(
"nickname"
);
}
}
if
(
!
isEqual
(
user
.
username
,
state
.
username
))
{
if
(
!
isEqual
(
currentUser
.
name
.
replace
(
UserNamePrefix
,
""
)
,
state
.
username
))
{
updateMask
.
push
(
"username"
);
updateMask
.
push
(
"username"
);
}
}
if
(
!
isEqual
(
u
ser
.
email
,
state
.
email
))
{
if
(
!
isEqual
(
currentU
ser
.
email
,
state
.
email
))
{
updateMask
.
push
(
"email"
);
updateMask
.
push
(
"email"
);
}
}
await
user
Store
.
patch
User
(
await
user
V1Store
.
update
User
(
UserPb
.
fromPartial
({
UserPb
.
fromPartial
({
name
:
`
${
UserNamePrefix
}${
state
.
username
}
`
,
name
:
`
${
UserNamePrefix
}${
state
.
username
}
`
,
id
:
u
ser
.
id
,
id
:
currentU
ser
.
id
,
nickname
:
state
.
nickname
,
nickname
:
state
.
nickname
,
email
:
state
.
email
,
email
:
state
.
email
,
avatarUrl
:
state
.
avatarUrl
,
avatarUrl
:
state
.
avatarUrl
,
...
...
web/src/components/UserBanner.tsx
View file @
e83d4834
import
*
as
api
from
"@/helpers/api"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useCurrentUser
from
"@/hooks/useCurrentUser"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
{
useGlobalStore
,
useUserStore
}
from
"@/store/module"
;
import
{
useGlobalStore
}
from
"@/store/module"
;
import
{
extractUsernameFromName
}
from
"@/store/v1"
;
import
{
extractUsernameFromName
}
from
"@/store/v1"
;
import
{
User_Role
}
from
"@/types/proto/api/v2/user_service"
;
import
{
User_Role
}
from
"@/types/proto/api/v2/user_service"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
@@ -13,7 +14,6 @@ const UserBanner = () => {
...
@@ -13,7 +14,6 @@ const UserBanner = () => {
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
navigateTo
=
useNavigateTo
();
const
navigateTo
=
useNavigateTo
();
const
globalStore
=
useGlobalStore
();
const
globalStore
=
useGlobalStore
();
const
userStore
=
useUserStore
();
const
{
systemStatus
}
=
globalStore
.
state
;
const
{
systemStatus
}
=
globalStore
.
state
;
const
user
=
useCurrentUser
();
const
user
=
useCurrentUser
();
const
title
=
user
?
user
.
nickname
:
systemStatus
.
customizedProfile
.
name
||
"memos"
;
const
title
=
user
?
user
.
nickname
:
systemStatus
.
customizedProfile
.
name
||
"memos"
;
...
@@ -27,7 +27,8 @@ const UserBanner = () => {
...
@@ -27,7 +27,8 @@ const UserBanner = () => {
};
};
const
handleSignOutBtnClick
=
async
()
=>
{
const
handleSignOutBtnClick
=
async
()
=>
{
await
userStore
.
doSignOut
();
await
api
.
signout
();
localStorage
.
removeItem
(
"userId"
);
window
.
location
.
href
=
"/auth"
;
window
.
location
.
href
=
"/auth"
;
};
};
...
...
web/src/hooks/useCurrentUser.ts
View file @
e83d4834
import
{
useEffect
}
from
"react"
;
import
{
useUserStore
}
from
"@/store/module"
;
import
{
useUserV1Store
}
from
"@/store/v1"
;
import
{
useUserV1Store
}
from
"@/store/v1"
;
import
{
User
}
from
"@/types/proto/api/v2/user_service"
;
const
useCurrentUser
=
()
=>
{
const
useCurrentUser
=
()
=>
{
const
userStore
=
useUserStore
();
const
userV1Store
=
useUserV1Store
();
const
userV1Store
=
useUserV1Store
();
const
currentUsername
=
userStore
.
state
.
user
?.
username
;
return
userV1Store
.
currentUser
as
User
;
useEffect
(()
=>
{
if
(
currentUsername
)
{
userV1Store
.
getOrFetchUserByUsername
(
currentUsername
);
}
},
[
currentUsername
]);
return
userV1Store
.
getUserByUsername
(
currentUsername
||
""
);
};
};
export
default
useCurrentUser
;
export
default
useCurrentUser
;
web/src/pages/AuthCallback.tsx
View file @
e83d4834
...
@@ -6,7 +6,6 @@ import Icon from "@/components/Icon";
...
@@ -6,7 +6,6 @@ import Icon from "@/components/Icon";
import
*
as
api
from
"@/helpers/api"
;
import
*
as
api
from
"@/helpers/api"
;
import
{
absolutifyLink
}
from
"@/helpers/utils"
;
import
{
absolutifyLink
}
from
"@/helpers/utils"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
{
useUserStore
}
from
"@/store/module"
;
import
{
useUserV1Store
}
from
"@/store/v1"
;
import
{
useUserV1Store
}
from
"@/store/v1"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
@@ -19,7 +18,6 @@ const AuthCallback = () => {
...
@@ -19,7 +18,6 @@ const AuthCallback = () => {
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
navigateTo
=
useNavigateTo
();
const
navigateTo
=
useNavigateTo
();
const
[
searchParams
]
=
useSearchParams
();
const
[
searchParams
]
=
useSearchParams
();
const
userStore
=
useUserStore
();
const
userV1Store
=
useUserV1Store
();
const
userV1Store
=
useUserV1Store
();
const
[
state
,
setState
]
=
useState
<
State
>
({
const
[
state
,
setState
]
=
useState
<
State
>
({
loading
:
true
,
loading
:
true
,
...
@@ -42,9 +40,7 @@ const AuthCallback = () => {
...
@@ -42,9 +40,7 @@ const AuthCallback = () => {
errorMessage
:
""
,
errorMessage
:
""
,
});
});
if
(
user
)
{
if
(
user
)
{
userStore
.
setCurrentUser
(
user
);
await
userV1Store
.
fetchCurrentUser
();
await
userStore
.
fetchCurrentUser
();
await
userV1Store
.
getOrFetchUserByUsername
(
user
.
username
);
navigateTo
(
"/"
);
navigateTo
(
"/"
);
}
else
{
}
else
{
toast
.
error
(
t
(
"message.login-failed"
));
toast
.
error
(
t
(
"message.login-failed"
));
...
...
web/src/pages/SignIn.tsx
View file @
e83d4834
...
@@ -8,7 +8,7 @@ import * as api from "@/helpers/api";
...
@@ -8,7 +8,7 @@ import * as api from "@/helpers/api";
import
{
absolutifyLink
}
from
"@/helpers/utils"
;
import
{
absolutifyLink
}
from
"@/helpers/utils"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
{
useGlobalStore
,
useUserStore
}
from
"@/store/module"
;
import
{
useGlobalStore
}
from
"@/store/module"
;
import
{
useUserV1Store
}
from
"@/store/v1"
;
import
{
useUserV1Store
}
from
"@/store/v1"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
@@ -16,7 +16,6 @@ const SignIn = () => {
...
@@ -16,7 +16,6 @@ const SignIn = () => {
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
navigateTo
=
useNavigateTo
();
const
navigateTo
=
useNavigateTo
();
const
globalStore
=
useGlobalStore
();
const
globalStore
=
useGlobalStore
();
const
userStore
=
useUserStore
();
const
userV1Store
=
useUserV1Store
();
const
userV1Store
=
useUserV1Store
();
const
actionBtnLoadingState
=
useLoading
(
false
);
const
actionBtnLoadingState
=
useLoading
(
false
);
const
{
appearance
,
locale
,
systemStatus
}
=
globalStore
.
state
;
const
{
appearance
,
locale
,
systemStatus
}
=
globalStore
.
state
;
...
@@ -78,9 +77,7 @@ const SignIn = () => {
...
@@ -78,9 +77,7 @@ const SignIn = () => {
actionBtnLoadingState
.
setLoading
();
actionBtnLoadingState
.
setLoading
();
const
{
data
:
user
}
=
await
api
.
signin
(
username
,
password
,
remember
);
const
{
data
:
user
}
=
await
api
.
signin
(
username
,
password
,
remember
);
if
(
user
)
{
if
(
user
)
{
userStore
.
setCurrentUser
(
user
);
await
userV1Store
.
fetchCurrentUser
();
await
userStore
.
fetchCurrentUser
();
await
userV1Store
.
getOrFetchUserByUsername
(
user
.
username
);
navigateTo
(
"/"
);
navigateTo
(
"/"
);
}
else
{
}
else
{
toast
.
error
(
t
(
"message.login-failed"
));
toast
.
error
(
t
(
"message.login-failed"
));
...
...
web/src/pages/SignUp.tsx
View file @
e83d4834
...
@@ -7,7 +7,7 @@ import LocaleSelect from "@/components/LocaleSelect";
...
@@ -7,7 +7,7 @@ import LocaleSelect from "@/components/LocaleSelect";
import
*
as
api
from
"@/helpers/api"
;
import
*
as
api
from
"@/helpers/api"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
useLoading
from
"@/hooks/useLoading"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
useNavigateTo
from
"@/hooks/useNavigateTo"
;
import
{
useGlobalStore
,
useUserStore
}
from
"@/store/module"
;
import
{
useGlobalStore
}
from
"@/store/module"
;
import
{
useUserV1Store
}
from
"@/store/v1"
;
import
{
useUserV1Store
}
from
"@/store/v1"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
import
{
useTranslate
}
from
"@/utils/i18n"
;
...
@@ -15,7 +15,6 @@ const SignUp = () => {
...
@@ -15,7 +15,6 @@ const SignUp = () => {
const
t
=
useTranslate
();
const
t
=
useTranslate
();
const
navigateTo
=
useNavigateTo
();
const
navigateTo
=
useNavigateTo
();
const
globalStore
=
useGlobalStore
();
const
globalStore
=
useGlobalStore
();
const
userStore
=
useUserStore
();
const
userV1Store
=
useUserV1Store
();
const
userV1Store
=
useUserV1Store
();
const
actionBtnLoadingState
=
useLoading
(
false
);
const
actionBtnLoadingState
=
useLoading
(
false
);
const
{
appearance
,
locale
,
systemStatus
}
=
globalStore
.
state
;
const
{
appearance
,
locale
,
systemStatus
}
=
globalStore
.
state
;
...
@@ -58,9 +57,7 @@ const SignUp = () => {
...
@@ -58,9 +57,7 @@ const SignUp = () => {
actionBtnLoadingState
.
setLoading
();
actionBtnLoadingState
.
setLoading
();
const
{
data
:
user
}
=
await
api
.
signup
(
username
,
password
);
const
{
data
:
user
}
=
await
api
.
signup
(
username
,
password
);
if
(
user
)
{
if
(
user
)
{
userStore
.
setCurrentUser
(
user
);
await
userV1Store
.
fetchCurrentUser
();
await
userStore
.
fetchCurrentUser
();
await
userV1Store
.
getOrFetchUserByUsername
(
user
.
username
);
navigateTo
(
"/"
);
navigateTo
(
"/"
);
}
else
{
}
else
{
toast
.
error
(
t
(
"message.signup-failed"
));
toast
.
error
(
t
(
"message.signup-failed"
));
...
...
web/src/router/index.tsx
View file @
e83d4834
import
{
lazy
}
from
"react"
;
import
{
lazy
}
from
"react"
;
import
{
createBrowserRouter
,
redirect
}
from
"react-router-dom"
;
import
{
createBrowserRouter
}
from
"react-router-dom"
;
import
App
from
"@/App"
;
import
App
from
"@/App"
;
import
{
initialGlobalState
,
initialUserState
}
from
"@/store/module"
;
import
{
initialGlobalState
}
from
"@/store/module"
;
const
Root
=
lazy
(()
=>
import
(
"@/layouts/Root"
));
const
Root
=
lazy
(()
=>
import
(
"@/layouts/Root"
));
const
SignIn
=
lazy
(()
=>
import
(
"@/pages/SignIn"
));
const
SignIn
=
lazy
(()
=>
import
(
"@/pages/SignIn"
));
...
@@ -28,20 +28,6 @@ const initialGlobalStateLoader = async () => {
...
@@ -28,20 +28,6 @@ const initialGlobalStateLoader = async () => {
return
null
;
return
null
;
};
};
const
initialUserStateLoader
=
async
(
redirectWhenNotFound
=
true
)
=>
{
let
user
=
undefined
;
try
{
user
=
await
initialUserState
();
}
catch
(
error
)
{
// do nothing.
}
if
(
!
user
&&
redirectWhenNotFound
)
{
return
redirect
(
"/explore"
);
}
return
null
;
};
const
router
=
createBrowserRouter
([
const
router
=
createBrowserRouter
([
{
{
path
:
"/"
,
path
:
"/"
,
...
@@ -67,54 +53,44 @@ const router = createBrowserRouter([
...
@@ -67,54 +53,44 @@ const router = createBrowserRouter([
{
{
path
:
""
,
path
:
""
,
element
:
<
Home
/>,
element
:
<
Home
/>,
loader
:
()
=>
initialUserStateLoader
(),
},
},
{
{
path
:
"review"
,
path
:
"review"
,
element
:
<
DailyReview
/>,
element
:
<
DailyReview
/>,
loader
:
()
=>
initialUserStateLoader
(),
},
},
{
{
path
:
"resources"
,
path
:
"resources"
,
element
:
<
Resources
/>,
element
:
<
Resources
/>,
loader
:
()
=>
initialUserStateLoader
(),
},
},
{
{
path
:
"inbox"
,
path
:
"inbox"
,
element
:
<
Inboxes
/>,
element
:
<
Inboxes
/>,
loader
:
()
=>
initialUserStateLoader
(),
},
},
{
{
path
:
"archived"
,
path
:
"archived"
,
element
:
<
Archived
/>,
element
:
<
Archived
/>,
loader
:
()
=>
initialUserStateLoader
(),
},
},
{
{
path
:
"setting"
,
path
:
"setting"
,
element
:
<
Setting
/>,
element
:
<
Setting
/>,
loader
:
()
=>
initialUserStateLoader
(),
},
},
{
{
path
:
"explore"
,
path
:
"explore"
,
element
:
<
Explore
/>,
element
:
<
Explore
/>,
loader
:
()
=>
initialUserStateLoader
(
false
),
},
},
],
],
},
},
{
{
path
:
"/m/:memoId"
,
path
:
"/m/:memoId"
,
element
:
<
MemoDetail
/>,
element
:
<
MemoDetail
/>,
loader
:
()
=>
initialUserStateLoader
(
false
),
},
},
{
{
path
:
"/m/:memoId/embed"
,
path
:
"/m/:memoId/embed"
,
element
:
<
EmbedMemo
/>,
element
:
<
EmbedMemo
/>,
loader
:
()
=>
initialUserStateLoader
(
false
),
},
},
{
{
path
:
"/u/:username"
,
path
:
"/u/:username"
,
element
:
<
UserProfile
/>,
element
:
<
UserProfile
/>,
loader
:
()
=>
initialUserStateLoader
(
false
),
},
},
{
{
path
:
"*"
,
path
:
"*"
,
...
...
web/src/store/index.ts
View file @
e83d4834
...
@@ -6,12 +6,10 @@ import globalReducer from "./reducer/global";
...
@@ -6,12 +6,10 @@ import globalReducer from "./reducer/global";
import
memoReducer
from
"./reducer/memo"
;
import
memoReducer
from
"./reducer/memo"
;
import
resourceReducer
from
"./reducer/resource"
;
import
resourceReducer
from
"./reducer/resource"
;
import
tagReducer
from
"./reducer/tag"
;
import
tagReducer
from
"./reducer/tag"
;
import
userReducer
from
"./reducer/user"
;
const
store
=
configureStore
({
const
store
=
configureStore
({
reducer
:
{
reducer
:
{
global
:
globalReducer
,
global
:
globalReducer
,
user
:
userReducer
,
memo
:
memoReducer
,
memo
:
memoReducer
,
tag
:
tagReducer
,
tag
:
tagReducer
,
filter
:
filterReducer
,
filter
:
filterReducer
,
...
...
web/src/store/module/index.ts
View file @
e83d4834
...
@@ -3,5 +3,4 @@ export * from "./filter";
...
@@ -3,5 +3,4 @@ export * from "./filter";
export
*
from
"./memo"
;
export
*
from
"./memo"
;
export
*
from
"./tag"
;
export
*
from
"./tag"
;
export
*
from
"./resource"
;
export
*
from
"./resource"
;
export
*
from
"./user"
;
export
*
from
"./dialog"
;
export
*
from
"./dialog"
;
web/src/store/module/user.ts
deleted
100644 → 0
View file @
b9444182
import
{
camelCase
}
from
"lodash-es"
;
import
{
authServiceClient
,
userServiceClient
}
from
"@/grpcweb"
;
import
*
as
api
from
"@/helpers/api"
;
import
storage
from
"@/helpers/storage"
;
import
{
getSystemColorScheme
}
from
"@/helpers/utils"
;
import
{
User
as
UserPb
}
from
"@/types/proto/api/v2/user_service"
;
import
store
,
{
useAppSelector
}
from
".."
;
import
{
setAppearance
,
setLocale
}
from
"../reducer/global"
;
import
{
patchUser
,
setHost
,
setUser
}
from
"../reducer/user"
;
const
defaultSetting
:
Setting
=
{
locale
:
"en"
,
appearance
:
getSystemColorScheme
(),
memoVisibility
:
"PRIVATE"
,
telegramUserId
:
""
,
};
const
defaultLocalSetting
:
LocalSetting
=
{
enableDoubleClickEditing
:
false
,
};
export
const
convertResponseModelUser
=
(
user
:
User
):
User
=>
{
// user default 'Basic Setting' should follow server's setting
// 'Basic Setting' fields: locale, appearance
const
{
systemStatus
}
=
store
.
getState
().
global
;
const
{
locale
,
appearance
}
=
systemStatus
.
customizedProfile
;
const
systemSetting
=
{
locale
,
appearance
};
const
setting
:
Setting
=
{
...
defaultSetting
,
...
systemSetting
,
};
const
{
localSetting
:
storageLocalSetting
}
=
storage
.
get
([
"localSetting"
]);
const
localSetting
:
LocalSetting
=
{
...
defaultLocalSetting
,
...
storageLocalSetting
,
};
if
(
user
.
userSettingList
)
{
for
(
const
userSetting
of
user
.
userSettingList
)
{
(
setting
as
any
)[
camelCase
(
userSetting
.
key
)]
=
JSON
.
parse
(
userSetting
.
value
);
}
}
return
{
...
user
,
setting
,
localSetting
,
createdTs
:
user
.
createdTs
*
1000
,
updatedTs
:
user
.
updatedTs
*
1000
,
};
};
export
const
initialUserState
=
async
()
=>
{
const
{
systemStatus
}
=
store
.
getState
().
global
;
if
(
systemStatus
.
host
)
{
store
.
dispatch
(
setHost
(
convertResponseModelUser
(
systemStatus
.
host
)));
}
const
user
=
await
fetchCurrentUser
();
if
(
user
)
{
if
(
user
.
setting
.
locale
)
{
store
.
dispatch
(
setLocale
(
user
.
setting
.
locale
));
}
if
(
user
.
setting
.
appearance
)
{
store
.
dispatch
(
setAppearance
(
user
.
setting
.
appearance
));
}
return
user
;
}
};
const
doSignOut
=
async
()
=>
{
await
api
.
signout
();
localStorage
.
removeItem
(
"userId"
);
};
const
fetchCurrentUser
=
async
()
=>
{
const
userId
=
localStorage
.
getItem
(
"userId"
);
if
(
userId
)
{
const
{
user
}
=
await
authServiceClient
.
getAuthStatus
({});
if
(
!
user
)
{
localStorage
.
removeItem
(
"userId"
);
return
;
}
const
{
data
}
=
await
api
.
getUserById
(
Number
(
userId
));
const
userMessage
=
convertResponseModelUser
(
data
);
if
(
userMessage
)
{
store
.
dispatch
(
setUser
(
userMessage
));
return
userMessage
;
}
}
};
export
const
useUserStore
=
()
=>
{
const
state
=
useAppSelector
((
state
)
=>
state
.
user
);
return
{
state
,
getState
:
()
=>
{
return
store
.
getState
().
user
;
},
doSignOut
,
fetchCurrentUser
,
setCurrentUser
:
async
(
user
:
User
)
=>
{
localStorage
.
setItem
(
"userId"
,
String
(
user
.
id
));
},
upsertUserSetting
:
async
(
key
:
string
,
value
:
any
)
=>
{
await
api
.
upsertUserSetting
({
key
:
key
as
any
,
value
:
JSON
.
stringify
(
value
),
});
await
fetchCurrentUser
();
},
upsertLocalSetting
:
async
(
localSetting
:
LocalSetting
)
=>
{
storage
.
set
({
localSetting
});
store
.
dispatch
(
patchUser
({
localSetting
}));
},
patchUser
:
async
(
user
:
UserPb
,
updateMask
:
string
[]):
Promise
<
void
>
=>
{
await
userServiceClient
.
updateUser
({
user
,
updateMask
});
// If the user is the current user and the username is changed, reload the page.
if
(
user
.
id
===
store
.
getState
().
user
.
user
?.
id
)
{
window
.
location
.
reload
();
}
},
deleteUser
:
async
(
name
:
string
)
=>
{
await
userServiceClient
.
deleteUser
({
name
,
});
},
};
};
web/src/store/reducer/user.ts
deleted
100644 → 0
View file @
b9444182
import
{
createSlice
,
PayloadAction
}
from
"@reduxjs/toolkit"
;
interface
State
{
// host is the user who hist the system
host
?:
User
;
// user is the user who is currently logged in
user
?:
User
;
}
const
userSlice
=
createSlice
({
name
:
"user"
,
initialState
:
{}
as
State
,
reducers
:
{
setHost
:
(
state
,
action
:
PayloadAction
<
User
|
undefined
>
)
=>
{
return
{
...
state
,
host
:
action
.
payload
,
};
},
setUser
:
(
state
,
action
:
PayloadAction
<
User
|
undefined
>
)
=>
{
return
{
...
state
,
user
:
action
.
payload
,
};
},
patchUser
:
(
state
,
action
:
PayloadAction
<
Partial
<
User
>>
)
=>
{
return
{
...
state
,
user
:
{
...
state
.
user
,
...
action
.
payload
,
}
as
User
,
};
},
},
});
export
const
{
setHost
,
setUser
,
patchUser
}
=
userSlice
.
actions
;
export
default
userSlice
.
reducer
;
web/src/store/v1/user.ts
View file @
e83d4834
import
{
create
}
from
"zustand"
;
import
{
create
}
from
"zustand"
;
import
{
userServiceClient
}
from
"@/grpcweb"
;
import
{
authServiceClient
,
userServiceClient
}
from
"@/grpcweb"
;
import
{
User
}
from
"@/types/proto/api/v2/user_service"
;
import
{
User
,
UserSetting
}
from
"@/types/proto/api/v2/user_service"
;
import
{
UserNamePrefix
,
extractUsernameFromName
}
from
"./resourceName"
;
import
{
UserNamePrefix
,
extractUsernameFromName
}
from
"./resourceName"
;
interface
UserV1Store
{
interface
UserV1Store
{
userMapByUsername
:
Record
<
string
,
User
>
;
userMapByUsername
:
Record
<
string
,
User
>
;
currentUser
?:
User
;
userSetting
?:
UserSetting
;
getOrFetchUserByUsername
:
(
username
:
string
)
=>
Promise
<
User
>
;
getOrFetchUserByUsername
:
(
username
:
string
)
=>
Promise
<
User
>
;
getUserByUsername
:
(
username
:
string
)
=>
User
;
getUserByUsername
:
(
username
:
string
)
=>
User
;
updateUser
:
(
user
:
Partial
<
User
>
,
updateMask
:
string
[])
=>
Promise
<
User
>
;
updateUser
:
(
user
:
Partial
<
User
>
,
updateMask
:
string
[])
=>
Promise
<
User
>
;
deleteUser
:
(
name
:
string
)
=>
Promise
<
void
>
;
fetchCurrentUser
:
()
=>
Promise
<
User
>
;
setCurrentUser
:
(
user
:
User
)
=>
void
;
updateUserSetting
:
(
userSetting
:
Partial
<
UserSetting
>
,
updateMark
:
string
[])
=>
Promise
<
UserSetting
>
;
}
}
const
getDefaultUserSetting
=
()
=>
{
return
UserSetting
.
fromPartial
({
locale
:
"en"
,
appearance
:
"auto"
,
memoVisibility
:
"PRIVATE"
,
});
};
// Request cache is used to prevent multiple requests.
// Request cache is used to prevent multiple requests.
const
requestCache
=
new
Map
<
string
,
Promise
<
any
>>
();
const
requestCache
=
new
Map
<
string
,
Promise
<
any
>>
();
...
@@ -57,4 +71,38 @@ export const useUserV1Store = create<UserV1Store>()((set, get) => ({
...
@@ -57,4 +71,38 @@ export const useUserV1Store = create<UserV1Store>()((set, get) => ({
set
(
userMap
);
set
(
userMap
);
return
updatedUser
;
return
updatedUser
;
},
},
deleteUser
:
async
(
name
:
string
)
=>
{
await
userServiceClient
.
deleteUser
({
name
,
});
},
fetchCurrentUser
:
async
()
=>
{
const
{
user
}
=
await
authServiceClient
.
getAuthStatus
({});
if
(
!
user
)
{
throw
new
Error
(
"User not found"
);
}
set
({
currentUser
:
user
});
const
{
setting
}
=
await
userServiceClient
.
getUserSetting
({});
set
({
userSetting
:
UserSetting
.
fromPartial
({
...
getDefaultUserSetting
(),
...
setting
,
}),
});
return
user
;
},
setCurrentUser
:
(
user
:
User
)
=>
{
set
({
currentUser
:
user
});
},
updateUserSetting
:
async
(
userSetting
:
Partial
<
UserSetting
>
,
updateMask
:
string
[])
=>
{
const
{
setting
:
updatedUserSetting
}
=
await
userServiceClient
.
updateUserSetting
({
setting
:
userSetting
,
updateMask
:
updateMask
,
});
if
(
!
updatedUserSetting
)
{
throw
new
Error
(
"User setting not found"
);
}
set
({
userSetting
:
updatedUserSetting
});
return
updatedUserSetting
;
},
}));
}));
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment