@rpg-engine/long-bow 0.8.238 → 0.8.239
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/dist/long-bow.cjs.development.js +9 -1
- package/dist/long-bow.cjs.development.js.map +1 -1
- package/dist/long-bow.cjs.production.min.js +1 -1
- package/dist/long-bow.cjs.production.min.js.map +1 -1
- package/dist/long-bow.esm.js +10 -2
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +3 -3
- package/src/components/Item/Inventory/__tests__/itemContainerHelper.spec.ts +60 -0
- package/src/components/Item/Inventory/itemContainerHelper.ts +9 -0
- package/src/components/LoginStreak/LoginStreakPanel.tsx +1 -1
- package/src/components/LoginStreak/__tests__/LoginStreakPanel.spec.tsx +33 -0
- package/src/stories/Features/loginStreak/LoginStreakPanel.stories.tsx +16 -16
- package/src/stories/Features/quest/QuestList.stories.tsx +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpg-engine/long-bow",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.239",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"build": "tsdx build",
|
|
25
25
|
"test": "tsdx test --passWithNoTests",
|
|
26
26
|
"lint": "tsdx lint",
|
|
27
|
-
"prepare": "
|
|
27
|
+
"prepare": "echo skip",
|
|
28
28
|
"size": "size-limit",
|
|
29
29
|
"analyze": "size-limit --why",
|
|
30
30
|
"storybook": "start-storybook -p 6006",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"dependencies": {
|
|
95
95
|
"@capacitor/core": "^6.1.0",
|
|
96
96
|
"@rollup/plugin-image": "^2.1.1",
|
|
97
|
-
"@rpg-engine/shared": "
|
|
97
|
+
"@rpg-engine/shared": "0.11.37",
|
|
98
98
|
"dayjs": "^1.11.2",
|
|
99
99
|
"font-awesome": "^4.7.0",
|
|
100
100
|
"fs-extra": "^10.1.0",
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IItem,
|
|
3
|
+
ISoulGemSchema,
|
|
4
|
+
ItemContainerType,
|
|
5
|
+
ItemRarities,
|
|
6
|
+
ItemSubType,
|
|
7
|
+
SoulGemCategory,
|
|
8
|
+
SoulGemsBlueprint,
|
|
9
|
+
} from '@rpg-engine/shared';
|
|
10
|
+
import { generateContextMenu } from '../itemContainerHelper';
|
|
11
|
+
|
|
12
|
+
const soulGem: ISoulGemSchema = {
|
|
13
|
+
key: SoulGemsBlueprint.Fire,
|
|
14
|
+
name: 'Fire Soul Gem',
|
|
15
|
+
category: SoulGemCategory.Offensive,
|
|
16
|
+
rarity: ItemRarities.Common,
|
|
17
|
+
damageBonus: 0.05,
|
|
18
|
+
cooldownReduction: 0,
|
|
19
|
+
manaCostReduction: 0,
|
|
20
|
+
radiusBonus: 0,
|
|
21
|
+
durationBonus: 0,
|
|
22
|
+
};
|
|
23
|
+
const item = { subType: ItemSubType.SoulGem, soulGem } as IItem;
|
|
24
|
+
const attach = { id: 'attach-soul-gem', text: 'Attach gem' };
|
|
25
|
+
|
|
26
|
+
describe('Soul Gem inventory context action', () => {
|
|
27
|
+
it('offers Attach gem exactly once for a carried Soul Gem', () => {
|
|
28
|
+
expect(
|
|
29
|
+
generateContextMenu(item, ItemContainerType.Inventory).filter(
|
|
30
|
+
(action) => action.id === attach.id
|
|
31
|
+
)
|
|
32
|
+
).toEqual([attach]);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it.each([
|
|
36
|
+
ItemContainerType.Depot,
|
|
37
|
+
ItemContainerType.Loot,
|
|
38
|
+
ItemContainerType.MapContainer,
|
|
39
|
+
ItemContainerType.Equipment,
|
|
40
|
+
null,
|
|
41
|
+
])('does not offer attachment outside inventory: %s', (containerType) => {
|
|
42
|
+
expect(generateContextMenu(item, containerType)).not.toContainEqual(attach);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('requires canonical Soul Gem metadata', () => {
|
|
46
|
+
expect(
|
|
47
|
+
generateContextMenu(
|
|
48
|
+
{ ...item, soulGem: undefined },
|
|
49
|
+
ItemContainerType.Inventory
|
|
50
|
+
)
|
|
51
|
+
).not.toContainEqual(attach);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('requires the Soul Gem subtype', () => {
|
|
55
|
+
const ordinaryItem = { soulGem } as IItem;
|
|
56
|
+
expect(
|
|
57
|
+
generateContextMenu(ordinaryItem, ItemContainerType.Inventory)
|
|
58
|
+
).not.toContainEqual(attach);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
ItemContainerType,
|
|
9
9
|
ItemSocketEvents,
|
|
10
10
|
ItemSocketEventsDisplayLabels,
|
|
11
|
+
ItemSubType,
|
|
11
12
|
ItemType
|
|
12
13
|
} from '@rpg-engine/shared';
|
|
13
14
|
|
|
@@ -207,5 +208,13 @@ export const generateContextMenu = (
|
|
|
207
208
|
contextActionMenu.push({ id: ItemSocketEvents.DetachGem, text: "Detach Gems" });
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
if (
|
|
212
|
+
itemContainerType === ItemContainerType.Inventory &&
|
|
213
|
+
item.subType === ItemSubType.SoulGem &&
|
|
214
|
+
item.soulGem
|
|
215
|
+
) {
|
|
216
|
+
contextActionMenu.push({ id: 'attach-soul-gem', text: 'Attach gem' });
|
|
217
|
+
}
|
|
218
|
+
|
|
210
219
|
return contextActionMenu;
|
|
211
220
|
};
|
|
@@ -90,7 +90,7 @@ export const LoginStreakPanel: React.FC<ILoginStreakPanelProps> = ({
|
|
|
90
90
|
{milestones.map((milestone) => (
|
|
91
91
|
<MilestoneCard key={milestone.day} $reached={milestone.reached}>
|
|
92
92
|
<MilestoneDayLabel>Day {milestone.day}</MilestoneDayLabel>
|
|
93
|
-
<MilestoneRewardName>{milestone.quantity}x {
|
|
93
|
+
<MilestoneRewardName>{milestone.rewards.map(reward => `${reward.quantity}x ${reward.itemName}`).join(', ')}</MilestoneRewardName>
|
|
94
94
|
<MilestoneBadge $reached={milestone.reached}>{milestone.reached ? '✓' : '○'}</MilestoneBadge>
|
|
95
95
|
</MilestoneCard>
|
|
96
96
|
))}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { cleanup, render, screen } from '@testing-library/react';
|
|
3
|
+
import { LoginStreakPanel } from '../LoginStreakPanel';
|
|
4
|
+
|
|
5
|
+
jest.mock('../../DraggableContainer', () => ({
|
|
6
|
+
DraggableContainer: ({ children }: { children: React.ReactNode }) => <>{children}</>,
|
|
7
|
+
}));
|
|
8
|
+
jest.mock('../../SimpleProgressBar', () => ({ SimpleProgressBar: () => null }));
|
|
9
|
+
|
|
10
|
+
afterEach(cleanup);
|
|
11
|
+
|
|
12
|
+
it('shows every reward from the shared milestone payload', () => {
|
|
13
|
+
render(
|
|
14
|
+
<LoginStreakPanel
|
|
15
|
+
streak={7}
|
|
16
|
+
longestStreak={7}
|
|
17
|
+
xpBonusPercent={15}
|
|
18
|
+
maxXpBonusPercent={50}
|
|
19
|
+
maxBonusDay={30}
|
|
20
|
+
isConsecutive
|
|
21
|
+
onClose={jest.fn()}
|
|
22
|
+
milestones={[{
|
|
23
|
+
day: 7,
|
|
24
|
+
reached: true,
|
|
25
|
+
rewards: [
|
|
26
|
+
{ itemKey: 'healing-potion', itemName: 'Healing Potion', quantity: 5 },
|
|
27
|
+
{ itemKey: 'mana-potion', itemName: 'Mana Potion', quantity: 3 },
|
|
28
|
+
],
|
|
29
|
+
}]}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
expect(screen.getByText('5x Healing Potion, 3x Mana Potion')).toBeTruthy();
|
|
33
|
+
});
|
|
@@ -16,10 +16,10 @@ export default meta;
|
|
|
16
16
|
type Story = StoryObj<ILoginStreakPanelProps>;
|
|
17
17
|
|
|
18
18
|
const mockMilestones: ILoginStreakMilestone[] = [
|
|
19
|
-
{ day: 7, itemName: 'Light Healing Potion', quantity: 5, reached: true },
|
|
20
|
-
{ day: 14, itemName: 'Greater Healing Potion', quantity: 3, reached: true },
|
|
21
|
-
{ day: 21, itemName: 'Light Mana Potion', quantity: 5, reached: false },
|
|
22
|
-
{ day: 30, itemName: 'Greater Mana Potion', quantity: 3, reached: false },
|
|
19
|
+
{ day: 7, rewards: [{ itemKey: 'light-healing-potion', itemName: 'Light Healing Potion', quantity: 5 }], reached: true },
|
|
20
|
+
{ day: 14, rewards: [{ itemKey: 'greater-healing-potion', itemName: 'Greater Healing Potion', quantity: 3 }], reached: true },
|
|
21
|
+
{ day: 21, rewards: [{ itemKey: 'light-mana-potion', itemName: 'Light Mana Potion', quantity: 5 }], reached: false },
|
|
22
|
+
{ day: 30, rewards: [{ itemKey: 'greater-mana-potion', itemName: 'Greater Mana Potion', quantity: 3 }], reached: false },
|
|
23
23
|
];
|
|
24
24
|
|
|
25
25
|
const Template = (args: ILoginStreakPanelProps) => (
|
|
@@ -53,10 +53,10 @@ export const InProgress: Story = {
|
|
|
53
53
|
maxBonusDay: 30,
|
|
54
54
|
isConsecutive: true,
|
|
55
55
|
milestones: [
|
|
56
|
-
{ day: 7, itemName: 'Light Healing Potion', quantity: 5, reached: true },
|
|
57
|
-
{ day: 14, itemName: 'Greater Healing Potion', quantity: 3, reached: false },
|
|
58
|
-
{ day: 21, itemName: 'Light Mana Potion', quantity: 5, reached: false },
|
|
59
|
-
{ day: 30, itemName: 'Greater Mana Potion', quantity: 3, reached: false },
|
|
56
|
+
{ day: 7, rewards: [{ itemKey: 'light-healing-potion', itemName: 'Light Healing Potion', quantity: 5 }], reached: true },
|
|
57
|
+
{ day: 14, rewards: [{ itemKey: 'greater-healing-potion', itemName: 'Greater Healing Potion', quantity: 3 }], reached: false },
|
|
58
|
+
{ day: 21, rewards: [{ itemKey: 'light-mana-potion', itemName: 'Light Mana Potion', quantity: 5 }], reached: false },
|
|
59
|
+
{ day: 30, rewards: [{ itemKey: 'greater-mana-potion', itemName: 'Greater Mana Potion', quantity: 3 }], reached: false },
|
|
60
60
|
],
|
|
61
61
|
milestoneRewardGranted: null,
|
|
62
62
|
onClose: () => console.log('close'),
|
|
@@ -88,10 +88,10 @@ export const MilestoneReached: Story = {
|
|
|
88
88
|
maxBonusDay: 30,
|
|
89
89
|
isConsecutive: true,
|
|
90
90
|
milestones: [
|
|
91
|
-
{ day: 7, itemName: 'Light Healing Potion', quantity: 5, reached: true },
|
|
92
|
-
{ day: 14, itemName: 'Greater Healing Potion', quantity: 3, reached: false },
|
|
93
|
-
{ day: 21, itemName: 'Light Mana Potion', quantity: 5, reached: false },
|
|
94
|
-
{ day: 30, itemName: 'Greater Mana Potion', quantity: 3, reached: false },
|
|
91
|
+
{ day: 7, rewards: [{ itemKey: 'light-healing-potion', itemName: 'Light Healing Potion', quantity: 5 }], reached: true },
|
|
92
|
+
{ day: 14, rewards: [{ itemKey: 'greater-healing-potion', itemName: 'Greater Healing Potion', quantity: 3 }], reached: false },
|
|
93
|
+
{ day: 21, rewards: [{ itemKey: 'light-mana-potion', itemName: 'Light Mana Potion', quantity: 5 }], reached: false },
|
|
94
|
+
{ day: 30, rewards: [{ itemKey: 'greater-mana-potion', itemName: 'Greater Mana Potion', quantity: 3 }], reached: false },
|
|
95
95
|
],
|
|
96
96
|
milestoneRewardGranted: { itemName: 'Light Healing Potion', quantity: 5 },
|
|
97
97
|
onClose: () => console.log('close'),
|
|
@@ -108,10 +108,10 @@ export const MaxBonus: Story = {
|
|
|
108
108
|
maxBonusDay: 30,
|
|
109
109
|
isConsecutive: true,
|
|
110
110
|
milestones: [
|
|
111
|
-
{ day: 7, itemName: 'Light Healing Potion', quantity: 5, reached: true },
|
|
112
|
-
{ day: 14, itemName: 'Greater Healing Potion', quantity: 3, reached: true },
|
|
113
|
-
{ day: 21, itemName: 'Light Mana Potion', quantity: 5, reached: true },
|
|
114
|
-
{ day: 30, itemName: 'Greater Mana Potion', quantity: 3, reached: true },
|
|
111
|
+
{ day: 7, rewards: [{ itemKey: 'light-healing-potion', itemName: 'Light Healing Potion', quantity: 5 }], reached: true },
|
|
112
|
+
{ day: 14, rewards: [{ itemKey: 'greater-healing-potion', itemName: 'Greater Healing Potion', quantity: 3 }], reached: true },
|
|
113
|
+
{ day: 21, rewards: [{ itemKey: 'light-mana-potion', itemName: 'Light Mana Potion', quantity: 5 }], reached: true },
|
|
114
|
+
{ day: 30, rewards: [{ itemKey: 'greater-mana-potion', itemName: 'Greater Mana Potion', quantity: 3 }], reached: true },
|
|
115
115
|
],
|
|
116
116
|
milestoneRewardGranted: null,
|
|
117
117
|
onClose: () => console.log('close'),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { QuestStatus, QuestType } from '@rpg-engine/shared';
|
|
1
|
+
import { IQuest, QuestStatus, QuestType } from '@rpg-engine/shared';
|
|
2
2
|
import { Story } from '@storybook/react';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import {
|
|
@@ -20,7 +20,7 @@ const Template: Story<IQuestListProps> = args => (
|
|
|
20
20
|
|
|
21
21
|
export const Default = Template.bind({});
|
|
22
22
|
|
|
23
|
-
const IQuestMock = [
|
|
23
|
+
const IQuestMock: IQuest[] = [
|
|
24
24
|
{
|
|
25
25
|
_id: '6317996c77f2420047a20b55',
|
|
26
26
|
rewards: [
|