diff --git a/src/devhub/components/molecule/AccountAutocomplete.jsx b/src/devhub/components/molecule/AccountAutocomplete.jsx
new file mode 100644
index 000000000..f205550df
--- /dev/null
+++ b/src/devhub/components/molecule/AccountAutocomplete.jsx
@@ -0,0 +1,143 @@
+if (!context.accountId || !props.term) return <>>;
+
+let results = [];
+const profilesData = Social.get("*/profile/name", "final") || {};
+const followingData = Social.get(
+ `${context.accountId}/graph/follow/**`,
+ "final"
+);
+if (!profilesData) return <>>;
+const profiles = Object.entries(profilesData);
+const term = (props.term || "").replace(/\W/g, "").toLowerCase();
+const limit = 5;
+
+for (let i = 0; i < profiles.length; i++) {
+ let score = 0;
+ const accountId = profiles[i][0];
+ const accountIdSearch = profiles[i][0].replace(/\W/g, "").toLowerCase();
+ const nameSearch = (profiles[i][1]?.profile?.name || "")
+ .replace(/\W/g, "")
+ .toLowerCase();
+ const accountIdSearchIndex = accountIdSearch.indexOf(term);
+ const nameSearchIndex = nameSearch.indexOf(term);
+
+ if (accountIdSearchIndex > -1 || nameSearchIndex > -1) {
+ score += 10;
+
+ if (accountIdSearchIndex === 0) {
+ score += 10;
+ }
+ if (nameSearchIndex === 0) {
+ score += 10;
+ }
+ if (followingData[accountId] === "") {
+ score += 30;
+ }
+
+ results.push({
+ accountId,
+ score,
+ });
+ }
+}
+
+results.sort((a, b) => b.score - a.score);
+results = results.slice(0, limit);
+
+function onResultClick(id) {
+ props.onSelect && props.onSelect(id);
+}
+
+const Wrapper = styled.div`
+ position: relative;
+ background: #eceef0;
+
+ &::before {
+ content: "";
+ display: block;
+ position: absolute;
+ right: 0;
+ width: 6px;
+ height: 100%;
+ background: linear-gradient(
+ to left,
+ rgba(236, 238, 240, 1),
+ rgba(236, 238, 240, 0)
+ );
+ z-index: 10;
+ }
+`;
+
+const Scroller = styled.div`
+ position: relative;
+ display: flex;
+ padding: 6px;
+ gap: 6px;
+ overflow: auto;
+ scroll-behavior: smooth;
+ align-items: center;
+ scrollbar-width: none;
+ -ms-overflow-style: none;
+ &::-webkit-scrollbar {
+ display: none;
+ }
+
+ > * {
+ max-width: 175px;
+ flex-grow: 0;
+ flex-shrink: 0;
+
+ button {
+ border: 1px solid #eceef0;
+ background: #fff !important;
+ border-radius: 6px;
+ padding: 3px 6px;
+ transition: all 200ms;
+
+ &:focus,
+ &:hover {
+ border-color: #687076;
+ }
+ }
+ }
+`;
+
+const CloseButton = styled.button`
+ background: none;
+ border: none;
+ display: block;
+ padding: 12px;
+ color #687076;
+ transition: all 200ms;
+
+ &:hover {
+ color: #000;
+ }
+`;
+
+if (results.length === 0) return <>>;
+
+return (
+
+
+
+
+
+
+ {results.map((result) => {
+ return (
+
+ );
+ })}
+
+
+);
diff --git a/src/devhub/components/molecule/SimpleMDE.jsx b/src/devhub/components/molecule/SimpleMDE.jsx
index 0f11aa048..264b1f1e1 100644
--- a/src/devhub/components/molecule/SimpleMDE.jsx
+++ b/src/devhub/components/molecule/SimpleMDE.jsx
@@ -212,9 +212,7 @@ const code = `
initialText: event.data.content }));
isEditorInitialized = true;
} else {
- console.log(event);
if (event.data.handler === 'autocompleteSelected') {
- console.log("we're in");
codeMirrorInstance.getDoc().setValue(event.data.content);
}
}
diff --git a/src/devhub/entity/post/Post.jsx b/src/devhub/entity/post/Post.jsx
index 274cdd6de..9ca826a7b 100644
--- a/src/devhub/entity/post/Post.jsx
+++ b/src/devhub/entity/post/Post.jsx
@@ -626,7 +626,7 @@ const tags = post.snapshot.labels ? (
diff --git a/src/devhub/entity/post/PostEditor.jsx b/src/devhub/entity/post/PostEditor.jsx
index 489f75fda..af094a82c 100644
--- a/src/devhub/entity/post/PostEditor.jsx
+++ b/src/devhub/entity/post/PostEditor.jsx
@@ -379,7 +379,7 @@ const callDescriptionDiv = () => {
{autocompleteEnabled && state.showAccountAutocomplete && (
word.startsWith("@"))
+ .map((mention) => mention.slice(1));
+ const newMentiones = allMentiones.filter(
+ (item) => !state.mentionsArray.includes(item)
+ );
+
State.update((lastKnownState) => ({
...lastKnownState,
text: value,
- showAccountAutocomplete,
+ showAccountAutocomplete: newMentiones?.length > 0,
+ mentionsArray: allMentiones,
+ mentionInput: newMentiones?.[0] ?? "",
}));
}
function autoCompleteAccountId(id) {
- let description = state.description.replace(/[\s]{0,1}@[^\s]*$/, "");
- description = `${description} @${id}`.trim() + " ";
+ // to make sure we update the @ at correct index
+ let currentIndex = 0;
+ const updatedDescription = state.description.replace(
+ /(?:^|\s)(@[^\s]*)/g,
+ (match) => {
+ if (currentIndex === state.mentionsArray.indexOf(state.mentionInput)) {
+ currentIndex++;
+ return ` @${id}`;
+ } else {
+ currentIndex++;
+ return match;
+ }
+ }
+ );
+
State.update((lastKnownState) => ({
...lastKnownState,
- description,
+ handler: "autocompleteSelected",
+ description: updatedDescription,
showAccountAutocomplete: false,
}));
}
@@ -51,26 +96,6 @@ const labels = labelStrings.map((s) => {
return { name: s };
});
-State.init({
- seekingFunding: false,
-
- author_id: context.accountId,
- // Should be a list of objects with field "name".
- labels,
- // Should be a list of labels as strings.
- // Both of the label structures should be modified together.
- labelStrings,
- postType: "Idea",
- name: props.name ?? "",
- description: props.description ?? "",
- amount: props.amount ?? "",
- token: props.token ?? "USDT",
- supervisor: props.supervisor ?? "neardevdao.near",
- githubLink: props.githubLink ?? "",
- warning: "",
- waitForDraftStateRestore: true,
-});
-
if (state.waitForDraftStateRestore) {
const draftstatestring = Storage.privateGet(DRAFT_STATE_STORAGE_KEY);
if (draftstatestring != null) {
@@ -313,9 +338,9 @@ const descriptionDiv = (
{autocompleteEnabled && state.showAccountAutocomplete && (
State.update({ showAccountAutocomplete: false }),
}}