poi-plugin-quest-info-2 0.8.9 → 0.9.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.
Files changed (39) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/CHANGELOG.md +20 -0
  4. package/README.md +3 -2
  5. package/build/kcQuestsData/DATA_VERSION +1 -1
  6. package/build/kcQuestsData/index.ts +1 -1
  7. package/build/kcQuestsData/quests-scn-new.json +1 -0
  8. package/build/kcQuestsData/quests-scn.json +57 -16
  9. package/build/kcanotifyGamedata/DATA_VERSION +1 -1
  10. package/build/kcanotifyGamedata/index.ts +1 -1
  11. package/build/prePostQuest.json +40 -5
  12. package/build/questCodeMap.json +6 -2
  13. package/i18n/en-US.json +8 -3
  14. package/i18n/index.ts +23 -4
  15. package/i18n/ja-JP.json +3 -3
  16. package/i18n/ko-KR.json +3 -2
  17. package/i18n/zh-CN.json +3 -3
  18. package/i18n/zh-TW.json +3 -3
  19. package/package.json +4 -2
  20. package/shims/globals.d.ts +6 -0
  21. package/src/Settings.tsx +67 -7
  22. package/src/Toolbar.tsx +53 -33
  23. package/src/__tests__/fixtures/firstLoginWithOneComplete.json +72 -0
  24. package/src/__tests__/fixtures/questList.json +338 -0
  25. package/src/__tests__/kcanotifyData.spec.ts +1 -1
  26. package/src/__tests__/kcwikiData.spec.ts +1 -1
  27. package/src/components/QuestCard/index.tsx +3 -3
  28. package/src/components/QuestCard/utils.tsx +3 -3
  29. package/src/patch.ts +3 -4
  30. package/src/poi/env.ts +4 -0
  31. package/src/poi/hooks.ts +55 -2
  32. package/src/poi/store.ts +25 -8
  33. package/src/poi/utils.ts +50 -0
  34. package/src/store/filterTags.ts +34 -13
  35. package/src/store/gameQuest.tsx +108 -5
  36. package/src/store/quest.ts +27 -83
  37. package/src/store/store.tsx +25 -19
  38. package/src/tags.tsx +83 -24
  39. package/tsconfig.json +1 -1
