@rpg-engine/long-bow 0.8.70 → 0.8.72

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpg-engine/long-bow",
3
- "version": "0.8.70",
3
+ "version": "0.8.72",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -84,7 +84,7 @@
84
84
  "dependencies": {
85
85
  "@capacitor/core": "^6.1.0",
86
86
  "@rollup/plugin-image": "^2.1.1",
87
- "@rpg-engine/shared": "^0.9.123",
87
+ "@rpg-engine/shared": "^0.10.10",
88
88
  "dayjs": "^1.11.2",
89
89
  "font-awesome": "^4.7.0",
90
90
  "fs-extra": "^10.1.0",
@@ -1,4 +1,4 @@
1
- import { IStoreItem, MetadataType } from '@rpg-engine/shared';
1
+ import { IProductBlueprint, MetadataType } from '@rpg-engine/shared';
2
2
  import React, { useState } from 'react';
3
3
  import { FaInfoCircle, FaShoppingBag, FaTimes, FaTrash } from 'react-icons/fa';
4
4
  import styled from 'styled-components';
@@ -9,12 +9,15 @@ import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
9
9
 
10
10
 
11
11
 
12
+ // Local cart item interface
13
+ interface ICartItem {
14
+ item: IProductBlueprint;
15
+ quantity: number;
16
+ metadata?: Record<string, any>;
17
+ }
18
+
12
19
  interface ICartViewProps {
13
- cartItems: {
14
- item: IStoreItem;
15
- quantity: number;
16
- metadata?: Record<string, any>;
17
- }[];
20
+ cartItems: ICartItem[];
18
21
  onRemoveFromCart: (itemKey: string) => void;
19
22
  onClose: () => void;
20
23
  onPurchase: () => Promise<boolean>;
@@ -111,6 +114,9 @@ export const CartView: React.FC<ICartViewProps> = ({
111
114
  </ItemIconContainer>
112
115
  <ItemDetails>
113
116
  <ItemName>{cartItem.item.name}</ItemName>
117
+ {cartItem.metadata?.inputValue && (
118
+ <CartMeta>{cartItem.metadata.inputValue}</CartMeta>
119
+ )}
114
120
  <ItemInfo>
115
121
  <span>${formatPrice(cartItem.item.price)}</span>
116
122
  <span>×</span>
@@ -339,3 +345,11 @@ const MetadataValue = styled.div`
339
345
  text-overflow: ellipsis;
340
346
  white-space: nowrap;
341
347
  `;
348
+
349
+ const CartMeta = styled.div`
350
+ font-family: 'Press Start 2P', cursive;
351
+ font-size: 0.75rem;
352
+ color: #ffffff;
353
+ opacity: 0.8;
354
+ margin-top: 0.25rem;
355
+ `;
@@ -1,4 +1,4 @@
1
- import { IItemPack, IPurchase, IStoreItem, ItemRarities, ItemSubType, ItemType, UserAccountTypes } from '@rpg-engine/shared';
1
+ import { IItemPack, IPurchase, IProductBlueprint, ItemRarities, ItemSubType, ItemType, UserAccountTypes, PaymentCurrency, PurchaseType } from '@rpg-engine/shared';
2
2
  import React, { ReactNode, useMemo, useState } from 'react';
3
3
  import { FaHistory, FaShoppingCart } from 'react-icons/fa';
4
4
  import styled from 'styled-components';
@@ -19,7 +19,7 @@ type TabId = 'premium' | 'packs' | 'items';
19
19
 
20
20
  // Define IStoreProps locally as a workaround
21
21
  export interface IStoreProps {
22
- items: IStoreItem[];
22
+ items: IProductBlueprint[];
23
23
  packs?: IItemPack[];
24
24
  atlasJSON: any;
25
25
  atlasIMG: string;
@@ -32,6 +32,7 @@ export interface IStoreProps {
32
32
  hidePremiumTab?: boolean;
33
33
  tabOrder?: TabId[];
34
34
  defaultActiveTab?: TabId;
35
+ textInputItemKeys?: string[];
35
36
  }
36
37
 
37
38
  export const Store: React.FC<IStoreProps> = ({
@@ -48,6 +49,7 @@ export const Store: React.FC<IStoreProps> = ({
48
49
  hidePremiumTab = false,
49
50
  tabOrder,
50
51
  defaultActiveTab,
52
+ textInputItemKeys = [],
51
53
  }) => {
52
54
  const [selectedPack, setSelectedPack] = useState<IItemPack | null>(null);
53
55
  const [activeTab, setActiveTab] = useState<TabId>(() => {
@@ -69,41 +71,33 @@ export const Store: React.FC<IStoreProps> = ({
69
71
  isCartOpen,
70
72
  } = useStoreCart();
71
73
  const [isCollectingMetadata, setIsCollectingMetadata] = useState(false);
72
- const [currentMetadataItem, setCurrentMetadataItem] = useState<IStoreItem | null>(null);
74
+ const [currentMetadataItem, setCurrentMetadataItem] = useState<IProductBlueprint | null>(null);
73
75
 
74
76
  const handleAddPackToCart = (pack: IItemPack) => {
75
- const packItem: IStoreItem = {
76
- _id: pack.key,
77
+ const packItem: IProductBlueprint = {
77
78
  key: pack.key,
78
79
  name: pack.title,
80
+ description: pack.description || '',
79
81
  price: pack.priceUSD,
82
+ currency: PaymentCurrency.USD,
80
83
  texturePath: pack.image.default || pack.image.src,
81
- textureKey: pack.image.default || pack.image.src,
82
- type: ItemType.Consumable,
83
- subType: ItemSubType.Other,
84
- description: pack.description || '',
85
- fullDescription: pack.description || '',
86
- textureAtlas: 'items',
87
- weight: 0,
84
+ type: PurchaseType.Pack,
85
+ onPurchase: async () => {},
86
+ itemType: ItemType.Consumable,
87
+ itemSubType: ItemSubType.Other,
88
88
  rarity: ItemRarities.Common,
89
- allowedEquipSlotType: [],
90
- isEquipable: false,
89
+ weight: 0,
91
90
  isStackable: false,
92
- isTwoHanded: false,
93
- hasUseWith: false,
94
91
  maxStackSize: 1,
95
92
  isUsable: false,
96
- isStorable: true,
97
- isSolid: false,
98
- isItemContainer: false,
99
93
  };
100
94
  handleAddToCart(packItem, 1);
101
95
  };
102
96
 
103
97
  const filterItems = (
104
- itemsToFilter: IStoreItem[],
98
+ itemsToFilter: IProductBlueprint[],
105
99
  type: 'items' | 'premium'
106
- ): IStoreItem[] => {
100
+ ): IProductBlueprint[] => {
107
101
  return itemsToFilter.filter(item => {
108
102
  if (type === 'premium') {
109
103
  return item.requiredAccountType?.length ?? 0 > 0;
@@ -188,6 +182,7 @@ export const Store: React.FC<IStoreProps> = ({
188
182
  atlasJSON={atlasJSON}
189
183
  atlasIMG={atlasIMG}
190
184
  userAccountType={userAccountType}
185
+ textInputItemKeys={textInputItemKeys}
191
186
  />
192
187
  ),
193
188
  },
@@ -1,4 +1,4 @@
1
- import { IStoreItem, MetadataType, UserAccountTypes } from '@rpg-engine/shared';
1
+ import { IProductBlueprint, MetadataType, UserAccountTypes } from '@rpg-engine/shared';
2
2
  import React, { useEffect, useState } from 'react';
3
3
  import { FaCartPlus } from 'react-icons/fa';
4
4
  import styled from 'styled-components';
@@ -8,10 +8,10 @@ import { CTAButton } from '../shared/CTAButton/CTAButton';
8
8
  import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
9
9
 
10
10
  interface IStoreCharacterSkinRowProps {
11
- item: IStoreItem;
11
+ item: IProductBlueprint;
12
12
  atlasJSON: Record<string, any>;
13
13
  atlasIMG: string;
14
- onAddToCart: (item: IStoreItem, quantity: number, metadata?: Record<string, any>) => void;
14
+ onAddToCart: (item: IProductBlueprint, quantity: number, metadata?: Record<string, any>) => void;
15
15
  userAccountType: UserAccountTypes;
16
16
  }
17
17
 
@@ -36,7 +36,7 @@ export const StoreCharacterSkinRow: React.FC<IStoreCharacterSkinRowProps> = ({
36
36
  // Effect to reset currentIndex when switching items
37
37
  useEffect(() => {
38
38
  setCurrentIndex(0);
39
- }, [item._id]);
39
+ }, [item.key]);
40
40
 
41
41
  const handlePreviousSkin = () => {
42
42
  setCurrentIndex((prevIndex) =>
@@ -1,14 +1,14 @@
1
- import { IItemPack, IStoreItem } from '@rpg-engine/shared';
1
+ import { IItemPack, IProductBlueprint } from '@rpg-engine/shared';
2
2
  import React from 'react';
3
3
  import { FaArrowLeft, FaCartPlus } from 'react-icons/fa';
4
4
  import styled from 'styled-components';
5
5
  import { CTAButton } from '../shared/CTAButton/CTAButton';
6
6
 
7
7
  interface IStoreItemDetailsProps {
8
- item: IStoreItem | (IItemPack & { name: string; texturePath: string });
8
+ item: IProductBlueprint | (IItemPack & { name: string; texturePath: string });
9
9
  imageUrl: string | { src: string; default?: string };
10
10
  onBack: () => void;
11
- onAddToCart: (item: IStoreItem) => void;
11
+ onAddToCart: (item: IProductBlueprint) => void;
12
12
  }
13
13
 
14
14
  export const StoreItemDetails: React.FC<IStoreItemDetailsProps> = ({
@@ -53,7 +53,7 @@ export const StoreItemDetails: React.FC<IStoreItemDetailsProps> = ({
53
53
  <CTAButton
54
54
  icon={<FaCartPlus />}
55
55
  label="Add to Cart"
56
- onClick={() => onAddToCart(item as IStoreItem)}
56
+ onClick={() => onAddToCart(item as IProductBlueprint)}
57
57
  fullWidth
58
58
  />
59
59
  </Actions>
@@ -1,4 +1,4 @@
1
- import { IStoreItem, UserAccountTypes } from '@rpg-engine/shared';
1
+ import { IProductBlueprint, UserAccountTypes } from '@rpg-engine/shared';
2
2
  import React, { useState } from 'react';
3
3
  import { FaCartPlus } from 'react-icons/fa';
4
4
  import styled from 'styled-components';
@@ -7,11 +7,13 @@ import { CTAButton } from '../shared/CTAButton/CTAButton';
7
7
  import { SpriteFromAtlas } from '../shared/SpriteFromAtlas';
8
8
 
9
9
  interface IStoreItemRowProps {
10
- item: IStoreItem;
10
+ item: IProductBlueprint;
11
11
  atlasJSON: Record<string, any>;
12
12
  atlasIMG: string;
13
- onAddToCart: (item: IStoreItem, quantity: number, metadata?: Record<string, any>) => void;
13
+ onAddToCart: (item: IProductBlueprint, quantity: number, metadata?: Record<string, any>) => void;
14
14
  userAccountType: UserAccountTypes;
15
+ showTextInput?: boolean;
16
+ textInputPlaceholder?: string;
15
17
  }
16
18
 
17
19
  export const StoreItemRow: React.FC<IStoreItemRowProps> = ({
@@ -20,8 +22,11 @@ export const StoreItemRow: React.FC<IStoreItemRowProps> = ({
20
22
  atlasIMG,
21
23
  onAddToCart,
22
24
  userAccountType,
25
+ showTextInput = false,
26
+ textInputPlaceholder = item.inputPlaceholder,
23
27
  }) => {
24
28
  const [quantity, setQuantity] = useState(1);
29
+ const [textInputValue, setTextInputValue] = useState('');
25
30
 
26
31
  const handleQuantityChange = (e: React.ChangeEvent<HTMLInputElement>) => {
27
32
  const value = parseInt(e.target.value) || 1;
@@ -45,10 +50,15 @@ export const StoreItemRow: React.FC<IStoreItemRowProps> = ({
45
50
  !item.requiredAccountType?.length ||
46
51
  item.requiredAccountType.includes(userAccountType);
47
52
 
48
- const handleAddToCart = () => {
53
+ const handleAddToCartInternal = () => {
49
54
  if (!hasRequiredAccount) return;
55
+ if (showTextInput) {
56
+ onAddToCart(item, 1, { inputValue: textInputValue });
57
+ setTextInputValue('');
58
+ } else {
50
59
  onAddToCart(item, quantity);
51
- setQuantity(1); // Reset quantity after adding to cart
60
+ setQuantity(1);
61
+ }
52
62
  };
53
63
 
54
64
  return (
@@ -68,9 +78,20 @@ export const StoreItemRow: React.FC<IStoreItemRowProps> = ({
68
78
  <ItemDetails>
69
79
  <ItemName>{item.name}</ItemName>
70
80
  <ItemPrice>${item.price}</ItemPrice>
81
+ <ItemDescription>{item.description}</ItemDescription>
71
82
  </ItemDetails>
72
83
 
73
84
  <Controls>
85
+ {/* Show text input if configured, else show arrows only for stackable items */}
86
+ {showTextInput ? (
87
+ <TextInput
88
+ type="text"
89
+ value={textInputValue}
90
+ placeholder={textInputPlaceholder}
91
+ onChange={e => setTextInputValue(e.target.value)}
92
+ className="rpgui-input"
93
+ />
94
+ ) : item.isStackable ? (
74
95
  <ArrowsContainer>
75
96
  <SelectArrow
76
97
  direction="left"
@@ -94,11 +115,12 @@ export const StoreItemRow: React.FC<IStoreItemRowProps> = ({
94
115
  size={24}
95
116
  />
96
117
  </ArrowsContainer>
118
+ ) : null}
97
119
 
98
120
  <CTAButton
99
121
  icon={<FaCartPlus />}
100
122
  label="Add"
101
- onClick={handleAddToCart}
123
+ onClick={handleAddToCartInternal}
102
124
  disabled={!hasRequiredAccount}
103
125
  />
104
126
  </Controls>
@@ -147,6 +169,13 @@ const ItemPrice = styled.div`
147
169
  color: #fef08a;
148
170
  `;
149
171
 
172
+ const ItemDescription = styled.div`
173
+ font-family: 'Press Start 2P', cursive;
174
+ font-size: 0.625rem;
175
+ color: rgba(255, 255, 255, 0.7);
176
+ line-height: 1.4;
177
+ `;
178
+
150
179
  const Controls = styled.div`
151
180
  display: flex;
152
181
  align-items: center;
@@ -179,3 +208,14 @@ const QuantityInput = styled.input`
179
208
  margin: 0;
180
209
  }
181
210
  `;
211
+
212
+ const TextInput = styled.input`
213
+ width: 120px;
214
+ text-align: center;
215
+ margin: 0 auto;
216
+ font-size: 0.875rem;
217
+ background: rgba(0, 0, 0, 0.2);
218
+ color: #ffffff;
219
+ border: none;
220
+ padding: 0.25rem;
221
+ `;
@@ -1,23 +1,24 @@
1
1
  import {
2
- ICartItem as IBaseCartItem,
3
2
  IPurchase,
4
3
  IPurchaseUnit,
5
- IStoreItem,
4
+ IProductBlueprint,
6
5
  MetadataType,
7
6
  PurchaseType
8
7
  } from '@rpg-engine/shared';
9
8
  import { useEffect, useRef, useState } from 'react';
10
9
  import { useStoreMetadata } from './useStoreMetadata';
11
10
 
12
- // Extend the base cart item to include metadata
13
- interface ICartItem extends IBaseCartItem {
11
+ // Create local cart item interface that uses IProductBlueprint
12
+ interface ICartItem {
13
+ item: IProductBlueprint;
14
+ quantity: number;
14
15
  metadata?: Record<string, any>;
15
16
  }
16
17
 
17
18
  interface IUseStoreCart {
18
19
  cartItems: ICartItem[];
19
20
  isCartOpen: boolean;
20
- handleAddToCart: (item: IStoreItem, quantity: number, metadata?: Record<string, any>) => void;
21
+ handleAddToCart: (item: IProductBlueprint, quantity: number, metadata?: Record<string, any>) => void;
21
22
  handleRemoveFromCart: (itemKey: string) => void;
22
23
  handlePurchase: (onPurchase: (purchase: IPurchase) => void) => void;
23
24
  openCart: () => void;
@@ -40,7 +41,7 @@ export const useStoreCart = (): IUseStoreCart => {
40
41
 
41
42
  const { collectMetadata, isCollectingMetadata } = useStoreMetadata();
42
43
 
43
- const handleAddToCart = async (item: IStoreItem, quantity: number, preselectedMetadata?: Record<string, any>) => {
44
+ const handleAddToCart = async (item: IProductBlueprint, quantity: number, preselectedMetadata?: Record<string, any>) => {
44
45
  // If metadata is already provided (from inline selection), use it directly
45
46
  if (preselectedMetadata) {
46
47
  setCartItems(prevItems => {
@@ -57,7 +58,7 @@ export const useStoreCart = (): IUseStoreCart => {
57
58
  }
58
59
 
59
60
  // If item requires metadata but none was provided, collect it before adding to cart
60
- if (item.metadataType && item.metadataType !== MetadataType.None) {
61
+ if (item.metadataType === MetadataType.CharacterSkin) {
61
62
  const metadata = await collectMetadata(item);
62
63
  if (!metadata) return; // User cancelled
63
64
 
@@ -156,8 +157,12 @@ export const useStoreCart = (): IUseStoreCart => {
156
157
  };
157
158
 
158
159
  // Helper functions
159
- function getPurchaseType(item: IStoreItem): PurchaseType {
160
- // Check if the item comes from a pack based on naming convention or other property
160
+ function getPurchaseType(item: IProductBlueprint): PurchaseType {
161
+ // Use the type from IProductBlueprint if available, otherwise infer
162
+ if (item.type) {
163
+ return item.type;
164
+ }
165
+ // Fallback logic for backward compatibility
161
166
  if (item.key.startsWith('pack_')) {
162
167
  return PurchaseType.Pack;
163
168
  } else {
@@ -1,16 +1,16 @@
1
- import { IStoreItem, MetadataType } from "@rpg-engine/shared";
1
+ import { IProductBlueprint, MetadataType } from "@rpg-engine/shared";
2
2
  import { useState } from "react";
3
3
 
4
4
  interface IUseStoreMetadata {
5
- collectMetadata: (item: IStoreItem) => Promise<Record<string, any> | null>;
5
+ collectMetadata: (item: IProductBlueprint) => Promise<Record<string, any> | null>;
6
6
  isCollectingMetadata: boolean;
7
7
  }
8
8
 
9
9
  export const useStoreMetadata = (): IUseStoreMetadata => {
10
10
  const [isCollectingMetadata, setIsCollectingMetadata] = useState(false);
11
11
 
12
- const collectMetadata = async (item: IStoreItem): Promise<Record<string, any> | null> => {
13
- if (!item.metadataType || item.metadataType === MetadataType.None) {
12
+ const collectMetadata = async (item: IProductBlueprint): Promise<Record<string, any> | null> => {
13
+ if (!item.metadataType || item.metadataType !== MetadataType.CharacterSkin) {
14
14
  return null;
15
15
  }
16
16
 
@@ -49,7 +49,7 @@ declare global {
49
49
  interface Window {
50
50
  __metadataResolvers?: {
51
51
  resolve: (metadata: Record<string, any> | null) => void;
52
- item: IStoreItem;
52
+ item: IProductBlueprint;
53
53
  };
54
54
  }
55
55
  }
@@ -1,4 +1,4 @@
1
- import { IStoreItem, MetadataType, UserAccountTypes } from '@rpg-engine/shared';
1
+ import { IProductBlueprint, MetadataType, UserAccountTypes } from '@rpg-engine/shared';
2
2
  import React, { useState } from 'react';
3
3
  import { ScrollableContent } from '../../shared/ScrollableContent/ScrollableContent';
4
4
  import { StoreCharacterSkinRow } from '../StoreCharacterSkinRow';
@@ -6,11 +6,12 @@ import { StoreItemRow } from '../StoreItemRow';
6
6
 
7
7
 
8
8
  interface IStoreItemsSectionProps {
9
- items: IStoreItem[];
10
- onAddToCart: (item: IStoreItem, quantity: number, metadata?: Record<string, any>) => void;
9
+ items: IProductBlueprint[];
10
+ onAddToCart: (item: IProductBlueprint, quantity: number, metadata?: Record<string, any>) => void;
11
11
  atlasJSON: Record<string, any>;
12
12
  atlasIMG: string;
13
13
  userAccountType?: UserAccountTypes;
14
+ textInputItemKeys?: string[];
14
15
  }
15
16
 
16
17
  export const StoreItemsSection: React.FC<IStoreItemsSectionProps> = ({
@@ -19,6 +20,7 @@ export const StoreItemsSection: React.FC<IStoreItemsSectionProps> = ({
19
20
  atlasJSON,
20
21
  atlasIMG,
21
22
  userAccountType,
23
+ textInputItemKeys = [],
22
24
  }) => {
23
25
  const [searchQuery, setSearchQuery] = useState('');
24
26
 
@@ -26,12 +28,12 @@ export const StoreItemsSection: React.FC<IStoreItemsSectionProps> = ({
26
28
  item.name.toLowerCase().includes(searchQuery.toLowerCase())
27
29
  );
28
30
 
29
- const renderStoreItem = (item: IStoreItem) => {
30
- // Use the specialized character skin row for items with character skin metadata
31
+ const renderStoreItem = (item: IProductBlueprint) => {
32
+ // Prefer a specialized character skin row when needed
31
33
  if (item.metadataType === MetadataType.CharacterSkin) {
32
34
  return (
33
35
  <StoreCharacterSkinRow
34
- key={item._id}
36
+ key={item.key}
35
37
  item={item}
36
38
  atlasJSON={atlasJSON}
37
39
  atlasIMG={atlasIMG}
@@ -40,11 +42,24 @@ export const StoreItemsSection: React.FC<IStoreItemsSectionProps> = ({
40
42
  />
41
43
  );
42
44
  }
43
-
44
- // Use the standard item row for all other items
45
+ // Render text input row when configured for this item key
46
+ if (textInputItemKeys.includes(item.key)) {
47
+ return (
48
+ <StoreItemRow
49
+ key={item.key}
50
+ item={item}
51
+ atlasJSON={atlasJSON}
52
+ atlasIMG={atlasIMG}
53
+ onAddToCart={onAddToCart}
54
+ userAccountType={userAccountType || UserAccountTypes.Free}
55
+ showTextInput
56
+ />
57
+ );
58
+ }
59
+ // Fallback to standard arrow-based row
45
60
  return (
46
61
  <StoreItemRow
47
- key={item._id}
62
+ key={item.key}
48
63
  item={item}
49
64
  atlasJSON={atlasJSON}
50
65
  atlasIMG={atlasIMG}
@@ -1,4 +1,4 @@
1
- import { IItemPack, IPurchase, IStoreItem, ItemRarities, ItemSubType, ItemType, MetadataType, UserAccountTypes } from '@rpg-engine/shared';
1
+ import { IItemPack, IPurchase, IProductBlueprint, ItemRarities, ItemSubType, ItemType, MetadataType, UserAccountTypes, PaymentCurrency, PurchaseType } from '@rpg-engine/shared';
2
2
  import type { Meta, StoryObj } from '@storybook/react';
3
3
  import React from 'react';
4
4
  import { RPGUIRoot } from '../../../components/RPGUI/RPGUIRoot';
@@ -29,41 +29,24 @@ export default meta;
29
29
  type Story = StoryObj<typeof Store>;
30
30
 
31
31
  // Create mock items once, with fixed stock values
32
- const storeItems: IStoreItem[] = mockItems.map((item, index) => ({
33
- _id: `original-${item.key}-${index}`,
32
+ const storeItems: IProductBlueprint[] = mockItems.map((item, index) => ({
34
33
  key: `original-${item.key}-${index}`,
35
34
  name: item.name,
36
35
  description: item.description,
37
- fullDescription: item.description,
36
+ price: item.basePrice,
37
+ currency: PaymentCurrency.USD,
38
38
  texturePath: item.texturePath,
39
39
  textureAtlas: 'items',
40
40
  textureKey: item.texturePath,
41
- price: item.basePrice,
42
- stock: 5 + (index % 5), // Fixed stock values based on index
43
- type: item.type,
44
- subType: item.subType,
45
- attack: item.attack || 0,
46
- defense: item.defense || 0,
47
- weight: item.weight,
41
+ type: PurchaseType.Item,
42
+ onPurchase: async () => {},
43
+ itemType: item.type,
44
+ itemSubType: item.subType,
48
45
  rarity: item.rarity,
49
- isEquipable: true,
46
+ weight: item.weight,
50
47
  isStackable: item.maxStackSize > 1,
51
- isUsable: true,
52
- isStorable: true,
53
- hasUseWith: false,
54
- isSolid: false,
55
- isTwoHanded: false,
56
- isItemContainer: false,
57
- layer: 1,
58
- allowedEquipSlotType: item.allowedEquipSlotType || [],
59
48
  maxStackSize: item.maxStackSize || 1,
60
- usableEffectDescription: item.usableEffectDescription || '',
61
- canSell: item.canSell ?? true,
62
- rangeType: item.rangeType,
63
- entityEffects: item.entityEffects || [],
64
- entityEffectChance: item.entityEffectChance || 0,
65
- equippedBuff: item.equippedBuff || [],
66
- equippedBuffDescription: item.equippedBuffDescription || '',
49
+ isUsable: true,
67
50
  requiredAccountType: item.rarity === 'Legendary' ? [UserAccountTypes.PremiumGold] : [],
68
51
  }));
69
52
 
@@ -87,35 +70,25 @@ const availableCharacters = [
87
70
  ];
88
71
 
89
72
  // Create character skin items
90
- const characterSkinItems: IStoreItem[] = [
73
+ const characterSkinItems: IProductBlueprint[] = [
91
74
  {
92
- _id: 'skin-character-customization',
93
75
  key: 'skin-character-customization',
94
76
  name: 'Character Skin Customization',
95
77
  description: 'Customize your character\'s appearance with a variety of skins',
96
- fullDescription: 'This premium item allows you to customize your character\'s appearance by selecting from a variety of available skins.',
78
+ price: 14.99,
79
+ currency: PaymentCurrency.USD,
97
80
  texturePath: 'items/character_customization.png',
98
81
  textureAtlas: 'items',
99
82
  textureKey: 'items/character_customization.png',
100
- price: 14.99,
101
- type: ItemType.Other,
102
- subType: ItemSubType.Other,
103
- attack: 0,
104
- defense: 0,
105
- weight: 0,
83
+ type: PurchaseType.Item,
84
+ onPurchase: async () => {},
85
+ itemType: ItemType.Other,
86
+ itemSubType: ItemSubType.Other,
106
87
  rarity: ItemRarities.Rare,
107
- isEquipable: false,
88
+ weight: 0,
108
89
  isStackable: false,
109
- isUsable: true,
110
- isStorable: true,
111
- hasUseWith: false,
112
- isSolid: false,
113
- isTwoHanded: false,
114
- isItemContainer: false,
115
- layer: 1,
116
- allowedEquipSlotType: [],
117
90
  maxStackSize: 1,
118
- // Add metadata type and config
91
+ isUsable: true,
119
92
  metadataType: MetadataType.CharacterSkin,
120
93
  metadataConfig: {
121
94
  availableCharacters,
@@ -124,34 +97,24 @@ const characterSkinItems: IStoreItem[] = [
124
97
  },
125
98
  },
126
99
  {
127
- _id: 'skin-premium-character-pack',
128
100
  key: 'skin-premium-character-pack',
129
101
  name: 'Premium Character Skin Pack',
130
102
  description: 'A premium collection of exclusive character skins',
131
- fullDescription: 'This exclusive premium pack gives you access to rare and unique character skins to stand out from the crowd.',
103
+ price: 24.99,
104
+ currency: PaymentCurrency.USD,
132
105
  texturePath: 'items/premium_character_pack.png',
133
106
  textureAtlas: 'items',
134
107
  textureKey: 'items/premium_character_pack.png',
135
- price: 24.99,
136
- type: ItemType.Other,
137
- subType: ItemSubType.Other,
138
- attack: 0,
139
- defense: 0,
140
- weight: 0,
108
+ type: PurchaseType.Item,
109
+ onPurchase: async () => {},
110
+ itemType: ItemType.Other,
111
+ itemSubType: ItemSubType.Other,
141
112
  rarity: ItemRarities.Epic,
142
- isEquipable: false,
113
+ weight: 0,
143
114
  isStackable: false,
144
- isUsable: true,
145
- isStorable: true,
146
- hasUseWith: false,
147
- isSolid: false,
148
- isTwoHanded: false,
149
- isItemContainer: false,
150
- layer: 1,
151
- allowedEquipSlotType: [],
152
115
  maxStackSize: 1,
116
+ isUsable: true,
153
117
  requiredAccountType: [UserAccountTypes.PremiumSilver],
154
- // Add metadata type and config with the same character options
155
118
  metadataType: MetadataType.CharacterSkin,
156
119
  metadataConfig: {
157
120
  availableCharacters,
@@ -162,22 +125,19 @@ const characterSkinItems: IStoreItem[] = [
162
125
  ];
163
126
 
164
127
  // Create duplicated items once with unique keys
165
- const duplicatedItems: IStoreItem[] = [
128
+ const duplicatedItems: IProductBlueprint[] = [
166
129
  ...storeItems,
167
130
  ...characterSkinItems,
168
131
  ...storeItems.map((item, index) => ({
169
132
  ...item,
170
- _id: `copy1-${item.key}-${index}`,
171
133
  key: `copy1-${item.key}-${index}`,
172
134
  })),
173
135
  ...storeItems.map((item, index) => ({
174
136
  ...item,
175
- _id: `copy2-${item.key}-${index}`,
176
137
  key: `copy2-${item.key}-${index}`,
177
138
  })),
178
139
  ...storeItems.map((item, index) => ({
179
140
  ...item,
180
- _id: `copy3-${item.key}-${index}`,
181
141
  key: `copy3-${item.key}-${index}`,
182
142
  })),
183
143
  ];
@@ -249,6 +209,7 @@ export const Default: Story = {
249
209
  hidePremiumTab={true}
250
210
  tabOrder={['items', 'packs']}
251
211
  defaultActiveTab="items"
212
+ textInputItemKeys={['original-greater-life-potion-2', 'original-angelic-sword-1']}
252
213
  />
253
214
  ),
254
215
  };