3
0
mirror of https://github.com/Qortal/q-shop.git synced 2025-02-01 07:42:21 +00:00

Added advanced setting to reset data container

This commit is contained in:
Justin Ferrari 2024-01-03 16:22:09 -05:00
parent d366c60050
commit 9348a52e97
4 changed files with 238 additions and 32 deletions

View File

@ -195,3 +195,52 @@ export const DownloadArrrWalletIcon = styled(DownloadSVG)(({ theme }) => ({
cursor: "pointer", cursor: "pointer",
}, },
})); }));
export const AdvancedSettingsBox = styled(Box)(({ theme }) => ({
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: "10px",
padding: "5px 10px",
borderRadius: "5px",
backgroundColor: theme.palette.background.paper,
"& .MuiTypography-root": {
fontFamily: "Karla",
fontSize: "20px",
fontWeight: 300,
letterSpacing: "0.2px",
}
}));
export const EditStoreButtonsRow = styled(Box)({
display: "flex",
alignItems: "center",
gap: "10px",
});
export const CreateNewDataContainerRow = styled(Box)({
display: "flex",
alignItems: "center",
});
export const CreateNewDataContainerButton = styled(Button)(({ theme }) => ({
backgroundColor: "#d43232",
textTransform: "none",
fontFamily: "Raleway",
fontWeight: 300,
gap: "5px",
fontSize: "17px",
borderRadius: "5px",
border: "none",
color: "white",
padding: "5px 15px",
transition: "all 0.3s ease-in-out",
boxShadow:
"rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;",
"&:hover": {
cursor: "pointer",
backgroundColor: "#a72727",
boxShadow:
"rgba(50, 50, 93, 0.35) 0px 3px 5px -1px, rgba(0, 0, 0, 0.4) 0px 2px 3px -1px;"
}
}));

View File

