@pioneer-platform/pioneer-react 0.0.2 → 0.2.32
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 +24 -0
- package/.github/workflows/release.yml +22 -0
- package/.github/workflows/update-license.yml +11 -0
- package/.lintstagedrc.json +6 -0
- package/.prettierrc +7 -0
- package/.vscode/extensions.json +8 -0
- package/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +40 -0
- package/commitlint.config.js +3 -0
- package/dist/assets/404 Error-rafiki.svg +1 -0
- package/dist/assets/Building blocks-amico.svg +1 -0
- package/dist/assets/chakra-ui-logomark-colored.svg +10 -0
- package/dist/assets/favicon.svg +0 -0
- package/dist/assets/react-icon.svg +7 -0
- package/dist/assets/ts-logo-512.svg +1 -0
- package/dist/assets/vite-logo.svg +15 -0
- package/dist/index.js +384249 -0
- package/dist/index_3bde86fb.js +205 -0
- package/dist/index_49fce0b0.js +384033 -0
- package/dist/index_d01e819c.css +63 -0
- package/dist/manifest.json +12 -0
- package/dist/robots.txt +6 -0
- package/index.html +13 -0
- package/netlify.toml +10 -0
- package/package.json +70 -10
- package/public/assets/404 Error-rafiki.svg +1 -0
- package/public/assets/Building blocks-amico.svg +1 -0
- package/public/assets/chakra-ui-logomark-colored.svg +10 -0
- package/public/assets/favicon.svg +0 -0
- package/public/assets/react-icon.svg +7 -0
- package/public/assets/ts-logo-512.svg +1 -0
- package/public/assets/vite-logo.svg +15 -0
- package/public/manifest.json +12 -0
- package/public/robots.txt +6 -0
- package/renovate.json +11 -0
- package/src/App.tsx +21 -0
- package/src/index.tsx +41 -0
- package/src/lib/assets/Icons/KeepKeyIcon.tsx +13 -0
- package/src/lib/assets/Icons/KeplrIcon.tsx +140 -0
- package/src/lib/assets/Icons/MetaMaskIcon.tsx +126 -0
- package/src/lib/assets/Icons/TallyHoIcon.tsx +17 -0
- package/src/lib/assets/Icons/XDEFIIcon.tsx +32 -0
- package/src/lib/assets/favicon.ico +0 -0
- package/src/lib/assets/png/keepkey.png +0 -0
- package/src/lib/assets/png/keplr.png +0 -0
- package/src/lib/assets/png/metamask.png +0 -0
- package/src/lib/assets/png/pioneer.png +0 -0
- package/src/lib/components/AssetSelect/index.tsx +166 -0
- package/src/lib/components/BlockchainSelect/index.tsx +166 -0
- package/src/lib/components/MiddleEllipsis/index.tsx +27 -0
- package/src/lib/components/WalletSelect/index.tsx +112 -0
- package/src/lib/components/auth/RequireAuth.tsx +22 -0
- package/src/lib/components/modals/AssetModal.tsx +67 -0
- package/src/lib/components/modals/SettingsModal.tsx +76 -0
- package/src/lib/components/pioneer/Pioneer/Balances.tsx +266 -0
- package/src/lib/components/pioneer/Pioneer/MiddleEllipsis.tsx +27 -0
- package/src/lib/components/pioneer/Pioneer/Nodes.tsx +0 -0
- package/src/lib/components/pioneer/Pioneer/Paths.tsx +290 -0
- package/src/lib/components/pioneer/Pioneer/Pubkey.tsx +67 -0
- package/src/lib/components/pioneer/Pioneer/Pubkeys.tsx +265 -0
- package/src/lib/components/pioneer/Pioneer/Receive.tsx +26 -0
- package/src/lib/components/pioneer/Pioneer/Send.tsx +135 -0
- package/src/lib/components/pioneer/Pioneer/View.tsx +44 -0
- package/src/lib/components/pioneer/Pioneer/Wallets.tsx +166 -0
- package/src/lib/components/pioneer/index.tsx +525 -0
- package/src/lib/components/utils/index.tsx +47 -0
- package/src/lib/context/Pioneer/index.tsx +420 -0
- package/src/lib/layout/Footer.tsx +22 -0
- package/src/lib/layout/Header.tsx +38 -0
- package/src/lib/layout/Meta.tsx +25 -0
- package/src/lib/layout/Pioneer/Balances.tsx +290 -0
- package/src/lib/layout/Pioneer/MiddleEllipsis.tsx +27 -0
- package/src/lib/layout/Pioneer/Pubkey.tsx +67 -0
- package/src/lib/layout/Pioneer/Receive.tsx +26 -0
- package/src/lib/layout/Pioneer/Send.tsx +135 -0
- package/src/lib/layout/Pioneer/View.tsx +44 -0
- package/src/lib/layout/Pioneer/Wallets.tsx +166 -0
- package/src/lib/layout/ThemeToggle.tsx +16 -0
- package/src/lib/layout/index.tsx +29 -0
- package/src/lib/pages/404/index.tsx +36 -0
- package/src/lib/pages/home/components/CTASection.tsx +36 -0
- package/src/lib/pages/home/components/SomeImage.tsx +36 -0
- package/src/lib/pages/home/components/SomeText.tsx +16 -0
- package/src/lib/pages/home/index.tsx +87 -0
- package/src/lib/router/Routings.tsx +45 -0
- package/src/lib/router/routes.tsx +13 -0
- package/src/lib/styles/theme/config.ts +5 -0
- package/src/lib/styles/theme/index.ts +17 -0
- package/tsconfig.json +19 -9
- package/turbo.json +17 -0
- package/vercel.json +4 -0
- package/vite.config.ts +110 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { Search2Icon } from "@chakra-ui/icons";
|
|
2
|
+
import {
|
|
3
|
+
Avatar,
|
|
4
|
+
AvatarBadge,
|
|
5
|
+
Box,
|
|
6
|
+
Button,
|
|
7
|
+
HStack,
|
|
8
|
+
Stack,
|
|
9
|
+
Image,
|
|
10
|
+
Modal,
|
|
11
|
+
ModalOverlay,
|
|
12
|
+
ModalContent,
|
|
13
|
+
ModalHeader,
|
|
14
|
+
ModalCloseButton,
|
|
15
|
+
ModalBody,
|
|
16
|
+
ModalFooter,
|
|
17
|
+
useDisclosure,
|
|
18
|
+
InputGroup,
|
|
19
|
+
InputLeftElement,
|
|
20
|
+
Input,
|
|
21
|
+
} from "@chakra-ui/react";
|
|
22
|
+
import React, { useState, useEffect } from "react";
|
|
23
|
+
|
|
24
|
+
//@ts-ignore
|
|
25
|
+
import KEEPKEY_ICON from "lib/assets/png/keepkey.png";
|
|
26
|
+
//@ts-ignore
|
|
27
|
+
import METAMASK_ICON from "lib/assets/png/metamask.png";
|
|
28
|
+
//@ts-ignore
|
|
29
|
+
import PIONEER_ICON from "lib/assets/png/pioneer.png";
|
|
30
|
+
import { usePioneer } from "lib/context/Pioneer";
|
|
31
|
+
|
|
32
|
+
import Receive from "./Receive";
|
|
33
|
+
import Send from "./Send";
|
|
34
|
+
import View from "./View";
|
|
35
|
+
|
|
36
|
+
// Import icons
|
|
37
|
+
// @ts-ignore
|
|
38
|
+
// @ts-ignore
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
|
|
41
|
+
interface Balance {
|
|
42
|
+
image?: string;
|
|
43
|
+
symbol: string;
|
|
44
|
+
name?: string;
|
|
45
|
+
balance?: any;
|
|
46
|
+
size?: string;
|
|
47
|
+
context?: string; // Added context field
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const getWalletType = (user: { walletDescriptions: any[] }, context: any) => {
|
|
51
|
+
if (user && user.walletDescriptions) {
|
|
52
|
+
const wallet = user.walletDescriptions.find((w) => w.id === context);
|
|
53
|
+
return wallet ? wallet.type : null;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const getWalletBadgeContent = (walletType: string) => {
|
|
59
|
+
const icons: any = {
|
|
60
|
+
metamask: METAMASK_ICON,
|
|
61
|
+
keepkey: KEEPKEY_ICON,
|
|
62
|
+
native: PIONEER_ICON,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const icon = icons[walletType];
|
|
66
|
+
|
|
67
|
+
if (!icon) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<AvatarBadge boxSize="1.25em" bg="green.500">
|
|
73
|
+
<Image rounded="full" src={icon} />
|
|
74
|
+
</AvatarBadge>
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export default function Balances({ balances }: { balances: Balance[] }) {
|
|
79
|
+
const { state, dispatch } = usePioneer();
|
|
80
|
+
const { user } = state;
|
|
81
|
+
const [currentPage, setCurrentPage] = useState(1);
|
|
82
|
+
const [selectedBalance, setSelectedBalance] = useState<Balance | null>(null);
|
|
83
|
+
const [selectedAction, setSelectedAction] = useState<string | null>(null);
|
|
84
|
+
const { isOpen, onOpen, onClose } = useDisclosure();
|
|
85
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
86
|
+
const balancesPerPage = 3;
|
|
87
|
+
|
|
88
|
+
const handlePageChange = (pageNumber: any) => {
|
|
89
|
+
setCurrentPage(pageNumber);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const handleSendClick = (balance: Balance) => {
|
|
93
|
+
setSelectedBalance(balance);
|
|
94
|
+
setSelectedAction("send");
|
|
95
|
+
onOpen();
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const handleReceiveClick = (balance: Balance) => {
|
|
99
|
+
setSelectedBalance(balance);
|
|
100
|
+
setSelectedAction("receive");
|
|
101
|
+
onOpen();
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const handleViewClick = (balance: Balance) => {
|
|
105
|
+
setSelectedBalance(balance);
|
|
106
|
+
setSelectedAction("view");
|
|
107
|
+
onOpen();
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
const setUser = async () => {
|
|
112
|
+
try {
|
|
113
|
+
if (user && user.wallets) {
|
|
114
|
+
const { walletDescriptions, balances } = user;
|
|
115
|
+
// console.log("walletDescriptions: ", walletDescriptions);
|
|
116
|
+
const updatedBalances = balances.map((balance: Balance) => {
|
|
117
|
+
const walletType = getWalletType(user, balance.context);
|
|
118
|
+
const badgeContent = getWalletBadgeContent(walletType);
|
|
119
|
+
// @ts-ignore
|
|
120
|
+
return {
|
|
121
|
+
...balance,
|
|
122
|
+
context: {
|
|
123
|
+
// @ts-ignore
|
|
124
|
+
...balance.context,
|
|
125
|
+
badge: badgeContent,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
dispatch({ type: "SET_BALANCES", payload: updatedBalances });
|
|
130
|
+
}
|
|
131
|
+
} catch (e) {
|
|
132
|
+
console.error("Error: ", e);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
setUser();
|
|
137
|
+
}, [user]);
|
|
138
|
+
|
|
139
|
+
// Filter and sort balances based on search query
|
|
140
|
+
const filteredBalances = balances.filter((balance: Balance) => {
|
|
141
|
+
// Convert the search query and balance symbol/name to lowercase for case-insensitive search
|
|
142
|
+
const query = searchQuery.toLowerCase();
|
|
143
|
+
const symbol = balance.symbol.toLowerCase();
|
|
144
|
+
const name = balance.name ? balance.name.toLowerCase() : "";
|
|
145
|
+
|
|
146
|
+
// Check if the symbol or name contains the search query
|
|
147
|
+
return symbol.includes(query) || name.includes(query);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const sortedBalances = filteredBalances.sort(
|
|
151
|
+
(a: Balance, b: Balance) => b.balance - a.balance
|
|
152
|
+
);
|
|
153
|
+
const currentBalances = sortedBalances.slice(
|
|
154
|
+
(currentPage - 1) * balancesPerPage,
|
|
155
|
+
currentPage * balancesPerPage
|
|
156
|
+
);
|
|
157
|
+
const totalPages = Math.ceil(filteredBalances.length / balancesPerPage);
|
|
158
|
+
|
|
159
|
+
// Function to generate custom pagination array
|
|
160
|
+
const generatePaginationArray = () => {
|
|
161
|
+
const paginationArray = [];
|
|
162
|
+
const totalPageButtons = 5; // Number of page buttons to display around the current page
|
|
163
|
+
|
|
164
|
+
if (totalPages <= totalPageButtons) {
|
|
165
|
+
// If total pages are less than or equal to totalPageButtons, show all page numbers
|
|
166
|
+
for (let i = 1; i <= totalPages; i++) {
|
|
167
|
+
paginationArray.push(i);
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
// If total pages are more than totalPageButtons, generate custom pagination
|
|
171
|
+
const middleButton = Math.floor(totalPageButtons / 2);
|
|
172
|
+
const startPage = Math.max(currentPage - middleButton, 1);
|
|
173
|
+
const endPage = Math.min(currentPage + middleButton, totalPages);
|
|
174
|
+
|
|
175
|
+
if (startPage > 1) {
|
|
176
|
+
// Add the first page and ellipsis if the current page is far enough from the first page
|
|
177
|
+
paginationArray.push(1, "...");
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Add page numbers between startPage and endPage (inclusive)
|
|
181
|
+
for (let i = startPage; i <= endPage; i++) {
|
|
182
|
+
paginationArray.push(i);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (endPage < totalPages) {
|
|
186
|
+
// Add the last page and ellipsis if the current page is far enough from the last page
|
|
187
|
+
paginationArray.push("...", totalPages);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return paginationArray;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<Stack spacing={4}>
|
|
196
|
+
<InputGroup>
|
|
197
|
+
<InputLeftElement pointerEvents="none">
|
|
198
|
+
<Search2Icon color="gray.300" />
|
|
199
|
+
</InputLeftElement>
|
|
200
|
+
<Input
|
|
201
|
+
placeholder="Bitcoin..."
|
|
202
|
+
type="text"
|
|
203
|
+
value={searchQuery}
|
|
204
|
+
onChange={(e) => setSearchQuery(e.target.value)}
|
|
205
|
+
/>
|
|
206
|
+
</InputGroup>
|
|
207
|
+
{currentBalances.map((balance: Balance, index: number) => (
|
|
208
|
+
<Box key={index}>
|
|
209
|
+
<HStack spacing={4} alignItems="center">
|
|
210
|
+
<Avatar src={balance.image} />
|
|
211
|
+
<Box>
|
|
212
|
+
<small>asset: {balance.symbol}</small>
|
|
213
|
+
<br />
|
|
214
|
+
<small>balance: {balance.balance}</small>
|
|
215
|
+
</Box>
|
|
216
|
+
</HStack>
|
|
217
|
+
<HStack mt={2} spacing={2}>
|
|
218
|
+
<Button
|
|
219
|
+
size="sm"
|
|
220
|
+
variant="outline"
|
|
221
|
+
onClick={() => handleSendClick(balance)}
|
|
222
|
+
>
|
|
223
|
+
Send
|
|
224
|
+
</Button>
|
|
225
|
+
<Button
|
|
226
|
+
size="sm"
|
|
227
|
+
variant="outline"
|
|
228
|
+
onClick={() => handleReceiveClick(balance)}
|
|
229
|
+
>
|
|
230
|
+
Receive
|
|
231
|
+
</Button>
|
|
232
|
+
<Button
|
|
233
|
+
size="sm"
|
|
234
|
+
variant="outline"
|
|
235
|
+
onClick={() => handleViewClick(balance)}
|
|
236
|
+
>
|
|
237
|
+
View
|
|
238
|
+
</Button>
|
|
239
|
+
</HStack>
|
|
240
|
+
</Box>
|
|
241
|
+
))}
|
|
242
|
+
<Box mt={4}>
|
|
243
|
+
{generatePaginationArray().map((page, index) => (
|
|
244
|
+
<Button
|
|
245
|
+
key={index}
|
|
246
|
+
size="sm"
|
|
247
|
+
variant={currentPage === page ? "solid" : "outline"}
|
|
248
|
+
onClick={() => handlePageChange(page)}
|
|
249
|
+
>
|
|
250
|
+
{page === "..." ? "..." : page}
|
|
251
|
+
</Button>
|
|
252
|
+
))}
|
|
253
|
+
</Box>
|
|
254
|
+
|
|
255
|
+
<Modal isOpen={isOpen} onClose={onClose} isCentered blockScrollOnMount>
|
|
256
|
+
<ModalOverlay />
|
|
257
|
+
<ModalContent>
|
|
258
|
+
<ModalHeader>{selectedAction}</ModalHeader>
|
|
259
|
+
<ModalCloseButton />
|
|
260
|
+
{selectedAction === "send" && (
|
|
261
|
+
<div>
|
|
262
|
+
<h3>Selected Action: Send</h3>
|
|
263
|
+
<p>Selected Asset: {selectedBalance?.symbol}</p>
|
|
264
|
+
<Send asset={selectedBalance} />
|
|
265
|
+
</div>
|
|
266
|
+
)}
|
|
267
|
+
{selectedAction === "receive" && (
|
|
268
|
+
<div>
|
|
269
|
+
<h3>Selected Action: Receive</h3>
|
|
270
|
+
<p>Selected Asset: {selectedBalance?.symbol}</p>
|
|
271
|
+
<Receive />
|
|
272
|
+
</div>
|
|
273
|
+
)}
|
|
274
|
+
{selectedAction === "view" && (
|
|
275
|
+
<div>
|
|
276
|
+
<h3>Selected Action: View</h3>
|
|
277
|
+
<p>Selected Asset: {selectedBalance?.symbol}</p>
|
|
278
|
+
<View />
|
|
279
|
+
</div>
|
|
280
|
+
)}
|
|
281
|
+
<ModalFooter>
|
|
282
|
+
<Button colorScheme="blue" onClick={onClose}>
|
|
283
|
+
Cancel
|
|
284
|
+
</Button>
|
|
285
|
+
</ModalFooter>
|
|
286
|
+
</ModalContent>
|
|
287
|
+
</Modal>
|
|
288
|
+
</Stack>
|
|
289
|
+
);
|
|
290
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type React from "react";
|
|
2
|
+
|
|
3
|
+
interface MiddleEllipsisProps {
|
|
4
|
+
text: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const MiddleEllipsis: React.FC<MiddleEllipsisProps> = ({ text }) => {
|
|
8
|
+
const maxLength = 20;
|
|
9
|
+
const ellipsis = "...";
|
|
10
|
+
|
|
11
|
+
if (!text || text.length <= maxLength) {
|
|
12
|
+
return <span>{text}</span>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const frontPart = text.slice(0, 7);
|
|
16
|
+
const backPart = text.slice(-10);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<span>
|
|
20
|
+
{frontPart}
|
|
21
|
+
{ellipsis}
|
|
22
|
+
{backPart}
|
|
23
|
+
</span>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export default MiddleEllipsis;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
chakra,
|
|
3
|
+
Stack,
|
|
4
|
+
CircularProgress,
|
|
5
|
+
Drawer,
|
|
6
|
+
DrawerOverlay,
|
|
7
|
+
DrawerContent,
|
|
8
|
+
DrawerHeader,
|
|
9
|
+
DrawerBody,
|
|
10
|
+
Tabs,
|
|
11
|
+
TabList,
|
|
12
|
+
TabPanels,
|
|
13
|
+
Tab,
|
|
14
|
+
TabPanel,
|
|
15
|
+
Avatar,
|
|
16
|
+
AvatarBadge,
|
|
17
|
+
Box,
|
|
18
|
+
Button,
|
|
19
|
+
Flex,
|
|
20
|
+
HStack,
|
|
21
|
+
IconButton,
|
|
22
|
+
Link,
|
|
23
|
+
Menu,
|
|
24
|
+
Image,
|
|
25
|
+
MenuButton,
|
|
26
|
+
MenuDivider,
|
|
27
|
+
Icon,
|
|
28
|
+
MenuItem,
|
|
29
|
+
MenuList,
|
|
30
|
+
Spacer,
|
|
31
|
+
Text,
|
|
32
|
+
useDisclosure,
|
|
33
|
+
Accordion,
|
|
34
|
+
AccordionItem,
|
|
35
|
+
AccordionButton,
|
|
36
|
+
AccordionIcon,
|
|
37
|
+
AccordionPanel,
|
|
38
|
+
SimpleGrid,
|
|
39
|
+
Card,
|
|
40
|
+
CardHeader,
|
|
41
|
+
Heading,
|
|
42
|
+
CardBody,
|
|
43
|
+
CardFooter,
|
|
44
|
+
Modal,
|
|
45
|
+
ModalOverlay,
|
|
46
|
+
ModalContent,
|
|
47
|
+
ModalHeader,
|
|
48
|
+
ModalCloseButton,
|
|
49
|
+
ModalBody,
|
|
50
|
+
ModalFooter,
|
|
51
|
+
} from "@chakra-ui/react";
|
|
52
|
+
import React, { useState } from "react";
|
|
53
|
+
|
|
54
|
+
import MiddleEllipsis from "./MiddleEllipsis";
|
|
55
|
+
|
|
56
|
+
interface Balance {
|
|
57
|
+
rating: number;
|
|
58
|
+
setRating: (rating: number) => void;
|
|
59
|
+
count?: number;
|
|
60
|
+
size?: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export default function Pubkey(Balance: any) {
|
|
64
|
+
const [hover, setHover] = useState<number | null>(null);
|
|
65
|
+
|
|
66
|
+
return <div>{JSON.stringify(Balance)}</div>;
|
|
67
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { FormControl, FormLabel, Input, Text } from "@chakra-ui/react";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import QRCode from "react-qr-code";
|
|
4
|
+
|
|
5
|
+
const Receive = () => {
|
|
6
|
+
const [address, setAddress] = useState("");
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<>
|
|
10
|
+
<FormControl>
|
|
11
|
+
<FormLabel>Address:</FormLabel>
|
|
12
|
+
<Input value={address} onChange={(e) => setAddress(e.target.value)} />
|
|
13
|
+
</FormControl>
|
|
14
|
+
|
|
15
|
+
{address && (
|
|
16
|
+
<>
|
|
17
|
+
<Text mt={4}>QR Code:</Text>
|
|
18
|
+
<QRCode value={address} size={128} />
|
|
19
|
+
<Text mt={2}>{address}</Text>
|
|
20
|
+
</>
|
|
21
|
+
)}
|
|
22
|
+
</>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export default Receive;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Card,
|
|
3
|
+
Button,
|
|
4
|
+
FormControl,
|
|
5
|
+
FormLabel,
|
|
6
|
+
Input,
|
|
7
|
+
Spinner,
|
|
8
|
+
Avatar,
|
|
9
|
+
} from "@chakra-ui/react";
|
|
10
|
+
import React, { useState, useEffect } from "react";
|
|
11
|
+
|
|
12
|
+
import { usePioneer } from "lib/context/Pioneer";
|
|
13
|
+
|
|
14
|
+
const Send = (Asset: any) => {
|
|
15
|
+
const { state, dispatch } = usePioneer();
|
|
16
|
+
const { user, app, api, wallet } = state;
|
|
17
|
+
const [amount, setAmount] = useState("");
|
|
18
|
+
const [address, setAddress] = useState("");
|
|
19
|
+
const [balance, setBalance] = useState("");
|
|
20
|
+
const [blockchain, setBlockchain] = useState("");
|
|
21
|
+
const [caip, setCaip] = useState(null);
|
|
22
|
+
const [txid, setTxid] = useState(null);
|
|
23
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
24
|
+
|
|
25
|
+
const handleSend = async () => {
|
|
26
|
+
try {
|
|
27
|
+
setIsLoading(true);
|
|
28
|
+
//console.log("Asset: ", Asset.asset);
|
|
29
|
+
//console.log("Address: ", address);
|
|
30
|
+
//console.log("amount: ", amount);
|
|
31
|
+
const ASSET = Asset.asset.symbol;
|
|
32
|
+
if (!address) alert("Must set an address!");
|
|
33
|
+
if (!amount) alert("Must set an amount!");
|
|
34
|
+
const send: any = {
|
|
35
|
+
blockchain,
|
|
36
|
+
network: Asset.asset.network,
|
|
37
|
+
asset: Asset.asset.symbol,
|
|
38
|
+
balance: Asset.asset.balance,
|
|
39
|
+
address,
|
|
40
|
+
amount,
|
|
41
|
+
noBroadcast: false,
|
|
42
|
+
};
|
|
43
|
+
if (Asset.asset.contract) send.contract = Asset.asset.contract;
|
|
44
|
+
const tx = {
|
|
45
|
+
type: "sendToAddress",
|
|
46
|
+
payload: send,
|
|
47
|
+
};
|
|
48
|
+
// console.log("tx: ", tx);
|
|
49
|
+
let invocation = await app.build(tx);
|
|
50
|
+
// console.log("invocation: ", invocation);
|
|
51
|
+
// sign
|
|
52
|
+
invocation = await app.sign(invocation, wallet);
|
|
53
|
+
// console.log("invocation: ", invocation);
|
|
54
|
+
invocation.network = ASSET; // TODO dont do this bullshit, use caip
|
|
55
|
+
invocation.noBroadcast = false;
|
|
56
|
+
invocation.sync = true;
|
|
57
|
+
invocation = await app.broadcast(invocation);
|
|
58
|
+
// console.log("invocation: ", invocation);
|
|
59
|
+
if (invocation && invocation.broadcast && invocation.broadcast.txid) {
|
|
60
|
+
setIsLoading(false);
|
|
61
|
+
setTxid(invocation.broadcast.txid);
|
|
62
|
+
// TODO open block explorer link
|
|
63
|
+
// window.open('https://example.com', '_blank'); // Open link in a new tab
|
|
64
|
+
}
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(error);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// onStart get balance of asset
|
|
71
|
+
// get max amount able to send
|
|
72
|
+
const onStart = async () => {
|
|
73
|
+
try {
|
|
74
|
+
// console.log("Asset: ", Asset.asset.caip);
|
|
75
|
+
// console.log("Asset: ", Asset.asset);
|
|
76
|
+
setCaip(Asset.asset.caip);
|
|
77
|
+
setBalance(Asset.asset.balance);
|
|
78
|
+
|
|
79
|
+
// get asset by caip
|
|
80
|
+
const asset = await api.AssetByCaip({ caip: Asset.asset.caip });
|
|
81
|
+
// console.log("asset: ",asset.data)
|
|
82
|
+
// console.log("asset: ",asset.data[0].blockchain)
|
|
83
|
+
setBlockchain(asset.data[0].blockchain);
|
|
84
|
+
// @ts-ignore
|
|
85
|
+
if (!asset.data[0].blockchain)
|
|
86
|
+
alert(`unknown asset! ciap: ${Asset.asset.caip}`);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.error(error);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
useEffect(() => {
|
|
93
|
+
onStart(); // Call the onStart function when the component mounts
|
|
94
|
+
}, []);
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<Card>
|
|
98
|
+
<h2>Balance: {balance}</h2>
|
|
99
|
+
<Avatar src={Asset.asset.image} />
|
|
100
|
+
<small>caip: {caip}</small>
|
|
101
|
+
<br />
|
|
102
|
+
{txid ? (
|
|
103
|
+
<div>
|
|
104
|
+
txid: <small> {txid} </small>
|
|
105
|
+
<Button>view on block explorer</Button>
|
|
106
|
+
</div>
|
|
107
|
+
) : (
|
|
108
|
+
<div>
|
|
109
|
+
<FormControl>
|
|
110
|
+
<FormLabel>Amount:</FormLabel>
|
|
111
|
+
<Input
|
|
112
|
+
type="number"
|
|
113
|
+
value={amount}
|
|
114
|
+
onChange={(e) => setAmount(e.target.value)}
|
|
115
|
+
/>
|
|
116
|
+
</FormControl>
|
|
117
|
+
|
|
118
|
+
<FormControl mt={4}>
|
|
119
|
+
<FormLabel>Address:</FormLabel>
|
|
120
|
+
<Input
|
|
121
|
+
value={address}
|
|
122
|
+
onChange={(e) => setAddress(e.target.value)}
|
|
123
|
+
/>
|
|
124
|
+
</FormControl>
|
|
125
|
+
|
|
126
|
+
<Button mt={4} colorScheme="blue" onClick={handleSend}>
|
|
127
|
+
{isLoading ? <Spinner /> : "Send"}
|
|
128
|
+
</Button>
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
131
|
+
</Card>
|
|
132
|
+
);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export default Send;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { List, ListItem, Text } from "@chakra-ui/react";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
const View = () => {
|
|
5
|
+
// Mocked transaction history data
|
|
6
|
+
const transactions = [
|
|
7
|
+
{
|
|
8
|
+
id: 1,
|
|
9
|
+
date: "2023-07-01",
|
|
10
|
+
amount: "0.5 BTC",
|
|
11
|
+
sender: "Sender A",
|
|
12
|
+
receiver: "Receiver B",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 2,
|
|
16
|
+
date: "2023-07-02",
|
|
17
|
+
amount: "1 ETH",
|
|
18
|
+
sender: "Sender C",
|
|
19
|
+
receiver: "Receiver D",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: 3,
|
|
23
|
+
date: "2023-07-03",
|
|
24
|
+
amount: "0.2 LTC",
|
|
25
|
+
sender: "Sender E",
|
|
26
|
+
receiver: "Receiver F",
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<List spacing={4}>
|
|
32
|
+
{transactions.map((transaction) => (
|
|
33
|
+
<ListItem key={transaction.id}>
|
|
34
|
+
<Text>Date: {transaction.date}</Text>
|
|
35
|
+
<Text>Amount: {transaction.amount}</Text>
|
|
36
|
+
<Text>Sender: {transaction.sender}</Text>
|
|
37
|
+
<Text>Receiver: {transaction.receiver}</Text>
|
|
38
|
+
</ListItem>
|
|
39
|
+
))}
|
|
40
|
+
</List>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export default View;
|