@rpg-engine/long-bow 0.6.69 → 0.6.71
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/components/Friends/SearchFriend.d.ts +4 -4
- package/dist/components/QuestList.d.ts +2 -3
- package/dist/components/Table/Table.d.ts +5 -0
- package/dist/components/shared/Ellipsis.d.ts +1 -1
- package/dist/components/shared/SimpleTooltip.d.ts +12 -0
- package/dist/long-bow.cjs.development.js +402 -180
- 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 +404 -183
- package/dist/long-bow.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Friends/FriendList.tsx +6 -19
- package/src/components/Friends/SearchFriend.tsx +160 -107
- package/src/components/QuestList.tsx +144 -107
- package/src/components/Table/Table.tsx +19 -0
- package/src/components/shared/Ellipsis.tsx +2 -2
- package/src/components/shared/SimpleTooltip.tsx +198 -0
- package/src/stories/QuestList.stories.tsx +12 -42
package/package.json
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
TableCell,
|
|
11
11
|
TableHeader,
|
|
12
12
|
TableRow,
|
|
13
|
+
UserActionLink,
|
|
13
14
|
} from '../Table/Table';
|
|
14
15
|
import { SearchFriend } from './SearchFriend';
|
|
15
16
|
export type IFriend = Pick<ICharacter, 'name' | '_id' | 'isOnline'>;
|
|
@@ -89,18 +90,18 @@ export const FriendList: React.FC<IFriendListProps> = ({
|
|
|
89
90
|
<TableCell>{friend.name}</TableCell>
|
|
90
91
|
<TableCell>
|
|
91
92
|
<ActionButtons>
|
|
92
|
-
<
|
|
93
|
-
color={uiColors.
|
|
93
|
+
<UserActionLink
|
|
94
|
+
color={uiColors.white}
|
|
94
95
|
onClick={() => onOpenPrivateMessage(friend)}
|
|
95
96
|
>
|
|
96
97
|
Chat
|
|
97
|
-
</
|
|
98
|
-
<
|
|
98
|
+
</UserActionLink>
|
|
99
|
+
<UserActionLink
|
|
99
100
|
color={uiColors.red}
|
|
100
101
|
onClick={() => onRemoveFriend(friend)}
|
|
101
102
|
>
|
|
102
103
|
Remove
|
|
103
|
-
</
|
|
104
|
+
</UserActionLink>
|
|
104
105
|
</ActionButtons>
|
|
105
106
|
</TableCell>
|
|
106
107
|
</TableRow>
|
|
@@ -152,17 +153,3 @@ const ButtonContainer = styled.div`
|
|
|
152
153
|
width: 100%;
|
|
153
154
|
margin-top: 1rem;
|
|
154
155
|
`;
|
|
155
|
-
|
|
156
|
-
interface IUserActionProps {
|
|
157
|
-
color: string;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const UserAction = styled.span<IUserActionProps>`
|
|
161
|
-
color: ${({ color }) => color} !important;
|
|
162
|
-
cursor: pointer;
|
|
163
|
-
margin-right: 0.5rem;
|
|
164
|
-
|
|
165
|
-
&:hover {
|
|
166
|
-
text-decoration: underline;
|
|
167
|
-
}
|
|
168
|
-
`;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { debounce } from 'lodash';
|
|
2
|
+
import React, { useCallback, useState } from 'react';
|
|
2
3
|
import styled from 'styled-components';
|
|
4
|
+
import { TableTab, UserActionLink } from '../..';
|
|
5
|
+
import { uiColors } from '../../constants/uiColors';
|
|
3
6
|
import { uiFonts } from '../../constants/uiFonts';
|
|
4
|
-
import {
|
|
5
|
-
import { Column } from '../shared/Column';
|
|
6
|
-
import type { IFriend } from './FriendList';
|
|
7
|
+
import { IFriend } from './FriendList';
|
|
7
8
|
|
|
8
|
-
interface
|
|
9
|
+
interface ISearchFriendProps {
|
|
9
10
|
searchedCharacters: IFriend[];
|
|
10
11
|
friendRequests: IFriend[];
|
|
11
12
|
onFocus?: () => void;
|
|
@@ -16,142 +17,194 @@ interface ISearchFriendProp {
|
|
|
16
17
|
onRejectRequest: (character: IFriend) => void;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
export const SearchFriend = (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
} = props;
|
|
20
|
+
export const SearchFriend: React.FC<ISearchFriendProps> = ({
|
|
21
|
+
searchedCharacters,
|
|
22
|
+
friendRequests,
|
|
23
|
+
onBlur,
|
|
24
|
+
onFocus,
|
|
25
|
+
onSearch,
|
|
26
|
+
onSendFriendRequest,
|
|
27
|
+
onAcceptRequest,
|
|
28
|
+
onRejectRequest,
|
|
29
|
+
}) => {
|
|
30
30
|
const [characterName, setCharacterName] = useState('');
|
|
31
31
|
|
|
32
|
+
const debouncedSearch = useCallback(
|
|
33
|
+
debounce((name: string) => {
|
|
34
|
+
onSearch(name);
|
|
35
|
+
}, 300),
|
|
36
|
+
[]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
40
|
+
const name = e.target.value;
|
|
41
|
+
setCharacterName(name);
|
|
42
|
+
debouncedSearch(name);
|
|
43
|
+
};
|
|
44
|
+
|
|
32
45
|
const handleSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
|
|
33
46
|
event.preventDefault();
|
|
34
|
-
if (
|
|
35
|
-
|
|
47
|
+
if (characterName.trim()) {
|
|
48
|
+
onSearch(characterName);
|
|
49
|
+
}
|
|
36
50
|
};
|
|
37
51
|
|
|
52
|
+
const searchTabContent = (
|
|
53
|
+
<ListContainer>
|
|
54
|
+
<SearchForm onSubmit={handleSubmit}>
|
|
55
|
+
<SearchInput
|
|
56
|
+
value={characterName}
|
|
57
|
+
id="characterName"
|
|
58
|
+
name="characterName"
|
|
59
|
+
onChange={handleInputChange}
|
|
60
|
+
type="text"
|
|
61
|
+
autoComplete="off"
|
|
62
|
+
onFocus={onFocus}
|
|
63
|
+
onBlur={onBlur}
|
|
64
|
+
onPointerDown={onFocus}
|
|
65
|
+
autoFocus
|
|
66
|
+
placeholder="Search for a character..."
|
|
67
|
+
/>
|
|
68
|
+
</SearchForm>
|
|
69
|
+
<CharacterList
|
|
70
|
+
characters={searchedCharacters}
|
|
71
|
+
onAction={onSendFriendRequest}
|
|
72
|
+
actionLabel="Add Friend"
|
|
73
|
+
/>
|
|
74
|
+
</ListContainer>
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const requestsTabContent = (
|
|
78
|
+
<ListContainer>
|
|
79
|
+
<FriendRequestSection
|
|
80
|
+
friendRequests={friendRequests}
|
|
81
|
+
onAccept={onAcceptRequest}
|
|
82
|
+
onReject={onRejectRequest}
|
|
83
|
+
/>
|
|
84
|
+
</ListContainer>
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
const tabs = [
|
|
88
|
+
{ id: 'search', title: 'Search', content: searchTabContent },
|
|
89
|
+
{
|
|
90
|
+
id: 'requests',
|
|
91
|
+
title: `Requests (${friendRequests.length})`,
|
|
92
|
+
content: requestsTabContent,
|
|
93
|
+
},
|
|
94
|
+
];
|
|
95
|
+
|
|
38
96
|
return (
|
|
39
|
-
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
<
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
97
|
+
<Container>
|
|
98
|
+
<TableTab
|
|
99
|
+
tabs={tabs}
|
|
100
|
+
activeTextColor="#000"
|
|
101
|
+
inactiveColor="#777"
|
|
102
|
+
borderColor="#f59e0b"
|
|
103
|
+
/>
|
|
104
|
+
</Container>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const CharacterList: React.FC<{
|
|
109
|
+
characters: IFriend[];
|
|
110
|
+
onAction: (character: IFriend) => void;
|
|
111
|
+
actionLabel: string;
|
|
112
|
+
}> = ({ characters, onAction, actionLabel }) => (
|
|
113
|
+
<ListContainer>
|
|
114
|
+
{characters.map(character => (
|
|
115
|
+
<ListItem key={character._id}>
|
|
116
|
+
<CharacterName>{character.name}</CharacterName>
|
|
117
|
+
<UserActionLink
|
|
118
|
+
color={uiColors.lightGreen}
|
|
119
|
+
onClick={() => onAction(character)}
|
|
120
|
+
>
|
|
121
|
+
{actionLabel}
|
|
122
|
+
</UserActionLink>
|
|
123
|
+
</ListItem>
|
|
124
|
+
))}
|
|
125
|
+
</ListContainer>
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const FriendRequestSection: React.FC<{
|
|
129
|
+
friendRequests: IFriend[];
|
|
130
|
+
onAccept: (character: IFriend) => void;
|
|
131
|
+
onReject: (character: IFriend) => void;
|
|
132
|
+
}> = ({ friendRequests, onAccept, onReject }) => (
|
|
133
|
+
<>
|
|
134
|
+
{friendRequests.length > 0 && (
|
|
64
135
|
<ListContainer>
|
|
65
|
-
{
|
|
66
|
-
<
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
136
|
+
{friendRequests.map(character => (
|
|
137
|
+
<ListItem key={character._id}>
|
|
138
|
+
<CharacterName>{character.name}</CharacterName>
|
|
139
|
+
<AcceptRejectActions>
|
|
140
|
+
<UserActionLink
|
|
141
|
+
color={uiColors.lightGreen}
|
|
142
|
+
onClick={() => onAccept(character)}
|
|
143
|
+
>
|
|
144
|
+
Accept
|
|
145
|
+
</UserActionLink>
|
|
146
|
+
<UserActionLink
|
|
147
|
+
color={uiColors.red}
|
|
148
|
+
onClick={() => onReject(character)}
|
|
149
|
+
>
|
|
150
|
+
Reject
|
|
151
|
+
</UserActionLink>
|
|
152
|
+
</AcceptRejectActions>
|
|
153
|
+
</ListItem>
|
|
76
154
|
))}
|
|
77
155
|
</ListContainer>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
{friendRequests.length > 0 && (
|
|
82
|
-
<ListContainer>
|
|
83
|
-
{friendRequests.map(character => (
|
|
84
|
-
<ListElement key={character._id}>
|
|
85
|
-
<p>{character.name}</p>
|
|
86
|
-
|
|
87
|
-
<AcceptRejectButtonContainer>
|
|
88
|
-
<Button
|
|
89
|
-
buttonType={ButtonTypes.RPGUIButton}
|
|
90
|
-
onPointerDown={() => onAcceptRequest(character)}
|
|
91
|
-
>
|
|
92
|
-
Accept
|
|
93
|
-
</Button>
|
|
94
|
-
<Button
|
|
95
|
-
buttonType={ButtonTypes.RPGUIButton}
|
|
96
|
-
onPointerDown={() => onRejectRequest(character)}
|
|
97
|
-
>
|
|
98
|
-
Reject
|
|
99
|
-
</Button>
|
|
100
|
-
</AcceptRejectButtonContainer>
|
|
101
|
-
</ListElement>
|
|
102
|
-
))}
|
|
103
|
-
</ListContainer>
|
|
104
|
-
)}
|
|
105
|
-
</>
|
|
106
|
-
);
|
|
107
|
-
};
|
|
156
|
+
)}
|
|
157
|
+
</>
|
|
158
|
+
);
|
|
108
159
|
|
|
109
|
-
const
|
|
160
|
+
const Container = styled.div`
|
|
161
|
+
display: flex;
|
|
162
|
+
flex-direction: column;
|
|
163
|
+
gap: 1rem;
|
|
164
|
+
`;
|
|
165
|
+
|
|
166
|
+
const SearchForm = styled.form`
|
|
110
167
|
display: flex;
|
|
111
|
-
width: 100%;
|
|
112
|
-
justify-content: center;
|
|
113
168
|
align-items: center;
|
|
169
|
+
width: 100%;
|
|
114
170
|
margin-top: 1rem;
|
|
115
171
|
`;
|
|
116
172
|
|
|
117
|
-
const
|
|
173
|
+
const SearchInput = styled.input`
|
|
118
174
|
width: 100%;
|
|
119
|
-
background-color: rgba(0, 0, 0, 0.25)
|
|
120
|
-
border: none
|
|
121
|
-
|
|
175
|
+
background-color: rgba(0, 0, 0, 0.25);
|
|
176
|
+
border: none;
|
|
177
|
+
padding: 0.5rem;
|
|
178
|
+
font-size: ${uiFonts.size.small};
|
|
122
179
|
`;
|
|
123
180
|
|
|
124
181
|
const ListContainer = styled.ul`
|
|
125
|
-
width: 100%;
|
|
126
|
-
c4height: 50vh;
|
|
127
|
-
border: none;
|
|
128
|
-
overflow-y: scroll;
|
|
129
182
|
list-style: none;
|
|
130
183
|
padding: 0;
|
|
184
|
+
margin: 0;
|
|
185
|
+
width: 100%;
|
|
186
|
+
max-height: 50vh;
|
|
187
|
+
overflow-y: auto;
|
|
131
188
|
|
|
132
189
|
@media (max-width: 768px) {
|
|
133
|
-
max-height:
|
|
190
|
+
max-height: 90vh;
|
|
134
191
|
}
|
|
135
192
|
`;
|
|
136
193
|
|
|
137
|
-
const
|
|
138
|
-
margin: 0.5rem 0 !important;
|
|
139
|
-
font-size: ${uiFonts.size.small};
|
|
140
|
-
padding: 0.5rem 2px;
|
|
194
|
+
const ListItem = styled.li`
|
|
141
195
|
display: flex;
|
|
142
196
|
align-items: center;
|
|
143
197
|
justify-content: space-between;
|
|
198
|
+
padding: 0.5rem;
|
|
199
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
144
200
|
`;
|
|
145
201
|
|
|
146
|
-
const
|
|
147
|
-
font-size: ${uiFonts.size.small}
|
|
148
|
-
margin
|
|
149
|
-
text-align: center;
|
|
150
|
-
gap: 0.5rem;
|
|
202
|
+
const CharacterName = styled.p`
|
|
203
|
+
font-size: ${uiFonts.size.small};
|
|
204
|
+
margin: 0;
|
|
151
205
|
`;
|
|
152
206
|
|
|
153
|
-
const
|
|
207
|
+
const AcceptRejectActions = styled.div`
|
|
154
208
|
display: flex;
|
|
155
|
-
justify-content: space-between;
|
|
156
209
|
gap: 0.5rem;
|
|
157
210
|
`;
|
|
@@ -1,135 +1,172 @@
|
|
|
1
|
-
import { IQuest } from '@rpg-engine/shared';
|
|
2
1
|
import React from 'react';
|
|
2
|
+
import 'react-tippy/dist/tippy.css';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
IQuest,
|
|
7
|
+
IQuestObjectiveInteraction,
|
|
8
|
+
IQuestObjectiveKill,
|
|
9
|
+
QuestStatus,
|
|
10
|
+
} from '@rpg-engine/shared';
|
|
11
|
+
import { uiColors } from '../constants/uiColors';
|
|
12
|
+
import { Table, TableCell, TableHeader, TableRow } from './Table/Table';
|
|
13
|
+
import { Ellipsis } from './shared/Ellipsis';
|
|
14
|
+
import { SimpleTooltip } from './shared/SimpleTooltip';
|
|
7
15
|
|
|
8
16
|
export interface IQuestListProps {
|
|
9
17
|
quests?: IQuest[];
|
|
10
|
-
onClose: () => void;
|
|
11
|
-
scale?: number;
|
|
12
18
|
}
|
|
13
19
|
|
|
14
|
-
export const QuestList: React.FC<IQuestListProps> = ({
|
|
15
|
-
quests,
|
|
16
|
-
onClose,
|
|
17
|
-
scale,
|
|
18
|
-
}) => {
|
|
20
|
+
export const QuestList: React.FC<IQuestListProps> = ({ quests }) => {
|
|
19
21
|
return (
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
22
|
+
<QuestListContainer>
|
|
23
|
+
{quests && quests.length > 0 ? (
|
|
24
|
+
<>
|
|
25
|
+
<Table>
|
|
26
|
+
<thead>
|
|
27
|
+
<TableRow>
|
|
28
|
+
<TableHeader>Status</TableHeader>
|
|
29
|
+
<TableHeader>Title</TableHeader>
|
|
30
|
+
<TableHeader>Description</TableHeader>
|
|
31
|
+
<TableHeader>Objectives</TableHeader>
|
|
32
|
+
<TableHeader>Rewards</TableHeader>
|
|
33
|
+
</TableRow>
|
|
34
|
+
</thead>
|
|
35
|
+
<tbody>
|
|
36
|
+
{quests.map((quest, i) => (
|
|
37
|
+
<TableRow key={i}>
|
|
38
|
+
<TableCell style={{ color: getStatusColor(quest.status) }}>
|
|
39
|
+
{quest.status ?? 'Unknown'}
|
|
40
|
+
</TableCell>
|
|
41
|
+
<TableCell>
|
|
42
|
+
<SimpleTooltip
|
|
43
|
+
content={formatText(quest.title)}
|
|
44
|
+
direction="bottom"
|
|
45
|
+
>
|
|
46
|
+
<Ellipsis maxWidth="300px">
|
|
47
|
+
{formatText(quest.title)}
|
|
48
|
+
</Ellipsis>
|
|
49
|
+
</SimpleTooltip>
|
|
50
|
+
</TableCell>
|
|
51
|
+
<TableCell>
|
|
52
|
+
<SimpleTooltip
|
|
53
|
+
content={quest.description}
|
|
54
|
+
direction="bottom"
|
|
55
|
+
>
|
|
56
|
+
<Ellipsis maxWidth="300px">{quest.description}</Ellipsis>
|
|
57
|
+
</SimpleTooltip>
|
|
58
|
+
</TableCell>
|
|
59
|
+
<TableCell>
|
|
60
|
+
<SimpleTooltip
|
|
61
|
+
content={formatObjectives(quest.objectives)}
|
|
62
|
+
direction="bottom"
|
|
63
|
+
>
|
|
64
|
+
<Ellipsis maxWidth="300px">
|
|
65
|
+
{formatObjectives(quest.objectives)}
|
|
66
|
+
</Ellipsis>
|
|
67
|
+
</SimpleTooltip>
|
|
68
|
+
</TableCell>
|
|
69
|
+
<TableCell>
|
|
70
|
+
<SimpleTooltip
|
|
71
|
+
content={formatRewards(quest.rewards)}
|
|
72
|
+
direction="bottom"
|
|
73
|
+
>
|
|
74
|
+
<Ellipsis maxWidth="200px">
|
|
75
|
+
{formatRewards(quest.rewards)}
|
|
76
|
+
</Ellipsis>
|
|
77
|
+
</SimpleTooltip>
|
|
78
|
+
</TableCell>
|
|
79
|
+
</TableRow>
|
|
80
|
+
))}
|
|
81
|
+
</tbody>
|
|
82
|
+
</Table>
|
|
83
|
+
</>
|
|
84
|
+
) : (
|
|
85
|
+
<NoQuestContainer>
|
|
86
|
+
<p>There are no ongoing quests</p>
|
|
87
|
+
</NoQuestContainer>
|
|
88
|
+
)}
|
|
89
|
+
</QuestListContainer>
|
|
53
90
|
);
|
|
54
91
|
};
|
|
55
92
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
93
|
+
// Updated helper function to format objectives
|
|
94
|
+
const formatObjectives = (
|
|
95
|
+
objectives: (IQuestObjectiveKill | IQuestObjectiveInteraction)[]
|
|
96
|
+
) => {
|
|
97
|
+
return objectives
|
|
98
|
+
.map(objective => {
|
|
99
|
+
if ('killCountTarget' in objective) {
|
|
100
|
+
// This is an IQuestObjectiveKill
|
|
101
|
+
const killObjective = objective as IQuestObjectiveKill;
|
|
102
|
+
return `Kill ${formatText(killObjective.creatureKeys.join(', '))}: ${
|
|
103
|
+
killObjective.killCount
|
|
104
|
+
}/${killObjective.killCountTarget}`;
|
|
105
|
+
} else if ('targetNPCkey' in objective) {
|
|
106
|
+
// This is an IQuestObjectiveInteraction
|
|
107
|
+
const interactionObjective = objective as IQuestObjectiveInteraction;
|
|
108
|
+
return `Interact with NPC: ${formatText(
|
|
109
|
+
interactionObjective.targetNPCkey ?? 'Unknown'
|
|
110
|
+
)}`;
|
|
111
|
+
} else {
|
|
112
|
+
return 'Unknown objective';
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
.join('; ');
|
|
116
|
+
};
|
|
61
117
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
118
|
+
// Other helper functions remain the same
|
|
119
|
+
const formatRewards = (rewards: IQuest['rewards']) => {
|
|
120
|
+
return rewards
|
|
121
|
+
.map(reward => {
|
|
122
|
+
return `${formatText(
|
|
123
|
+
reward.itemKeys.map(itemKey => itemKey + ' x' + reward.qty).join(', ')
|
|
124
|
+
)}${
|
|
125
|
+
reward.spellKeys
|
|
126
|
+
? `, Spells: ${formatText(reward.spellKeys.join(', '))}`
|
|
127
|
+
: ''
|
|
128
|
+
}`;
|
|
129
|
+
})
|
|
130
|
+
.join('; ');
|
|
131
|
+
};
|
|
68
132
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
133
|
+
const formatText = (text: string) => {
|
|
134
|
+
return text
|
|
135
|
+
.split('-')
|
|
136
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
|
137
|
+
.join(' ');
|
|
138
|
+
};
|
|
73
139
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
140
|
+
const getStatusColor = (status?: QuestStatus) => {
|
|
141
|
+
switch (status) {
|
|
142
|
+
case QuestStatus.Pending:
|
|
143
|
+
return uiColors.orange; // Orange
|
|
144
|
+
case QuestStatus.InProgress:
|
|
145
|
+
return uiColors.blue; // Deep Sky Blue
|
|
146
|
+
case QuestStatus.Completed:
|
|
147
|
+
return uiColors.lightGreen; // Lime Green
|
|
148
|
+
default:
|
|
149
|
+
return uiColors.white; // Default to white
|
|
77
150
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const Title = styled.h1`
|
|
81
|
-
z-index: 22;
|
|
82
|
-
font-size: ${uiFonts.size.medium} !important;
|
|
83
|
-
color: yellow !important;
|
|
84
|
-
`;
|
|
151
|
+
};
|
|
85
152
|
|
|
153
|
+
// Styled components
|
|
86
154
|
const QuestListContainer = styled.div`
|
|
87
155
|
margin-top: 20px;
|
|
88
156
|
margin-bottom: 40px;
|
|
89
157
|
overflow-y: auto;
|
|
90
158
|
max-height: 400px;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
.quest-number {
|
|
99
|
-
border-radius: 50%;
|
|
100
|
-
width: 28px;
|
|
101
|
-
height: 28px;
|
|
102
|
-
display: flex;
|
|
103
|
-
align-items: center;
|
|
104
|
-
justify-content: center;
|
|
105
|
-
margin-right: 16px;
|
|
106
|
-
background-color: brown;
|
|
107
|
-
flex-shrink: 0;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.quest-number.completed {
|
|
111
|
-
background-color: yellow;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
p {
|
|
115
|
-
margin: 0;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.quest-detail__title {
|
|
119
|
-
color: yellow;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
.quest-detail__description {
|
|
123
|
-
margin-top: 5px;
|
|
124
|
-
}
|
|
125
|
-
.Noquest-detail__description {
|
|
126
|
-
margin-top: 5px;
|
|
127
|
-
margin: auto;
|
|
128
|
-
}
|
|
159
|
+
background-color: ${uiColors.darkGray};
|
|
160
|
+
padding: 20px;
|
|
161
|
+
border-radius: 10px;
|
|
162
|
+
border: 1px solid ${uiColors.gray};
|
|
163
|
+
font-size: 0.7rem;
|
|
129
164
|
`;
|
|
165
|
+
|
|
130
166
|
const NoQuestContainer = styled.div`
|
|
131
167
|
text-align: center;
|
|
132
168
|
p {
|
|
133
169
|
margin-top: 5px;
|
|
170
|
+
color: ${uiColors.lightGray};
|
|
134
171
|
}
|
|
135
172
|
`;
|