@ -7,9 +7,15 @@ import {
IconButton, IconButton,
Tooltip, Tooltip,
Zoom, Zoom,
Box,
} from "@mui/material"; } from "@mui/material";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { toggleCreateStoreModal } from "../../state/features/globalSlice"; import {
toggleCreateStoreModal,
setDataContainer,
resetListProducts,
resetProducts
} from "../../state/features/globalSlice";
import { RootState } from "../../state/store"; import { RootState } from "../../state/store";
import { import {
AddLogoButton, AddLogoButton,
@ -25,6 +31,10 @@ import {
ModalTitle, ModalTitle,
StoreLogoPreview, StoreLogoPreview,
TimesIcon, TimesIcon,
AdvancedSettingsBox,
EditStoreButtonsRow,
CreateNewDataContainerRow,
CreateNewDataContainerButton,
} from "./CreateStoreModal-styles"; } from "./CreateStoreModal-styles";
import ImageUploader from "../common/ImageUploader"; import ImageUploader from "../common/ImageUploader";
import { import {
@ -37,6 +47,11 @@ import {
import { supportedCoinsArray } from "../../constants/supported-coins"; import { supportedCoinsArray } from "../../constants/supported-coins";
import { QortalSVG } from "../../assets/svgs/QortalSVG"; import { QortalSVG } from "../../assets/svgs/QortalSVG";
import { ARRRSVG } from "../../assets/svgs/ARRRSVG"; import { ARRRSVG } from "../../assets/svgs/ARRRSVG";
import { ReusableModal } from "./ReusableModal";
import { DATA_CONTAINER_BASE, STORE_BASE } from "../../constants/identifiers";
import { objectToBase64 } from "../../utils/toBase64";
import { ShortDataContainer } from "../../wrappers/GlobalWrapper";
import { setNotification } from "../../state/features/notificationsSlice";
interface ForeignCoins { interface ForeignCoins {
[key: string]: string; [key: string]: string;
@ -62,6 +77,7 @@ const MyModal: React.FC<MyModalProps> = ({ open, onClose, onPublish }) => {
const currentStore = useSelector( const currentStore = useSelector(
(state: RootState) => state.global.currentStore (state: RootState) => state.global.currentStore
); );
const user = useSelector((state: RootState) => state.auth.user);
const storeId = useSelector((state: RootState) => state.store.storeId); const storeId = useSelector((state: RootState) => state.store.storeId);
@ -76,6 +92,10 @@ const MyModal: React.FC<MyModalProps> = ({ open, onClose, onPublish }) => {
>(["QORT"]); >(["QORT"]);
const [qortWalletAddress, setQortWalletAddress] = useState<string>(""); const [qortWalletAddress, setQortWalletAddress] = useState<string>("");
const [arrrWalletAddress, setArrrWalletAddress] = useState<string>(""); const [arrrWalletAddress, setArrrWalletAddress] = useState<string>("");
const [showAdvancedSettings, setShowAdvancedSettings] =
useState<boolean>(false);
const [showCreateNewDataContainerModal, setShowCreateNewDataContainerModal] =
useState<boolean>(false);
const theme = useTheme(); const theme = useTheme();
@ -88,11 +108,14 @@ const MyModal: React.FC<MyModalProps> = ({ open, onClose, onPublish }) => {
} }
const foreignCoins: ForeignCoins = { const foreignCoins: ForeignCoins = {
ARRR: arrrWalletAddress ARRR: arrrWalletAddress,
} };
supportedCoinsSelected.filter((coin)=> coin !== 'QORT').forEach((item: string)=> { supportedCoinsSelected
if(!foreignCoins[item]) throw new Error(`Please add a ${item} address`) .filter(coin => coin !== "QORT")
}) .forEach((item: string) => {
if (!foreignCoins[item])
throw new Error(`Please add a ${item} address`);
});
await onPublish({ await onPublish({
title, title,
description, description,
@ -100,9 +123,9 @@ const MyModal: React.FC<MyModalProps> = ({ open, onClose, onPublish }) => {
location, location,
logo, logo,
foreignCoins: { foreignCoins: {
ARRR: arrrWalletAddress ARRR: arrrWalletAddress,
}, },
supportedCoins: supportedCoinsSelected supportedCoins: supportedCoinsSelected,
}); });
handleClose(); handleClose();
} catch (error: any) { } catch (error: any) {
@ -117,8 +140,8 @@ const MyModal: React.FC<MyModalProps> = ({ open, onClose, onPublish }) => {
setLogo(currentStore?.logo || null); setLogo(currentStore?.logo || null);
setLocation(currentStore?.location || ""); setLocation(currentStore?.location || "");
setShipsTo(currentStore?.shipsTo || ""); setShipsTo(currentStore?.shipsTo || "");
setSupportedCoinsSelected(currentStore?.supportedCoins || ['QORT']) setSupportedCoinsSelected(currentStore?.supportedCoins || ["QORT"]);
setArrrWalletAddress(currentStore?.foreignCoins?.ARRR || "") setArrrWalletAddress(currentStore?.foreignCoins?.ARRR || "");
} }
}, [currentStore, storeId, open]); }, [currentStore, storeId, open]);
@ -130,8 +153,9 @@ const MyModal: React.FC<MyModalProps> = ({ open, onClose, onPublish }) => {
setLogo(null); setLogo(null);
setLocation(""); setLocation("");
setShipsTo(""); setShipsTo("");
setArrrWalletAddress("") setArrrWalletAddress("");
setSupportedCoinsSelected(["QORT"]) setSupportedCoinsSelected(["QORT"]);
setShowAdvancedSettings(false);
dispatch(toggleCreateStoreModal(false)); dispatch(toggleCreateStoreModal(false));
onClose(); onClose();
}; };
@ -145,19 +169,82 @@ const MyModal: React.FC<MyModalProps> = ({ open, onClose, onPublish }) => {
setSupportedCoinsSelected(prevChips => prevChips.filter(c => c !== chip)); setSupportedCoinsSelected(prevChips => prevChips.filter(c => c !== chip));
}; };
const importAddress = async (coin: string)=> { const importAddress = async (coin: string) => {
try { try {
const res = await qortalRequest({ const res = await qortalRequest({
action: 'GET_USER_WALLET', action: "GET_USER_WALLET",
coin coin,
}) });
if(res?.address){ if (res?.address) {
setArrrWalletAddress(res.address) setArrrWalletAddress(res.address);
} }
} catch (error) { } catch (error) {
console.error(error);
} }
} };
// Recreate Shop Data
const handleRecreateShopData = async () => {
if (!currentStore || !user?.name) {
dispatch(
setNotification({
msg: "Error! Missing shop data or name",
alertType: "error",
})
);
return;
}
try {
const shortStoreId = currentStore?.shortStoreId;
const dataContainer: ShortDataContainer = {
storeId: currentStore.id,
shortStoreId: shortStoreId,
owner: user.name,
products: {},
};
const dataContainerToBase64 = await objectToBase64(dataContainer);
const dataContainerCreated = await qortalRequest({
action: "PUBLISH_QDN_RESOURCE",
name: user?.name,
service: "DOCUMENT",
data64: dataContainerToBase64,
identifier: `${currentStore.id}-${DATA_CONTAINER_BASE}`,
});
console.log({ dataContainerCreated });
if (dataContainerCreated && !dataContainerCreated.error) {
dispatch(
setDataContainer({
...dataContainer,
id: `${currentStore.id}-${DATA_CONTAINER_BASE}`,
})
);
dispatch(resetListProducts());
dispatch(resetProducts());
dispatch(
setNotification({
msg: "Data Container Created!",
alertType: "success",
})
);
onClose();
}
setShowCreateNewDataContainerModal(false);
setShowAdvancedSettings(false);
} catch (error) {
console.error(error);
navigate("/");
dispatch(
setNotification({
msg: "Error when creating the data container. Please try again!",
alertType: "error",
})
);
dispatch(updateRecentlyVisitedStoreId(""));
dispatch(clearDataCotainer());
}
};
return ( return (
<Modal <Modal
@ -294,7 +381,11 @@ const MyModal: React.FC<MyModalProps> = ({ open, onClose, onPublish }) => {
arrow={true} arrow={true}
title="Import your ARRR Wallet Address from your current account" title="Import your ARRR Wallet Address from your current account"
> >
<IconButton disableFocusRipple={true} disableRipple={true} onClick={()=> importAddress('ARRR')}> <IconButton
disableFocusRipple={true}
disableRipple={true}
onClick={() => importAddress("ARRR")}
>
<DownloadArrrWalletIcon <DownloadArrrWalletIcon
color={theme.palette.text.primary} color={theme.palette.text.primary}
height="40" height="40"
@ -361,20 +452,81 @@ const MyModal: React.FC<MyModalProps> = ({ open, onClose, onPublish }) => {
/> />
)} )}
/> />
{showAdvancedSettings && (
<CreateNewDataContainerRow
onClick={() => {
setShowCreateNewDataContainerModal(true);
}}
>
<CreateNewDataContainerButton>
Recreate Shop Data
</CreateNewDataContainerButton>
</CreateNewDataContainerRow>
)}
<FormControl fullWidth sx={{ marginBottom: 2 }}></FormControl> <FormControl fullWidth sx={{ marginBottom: 2 }}></FormControl>
{errorMessage && ( {errorMessage && (
<Typography color="error" variant="body1"> <Typography color="error" variant="body1">
{errorMessage} {errorMessage}
</Typography> </Typography>
)} )}
<ButtonRow sx={{ display: "flex", justifyContent: "flex-end", gap: 1 }}> <ButtonRow sx={{ display: "flex", justifyContent: "space-between" }}>
<CancelButton variant="outlined" color="error" onClick={handleClose}> <AdvancedSettingsBox>
Cancel <Typography>Advanced Settings</Typography>
</CancelButton> <FiltersCheckbox
<CreateButton variant="contained" onClick={handlePublish}> checked={showAdvancedSettings}
Edit Shop onChange={() => setShowAdvancedSettings(!showAdvancedSettings)}
</CreateButton> />
</AdvancedSettingsBox>
<EditStoreButtonsRow>
<CancelButton
variant="outlined"
color="error"
onClick={handleClose}
>
Cancel
</CancelButton>
<CreateButton variant="contained" onClick={handlePublish}>
Edit Shop
</CreateButton>
</EditStoreButtonsRow>
</ButtonRow> </ButtonRow>
<ReusableModal
open={showCreateNewDataContainerModal}
customStyles={{
width: "50%",
maxWidth: 1700,
height: "auto",
backgroundColor:
theme.palette.mode === "light" ? "#e8e8e8" : "#32333c",
position: "relative",
padding: "25px",
borderRadius: "3px",
overflowY: "auto",
overflowX: "hidden",
maxHeight: "90vh",
}}
>
<Box>
Warning! Are you sure you want to recreate your shop's data? This
will clear all your shop's products. This should only be done as a
last resort if you cannot access your product manager or if you are
experiencing issues products displaying properly.
</Box>
<ButtonRow>
<CancelButton
variant="outlined"
color="error"
onClick={() => {
setShowCreateNewDataContainerModal(false);
}}
>
Cancel
</CancelButton>
<CreateButton variant="contained" onClick={handleRecreateShopData}>
Recreate Shop Data
</CreateButton>
</ButtonRow>
</ReusableModal>
</ModalBody> </ModalBody>
</Modal> </Modal>
); );

