mirror of
https://github.com/Qortal/q-shop.git
synced 2025-01-30 06:42:21 +00:00
added multi-publish
This commit is contained in:
parent
6131c89f7c
commit
f8c678b740
23
src/assets/svgs/CircleSVG.tsx
Normal file
23
src/assets/svgs/CircleSVG.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { IconTypes } from "./IconTypes";
|
||||
|
||||
export const CircleSVG: React.FC<IconTypes> = ({
|
||||
color,
|
||||
height,
|
||||
width,
|
||||
className,
|
||||
onClickFunc,
|
||||
}) => {
|
||||
return (
|
||||
<svg
|
||||
onClick={onClickFunc}
|
||||
className={className}
|
||||
fill={color}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
height={height}
|
||||
viewBox="0 -960 960 960"
|
||||
width={width}
|
||||
>
|
||||
<path d="m424-296 282-282-56-56-226 226-114-114-56 56 170 170Zm56 216q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z" />
|
||||
</svg>
|
||||
);
|
||||
};
|
23
src/assets/svgs/EmptyCircleSVG.tsx
Normal file
23
src/assets/svgs/EmptyCircleSVG.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { IconTypes } from "./IconTypes";
|
||||
|
||||
export const EmptyCircleSVG: React.FC<IconTypes> = ({
|
||||
color,
|
||||
height,
|
||||
width,
|
||||
className,
|
||||
onClickFunc,
|
||||
}) => {
|
||||
return (
|
||||
|
||||
<svg onClick={onClickFunc}
|
||||
className={className}
|
||||
fill={color}
|
||||
|
||||
height={height}
|
||||
|
||||
width={width} xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" ><path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
214
src/components/common/MultiplePublish/MultiplePublish.tsx
Normal file
214
src/components/common/MultiplePublish/MultiplePublish.tsx
Normal file
@ -0,0 +1,214 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
CircularProgress,
|
||||
Modal,
|
||||
Typography,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import React, { useCallback, useEffect, useState, useRef } from "react";
|
||||
import { CircleSVG } from "../../../assets/svgs/CircleSVG";
|
||||
import { EmptyCircleSVG } from "../../../assets/svgs/EmptyCircleSVG";
|
||||
import { styled } from "@mui/system";
|
||||
|
||||
interface Publish {
|
||||
resources: any[];
|
||||
action: string;
|
||||
}
|
||||
|
||||
interface MultiplePublishProps {
|
||||
publishes: Publish;
|
||||
isOpen: boolean;
|
||||
onSubmit: ()=> void
|
||||
onError: (message?: string)=> void
|
||||
}
|
||||
export const MultiplePublish = ({ publishes, isOpen, onSubmit, onError}: MultiplePublishProps) => {
|
||||
const theme = useTheme();
|
||||
const listOfSuccessfulPublishesRef = useRef([])
|
||||
const [listOfSuccessfulPublishes, setListOfSuccessfulPublishes] = useState<
|
||||
any[]
|
||||
>([]);
|
||||
const [listOfUnsuccessfulPublishes, setListOfUnSuccessfulPublishes] = useState<
|
||||
any[]
|
||||
>([]);
|
||||
const [currentlyInPublish, setCurrentlyInPublish] = useState(null);
|
||||
const hasStarted = useRef(false);
|
||||
const publish = useCallback(async (pub: any) => {
|
||||
const lengthOfResources = pub?.resources?.length
|
||||
const lengthOfTimeout = lengthOfResources * 30000
|
||||
return await qortalRequestWithTimeout(pub, lengthOfTimeout);
|
||||
}, []);
|
||||
const [isPublishing, setIsPublishing] = useState(true)
|
||||
|
||||
const handlePublish = useCallback(
|
||||
async (pub: any) => {
|
||||
try {
|
||||
setCurrentlyInPublish(pub?.identifier);
|
||||
setIsPublishing(true)
|
||||
const res = await publish(pub);
|
||||
|
||||
onSubmit()
|
||||
setListOfUnSuccessfulPublishes([])
|
||||
|
||||
} catch (error: any) {
|
||||
const unsuccessfulPublishes = error?.error?.unsuccessfulPublishes || []
|
||||
if(error?.error === 'User declined request'){
|
||||
onError()
|
||||
return
|
||||
}
|
||||
|
||||
if(error?.error === 'The request timed out'){
|
||||
onError("The request timed out")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if(unsuccessfulPublishes?.length > 0){
|
||||
setListOfUnSuccessfulPublishes(unsuccessfulPublishes)
|
||||
|
||||
}
|
||||
} finally {
|
||||
|
||||
setIsPublishing(false)
|
||||
}
|
||||
},
|
||||
[publish]
|
||||
);
|
||||
|
||||
const retry = ()=> {
|
||||
let newlistOfMultiplePublishes: any[] = [];
|
||||
listOfUnsuccessfulPublishes?.forEach((item)=> {
|
||||
const findPub = publishes?.resources.find((res: any)=> res?.identifier === item.identifier)
|
||||
if(findPub){
|
||||
newlistOfMultiplePublishes.push(findPub)
|
||||
}
|
||||
})
|
||||
const multiplePublish = {
|
||||
...publishes,
|
||||
resources: newlistOfMultiplePublishes
|
||||
};
|
||||
handlePublish(multiplePublish)
|
||||
}
|
||||
|
||||
const startPublish = useCallback(
|
||||
async (pubs: any) => {
|
||||
await handlePublish(pubs);
|
||||
},
|
||||
[handlePublish, onSubmit, listOfSuccessfulPublishes, publishes]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (publishes && !hasStarted.current) {
|
||||
hasStarted.current = true;
|
||||
startPublish(publishes);
|
||||
}
|
||||
}, [startPublish, publishes, listOfSuccessfulPublishes]);
|
||||
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={isOpen}
|
||||
aria-labelledby="modal-title"
|
||||
aria-describedby="modal-description"
|
||||
sx={{
|
||||
zIndex: 10001
|
||||
}}
|
||||
>
|
||||
<ModalBody
|
||||
sx={{
|
||||
minHeight: "50vh",
|
||||
}}
|
||||
>
|
||||
{publishes?.resources?.map((publish: any) => {
|
||||
const unpublished = listOfUnsuccessfulPublishes.map(item => item?.identifier)
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography>{publish?.identifier}</Typography>
|
||||
{!isPublishing && hasStarted.current ? (
|
||||
<>
|
||||
{!unpublished.includes(publish.identifier) ? (
|
||||
<CircleSVG
|
||||
color={theme.palette.text.primary}
|
||||
height="24px"
|
||||
width="24px"
|
||||
/>
|
||||
) : (
|
||||
<EmptyCircleSVG
|
||||
color={theme.palette.text.primary}
|
||||
height="24px"
|
||||
width="24px"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
): <CircularProgress size={16} color="secondary"/>}
|
||||
|
||||
</Box>
|
||||
);
|
||||
})}
|
||||
{!isPublishing && listOfUnsuccessfulPublishes.length > 0 && (
|
||||
<>
|
||||
<Typography sx={{
|
||||
marginTop: '20px',
|
||||
fontSize: '16px'
|
||||
}}>Some files were not published. Please try again. It's important that all the files get published. Maybe wait a couple minutes if the error keeps occurring</Typography>
|
||||
<Button variant="contained" onClick={()=> {
|
||||
retry()
|
||||
}}>Try again</Button>
|
||||
</>
|
||||
)}
|
||||
|
||||
</ModalBody>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export const ModalBody = styled(Box)(({ theme }) => ({
|
||||
position: "absolute",
|
||||
backgroundColor: theme.palette.background.default,
|
||||
borderRadius: "4px",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
width: "75%",
|
||||
maxWidth: "900px",
|
||||
padding: "15px 35px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "17px",
|
||||
overflowY: "auto",
|
||||
maxHeight: "95vh",
|
||||
boxShadow:
|
||||
theme.palette.mode === "dark"
|
||||
? "0px 4px 5px 0px hsla(0,0%,0%,0.14), 0px 1px 10px 0px hsla(0,0%,0%,0.12), 0px 2px 4px -1px hsla(0,0%,0%,0.2)"
|
||||
: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px",
|
||||
"&::-webkit-scrollbar-track": {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
"&::-webkit-scrollbar-track:hover": {
|
||||
backgroundColor: theme.palette.background.paper,
|
||||
},
|
||||
"&::-webkit-scrollbar": {
|
||||
width: "16px",
|
||||
height: "10px",
|
||||
backgroundColor: theme.palette.mode === "light" ? "#f6f8fa" : "#292d3e",
|
||||
},
|
||||
"&::-webkit-scrollbar-thumb": {
|
||||
backgroundColor: theme.palette.mode === "light" ? "#d3d9e1" : "#575757",
|
||||
borderRadius: "8px",
|
||||
backgroundClip: "content-box",
|
||||
border: "4px solid transparent",
|
||||
},
|
||||
"&::-webkit-scrollbar-thumb:hover": {
|
||||
backgroundColor: theme.palette.mode === "light" ? "#b7bcc4" : "#474646",
|
||||
},
|
||||
}));
|
46
src/components/common/useModal.tsx
Normal file
46
src/components/common/useModal.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
interface State {
|
||||
isShow: boolean;
|
||||
}
|
||||
export const useModal = () => {
|
||||
const [state, setState] = useState<State>({
|
||||
isShow: false,
|
||||
});
|
||||
const promiseConfig = useRef<any>(null);
|
||||
const show = async () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
promiseConfig.current = {
|
||||
resolve,
|
||||
reject,
|
||||
};
|
||||
setState({
|
||||
isShow: true,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const hide = () => {
|
||||
setState({
|
||||
isShow: false,
|
||||
});
|
||||
};
|
||||
|
||||
const onOk = (payload?:any) => {
|
||||
const { resolve } = promiseConfig.current;
|
||||
hide();
|
||||
resolve(payload);
|
||||
};
|
||||
|
||||
const onCancel = () => {
|
||||
const { reject } = promiseConfig.current;
|
||||
hide();
|
||||
reject();
|
||||
};
|
||||
return {
|
||||
show,
|
||||
onOk,
|
||||
onCancel,
|
||||
isShow: state.isShow
|
||||
};
|
||||
};
|
@ -140,8 +140,9 @@ const MyModal: React.FC<MyModalProps> = ({ open, onClose, onPublish }) => {
|
||||
setLogo(currentStore?.logo || null);
|
||||
setLocation(currentStore?.location || "");
|
||||
setShipsTo(currentStore?.shipsTo || "");
|
||||
setSupportedCoinsSelected(currentStore?.supportedCoins || ["QORT"]);
|
||||
setArrrWalletAddress(currentStore?.foreignCoins?.ARRR || "");
|
||||
const selectedCoinsList = [...new Set([...(currentStore?.supportedCoins || []), 'QORT'])];
|
||||
setSupportedCoinsSelected(selectedCoinsList)
|
||||
setArrrWalletAddress(currentStore?.foreignCoins?.ARRR || "")
|
||||
}
|
||||
}, [currentStore, storeId, open]);
|
||||
|
||||
@ -233,15 +234,12 @@ const MyModal: React.FC<MyModalProps> = ({ open, onClose, onPublish }) => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
navigate("/");
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: "Error when creating the data container. Please try again!",
|
||||
alertType: "error",
|
||||
})
|
||||
);
|
||||
dispatch(updateRecentlyVisitedStoreId(""));
|
||||
dispatch(clearDataCotainer());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -81,6 +81,8 @@ import { AcceptedCoin } from "../StoreList/StoreList-styles";
|
||||
import { ARRRSVG } from "../../assets/svgs/ARRRSVG";
|
||||
import { setPreferredCoin } from "../../state/features/storeSlice";
|
||||
import { CoinFilter } from "../Store/Store/Store";
|
||||
import { useModal } from "../../components/common/useModal";
|
||||
import { MultiplePublish } from "../../components/common/MultiplePublish/MultiplePublish";
|
||||
|
||||
/* Currency must be replaced in the order confirmation email by proper currency */
|
||||
|
||||
@ -92,7 +94,8 @@ interface CountryProps {
|
||||
export const Cart = () => {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
||||
|
||||
const {isShow, onCancel, onOk, show} = useModal()
|
||||
const [publishes, setPublishes] = useState<any>(null);
|
||||
const uid = new ShortUniqueId({
|
||||
length: 10,
|
||||
});
|
||||
@ -754,7 +757,9 @@ export const Cart = () => {
|
||||
encrypt: true,
|
||||
publicKeys: [resAddress.publicKey, usernamePublicKey],
|
||||
};
|
||||
await qortalRequest(multiplePublish);
|
||||
setPublishes(multiplePublish)
|
||||
await show()
|
||||
// await qortalRequest(multiplePublish);
|
||||
// Clear this cart state from global carts redux
|
||||
dispatch(removeCartFromCarts({ storeId }));
|
||||
// Clear cart local state
|
||||
@ -787,6 +792,7 @@ export const Cart = () => {
|
||||
);
|
||||
} finally {
|
||||
dispatch(setIsLoadingGlobal(false));
|
||||
setPublishes(null)
|
||||
}
|
||||
};
|
||||
|
||||
@ -828,6 +834,18 @@ export const Cart = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{isShow && (
|
||||
<MultiplePublish
|
||||
isOpen={isShow}
|
||||
onError={(messageNotification)=> {
|
||||
onCancel()
|
||||
}}
|
||||
onSubmit={() => {
|
||||
onOk()
|
||||
}}
|
||||
publishes={publishes}
|
||||
/>
|
||||
)}
|
||||
<ReusableModal
|
||||
open={isOpen}
|
||||
customStyles={{
|
||||
|
@ -57,10 +57,15 @@ import {
|
||||
STORE_BASE,
|
||||
} from "../../constants/identifiers";
|
||||
import { resetOrders } from "../../state/features/orderSlice";
|
||||
import { useModal } from "../../components/common/useModal";
|
||||
import { MultiplePublish } from "../../components/common/MultiplePublish/MultiplePublish";
|
||||
|
||||
const uid = new ShortUniqueId({ length: 10 });
|
||||
|
||||
export const ProductManager = () => {
|
||||
const {isShow, onCancel, onOk, show} = useModal()
|
||||
const [publishes, setPublishes] = useState<any>(null);
|
||||
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
@ -362,7 +367,9 @@ export const ProductManager = () => {
|
||||
action: "PUBLISH_MULTIPLE_QDN_RESOURCES",
|
||||
resources: [...publishMultipleCatalogues, publishDataContainer],
|
||||
};
|
||||
await qortalRequest(multiplePublish);
|
||||
setPublishes(multiplePublish)
|
||||
await show()
|
||||
// await qortalRequest(multiplePublish);
|
||||
|
||||
// Clear productsToSave from Redux store
|
||||
dispatch(clearAllProductsToSave());
|
||||
@ -431,6 +438,8 @@ export const ProductManager = () => {
|
||||
dispatch(setNotification(notificationObj));
|
||||
|
||||
throw new Error("Failed to send message");
|
||||
} finally {
|
||||
setPublishes(null)
|
||||
}
|
||||
}
|
||||
|
||||
@ -656,6 +665,18 @@ export const ProductManager = () => {
|
||||
|
||||
{/* Confirm Remove Product from productsToSave in global state */}
|
||||
<Modal />
|
||||
{isShow && (
|
||||
<MultiplePublish
|
||||
isOpen={isShow}
|
||||
onError={(messageNotification)=> {
|
||||
onCancel()
|
||||
}}
|
||||
onSubmit={() => {
|
||||
onOk()
|
||||
}}
|
||||
publishes={publishes}
|
||||
/>
|
||||
)}
|
||||
</ProductManagerContainer>
|
||||
);
|
||||
};
|
||||
|
@ -48,6 +48,8 @@ import {
|
||||
import QortalLogo from "../assets/img/Q-AppsLogo.webp";
|
||||
import { DownloadCircleSVG } from "../assets/svgs/DownloadCircleSVG";
|
||||
import { UAParser } from "ua-parser-js";
|
||||
import { useModal } from "../components/common/useModal";
|
||||
import { MultiplePublish } from "../components/common/MultiplePublish/MultiplePublish";
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
@ -65,7 +67,7 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const theme = useTheme();
|
||||
|
||||
const [isCreatingShop, setIsCreatingShop] = useState(false)
|
||||
// Determine which OS they're on
|
||||
const parser = new UAParser();
|
||||
|
||||
@ -109,7 +111,8 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||
useState<boolean>(false);
|
||||
const [retryDataContainer, setRetryDataContainer] = useState<boolean>(false);
|
||||
const [showDownloadModal, setShowDownloadModal] = useState<boolean>(false);
|
||||
|
||||
const {isShow, onCancel, onOk, show} = useModal()
|
||||
const [publishes, setPublishes] = useState<any>(null);
|
||||
useEffect(() => {
|
||||
if (!user?.name) return;
|
||||
|
||||
@ -269,104 +272,7 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handlePublishDataContainer = React.useCallback(async () => {
|
||||
try {
|
||||
const dataContainerToBase64 = await objectToBase64(storedDataContainer);
|
||||
// Publish Data Container to QDN
|
||||
const resourceResponse = await qortalRequest({
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: storedDataContainer?.owner,
|
||||
service: "DOCUMENT",
|
||||
data64: dataContainerToBase64,
|
||||
identifier: `${storedDataContainer?.storeId}-${DATA_CONTAINER_BASE}`,
|
||||
filename: "datacontainer.json",
|
||||
});
|
||||
if (isSuccessful(resourceResponse)) {
|
||||
await new Promise<void>((res, rej) => {
|
||||
setTimeout(() => {
|
||||
res();
|
||||
}, 1000);
|
||||
});
|
||||
dispatch(
|
||||
setDataContainer({
|
||||
...storedDataContainer,
|
||||
id: `${storedDataContainer?.storeId}-${DATA_CONTAINER_BASE}`,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: "Shop successfully created",
|
||||
alertType: "success",
|
||||
})
|
||||
);
|
||||
setCloseCreateStoreModal(true);
|
||||
setRetryDataContainer(false);
|
||||
setOpenDataContainer(false);
|
||||
} else {
|
||||
setOpenDataContainer(true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: "You must create a data container in order to create a shop!",
|
||||
alertType: "error",
|
||||
})
|
||||
);
|
||||
// Try again after 8 seconds automatically
|
||||
setOpenDataContainer(true);
|
||||
let interval: number | undefined = undefined;
|
||||
const dataContainerToBase64 = await objectToBase64(storedDataContainer);
|
||||
interval = window.setInterval(async () => {
|
||||
try {
|
||||
const resourceResponse = await qortalRequest({
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: storedDataContainer?.owner,
|
||||
service: "DOCUMENT",
|
||||
data64: dataContainerToBase64,
|
||||
identifier: `${storedDataContainer?.storeId}-${DATA_CONTAINER_BASE}`,
|
||||
filename: "datacontainer.json",
|
||||
});
|
||||
if (isSuccessful(resourceResponse)) {
|
||||
await new Promise<void>((res, rej) => {
|
||||
setTimeout(() => {
|
||||
res();
|
||||
}, 1000);
|
||||
});
|
||||
dispatch(
|
||||
setDataContainer({
|
||||
...storedDataContainer,
|
||||
id: `${storedDataContainer?.storeId}-${DATA_CONTAINER_BASE}`,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: "Shop successfully created",
|
||||
alertType: "success",
|
||||
})
|
||||
);
|
||||
setCloseCreateStoreModal(true);
|
||||
setRetryDataContainer(false);
|
||||
setOpenDataContainer(false);
|
||||
clearInterval(interval);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setRetryDataContainer(false);
|
||||
// clear interval
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: "You must create a data container in order to create a shop!",
|
||||
alertType: "error",
|
||||
})
|
||||
);
|
||||
}
|
||||
}, 8000);
|
||||
}
|
||||
}, [storedDataContainer]);
|
||||
|
||||
|
||||
// If they successfully create a store but not a data container, keep the data-container information in the state.
|
||||
// Wait 8 seconds and try again automatically. If it fails again, then tell them to republish again.
|
||||
@ -382,6 +288,8 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||
foreignCoins,
|
||||
supportedCoins,
|
||||
}: onPublishParam) => {
|
||||
if(isCreatingShop) return
|
||||
setIsCreatingShop(true)
|
||||
if (!user || !user.name)
|
||||
throw new Error("Cannot publish: You do not have a Qortal name");
|
||||
if (!title) throw new Error("A title is required");
|
||||
@ -429,7 +337,7 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||
`**coins:QORTtrue,ARRR${supportedCoins.includes("ARRR")}**` +
|
||||
description.slice(0, 180);
|
||||
|
||||
const resourceResponse = await qortalRequest({
|
||||
const resourceStore = {
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: name,
|
||||
service: "STORE",
|
||||
@ -438,13 +346,9 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||
title,
|
||||
description: metadescription,
|
||||
identifier: identifier,
|
||||
});
|
||||
if (isSuccessful(resourceResponse)) {
|
||||
await new Promise<void>((res, rej) => {
|
||||
setTimeout(() => {
|
||||
res();
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const createdAt = Date.now();
|
||||
const dataContainer = {
|
||||
storeId: identifier,
|
||||
@ -472,15 +376,43 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||
updated: createdAt,
|
||||
};
|
||||
|
||||
const dataContainerToBase64 = await objectToBase64(dataContainer);
|
||||
// Publish Data Container to QDN
|
||||
const resourceDatacontainer = {
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: name,
|
||||
service: "DOCUMENT",
|
||||
data64: dataContainerToBase64,
|
||||
identifier: `${identifier}-${DATA_CONTAINER_BASE}`,
|
||||
filename: "datacontainer.json",
|
||||
}
|
||||
|
||||
const multiplePublish = {
|
||||
action: "PUBLISH_MULTIPLE_QDN_RESOURCES",
|
||||
resources: [resourceStore, resourceDatacontainer],
|
||||
};
|
||||
setPublishes(multiplePublish)
|
||||
await show()
|
||||
dispatch(setCurrentStore(storefullObj));
|
||||
dispatch(addToHashMapStores(storefullObj));
|
||||
dispatch(addToStores(storefullObj));
|
||||
dispatch(addToAllMyStores(storeData));
|
||||
setStoredDataContainer(dataContainer);
|
||||
setRetryDataContainer(true);
|
||||
} else {
|
||||
throw new Error("Failed to create store");
|
||||
}
|
||||
dispatch(
|
||||
setDataContainer({
|
||||
...dataContainer,
|
||||
id: `${identifier}-${DATA_CONTAINER_BASE}`,
|
||||
})
|
||||
);
|
||||
dispatch(
|
||||
setNotification({
|
||||
msg: "Shop successfully created",
|
||||
alertType: "success",
|
||||
})
|
||||
);
|
||||
setCloseCreateStoreModal(true);
|
||||
setOpenDataContainer(false);
|
||||
|
||||
|
||||
} catch (error: any) {
|
||||
let notificationObj: any = null;
|
||||
if (typeof error === "string") {
|
||||
@ -507,6 +439,8 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||
console.error(error);
|
||||
throw new Error("An unknown error occurred");
|
||||
}
|
||||
} finally {
|
||||
setIsCreatingShop(false)
|
||||
}
|
||||
},
|
||||
[user]
|
||||
@ -821,24 +755,22 @@ const GlobalWrapper: React.FC<Props> = ({ children, setTheme }) => {
|
||||
}
|
||||
}, [recentlyVisitedStoreId, myStores, userOwnDataContainer]);
|
||||
|
||||
// Handle publishing of data container when creating a store, or if it fails too (Need this to be able to call it from the reusable modal)
|
||||
useEffect(() => {
|
||||
const publishDataContainer = async () => {
|
||||
// Publish Data Container to QDN here
|
||||
await handlePublishDataContainer();
|
||||
};
|
||||
if (
|
||||
retryDataContainer &&
|
||||
storedDataContainer &&
|
||||
Object.keys(storedDataContainer).length > 0
|
||||
) {
|
||||
publishDataContainer();
|
||||
}
|
||||
// We only want to run this when retryDataContainer changes, or else storedDataContainer will be cleared beforehand.
|
||||
}, [retryDataContainer]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{isShow && (
|
||||
<MultiplePublish
|
||||
isOpen={isShow}
|
||||
onError={()=> {
|
||||
onCancel()
|
||||
}}
|
||||
onSubmit={() => {
|
||||
onOk()
|
||||
}}
|
||||
publishes={publishes}
|
||||
/>
|
||||
)}
|
||||
{isLoadingGlobal && <PageLoader />}
|
||||
{isOpenCreateStoreModal && user?.name && (
|
||||
<CreateStoreModal
|
||||
|
Loading…
Reference in New Issue
Block a user