poi-plugin-quest-info-2 0.4.2 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Settings.tsx CHANGED
@@ -1,11 +1,16 @@
1
1
  import React, { StrictMode, useCallback } from 'react'
2
- import { Button, AnchorButton, Text } from '@blueprintjs/core'
2
+ import { Button, AnchorButton, Text, Checkbox } from '@blueprintjs/core'
3
3
  import { IconNames } from '@blueprintjs/icons'
4
4
  import styled from 'styled-components'
5
5
  import { version as PACKAGE_VERSION, homepage } from '../package.json'
6
6
  import { version as DATA_VERSION } from '../build/kcanotifyGamedata'
7
7
  import { usePluginTranslation } from './poi'
8
- import { removeStorage } from './store'
8
+ import {
9
+ useRemoveStorage,
10
+ StoreProvider,
11
+ useLanguage,
12
+ usePreferKcwiki,
13
+ } from './store'
9
14
 
10
15
  const Container = styled.div`
11
16
  display: flex;
@@ -18,27 +23,52 @@ const Container = styled.div`
18
23
  }
19
24
  `
20
25
 
21
- export const Settings = () => {
26
+ const useIsSimplifiedChinese = () => useLanguage() === 'zh-CN'
27
+
28
+ const SettingsMain = () => {
22
29
  const { t } = usePluginTranslation()
23
- const handleClearCache = useCallback(() => removeStorage(), [])
30
+ const isSimplifiedChinese = useIsSimplifiedChinese()
31
+ const removeStorage = useRemoveStorage()
32
+ const [preferKcwiki, setPreferKcwiki] = usePreferKcwiki()
33
+ const handleEnabledChange: React.FormEventHandler<HTMLInputElement> =
34
+ useCallback(() => {
35
+ setPreferKcwiki(!preferKcwiki)
36
+ }, [preferKcwiki, setPreferKcwiki])
37
+
24
38
  return (
25
- <StrictMode>
26
- <Container>
27
- <Text>{t('Version', { version: PACKAGE_VERSION })}</Text>
28
- <Text>{t('Data Version', { version: DATA_VERSION })}</Text>
29
- <AnchorButton
30
- icon={IconNames.CODE}
31
- rightIcon={IconNames.SHARE}
32
- text={t('View source code on GitHub')}
33
- href={homepage}
34
- target="_blank"
35
- ></AnchorButton>
36
- <Button
37
- icon={IconNames.TRASH}
38
- text={t('Restore defaults')}
39
- onClick={handleClearCache}
40
- ></Button>
41
- </Container>
42
- </StrictMode>
39
+ <>
40
+ <Checkbox
41
+ checked={preferKcwiki}
42
+ disabled={!isSimplifiedChinese}
43
+ label={t('Use Kcwiki data')}
44
+ onChange={handleEnabledChange}
45
+ />
46
+
47
+ <Text>{t('Version', { version: PACKAGE_VERSION })}</Text>
48
+ <Text>{t('Data Version', { version: DATA_VERSION })}</Text>
49
+ <AnchorButton
50
+ icon={IconNames.CODE}
51
+ rightIcon={IconNames.SHARE}
52
+ text={t('View source code on GitHub')}
53
+ href={homepage}
54
+ target="_blank"
55
+ ></AnchorButton>
56
+
57
+ <Button
58
+ icon={IconNames.TRASH}
59
+ text={t('Restore defaults')}
60
+ onClick={removeStorage}
61
+ ></Button>
62
+ </>
43
63
  )
44
64
  }
65
+
66
+ export const Settings = () => (
67
+ <StrictMode>
68
+ <StoreProvider>
69
+ <Container>
70
+ <SettingsMain />
71
+ </Container>
72
+ </StoreProvider>
73
+ </StrictMode>
74
+ )
package/src/Toolbar.tsx CHANGED
@@ -3,7 +3,7 @@ import { IconNames } from '@blueprintjs/icons'
3
3
  import styled from 'styled-components'
4
4
  import React, { useCallback } from 'react'
5
5
  import type { ChangeEvent } from 'react'
6
- import { useThrottle } from './utils'
6
+ import { useThrottle } from 'react-use'
7
7
  import { useQuest, useStore } from './store'
8
8
  import {
9
9
  ALL_TYPE_TAG,
@@ -158,7 +158,9 @@ const useToolbarFilter = () => {
158
158
 
159
159
  const stringFilter = useCallback(
160
160
  (quest: KcanotifyQuestExt) => {
161
- const text = `${quest.code} ${quest.name} ${quest.desc}`
161
+ const text = `${quest.code} ${quest.name} ${quest.desc} ${
162
+ quest.memo ?? ''
163
+ }`
162
164
  if (!searchKeywords) {
163
165
  return true
164
166
  }
@@ -1,5 +1,17 @@
1
- import { version } from '../../build/kcanotifyGamedata'
1
+ import { version, QuestData } from '../../build/kcanotifyGamedata'
2
2
 
3
3
  test('should Kcanotify Game data version correct', () => {
4
- expect(version).toMatchInlineSnapshot(`"5.3.0.3"`)
4
+ expect(version).toMatchInlineSnapshot(`"5.3.3.0"`)
5
+ })
6
+
7
+ test('should Kcanotify Game data keys correct', () => {
8
+ expect(Object.keys(QuestData)).toMatchInlineSnapshot(`
9
+ Array [
10
+ "zh-CN",
11
+ "zh-TW",
12
+ "ja-JP",
13
+ "en-US",
14
+ "ko-KR",
15
+ ]
16
+ `)
5
17
  })
@@ -0,0 +1,9 @@
1
+ import { KcwikiQuestData } from '../../build/kcQuestsData'
2
+
3
+ test('should KcwikiQuestData Game data keys correct', () => {
4
+ expect(Object.keys(KcwikiQuestData)).toMatchInlineSnapshot(`
5
+ Array [
6
+ "zh-CN",
7
+ ]
8
+ `)
9
+ })
@@ -43,6 +43,10 @@ const CardBody = styled.div`
43
43
  display: flex;
