diff --git a/apps/builddao/widget/components/project/Card.jsx b/apps/builddao/widget/components/project/Card.jsx index c48afb43..1a1c0bde 100644 --- a/apps/builddao/widget/components/project/Card.jsx +++ b/apps/builddao/widget/components/project/Card.jsx @@ -6,6 +6,10 @@ const { Avatar, Hashtag, Button } = VM.require( Button: () => <>, }; +const { href } = VM.require("buildhub.near/widget/lib.url") || { + href: () => {}, +}; + const { ProfileImages } = VM.require( "buildhub.near/widget/components.ProfileImages" ) || { @@ -21,8 +25,8 @@ const Card = styled.div` flex-direction: column; align-items: flex-start; gap: 24px; - color: var(--text-color, #fff); + justify-content: space-between; .info { display: flex; @@ -42,6 +46,12 @@ const Card = styled.div` font-weight: 700; } } + .c-top { + display: flex; + flex-direction: column; + gap: 24px; + width: 100%; + } .bt-w { flex: 1; button { @@ -50,38 +60,56 @@ const Card = styled.div` } `; -const ProjectCard = ({ title, tags, people, accountId }) => { +const ProjectCard = ({ project, type, app }) => { + const { title, accountId, tags, collaborators, metadata } = project; return ( - -
-

{title.length > 30 ? `${title.slice(0, 25)}...` : title}

- {`@${ - accountId.length > 30 - ? `${accountId.slice(0, 20)}...${accountId.slice( - accountId.length - 4 - )}` - : accountId - }`} -
-
- {tags.map((tag) => ( - - {tag} - - ))} +
+ +
+

+ {metadata.title.length > 30 + ? `${metadata.title.slice(0, 25)}...` + : metadata.title} +

+ {`@${ + accountId.length > 30 + ? `${accountId.slice(0, 20)}...${accountId.slice( + accountId.length - 4 + )}` + : accountId + }`} +
+
+ {tags.map((tag) => ( + + {tag} + + ))} +
+
+ +
-
- +
+
- ); }; diff --git a/apps/builddao/widget/components/project/Tabs.jsx b/apps/builddao/widget/components/project/Tabs.jsx deleted file mode 100644 index 56533139..00000000 --- a/apps/builddao/widget/components/project/Tabs.jsx +++ /dev/null @@ -1,151 +0,0 @@ -const { Post } = VM.require("buildhub.near/widget/components") || { - Post: () => <>, -}; - -const accountId = props.accountId ?? context.accountId; -if (!accountId) { - return "No account ID"; -} - -const profile = props.profile ?? Social.getr(`${accountId}/profile`); - -if (profile === null) { - return "Loading"; -} - -const description = profile.description; - -const pills = [ - { id: "overview", title: "Overview" }, - { id: "discussion", title: "Discussion" }, - { id: "task", title: "Task" }, - { id: "code", title: "Code" }, - { id: "roadmap", title: "Roadmap" }, -]; - -const Nav = styled.div` - .nav-pills { - background: var(--bg-1, #0b0c14); - font-weight: 500; - --bs-nav-pills-border-radius: 0; - --bs-nav-link-color: var(--font-color, #fff); - --bs-nav-pills-link-active-color: var(--font-color, #fff); - --bs-nav-pills-link-active-bg: var(--bg-1, #0b0c14); - --bs-nav-link-padding-y: 0.75rem; - border-bottom: 1px solid var(--stroke-color, rgba(255, 255, 255, 0.2)); - padding-top: 3px; - } - .nav-link.active { - border-bottom: 2px solid var(--Yellow, #ffaf51); - } - - .nav-item:not(:has(> .disabled)):hover { - background: rgba(13, 110, 253, 0.15); - } -`; - -return ( - <> - -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -); diff --git a/apps/builddao/widget/components/project/page/Code.jsx b/apps/builddao/widget/components/project/page/Code.jsx index 1d98581e..4e0d6553 100644 --- a/apps/builddao/widget/components/project/page/Code.jsx +++ b/apps/builddao/widget/components/project/page/Code.jsx @@ -1 +1,35 @@ -return
Code
; +const { Button } = VM.require("buildhub.near/widget/components") || { + Button: () => <>, +}; + +const { getProjectMeta } = VM.require( + "buildhub.near/widget/lib.project-data" +) || { + getProjectMeta: () => {}, +}; + +const { id } = props; + +const project = getProjectMeta(id); + +const { projectLink } = project; +const Container = styled.div` + display: flex; + flex-direction: column; + gap: 16px; + align-items: center; + justify-content: center; +`; + +return ( + + + +); diff --git a/apps/builddao/widget/components/project/page/Overview.jsx b/apps/builddao/widget/components/project/page/Overview.jsx index b9f3946e..f68ab9ec 100644 --- a/apps/builddao/widget/components/project/page/Overview.jsx +++ b/apps/builddao/widget/components/project/page/Overview.jsx @@ -1,9 +1,21 @@ -const { Hashtag } = VM.require("buildhub.near/widget/components") || { +const { User, Hashtag } = VM.require("buildhub.near/widget/components") || { + User: () => <>, Hashtag: () => <>, }; -const accountId = props.accountId; -const profile = props.profile; +const { getProjectMeta } = VM.require( + "buildhub.near/widget/lib.project-data" +) || { + getProjectMeta: () => {}, +}; + +const { id } = props; + +const project = getProjectMeta(id); + +const { description, tags, contributors, accountId, profile } = project; + +console.log("contributors", contributors); const Container = styled.div` display: flex; @@ -51,15 +63,15 @@ const MapIcon = () => ( ); -const tags = Object.keys(profile.tags ?? []); +// const tags = Object.keys(profile.tags ?? []); return (

About

- {profile.description ? ( - + {description ? ( + ) : ( "No information available" )} @@ -76,24 +88,32 @@ return (

Team Size

- {!profile.members && "0"} - {profile.members.length <= 10 && "1-10"} - {profile.members.length <= 50 && "10-50"} - {profile.members.length <= 100 && "50-100"} - {profile.members.length > 100 && "100+"} + {!contributors || !contributors.length + ? "0" + : contributors.length <= 10 + ? "1-10" + : contributors.length <= 50 + ? "10-50" + : contributors.length <= 100 + ? "50-100" + : "100+"}

Contributors

- {!profile.contributors &&

No Contributors

} + {!contributors &&

No Contributors

} +
+ {contributors && + contributors.map((teammate) => ( + + ))} +

Project Tags

- {tags.map((it) => ( - {it} - ))} + {tags && tags.map((it) => {it})} {tags.length === 0 &&

No tags

}
diff --git a/apps/builddao/widget/components/project/page/Roadmap.jsx b/apps/builddao/widget/components/project/page/Roadmap.jsx index 67d56651..1f553b9a 100644 --- a/apps/builddao/widget/components/project/page/Roadmap.jsx +++ b/apps/builddao/widget/components/project/page/Roadmap.jsx @@ -1 +1,47 @@ -return
Roadmap
; +const { Button } = VM.require("buildhub.near/widget/components") || { + Button: () => <>, +}; + +const { getProjectMeta } = VM.require( + "buildhub.near/widget/lib.project-data" +) || { + getProjectMeta: () => {}, +}; + +const { id } = props; + +const project = getProjectMeta(id); + +const { demoLink, learning } = project; +const Container = styled.div` + display: flex; + flex-direction: column; + gap: 16px; + justify-content: center; + .link { + display: flex; + gap: 16px; + flex-direction: row; + align-items: center; + } + .learning { + display: flex; + flex-direction: column; + gap: 16px; + } +`; + +return ( + +
+
Link:
+ +
+
+
What I learned
+

{learning}

+
+
+); diff --git a/apps/builddao/widget/lib/project-data.jsx b/apps/builddao/widget/lib/project-data.jsx new file mode 100644 index 00000000..65380cc8 --- /dev/null +++ b/apps/builddao/widget/lib/project-data.jsx @@ -0,0 +1,64 @@ +// Get id from the file as a parameter +// process the data and return project object with all the data needed + +const { extractValidNearAddresses } = VM.require( + "buildbox.near/widget/utils.projects-sdk" +) || { + extractValidNearAddresses: () => {}, +}; + +const extractNearAddress = (id) => { + const parts = id.split("/"); + if (parts.length > 0) { + return parts[0]; + } + return ""; +}; + +const getProjectMeta = (id) => { + if (!id) { + throw new Error("Invalid project ID"); + } + + const accountId = extractNearAddress(id); + + const data = Social.get(id + "/**", "final"); + + if (!data) { + throw new Error("Failed to fetch project data"); + } + + try { + const profile = Social.getr(`${accountId}/profile`, "final"); + + const pj = JSON.parse(data[""]); + + console.log("project data ini", pj); + + const validAddresses = pj?.teammates + ? extractValidNearAddresses(pj.teammates) + : []; + const uniqueContributors = [...new Set([accountId, ...validAddresses])]; + + const project = { + title: pj.title, + description: pj.description, + tags: pj.tracks, + projectLink: pj.projectLink, + demoLink: pj.demoLink, + contactInfo: pj.contactInfo, + referrer: pj.referrer, + learning: pj.learning, + contributors: uniqueContributors, + accountId: accountId, + profile: profile, + }; + + return project; + } catch (error) { + console.error("Error parsing project data:", error); + return null; + } +}; + +return { getProjectMeta }; diff --git a/apps/builddao/widget/page/project-feed.jsx b/apps/builddao/widget/page/project-feed.jsx index 45073aa4..413a2a4e 100644 --- a/apps/builddao/widget/page/project-feed.jsx +++ b/apps/builddao/widget/page/project-feed.jsx @@ -1,7 +1,8 @@ -const { fetchProjects } = VM.require( +const { fetchProjects, extractValidNearAddresses } = VM.require( "buildbox.near/widget/utils.projects-sdk" ) || { fetchProjects: () => {}, + extractValidNearAddresses: () => {}, }; const { Button } = VM.require("buildhub.near/widget/components") || { @@ -23,33 +24,6 @@ if (!data) { return "Loading..."; } -/* HELPER FUNCTION */ -function isNearAddress(address) { - if (typeof address !== "string") { - return false; - } - - // Allow both ".near" and ".testnet" endings - if (!address.endsWith(".near") && !address.endsWith(".testnet")) { - return false; - } - - const parts = address.split("."); - if (parts.length !== 2) { - return false; - } - - if (parts[0].length < 2 || parts[0].length > 32) { - return false; - } - - if (!/^[a-z0-9_-]+$/i.test(parts[0])) { - return false; - } - - return true; -} - const processData = useCallback( (data) => { const accounts = Object.entries(data); @@ -62,18 +36,7 @@ const processData = useCallback( const metadata = JSON.parse(kv[1]); const members = metadata.teammates; - // if (members) { - // removing extra characters and splitting the string into an array - const arr = members.replace(/[\[\]\(\)@]/g, "").split(/[\s,]+/); - - // filtering out teammates that are not near addresses - const hexRegex = /^[0-9A-F\-_]+$/i; - const valid = arr.filter((teammate) => { - if (hexRegex.test(teammate)) { - return teammate; - } - return isNearAddress(teammate); - }); + const valid = extractValidNearAddresses(members); valid.unshift(accountId); @@ -82,7 +45,6 @@ const processData = useCallback( // } const collaborators = unique || []; - // console.log("metadata: ", metadata); return { accountId, type: type, @@ -195,7 +157,6 @@ const tagFilters = useMemo(() => { return tags; }, [projects]); -console.log("tagFilters", tagFilters); return ( No Projects Found

)} {filteredProjects.map((project) => ( - + ))}
diff --git a/apps/builddao/widget/page/project.jsx b/apps/builddao/widget/page/project.jsx index e2a78783..312331e7 100644 --- a/apps/builddao/widget/page/project.jsx +++ b/apps/builddao/widget/page/project.jsx @@ -1,18 +1,34 @@ -const { page, tab, ...passProps } = props; +const { page, tab, type, app, ...passProps } = props; const { routes } = VM.require("buildhub.near/widget/config.project") ?? { routes: {}, }; -const { ProjectLayout } = VM.require("buildhub.near/widget/template.ProjectLayout") || { +const { ProjectLayout } = VM.require( + "buildhub.near/widget/template.ProjectLayout" +) || { ProjectLayout: () => <>, }; +const { id } = props; +const extractNearAddress = (id) => { + const parts = id.split("/"); + if (parts.length > 0) { + return parts[0]; + } + return ""; +}; +const accountId = extractNearAddress(id); + +const data = Social.get(id + "/**", "final"); + +if (!id || !data) { + return "Loading..."; +} + if (!page) page = Object.keys(routes)[0] || "home"; -const Root = styled.div` - -`; +const Root = styled.div``; function Router({ active, routes }) { // this may be converted to a module at devs.near/widget/Router @@ -61,16 +77,36 @@ const Content = styled.div` height: 100%; `; -const profile = Social.getr(`${props.accountId}/profile`, "final"); +function transformKeys(obj) { + obj.tags = obj.tracks; + delete obj.tracks; + + obj.contributors = obj.teammates; + delete obj.teammates; + + return obj; +} + +const project = transformKeys(JSON.parse(data[""])); + +const profile = Social.getr(`${accountId}/profile`, "final"); return ( - + -); \ No newline at end of file +); diff --git a/apps/builddao/widget/page/projects.jsx b/apps/builddao/widget/page/projects.jsx index 8385f4fe..e4572532 100644 --- a/apps/builddao/widget/page/projects.jsx +++ b/apps/builddao/widget/page/projects.jsx @@ -9,7 +9,7 @@ const { theme } = VM.require("buildhub.near/widget/config.theme") ?? { }; const { SidebarLayout } = VM.require( - "buildhub.near/widget/template.SidebarLayout", + "buildhub.near/widget/template.SidebarLayout" ) || { SidebarLayout: () => <>, }; @@ -20,6 +20,12 @@ const Root = styled.div` ${theme}// can come from config `; +const [activeRoute, setActiveRoute] = useState(page); + +useEffect(() => { + setActiveRoute(page); +}, [page]); + function Router({ active, routes }) { // this may be converted to a module at devs.near/widget/Router const routeParts = active.split("."); @@ -62,10 +68,7 @@ const Content = styled.div` return ( - + diff --git a/apps/builddao/widget/template/ProjectLayout.jsx b/apps/builddao/widget/template/ProjectLayout.jsx index 833e69d5..927c747b 100644 --- a/apps/builddao/widget/template/ProjectLayout.jsx +++ b/apps/builddao/widget/template/ProjectLayout.jsx @@ -58,7 +58,7 @@ const ProfileInfo = styled.div` .info { display: flex; - align-items: center; + align-items: flex-start; gap: 4px; flex-direction: column; h3 { @@ -107,7 +107,30 @@ const Nav = styled.div` } `; -const ProjectLayout = ({ accountId, profile, routes, children }) => { +const ProjectLayout = ({ + accountId, + profile, + routes, + children, + project, + id, +}) => { + const { + title, + description, + tags, + collaborators, + projectLink, + demoLink, + contactInfo, + referrer, + learning, + } = project; + + const [address, app, type, titleUrl] = id.split("/"); + + console.log("params", { app, type, titleUrl }); + if (!accountId) { return

No Account ID

; } @@ -159,7 +182,7 @@ const ProjectLayout = ({ accountId, profile, routes, children }) => {
-

{profile.name}

+

{title ?? profile.name}

@{accountId}

@@ -182,8 +205,12 @@ const ProjectLayout = ({ accountId, profile, routes, children }) => {
  • @@ -197,7 +224,7 @@ const ProjectLayout = ({ accountId, profile, routes, children }) => { aria-controls={`pills-${it}`} aria-selected={i === 0} > - {it} + {it.slice(0, 1).toUpperCase() + it.slice(1)}