@@ -19,7 +19,7 @@ export const questStatusMap: Record<QUEST_STATUS, React.FC> = {
19
19
  [QUEST_STATUS.LOCKED]: function Locked() {
20
20
  const { t } = usePluginTranslation()
21
21
  return (
22
- <Tooltip content={t('Locked')}>
22
+ <Tooltip content={t('Locked', { number: '' })}>
23
23
  <Icon icon={IconNames.LOCK} iconSize={Icon.SIZE_LARGE}></Icon>
24
24
  </Tooltip>
25
25
  )
@@ -29,7 +29,7 @@ export const questStatusMap: Record<QUEST_STATUS, React.FC> = {
29
29
  [QUEST_STATUS.IN_PROGRESS]: function InProgress() {
30
30
  const { t } = usePluginTranslation()
31
31
  return (
32
- <Tooltip content={t('In Progress')}>
32
+ <Tooltip content={t('In Progress', { number: '' })}>
33
33
  <img src={IconInProgress}></img>
34
34
  </Tooltip>
35
35
  )
@@ -45,7 +45,7 @@ export const questStatusMap: Record<QUEST_STATUS, React.FC> = {
45
45
  [QUEST_STATUS.ALREADY_COMPLETED]: function AlreadyCompleted() {
46
46
  const { t } = usePluginTranslation()
47
47
  return (
48
- <Tooltip content={t('Already Completed')}>
48
+ <Tooltip content={t('Already Completed', { number: '' })}>
49
49
  <Icon icon={IconNames.TICK} iconSize={Icon.SIZE_LARGE}></Icon>
50
50
  </Tooltip>
51
51
  )
package/src/patch.ts CHANGED
@@ -1,14 +1,13 @@
1
- import { name as PACKAGE_NAME } from '../package.json'
2
- import { getPoiStore } from './poi/store'
3
- import { importFromPoi } from './poi/env'
1
+ import type { i18n } from 'i18next'
4
2
  import { QuestData } from '../build/kcanotifyGamedata'
5
3
  import { KcwikiQuestData } from '../build/kcQuestsData'
4
+ import { importFromPoi, PACKAGE_NAME } from './poi/env'
5
+ import { getPoiStore } from './poi/store'
6
6
  import {
7
7
  checkIsKcwikiSupportedLanguages,
8
8
  getStorage,
9
9
  isSupportedLanguages,
10
10
  } from './store'
11
- import type { i18n } from 'i18next'
12
11
 
13
12
  const LEGACY_QUEST_PLUGIN_ID = 'poi-plugin-quest-info'
14
13
  const HACK_KEY = `__patched-from-${PACKAGE_NAME}`
package/src/poi/env.ts CHANGED
@@ -1,3 +1,7 @@
1
+ import { name } from '../../package.json'
2
+
3
+ export const PACKAGE_NAME = name as 'poi-plugin-quest-info-2'
4
+
1
5
  export const IN_POI = 'POI_VERSION' in globalThis
2
6
  /**
3
7
  * Prevent webpack early error
package/src/poi/hooks.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  import { useEffect, useState } from 'react'
2
2
  import { useTranslation } from 'react-i18next'
3
- import { name as PACKAGE_NAME } from '../../package.json'
4
- import { observePluginStore, observePoiStore } from './store'
3
+ import { PACKAGE_NAME } from './env'
4
+ import {
5
+ exportPoiState,
6
+ importPoiState,
7
+ observePluginStore,
8
+ observePoiStore,
9
+ } from './store'
5
10
  import { GameQuest, PoiQuestState, PoiState, QuestTab } from './types'
6
11
 
7
12
  export const activeQuestsSelector = (state: PoiState): PoiQuestState =>
@@ -21,6 +26,7 @@ export const useActiveQuest = () => {
21
26
  }
22
27
 
23
28
  export const usePluginTranslation = () => {
29
+ // @ts-expect-error we declared a incorrect types in i18n/index.ts
24
30
  return useTranslation(PACKAGE_NAME)
25
31
  }
26
32
 
@@ -65,3 +71,50 @@ export const useIsQuestPluginTab = () => {
65
71
  const activeMainTab = useActiveTab()
66
72
  return activeMainTab === PACKAGE_NAME
67
73
  }
74
+
75
+ const checkQuestList = (questList: unknown): questList is GameQuest[] => {
76
+ if (!Array.isArray(questList)) {
77
+ return false
78
+ }
79
+ // just a simple check
80
+ return questList.every((q) => q && q.api_no)
81
+ }
82
+
83
+ export const useStateExporter = () => {
84
+ const exportQuestDataToClipboard = async () => {
85
+ const state = await exportPoiState()
86
+ if (!state?.ext[PACKAGE_NAME]._.questList) {
87
+ console.error('poi state', state)
88
+ throw new Error('Failed to export quest data! questList not found!')
89
+ }
90
+ return navigator.clipboard.writeText(
91
+ JSON.stringify(state?.ext[PACKAGE_NAME]._.questList)
92
+ )
93
+ }
94
+ const importAsPoiState = (stateString: string) => {
95
+ const maybeQuestList: unknown = JSON.parse(stateString)
96
+
97
+ if (!checkQuestList(maybeQuestList)) {
98
+ console.error(maybeQuestList)
99
+ throw new Error('Failed to import quest state! Incorrect data format!')
100
+ }
101
+
102
+ importPoiState({
103
+ ext: {
104
+ [PACKAGE_NAME]: {
105
+ _: { questList: maybeQuestList, tabId: QuestTab.ALL },
106
+ },
107
+ },
108
+ ui: {
109
+ activeMainTab: '',
110
+ activeFleetId: undefined,
111
+ activePluginName: undefined,
112
+ },
113
+ plugins: [],
114
+ })
115
+ }
116
+ return {
117
+ exportQuestDataToClipboard,
118
+ importAsPoiState,
119
+ }
120
+ }
package/src/poi/store.ts CHANGED
@@ -1,7 +1,6 @@
1
- import { name as PACKAGE_NAME } from '../../package.json'
2
1
  import type { PluginState } from '../reducer'
3
2
  import { id, noop } from '../utils'
4
- import { importFromPoi, IN_POI } from './env'
3
+ import { importFromPoi, IN_POI, PACKAGE_NAME } from './env'
5
4
  import type { PoiState, Store } from './types'
6
5
 
7
6
  /**
@@ -51,10 +50,11 @@ export const observePluginStore = <SelectedState = PluginState>(
51
50
  selector: (state: PluginState) => SelectedState = id as any
52
51
  ) => observePoiStore(onChange, (s) => selector(s?.ext[PACKAGE_NAME]))
53
52
 
54
- const fallbackStore: Store<PoiState> = {
55
- getState: noop as () => PoiState,
56
- subscribe: () => (() => {}) as () => () => void,
57
- }
53
+ const genFallbackStore = (state?: PoiState) =>
54
+ ({
55
+ getState: () => state,
56
+ subscribe: () => (() => {}) as () => () => void,
57
+ } as Store<PoiState>)
58
58
 
59
59
  let globalStore: Store<PoiState> | null = null
60
60
  /**
@@ -73,6 +73,23 @@ export const getPoiStore: () => Promise<Store<PoiState>> = async () => {
73
73
  console.warn('Load global store error', error)
74
74
  }
75
75
  }
76
- globalStore = fallbackStore
77
- return fallbackStore
76
+ globalStore = genFallbackStore()
77
+ return globalStore
78
+ }
79
+
80
+ export const exportPoiState = async () => {
81
+ if (!IN_POI) {
82
+ throw new Error(
83
+ 'Failed export state from poi! You are not currently in the poi environment!'
84
+ )
85
+ }
86
+ const { getState } = await getPoiStore()
87
+ return getState()
88
+ }
89
+
90
+ /**
91
+ * TODO fix state update
92
+ */
93
+ export const importPoiState = (state: PoiState) => {
94
+ globalStore = genFallbackStore(state)
78
95
  }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * See https://dev.poooi.app/docs/api-poi-utils.html#notifications
3
+ */
4
+ import { IN_POI } from './env'
5
+
6
+ export const toast = (message: string) => {
7
+ if (!IN_POI) {
8
+ // eslint-disable-next-line no-console
9
+ console.log('[Toast]', message)
10
+ return
11
+ }
12
+ window.toast(message)
13
+ }
14
+
15
+ export const tips = {
16
+ log(message: string) {
17
+ if (!IN_POI) {
18
+ // eslint-disable-next-line no-console
19
+ console.log('[log]', message)
20
+ return
21
+ }
22
+ // @ts-expect-error poi env
23
+ window.log(message) // display on the information bar below game window
24
+ },
25
+ warn(message: string) {
26
+ if (!IN_POI) {
27
+ console.warn('[warn]', message)
28
+ return
29
+ }
30
+ // @ts-expect-error poi env
31
+ window.warn(message) // display on the information bar below game window
32
+ },
33
+ error(message: string) {
34
+ if (!IN_POI) {
35
+ console.error('[error]', message)
36
+ return
37
+ }
38
+ // @ts-expect-error poi env
39
+ window.error(message) // display on the information bar below game window
40
+ },
41
+ success(message: string) {
42
+ if (!IN_POI) {
43
+ // eslint-disable-next-line no-console
44
+ console.log('[success]', message)
45
+ return
46
+ }
47
+ // @ts-expect-error poi env
48
+ window.success(message) // display on the information bar below game window
49
+ },
50
+ }
@@ -2,13 +2,8 @@ import { useCallback } from 'react'
2
2
  import { useUpdateEffect } from 'react-use'
3
3
  import { useGameTab } from '../poi/hooks'
4
4
  import { QuestTab } from '../poi/types'
5
- import {
6
- ALL_CATEGORY_TAG,
7
- ALL_TYPE_TAG,
8
- CATEGORY_TAGS,
9
- TYPE_TAGS,
10
- } from '../tags'
11
- import { useStore, useSyncWithGame } from './store'
5
+ import { CATEGORY_TAGS, TYPE_TAGS } from '../tags'
6
+ import { ALL_CATEGORY_TAG, ALL_TYPE_TAG, PROGRESS_TAG, useStore } from './store'
12
7
 
13
8
  export const useFilterTags = () => {
14
9
  const {
@@ -32,7 +27,7 @@ export const useFilterTags = () => {
32
27
  },
33
28
  [updateStore]
34
29
  )
35
- const manualSetTypeTags = useCallback(
30
+ const setMultiTypeTags = useCallback(
36
31
  (data: Record<string, boolean>) => {
37
32
  updateStore({ typeTags: data })
38
33
  },
@@ -49,18 +44,44 @@ export const useFilterTags = () => {
49
44
  setCategoryTags,
50
45
  setCategoryTagsAll,
51
46
  setTypeTags,
52
- manualSetTypeTags,
47
+ setMultiTypeTags,
53
48
  setTypeTagsAll,
54
49
  }
55
50
  }
56
51
 
52
+ export const useFilterProgressTag = () => {
53
+ const {
54
+ store: { progressTag },
55
+ updateStore,
56
+ } = useStore()
57
+
58
+ const toggleTag = useCallback(
59
+ (tag: PROGRESS_TAG) => {
60
+ if (progressTag === tag) {
61
+ updateStore({ progressTag: PROGRESS_TAG.All })
62
+ return
63
+ }
64
+ updateStore({ progressTag: tag })
65
+ },
66
+ [progressTag, updateStore]
67
+ )
68
+
69
+ return {
70
+ progressTag,
71
+ toggleTag,
72
+ }
73
+ }
74
+
75
+ /**
76
+ * @deprecated Should not update state when render
77
+ */
57
78
  export const useSyncGameTagEffect = () => {
58
- const { syncWithGame } = useSyncWithGame()
79
+ const { progressTag } = useFilterProgressTag()
59
80
  const filterTags = useFilterTags()
60
81
  const tab = useGameTab()
61
82
 
62
83
  useUpdateEffect(() => {
63
- if (!syncWithGame) {
84
+ if (progressTag !== PROGRESS_TAG.Unlocked) {
64
85
  return
65
86
  }
66
87
  switch (tab) {
@@ -80,7 +101,7 @@ export const useSyncGameTagEffect = () => {
80
101
  filterTags.setTypeTags('In Progress')
81
102
  break
82
103
  case QuestTab.OTHERS:
83
- filterTags.manualSetTypeTags({ Quarterly: true, Yearly: true })
104
+ filterTags.setMultiTypeTags({ Quarterly: true, Yearly: true })
84
105
  break
85
106
  case QuestTab.ONCE:
86
107
  filterTags.setTypeTags('One-time')
@@ -88,5 +109,5 @@ export const useSyncGameTagEffect = () => {
88
109
  default:
89
110
  break
90
111
  }
91
- }, [syncWithGame, tab])
112
+ }, [tab])
92
113
  }
@@ -1,20 +1,123 @@
1
- import React, { createContext, useContext } from 'react'
2
1
  import type { ReactNode } from 'react'
3
- import { GameQuest } from '../poi/types'
2
+ import React, { createContext, useContext } from 'react'
4
3
  import { useGameQuest } from '../poi/hooks'
4
+ import { GameQuest } from '../poi/types'
5
+ import {
6
+ getCompletedQuest,
7
+ getLockedQuest,
8
+ questApiStateToQuestStatus,
9
+ QUEST_STATUS,
10
+ } from '../questHelper'
5
11
 
6
- export const GameQuestContext = createContext<GameQuest[]>([])
12
+ export const GameQuestContext = createContext<{
13
+ gameQuest: GameQuest[]
14
+ questStatusQuery: (gameId: number) => QUEST_STATUS
15
+ lockedQuestNum: number
16
+ unlockedQuestNum: number
17
+ completedQuestNum: number
18
+ alreadyCompletedQuestNum: number
19
+ }>({
20
+ gameQuest: [],
21
+ questStatusQuery: () => QUEST_STATUS.UNKNOWN,
22
+ lockedQuestNum: 0,
23
+ unlockedQuestNum: 0,
24
+ completedQuestNum: 0,
25
+ alreadyCompletedQuestNum: 0,
26
+ })
27
+
28
+ const useQuestStatusQuery = (inProgressQuests: GameQuest[]) => {
29
+ const gameQuestIds = inProgressQuests.map((quest) => quest.api_no)
30
+ const unlockedGameQuest = Object.fromEntries(
31
+ inProgressQuests.map((quest) => [quest.api_no, quest])
32
+ )
33
+ const alreadyCompletedQuest = getCompletedQuest(gameQuestIds)
34
+ const lockedQuest = getLockedQuest(gameQuestIds)
35
+ const completedQuest = inProgressQuests
36
+ .map((quest) => questApiStateToQuestStatus(quest.api_state))
37
+ .filter((status) => status === QUEST_STATUS.COMPLETED)
38
+ return {
39
+ lockedQuestNum: Object.keys(lockedQuest).length,
40
+ unlockedQuestNum: Object.keys(unlockedGameQuest).length,
41
+ completedQuestNum: completedQuest.length,
42
+ alreadyCompletedQuestNum: Object.keys(alreadyCompletedQuest).length,
43
+ questStatusQuery: (gameId: number) => {
44
+ const theGameQuest = unlockedGameQuest[gameId]
45
+ if (theGameQuest) {
46
+ // the quest is in game
47
+ return questApiStateToQuestStatus(theGameQuest.api_state)
48
+ }
49
+
50
+ if (gameId in lockedQuest) {
51
+ return QUEST_STATUS.LOCKED
52
+ }
53
+ if (gameId in alreadyCompletedQuest) {
54
+ return QUEST_STATUS.ALREADY_COMPLETED
55
+ }
56
+ return QUEST_STATUS.UNKNOWN
57
+ },
58
+ }
59
+ }
7
60
 
8
61
  export const GameQuestProvider = ({ children }: { children?: ReactNode }) => {
9
62
  const gameQuest = useGameQuest()
63
+ const {
64
+ lockedQuestNum,
65
+ unlockedQuestNum,
66
+ completedQuestNum,
67
+ alreadyCompletedQuestNum,
68
+ questStatusQuery,
69
+ } = useQuestStatusQuery(gameQuest)
70
+
10
71
  return (
11
- <GameQuestContext.Provider value={gameQuest}>
72
+ <GameQuestContext.Provider
73
+ value={{
74
+ gameQuest,
75
+ questStatusQuery,
76
+ lockedQuestNum,
77
+ unlockedQuestNum,
78
+ completedQuestNum,
79
+ alreadyCompletedQuestNum,
80
+ }}
81
+ >
12
82
  {children}
13
83
  </GameQuestContext.Provider>
14
84
  )
15
85
  }
16
86
 
87
+ /**
88
+ * Get the questList from poi.
89
+ *
90
+ * Same as {@link useGameQuest}, but singleton
91
+ */
17
92
  export const useGlobalGameQuest = () => {
18
- const gameQuest = useContext(GameQuestContext)
93
+ const { gameQuest } = useContext(GameQuestContext)
19
94
  return gameQuest
20
95
  }
96
+
97
+ /**
98
+ * Get the questList from poi.
99
+ *
100
+ * Same as {@link useQuestStatusQuery}, but singleton
101
+ */
102
+ export const useGlobalQuestStatusQuery = () => {
103
+ const { questStatusQuery } = useContext(GameQuestContext)
104
+ return questStatusQuery
105
+ }
106
+
107
+ /**
108
+ * Get the number of quests in different states.
109
+ */
110
+ export const useGlobalQuestStatusNum = () => {
111
+ const {
112
+ lockedQuestNum,
113
+ unlockedQuestNum,
114
+ completedQuestNum,
115
+ alreadyCompletedQuestNum,
116
+ } = useContext(GameQuestContext)
117
+ return {
118
+ lockedQuestNum,
119
+ unlockedQuestNum,
120
+ completedQuestNum,
121
+ alreadyCompletedQuestNum,
122
+ }
123
+ }
@@ -1,19 +1,13 @@
1
- import { useCallback } from 'react'
2
1
  import { usePluginTranslation } from '../poi/hooks'
3
2
  import {
4
3
  DocQuest,
5
- getCategory,
6
- getCompletedQuest,
7
4
  getKcanotifyQuestData,
8
- getLockedQuest,
9
5
  getQuestIdByCode,
10
- questApiStateToQuestStatus,
11
6
  QUEST_STATUS,
12
7
  UnionQuest,
13
8
  } from '../questHelper'
14
- import { useGlobalGameQuest } from './gameQuest'
9
+ import { useGlobalGameQuest, useGlobalQuestStatusQuery } from './gameQuest'
15
10
  import { checkIsKcwikiSupportedLanguages, useKcwikiData } from './kcwiki'
16
- import { useStore, useSyncWithGame } from './store'
17
11
 
18
12
  const DEFAULT_LANG = 'ja-JP'
19
13
 
@@ -53,40 +47,27 @@ const useQuestMap = (): Record<string, DocQuest> => {
53
47
  export const useQuest = (): UnionQuest[] => {
54
48
  const docQuestMap = useQuestMap()
55
49
  const gameQuest = useGlobalGameQuest()
56
- const { syncWithGame } = useSyncWithGame()
57
-
58
- if (syncWithGame && gameQuest.length) {
59
- return gameQuest.map((quest) => {
60
- const gameId = quest.api_no
61
- if (gameId in docQuestMap) {
62
- return {
63
- gameId,
64
- gameQuest: quest,
65
- docQuest: docQuestMap[String(gameId) as keyof typeof docQuestMap],
66
- }
67
- }
68
-
69
- // Not yet recorded quest
70
- // May be a new quest
71
- return {
72
- gameId,
73
- gameQuest: quest,
74
- docQuest: {
75
- code: `${getCategory(quest.api_category).wikiSymbol}?`,
76
- name: quest.api_title,
77
- desc: quest.api_detail,
78
- },
79
- }
80
- })
81
- } else {
82
- // Return all recorded quests
83
- return Object.entries(docQuestMap).map(([gameId, val]) => ({
84
- gameId: +gameId,
85
- // Maybe empty
86
- gameQuest: gameQuest.find((quest) => quest.api_no === Number(gameId))!,
87
- docQuest: val,
88
- }))
89
- }
50
+ // TODO extract new quest from game quest
51
+ // Not yet recorded quest
52
+ // May be a new quest
53
+ // if (!(gameId in docQuestMap)) {
54
+ // return {
55
+ // gameId,
56
+ // gameQuest: quest,
57
+ // docQuest: {
58
+ // code: `${getCategory(quest.api_category).wikiSymbol}?`,
59
+ // name: quest.api_title,
60
+ // desc: quest.api_detail,
61
+ // },
62
+ // }
63
+ // }
64
+ // Return all recorded quests
65
+ return Object.entries(docQuestMap).map(([gameId, val]) => ({
66
+ gameId: +gameId,
67
+ // Maybe empty
68
+ gameQuest: gameQuest.find((quest) => quest.api_no === Number(gameId))!,
69
+ docQuest: val,
70
+ }))
90
71
  }
91
72
 
92
73
  export const useQuestByCode = (code: string) => {
@@ -101,50 +82,13 @@ export const useQuestByCode = (code: string) => {
101
82
  return null
102
83
  }
103
84
 
85
+ /**
86
+ * Get the completion status of a specific game quest
87
+ */
104
88
  export const useQuestStatus = (gameId: number | null) => {
105
- const gameQuest = useGlobalGameQuest()
106
-
89
+ const searcher = useGlobalQuestStatusQuery()
107
90
  if (!gameId) {
108
91
  return QUEST_STATUS.UNKNOWN
109
92
  }
110
- const theGameQuest = gameQuest.find((quest) => quest.api_no === gameId)
111
- if (theGameQuest) {
112
- // the quest is in game
113
- return questApiStateToQuestStatus(theGameQuest.api_state)
114
- }
115
-
116
- const gameQuestId = gameQuest.map((quest) => quest.api_no)
117
- const completedQuest = getCompletedQuest(gameQuestId)
118
- const lockedQuest = getLockedQuest(gameQuestId)
119
-
120
- if (gameId in lockedQuest) {
121
- return QUEST_STATUS.LOCKED
122
- }
123
- if (gameId in completedQuest) {
124
- return QUEST_STATUS.ALREADY_COMPLETED
125
- }
126
- return QUEST_STATUS.UNKNOWN
127
- }
128
-
129
- /**
130
- * @deprecated Not large card now
131
- */
132
- export const useLargeCard = () => {
133
- const {
134
- store: { largeCard },
135
- updateStore,
136
- } = useStore()
137
- const setLarge = useCallback(
138
- (gameId: string) => updateStore({ largeCard: gameId }),
139
- [updateStore]
140
- )
141
- const setMinimal = useCallback(
142
- () => updateStore({ largeCard: null }),
143
- [updateStore]
144
- )
145
- return {
146
- largeCard,
147
- setLarge,
148
- setMinimal,
149
- }
93
+ return searcher(gameId)
150
94
  }
@@ -7,10 +7,24 @@ import React, {
7
7
  useState,
8
8
  } from 'react'
9
9
  import { useMount, useUpdateEffect } from 'react-use'
10
- import { name as PACKAGE_NAME } from '../../package.json'
11
- import { ALL_CATEGORY_TAG, ALL_TYPE_TAG } from '../tags'
10
+ import { PACKAGE_NAME } from '../poi/env'
11
+ import { noop, yes } from '../utils'
12
12
  import { GameQuestProvider } from './gameQuest'
13
13
 
14
+ export const ALL_CATEGORY_TAG = {
15
+ name: 'All',
16
+ filter: yes,
17
+ } as const
18
+
19
+ export const ALL_TYPE_TAG = ALL_CATEGORY_TAG
20
+
21
+ export enum PROGRESS_TAG {
22
+ All = 'All',
23
+ Unlocked = 'Unlocked',
24
+ Locked = 'Locked',
25
+ AlreadyCompleted = 'AlreadyCompleted',
26
+ }
27
+
14
28
  export const initialState = {
15
29
  searchInput: '',
16
30
  typeTags: {
@@ -19,8 +33,8 @@ export const initialState = {
19
33
  categoryTags: {
20
34
  [ALL_CATEGORY_TAG.name]: true,
21
35
  } as Record<string, boolean>,
22
- largeCard: null as null | string,
23
- syncWithGame: false,
36
+ progressTag: PROGRESS_TAG.All,
37
+ syncWithGame: false as const,
24
38
  preferKcwikiData: true,
25
39
  }
26
40
 
@@ -39,7 +53,7 @@ const useStorage = <T,>(initialValue: T) => {
39
53
  return
40
54
  }
41
55
  const parsedStorage: T = JSON.parse(stringStore)
42
- setState(parsedStorage)
56
+ setState({ ...initialState, ...parsedStorage })
43
57
  } catch (error) {
44
58
  console.error('Failed to load storage', error)
45
59
  }
@@ -97,22 +111,14 @@ export const useRemoveStorage = () => {
97
111
  }
98
112
  }
99
113
 
114
+ /**
115
+ * @deprecated Use progress tag
116
+ */
100
117
  export const useSyncWithGame = () => {
101
- const {
102
- store: { syncWithGame },
103
- updateStore,
104
- } = useStore()
105
- const setSyncWithGame = useCallback(
106
- (value: boolean) => {
107
- updateStore({ syncWithGame: value })
108
- },
109
- [updateStore]
110
- )
111
- const toggleSyncWithGame = useCallback(() => {
112
- setSyncWithGame(!syncWithGame)
113
- }, [setSyncWithGame, syncWithGame])
118
+ const setSyncWithGame = noop
119
+ const toggleSyncWithGame = noop
114
120
  return {
115
- syncWithGame,
121
+ syncWithGame: false as const,
116
122
  setSyncWithGame,
117
123
  toggleSyncWithGame,
118
124
  }