CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history
useIssues.ts
Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.
| c53cf00 | 1 | import { useState, useEffect, useCallback } from 'react'; |
| 2 | import { api, type Issue, type IssueComment } from '../api/client'; | |
| 3 | ||
| 4 | export function useIssues(owner: string | null, repo: string | null, state: 'open' | 'closed' | 'all' = 'open') { | |
| 5 | const [issues, setIssues] = useState<Issue[]>([]); | |
| 6 | const [loading, setLoading] = useState(false); | |
| 7 | const [error, setError] = useState<string | null>(null); | |
| 8 | ||
| 9 | const fetch = useCallback(async () => { | |
| 10 | if (!owner || !repo) return; | |
| 11 | setLoading(true); | |
| 12 | setError(null); | |
| 13 | try { | |
| 14 | const data = await api.listIssues(owner, repo, state); | |
| 15 | setIssues(data); | |
| 16 | } catch (err) { | |
| 17 | setError(err instanceof Error ? err.message : 'Failed to load issues'); | |
| 18 | } finally { | |
| 19 | setLoading(false); | |
| 20 | } | |
| 21 | }, [owner, repo, state]); | |
| 22 | ||
| 23 | useEffect(() => { | |
| 24 | fetch(); | |
| 25 | }, [fetch]); | |
| 26 | ||
| 27 | return { issues, loading, error, refresh: fetch }; | |
| 28 | } | |
| 29 | ||
| 30 | export function useIssue(owner: string | null, repo: string | null, number: number | null) { | |
| 31 | const [issue, setIssue] = useState<Issue | null>(null); | |
| 32 | const [comments, setComments] = useState<IssueComment[]>([]); | |
| 33 | const [loading, setLoading] = useState(false); | |
| 34 | const [error, setError] = useState<string | null>(null); | |
| 35 | const [submitting, setSubmitting] = useState(false); | |
| 36 | ||
| 37 | const fetch = useCallback(async () => { | |
| 38 | if (!owner || !repo || number === null) return; | |
| 39 | setLoading(true); | |
| 40 | setError(null); | |
| 41 | try { | |
| 42 | const data = await api.getIssue(owner, repo, number); | |
| 43 | setIssue(data.issue); | |
| 44 | setComments(data.comments); | |
| 45 | } catch (err) { | |
| 46 | setError(err instanceof Error ? err.message : 'Failed to load issue'); | |
| 47 | } finally { | |
| 48 | setLoading(false); | |
| 49 | } | |
| 50 | }, [owner, repo, number]); | |
| 51 | ||
| 52 | useEffect(() => { | |
| 53 | fetch(); | |
| 54 | }, [fetch]); | |
| 55 | ||
| 56 | const addComment = useCallback(async (body: string) => { | |
| 57 | if (!owner || !repo || number === null) return; | |
| 58 | setSubmitting(true); | |
| 59 | try { | |
| 60 | const comment = await api.createIssueComment(owner, repo, number, body); | |
| 61 | setComments((prev) => [...prev, comment]); | |
| 62 | } finally { | |
| 63 | setSubmitting(false); | |
| 64 | } | |
| 65 | }, [owner, repo, number]); | |
| 66 | ||
| 67 | return { issue, comments, loading, error, submitting, refresh: fetch, addComment }; | |
| 68 | } |