mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-05-15 22:26:58 +00:00
888 lines
30 KiB
TypeScript
888 lines
30 KiB
TypeScript
import React, {
|
|
useCallback,
|
|
useContext,
|
|
useEffect,
|
|
useRef,
|
|
useState,
|
|
} from 'react';
|
|
import {
|
|
Avatar,
|
|
Box,
|
|
Button,
|
|
ButtonBase,
|
|
Collapse,
|
|
Dialog,
|
|
DialogActions,
|
|
DialogContent,
|
|
DialogContentText,
|
|
DialogTitle,
|
|
MenuItem,
|
|
Popover,
|
|
Select,
|
|
TextField,
|
|
Typography,
|
|
useTheme,
|
|
} from '@mui/material';
|
|
import { LoadingButton } from '@mui/lab';
|
|
import LockIcon from '@mui/icons-material/Lock';
|
|
import NoEncryptionGmailerrorredIcon from '@mui/icons-material/NoEncryptionGmailerrorred';
|
|
import {
|
|
MyContext,
|
|
getArbitraryEndpointReact,
|
|
getBaseApiReact,
|
|
} from '../../App';
|
|
import { Spacer } from '../../common/Spacer';
|
|
import { CustomLoader } from '../../common/CustomLoader';
|
|
import { RequestQueueWithPromise } from '../../utils/queue/queue';
|
|
|
|
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 { useVirtualizer } from '@tanstack/react-virtual';
|
|
import ErrorBoundary from '../../common/ErrorBoundary';
|
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
|
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
|
import { getFee } from '../../background';
|
|
import { useAtom } from 'jotai';
|
|
export const requestQueuePromos = new RequestQueueWithPromise(3);
|
|
|
|
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 });
|
|
|
|
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] = useAtom(
|
|
myGroupsWhereIAmAdminAtom
|
|
);
|
|
const [promotions, setPromotions] = useAtom(promotionsAtom);
|
|
const [promotionTimeInterval, setPromotionTimeInterval] = useAtom(
|
|
promotionTimeIntervalAtom
|
|
);
|
|
|
|
const [isExpanded, setIsExpanded] = React.useState(false);
|
|
|
|
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 theme = useTheme();
|
|
const listRef = useRef();
|
|
const rowVirtualizer = useVirtualizer({
|
|
count: promotions.length,
|
|
getItemKey: React.useCallback(
|
|
(index) => promotions[index]?.identifier,
|
|
[promotions]
|
|
),
|
|
getScrollElement: () => listRef.current,
|
|
estimateSize: () => 80, // Provide an estimated height of items, adjust this as needed
|
|
overscan: 10, // Number of items to render outside the visible area to improve smoothness
|
|
});
|
|
|
|
useEffect(() => {
|
|
try {
|
|
(async () => {
|
|
const feeRes = await getFee('ARBITRARY');
|
|
setFee(feeRes?.fee);
|
|
})();
|
|
} catch (error) {
|
|
console.log(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.sort((a, b) => b.created - a.created)
|
|
);
|
|
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, promotionTimeInterval]);
|
|
|
|
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');
|
|
});
|
|
}); // TODO translate
|
|
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) => {
|
|
window
|
|
.sendMessage('joinGroup', {
|
|
groupId,
|
|
})
|
|
.then((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);
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
setInfoSnack({
|
|
type: 'error',
|
|
message: error.message || 'An error occurred',
|
|
});
|
|
setOpenSnack(true);
|
|
rej(error);
|
|
});
|
|
});
|
|
setIsLoadingJoinGroup(false);
|
|
} catch (error) {
|
|
} finally {
|
|
setIsLoadingJoinGroup(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Box
|
|
sx={{
|
|
width: '100%',
|
|
display: 'flex',
|
|
marginTop: '20px',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
}}
|
|
>
|
|
<Box
|
|
sx={{
|
|
display: 'flex',
|
|
gap: '20px',
|
|
width: '100%',
|
|
justifyContent: 'space-between',
|
|
}}
|
|
>
|
|
<ButtonBase
|
|
sx={{
|
|
display: 'flex',
|
|
flexDirection: 'row',
|
|
padding: `0px ${isExpanded ? '24px' : '20px'}`,
|
|
gap: '10px',
|
|
justifyContent: 'flex-start',
|
|
alignSelf: isExpanded && 'flex-start',
|
|
}}
|
|
onClick={() => setIsExpanded((prev) => !prev)}
|
|
>
|
|
<Typography
|
|
sx={{
|
|
fontSize: '1rem',
|
|
}}
|
|
>
|
|
Group promotions{' '}
|
|
{promotions.length > 0 && ` (${promotions.length})`}
|
|
</Typography>
|
|
{isExpanded ? (
|
|
<ExpandLessIcon
|
|
sx={{
|
|
marginLeft: 'auto',
|
|
}}
|
|
/>
|
|
) : (
|
|
<ExpandMoreIcon
|
|
sx={{
|
|
marginLeft: 'auto',
|
|
}}
|
|
/>
|
|
)}
|
|
</ButtonBase>
|
|
|
|
<Box
|
|
style={{
|
|
width: '330px',
|
|
}}
|
|
/>
|
|
</Box>
|
|
|
|
<Collapse in={isExpanded} timeout="auto" unmountOnExit>
|
|
<>
|
|
<Box
|
|
sx={{
|
|
width: '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,
|
|
}}
|
|
></Typography>
|
|
|
|
<Button
|
|
variant="contained"
|
|
onClick={() => setIsShowModal(true)}
|
|
sx={{
|
|
fontSize: '12px',
|
|
}}
|
|
>
|
|
Add Promotion
|
|
</Button>
|
|
</Box>
|
|
|
|
<Spacer height="10px" />
|
|
</Box>
|
|
<Box
|
|
sx={{
|
|
bgcolor: 'background.paper',
|
|
borderRadius: '19px',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
maxHeight: '700px',
|
|
maxWidth: '90%',
|
|
padding: '20px 0px',
|
|
width: '750px',
|
|
}}
|
|
>
|
|
{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',
|
|
position: 'relative',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
width: '100%',
|
|
}}
|
|
>
|
|
<div
|
|
ref={listRef}
|
|
className="scrollable-container"
|
|
style={{
|
|
flexGrow: 1,
|
|
overflow: 'auto',
|
|
position: 'relative',
|
|
display: 'flex',
|
|
height: '0px',
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
height: rowVirtualizer.getTotalSize(),
|
|
width: '100%',
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: 0,
|
|
width: '100%',
|
|
}}
|
|
>
|
|
{rowVirtualizer.getVirtualItems().map((virtualRow) => {
|
|
const index = virtualRow.index;
|
|
const promotion = promotions[index];
|
|
return (
|
|
<div
|
|
data-index={virtualRow.index} //needed for dynamic row height measurement
|
|
ref={rowVirtualizer.measureElement} //measure dynamic row height
|
|
key={promotion?.identifier}
|
|
style={{
|
|
position: 'absolute',
|
|
top: 0,
|
|
left: '50%', // Move to the center horizontally
|
|
transform: `translateY(${virtualRow.start}px) translateX(-50%)`, // Adjust for centering
|
|
width: '100%', // Control width (90% of the parent)
|
|
padding: '10px 0',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
overscrollBehavior: 'none',
|
|
flexDirection: 'column',
|
|
gap: '5px',
|
|
}}
|
|
>
|
|
<ErrorBoundary
|
|
fallback={
|
|
<Typography>
|
|
Error loading content: Invalid Data
|
|
</Typography>
|
|
}
|
|
>
|
|
<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: theme.palette.text.primary,
|
|
}}
|
|
alt={promotion?.name}
|
|
src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${
|
|
promotion?.name
|
|
}/qortal_avatar?async=true`}
|
|
>
|
|
{promotion?.name?.charAt(0)}
|
|
</Avatar>
|
|
|
|
<Typography
|
|
sx={{
|
|
fontWight: 600,
|
|
fontFamily: 'Inter',
|
|
}}
|
|
>
|
|
{promotion?.name}
|
|
</Typography>
|
|
</Box>
|
|
|
|
<Typography
|
|
sx={{
|
|
fontWight: 600,
|
|
fontFamily: 'Inter',
|
|
}}
|
|
>
|
|
{promotion?.groupName}
|
|
</Typography>
|
|
</Box>
|
|
|
|
<Spacer height="20px" />
|
|
|
|
<Box
|
|
sx={{
|
|
display: 'flex',
|
|
gap: '20px',
|
|
alignItems: 'center',
|
|
}}
|
|
>
|
|
{promotion?.isOpen === false && (
|
|
<LockIcon
|
|
sx={{
|
|
color: theme.palette.other.positive,
|
|
}}
|
|
/>
|
|
)}
|
|
{promotion?.isOpen === true && (
|
|
<NoEncryptionGmailerrorredIcon
|
|
sx={{
|
|
color: theme.palette.other.danger,
|
|
}}
|
|
/>
|
|
)}
|
|
<Typography
|
|
sx={{
|
|
fontSize: '15px',
|
|
fontWeight: 600,
|
|
}}
|
|
>
|
|
{promotion?.isOpen
|
|
? 'Public group'
|
|
: 'Private group'}
|
|
</Typography>
|
|
</Box>
|
|
|
|
<Spacer height="20px" />
|
|
|
|
<Typography
|
|
sx={{
|
|
fontWight: 600,
|
|
fontFamily: 'Inter',
|
|
}}
|
|
>
|
|
{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',
|
|
color: theme.palette.text.primary,
|
|
}}
|
|
>
|
|
Join Group: {` ${promotion?.groupName}`}
|
|
</Button>
|
|
</Box>
|
|
</Box>
|
|
|
|
<Spacer height="50px" />
|
|
</ErrorBoundary>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Box>
|
|
</>
|
|
</Collapse>
|
|
|
|
<Spacer height="20px" />
|
|
|
|
{isShowModal && (
|
|
<Dialog
|
|
open={isShowModal}
|
|
aria-labelledby="alert-dialog-title"
|
|
aria-describedby="alert-dialog-description"
|
|
>
|
|
<DialogTitle id="alert-dialog-title">
|
|
{'Promote your group to non-members'}
|
|
</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)}
|
|
variant="outlined"
|
|
>
|
|
{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: theme.palette.text.primary,
|
|
},
|
|
'& .MuiFormLabel-root.Mui-focused': {
|
|
color: theme.palette.text.primary,
|
|
},
|
|
}}
|
|
/>
|
|
</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>
|
|
);
|
|
};
|