44
44
  flex: 1;
45
45
  flex-direction: column;
46
+
47
+ * + * {
48
+ margin-top: 8px;
49
+ }
46
50
  `
47
51
 
48
52
  const CardTail = styled.div`
package/src/patch.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  import { name as PACKAGE_NAME } from '../package.json'
2
2
  import { getPoiStore, importFromPoi } from './poi'
3
3
  import { QuestData } from '../build/kcanotifyGamedata'
4
-
4
+ import { KcwikiQuestData } from '../build/kcQuestsData'
5
+ import {
6
+ checkIsKcwikiSupportedLanguages,
7
+ getStorage,
8
+ isSupportedLanguages,
9
+ } from './store'
5
10
  const LEGACY_QUEST_PLUGIN_ID = 'poi-plugin-quest-info'
6
11
  const HACK_KEY = `__patched-from-${PACKAGE_NAME}`
7
12
 
@@ -19,6 +24,28 @@ const isLegacyQuestPluginEnabled = async () => {
19
24
  return false
20
25
  }
21
26
 
27
+ const getQuestState = (maybeLanguage: string) => {
28
+ const supported = isSupportedLanguages(maybeLanguage)
29
+ if (!supported) {
30
+ return {}
31
+ }
32
+ const preferKcwikiData = getStorage()?.preferKcwikiData ?? true
33
+ const kcwikiSupported = checkIsKcwikiSupportedLanguages(maybeLanguage)
34
+
35
+ const data =
36
+ preferKcwikiData && kcwikiSupported
37
+ ? KcwikiQuestData[maybeLanguage]
38
+ : QuestData[maybeLanguage]
39
+
40
+ return Object.entries(data).reduce((acc, [apiNo, { code, desc }]) => {
41
+ acc[apiNo] = {
42
+ wiki_id: code,
43
+ condition: desc,
44
+ }
45
+ return acc
46
+ }, {} as Record<string, { wiki_id: string; condition: string }>)
47
+ }
48
+
22
49
  /**
23
50
  * Patch the reducer of `poi-plugin-quest-info` for poi's task panel tips
24
51
  * See https://github.com/poooi/poi/blob/da75b507e8f67615a39dc4fdb466e34ff5b5bdcf/views/components/main/parts/task-panel.es#L243
@@ -30,23 +57,6 @@ export const patchLegacyQuestPluginReducer = async () => {
30
57
  return
31
58
  }
32
59
 
33
- const getQuestState = (maybeLanguage: string) => {
34
- if (!(maybeLanguage in QuestData)) {
35
- return {}
36
- }
37
- const lang = maybeLanguage as keyof typeof QuestData
38
- return Object.entries(QuestData[lang]).reduce(
39
- (acc, [apiNo, { code, desc }]) => {
40
- acc[apiNo] = {
41
- wiki_id: code,
42
- condition: desc,
43
- }
44
- return acc
45
- },
46
- {} as Record<string, { wiki_id: string; condition: string }>
47
- )
48
- }
49
-
50
60
  const language = (globalThis as any).i18next.language
51
61
  const initState = {
52
62
  [HACK_KEY]: true,
@@ -1,6 +1,6 @@
1
1
  import { QuestData } from '../build/kcanotifyGamedata'
2
2
 
3
- export type KcanotifyQuest = {
3
+ type KcanotifyQuest = {
4
4
  code: string
5
5
  name: string
6
6
  desc: string
@@ -1,2 +1,3 @@
1
1
  export * from './store'
2
2
  export * from './quest'
3
+ export * from './kcwiki'
@@ -0,0 +1,29 @@
1
+ import { KcwikiQuestData } from '../../build/kcQuestsData'
2
+ import { useStore } from '.'
3
+
4
+ export const usePreferKcwiki = () => {
5
+ const {
6
+ store: { preferKcwikiData },
7
+ updateStore,
8
+ } = useStore()
9
+ const setPreferKcwikiData = (val: boolean) =>
10
+ updateStore({ preferKcwikiData: val })
11
+ return [preferKcwikiData, setPreferKcwikiData] as const
12
+ }
13
+
14
+ export const checkIsKcwikiSupportedLanguages = (
15
+ lang: string
16
+ ): lang is keyof typeof KcwikiQuestData => lang in KcwikiQuestData
17
+
18
+ export const useKcwikiData = (lang: string) => {
19
+ const [preferKcwiki] = usePreferKcwiki()
20
+ const supported = checkIsKcwikiSupportedLanguages(lang)
21
+
22
+ if (!preferKcwiki) {
23
+ return null
24
+ }
25
+ if (!supported) {
26
+ return null
27
+ }
28
+ return KcwikiQuestData[lang]
29
+ }
@@ -1,4 +1,5 @@
1
1
  import { useCallback, useEffect, useState } from 'react'
2
+ import { checkIsKcwikiSupportedLanguages } from '.'
2
3
  import { QuestData } from '../../build/kcanotifyGamedata'
3
4
  import {
4
5
  activeQuestsSelector,
@@ -9,17 +10,29 @@ import {
9
10
  usePluginTranslation,
10
11
  } from '../poi'
11
12
  import { getCategory, KcanotifyQuestExt } from '../questHelper'
13
+ import { useKcwikiData } from './kcwiki'
12
14
  import { useStore } from './store'
13
15
 
14
16
  const DEFAULT_LANG = 'ja-JP'
15
17
 
18
+ export const checkIsKcanotifySupportedLanguages = (
19
+ lang: string
20
+ ): lang is keyof typeof QuestData => lang in QuestData
21
+
22
+ export const isSupportedLanguages = (
23
+ lang: string
24
+ ): lang is keyof typeof QuestData =>
25
+ checkIsKcanotifySupportedLanguages(lang) ||
26
+ checkIsKcwikiSupportedLanguages(lang)
27
+
16
28
  export const useLanguage = () => {
17
- const { i18n } = usePluginTranslation()
18
- const language =
19
- i18n.language in QuestData
20
- ? (i18n.language as keyof typeof QuestData)
21
- : DEFAULT_LANG
22
- return language
29
+ const {
30
+ i18n: { language },
31
+ } = usePluginTranslation()
32
+ const lang = checkIsKcanotifySupportedLanguages(language)
33
+ ? language
34
+ : DEFAULT_LANG
35
+ return lang
23
36
  }
24
37
 
25
38
  const useActiveQuest = () => {
@@ -35,8 +48,12 @@ const useActiveQuest = () => {
35
48
  return activeQuests
36
49
  }
37
50
 
38
- const useKcanotifyQuestMap = () => {
51
+ const useQuestMap = () => {
39
52
  const lang = useLanguage()
53
+ const kcwikiData = useKcwikiData(lang)
54
+ if (kcwikiData) {
55
+ return kcwikiData
56
+ }
40
57
  return QuestData[lang]
41
58
  }
42
59
 
@@ -52,7 +69,7 @@ const useGameQuest = () => {
52
69
 
53
70
  export const useQuest = (): KcanotifyQuestExt[] => {
54
71
  const activeQuest = useActiveQuest()
55
- const kcanotifyQuestMap = useKcanotifyQuestMap()
72
+ const questMap = useQuestMap()
56
73
  const gameQuest = useGameQuest()
57
74
  const {
58
75
  store: { syncWithGame },
@@ -66,13 +83,11 @@ export const useQuest = (): KcanotifyQuestExt[] => {
66
83
  return gameQuest.map((quest) => {
67
84
  const gameId = String(quest.api_no)
68
85
  const active = gameId in activeQuest
69
- if (gameId in kcanotifyQuestMap) {
86
+ if (gameId in questMap) {
70
87
  return {
71
88
  gameId,
72
89
  active,
73
- ...kcanotifyQuestMap[
74
- gameId as unknown as keyof typeof kcanotifyQuestMap
75
- ],
90
+ ...questMap[gameId as unknown as keyof typeof questMap],
76
91
  }
77
92
  }
78
93
 
@@ -88,7 +103,7 @@ export const useQuest = (): KcanotifyQuestExt[] => {
88
103
  })
89
104
  } else {
90
105
  // Return all recorded quests
91
- return Object.entries(kcanotifyQuestMap).map(([gameId, val]) => ({
106
+ return Object.entries(questMap).map(([gameId, val]) => ({
92
107
  gameId,
93
108
  active: gameId in activeQuest,
94
109
  ...val,
@@ -4,13 +4,10 @@ import React, {
4
4
  SetStateAction,
5
5
  useCallback,
6
6
  useContext,
7
- useEffect,
8
- useState,
9
7
  } from 'react'
10
- import { IN_POI } from '../poi'
11
8
  import { ALL_TYPE_TAG, ALL_CATEGORY_TAG } from '../tags'
12
9
  import { name as PACKAGE_NAME } from '../../package.json'
13
- import { useMount, useUpdateEffect } from '../utils'
10
+ import { createGlobalState, useMount, useUpdateEffect } from 'react-use'
14
11
 
15
12
  export const initialState = {
16
13
  searchInput: '',
@@ -21,23 +18,18 @@ export const initialState = {
21
18
  [ALL_CATEGORY_TAG.name]: true,
22
19
  } as Record<string, boolean>,
23
20
  largeCard: null as null | string,
24
- syncWithGame: IN_POI,
21
+ syncWithGame: false,
22
+ preferKcwikiData: true,
25
23
  }
26
24
 
27
25
  export type State = typeof initialState
28
26
 
29
27
  // Persist state
30
28
  const STORAGE_KEY = PACKAGE_NAME
31
- let onRemoveStorage: (() => void)[] = []
32
- export const removeStorage = () => {
33
- localStorage.removeItem(STORAGE_KEY)
34
- onRemoveStorage.forEach((i) => i())
35
- }
36
29
 
37
30
  const useStorage = (
38
31
  store: State,
39
32
  setState: (state: State) => void,
40
- onRemove = () => {},
41
33
  merge = true
42
34
  ) => {
43
35
  // Load storage at mount
@@ -46,7 +38,7 @@ const useStorage = (
46
38
  if (stringStore == null) {
47
39
  return
48
40
  }
49
- const parsedStorage = JSON.parse(stringStore)
41
+ const parsedStorage: State = JSON.parse(stringStore)
50
42
  // TODO use deep merge
51
43
  const storageStore = merge ? { ...store, ...parsedStorage } : parsedStorage
52
44
  setState(storageStore)
@@ -57,24 +49,24 @@ const useStorage = (
57
49
  const serializedStore = JSON.stringify(store)
58
50
  localStorage.setItem(STORAGE_KEY, serializedStore)
59
51
  }, [store])
52
+ }
60
53
 
61
- useEffect(() => {
62
- onRemoveStorage.push(onRemove)
63
- return () => {
64
- onRemoveStorage = onRemoveStorage.filter((i) => i !== onRemove)
65
- }
66
- })
54
+ export const getStorage = () => {
55
+ const stringStore = localStorage.getItem(STORAGE_KEY)
56
+ if (stringStore == null) {
57
+ return
58
+ }
59
+ return JSON.parse(stringStore) as State
67
60
  }
68
61
 
69
62
  const StateContext = createContext<State>(initialState)
70
63
  const SetStateContext = createContext<Dispatch<SetStateAction<State>>>(() => {})
71
64
 
72
- export const StoreProvider = ({ children }: { children: React.ReactChild }) => {
73
- const [state, setState] = useState(initialState)
74
- const onStorageRemove = useCallback(() => {
75
- setState(initialState)
76
- }, [])
77
- useStorage(state, setState, onStorageRemove)
65
+ const useGlobalState = createGlobalState<State>(initialState)
66
+
67
+ export const StoreProvider = ({ children }: { children?: React.ReactNode }) => {
68
+ const [state, setState] = useGlobalState()
69
+ useStorage(state, setState)
78
70
  return (
79
71
  <SetStateContext.Provider value={setState}>
80
72
  <StateContext.Provider value={state}>{children}</StateContext.Provider>
@@ -91,3 +83,11 @@ export const useStore = () => {
91
83
  )
92
84
  return { store, setStore, updateStore }
93
85
  }
86
+
87
+ export const useRemoveStorage = () => {
88
+ const { updateStore } = useStore()
89
+ return () => {
90
+ localStorage.removeItem(STORAGE_KEY)
91
+ updateStore(initialState)
92
+ }
93
+ }
package/src/utils.ts DELETED
@@ -1,77 +0,0 @@
1
- import { useEffect, useRef, useState, EffectCallback } from 'react'
2
-
3
- // See react-use
4
- // licensed under the The Unlicense
5
- // https://github.com/streamich/react-use
6
-
7
- const useEffectOnce = (effect: EffectCallback) => {
8
- // eslint-disable-next-line react-hooks/exhaustive-deps
9
- useEffect(effect, [])
10
- }
11
-
12
- export const useMount = (fn: () => void) => {
13
- useEffectOnce(() => {
14
- fn()
15
- })
16
- }
17
-
18
- const useUnmount = (fn: () => any): void => {
19
- const fnRef = useRef(fn)
20
-
21
- // update the ref each render so if it change the newest callback will be invoked
22
- fnRef.current = fn
23
-
24
- useEffectOnce(() => () => fnRef.current())
25
- }
26
-
27
- export const useThrottle = <T>(value: T, ms = 200) => {
28
- const [state, setState] = useState<T>(value)
29
- const timeout = useRef<ReturnType<typeof setTimeout>>()
30
- const nextValue = useRef(null) as any
31
- const hasNextValue = useRef(0) as any
32
-
33
- useEffect(() => {
34
- if (!timeout.current) {
35
- setState(value)
36
- const timeoutCallback = () => {
37
- if (hasNextValue.current) {
38
- hasNextValue.current = false
39
- setState(nextValue.current)
40
- timeout.current = setTimeout(timeoutCallback, ms)
41
- } else {
42
- timeout.current = undefined
43
- }
44
- }
45
- timeout.current = setTimeout(timeoutCallback, ms)
46
- } else {
47
- nextValue.current = value
48
- hasNextValue.current = true
49
- }
50
- // eslint-disable-next-line react-hooks/exhaustive-deps
51
- }, [value])
52
-
53
- useUnmount(() => {
54
- timeout.current && clearTimeout(timeout.current)
55
- })
56
-
57
- return state
58
- }
59
-
60
- function useFirstMountState(): boolean {
61
- const isFirst = useRef(true)
62
- if (isFirst.current) {
63
- isFirst.current = false
64
- return true
65
- }
66
- return isFirst.current
67
- }
68
-
69
- export const useUpdateEffect: typeof useEffect = (effect, deps) => {
70
- const isFirstMount = useFirstMountState()
71
- useEffect(() => {
72
- if (!isFirstMount) {
73
- return effect()
74
- }
75
- // eslint-disable-next-line react-hooks/exhaustive-deps
76
- }, deps)
77
- }