Skip to content

Commit ba027ab

Browse files
committed
refactor: improve config and user
1 parent 46fdc01 commit ba027ab

File tree

12 files changed

+190
-103
lines changed

12 files changed

+190
-103
lines changed

src/actions/user.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Action, ActionPanel, Icon, showHUD } from '@raycast/api'
2+
import { Login } from '../views/login'
23

34
export const openProfile = (username: string) => [
45
<Action.OpenInBrowser
@@ -25,3 +26,13 @@ export const openProfile = (username: string) => [
2526
/>
2627
</ActionPanel.Submenu>,
2728
]
29+
30+
export const loginNewUser = (
31+
<Action.Push
32+
key="userUser"
33+
title="登录新用户"
34+
target={<Login />}
35+
icon={Icon.Plus}
36+
shortcut={{ modifiers: ['cmd'], key: 'n' }}
37+
/>
38+
)

src/components/user-select.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
import { Form } from '@raycast/api'
22
import { useUsers } from '../hooks/user'
3+
import type { ConfigUser } from '../utils/config'
34

4-
export function UserSelect() {
5-
const { users } = useUsers()
5+
export function UserSelect({
6+
onChange,
7+
}: {
8+
onChange?: (user: ConfigUser | undefined) => void
9+
}) {
10+
const { users, findUser } = useUsers()
11+
12+
const handleChange = (userId: string) => {
13+
if (!onChange) return
14+
const user = findUser(userId)
15+
onChange(user)
16+
}
617

718
return (
8-
<Form.Dropdown id="userId" title="用户">
19+
<Form.Dropdown id="userId" title="用户" onChange={handleChange}>
920
{users.map((user) => (
1021
<Form.Dropdown.Item
1122
key={user.userId}

src/hooks/config.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { useEffect, useState } from 'react'
2+
import { defaultConfig, readConfig, writeConfig } from '../utils/config'
3+
import type { Config } from '../utils/config'
4+
5+
export const useConfig = () => {
6+
const [config, setState] = useState<Config>(defaultConfig)
7+
const [ready, setReady] = useState(false)
8+
9+
const setConfig = async (config: Config) => {
10+
await writeConfig(config)
11+
await reload()
12+
}
13+
14+
const reload = async () => {
15+
setState(await readConfig())
16+
setReady(true)
17+
}
18+
19+
useEffect(() => {
20+
reload()
21+
}, [])
22+
23+
return {
24+
config,
25+
ready,
26+
setConfig,
27+
reload,
28+
}
29+
}

src/hooks/user.ts

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,67 @@
1-
import { useEffect, useMemo, useState } from 'react'
1+
import { useMemo } from 'react'
22
import { JikeClient } from 'jike-sdk'
3-
import { getConfig } from '../utils/config'
3+
import { getUserIndex } from '../utils/user'
4+
import { useConfig } from './config'
45
import type { ConfigUser } from '../utils/config'
56

67
export function useUsers() {
7-
const [users, setUsers] = useState<ConfigUser[]>([])
8+
const { config, ready, setConfig, reload } = useConfig()
9+
const { users } = config
10+
const noUser = ready ? users.length === 0 : false
811

9-
const update = () => getConfig().then((cfg) => setUsers(cfg.users))
12+
const findUser = (userId: string) => users.find((u) => u.userId === userId)
1013

11-
const findUser = (userId: string) =>
12-
useMemo(() => users.find((u) => u.userId === userId), [users])
13-
14-
useEffect(() => {
15-
update()
16-
}, [])
14+
const setUsers = async (users: ConfigUser[]) =>
15+
setConfig({ ...config, users })
1716

1817
return {
18+
ready,
1919
users,
20-
update,
20+
noUser,
21+
reload,
2122
findUser,
23+
setUsers,
2224
}
2325
}
2426

25-
export function useClient(user?: ConfigUser) {
26-
const client = useMemo(() => user && JikeClient.fromJSON(user), [user])
27+
export function useClient(user: ConfigUser): JikeClient
28+
export function useClient(user: ConfigUser | undefined): JikeClient | undefined
29+
export function useClient(
30+
user: ConfigUser | undefined
31+
): JikeClient | undefined {
32+
return useMemo(() => user && JikeClient.fromJSON(user), [user])
33+
}
34+
35+
interface UseUser<isUser extends boolean = false> {
36+
user: ConfigUser | (isUser extends true ? never : undefined)
37+
client: JikeClient | (isUser extends true ? never : undefined)
38+
setUser: (newUser: ConfigUser | undefined) => Promise<void>
39+
}
40+
export function useUser(userId: string): UseUser<false>
41+
export function useUser(user: ConfigUser): UseUser<true>
42+
export function useUser(userId: string | ConfigUser): UseUser<boolean> {
43+
const { users, findUser, setUsers } = useUsers()
44+
const user =
45+
typeof userId === 'string'
46+
? useMemo(() => findUser(userId), [users, userId])
47+
: userId
48+
const client = useClient(user)
49+
const index = useMemo(() => getUserIndex(users, user), [users, user])
50+
51+
const setUser = (newUser: ConfigUser | undefined) => {
52+
if (index === -1) throw new Error('User not found')
53+
54+
if (newUser) {
55+
users[index] = newUser
56+
} else {
57+
users.splice(index, 1)
58+
}
59+
return setUsers(users)
60+
}
2761

2862
return {
63+
user,
2964
client,
65+
setUser,
3066
}
3167
}

src/utils/config.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,12 @@ export interface Config {
88
users: ConfigUser[]
99
}
1010

11+
export const defaultConfig: Config = { users: [] }
1112
export const configPath = path.resolve(environment.supportPath, 'config.json')
1213

13-
export const getConfig = async () => {
14-
const defaultConfig: Config = { users: [] }
14+
export const readConfig = async () => {
1515
return (await readJSON<Config>(configPath)) || defaultConfig
1616
}
1717

18-
export const updateConfig = async (
19-
update: (cfg: Config) => void | Config | Promise<Config | void>
20-
) => {
21-
let cfg = await getConfig()
22-
cfg = (await update(cfg)) || cfg
23-
await writeJSON(configPath, cfg)
24-
}
18+
export const writeConfig = async (config: Config) =>
19+
writeJSON(configPath, config)

src/utils/user.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { ConfigUser } from './config'
22

3-
export const isSameUser = (left: ConfigUser, right: ConfigUser) =>
3+
export const isSameUser = (left: ConfigUser, right: ConfigUser | undefined) =>
44
// left.endpointUrl === right.endpointUrl &&
5-
left.userId === right.userId
5+
left.userId === right?.userId
66

7-
export const findUser = (users: ConfigUser[], user: ConfigUser) => {
8-
const index = users.findIndex((u) => isSameUser(user, u))
9-
return [users[index], index] as const
10-
}
7+
export const getUserIndex = (
8+
users: ConfigUser[],
9+
user: ConfigUser | undefined
10+
) => users.findIndex((u) => isSameUser(u, user))

src/views/like-top.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import {
1010
import { limit } from 'jike-sdk'
1111
import { useEffect, useMemo, useState } from 'react'
1212
import { UserSelect } from '../components/user-select'
13-
import { useClient, useUsers } from '../hooks/user'
13+
import { useUser, useUsers } from '../hooks/user'
1414
import { handleError } from '../utils/errors'
1515
import { openProfile } from '../actions/user'
16+
import { NoUser } from './no-user'
1617
import type { Entity, JikePostWithDetail } from 'jike-sdk'
1718

1819
export interface LikeTopForm {
@@ -23,12 +24,11 @@ export interface LikeTopForm {
2324

2425
export function LikeTop() {
2526
const { push } = useNavigation()
27+
const { noUser } = useUsers()
2628

27-
const onSubmit = (form: LikeTopForm) => {
28-
push(<LikeTopResult {...form} />)
29-
}
29+
const onSubmit = (form: LikeTopForm) => push(<LikeTopResult {...form} />)
3030

31-
return (
31+
return !noUser ? (
3232
<Form
3333
navigationTitle="点赞排行榜"
3434
actions={
@@ -42,6 +42,8 @@ export function LikeTop() {
4242
<Form.TextField id="postCount" title="动态数量" defaultValue="0" />
4343
<Form.Description text="统计多少条最近发布的动态,0 为所有动态" />
4444
</Form>
45+
) : (
46+
<NoUser />
4547
)
4648
}
4749

@@ -55,6 +57,7 @@ function LikeTopResult({ userId, topCount, postCount }: LikeTopForm) {
5557
const [loading, setLoading] = useState(false)
5658
const [posts, setPosts] = useState<JikePostWithDetail[]>([])
5759
const [likeStat, setLikeStat] = useState<LikeStat[]>([])
60+
const { client } = useUser(userId)
5861

5962
const countRanking = useMemo(
6063
() =>
@@ -67,10 +70,6 @@ function LikeTopResult({ userId, topCount, postCount }: LikeTopForm) {
6770
)
6871
const getRanking = (count: number) => countRanking.indexOf(count) + 1
6972

70-
const { findUser } = useUsers()
71-
const user = findUser(userId)
72-
const { client } = useClient(user)
73-
7473
const fetchResult = async (ab: AbortController) => {
7574
if (!client) return
7675

src/views/login/index.tsx

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { popToRoot, useNavigation } from '@raycast/api'
22
import { JikeClient } from 'jike-sdk'
33
import { useMemo } from 'react'
4-
import { updateConfig } from '../../utils/config'
5-
import { isSameUser } from '../../utils/user'
4+
import { getUserIndex } from '../../utils/user'
65
import { handleError } from '../../utils/errors'
6+
import { useUsers } from '../../hooks/user'
77
import { FormEndpointInfo } from './form-endpoint-info'
88
import { FormAuth } from './form-auth'
99
import type { AuthForm } from './form-auth'
@@ -19,6 +19,7 @@ export function Login() {
1919

2020
function Auth({ endpointInfo }: { endpointInfo: EndpointInfo }) {
2121
const client = useMemo(() => new JikeClient(endpointInfo), [endpointInfo])
22+
const { users, setUsers } = useUsers()
2223

2324
const onLogin = async ({
2425
areaCode,
@@ -36,15 +37,13 @@ function Auth({ endpointInfo }: { endpointInfo: EndpointInfo }) {
3637

3738
const user = await client.toJSON()
3839

39-
// Save
40-
await updateConfig(async (cfg) => {
41-
const index = cfg.users.findIndex((_auth) => isSameUser(user, _auth))
42-
if (index > -1) {
43-
cfg.users[index] = user
44-
} else {
45-
cfg.users.push(user)
46-
}
47-
})
40+
const idx = getUserIndex(users, user)
41+
if (idx > -1) {
42+
users[idx] = user
43+
} else {
44+
users.push(user)
45+
}
46+
setUsers(users)
4847

4948
popToRoot()
5049
return user.screenName

src/views/no-user.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ActionPanel, Detail } from '@raycast/api'
2+
import { loginNewUser } from '../actions/user'
3+
4+
export function NoUser() {
5+
const contents = `
6+
# 请先登录账号
7+
8+
**您需要登录账号后,才可以进行本操作**
9+
`
10+
return (
11+
<Detail
12+
markdown={contents}
13+
navigationTitle="未登录账号"
14+
actions={<ActionPanel>{loginNewUser}</ActionPanel>}
15+
/>
16+
)
17+
}

src/views/post.tsx

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,37 @@ import {
66
showToast,
77
useNavigation,
88
} from '@raycast/api'
9-
import { ApiOptions, JikeClient } from 'jike-sdk'
9+
import { ApiOptions } from 'jike-sdk'
10+
import { useState } from 'react'
1011
import { handleError } from '../utils/errors'
11-
import { useUsers } from '../hooks/user'
1212
import { UserSelect } from '../components/user-select'
13+
import { useClient, useUsers } from '../hooks/user'
14+
import { NoUser } from './no-user'
15+
import type { ConfigUser } from '../utils/config'
1316

1417
export function Post() {
1518
const { pop } = useNavigation()
16-
const { findUser } = useUsers()
19+
const { noUser } = useUsers()
20+
const [user, setUser] = useState<ConfigUser>()
21+
const client = useClient(user)
1722

18-
const submit = async ({
19-
userId,
20-
content,
21-
}: {
22-
userId: string
23-
content: string
24-
}) => {
25-
if (content.trim().length === 0) {
23+
const submit = async ({ content }: { content: string }) => {
24+
if (!user) {
25+
await showToast({
26+
title: '请选择用户',
27+
style: Toast.Style.Failure,
28+
})
29+
return
30+
} else if (content.trim().length === 0) {
2631
await showToast({
2732
title: '内容不能为空',
2833
style: Toast.Style.Failure,
2934
})
3035
return
3136
}
3237

33-
const user = findUser(userId)!
34-
const client = JikeClient.fromJSON(user)
3538
try {
36-
await client.createPost(ApiOptions.PostType.ORIGINAL, content)
39+
await client!.createPost(ApiOptions.PostType.ORIGINAL, content)
3740
} catch (err) {
3841
handleError(err)
3942
return
@@ -46,7 +49,7 @@ export function Post() {
4649
pop()
4750
}
4851

49-
return (
52+
return !noUser ? (
5053
<Form
5154
navigationTitle="发布动态"
5255
actions={
@@ -55,7 +58,7 @@ export function Post() {
5558
</ActionPanel>
5659
}
5760
>
58-
<UserSelect />
61+
<UserSelect onChange={setUser} />
5962

6063
<Form.TextArea
6164
id="content"
@@ -64,5 +67,7 @@ export function Post() {
6467
autoFocus
6568
/>
6669
</Form>
70+
) : (
71+
<NoUser />
6772
)
6873
}

0 commit comments

Comments
 (0)