From a04c38ce6fe7c287942651364b87ef01b1435914 Mon Sep 17 00:00:00 2001
From: Megha-Dev-19 <100185149+Megha-Dev-19@users.noreply.github.com>
Date: Wed, 10 Apr 2024 07:31:53 +0530
Subject: [PATCH] Proposal Notifications support (#167)
* make vote notification optional
* added notification for proposal
* update file names
* Update Proposals.jsx
---------
Co-authored-by: Elliot Braem <16282460+elliotBraem@users.noreply.github.com>
---
.../widget/Notification/Item/Left.jsx | 9 +
.../widget/Notification/Item/Right.jsx | 24 +++
.../widget/Notification/Item/buildhub.jsx | 22 +++
.../NotificationRolesSelector.jsx | 173 ++++++++++++++++++
apps/builddao/widget/Proposals.jsx | 64 +++----
.../components/modals/propose/AddMember.jsx | 19 +-
.../modals/propose/FunctionCall.jsx | 18 +-
.../modals/propose/RemoveMember.jsx | 19 +-
.../widget/components/modals/propose/Text.jsx | 19 +-
.../components/modals/propose/Transfer.jsx | 23 ++-
10 files changed, 340 insertions(+), 50 deletions(-)
create mode 100644 apps/builddao/widget/Notification/Item/Left.jsx
create mode 100644 apps/builddao/widget/Notification/Item/Right.jsx
create mode 100644 apps/builddao/widget/Notification/Item/buildhub.jsx
create mode 100644 apps/builddao/widget/Notification/NotificationRolesSelector.jsx
diff --git a/apps/builddao/widget/Notification/Item/Left.jsx b/apps/builddao/widget/Notification/Item/Left.jsx
new file mode 100644
index 00000000..ea3c7e3e
--- /dev/null
+++ b/apps/builddao/widget/Notification/Item/Left.jsx
@@ -0,0 +1,9 @@
+const { href } = VM.require("buildhub.near/widget/lib.url") || {
+ href: () => {}
+};
+
+if (!props.type) {
+ return "Loading ...";
+}
+
+return <>{props.message}>;
diff --git a/apps/builddao/widget/Notification/Item/Right.jsx b/apps/builddao/widget/Notification/Item/Right.jsx
new file mode 100644
index 00000000..4c941075
--- /dev/null
+++ b/apps/builddao/widget/Notification/Item/Right.jsx
@@ -0,0 +1,24 @@
+const { href } = VM.require("buildhub.near/widget/lib.url") || {
+ href: () => {}
+};
+
+if (!props.type) {
+ return "Loading ...";
+}
+
+return (
+
+ View
+
+);
diff --git a/apps/builddao/widget/Notification/Item/buildhub.jsx b/apps/builddao/widget/Notification/Item/buildhub.jsx
new file mode 100644
index 00000000..058712ed
--- /dev/null
+++ b/apps/builddao/widget/Notification/Item/buildhub.jsx
@@ -0,0 +1,22 @@
+const { value } = props;
+
+return (
+
+ ),
+ R: (
+
+ ),
+ ...props
+ }}
+ />
+);
diff --git a/apps/builddao/widget/Notification/NotificationRolesSelector.jsx b/apps/builddao/widget/Notification/NotificationRolesSelector.jsx
new file mode 100644
index 00000000..5d96449a
--- /dev/null
+++ b/apps/builddao/widget/Notification/NotificationRolesSelector.jsx
@@ -0,0 +1,173 @@
+const DaoSDK = VM.require("sdks.near/widget/SDKs.Sputnik.DaoSDK");
+const { InputField } = VM.require("buildhub.near/widget/components") || {
+ InputField: <>>
+};
+
+if (!DaoSDK) {
+ return <>>;
+}
+const [groupsAndMembers, setGroupsAndMembers] = useState([]);
+const [selectedRoles, setSelectedRoles] = useState({}); // { role:boolean }
+const daoId = props.daoId || "build.sputnik-dao.near";
+const accountId = props.accountId ?? context.accountId;
+const onUpdate = props.onUpdate ?? (() => {});
+const proposalType = props.proposalType;
+const [message, setMessage] = useState(
+ `${accountId} created ${proposalType} proposal for ${daoId}`
+);
+const bootstrapTheme = props.bootstrapTheme || "dark";
+
+const sdk = DaoSDK(daoId);
+
+const group = sdk.getGroupsAndMembers();
+if (group === null || !group.length) {
+ return;
+}
+setGroupsAndMembers(group);
+
+const handleCheckboxChange = (role) => {
+ setSelectedRoles((prevRoles) => {
+ if (prevRoles.hasOwnProperty(role)) {
+ return {
+ ...prevRoles,
+ [role]: !prevRoles[role]
+ };
+ } else {
+ return {
+ ...prevRoles,
+ [role]: true
+ };
+ }
+ });
+};
+
+const ThemeContainer =
+ props.ThemeContainer ||
+ styled.div`
+ --primary-color: rgb(255, 175, 81);
+ `;
+
+const Wrapper = styled.div`
+ .checked > span:first-child {
+ background: var(--primary-color) !important;
+ border-color: var(--primary-color) !important;
+ }
+
+ .cbx:hover span:first-child {
+ border-color: var(--primary-color) !important;
+ }
+
+ button[type="checkbox"]:hover {
+ background: none !important;
+ }
+
+ label {
+ font-size: 13px;
+ }
+`;
+
+const createNotificationsData = () => {
+ const someRoleSelected = Object.values(selectedRoles).some(
+ (value) => value === true
+ );
+ if (!someRoleSelected) {
+ return null;
+ }
+ const membersToNotify = [];
+ Object.keys(selectedRoles).map((item) => {
+ if (selectedRoles[item] === true) {
+ membersToNotify = membersToNotify.concat(
+ groupsAndMembers.find((group) => group.name === item).members
+ );
+ }
+ });
+ const uniqueMembersArray = [...new Set(membersToNotify)];
+ const notification = {
+ [accountId]: {
+ index: {
+ notify: JSON.stringify(
+ uniqueMembersArray.map((account) => {
+ return {
+ key: account,
+ value: {
+ message: message,
+ params: {
+ daoId: daoId,
+ tab: "proposals",
+ page: "proposal"
+ },
+ type: "buildhub/custom",
+ widget: "buildhub.near/widget/home"
+ }
+ };
+ })
+ )
+ }
+ }
+ };
+ const call = [
+ {
+ contractName: "social.near",
+ methodName: "set",
+ args: { data: notification, options: { refund_unused_deposit: true } },
+ deposit: 200000000000000000000000
+ }
+ ];
+ return call;
+};
+
+useEffect(() => {
+ onUpdate(createNotificationsData());
+}, [selectedRoles]);
+
+const capitalizeFirstLetter = (string) => {
+ return string.charAt(0).toUpperCase() + string.slice(1);
+};
+
+const groupList = useMemo(() => {
+ return (
+ Array.isArray(groupsAndMembers) &&
+ groupsAndMembers.map((group) => {
+ const membersLength = group?.members.length;
+ if (!membersLength) {
+ return null;
+ }
+ return (
+
+
+ {capitalizeFirstLetter(group.name)} ({membersLength} members)
+
+ ),
+ onChange: (checked) => handleCheckboxChange(group.name),
+ checked: selectedRoles[group.name] ?? false
+ }}
+ />
+
+ );
+ })
+ );
+}, [groupsAndMembers, selectedRoles]);
+
+return (
+
+
+ Send notification to following roles: (Optional)
+
+
+ setMessage(e.target.value)}
+ />
+
+ {groupList}
+
+
+);
diff --git a/apps/builddao/widget/Proposals.jsx b/apps/builddao/widget/Proposals.jsx
index 9e8430a1..3ea2fdeb 100644
--- a/apps/builddao/widget/Proposals.jsx
+++ b/apps/builddao/widget/Proposals.jsx
@@ -5,6 +5,7 @@ const { Button, Modal } = VM.require("buildhub.near/widget/components") || {
const { Header } = VM.require("buildhub.near/widget/components.Header") || {
Header: () => <>>,
+
};
const DaoSDK = VM.require("sdks.near/widget/SDKs.Sputnik.DaoSDK") || (() => {});
@@ -113,7 +114,7 @@ const NotificationModal = () => {
daoId,
proposalId: voteDetails.proposalId,
proposer: voteDetails.proposer,
- showNotification: false,
+ showNotification: false
});
setNotificationModal(false);
}}
@@ -128,7 +129,7 @@ const NotificationModal = () => {
daoId,
proposalId: voteDetails.proposalId,
proposer: voteDetails.proposer,
- showNotification: true,
+ showNotification: true
});
setNotificationModal(false);
}}
@@ -156,13 +157,13 @@ const handleVote = ({ action, proposalId, proposer, showNotification }) => {
daoId: daoId,
proposalId: proposalId,
},
- type: "custom",
- widget: "buildhub.near/widget/Proposals",
- },
- },
- ]),
- },
- },
+ type: "buildhub/custom",
+ widget: "buildhub.near/widget/Proposals"
+ }
+ }
+ ])
+ }
+ }
};
sdk.actProposal({
@@ -176,12 +177,14 @@ const handleVote = ({ action, proposalId, proposer, showNotification }) => {
methodName: "set",
args: {
data: notification,
- options: { refund_unused_deposit: true },
+ options: { refund_unused_deposit: true }
},
- deposit: 100000000000000000000000,
- },
+ deposit: Big(JSON.stringify(notification).length * 16)
+ .mul(Big(10).pow(20))
+ .toString()
+ }
]
- : null,
+ : null
});
};
@@ -302,7 +305,8 @@ const proposalsComponent = useMemo(() => {
handleVote: (data) => {
setVoteDetails(data);
setNotificationModal(true);
- },
+
+ }
}}
/>
);
@@ -321,7 +325,7 @@ return (
src="buildhub.near/widget/components.modals.CreateProposal"
props={{
showModal: showProposalModal,
- toggleModal: () => setShowModal(!showProposalModal),
+ toggleModal: () => setShowModal(!showProposalModal)
}}
/>
setFiltersModal(!showFiltersModal),
}}
/>
-
-
-
Proposals
-
-
-
-
+
+
Proposals
+
+
+
-
+
{proposalsComponent}
{!proposalId && (
diff --git a/apps/builddao/widget/components/modals/propose/AddMember.jsx b/apps/builddao/widget/components/modals/propose/AddMember.jsx
index e1b6a780..68725864 100644
--- a/apps/builddao/widget/components/modals/propose/AddMember.jsx
+++ b/apps/builddao/widget/components/modals/propose/AddMember.jsx
@@ -1,5 +1,5 @@
const { Button } = VM.require("buildhub.near/widget/components") || {
- Button: () => <>>,
+ Button: () => <>>
};
const DaoSDK = VM.require("sdks.near/widget/SDKs.Sputnik.DaoSDK") || (() => {});
@@ -29,6 +29,7 @@ useEffect(() => {
}, [props.item]);
const memoizedKey = useMemo((editorKey) => editorKey, [editorKey]);
const [validatedAddresss, setValidatedAddresss] = useState(true);
+const [notificationsData, setNotificationData] = useState(null);
const regex = /.{1}\.near$/;
useEffect(() => {
@@ -221,12 +222,21 @@ return (
embedCss: props.customCSS || MarkdownEditor,
onChange: (v) => {
setText(v);
- },
+ }
}}
/>
-
+ {
+ setNotificationData(v);
+ },
+ proposalType: "Add Member"
+ }}
+ />
diff --git a/apps/builddao/widget/components/modals/propose/FunctionCall.jsx b/apps/builddao/widget/components/modals/propose/FunctionCall.jsx
index a68d101b..1bab145b 100644
--- a/apps/builddao/widget/components/modals/propose/FunctionCall.jsx
+++ b/apps/builddao/widget/components/modals/propose/FunctionCall.jsx
@@ -1,5 +1,5 @@
const { Button } = VM.require("buildhub.near/widget/components") || {
- Button: () => <>>,
+ Button: () => <>>
};
const DaoSDK = VM.require("sdks.near/widget/SDKs.Sputnik.DaoSDK") || (() => {});
@@ -14,6 +14,7 @@ const [deposit, setDeposit] = useState(0);
const [validatedAddresss, setValidatedAddress] = useState(true);
const [text, setText] = useState("");
const [editorKey, setEditorKey] = useState(0);
+const [notificationsData, setNotificationData] = useState(null);
const bootstrapTheme = props.bootstrapTheme;
@@ -249,11 +250,21 @@ return (
embedCss: props.customCSS || MarkdownEditor,
onChange: (v) => {
setText(v);
- },
+ }
}}
/>
+ {
+ setNotificationData(v);
+ },
+ proposalType: "Function Call"
+ }}
+ />
diff --git a/apps/builddao/widget/components/modals/propose/RemoveMember.jsx b/apps/builddao/widget/components/modals/propose/RemoveMember.jsx
index 8dcba1e5..27e63ebf 100644
--- a/apps/builddao/widget/components/modals/propose/RemoveMember.jsx
+++ b/apps/builddao/widget/components/modals/propose/RemoveMember.jsx
@@ -1,5 +1,5 @@
const { Button } = VM.require("buildhub.near/widget/components") || {
- Button: () => <>>,
+ Button: () => <>>
};
const DaoSDK = VM.require("sdks.near/widget/SDKs.Sputnik.DaoSDK") || (() => {});
@@ -15,6 +15,7 @@ const sdk = DaoSDK(selectedDAO);
const [text, setText] = useState("");
const [editorKey, setEditorKey] = useState(0);
+const [notificationsData, setNotificationData] = useState(null);
const bootstrapTheme = props.bootstrapTheme;
useEffect(() => {
@@ -223,12 +224,21 @@ return (
embedCss: props.customCSS || MarkdownEditor,
onChange: (v) => {
setText(v);
- },
+ }
}}
/>
-
+ {
+ setNotificationData(v);
+ },
+ proposalType: "Remove Member"
+ }}
+ />
diff --git a/apps/builddao/widget/components/modals/propose/Text.jsx b/apps/builddao/widget/components/modals/propose/Text.jsx
index cfbb5072..04220e6b 100644
--- a/apps/builddao/widget/components/modals/propose/Text.jsx
+++ b/apps/builddao/widget/components/modals/propose/Text.jsx
@@ -1,5 +1,5 @@
const { Button } = VM.require("buildhub.near/widget/components") || {
- Button: () => <>>,
+ Button: () => <>>
};
const DaoSDK = VM.require("sdks.near/widget/SDKs.Sputnik.DaoSDK") || (() => {});
@@ -19,6 +19,7 @@ useEffect(() => {
}, [props.item]);
const memoizedKey = useMemo((editorKey) => editorKey, [editorKey]);
const selectedDAO = props.selectedDAO;
+const [notificationsData, setNotificationData] = useState(null);
const sdk = DaoSDK(selectedDAO);
const MarkdownEditor = `
@@ -165,10 +166,21 @@ return (
embedCss: props.customCSS || MarkdownEditor,
onChange: (v) => {
setText(v);
- },
+ }
}}
/>
+ {
+ setNotificationData(v);
+ },
+ proposalType: "Add Member"
+ }}
+ />
+ {console.log(notificationsData)}
diff --git a/apps/builddao/widget/components/modals/propose/Transfer.jsx b/apps/builddao/widget/components/modals/propose/Transfer.jsx
index 2af69c4e..615afebf 100644
--- a/apps/builddao/widget/components/modals/propose/Transfer.jsx
+++ b/apps/builddao/widget/components/modals/propose/Transfer.jsx
@@ -1,5 +1,5 @@
const { Button } = VM.require("buildhub.near/widget/components") || {
- Button: () => <>>,
+ Button: () => <>>
};
const DaoSDK = VM.require("sdks.near/widget/SDKs.Sputnik.DaoSDK") || (() => {});
@@ -17,6 +17,8 @@ const bootstrapTheme = props.bootstrapTheme;
const [text, setText] = useState("");
const [editorKey, setEditorKey] = useState(0);
+const [notificationsData, setNotificationData] = useState(null);
+
useEffect(() => {
if (!props.item) {
return;
@@ -37,8 +39,8 @@ const tokensData = [
icon: "",
name: "NEAR",
symbol: "NEAR",
- tokenId: NearTokenId,
- },
+ tokenId: NearTokenId
+ }
];
if (res.body) {
res.body?.tokens?.fts.map((item) => {
@@ -262,11 +264,21 @@ return (
embedCss: props.customCSS || MarkdownEditor,
onChange: (v) => {
setText(v);
- },
+ }
}}
/>
+ {
+ setNotificationData(v);
+ },
+ proposalType: "Add Member"
+ }}
+ />