Qortal Dev
2 weeks ago
14 changed files with 924 additions and 154 deletions
@ -0,0 +1,56 @@
|
||||
import { |
||||
FormControl, |
||||
InputLabel, |
||||
MenuItem, |
||||
OutlinedInput, |
||||
Select, |
||||
} from "@mui/material"; |
||||
import { SxProps } from "@mui/system"; |
||||
import { signal, Signal } from "@preact/signals-react"; |
||||
import { useSignals } from "@preact/signals-react/runtime"; |
||||
import React, { useState } from "react"; |
||||
|
||||
interface SelectFieldProps { |
||||
options: string[]; |
||||
value: Signal<string>; |
||||
label: string; |
||||
sx?: SxProps; |
||||
} |
||||
export const SelectField = ({ |
||||
options, |
||||
value, |
||||
label, |
||||
sx = {}, |
||||
}: SelectFieldProps) => { |
||||
useSignals(); |
||||
|
||||
return ( |
||||
<FormControl fullWidth> |
||||
<InputLabel |
||||
sx={{ |
||||
fontSize: "100%", |
||||
color: "rgba(84, 84, 84, 0.70)", |
||||
}} |
||||
id={label} |
||||
> |
||||
{label} |
||||
</InputLabel> |
||||
<Select |
||||
fullWidth |
||||
labelId={label} |
||||
value={value.value || ""} |
||||
variant={"standard"} |
||||
onChange={e => { |
||||
value.value = e.target.value; |
||||
}} |
||||
sx={{ color: "black", ...sx }} |
||||
> |
||||
{options.map(option => ( |
||||
<MenuItem key={option} value={option}> |
||||
{option} |
||||
</MenuItem> |
||||
))} |
||||
</Select> |
||||
</FormControl> |
||||
); |
||||
}; |
@ -1 +1,4 @@
|
||||
export const appOwner = "Q-Mintership"; |
||||
|
||||
const maxSizeMB = 25; |
||||
export const maxPrivateFileSize = maxSizeMB * 1024 * 1024; |
||||
|
@ -0,0 +1,130 @@
|
||||
import AddIcon from "@mui/icons-material/Add"; |
||||
import RemoveIcon from "@mui/icons-material/Remove"; |
||||
import { |
||||
Box, |
||||
Button, |
||||
IconButton, |
||||
MenuItem, |
||||
OutlinedInput, |
||||
Select, |
||||
SelectChangeEvent, |
||||
} from "@mui/material"; |
||||
import { styled } from "@mui/material/styles"; |
||||
import { signal, Signal } from "@preact/signals-react"; |
||||
import { useSignals } from "@preact/signals-react/runtime"; |
||||
import React, { useEffect } from "react"; |
||||
import ShortUniqueId from "short-unique-id"; |
||||
import { SelectField } from "../../components/common/SelectField"; |
||||
import { NewMessageInputRow } from "../Home/Home-styles"; |
||||
import { GroupPermissions, GroupPermissionType } from "./Forum"; |
||||
import { QmailTextField } from "./QmailTextField"; |
||||
|
||||
export interface Group { |
||||
id: Signal<string>; |
||||
name: string; |
||||
permissions: Signal<GroupPermissionType>; |
||||
} |
||||
export interface GroupPermissionsFormProps { |
||||
groups: Signal<Group[]>; |
||||
} |
||||
export const GroupPermissionsForm = ({ groups }: GroupPermissionsFormProps) => { |
||||
useSignals(); |
||||
|
||||
const uid = new ShortUniqueId(); |
||||
const newGroup = { |
||||
id: signal<string>(""), |
||||
name: "", |
||||
permissions: signal<GroupPermissionType>("Read"), |
||||
} as Group; |
||||
const addGroup = () => { |
||||
groups.value = [...groups.value, newGroup]; |
||||
}; |
||||
|
||||
const removeGroup = (groupIndex: number) => { |
||||
if (groups.value.length > 1) |
||||
groups.value = groups.value.filter( |
||||
(group, index) => index !== groupIndex |
||||
); |
||||
else groups.value = [newGroup]; |
||||
}; |
||||
|
||||
const buttonStyle = { |
||||
width: "70px", |
||||
height: "70px", |
||||
}; |
||||
|
||||
const StyledIconButton = styled(IconButton)(` |
||||
width: 60px; |
||||
height: 60px; |
||||
border-radius: 4px; |
||||
&:hover { |
||||
background-color: #cccdd0; |
||||
} |
||||
`);
|
||||
|
||||
const iconStyle = { fontSize: 50, color: "#2e3d60" }; |
||||
const options = ["Read", "Write"]; |
||||
|
||||
return ( |
||||
<Box |
||||
sx={{ |
||||
display: "flex", |
||||
|
||||
width: "100%", |
||||
flexDirection: "column", |
||||
alignItems: "end", |
||||
}} |
||||
> |
||||
{groups.value.map((group, index) => ( |
||||
<NewMessageInputRow |
||||
sx={{ |
||||
height: "80px", |
||||
width: "100%", |
||||
display: "grid", |
||||
gridTemplateColumns: "1fr 1fr", |
||||
alignItems: "end", |
||||
}} |
||||
key={uid()} |
||||
> |
||||
<Box> |
||||
<StyledIconButton |
||||
onClick={addGroup} |
||||
sx={{ |
||||
visibility: |
||||
index === groups.value.length - 1 ? "visible" : "hidden", |
||||
}} |
||||
> |
||||
<AddIcon sx={iconStyle} /> |
||||
</StyledIconButton> |
||||
|
||||
<StyledIconButton onClick={() => removeGroup(index)}> |
||||
<RemoveIcon sx={{ ...iconStyle, fontSize: 50 }} /> |
||||
</StyledIconButton> |
||||
<QmailTextField |
||||
value={group.id} |
||||
label={"Group ID"} |
||||
filter={/[^0-9]/} |
||||
sx={{ |
||||
width: "50%", |
||||
height: "70px", |
||||
borderBottom: "1px solid gray", |
||||
}} |
||||
maxLength={10} |
||||
/> |
||||
</Box> |
||||
|
||||
<SelectField |
||||
options={options} |
||||
value={group.permissions} |
||||
label={"Group Permissions"} |
||||
sx={{ |
||||
"& .MuiSvgIcon-root": { |
||||
color: "gray", |
||||
}, |
||||
}} |
||||
/> |
||||
</NewMessageInputRow> |
||||
))} |
||||
</Box> |
||||
); |
||||
}; |
@ -0,0 +1,289 @@
|
||||
import { ReadonlySignal } from "@preact/signals-react"; |
||||
import { ATTATCHMENT_BASE, THREAD_BASE } from "../../constants/Identifiers"; |
||||
import { |
||||
MAIL_ATTACHMENT_SERVICE_TYPE, |
||||
MAIL_SERVICE_TYPE, |
||||
THREAD_SERVICE_TYPE, |
||||
} from "../../constants/mail"; |
||||
import { setNotification } from "../../state/features/notificationsSlice"; |
||||
import { store } from "../../state/store"; |
||||
import { getGroup } from "../../utils/QortalRequests"; |
||||
import { objectToBase64, toBase64 } from "../../utils/toBase64"; |
||||
import { Group } from "./GroupPermissionsForm"; |
||||
import { NewForumModalData } from "./NewForumModal"; |
||||
|
||||
const getGroupNames = async (groups: Group[]) => { |
||||
const groupPromises = groups.map(group => getGroup(group.id.value)); |
||||
return await Promise.all(groupPromises); |
||||
}; |
||||
|
||||
const verifyData = async (formData: NewForumModalData) => { |
||||
const { name, title, encryption, groups, description } = formData; |
||||
|
||||
let errorMsg = ""; |
||||
if (!name) errorMsg = "Cannot send a message without a access to your name"; |
||||
if (!title) errorMsg = "Forum title is empty"; |
||||
if (!encryption) errorMsg = "Encryption Type is empty"; |
||||
if (!description) errorMsg = "Description is empty"; |
||||
if (groups.filter(group => !!group.id).length < groups.length) |
||||
errorMsg = "A group has an empty ID"; |
||||
if (groups.filter(group => !!group.permissions).length < groups.length) |
||||
errorMsg = "A group has an empty permissions"; |
||||
|
||||
const groupsWithNames = await getGroupNames(groups); |
||||
|
||||
if (groupsWithNames.filter(group => !!group.groupName).length < groups.length) |
||||
errorMsg = "A group doesn't exist"; |
||||
|
||||
// if (!groupInfo) {
|
||||
// errorMsg = "Cannot access group information";
|
||||
// }
|
||||
//
|
||||
// // if (!description) missingFields.push('subject')
|
||||
// if (missingFields.length > 0) {
|
||||
// const missingFieldsString = missingFields.join(", ");
|
||||
// const errMsg = `Missing: ${missingFieldsString}`;
|
||||
// errorMsg = errMsg;
|
||||
// }
|
||||
// const noExtension = attachments.filter(item => !item.extension);
|
||||
// if (noExtension.length > 0) {
|
||||
// errorMsg =
|
||||
// "One of your attachments does not have an extension (example: .png, .pdf, ect...)";
|
||||
// }
|
||||
//
|
||||
return errorMsg; |
||||
}; |
||||
export const publishForum = async (formData: NewForumModalData) => { |
||||
const { name, title, encryption, groups, description } = formData; |
||||
const errorMsg = await verifyData(formData); |
||||
try { |
||||
if (errorMsg) { |
||||
store.dispatch( |
||||
setNotification({ |
||||
msg: errorMsg, |
||||
alertType: "error", |
||||
}) |
||||
); |
||||
throw new Error(errorMsg); |
||||
} |
||||
} catch (error) { |
||||
console.log(error); |
||||
} |
||||
debugger; |
||||
|
||||
//
|
||||
// const mailObject: any = {
|
||||
// subject,
|
||||
// createdAt: Date.now(),
|
||||
// version: 1,
|
||||
// attachments,
|
||||
// textContentV2: value,
|
||||
// name,
|
||||
// threadOwner: currentThread?.threadData?.name || name,
|
||||
// };
|
||||
//
|
||||
// try {
|
||||
// const groupPublicKeys = Object.keys(members)?.map(
|
||||
// (key: any) => members[key]?.publicKey
|
||||
// );
|
||||
// if (!groupPublicKeys || groupPublicKeys?.length === 0) {
|
||||
// throw new Error("No members in this group could be found");
|
||||
// }
|
||||
//
|
||||
// // START OF ATTACHMENT LOGIC
|
||||
//
|
||||
// const attachmentArray: any[] = [];
|
||||
// for (const singleAttachment of attachments) {
|
||||
// const attachment = singleAttachment.file;
|
||||
//
|
||||
// const fileBase64 = await toBase64(attachment);
|
||||
// if (typeof fileBase64 !== "string" || !fileBase64)
|
||||
// throw new Error("Could not convert file to base64");
|
||||
// const base64String = fileBase64.split(",")[1];
|
||||
//
|
||||
// const id = uid();
|
||||
// const id2 = uid();
|
||||
// const identifier = `${ATTATCHMENT_BASE}${id}_${id2}`;
|
||||
// let fileExtension = attachment?.name?.split(".")?.pop();
|
||||
// if (!fileExtension) {
|
||||
// fileExtension = singleAttachment.extension;
|
||||
// }
|
||||
// const obj = {
|
||||
// name: name,
|
||||
// service: MAIL_ATTACHMENT_SERVICE_TYPE,
|
||||
// filename: `${id}.${fileExtension}`,
|
||||
// originalFilename: attachment?.name || "",
|
||||
// identifier,
|
||||
// data64: base64String,
|
||||
// type: attachment?.type,
|
||||
// };
|
||||
//
|
||||
// attachmentArray.push(obj);
|
||||
// }
|
||||
//
|
||||
// if (attachmentArray?.length > 0) {
|
||||
// mailObject.attachments = attachmentArray.map(item => {
|
||||
// return {
|
||||
// identifier: item.identifier,
|
||||
// name,
|
||||
// service: MAIL_ATTACHMENT_SERVICE_TYPE,
|
||||
// filename: item.filename,
|
||||
// originalFilename: item.originalFilename,
|
||||
// type: item?.type,
|
||||
// };
|
||||
// });
|
||||
//
|
||||
// // const multiplePublish = {
|
||||
// // action: "PUBLISH_MULTIPLE_QDN_RESOURCES",
|
||||
// // resources: [...attachmentArray],
|
||||
// // encrypt: true,
|
||||
// // publicKeys: groupPublicKeys,
|
||||
// // };
|
||||
// // await qortalRequest(multiplePublish);
|
||||
// }
|
||||
//
|
||||
// //END OF ATTACHMENT LOGIC
|
||||
// if (!isMessage) {
|
||||
// const idThread = uid();
|
||||
// const messageToBase64 = await objectToBase64(mailObject);
|
||||
// const threadObject = {
|
||||
// title: threadTitle,
|
||||
// groupId: groupInfo.id,
|
||||
// createdAt: Date.now(),
|
||||
// name,
|
||||
// };
|
||||
// const threadToBase64 = await objectToBase64(threadObject);
|
||||
// let identifierThread = `${THREAD_BASE}${groupInfo.id}_${idThread}`;
|
||||
// let requestBodyThread: any = {
|
||||
// name: name,
|
||||
// service: THREAD_SERVICE_TYPE,
|
||||
// data64: threadToBase64,
|
||||
// identifier: identifierThread,
|
||||
// description: threadTitle?.slice(0, 200),
|
||||
// action: "PUBLISH_QDN_RESOURCE",
|
||||
// };
|
||||
// const idMsg = uid();
|
||||
// let groupIndex = identifierThread.indexOf("group");
|
||||
// let result = identifierThread.substring(groupIndex);
|
||||
// let identifier = `qortal_qmail_thmsg_${result}_${idMsg}`;
|
||||
// let requestBody: any = {
|
||||
// name: name,
|
||||
// service: MAIL_SERVICE_TYPE,
|
||||
// data64: messageToBase64,
|
||||
// identifier,
|
||||
// };
|
||||
// const multiplePublishMsg = {
|
||||
// action: "PUBLISH_MULTIPLE_QDN_RESOURCES",
|
||||
// resources: [requestBody, ...attachmentArray],
|
||||
// encrypt: true,
|
||||
// publicKeys: groupPublicKeys,
|
||||
// };
|
||||
// await qortalRequest(requestBodyThread);
|
||||
// setPublishes(multiplePublishMsg);
|
||||
// setIsOpenMultiplePublish(true);
|
||||
// // await qortalRequest(multiplePublishMsg);
|
||||
// // dispatch(
|
||||
// // setNotification({
|
||||
// // msg: "Message sent",
|
||||
// // alertType: "success",
|
||||
// // })
|
||||
// // );
|
||||
// if (threadCallback) {
|
||||
// // threadCallback({
|
||||
// // threadData: threadObject,
|
||||
// // threadOwner: name,
|
||||
// // name,
|
||||
// // threadId: identifierThread,
|
||||
// // created: Date.now(),
|
||||
// // service: 'MAIL_PRIVATE',
|
||||
// // identifier: identifier
|
||||
// // })
|
||||
// setCallbackContent({
|
||||
// thread: {
|
||||
// threadData: threadObject,
|
||||
// threadOwner: name,
|
||||
// name,
|
||||
// threadId: identifierThread,
|
||||
// created: Date.now(),
|
||||
// service: "MAIL_PRIVATE",
|
||||
// identifier: identifier,
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
// closeModal();
|
||||
// } else {
|
||||
// if (!currentThread) throw new Error("unable to locate thread Id");
|
||||
// const idThread = currentThread.threadId;
|
||||
// const messageToBase64 = await objectToBase64(mailObject);
|
||||
// const idMsg = uid();
|
||||
// let groupIndex = idThread.indexOf("group");
|
||||
// let result = idThread.substring(groupIndex);
|
||||
// let identifier = `qortal_qmail_thmsg_${result}_${idMsg}`;
|
||||
// let requestBody: any = {
|
||||
// name: name,
|
||||
// service: MAIL_SERVICE_TYPE,
|
||||
// data64: messageToBase64,
|
||||
// identifier,
|
||||
// };
|
||||
// const multiplePublishMsg = {
|
||||
// action: "PUBLISH_MULTIPLE_QDN_RESOURCES",
|
||||
// resources: [requestBody, ...attachmentArray],
|
||||
// encrypt: true,
|
||||
// publicKeys: groupPublicKeys,
|
||||
// };
|
||||
// setPublishes(multiplePublishMsg);
|
||||
// setIsOpenMultiplePublish(true);
|
||||
// // await qortalRequest(multiplePublishMsg);
|
||||
// // dispatch(
|
||||
// // setNotification({
|
||||
// // msg: "Message sent",
|
||||
// // alertType: "success",
|
||||
// // })
|
||||
// // );
|
||||
// if (messageCallback) {
|
||||
// setCallbackContent({
|
||||
// message: {
|
||||
// identifier,
|
||||
// id: identifier,
|
||||
// name,
|
||||
// service: MAIL_SERVICE_TYPE,
|
||||
// created: Date.now(),
|
||||
// ...mailObject,
|
||||
// },
|
||||
// });
|
||||
// // messageCallback({
|
||||
// // identifier,
|
||||
// // id: identifier,
|
||||
// // name,
|
||||
// // service: MAIL_SERVICE_TYPE,
|
||||
// // created: Date.now(),
|
||||
// // ...mailObject,
|
||||
// // });
|
||||
// }
|
||||
//
|
||||
// closeModal();
|
||||
// }
|
||||
// } catch (error: any) {
|
||||
// let notificationObj = null;
|
||||
// if (typeof error === "string") {
|
||||
// notificationObj = {
|
||||
// msg: error || "Failed to send message",
|
||||
// alertType: "error",
|
||||
// };
|
||||
// } else if (typeof error?.error === "string") {
|
||||
// notificationObj = {
|
||||
// msg: error?.error || "Failed to send message",
|
||||
// alertType: "error",
|
||||
// };
|
||||
// } else {
|
||||
// notificationObj = {
|
||||
// msg: error?.message || "Failed to send message",
|
||||
// alertType: "error",
|
||||
// };
|
||||
// }
|
||||
// if (!notificationObj) return;
|
||||
// dispatch(setNotification(notificationObj));
|
||||
//
|
||||
// throw new Error("Failed to send message");
|
||||
// }
|
||||
}; |
@ -0,0 +1,211 @@
|
||||
import CloseIcon from "@mui/icons-material/Close"; |
||||
import { Box, Input, Typography } from "@mui/material"; |
||||
import { |
||||
ReadonlySignal, |
||||
Signal, |
||||
signal, |
||||
useComputed, |
||||
useSignal, |
||||
useSignalEffect, |
||||
} from "@preact/signals-react"; |
||||
import { useSignals } from "@preact/signals-react/runtime"; |
||||
import mime from "mime"; |
||||
import React, { useState } from "react"; |
||||
import { useDropzone } from "react-dropzone"; |
||||
import { useDispatch, useSelector } from "react-redux"; |
||||
import { useNavigate } from "react-router-dom"; |
||||
import ComposeIconSVG from "../../assets/svgs/ComposeIcon.svg"; |
||||
import { CreateThreadIcon } from "../../assets/svgs/CreateThreadIcon"; |
||||
import ModalCloseSVG from "../../assets/svgs/ModalClose.svg"; |
||||
import AttachmentSVG from "../../assets/svgs/NewMessageAttachment.svg"; |
||||
import { SendNewMessage } from "../../assets/svgs/SendNewMessage"; |
||||
import { SelectField } from "../../components/common/SelectField"; |
||||
import { Spacer } from "../../components/common/Spacer"; |
||||
import { TextEditor } from "../../components/common/TextEditor/TextEditor"; |
||||
import { ReusableModal } from "../../components/modals/ReusableModal"; |
||||
import { useTestIdentifiers } from "../../constants/Identifiers"; |
||||
import { appOwner, maxPrivateFileSize } from "../../constants/Misc"; |
||||
import { setNotification } from "../../state/features/notificationsSlice"; |
||||
import { RootState } from "../../state/store"; |
||||
import { formatBytes } from "../../utils/displaySize"; |
||||
import { getFileExtension } from "../../utils/helpers"; |
||||
import { |
||||
AttachmentContainer, |
||||
CloseContainer, |
||||
ComposeContainer, |
||||
ComposeIcon, |
||||
ComposeP, |
||||
InstanceContainer, |
||||
InstanceFooter, |
||||
InstanceListContainer, |
||||
InstanceListHeader, |
||||
NewMessageAttachmentImg, |
||||
NewMessageCloseImg, |
||||
NewMessageHeaderP, |
||||
NewMessageInputRow, |
||||
NewMessageSendButton, |
||||
NewMessageSendP, |
||||
} from "../Home/Home-styles"; |
||||
import { GroupPermissionType } from "./Forum"; |
||||
import { Group, GroupPermissionsForm } from "./GroupPermissionsForm"; |
||||
import { publishForum } from "./NewForumModal-data"; |
||||
import { QmailTextField } from "./QmailTextField"; |
||||
|
||||
export type EncryptionType = "None" | "Group" | "GroupAdmin"; |
||||
export type NewForumModalData = { |
||||
name: string | undefined; |
||||
title: string; |
||||
encryption: "None" | "Group" | "GroupAdmin" | ""; |
||||
groups: Group[]; |
||||
description: string; |
||||
}; |
||||
|
||||
export const NewForumModal = () => { |
||||
useSignals(); |
||||
const navigate = useNavigate(); |
||||
const isOpen = useSignal<boolean>(false); |
||||
|
||||
const forumTitle = useSignal<string>(""); |
||||
const description = useSignal<string>(""); |
||||
|
||||
const selectedEncryptionType = useSignal<EncryptionType | "">("None"); |
||||
const formData = useComputed(() => { |
||||
return { |
||||
name: user?.name, |
||||
title: forumTitle.value, |
||||
encryption: selectedEncryptionType.value, |
||||
groups: groups.value, |
||||
description: description.value, |
||||
}; |
||||
}); |
||||
|
||||
const { user } = useSelector((state: RootState) => state.auth); |
||||
|
||||
// const dispatch = useDispatch();
|
||||
|
||||
const closeModal = () => { |
||||
forumTitle.value = ""; |
||||
description.value = ""; |
||||
isOpen.value = false; |
||||
}; |
||||
|
||||
const groups = signal<Group[]>([ |
||||
{ |
||||
id: signal<string>(""), |
||||
name: "", |
||||
permissions: signal<GroupPermissionType>("Read"), |
||||
}, |
||||
]); |
||||
return ( |
||||
<Box |
||||
sx={{ |
||||
display: "flex", |
||||
}} |
||||
> |
||||
<InstanceContainer> |
||||
{(user?.name === appOwner || useTestIdentifiers) && ( |
||||
<ComposeContainer onClick={e => (isOpen.value = true)}> |
||||
<ComposeIcon src={ComposeIconSVG} /> |
||||
<ComposeP>{"New Forum"}</ComposeP> |
||||
</ComposeContainer> |
||||
)} |
||||
<ComposeContainer onClick={e => navigate("/sponsorshipData")}> |
||||
<ComposeIcon src={ComposeIconSVG} /> |
||||
<ComposeP>{"Sponsorship Data"}</ComposeP> |
||||
</ComposeContainer> |
||||
</InstanceContainer> |
||||
<ReusableModal |
||||
open={isOpen.value} |
||||
customStyles={{ |
||||
maxHeight: "95vh", |
||||
maxWidth: "950px", |
||||
height: "700px", |
||||
borderRadius: "12px 12px 0px 0px", |
||||
background: "var(--Mail-Background, #313338)", |
||||
padding: "0px", |
||||
gap: "0px", |
||||
}} |
||||
> |
||||
<InstanceListHeader |
||||
sx={{ |
||||
backgroundColor: "unset", |
||||
height: "50px", |
||||
padding: "20px 42px", |
||||
flexDirection: "row", |
||||
justifyContent: "space-between", |
||||
alignItems: "center", |
||||
}} |
||||
> |
||||
<NewMessageHeaderP>{"New Forum"}</NewMessageHeaderP> |
||||
<CloseContainer onClick={closeModal}> |
||||
<NewMessageCloseImg src={ModalCloseSVG} /> |
||||
</CloseContainer> |
||||
</InstanceListHeader> |
||||
<InstanceListContainer |
||||
sx={{ |
||||
backgroundColor: "rgba(217, 217, 217, 1)", |
||||
padding: "20px 42px", |
||||
height: "calc(100% - 150px)", |
||||
flexShrink: 0, |
||||
}} |
||||
> |
||||
<NewMessageInputRow sx={{ height: "80px", alignItems: "end" }}> |
||||
<QmailTextField |
||||
value={forumTitle} |
||||
label={"Forum Title"} |
||||
sx={{ |
||||
height: "60px", |
||||
borderBottom: "1px solid gray", |
||||
}} |
||||
maxLength={30} |
||||
/> |
||||
<SelectField |
||||
options={["None", "Group", "GroupAdmin"]} |
||||
label={"Encryption Type"} |
||||
value={selectedEncryptionType} |
||||
sx={{ |
||||
"& .MuiSvgIcon-root": { |
||||
color: "gray", |
||||
}, |
||||
}} |
||||
/> |
||||
</NewMessageInputRow> |
||||
<GroupPermissionsForm groups={groups} /> |
||||
<Spacer height="40px" /> |
||||
<Box |
||||
sx={{ |
||||
maxHeight: "40vh", |
||||
}} |
||||
> |
||||
<p style={{ color: "black" }}> Description </p> |
||||
<TextEditor |
||||
inlineContent={description.value} |
||||
setInlineContent={(val: any) => { |
||||
description.value = val; |
||||
}} |
||||
/> |
||||
</Box> |
||||
</InstanceListContainer> |
||||
<InstanceFooter |
||||
sx={{ |
||||
backgroundColor: "rgba(217, 217, 217, 1)", |
||||
padding: "20px 42px", |
||||
alignItems: "center", |
||||
height: "90px", |
||||
}} |
||||
> |
||||
<NewMessageSendButton onClick={() => publishForum(formData.value)}> |
||||
<NewMessageSendP>{"Create Forum"}</NewMessageSendP> |
||||
|
||||
<CreateThreadIcon |
||||
color="red" |
||||
opacity={1} |
||||
height="25px" |
||||
width="25px" |
||||
/> |
||||
</NewMessageSendButton> |
||||
</InstanceFooter> |
||||
</ReusableModal> |
||||
</Box> |
||||
); |
||||
}; |
@ -0,0 +1,58 @@
|
||||
import { Input } from "@mui/material"; |
||||
import { SxProps } from "@mui/system"; |
||||
import { Signal, useSignalEffect } from "@preact/signals-react"; |
||||
import { useSignals } from "@preact/signals-react/runtime"; |
||||
import React from "react"; |
||||
|
||||
interface QmailTextFieldProps { |
||||
value: Signal<string>; |
||||
label: string; |
||||
sx?: SxProps; |
||||
filter?: RegExp; |
||||
maxLength?: number; |
||||
} |
||||
export const QmailTextField = ({ |
||||
value, |
||||
label, |
||||
sx = {}, |
||||
filter, |
||||
maxLength = 60, |
||||
}: QmailTextFieldProps) => { |
||||
useSignals(); |
||||
useSignalEffect(() => { |
||||
if (filter) value.value = value.value.replace(filter, ""); |
||||
}); |
||||
|
||||
return ( |
||||
<> |
||||
<Input |
||||
id="standard-adornment-name" |
||||
value={value.value} |
||||
onChange={e => { |
||||
if (e.target.value.length <= maxLength) value.value = e.target.value; |
||||
}} |
||||
placeholder={label} |
||||
disableUnderline |
||||
autoComplete="off" |
||||
autoCorrect="off" |
||||
sx={{ |
||||
width: "100%", |
||||
color: "black", |
||||
"& .MuiInput-input::placeholder": { |
||||
color: "rgba(84, 84, 84, 0.70) !important", |
||||
fontSize: "100%", |
||||
fontStyle: "normal", |
||||
fontWeight: 400, |
||||
lineHeight: "120%", // 24px
|
||||
letterSpacing: "0.15px", |
||||
opacity: 1, |
||||
}, |
||||
"&:focus": { |
||||
outline: "none", |
||||
}, |
||||
...sx, |
||||
}} |
||||
/> |
||||
</> |
||||
); |
||||
}; |
@ -0,0 +1,27 @@
|
||||
export interface GroupData { |
||||
groupId: number; |
||||
owner: string; |
||||
groupName: string; |
||||
description: string; |
||||
created: number; |
||||
isOpen: boolean; |
||||
approvalThreshold: string; |
||||
minimumBlockDelay: number; |
||||
maximumBlockDelay: number; |
||||
memberCount: number; |
||||
} |
||||
|
||||
export const listGroups = async () => { |
||||
return (await qortalRequest({ action: "LIST_GROUPS" })) as GroupData[]; |
||||
}; |
||||
|
||||
export const getGroup = async (groupID: number | string) => { |
||||
const url = `/groups/${groupID.toString()}`; |
||||
const response = await fetch(url, { |
||||
method: "GET", |
||||
headers: { |
||||
"Content-Type": "application/json", |
||||
}, |
||||
}); |
||||
return (await response.json()) as GroupData; |
||||
}; |
Loading…
Reference in new issue