added group link, poster, and copy address

This commit is contained in:
PhilReact 2025-01-21 09:08:47 +02:00
parent 459230897a
commit 68e9674058
13 changed files with 420 additions and 86 deletions

View File

@ -124,6 +124,7 @@ import { useHandleUserInfo } from "./components/Group/useHandleUserInfo";
import { Minting } from "./components/Minting/Minting";
import { isRunningGateway } from "./qortalRequests";
import { QMailStatus } from "./components/QMailStatus";
import { GlobalActions } from "./components/GlobalActions/GlobalActions";
type extStates =
| "not-authenticated"
@ -1686,6 +1687,7 @@ function App() {
}}
>
<TaskManger getUserInfo={getUserInfo} />
<GlobalActions memberGroups={memberGroups} />
</MyContext.Provider>
)}
<Spacer height="20px" />

View File

@ -97,6 +97,28 @@ export const MessageDisplay = ({ htmlContent, isReply }) => {
window.electronAPI.openExternal(href);
} else if (target.getAttribute('data-url')) {
const url = target.getAttribute('data-url');
let copyUrl = url
try {
copyUrl = copyUrl.replace(/^(qortal:\/\/)/, '')
if (copyUrl.startsWith('use-')) {
// Handle the new 'use' format
const parts = copyUrl.split('/')
const type = parts[0].split('-')[1] // e.g., 'group' from 'use-group'
parts.shift()
const action = parts.length > 0 ? parts[0].split('-')[1] : null // e.g., 'invite' from 'action-invite'
parts.shift()
const idPrefix = parts.length > 0 ? parts[0].split('-')[0] : null // e.g., 'groupid' from 'groupid-321'
const id = parts.length > 0 ? parts[0].split('-')[1] : null // e.g., '321' from 'groupid-321'
if(action === 'join'){
executeEvent("globalActionJoinGroup", { groupId: id});
return
}
}
} catch (error) {
//error
}
const res = extractComponents(url);
if (res) {
const { service, name, identifier, path } = res;

View File

@ -0,0 +1,10 @@
import React from 'react'
import { JoinGroup } from './JoinGroup'
export const GlobalActions = ({memberGroups}) => {
return (
<>
<JoinGroup memberGroups={memberGroups} />
</>
)
}

View File

@ -0,0 +1,272 @@
import React, { useContext, useEffect, useMemo, useState } from "react";
import { subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
import {
Box,
Button,
ButtonBase,
CircularProgress,
Dialog,
DialogActions,
DialogContent,
Typography,
} from "@mui/material";
import { CustomButton, CustomButtonAccept } from "../../App-styles";
import { getBaseApiReact, MyContext } from "../../App";
import { getFee } from "../../background";
import { CustomizedSnackbars } from "../Snackbar/Snackbar";
import { FidgetSpinner } from "react-loader-spinner";
export const JoinGroup = ({ memberGroups }) => {
const { show, setTxList } = useContext(MyContext);
const [openSnack, setOpenSnack] = useState(false);
const [infoSnack, setInfoSnack] = useState(null);
const [groupInfo, setGroupInfo] = useState(null);
const [isLoadingInfo, setIsLoadingInfo] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const [isLoadingJoinGroup, setIsLoadingJoinGroup] = useState(false);
const handleJoinGroup = async (e) => {
setGroupInfo(null);
const groupId = e?.detail?.groupId;
if (groupId) {
try {
setIsOpen(true);
setIsLoadingInfo(true);
const response = await fetch(`${getBaseApiReact()}/groups/${groupId}`);
const groupData = await response.json();
setGroupInfo(groupData);
} catch (error) {
} finally {
setIsLoadingInfo(false);
}
}
};
useEffect(() => {
subscribeToEvent("globalActionJoinGroup", handleJoinGroup);
return () => {
unsubscribeFromEvent("globalActionJoinGroup", handleJoinGroup);
};
}, []);
const isInGroup = useMemo(()=> {
return !!memberGroups.find((item)=> +item?.groupId === +groupInfo?.groupId)
}, [memberGroups, groupInfo])
const joinGroup = 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);
res(response);
return;
} else {
setInfoSnack({
type: "error",
message: response?.error,
});
setOpenSnack(true);
rej(response.error);
}
}
);
});
setIsLoadingJoinGroup(false);
} catch (error) {
} finally {
setIsLoadingJoinGroup(false);
}
};
return (
<>
<Dialog
open={isOpen}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogContent>
{!groupInfo && (
<Box
sx={{
width: "325px",
height: "150px",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{" "}
<CircularProgress
size={25}
sx={{
color: "white",
}}
/>{" "}
</Box>
)}
<Box
sx={{
width: "325px",
height: "auto",
maxHeight: "400px",
display: !groupInfo ? "none" : "flex",
flexDirection: "column",
alignItems: "center",
gap: "10px",
padding: "10px",
}}
>
<Typography
sx={{
fontSize: "15px",
fontWeight: 600,
}}
>
Group name: {` ${groupInfo?.groupName}`}
</Typography>
<Typography
sx={{
fontSize: "15px",
fontWeight: 600,
}}
>
Number of members: {` ${groupInfo?.memberCount}`}
</Typography>
{groupInfo?.description && (
<Typography
sx={{
fontSize: "15px",
fontWeight: 600,
}}
>
{groupInfo?.description}
</Typography>
)}
{isInGroup && (
<Typography
sx={{
fontSize: "14px",
fontWeight: 600,
}}
>
*You are already in this group!
</Typography>
)}
{!isInGroup && groupInfo?.isOpen === false && (
<Typography
sx={{
fontSize: "14px",
fontWeight: 600,
}}
>
*This is a closed/private group, so you will need to wait until
an admin accepts your request
</Typography>
)}
</Box>
</DialogContent>
<DialogActions>
<ButtonBase onClick={() => {
joinGroup(groupInfo, groupInfo?.isOpen);
setIsOpen(false);
}} disabled={isInGroup}>
<CustomButtonAccept
color="black"
bgColor="var(--green)"
sx={{
minWidth: "102px",
height: "45px",
fontSize: '16px',
opacity: isInGroup ? 0.1 : 1
}}
>
Join
</CustomButtonAccept>
</ButtonBase>
<CustomButtonAccept
color="black"
bgColor="var(--danger)"
sx={{
minWidth: "102px",
height: "45px",
}}
onClick={() => setIsOpen(false)}
>
Close
</CustomButtonAccept>
</DialogActions>
</Dialog>
<CustomizedSnackbars
open={openSnack}
setOpen={setOpenSnack}
info={infoSnack}
setInfo={setInfoSnack}
/>
{isLoadingJoinGroup && (
<Box
sx={{
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<FidgetSpinner
visible={true}
height="80"
width="80"
ariaLabel="fidget-spinner-loading"
wrapperStyle={{}}
wrapperClass="fidget-spinner-wrapper"
/>
</Box>
)}
</>
);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,6 +1,12 @@
import React, { useCallback, useEffect, useState } from "react";
import { saveToLocalStorage } from "../Apps/AppsNavBar";
import creationImg from './img/creation.webp'
import dashboardImg from './img/dashboard.webp'
import groupsImg from './img/groups.webp'
import importantImg from './img/important.webp'
import navigationImg from './img/navigation.webp'
import overviewImg from './img/overview.webp'
import startedImg from './img/started.webp'
const checkIfGatewayIsOnline = async () => {
try {
@ -71,6 +77,7 @@ useEffect(()=> {
name: "a-test",
service: "VIDEO",
identifier: "account-creation-hub",
poster: creationImg
},
});
}
@ -86,6 +93,7 @@ useEffect(()=> {
name: "a-test",
service: "VIDEO",
identifier: "important-information-hub",
poster: importantImg
},
});
}
@ -104,6 +112,7 @@ useEffect(()=> {
name: "a-test",
service: "VIDEO",
identifier: "getting-started-hub",
poster: startedImg
},
},
{
@ -112,6 +121,7 @@ useEffect(()=> {
name: "a-test",
service: "VIDEO",
identifier: "overview-hub",
poster: overviewImg
},
},
{
@ -120,6 +130,7 @@ useEffect(()=> {
name: "a-test",
service: "VIDEO",
identifier: "groups-hub",
poster: groupsImg
},
},
],
@ -139,6 +150,7 @@ useEffect(()=> {
name: "a-test",
service: "VIDEO",
identifier: "apps-dashboard-hub",
poster: dashboardImg
},
},
{
@ -147,9 +159,9 @@ useEffect(()=> {
name: "a-test",
service: "VIDEO",
identifier: "apps-navigation-hub",
poster: navigationImg
},
}
],
});
}

View File

@ -80,7 +80,8 @@ export const WrapperUserAction = ({ children, address, name, disabled }) => {
}, 200);
}}
sx={{
color: 'white'
color: 'white',
justifyContent: 'flex-start'
}}
>
Message
@ -98,11 +99,26 @@ export const WrapperUserAction = ({ children, address, name, disabled }) => {
}}
sx={{
color: 'white'
color: 'white',
justifyContent: 'flex-start'
}}
>
Send QORT
</Button>
<Button
variant="text"
onClick={() => {
navigator.clipboard.writeText(address|| "");
handleClose();
}}
sx={{
color: 'white',
justifyContent: 'flex-start'
}}
>
Copy address
</Button>
</Box>
</Popover>
</>