mirror of
https://github.com/Qortal/chrome-extension.git
synced 2025-03-15 04:12:32 +00:00
added group promotions
This commit is contained in:
parent
217e20ec4b
commit
c4b09db91d
@ -73,4 +73,19 @@ export const hasSettingsChangedAtom = atom({
|
||||
export const navigationControllerAtom = atom({
|
||||
key: 'navigationControllerAtom',
|
||||
default: {},
|
||||
});
|
||||
|
||||
export const myGroupsWhereIAmAdminAtom = atom({
|
||||
key: 'myGroupsWhereIAmAdminAtom',
|
||||
default: [],
|
||||
});
|
||||
|
||||
export const promotionTimeIntervalAtom = atom({
|
||||
key: 'promotionTimeIntervalAtom',
|
||||
default: 0,
|
||||
});
|
||||
|
||||
export const promotionsAtom = atom({
|
||||
key: 'promotionsAtom',
|
||||
default: [],
|
||||
});
|
@ -16,13 +16,17 @@ import { Spacer } from "../../common/Spacer";
|
||||
import { CustomLoader } from "../../common/CustomLoader";
|
||||
import { getBaseApi } from "../../background";
|
||||
import { MyContext, getBaseApiReact, isMobile } from "../../App";
|
||||
import { myGroupsWhereIAmAdminAtom } from "../../atoms/global";
|
||||
import { useSetRecoilState } from "recoil";
|
||||
export const requestQueueGroupJoinRequests = new RequestQueueWithPromise(2)
|
||||
|
||||
export const GroupJoinRequests = ({ myAddress, groups, setOpenManageMembers, getTimestampEnterChat, setSelectedGroup, setGroupSection, setMobileViewMode }) => {
|
||||
const [groupsWithJoinRequests, setGroupsWithJoinRequests] = React.useState([])
|
||||
const [loading, setLoading] = React.useState(true)
|
||||
const {txList, setTxList} = React.useContext(MyContext)
|
||||
|
||||
const setMyGroupsWhereIAmAdmin = useSetRecoilState(
|
||||
myGroupsWhereIAmAdminAtom
|
||||
);
|
||||
|
||||
|
||||
const getJoinRequests = async ()=> {
|
||||
@ -50,6 +54,8 @@ export const GroupJoinRequests = ({ myAddress, groups, setOpenManageMembers, get
|
||||
|
||||
|
||||
await Promise.all(getAllGroupsAsAdmin)
|
||||
setMyGroupsWhereIAmAdmin(groupsAsAdmin)
|
||||
|
||||
const res = await Promise.all(groupsAsAdmin.map(async (group)=> {
|
||||
|
||||
const joinRequestResponse = await requestQueueGroupJoinRequests.enqueue(()=> {
|
||||
|
@ -6,6 +6,7 @@ import { ThingsToDoInitial } from "./ThingsToDoInitial";
|
||||
import { GroupJoinRequests } from "./GroupJoinRequests";
|
||||
import { GroupInvites } from "./GroupInvites";
|
||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||
import { ListOfGroupPromotions } from "./ListOfGroupPromotions";
|
||||
|
||||
export const Home = ({
|
||||
refreshHomeDataFunc,
|
||||
@ -105,6 +106,9 @@ export const Home = ({
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
{!isLoadingGroups && (
|
||||
<ListOfGroupPromotions />
|
||||
)}
|
||||
<Spacer height="180px" />
|
||||
</Box>
|
||||
);
|
||||
|
@ -6,6 +6,7 @@ import { ThingsToDoInitial } from "./ThingsToDoInitial";
|
||||
import { GroupJoinRequests } from "./GroupJoinRequests";
|
||||
import { GroupInvites } from "./GroupInvites";
|
||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||
import { ListOfGroupPromotions } from "./ListOfGroupPromotions";
|
||||
|
||||
export const HomeDesktop = ({
|
||||
refreshHomeDataFunc,
|
||||
@ -122,6 +123,9 @@ export const HomeDesktop = ({
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
{!isLoadingGroups && (
|
||||
<ListOfGroupPromotions />
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Spacer height="26px" />
|
||||
|
774
src/components/Group/ListOfGroupPromotions.tsx
Normal file
774
src/components/Group/ListOfGroupPromotions.tsx
Normal file
@ -0,0 +1,774 @@
|
||||
import React, {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import {
|
||||
Avatar,
|
||||
Box,
|
||||
Button,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
DialogContentText,
|
||||
DialogTitle,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemButton,
|
||||
ListItemText,
|
||||
MenuItem,
|
||||
Popover,
|
||||
Select,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import {
|
||||
AutoSizer,
|
||||
CellMeasurer,
|
||||
CellMeasurerCache,
|
||||
List,
|
||||
} from "react-virtualized";
|
||||
import { getNameInfo } from "./Group";
|
||||
import { getBaseApi, getFee } from "../../background";
|
||||
import { LoadingButton } from "@mui/lab";
|
||||
import {
|
||||
MyContext,
|
||||
getArbitraryEndpointReact,
|
||||
getBaseApiReact,
|
||||
isMobile,
|
||||
} from "../../App";
|
||||
import { Spacer } from "../../common/Spacer";
|
||||
import { CustomLoader } from "../../common/CustomLoader";
|
||||
import { RequestQueueWithPromise } from "../../utils/queue/queue";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { myGroupsWhereIAmAdminAtom, promotionTimeIntervalAtom, promotionsAtom } from "../../atoms/global";
|
||||
import { Label } from "./AddGroup";
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import { CustomizedSnackbars } from "../Snackbar/Snackbar";
|
||||
import { getGroupNames } from "./UserListOfInvites";
|
||||
import { WrapperUserAction } from "../WrapperUserAction";
|
||||
|
||||
export const requestQueuePromos = new RequestQueueWithPromise(20);
|
||||
|
||||
export function utf8ToBase64(inputString: string): string {
|
||||
// Encode the string as UTF-8
|
||||
const utf8String = encodeURIComponent(inputString).replace(
|
||||
/%([0-9A-F]{2})/g,
|
||||
(match, p1) => String.fromCharCode(Number("0x" + p1))
|
||||
);
|
||||
|
||||
// Convert the UTF-8 encoded string to base64
|
||||
const base64String = btoa(utf8String);
|
||||
return base64String;
|
||||
}
|
||||
|
||||
const uid = new ShortUniqueId({ length: 8 });
|
||||
|
||||
const cache = new CellMeasurerCache({
|
||||
fixedWidth: true,
|
||||
defaultHeight: 50,
|
||||
});
|
||||
|
||||
export function getGroupId(str) {
|
||||
const match = str.match(/group-(\d+)-/);
|
||||
return match ? match[1] : null;
|
||||
}
|
||||
const THIRTY_MINUTES = 30 * 60 * 1000; // 30 minutes in milliseconds
|
||||
export const ListOfGroupPromotions = () => {
|
||||
const [popoverAnchor, setPopoverAnchor] = useState(null);
|
||||
const [openPopoverIndex, setOpenPopoverIndex] = useState(null);
|
||||
const [selectedGroup, setSelectedGroup] = useState(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [isShowModal, setIsShowModal] = useState(false);
|
||||
const [text, setText] = useState("");
|
||||
const [myGroupsWhereIAmAdmin, setMyGroupsWhereIAmAdmin] = useRecoilState(
|
||||
myGroupsWhereIAmAdminAtom
|
||||
);
|
||||
const [promotions, setPromotions] = useRecoilState(
|
||||
promotionsAtom
|
||||
);
|
||||
const [promotionTimeInterval, setPromotionTimeInterval] = useRecoilState(
|
||||
promotionTimeIntervalAtom
|
||||
);
|
||||
const [openSnack, setOpenSnack] = useState(false);
|
||||
const [infoSnack, setInfoSnack] = useState(null);
|
||||
const [fee, setFee] = useState(null);
|
||||
const [isLoadingJoinGroup, setIsLoadingJoinGroup] = useState(false);
|
||||
const [isLoadingPublish, setIsLoadingPublish] = useState(false);
|
||||
const { show, setTxList } = useContext(MyContext);
|
||||
|
||||
const listRef = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
(async () => {
|
||||
const feeRes = await getFee("ARBITRARY");
|
||||
setFee(feeRes?.fee);
|
||||
})();
|
||||
} catch (error) {}
|
||||
}, []);
|
||||
const getPromotions = useCallback(async () => {
|
||||
try {
|
||||
setPromotionTimeInterval(Date.now())
|
||||
const identifier = `group-promotions-ui24-`;
|
||||
const url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=100&includemetadata=false&reverse=true&prefix=true`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const responseData = await response.json();
|
||||
let data: any[] = [];
|
||||
const uniqueGroupIds = new Set();
|
||||
const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
|
||||
const getPromos = responseData?.map(async (promo: any) => {
|
||||
if (promo?.size < 200 && promo.created > oneWeekAgo) {
|
||||
const name = await requestQueuePromos.enqueue(async () => {
|
||||
const url = `${getBaseApiReact()}/arbitrary/${promo.service}/${
|
||||
promo.name
|
||||
}/${promo.identifier}`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
});
|
||||
|
||||
try {
|
||||
const responseData = await response.text();
|
||||
if (responseData) {
|
||||
const groupId = getGroupId(promo.identifier);
|
||||
|
||||
// Check if this groupId has already been processed
|
||||
if (!uniqueGroupIds.has(groupId)) {
|
||||
// Add the groupId to the set
|
||||
uniqueGroupIds.add(groupId);
|
||||
|
||||
// Push the item to data
|
||||
data.push({
|
||||
data: responseData,
|
||||
groupId,
|
||||
...promo,
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching promo:", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
await Promise.all(getPromos);
|
||||
const groupWithInfo = await getGroupNames(data);
|
||||
setPromotions(groupWithInfo);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const now = Date.now();
|
||||
|
||||
const timeSinceLastFetch = now - promotionTimeInterval;
|
||||
const initialDelay = timeSinceLastFetch >= THIRTY_MINUTES
|
||||
? 0
|
||||
: THIRTY_MINUTES - timeSinceLastFetch;
|
||||
const initialTimeout = setTimeout(() => {
|
||||
getPromotions();
|
||||
|
||||
// Start a 30-minute interval
|
||||
const interval = setInterval(() => {
|
||||
getPromotions();
|
||||
}, THIRTY_MINUTES);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, initialDelay);
|
||||
|
||||
return () => clearTimeout(initialTimeout);
|
||||
}, [getPromotions]);
|
||||
|
||||
const handlePopoverOpen = (event, index) => {
|
||||
setPopoverAnchor(event.currentTarget);
|
||||
setOpenPopoverIndex(index);
|
||||
};
|
||||
|
||||
const handlePopoverClose = () => {
|
||||
setPopoverAnchor(null);
|
||||
setOpenPopoverIndex(null);
|
||||
};
|
||||
const publishPromo = async () => {
|
||||
try {
|
||||
setIsLoadingPublish(true);
|
||||
|
||||
const data = utf8ToBase64(text);
|
||||
const identifier = `group-promotions-ui24-group-${selectedGroup}-${uid.rnd()}`;
|
||||
|
||||
await new Promise((res, rej) => {
|
||||
window
|
||||
.sendMessage("publishOnQDN", {
|
||||
data: data,
|
||||
identifier: identifier,
|
||||
service: "DOCUMENT",
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response?.error) {
|
||||
res(response);
|
||||
return;
|
||||
}
|
||||
rej(response.error);
|
||||
})
|
||||
.catch((error) => {
|
||||
rej(error.message || "An error occurred");
|
||||
});
|
||||
});
|
||||
setInfoSnack({
|
||||
type: "success",
|
||||
message:
|
||||
"Successfully published promotion. It may take a couple of minutes for the promotion to appear",
|
||||
});
|
||||
setOpenSnack(true);
|
||||
setText("");
|
||||
setSelectedGroup(null);
|
||||
setIsShowModal(false);
|
||||
} catch (error) {
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message:
|
||||
error?.message || "Error publishing the promotion. Please try again",
|
||||
});
|
||||
setOpenSnack(true);
|
||||
} finally {
|
||||
setIsLoadingPublish(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleJoinGroup = async (group, isOpen) => {
|
||||
try {
|
||||
const groupId = group.groupId;
|
||||
const fee = await getFee("JOIN_GROUP");
|
||||
await show({
|
||||
message: "Would you like to perform an JOIN_GROUP transaction?",
|
||||
publishFee: fee.fee + " QORT",
|
||||
});
|
||||
setIsLoadingJoinGroup(true);
|
||||
await new Promise((res, rej) => {
|
||||
chrome?.runtime?.sendMessage(
|
||||
{
|
||||
action: "joinGroup",
|
||||
payload: {
|
||||
groupId,
|
||||
},
|
||||
},
|
||||
(response) => {
|
||||
|
||||
if (!response?.error) {
|
||||
setInfoSnack({
|
||||
type: "success",
|
||||
message: "Successfully requested to join group. It may take a couple of minutes for the changes to propagate",
|
||||
});
|
||||
if(isOpen){
|
||||
setTxList((prev)=> [{
|
||||
...response,
|
||||
type: 'joined-group',
|
||||
label: `Joined Group ${group?.groupName}: awaiting confirmation`,
|
||||
labelDone: `Joined Group ${group?.groupName}: success !`,
|
||||
done: false,
|
||||
groupId,
|
||||
}, ...prev])
|
||||
} else {
|
||||
setTxList((prev)=> [{
|
||||
...response,
|
||||
type: 'joined-group-request',
|
||||
label: `Requested to join Group ${group?.groupName}: awaiting confirmation`,
|
||||
labelDone: `Requested to join Group ${group?.groupName}: success !`,
|
||||
done: false,
|
||||
groupId,
|
||||
}, ...prev])
|
||||
}
|
||||
setOpenSnack(true);
|
||||
handlePopoverClose();
|
||||
res(response);
|
||||
return;
|
||||
} else {
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message: response?.error,
|
||||
});
|
||||
setOpenSnack(true);
|
||||
rej(response.error);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
setIsLoadingJoinGroup(false);
|
||||
} catch (error) {
|
||||
} finally {
|
||||
setIsLoadingJoinGroup(false);
|
||||
}
|
||||
};
|
||||
|
||||
// const handleCancelInvitation = async (address)=> {
|
||||
// try {
|
||||
// const fee = await getFee('CANCEL_GROUP_INVITE')
|
||||
// await show({
|
||||
// message: "Would you like to perform a CANCEL_GROUP_INVITE transaction?" ,
|
||||
// publishFee: fee.fee + ' QORT'
|
||||
// })
|
||||
// setIsLoadingCancelInvite(true)
|
||||
// await new Promise((res, rej)=> {
|
||||
// window.sendMessage("cancelInvitationToGroup", {
|
||||
// groupId,
|
||||
// qortalAddress: address,
|
||||
// })
|
||||
// .then((response) => {
|
||||
// if (!response?.error) {
|
||||
// setInfoSnack({
|
||||
// type: "success",
|
||||
// message: "Successfully canceled invitation. It may take a couple of minutes for the changes to propagate",
|
||||
// });
|
||||
// setOpenSnack(true);
|
||||
// handlePopoverClose();
|
||||
// setIsLoadingCancelInvite(true);
|
||||
// res(response);
|
||||
// return;
|
||||
// }
|
||||
// setInfoSnack({
|
||||
// type: "error",
|
||||
// message: response?.error,
|
||||
// });
|
||||
// setOpenSnack(true);
|
||||
// rej(response.error);
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// setInfoSnack({
|
||||
// type: "error",
|
||||
// message: error.message || "An error occurred",
|
||||
// });
|
||||
// setOpenSnack(true);
|
||||
// rej(error);
|
||||
// });
|
||||
|
||||
// })
|
||||
// } catch (error) {
|
||||
|
||||
// } finally {
|
||||
// setIsLoadingCancelInvite(false)
|
||||
// }
|
||||
// }
|
||||
|
||||
const rowRenderer = ({ index, key, parent, style }) => {
|
||||
const promotion = promotions[index];
|
||||
|
||||
return (
|
||||
<CellMeasurer
|
||||
key={key}
|
||||
cache={cache}
|
||||
parent={parent}
|
||||
columnIndex={0}
|
||||
rowIndex={index}
|
||||
>
|
||||
{({ measure }) => (
|
||||
<div style={style} onLoad={measure}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
width: "100%",
|
||||
padding: "0px 20px",
|
||||
}}
|
||||
>
|
||||
<Popover
|
||||
open={openPopoverIndex === promotion?.groupId}
|
||||
anchorEl={popoverAnchor}
|
||||
onClose={(event, reason) => {
|
||||
if (reason === "backdropClick") {
|
||||
// Prevent closing on backdrop click
|
||||
return;
|
||||
}
|
||||
handlePopoverClose(); // Close only on other events like Esc key press
|
||||
}}
|
||||
anchorOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "center",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "center",
|
||||
}}
|
||||
style={{ marginTop: "8px" }}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "325px",
|
||||
height: "auto",
|
||||
maxHeight: "400px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: "10px",
|
||||
padding: "10px",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "13px",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
Group name: {` ${promotion?.groupName}`}
|
||||
</Typography>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "13px",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
Number of members: {` ${promotion?.memberCount}`}
|
||||
</Typography>
|
||||
{promotion?.description && (
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "13px",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
{promotion?.description}
|
||||
</Typography>
|
||||
)}
|
||||
{promotion?.isOpen === false && (
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "13px",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
*This is a closed/private group, so you will need to wait
|
||||
until an admin accepts your request
|
||||
</Typography>
|
||||
)}
|
||||
<Spacer height="5px" />
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: "20px",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<LoadingButton
|
||||
loading={isLoadingJoinGroup}
|
||||
loadingPosition="start"
|
||||
variant="contained"
|
||||
onClick={handlePopoverClose}
|
||||
>
|
||||
Close
|
||||
</LoadingButton>
|
||||
<LoadingButton
|
||||
loading={isLoadingJoinGroup}
|
||||
loadingPosition="start"
|
||||
variant="contained"
|
||||
onClick={() =>
|
||||
handleJoinGroup(promotion, promotion?.isOpen)
|
||||
}
|
||||
>
|
||||
Join
|
||||
</LoadingButton>
|
||||
</Box>
|
||||
</Box>
|
||||
</Popover>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
gap: "15px",
|
||||
}}
|
||||
>
|
||||
<Avatar
|
||||
sx={{
|
||||
backgroundColor: "#27282c",
|
||||
color: "white",
|
||||
}}
|
||||
alt={promotion?.name}
|
||||
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
||||
promotion?.name
|
||||
}/qortal_avatar?async=true`}
|
||||
>
|
||||
{promotion?.name?.charAt(0)}
|
||||
</Avatar>
|
||||
<Typography
|
||||
sx={{
|
||||
fontWight: 600,
|
||||
fontFamily: "Inter",
|
||||
color: "cadetBlue",
|
||||
}}
|
||||
>
|
||||
{promotion?.name}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
fontWight: 600,
|
||||
fontFamily: "Inter",
|
||||
color: "cadetBlue",
|
||||
}}
|
||||
>
|
||||
{promotion?.groupName}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Spacer height="20px" />
|
||||
<Typography
|
||||
sx={{
|
||||
fontWight: 600,
|
||||
fontFamily: "Inter",
|
||||
color: "cadetBlue",
|
||||
}}
|
||||
>
|
||||
{promotion?.data}
|
||||
</Typography>
|
||||
<Spacer height="20px" />
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={(event) => handlePopoverOpen(event, promotion?.groupId)}
|
||||
sx={{
|
||||
fontSize: "12px",
|
||||
}}
|
||||
>
|
||||
Join Group: {` ${promotion?.groupName}`}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
<Spacer height="50px" />
|
||||
</div>
|
||||
)}
|
||||
</CellMeasurer>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
marginTop: "25px",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: isMobile ? "320px" : "750px",
|
||||
maxWidth: "90%",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
padding: "0px 20px",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "13px",
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
Group Promotions
|
||||
</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={() => setIsShowModal(true)}
|
||||
sx={{
|
||||
fontSize: "12px",
|
||||
}}
|
||||
>
|
||||
Add Promotion
|
||||
</Button>
|
||||
</Box>
|
||||
<Spacer height="10px" />
|
||||
</Box>
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
width: isMobile ? "320px" : "750px",
|
||||
maxWidth: "90%",
|
||||
maxHeight: "700px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
bgcolor: "background.paper",
|
||||
padding: "20px 0px",
|
||||
borderRadius: "19px",
|
||||
}}
|
||||
>
|
||||
{loading && promotions.length === 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<CustomLoader />
|
||||
</Box>
|
||||
)}
|
||||
{!loading && promotions.length === 0 && (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100%",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "11px",
|
||||
fontWeight: 400,
|
||||
color: "rgba(255, 255, 255, 0.2)",
|
||||
}}
|
||||
>
|
||||
Nothing to display
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
height: "600px",
|
||||
}}
|
||||
>
|
||||
<AutoSizer>
|
||||
{({ height, width }) => (
|
||||
<List
|
||||
ref={listRef}
|
||||
width={width}
|
||||
height={height}
|
||||
rowCount={promotions.length}
|
||||
rowHeight={cache.rowHeight}
|
||||
rowRenderer={rowRenderer}
|
||||
deferredMeasurementCache={cache}
|
||||
/>
|
||||
)}
|
||||
</AutoSizer>
|
||||
</div>
|
||||
</Box>
|
||||
<Spacer height="20px" />
|
||||
|
||||
{isShowModal && (
|
||||
<Dialog
|
||||
open={isShowModal}
|
||||
aria-labelledby="alert-dialog-title"
|
||||
aria-describedby="alert-dialog-description"
|
||||
>
|
||||
<DialogTitle id="alert-dialog-title">
|
||||
{"Publish Group Promotion"}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText id="alert-dialog-description">
|
||||
Only the latest promotion from the week will be shown for your
|
||||
group.
|
||||
</DialogContentText>
|
||||
<DialogContentText id="alert-dialog-description2">
|
||||
Max 200 characters. Publish Fee: {fee && fee} {" QORT"}
|
||||
</DialogContentText>
|
||||
<Spacer height="20px" />
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: "5px",
|
||||
}}
|
||||
>
|
||||
<Label>Select a group</Label>
|
||||
<Label>Only groups where you are an admin will be shown</Label>
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={selectedGroup}
|
||||
label="Groups where you are an admin"
|
||||
onChange={(e) => setSelectedGroup(e.target.value)}
|
||||
>
|
||||
{myGroupsWhereIAmAdmin?.map((group) => {
|
||||
return (
|
||||
<MenuItem key={group?.groupId} value={group?.groupId}>
|
||||
{group?.groupName}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</Box>
|
||||
<Spacer height="20px" />
|
||||
<TextField
|
||||
label="Promotion text"
|
||||
variant="filled"
|
||||
fullWidth
|
||||
value={text}
|
||||
onChange={(e) => setText(e.target.value)}
|
||||
inputProps={{
|
||||
maxLength: 200,
|
||||
}}
|
||||
multiline={true}
|
||||
sx={{
|
||||
"& .MuiFormLabel-root": {
|
||||
color: "white",
|
||||
},
|
||||
"& .MuiFormLabel-root.Mui-focused": {
|
||||
color: "white",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button
|
||||
disabled={isLoadingPublish}
|
||||
variant="contained"
|
||||
onClick={() => setIsShowModal(false)}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
<Button
|
||||
disabled={!text.trim() || !selectedGroup || isLoadingPublish}
|
||||
variant="contained"
|
||||
onClick={publishPromo}
|
||||
autoFocus
|
||||
>
|
||||
Publish
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)}
|
||||
<CustomizedSnackbars
|
||||
open={openSnack}
|
||||
setOpen={setOpenSnack}
|
||||
info={infoSnack}
|
||||
setInfo={setInfoSnack}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user