Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions apps/builddao/widget/Bookmarks.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const { Post } = VM.require("buildhub.near/widget/components") || (() => <></>);

const accountId = props.accountId ?? context.accountId;

const bookmarks = Social.getr(`${accountId}/graph/bookmark`, "final", {
withBlockHeight: true,
});

const StorageKey = "order";
const order = Storage.privateGet(StorageKey);
const apps = useMemo(() => {
if (bookmarks === null || order === null) {
return [];
}
const starredApps = new Map();
const path = [];

const buildSrc = (node) => {
if (node.hasOwnProperty("")) {
starredApps.set(path.join("/"), node[":block"]);
}
Object.entries(node).forEach(([key, value]) => {
if (typeof value === "object") {
path.push(key);
buildSrc(value);
path.pop();
}
});
};

buildSrc(bookmarks ?? {}, [], starredApps);
let apps = [...starredApps.entries()];
apps.sort((a, b) => b[1] - a[1]);
apps = apps.map((a) => a[0]);
apps.sort((a, b) => (order?.[a] || 0) - (order?.[b] || 0));
Storage.privateSet(
StorageKey,
Object.fromEntries(apps.map((a, i) => [a, i + 1]))
);
return apps;
}, [bookmarks, order]);

let transformedArray = apps.map((item) => {
let splitParts = item.split("/");
let accountId = splitParts[0];
let lastPart = splitParts[splitParts.length - 1];
let blockHeight = isNaN(lastPart) ? null : parseInt(lastPart);

return { accountId, blockHeight };
});

let filteredArray = transformedArray.filter(
(item) => item.blockHeight !== null
);

