poi-plugin-quest-info-2 0.7.3 → 0.8.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/.eslintrc.js +0 -2
- package/build/kcQuestsData/DATA_VERSION +1 -1
- package/build/kcQuestsData/index.ts +1 -1
- package/build/kcQuestsData/quests-scn-new.json +1 -3
- package/build/kcQuestsData/quests-scn.json +72 -72
- package/build/kcanotifyGamedata/DATA_VERSION +1 -1
- package/build/kcanotifyGamedata/index.ts +1 -1
- package/build/kcanotifyGamedata/quests-en.json +12 -0
- package/build/kcanotifyGamedata/quests-jp.json +12 -0
- package/build/kcanotifyGamedata/quests-ko.json +12 -0
- package/build/kcanotifyGamedata/quests-scn.json +12 -0
- package/build/kcanotifyGamedata/quests-tcn.json +12 -0
- package/build/prePostQuest.json +3 -3
- package/build/questCategory.json +2 -0
- package/build/{questMap.json → questCodeMap.json} +0 -0
- package/i18n/en-US.json +2 -0
- package/i18n/ja-JP.json +3 -1
- package/i18n/ko-KR.json +3 -1
- package/i18n/zh-CN.json +3 -1
- package/i18n/zh-TW.json +3 -1
- package/package.json +14 -13
- package/src/__tests__/__snapshots__/questHelper.spec.ts.snap +399 -0
- package/src/__tests__/kcanotifyData.spec.ts +1 -1
- package/src/__tests__/kcwikiData.spec.ts +1 -1
- package/src/__tests__/questCategory.spec.ts +1 -1
- package/src/__tests__/questHelper.spec.ts +36 -0
- package/src/components/QuestCard/MinimalQuestCard.tsx +3 -0
- package/src/components/QuestCard/index.tsx +37 -45
- package/src/components/QuestCard/utils.tsx +8 -0
- package/src/components/QuestList.tsx +4 -23
- package/src/components/QuestTag.tsx +75 -12
- package/src/poi/hooks.ts +6 -6
- package/src/questHelper.ts +73 -3
- package/src/store/kcwiki.ts +7 -3
- package/src/store/quest.ts +55 -9
- package/src/tags.tsx +2 -2
- package/tsconfig.json +3 -2
|
@@ -4,7 +4,7 @@ import newQuestData from '../../build/kcQuestsData/quests-scn-new.json'
|
|
|
4
4
|
describe('should version correct', () => {
|
|
5
5
|
test('should KcwikiQuestData Game data version correct', () => {
|
|
6
6
|
expect(version).toMatchInlineSnapshot(
|
|
7
|
-
`"
|
|
7
|
+
`"cf24003d54c1b9cb2f6a76cdd670de717de0886c"`
|
|
8
8
|
)
|
|
9
9
|
})
|
|
10
10
|
|
|
@@ -9,7 +9,7 @@ describe('should questCategory correct', () => {
|
|
|
9
9
|
expect(questCategory.monthlyQuest.length).toMatchInlineSnapshot(`11`)
|
|
10
10
|
expect(questCategory.quarterlyQuest.length).toMatchInlineSnapshot(`25`)
|
|
11
11
|
expect(questCategory.yearlyQuest.length).toMatchInlineSnapshot(`37`)
|
|
12
|
-
expect(questCategory.singleQuest.length).toMatchInlineSnapshot(`
|
|
12
|
+
expect(questCategory.singleQuest.length).toMatchInlineSnapshot(`477`)
|
|
13
13
|
})
|
|
14
14
|
|
|
15
15
|
test('snapshot', () => {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getCompletedQuest,
|
|
3
|
+
getLockedQuest,
|
|
4
|
+
getPostQuestIds,
|
|
5
|
+
getPreQuestIds,
|
|
6
|
+
} from '../questHelper'
|
|
7
|
+
|
|
8
|
+
describe('questHelper', () => {
|
|
9
|
+
test('should getPreQuestIds correct', () => {
|
|
10
|
+
expect(getPreQuestIds(101)).toEqual([])
|
|
11
|
+
expect(getPreQuestIds(102)).toEqual([101])
|
|
12
|
+
expect(getPreQuestIds(236)).toEqual([235, 273])
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
test('should getPostQuestIds correct', () => {
|
|
16
|
+
expect(getPostQuestIds(101)).toEqual([102])
|
|
17
|
+
expect(getPostQuestIds(105)).toEqual([106, 108, 254, 401, 612, 816])
|
|
18
|
+
expect(getPostQuestIds(140)).toEqual([])
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
test('should 101 no completed quest', () => {
|
|
22
|
+
expect(getCompletedQuest([101])).toEqual({})
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('should 236 getCompletedQuest correct', () => {
|
|
26
|
+
expect(getCompletedQuest([236])).toMatchSnapshot()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('should 101 locked quests match snapshot', () => {
|
|
30
|
+
expect(getLockedQuest([101])).toMatchSnapshot()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('should 196 getLockedQuest correct', () => {
|
|
34
|
+
expect(getLockedQuest([196])).toMatchSnapshot()
|
|
35
|
+
})
|
|
36
|
+
})
|
|
@@ -6,6 +6,9 @@ import type { QuestCardProps } from './index'
|
|
|
6
6
|
import { CardBody, CardTail, CatIndicator, FlexCard } from './styles'
|
|
7
7
|
import { questStatusMap } from './utils'
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated
|
|
11
|
+
*/
|
|
9
12
|
export const MinimalQuestCard = forwardRef<
|
|
10
13
|
Card,
|
|
11
14
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { Card, Elevation, H5
|
|
1
|
+
import { Card, Elevation, H5 } from '@blueprintjs/core'
|
|
2
2
|
import React, { forwardRef } from 'react'
|
|
3
3
|
import type { StyledComponentProps } from 'styled-components'
|
|
4
4
|
import { usePluginTranslation } from '../../poi/hooks'
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
getQuestPrePost,
|
|
7
|
+
guessQuestCategory,
|
|
8
|
+
QUEST_STATUS,
|
|
9
|
+
} from '../../questHelper'
|
|
10
|
+
import { useQuestStatus } from '../../store/quest'
|
|
6
11
|
import { QuestTag } from '../QuestTag'
|
|
7
12
|
import {
|
|
8
13
|
CardActionWrapper,
|
|
@@ -14,6 +19,7 @@ import {
|
|
|
14
19
|
TagsWrapper,
|
|
15
20
|
} from './styles'
|
|
16
21
|
import { questIconMap, questStatusMap } from './utils'
|
|
22
|
+
import { IN_POI } from '../../poi/env'
|
|
17
23
|
|
|
18
24
|
export type QuestCardProps = {
|
|
19
25
|
gameId: number
|
|
@@ -29,15 +35,15 @@ export type QuestCardProps = {
|
|
|
29
35
|
const CardAction = ({ gameId }: { gameId: number }) => {
|
|
30
36
|
const { t } = usePluginTranslation()
|
|
31
37
|
|
|
32
|
-
const
|
|
38
|
+
const prePostQuests = getQuestPrePost(gameId)
|
|
33
39
|
|
|
34
40
|
return (
|
|
35
41
|
<CardActionWrapper>
|
|
36
42
|
<TagsWrapper>
|
|
37
|
-
{!!
|
|
43
|
+
{!!prePostQuests.pre.length && (
|
|
38
44
|
<>
|
|
39
45
|
<SpanText>{t('Requires')}</SpanText>
|
|
40
|
-
{
|
|
46
|
+
{prePostQuests.pre.map((i) => (
|
|
41
47
|
<QuestTag key={i} code={i}></QuestTag>
|
|
42
48
|
))}
|
|
43
49
|
</>
|
|
@@ -45,10 +51,10 @@ const CardAction = ({ gameId }: { gameId: number }) => {
|
|
|
45
51
|
</TagsWrapper>
|
|
46
52
|
|
|
47
53
|
<TagsWrapper>
|
|
48
|
-
{!!
|
|
54
|
+
{!!prePostQuests.post.length && (
|
|
49
55
|
<>
|
|
50
56
|
<SpanText>{t('Unlocks')}</SpanText>
|
|
51
|
-
{
|
|
57
|
+
{prePostQuests.post.map((i) => (
|
|
52
58
|
<QuestTag key={i} code={i}></QuestTag>
|
|
53
59
|
))}
|
|
54
60
|
</>
|
|
@@ -62,44 +68,30 @@ export const QuestCard = forwardRef<
|
|
|
62
68
|
Card,
|
|
63
69
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
64
70
|
QuestCardProps & StyledComponentProps<typeof Card, any, {}, never>
|
|
65
|
-
>(
|
|
66
|
-
(
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
name,
|
|
71
|
-
desc,
|
|
72
|
-
tip,
|
|
73
|
-
tip2,
|
|
74
|
-
status = QUEST_STATUS.DEFAULT,
|
|
75
|
-
...props
|
|
76
|
-
},
|
|
77
|
-
ref
|
|
78
|
-
) => {
|
|
79
|
-
const headIcon = questIconMap[guessQuestCategory(code).type]
|
|
80
|
-
const TailIcon = questStatusMap[status]
|
|
71
|
+
>(({ gameId, code, name, desc, tip, tip2, ...props }, ref) => {
|
|
72
|
+
const status = useQuestStatus(gameId)
|
|
73
|
+
const headIcon = questIconMap[guessQuestCategory(code).type]
|
|
74
|
+
const TailIcon = questStatusMap[status]
|
|
75
|
+
const inPoi = IN_POI
|
|
81
76
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
77
|
+
return (
|
|
78
|
+
<FlexCard
|
|
79
|
+
ref={ref}
|
|
80
|
+
elevation={Elevation.ZERO}
|
|
81
|
+
interactive={false}
|
|
82
|
+
{...props}
|
|
83
|
+
>
|
|
84
|
+
<CardMedia src={headIcon}></CardMedia>
|
|
85
|
+
<CardBody>
|
|
86
|
+
<H5>{[code, name].filter((i) => i != undefined).join(' - ')}</H5>
|
|
87
|
+
<div>{desc}</div>
|
|
88
|
+
{tip2 && <b>{tip2}</b>}
|
|
89
|
+
{tip && <i>{tip}</i>}
|
|
95
90
|
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
<CardAction gameId={gameId}></CardAction>
|
|
92
|
+
</CardBody>
|
|
98
93
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
)
|
|
94
|
+
<CardTail>{inPoi && <TailIcon />}</CardTail>
|
|
95
|
+
</FlexCard>
|
|
96
|
+
)
|
|
97
|
+
})
|
|
@@ -50,6 +50,14 @@ export const questStatusMap: Record<QUEST_STATUS, React.FC> = {
|
|
|
50
50
|
</Tooltip>
|
|
51
51
|
)
|
|
52
52
|
},
|
|
53
|
+
[QUEST_STATUS.UNKNOWN]: function AlreadyCompleted() {
|
|
54
|
+
const { t } = usePluginTranslation()
|
|
55
|
+
return (
|
|
56
|
+
<Tooltip content={t('Unknown')}>
|
|
57
|
+
<Icon icon={IconNames.HELP} iconSize={Icon.SIZE_LARGE}></Icon>
|
|
58
|
+
</Tooltip>
|
|
59
|
+
)
|
|
60
|
+
},
|
|
53
61
|
}
|
|
54
62
|
|
|
55
63
|
// transparent GIF pixel
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useCallback, useEffect, useRef } from 'react'
|
|
2
|
+
import type { ListRowProps } from 'react-virtualized'
|
|
2
3
|
// See https://github.com/bvaughn/react-virtualized
|
|
3
4
|
import {
|
|
4
5
|
AutoSizer,
|
|
@@ -7,13 +8,10 @@ import {
|
|
|
7
8
|
List,
|
|
8
9
|
ListRowRenderer,
|
|
9
10
|
} from 'react-virtualized'
|
|
10
|
-
import type { ListRowProps } from 'react-virtualized'
|
|
11
11
|
import styled from 'styled-components'
|
|
12
|
-
import {
|
|
12
|
+
import { useIsQuestPluginTab } from '../poi/hooks'
|
|
13
13
|
import type { UnionQuest } from '../questHelper'
|
|
14
14
|
import { QuestCard } from './QuestCard'
|
|
15
|
-
import { useIsQuestPluginTab } from '../poi/hooks'
|
|
16
|
-
import { QUEST_API_STATE } from '../poi/types'
|
|
17
15
|
|
|
18
16
|
const QuestListWrapper = styled.div`
|
|
19
17
|
flex: 1;
|
|
@@ -26,28 +24,12 @@ const cache = new CellMeasurerCache({
|
|
|
26
24
|
fixedWidth: true,
|
|
27
25
|
})
|
|
28
26
|
|
|
29
|
-
const questStateToQuestStatus = (
|
|
30
|
-
state: QUEST_API_STATE | undefined
|
|
31
|
-
): QUEST_STATUS => {
|
|
32
|
-
switch (state) {
|
|
33
|
-
case QUEST_API_STATE.DEFAULT:
|
|
34
|
-
return QUEST_STATUS.DEFAULT
|
|
35
|
-
case QUEST_API_STATE.COMPLETED:
|
|
36
|
-
return QUEST_STATUS.COMPLETED
|
|
37
|
-
case QUEST_API_STATE.IN_PROGRESS:
|
|
38
|
-
return QUEST_STATUS.IN_PROGRESS
|
|
39
|
-
default:
|
|
40
|
-
return QUEST_STATUS.DEFAULT
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
27
|
const useQuestsRowRenderer = (quests: UnionQuest[]) => {
|
|
45
28
|
const rowRenderer = useCallback(
|
|
46
29
|
({ key, index, style, parent }: ListRowProps) => {
|
|
47
30
|
const quest = quests[index]
|
|
48
31
|
const { gameId } = quest
|
|
49
32
|
const { code, name, desc, memo, memo2, pre } = quest.docQuest
|
|
50
|
-
const questStatus = questStateToQuestStatus(quest.gameQuest?.api_state)
|
|
51
33
|
|
|
52
34
|
return (
|
|
53
35
|
<CellMeasurer
|
|
@@ -67,7 +49,6 @@ const useQuestsRowRenderer = (quests: UnionQuest[]) => {
|
|
|
67
49
|
tip={memo}
|
|
68
50
|
tip2={memo2}
|
|
69
51
|
preQuest={pre}
|
|
70
|
-
status={questStatus}
|
|
71
52
|
></QuestCard>
|
|
72
53
|
</div>
|
|
73
54
|
</CellMeasurer>
|
|
@@ -78,7 +59,7 @@ const useQuestsRowRenderer = (quests: UnionQuest[]) => {
|
|
|
78
59
|
return rowRenderer
|
|
79
60
|
}
|
|
80
61
|
|
|
81
|
-
export const QuestList:
|
|
62
|
+
export const QuestList = ({ quests }: { quests: UnionQuest[] }) => {
|
|
82
63
|
const activeTab = useIsQuestPluginTab()
|
|
83
64
|
const listRef = useRef<List>(null)
|
|
84
65
|
const rowRenderer: ListRowRenderer = useQuestsRowRenderer(quests)
|
|
@@ -1,23 +1,70 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import type { TooltipProps } from '@blueprintjs/core'
|
|
2
|
+
import { Tag, Tooltip } from '@blueprintjs/core'
|
|
3
|
+
import { IconNames } from '@blueprintjs/icons'
|
|
4
|
+
import React, { forwardRef, useCallback } from 'react'
|
|
3
5
|
import styled from 'styled-components'
|
|
4
|
-
import { guessQuestCategory } from '../questHelper'
|
|
6
|
+
import { DocQuest, guessQuestCategory, QUEST_STATUS } from '../questHelper'
|
|
5
7
|
import { useFilterTags } from '../store/filterTags'
|
|
8
|
+
import { useQuestByCode, useQuestStatus } from '../store/quest'
|
|
6
9
|
import { useSearchInput } from '../store/search'
|
|
7
10
|
|
|
8
11
|
const TagWrapper = styled(Tag)`
|
|
9
12
|
margin: 2px 4px;
|
|
10
|
-
user-select: none;
|
|
13
|
+
user-select: ${({ interactive }) => (interactive ? 'none' : 'auto')};
|
|
11
14
|
overflow: visible;
|
|
12
15
|
|
|
13
16
|
& > span {
|
|
14
|
-
cursor: pointer;
|
|
17
|
+
cursor: ${({ interactive }) => (interactive ? 'pointer' : 'auto')};
|
|
15
18
|
}
|
|
16
19
|
`
|
|
17
20
|
|
|
21
|
+
const QuestTooltip = forwardRef<
|
|
22
|
+
Tooltip,
|
|
23
|
+
Omit<TooltipProps, 'content'> & {
|
|
24
|
+
quest: DocQuest
|
|
25
|
+
children: React.ReactNode
|
|
26
|
+
}
|
|
27
|
+
>(({ quest, children, ...props }, ref) => {
|
|
28
|
+
if (!quest) {
|
|
29
|
+
return <>{children}</>
|
|
30
|
+
}
|
|
31
|
+
return (
|
|
32
|
+
<Tooltip
|
|
33
|
+
ref={ref}
|
|
34
|
+
content={
|
|
35
|
+
<>
|
|
36
|
+
<div>{`${quest.code} - ${quest.name}`}</div>
|
|
37
|
+
<div>{quest.desc}</div>
|
|
38
|
+
{quest.memo2 && <b>{quest.memo2}</b>}
|
|
39
|
+
{quest.memo && <i>{quest.memo}</i>}
|
|
40
|
+
</>
|
|
41
|
+
}
|
|
42
|
+
placement={'top'}
|
|
43
|
+
{...props}
|
|
44
|
+
>
|
|
45
|
+
{children}
|
|
46
|
+
</Tooltip>
|
|
47
|
+
)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const getTagIcon = (questStatus: QUEST_STATUS) => {
|
|
51
|
+
switch (questStatus) {
|
|
52
|
+
case QUEST_STATUS.ALREADY_COMPLETED:
|
|
53
|
+
return IconNames.TICK
|
|
54
|
+
case QUEST_STATUS.LOCKED:
|
|
55
|
+
return IconNames.LOCK
|
|
56
|
+
default:
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
18
61
|
export const QuestTag = ({ code }: { code: string }) => {
|
|
19
62
|
const { setSearchInput } = useSearchInput()
|
|
20
63
|
const { setCategoryTagsAll, setTypeTagsAll } = useFilterTags()
|
|
64
|
+
const maybeQuest = useQuestByCode(code)
|
|
65
|
+
const maybeGameId = maybeQuest?.gameId ?? null
|
|
66
|
+
const questStatus = useQuestStatus(maybeGameId)
|
|
67
|
+
const tagIcon = getTagIcon(questStatus)
|
|
21
68
|
|
|
22
69
|
const handleClick = useCallback(() => {
|
|
23
70
|
setSearchInput(code)
|
|
@@ -29,13 +76,29 @@ export const QuestTag = ({ code }: { code: string }) => {
|
|
|
29
76
|
indicatorColor === '#fff' || indicatorColor === '#87da61'
|
|
30
77
|
? 'black'
|
|
31
78
|
: 'white'
|
|
79
|
+
|
|
80
|
+
if (!maybeQuest) {
|
|
81
|
+
return (
|
|
82
|
+
<TagWrapper
|
|
83
|
+
icon={IconNames.HELP}
|
|
84
|
+
style={{ color: fontColor, background: indicatorColor }}
|
|
85
|
+
>
|
|
86
|
+
{code}
|
|
87
|
+
</TagWrapper>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const quest = maybeQuest.docQuest
|
|
32
92
|
return (
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
93
|
+
<QuestTooltip quest={quest}>
|
|
94
|
+
<TagWrapper
|
|
95
|
+
interactive
|
|
96
|
+
icon={tagIcon}
|
|
97
|
+
onClick={handleClick}
|
|
98
|
+
style={{ color: fontColor, background: indicatorColor }}
|
|
99
|
+
>
|
|
100
|
+
{code}
|
|
101
|
+
</TagWrapper>
|
|
102
|
+
</QuestTooltip>
|
|
40
103
|
)
|
|
41
104
|
}
|
package/src/poi/hooks.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
2
|
import { useTranslation } from 'react-i18next'
|
|
3
|
-
import { observePluginStore, observePoiStore } from './store'
|
|
4
3
|
import { name as PACKAGE_NAME } from '../../package.json'
|
|
4
|
+
import { observePluginStore, observePoiStore } from './store'
|
|
5
5
|
import { GameQuest, PoiQuestState, PoiState, QuestTab } from './types'
|
|
6
6
|
|
|
7
|
+
export const activeQuestsSelector = (state: PoiState): PoiQuestState =>
|
|
8
|
+
state?.info?.quests?.activeQuests ?? {}
|
|
9
|
+
|
|
7
10
|
export const useActiveQuest = () => {
|
|
8
11
|
const [activeQuests, setActiveQuests] = useState<PoiQuestState>({})
|
|
9
12
|
|
|
@@ -17,9 +20,6 @@ export const useActiveQuest = () => {
|
|
|
17
20
|
return activeQuests
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
export const activeQuestsSelector = (state: PoiState): PoiQuestState =>
|
|
21
|
-
state?.info?.quests?.activeQuests ?? {}
|
|
22
|
-
|
|
23
23
|
export const usePluginTranslation = () => {
|
|
24
24
|
return useTranslation(PACKAGE_NAME)
|
|
25
25
|
}
|
|
@@ -30,7 +30,7 @@ export const useGameQuest = () => {
|
|
|
30
30
|
const listener = (quests: GameQuest[] | null) => setQuests(quests ?? [])
|
|
31
31
|
// See reducer.ts
|
|
32
32
|
return observePluginStore(listener, (i) => i?._?.questList)
|
|
33
|
-
}, [])
|
|
33
|
+
}, [setQuests])
|
|
34
34
|
return quests
|
|
35
35
|
}
|
|
36
36
|
|
package/src/questHelper.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import moize from 'moize'
|
|
2
|
+
import { QuestData } from '../build/kcanotifyGamedata'
|
|
3
|
+
import { KcwikiQuestData } from '../build/kcQuestsData'
|
|
2
4
|
import newQuestData from '../build/kcQuestsData/quests-scn-new.json'
|
|
3
5
|
import prePostQuest from '../build/prePostQuest.json'
|
|
6
|
+
import questCategory from '../build/questCategory.json'
|
|
7
|
+
import questCodeMap from '../build/questCodeMap.json'
|
|
4
8
|
import { GameQuest, QUEST_API_STATE } from './poi/types'
|
|
5
9
|
|
|
6
|
-
type DocQuest = {
|
|
10
|
+
export type DocQuest = {
|
|
7
11
|
code: string
|
|
8
12
|
name: string
|
|
9
13
|
desc: string
|
|
@@ -35,6 +39,9 @@ export type UnionQuest = {
|
|
|
35
39
|
docQuest: DocQuest
|
|
36
40
|
}
|
|
37
41
|
|
|
42
|
+
export const getKcwikiQuestData = () => KcwikiQuestData
|
|
43
|
+
export const getKcanotifyQuestData = () => QuestData
|
|
44
|
+
|
|
38
45
|
const dailyQuest = new Set(questCategory.dailyQuest)
|
|
39
46
|
const weeklyQuest = new Set(questCategory.weeklyQuest)
|
|
40
47
|
const monthlyQuest = new Set(questCategory.monthlyQuest)
|
|
@@ -197,17 +204,80 @@ export const isUnknownCategoryQuest = ({ code }: DocQuest) =>
|
|
|
197
204
|
// Starts with unknown character
|
|
198
205
|
/^[^ABCDEFG]/.test(code)
|
|
199
206
|
|
|
200
|
-
export const
|
|
207
|
+
export const getQuestPrePost = (gameId: number) => {
|
|
201
208
|
if (!(gameId in prePostQuest)) {
|
|
202
209
|
return { pre: [], post: [] }
|
|
203
210
|
}
|
|
204
211
|
return prePostQuest[String(gameId) as keyof typeof prePostQuest]
|
|
205
212
|
}
|
|
206
213
|
|
|
214
|
+
export const getQuestIdByCode = (code: string) => {
|
|
215
|
+
if (code in questCodeMap) {
|
|
216
|
+
return questCodeMap[code as keyof typeof questCodeMap]
|
|
217
|
+
}
|
|
218
|
+
return null
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export const getPreQuestIds = (gameId: number): number[] =>
|
|
222
|
+
getQuestPrePost(gameId)
|
|
223
|
+
.pre.map((code) => getQuestIdByCode(code))
|
|
224
|
+
.filter(Boolean) as number[]
|
|
225
|
+
|
|
226
|
+
export const getPostQuestIds = (gameId: number): number[] =>
|
|
227
|
+
getQuestPrePost(gameId)
|
|
228
|
+
.post.map((code) => getQuestIdByCode(code))
|
|
229
|
+
.filter(Boolean) as number[]
|
|
230
|
+
|
|
231
|
+
const calcQuestMap = (
|
|
232
|
+
inProgressQuests: number[],
|
|
233
|
+
next: (gameId: number) => number[]
|
|
234
|
+
) => {
|
|
235
|
+
const map: Record<number, true> = {}
|
|
236
|
+
const queue: number[] = inProgressQuests.flatMap(next)
|
|
237
|
+
while (queue.length) {
|
|
238
|
+
const gameId = queue.shift()!
|
|
239
|
+
if (gameId in map) {
|
|
240
|
+
continue
|
|
241
|
+
}
|
|
242
|
+
map[gameId] = true
|
|
243
|
+
|
|
244
|
+
next(gameId).forEach((nextGameId) => {
|
|
245
|
+
queue.push(nextGameId)
|
|
246
|
+
})
|
|
247
|
+
}
|
|
248
|
+
return map
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export const getCompletedQuest = moize((inProgressQuest: number[]) => {
|
|
252
|
+
const completedQuest = calcQuestMap(inProgressQuest, getPreQuestIds)
|
|
253
|
+
return completedQuest
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
export const getLockedQuest = moize((inProgressQuest: number[]) => {
|
|
257
|
+
const lockedQuest = calcQuestMap(inProgressQuest, getPostQuestIds)
|
|
258
|
+
return lockedQuest
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
export const questApiStateToQuestStatus = (
|
|
262
|
+
state: QUEST_API_STATE | undefined
|
|
263
|
+
): QUEST_STATUS => {
|
|
264
|
+
switch (state) {
|
|
265
|
+
case QUEST_API_STATE.DEFAULT:
|
|
266
|
+
return QUEST_STATUS.DEFAULT
|
|
267
|
+
case QUEST_API_STATE.COMPLETED:
|
|
268
|
+
return QUEST_STATUS.COMPLETED
|
|
269
|
+
case QUEST_API_STATE.IN_PROGRESS:
|
|
270
|
+
return QUEST_STATUS.IN_PROGRESS
|
|
271
|
+
default:
|
|
272
|
+
return QUEST_STATUS.DEFAULT
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
207
276
|
export enum QUEST_STATUS {
|
|
208
277
|
LOCKED,
|
|
209
278
|
DEFAULT,
|
|
210
279
|
IN_PROGRESS,
|
|
211
280
|
COMPLETED,
|
|
212
281
|
ALREADY_COMPLETED,
|
|
282
|
+
UNKNOWN,
|
|
213
283
|
}
|
package/src/store/kcwiki.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { KcwikiQuestData } from '../../build/kcQuestsData'
|
|
2
1
|
import { useStore } from '.'
|
|
2
|
+
import { getKcwikiQuestData } from '../questHelper'
|
|
3
3
|
|
|
4
4
|
export const usePreferKcwiki = () => {
|
|
5
5
|
const {
|
|
@@ -13,7 +13,10 @@ export const usePreferKcwiki = () => {
|
|
|
13
13
|
|
|
14
14
|
export const checkIsKcwikiSupportedLanguages = (
|
|
15
15
|
lang: string
|
|
16
|
-
): lang is keyof typeof
|
|
16
|
+
): lang is keyof typeof kcwikiQuestData => {
|
|
17
|
+
const kcwikiQuestData = getKcwikiQuestData()
|
|
18
|
+
return lang in kcwikiQuestData
|
|
19
|
+
}
|
|
17
20
|
|
|
18
21
|
export const useKcwikiData = (lang: string) => {
|
|
19
22
|
const [preferKcwiki] = usePreferKcwiki()
|
|
@@ -25,5 +28,6 @@ export const useKcwikiData = (lang: string) => {
|
|
|
25
28
|
if (!supported) {
|
|
26
29
|
return null
|
|
27
30
|
}
|
|
28
|
-
|
|
31
|
+
const kcwikiQuestData = getKcwikiQuestData()
|
|
32
|
+
return kcwikiQuestData[lang]
|
|
29
33
|
}
|
package/src/store/quest.ts
CHANGED
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import { useCallback } from 'react'
|
|
2
|
-
import { QuestData } from '../../build/kcanotifyGamedata'
|
|
3
2
|
import { useGameQuest, usePluginTranslation } from '../poi/hooks'
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import {
|
|
4
|
+
DocQuest,
|
|
5
|
+
getCategory,
|
|
6
|
+
getCompletedQuest,
|
|
7
|
+
getKcanotifyQuestData,
|
|
8
|
+
getLockedQuest,
|
|
9
|
+
getQuestIdByCode,
|
|
10
|
+
questApiStateToQuestStatus,
|
|
11
|
+
QUEST_STATUS,
|
|
12
|
+
UnionQuest,
|
|
13
|
+
} from '../questHelper'
|
|
14
|
+
import { checkIsKcwikiSupportedLanguages, useKcwikiData } from './kcwiki'
|
|
7
15
|
import { useStore, useSyncWithGame } from './store'
|
|
8
16
|
|
|
9
17
|
const DEFAULT_LANG = 'ja-JP'
|
|
10
18
|
|
|
11
|
-
|
|
19
|
+
const checkIsKcanotifySupportedLanguages = (
|
|
12
20
|
lang: string
|
|
13
|
-
): lang is keyof typeof
|
|
21
|
+
): lang is keyof typeof kcaQuestData => {
|
|
22
|
+
const kcaQuestData = getKcanotifyQuestData()
|
|
23
|
+
return lang in kcaQuestData
|
|
24
|
+
}
|
|
14
25
|
|
|
15
26
|
export const isSupportedLanguages = (
|
|
16
27
|
lang: string
|
|
17
|
-
): lang is keyof typeof
|
|
28
|
+
): lang is keyof ReturnType<typeof getKcanotifyQuestData> =>
|
|
18
29
|
checkIsKcanotifySupportedLanguages(lang) ||
|
|
19
30
|
checkIsKcwikiSupportedLanguages(lang)
|
|
20
31
|
|
|
@@ -28,13 +39,14 @@ export const useLanguage = () => {
|
|
|
28
39
|
return lang
|
|
29
40
|
}
|
|
30
41
|
|
|
31
|
-
const useQuestMap = () => {
|
|
42
|
+
const useQuestMap = (): Record<string, DocQuest> => {
|
|
32
43
|
const lang = useLanguage()
|
|
33
44
|
const kcwikiData = useKcwikiData(lang)
|
|
34
45
|
if (kcwikiData) {
|
|
35
46
|
return kcwikiData
|
|
36
47
|
}
|
|
37
|
-
|
|
48
|
+
const kcaQuestData = getKcanotifyQuestData()
|
|
49
|
+
return kcaQuestData[lang]
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
export const useQuest = (): UnionQuest[] => {
|
|
@@ -76,6 +88,40 @@ export const useQuest = (): UnionQuest[] => {
|
|
|
76
88
|
}
|
|
77
89
|
}
|
|
78
90
|
|
|
91
|
+
export const useQuestByCode = (code: string): UnionQuest | null => {
|
|
92
|
+
const questMap = useQuestMap()
|
|
93
|
+
const gameId = getQuestIdByCode(code)
|
|
94
|
+
if (gameId && gameId in questMap) {
|
|
95
|
+
return {
|
|
96
|
+
gameId,
|
|
97
|
+
docQuest: questMap[String(gameId) as keyof typeof questMap],
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export const useQuestStatus = (gameId: number | null) => {
|
|
104
|
+
const gameQuest = useGameQuest()
|
|
105
|
+
const gameQuestId = gameQuest.map((quest) => quest.api_no)
|
|
106
|
+
const completedQuest = getCompletedQuest(gameQuestId)
|
|
107
|
+
const lockedQuest = getLockedQuest(gameQuestId)
|
|
108
|
+
|
|
109
|
+
if (!gameId) {
|
|
110
|
+
return QUEST_STATUS.UNKNOWN
|
|
111
|
+
}
|
|
112
|
+
const theGameQuest = gameQuest.find((quest) => quest.api_no === gameId)
|
|
113
|
+
if (theGameQuest) {
|
|
114
|
+
return questApiStateToQuestStatus(theGameQuest.api_state)
|
|
115
|
+
}
|
|
116
|
+
if (gameId in lockedQuest) {
|
|
117
|
+
return QUEST_STATUS.LOCKED
|
|
118
|
+
}
|
|
119
|
+
if (gameId in completedQuest) {
|
|
120
|
+
return QUEST_STATUS.ALREADY_COMPLETED
|
|
121
|
+
}
|
|
122
|
+
return QUEST_STATUS.UNKNOWN
|
|
123
|
+
}
|
|
124
|
+
|
|
79
125
|
/**
|
|
80
126
|
* @deprecated Not large card now
|
|
81
127
|
*/
|
package/src/tags.tsx
CHANGED
|
@@ -38,12 +38,12 @@ export const ALL_CATEGORY_TAG = {
|
|
|
38
38
|
export const ALL_TYPE_TAG = ALL_CATEGORY_TAG
|
|
39
39
|
|
|
40
40
|
const withDocQuest =
|
|
41
|
-
<T
|
|
41
|
+
<T,>(filterFn: (q: UnionQuest['docQuest']) => T) =>
|
|
42
42
|
(unionQuest: UnionQuest) =>
|
|
43
43
|
filterFn(unionQuest.docQuest)
|
|
44
44
|
|
|
45
45
|
const withGameQuestOr =
|
|
46
|
-
<T
|
|
46
|
+
<T,>(filterFn: (q: GameQuest) => T, fallback: T) =>
|
|
47
47
|
({ gameQuest }: UnionQuest) => {
|
|
48
48
|
if (!gameQuest) {
|
|
49
49
|
return fallback
|
package/tsconfig.json
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
|
45
45
|
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
|
46
46
|
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
|
47
|
-
"importsNotUsedAsValues": "error",
|
|
47
|
+
// "importsNotUsedAsValues": "error",
|
|
48
48
|
|
|
49
49
|
/* Module Resolution Options */
|
|
50
50
|
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
|
@@ -72,5 +72,6 @@
|
|
|
72
72
|
/* Advanced Options */
|
|
73
73
|
"skipLibCheck": true /* Skip type checking of declaration files. */,
|
|
74
74
|
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
|
75
|
-
}
|
|
75
|
+
},
|
|
76
|
+
"exclude": ["./node_modules/**/*"]
|
|
76
77
|
}
|