View File

@ -217,13 +217,17 @@ export const Store = () => {
const switchCoin = async ()=> { const switchCoin = async ()=> {
dispatch(setIsLoadingGlobal(true)); dispatch(setIsLoadingGlobal(true));
await calculateARRRExchangeRate() await calculateARRRExchangeRate()
dispatch(setIsLoadingGlobal(false)); dispatch(setIsLoadingGlobal(false));
} }
// If shop's datacontainer changes, and listProducts becomes empty, clear local products array
useEffect(() => {
if (username === user?.name && userOwnDataContainer && Object.keys(userOwnDataContainer.products).length === 0) {
setProducts([]);
}
}, [userOwnDataContainer]);
useEffect(()=> { useEffect(()=> {
if(preferredCoin === CoinFilter.arrr && storeToUse?.supportedCoins?.includes(CoinFilter.arrr)){ if(preferredCoin === CoinFilter.arrr && storeToUse?.supportedCoins?.includes(CoinFilter.arrr)){
switchCoin() switchCoin()

View File

@ -53,7 +53,8 @@ interface Props {
children: React.ReactNode; children: React.ReactNode;
setTheme: (val: string) => void; setTheme: (val: string) => void;
} }
interface ShortDataContainer {
export interface ShortDataContainer {
storeId: string; storeId: string;
shortStoreId: string; shortStoreId: string;
owner: string; owner: string;