on master help sign in
Miscellaneous quality of life improvements to Grants (#739)
d67be41Josh Lehman
components/GrantPreview.js+3−2
@@ -2,7 +2,8 @@ import classnames from "classnames";
2import Link from "next/link";
2import Link from "next/link";
3
3
4export default function GrantPreview({ grant }) {
4export default function GrantPreview({ grant }) {
5+ const isCompleted = grant.extra.completed;
5− const isOpen = !grant.extra.completed && grant.extra.assignee === "";
6+ const isOpen = !isCompleted && grant.extra.assignee === "";
6 const type = grant.taxonomies.grant_type;
7 const type = grant.taxonomies.grant_type;
7
8
8 const className = classnames({
9 const className = classnames({
@@ -23,7 +24,7 @@ export default function GrantPreview({ grant }) {
23 {grant.title}
24 {grant.title}
24 </h3>
25 </h3>
25 <div className={`bg-gray text-wall badge-sm ml-2`}>
26 <div className={`bg-gray text-wall badge-sm ml-2`}>
26− {isOpen ? "Open" : "Completed"}
27+ {!isCompleted ? (isOpen ? "Open" : "In Progress") : "Completed"}
27 </div>
28 </div>
28 </div>
29 </div>
29 <p className="mb-4">{grant.extra.description}</p>
30 <p className="mb-4">{grant.extra.description}</p>
content/grants/ra-page-tracking.md+1−1
@@ -9,7 +9,7 @@ image = ""
9description = "Improve Page Tracking"
9description = "Improve Page Tracking"
10reward = 2
10reward = 2
11mentor = "~silsyn-wathep"
11mentor = "~silsyn-wathep"
12−assignee = "~sovmep-ripsum"
12+assignee = ""
13completed = false
13completed = false
14work_request_link = "https://airtable.com/shr4qt9t9kz7RaOIa?prefill_Grant+ID=A0039&prefill_Grant+Name=Runtime%20Apprenticeship%3A%20Improve%20Page%20Tracking"
14work_request_link = "https://airtable.com/shr4qt9t9kz7RaOIa?prefill_Grant+ID=A0039&prefill_Grant+Name=Runtime%20Apprenticeship%3A%20Improve%20Page%20Tracking"
15+++
15+++
pages/grants.js+132−73
@@ -71,42 +71,59 @@ export default function Grants({
71}) {
71}) {
72 const [activeTags, setTags] = useState([]);
72 const [activeTags, setTags] = useState([]);
73 const [activeTypes, setTypes] = useState(types);
73 const [activeTypes, setTypes] = useState(types);
74+ const [includeOpen, setIncludeOpen] = useState(true);
74 const [includeCompleted, setIncludeCompleted] = useState(false);
75 const [includeCompleted, setIncludeCompleted] = useState(false);
76+ const [includeInProgress, setIncludeInProgress] = useState(false);
75 const [tab, setTab] = useState(0);
77 const [tab, setTab] = useState(0);
76 const post = {
78 const post = {
77 title: "Grants",
79 title: "Grants",
78 description: "Contribute to the Urbit project while earning address space.",
80 description: "Contribute to the Urbit project while earning address space.",
79 };
81 };
80
82
81− const postsByCompletion = posts.filter((post) => {
83+ const annotatedPosts = posts.map((post) => {
82− return includeCompleted
84+ if (post.extra.completed) {
83− ? true
85+ return { ...post, status: "completed" };
84− : !post.extra.completed && post.extra.assignee === "";
86+ } else if (post.extra.assignee && post.extra.assignee.length > 0) {
87+ return { ...post, status: "wip" };
88+ } else {
89+ return { ...post, status: "open" };
90+ }
85 });
91 });
86
92
93+ const byStatus = (post) => {
94+ return (
95+ (includeOpen ? post.status === "open" : false) ||
96+ (includeCompleted ? post.status === "completed" : false) ||
97+ (includeInProgress ? post.status === "wip" : false)
98+ );
99+ };
100+
101+ const postsByStatus = annotatedPosts.filter(byStatus);
102+
87− const filteredPosts = postsByCompletion.filter((post) => {
103+ const filteredPosts = annotatedPosts.filter((post) => {
88 // Posts are returned if they match both the selected category and selected tags, or if the user has no category filters set.
104 // Posts are returned if they match both the selected category and selected tags, or if the user has no category filters set.
89 const hasCategory = post.taxonomies.grant_category.some((category) =>
105 const hasCategory = post.taxonomies.grant_category.some((category) =>
90 activeTags.includes(category)
106 activeTags.includes(category)
91 );
107 );
108+
92 const noTagsSelected = activeTags.length === 0;
109 const noTagsSelected = activeTags.length === 0;
93 const hasType = post.taxonomies.grant_type.some((type) =>
110 const hasType = post.taxonomies.grant_type.some((type) =>
94 activeTypes.includes(type)
111 activeTypes.includes(type)
95 );
112 );
96
113
97− return (hasCategory || noTagsSelected) && hasType;
114+ return (hasCategory || noTagsSelected) && byStatus(post) && hasType;
98 });
115 });
99
116
100− const allCount = postsByCompletion.length;
117+ const allCount = postsByStatus.length;
101
118
102 const counts = {
119 const counts = {
103− Bounty: postsByCompletion.filter((post) =>
120+ Bounty: postsByStatus.filter((post) =>
104 post.taxonomies.grant_type.includes("Bounty")
121 post.taxonomies.grant_type.includes("Bounty")
105 ).length,
122 ).length,
106− Apprenticeship: postsByCompletion.filter((post) =>
123+ Apprenticeship: postsByStatus.filter((post) =>
107 post.taxonomies.grant_type.includes("Apprenticeship")
124 post.taxonomies.grant_type.includes("Apprenticeship")
108 ).length,
125 ).length,
109− Proposal: postsByCompletion.filter((post) =>
126+ Proposal: postsByStatus.filter((post) =>
110 post.taxonomies.grant_type.includes("Proposal")
127 post.taxonomies.grant_type.includes("Proposal")
111 ).length,
128 ).length,
112 };
129 };
@@ -123,7 +140,7 @@ export default function Grants({
123 // Heading and introduction
140 // Heading and introduction
124 }
141 }
125 <Section wide short>
142 <Section wide short>
126− <div className="flex flex-column justify-between">
143+ <div className="flex flex-column justify-between pb-16">
127 <div>
144 <div>
128 <h1 className="pb-16">Grants</h1>
145 <h1 className="pb-16">Grants</h1>
129 <p className="mb-8">
146 <p className="mb-8">
@@ -137,7 +154,23 @@ export default function Grants({
137 at urbit.org, Tlon developers, and community mentors.
154 at urbit.org, Tlon developers, and community mentors.
138 </p>
155 </p>
139 </div>
156 </div>
140− <TableOfContents staticPosition noh3s />
157+ </div>
158+ <div className="flex flex-wrap">
159+ <Link href="#find-a-grant">
160+ <button className="button-lg bg-green text-white mr-2">
161+ View Grants
162+ </button>
163+ </Link>
164+ <Link href="#proposals">
165+ <button className="button-lg bg-blue text-white mr-2">
166+ Submit a Proposal
167+ </button>
168+ </Link>
169+ <Link href="#gifts">
170+ <a className="button-lg bg-ultraDeepWall text-white mr-2">
171+ Recent Gifts
172+ </a>
173+ </Link>
141 </div>
174 </div>
142 </Section>
175 </Section>
143 {
176 {
@@ -171,12 +204,79 @@ export default function Grants({
171 })}
204 })}
172 </div>
205 </div>
173 </Section>
206 </Section>
174− {
207+ {/* Submit a proposal */}
208+ <Section wide>
209+ <h2 className="mb-16" id="proposals">
210+ Proposals
211+ </h2>
212+ <p className="mb-8">
213+ Contributors are also welcome to have their personal projects
214+ considered as a proposal. If you'd like to propose a project for the
215+ grants program, first review our
216+ <a href="/grant-submission-guide">submission guide</a>, and feel
217+ free to{" "}
218+ <a href="https://airtable.com/shrCi54rEDxgSZr3z">
219+ submit your proposal
220+ </a>
221+ .
222+ </p>
223+
224+ <Link href="#find-a-grant">
225+ <button
226+ className="button-lg bg-blue text-white mr-2"
227+ onClick={() => {
228+ setIncludeInProgress(true);
229+ setIncludeCompleted(true);
230+ setTab(1);
231+ setTypes(["Proposal"]);
232+ }}
233+ >
234+ View Proposals
235+ </button>
236+ </Link>
237+ </Section>
238+ {/* Gift Grants */}
239+ <Section wide>
240+ <div className="pb-16">
241+ <h2 className="pb-16" id="gifts">
242+ Gifts
243+ </h2>
244+ <p className="mb-8">
245+ Gifts are given post-facto for exceptional contributions.
246+ </p>
247+ {/* Uncomment once people added to content/gifts folder. */}
248+ {/* {gifts.map((e) => {
249+ return (
250+ <div className="bg-wall rounded-xl p-4 my-8 flex justify-between">
251+ <p className="font-semibold">
252+ {e.name}
253+ </p>
254+ <p>{e.planet}</p>
255+ <p>{e.date}</p>
256+ <a className="type-p" href={e.link}>Link</a>
257+ </div>
258+ )
259+ })} */}
260+ <div className="flex flex-wrap">
261+ <PostPreview
262+ post={giftPosts[0]}
263+ className={`w-full md:w-1/2 pr-0 pb-8 md:pr-4`}
264+ key={giftPosts[0].slug}
265+ section={giftPosts[0].section}
266+ />
267+ <PostPreview
268+ post={giftPosts[1]}
269+ className={`w-full md:w-1/2 pl-0 pb-8 md:pl-4`}
270+ key={giftPosts[1].slug}
271+ section={giftPosts[1].section}
272+ />
273+ </div>
274+ </div>
275+ </Section>
175− // Find a Grant
276+ {/* Find a Grant */}
176− }
177 <Section wide>
277 <Section wide>
178 <h2 id="find-a-grant" className="pb-8">
278 <h2 id="find-a-grant" className="pb-8">
179− Find A Grant
279+ Find a Grant
180 </h2>
280 </h2>
181 <h5 className="text-black font-semibold my-2">Work Programs</h5>
281 <h5 className="text-black font-semibold my-2">Work Programs</h5>
182 <div className="flex flex-wrap items-center pb-2">
282 <div className="flex flex-wrap items-center pb-2">
@@ -233,6 +333,13 @@ export default function Grants({
233 </div>
333 </div>
234 {
334 {
235 <div className="pb-8 flex items-center">
335 <div className="pb-8 flex items-center">
336+ <button
337+ className="mr-4 badge-sm bg-black text-white"
338+ onClick={() => setIncludeOpen(!includeOpen)}
339+ >
340+ {includeOpen ? "Exclude Open" : "Include Open"}
341+ </button>
342+
236 <button
343 <button
237 className="mr-4 badge-sm bg-black text-white"
344 className="mr-4 badge-sm bg-black text-white"
238 onClick={() => setIncludeCompleted(!includeCompleted)}
345 onClick={() => setIncludeCompleted(!includeCompleted)}
@@ -240,6 +347,15 @@ export default function Grants({
240 {includeCompleted ? "Exclude Completed" : "Include Completed"}
347 {includeCompleted ? "Exclude Completed" : "Include Completed"}
241 </button>
348 </button>
242
349
350+ <button
351+ className="mr-4 badge-sm bg-black text-white"
352+ onClick={() => setIncludeInProgress(!includeInProgress)}
353+ >
354+ {includeInProgress
355+ ? "Exclude In Progress"
356+ : "Include In Progress"}
357+ </button>
358+
243 <h4>
359 <h4>
244 Showing {filteredPosts.length} grant
360 Showing {filteredPosts.length} grant
245 {filteredPosts.length === 1 ? "" : "s"}
361 {filteredPosts.length === 1 ? "" : "s"}
@@ -250,63 +366,6 @@ export default function Grants({
250 return <GrantPreview grant={post} />;
366 return <GrantPreview grant={post} />;
251 })}
367 })}
252 </Section>
368 </Section>
253− {/* Submit a proposal */}
254− <Section wide>
255− <h2 className="mb-16" id="proposals">
256− Proposals
257− </h2>
258− <p className="mb-8">
259− Contributors are also welcome to have their personal projects
260− considered as a proposal. If you'd like to propose a project for the
261− grants program, first review our
262− <a href="/grant-submission-guide">submission guide</a>, and feel
263− free to{" "}
264− <a href="https://airtable.com/shrCi54rEDxgSZr3z">
265− submit your proposal
266− </a>
267− .
268− </p>
269− </Section>
270− {
271− // Gift Grants
272− }
273− <Section wide>
274− <div className="pb-16">
275− <h2 className="pb-16" id="gifts">
276− Gifts
277− </h2>
278− <p className="mb-8">
279− Gifts are given post-facto for exceptional contributions.
280− </p>
281− {/* Uncomment once people added to content/gifts folder. */}
282− {/* {gifts.map((e) => {
283− return (
284− <div className="bg-wall rounded-xl p-4 my-8 flex justify-between">
285− <p className="font-semibold">
286− {e.name}
287− </p>
288− <p>{e.planet}</p>
289− <p>{e.date}</p>
290− <a className="type-p" href={e.link}>Link</a>
291− </div>
292− )
293− })} */}
294− <div className="flex flex-wrap">
295− <PostPreview
296− post={giftPosts[0]}
297− className={`w-full md:w-1/2 pr-0 pb-8 md:pr-4`}
298− key={giftPosts[0].slug}
299− section={giftPosts[0].section}
300− />
301− <PostPreview
302− post={giftPosts[1]}
303− className={`w-full md:w-1/2 pl-0 pb-8 md:pl-4`}
304− key={giftPosts[1].slug}
305− section={giftPosts[1].section}
306− />
307− </div>
308− </div>
309− </Section>
310 </SingleColumn>
369 </SingleColumn>
311 <Footer />
370 <Footer />
312 </Container>
371 </Container>
pages/grants/[slug].js+4−2
@@ -37,8 +37,10 @@ export default function Grant({ post, markdown, search, similarGrants }) {
37 <Header search={search} />
37 <Header search={search} />
38 <Section narrow short>
38 <Section narrow short>
39 <h1>{post.title}</h1>
39 <h1>{post.title}</h1>
40− {post.extra.author ? (
40+ {post.extra.assignee ? (
41− <div className="type-ui text-gray mt-4">{post.extra.author}</div>
41+ <div className="type-ui text-gray mt-4">
42+ Grantee: {post.extra.assignee}
43+ </div>
42 ) : null}
44 ) : null}
43 {post.extra.ship ? (
45 {post.extra.ship ? (
44 <div className="type-ui text-gray font-mono">{post.extra.ship}</div>
46 <div className="type-ui text-gray font-mono">{post.extra.ship}</div>