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.
- package/.changeset/README.md +8 -0
- package/.changeset/config.json +11 -0
- package/CHANGELOG.md +20 -0
- package/README.md +3 -2
- package/build/kcQuestsData/DATA_VERSION +1 -1
- package/build/kcQuestsData/index.ts +1 -1
- package/build/kcQuestsData/quests-scn-new.json +1 -0
- package/build/kcQuestsData/quests-scn.json +57 -16
- package/build/kcanotifyGamedata/DATA_VERSION +1 -1
- package/build/kcanotifyGamedata/index.ts +1 -1
- package/build/prePostQuest.json +40 -5
- package/build/questCodeMap.json +6 -2
- package/i18n/en-US.json +8 -3
- package/i18n/index.ts +23 -4
- package/i18n/ja-JP.json +3 -3
- package/i18n/ko-KR.json +3 -2
- package/i18n/zh-CN.json +3 -3
- package/i18n/zh-TW.json +3 -3
- package/package.json +4 -2
- package/shims/globals.d.ts +6 -0
- package/src/Settings.tsx +67 -7
- package/src/Toolbar.tsx +53 -33
- package/src/__tests__/fixtures/firstLoginWithOneComplete.json +72 -0
- package/src/__tests__/fixtures/questList.json +338 -0
- package/src/__tests__/kcanotifyData.spec.ts +1 -1
- package/src/__tests__/kcwikiData.spec.ts +1 -1
- package/src/components/QuestCard/index.tsx +3 -3
- package/src/components/QuestCard/utils.tsx +3 -3
- package/src/patch.ts +3 -4
- package/src/poi/env.ts +4 -0
- package/src/poi/hooks.ts +55 -2
- package/src/poi/store.ts +25 -8
- package/src/poi/utils.ts +50 -0
- package/src/store/filterTags.ts +34 -13
- package/src/store/gameQuest.tsx +108 -5
- package/src/store/quest.ts +27 -83
- package/src/store/store.tsx +25 -19
- package/src/tags.tsx +83 -24
- 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 {
|
|
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
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 {
|
|
4
|
-
import {
|
|
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
|
|
55
|
-
|
|
56
|
-
|
|
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 =
|
|
77
|
-
return
|
|
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
|
}
|
package/src/poi/utils.ts
ADDED
|
@@ -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
|
+
}
|
package/src/store/filterTags.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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 {
|
|
79
|
+
const { progressTag } = useFilterProgressTag()
|
|
59
80
|
const filterTags = useFilterTags()
|
|
60
81
|
const tab = useGameTab()
|
|
61
82
|
|
|
62
83
|
useUpdateEffect(() => {
|
|
63
|
-
if (
|
|
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.
|
|
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
|
-
}, [
|
|
112
|
+
}, [tab])
|
|
92
113
|
}
|
package/src/store/gameQuest.tsx
CHANGED
|
@@ -1,20 +1,123 @@
|
|
|
1
|
-
import React, { createContext, useContext } from 'react'
|
|
2
1
|
import type { ReactNode } from 'react'
|
|
3
|
-
import {
|
|
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<
|
|
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
|
|
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
|
+
}
|
package/src/store/quest.ts
CHANGED
|
@@ -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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
|
106
|
-
|
|
89
|
+
const searcher = useGlobalQuestStatusQuery()
|
|
107
90
|
if (!gameId) {
|
|
108
91
|
return QUEST_STATUS.UNKNOWN
|
|
109
92
|
}
|
|
110
|
-
|
|
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
|
}
|
package/src/store/store.tsx
CHANGED
|
@@ -7,10 +7,24 @@ import React, {
|
|
|
7
7
|
useState,
|
|
8
8
|
} from 'react'
|
|
9
9
|
import { useMount, useUpdateEffect } from 'react-use'
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|