feedback-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev 4a4c54cd95c6
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 54b9c9d7fdc2b68029ce2e57
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
src/Roadmap.tsx
// The public roadmap: what is under review, planned, in progress and done, most voted first
// (done: most recent first).
import { useMemo, useState } from "react";
import { useBoard, boardPath, Empty } from "./Board";
import { VoteButton } from "./Ideas";
import { ROADMAP, STATUS_LABEL, parseIds, sortPosts, listed } from "../functions/lib/feedback";

const DONE_SHOWN = 12;

export function Roadmap() {
  const { boardId, posts, tags } = useBoard();
  const [allDone, setAllDone] = useState(false);
  const columns = useMemo(() => {
    const visible = listed(posts).filter((p) => !p.hidden);
    return ROADMAP.map((s) => ({
      status: s,
      posts: s === "done"
        ? visible.filter((p) => p.status === s).sort((a, b) => b.statusAt - a.statusAt)
        : sortPosts(visible.filter((p) => p.status === s), "top"),
    }));
  }, [posts]);

  if (!columns.some((c) => c.posts.length)) return (
    <Empty title="Nothing on the roadmap yet">
      <p className="muted">Ideas show up here once the board's team marks them under review, planned, in progress or done.</p>
    </Empty>
  );

  return (
    <div className="roadmap">
      {columns.map((c) => {
        const list = c.status === "done" && !allDone ? c.posts.slice(0, DONE_SHOWN) : c.posts;
        return (
          <section key={c.status} className={`road-col road-${c.status}`} aria-label={STATUS_LABEL[c.status]}>
            <h2 className="road-head"><span className={`dot dot-${c.status}`} aria-hidden="true" />{STATUS_LABEL[c.status]}<span className="road-count">{c.posts.length}</span></h2>
            {list.length ? (
              <ul className="road-list">
                {list.map((p) => {
                  const ids = parseIds(p.tags);
                  return (
                    <li key={p.id} className="road-card">
                      <VoteButton post={p} />
                      <div className="road-card-body">
                        <a href={boardPath(boardId, `/p/${p.id}`)} data-nav>{p.title}</a>
                        {ids.length > 0 && <p className="road-tags">{tags.filter((t) => ids.includes(t.id)).map((t) => <span key={t.id} className="tag">{t.name}</span>)}</p>}
                      </div>
                    </li>
                  );
                })}
              </ul>
            ) : <p className="road-empty">Nothing here yet.</p>}
            {c.status === "done" && c.posts.length > DONE_SHOWN && !allDone && (
              <button className="link-btn" type="button" onClick={() => setAllDone(true)}>Show all {c.posts.length}</button>
            )}
          </section>
        );
      })}
    </div>
  );
}

Change history

Point store links to openapps.free
4a4c54cd95 · 18 hours ago
Release with preview
1d0728818d · 19 hours ago
Retry release
1abc843b3f · 19 hours ago
Bind app agent address in policy
00eb15f50d · 19 hours ago
Use OpenApps service URLs and add contribution strip
347a7b8ca0 · 19 hours ago
Bounded source sync
a0aaceae63 · 1 day ago
Bounded source sync
3125b8113f · 1 day ago
Bounded source sync
882a76ba95 · 1 day ago
Bounded source sync
852d9782ee · 1 day ago
Bounded source sync
a8ee705109 · 1 day ago