2024-09-12 05:01:36 +03:00

273 lines
7.5 KiB
TypeScript

import {
Box,
Button,
ListItem,
ListItemButton,
ListItemText,
Popover,
TextField,
Typography,
} from "@mui/material";
import React, {
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import {
AutoSizer,
CellMeasurer,
CellMeasurerCache,
List,
} from "react-virtualized";
import _ from "lodash";
import { MyContext, getBaseApiReact } from "../../App";
import { LoadingButton } from "@mui/lab";
import { getBaseApi, getFee } from "../../background";
const cache = new CellMeasurerCache({
fixedWidth: true,
defaultHeight: 50,
});
export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
const { memberGroups, show, setTxList } = useContext(MyContext);
const [groups, setGroups] = useState([]);
const [popoverAnchor, setPopoverAnchor] = useState(null); // Track which list item the popover is anchored to
const [openPopoverIndex, setOpenPopoverIndex] = useState(null); // Track which list item has the popover open
const listRef = useRef();
const [inputValue, setInputValue] = useState("");
const [filteredItems, setFilteredItems] = useState(groups);
const [isLoading, setIsLoading] = useState(false);
const handleFilter = useCallback(
(query) => {
if (query) {
setFilteredItems(
groups.filter((item) =>
item.groupName.toLowerCase().includes(query.toLowerCase())
)
);
} else {
setFilteredItems(groups);
}
},
[groups]
);
const debouncedFilter = useMemo(
() => _.debounce(handleFilter, 500),
[handleFilter]
);
const handleChange = (event) => {
const value = event.target.value;
setInputValue(value);
debouncedFilter(value);
};
const getGroups = async () => {
try {
const response = await fetch(
`${getBaseApiReact()}/groups/?limit=0`
);
const groupData = await response.json();
const filteredGroup = groupData.filter(
(item) => !memberGroups.find((group) => group.groupId === item.groupId)
);
setGroups(filteredGroup);
setFilteredItems(filteredGroup);
} catch (error) {
console.error(error);
}
};
useEffect(() => {
getGroups();
}, [memberGroups]);
const handlePopoverOpen = (event, index) => {
setPopoverAnchor(event.currentTarget);
setOpenPopoverIndex(index);
};
const handlePopoverClose = () => {
setPopoverAnchor(null);
setOpenPopoverIndex(null);
};
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'
})
setIsLoading(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);
}
}
);
});
setIsLoading(false);
} catch (error) {} finally {
setIsLoading(false);
}
};
const rowRenderer = ({ index, key, parent, style }) => {
const group = filteredItems[index];
return (
<CellMeasurer
key={key}
cache={cache}
parent={parent}
columnIndex={0}
rowIndex={index}
>
{({ measure }) => (
<div style={style} onLoad={measure}>
<ListItem disablePadding>
<Popover
open={openPopoverIndex === index}
anchorEl={popoverAnchor}
onClose={handlePopoverClose}
anchorOrigin={{
vertical: "bottom",
horizontal: "center",
}}
transformOrigin={{
vertical: "top",
horizontal: "center",
}}
style={{ marginTop: "8px" }}
>
<Box
sx={{
width: "325px",
height: "250px",
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "10px",
padding: "10px",
}}
>
<Typography>Join {group?.groupName}</Typography>
<Typography>
{group?.isOpen === false &&
"This is a closed/private group, so you will need to wait until an admin accepts your request"}
</Typography>
<LoadingButton
loading={isLoading}
loadingPosition="start"
variant="contained"
onClick={() => handleJoinGroup(group, group?.isOpen)}
>
Join group
</LoadingButton>
</Box>
</Popover>
<ListItemButton
onClick={(event) => handlePopoverOpen(event, index)}
>
<ListItemText
primary={group?.groupName}
secondary={group?.description}
/>
</ListItemButton>
</ListItem>
</div>
)}
</CellMeasurer>
);
};
return (
<div>
<p>Groups list</p>
<TextField
label="Search for Groups"
variant="outlined"
fullWidth
value={inputValue}
onChange={handleChange}
/>
<div
style={{
position: "relative",
height: "500px",
width: "600px",
display: "flex",
flexDirection: "column",
flexShrink: 1,
}}
>
<AutoSizer>
{({ height, width }) => (
<List
ref={listRef}
width={width}
height={height}
rowCount={filteredItems.length}
rowHeight={cache.rowHeight}
rowRenderer={rowRenderer}
deferredMeasurementCache={cache}
/>
)}
</AutoSizer>
</div>
</div>
);
};