return (
<>
{(filteredArray ?? []).map((item) => (
<Post
accountId={item.accountId}
blockHeight={item.blockHeight}
noBorder={true}
/>
))}
{filteredArray.length === 0 && (
<p className="fw-bold text-white">No Bookmarks Yet!</p>
)}
</>
);
69 changes: 40 additions & 29 deletions apps/builddao/widget/Feed.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ const feeds = {
- [Provide any context or details]
`,
},
bookmarks: {
label: "Bookmarks",
icon: "bi-bookmark",
name: "bookmark",
},
};

const [activeFeed, setActiveFeed] = useState(type || "resolutions");
Expand All @@ -158,42 +163,48 @@ return (
</StyledAside>
<MainContent>
{context.accountId ? (
<Widget
src="/*__@appAccount__*//widget/Compose"
props={{
feed: feeds[activeFeed],
template: feeds[activeFeed].template,
}}
/>
activeFeed !== "bookmarks" ? (
<Widget
src="/*__@appAccount__*//widget/Compose"
props={{
feed: feeds[activeFeed],
template: feeds[activeFeed].template,
}}
/>
) : (
<Widget src="/*__@appAccount__*//widget/Bookmarks" />
)
) : (
<Widget
src="/*__@appAccount__*//widget/components.login-now"
props={props}
/>
)}
<Feed
index={[
{
action: "hashtag",
key: activeFeed,
options: {
limit: 10,
order: "desc",
accountId: props.accounts,
},
cacheOptions: {
ignoreCache: true,
{activeFeed !== "bookmarks" && (
<Feed
index={[
{
action: "hashtag",
key: activeFeed,
options: {
limit: 10,
order: "desc",
accountId: props.accounts,
},
cacheOptions: {
ignoreCache: true,
},
},
},
]}
Item={(p) => (
<Post
accountId={p.accountId}
blockHeight={p.blockHeight}
noBorder={true}
/>
)}
/>
]}
Item={(p) => (
<Post
accountId={p.accountId}
blockHeight={p.blockHeight}
noBorder={true}
/>
)}
/>
)}
</MainContent>
</Container>
);
105 changes: 75 additions & 30 deletions apps/builddao/widget/components/post/BookmarkButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,51 @@ const bookmarks = Social.index("bookmark", item);

const dataLoading = bookmarks === null;

const bookmarksByUsers = {};
const bookmarksByUser = {};

(bookmarks || []).forEach((bookmark) => {
if (bookmark.value.type === "bookmark") {
bookmarksByUsers[bookmark.accountId] = bookmark;
bookmarksByUser[bookmark.accountId] = bookmark;
} else if (bookmark.value.type === "unbookmark") {
delete bookmarksByUsers[bookmark.accountId];
delete bookmarksByUser[bookmark.accountId];
}
});

if (state.hasBookmark === true) {
bookmarksByUsers[context.accountId] = {
bookmarksByUser[context.accountId] = {
accountId: context.accountId,
};
} else if (state.hasBookmark === false) {
delete bookmarksByUsers[context.accountId];
delete bookmarksByUser[context.accountId];
}

const accountsWithBookmarks = Object.keys(bookmarksByUsers);
const likeCount = accountsWithBookmarks.length;
const hasBookmark = context.accountId && !!bookmarksByUsers[context.accountId];
const accountsWithBookmarks = Object.keys(bookmarksByUser);
const bookmarkCount = accountsWithBookmarks.length;
const hasBookmark = context.accountId && !!bookmarksByUser[context.accountId];

const bookmarkSvg = (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
class="bi bi-bookmark"
viewBox="0 0 16 16"
>
<path
d="M4.16671 1.66667H15.8334C16.2936 1.66667 16.6667 2.03977 16.6667 2.50001V18.4528C16.6667 18.6828 16.4801 18.8695 16.25 18.8695C16.1718 18.8695 16.095 18.8473 16.0287 18.8058L10 15.0261L3.97137 18.8058C3.7764 18.928 3.51926 18.8691 3.39702 18.6741C3.35543 18.6078 3.33337 18.5311 3.33337 18.4528V2.50001C3.33337 2.03977 3.70647 1.66667 4.16671 1.66667ZM15 3.33334H5.00004V16.1937L10 13.0589L15 16.1937V3.33334Z"
fill="currentColor"
/>
<path d="M2 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v13.5a.5.5 0 0 1-.777.416L8 13.101l-5.223 2.815A.5.5 0 0 1 2 15.5zm2-1a1 1 0 0 0-1 1v12.566l4.723-2.482a.5.5 0 0 1 .554 0L13 14.566V2a1 1 0 0 0-1-1z" />
</svg>
);

const bookmarkFillSvg = (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="#FFAF51"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
class="bi bi-bookmark-fill"
viewBox="0 0 16 16"
>
<path
d="M4.16671 1.66675H15.8334C16.2936 1.66675 16.6667 2.03985 16.6667 2.50008V18.4528C16.6667 18.6829 16.4801 18.8696 16.25 18.8696C16.1718 18.8696 16.095 18.8474 16.0287 18.8058L10 15.0262L3.97137 18.8058C3.7764 18.9281 3.51926 18.8692 3.39702 18.6742C3.35543 18.6078 3.33337 18.5312 3.33337 18.4528V2.50008C3.33337 2.03985 3.70647 1.66675 4.16671 1.66675ZM15 3.33341H5.00004V16.1937L10 13.059L15 16.1937V3.33341Z"
fill="#FFAF51"
/>
<path d="M2 2v13.5a.5.5 0 0 0 .74.439L8 13.069l5.26 2.87A.5.5 0 0 0 14 15.5V2a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2" />
</svg>
);

Expand Down Expand Up @@ -128,38 +125,66 @@ const BookmarkButton = styled.div`
}
`;

const likeClick = () => {
const bookmarkClick = () => {
if (state.loading || dataLoading || !context.accountId) {
return;
}
State.update({
loading: true,
});
const type = hasBookmark ? "unbookmark" : "bookmark";
const data = {
index: {
bookmark: JSON.stringify({
key: item,
value: {
type: hasBookmark ? "unbookmark" : "bookmark",
type,
},
}),
},
};

if (item.type === "social" && typeof item.path === "string") {
const keys = item.path.split("/");
keys.push(item.blockHeight);
if (keys.length > 0) {
data.graph = {
bookmark: {},
};
let root = data.graph.bookmark;
keys.slice(0, -1).forEach((key) => {
root = root[key] = {};
});
root[keys[keys.length - 1]] = hasBookmark ? null : "";
}
}

if (!hasBookmark && props.notifyAccountId) {
data.index.notify = JSON.stringify({
key: props.notifyAccountId,
value: {
type,
item,
},
});
}

Social.set(data, {
onCommit: () => State.update({ loading: false, hasBookmark: !hasBookmark }),
onCancel: () => State.update({ loading: false }),
});
};

const title = hasBookmark ? "Unbookmark" : "Bookmark";
const title = hasBookmark
? props.titleUnbookmark ?? "Unbookmark"
: props.titleBookmark ?? "Bookmark";

return (
const inner = (
<div className="d-inline-flex align-items-center">
<BookmarkButton
disabled={state.loading || dataLoading || !context.accountId}
title={title}
onClick={likeClick}
title={!props.tooltip ? title : undefined}
onClick={bookmarkClick}
>
<span
className={`icon ${state.loading ? "loading " : ""}${
Expand All @@ -168,6 +193,26 @@ return (
>
{hasBookmark ? bookmarkFillSvg : bookmarkSvg}
</span>
{bookmarkCount > 0 && (
<span className={`count ${hasBookmark ? "bookmarked" : ""}`}>
<Widget
loading={bookmarkCount || ""}
src="mob.near/widget/N.Overlay.Faces"
props={{ accounts: bookmarksByUser, limit: 10 }}
/>
</span>
)}
</BookmarkButton>
</div>
);

return props.tooltip ? (
<OverlayTrigger
placement={props.overlayPlacement ?? "auto"}
overlay={<Tooltip>{title}</Tooltip>}
>
{inner}
</OverlayTrigger>
) : (
inner
);