IssueList.tsx
⎇
Raw
1import type { IssueRow, RepositoryRow } from "../../db/index.ts";
2import { displayName } from "../../lib/users.ts";
3import type { SessionUser } from "../../middleware/session.ts";
4import { Avatar } from "../Avatar.tsx";
5import { Layout } from "../layout.tsx";
6import { Pagination, type PaginationInfo } from "../Pagination.tsx";
7import { RepoHeader } from "../repos/RepoHeader.tsx";
8import { RepoNav } from "../repos/RepoNav.tsx";
9
10interface IssueListProps {
11 user: SessionUser | null;
12 repo: RepositoryRow;
13 issues: (IssueRow & {
14 author_username: string;
15 author_avatar_version: number | null;
16 })[];
17 status: "open" | "closed" | "completed";
18 counts: Record<string, number>;
19 pagination: PaginationInfo;
20}
21
22export function IssueList({
23 user,
24 repo,
25 issues,
26 status,
27 counts,
28 pagination,
29}: IssueListProps) {
30 return (
31 <Layout user={user} title={`Issues — ${repo.name}`}>
32 <div class="container">
33 <RepoHeader repo={repo} />
34 <RepoNav repo={repo} active="issues" user={user} />
35 <div class="list-header">
36 <div class="list-header-tabs">
37 <a
38 href={`/${repo.name}/issues?status=open`}
39 class={`list-tab${status === "open" ? " active" : ""}`}
40 >
41 Open{" "}
42 {(counts.open ?? 0) > 0 && (
43 <span class="tab-count">{counts.open}</span>
44 )}
45 </a>
46 <a
47 href={`/${repo.name}/issues?status=completed`}
48 class={`list-tab${status === "completed" ? " active" : ""}`}
49 >
50 Completed{" "}
51 {(counts.completed ?? 0) > 0 && (
52 <span class="tab-count">
53 {counts.completed}
54 </span>
55 )}
56 </a>
57 <a
58 href={`/${repo.name}/issues?status=closed`}
59 class={`list-tab${status === "closed" ? " active" : ""}`}
60 >
61 Closed{" "}
62 {(counts.closed ?? 0) > 0 && (
63 <span class="tab-count">{counts.closed}</span>
64 )}
65 </a>
66 </div>
67 {user && (
68 <a
69 href={`/${repo.name}/issues/new`}
70 class="btn btn-primary btn-sm"
71 >
72 New issue
73 </a>
74 )}
75 </div>
76 {issues.length === 0 ? (
77 <div class="empty-state">
78 <p>No {status} issues.</p>
79 </div>
80 ) : (
81 <ul class="issue-list">
82 {issues.map((issue) => (
83 <li class="issue-item">
84 <div class="issue-main">
85 <span
86 class={`issue-status-dot ${issue.status}`}
87 />
88 <a
89 href={`/${repo.name}/issues/${issue.number}`}
90 class="issue-title"
91 >
92 {issue.title}
93 </a>
94 <span class="issue-number">
95 #{issue.number}
96 </span>
97 </div>
98 <div class="issue-meta">
99 <Avatar
100 userId={issue.author_id}
101 version={issue.author_avatar_version}
102 size={20}
103 />
104 <span class="issue-author">
105 opened by{" "}
106 {displayName(issue.author_username)}
107 </span>
108 <time datetime={issue.created_at}>
109 {new Date(
110 issue.created_at,
111 ).toLocaleDateString()}
112 </time>
113 </div>
114 </li>
115 ))}
116 </ul>
117 )}
118 <Pagination {...pagination} />
119 </div>
120 </Layout>
121 );
122}
123