Merge pull request #74 from johndoe6345789/codex/move-helpers-to-a-custom-hook

Move GitHub badge/format/copy helpers into hook and expose actions
This commit is contained in:
2026-01-18 00:59:32 +00:00
committed by GitHub
2 changed files with 67 additions and 50 deletions

View File

@@ -241,12 +241,9 @@ export function GitHubBuildStatus({ owner, repo, defaultBranch = 'main' }: GitHu
loading,
error,
copiedBadge,
fetchData,
copyBadgeMarkdown,
getBadgeUrl,
getBadgeMarkdown,
formatTime,
actions,
} = useGithubBuildStatus({ owner, repo, defaultBranch })
const { refresh, copyBadgeMarkdown, getBadgeUrl, getBadgeMarkdown, formatTime } = actions
if (loading) {
return (
@@ -291,7 +288,7 @@ export function GitHubBuildStatus({ owner, repo, defaultBranch = 'main' }: GitHu
<XCircle size={20} weight="fill" className="text-red-500 mt-0.5" />
<div className="flex-1 space-y-2">
<p className="text-sm text-red-500">{error}</p>
<Button size="sm" variant="outline" onClick={fetchData} className="text-xs">
<Button size="sm" variant="outline" onClick={refresh} className="text-xs">
{copy.error.retry}
</Button>
</div>
@@ -331,7 +328,7 @@ export function GitHubBuildStatus({ owner, repo, defaultBranch = 'main' }: GitHu
</CardTitle>
<CardDescription>{copy.header.description}</CardDescription>
</div>
<Button size="sm" variant="ghost" onClick={fetchData} className="text-xs">
<Button size="sm" variant="ghost" onClick={refresh} className="text-xs">
{copy.header.refresh}
</Button>
</div>

View File

@@ -1,4 +1,4 @@
import { useCallback, useEffect, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { toast } from 'sonner'
import copy from '@/data/github-build-status.json'
@@ -31,9 +31,6 @@ interface UseGithubBuildStatusArgs {
defaultBranch?: string
}
const formatWithCount = (template: string, count: number) =>
template.replace('{count}', count.toString())
export const useGithubBuildStatus = ({
owner,
repo,
@@ -45,6 +42,10 @@ export const useGithubBuildStatus = ({
const [error, setError] = useState<string | null>(null)
const [copiedBadge, setCopiedBadge] = useState<string | null>(null)
const formatWithCount = useCallback((template: string, count: number) => {
return template.replace('{count}', count.toString())
}, [])
const fetchData = useCallback(async () => {
try {
setLoading(true)
@@ -79,53 +80,72 @@ export const useGithubBuildStatus = ({
fetchData()
}, [fetchData])
const getBadgeUrl = (workflowPath: string, branch = defaultBranch) => {
const workflowFile = workflowPath.split('/').pop()
if (branch) {
return `https://github.com/${owner}/${repo}/actions/workflows/${workflowFile}/badge.svg?branch=${branch}`
}
return `https://github.com/${owner}/${repo}/actions/workflows/${workflowFile}/badge.svg`
}
const getBadgeUrl = useCallback(
(workflowPath: string, branch = defaultBranch) => {
const workflowFile = workflowPath.split('/').pop()
if (branch) {
return `https://github.com/${owner}/${repo}/actions/workflows/${workflowFile}/badge.svg?branch=${branch}`
}
return `https://github.com/${owner}/${repo}/actions/workflows/${workflowFile}/badge.svg`
},
[defaultBranch, owner, repo],
)
const getBadgeMarkdown = (workflowPath: string, workflowName: string, branch?: string) => {
const badgeUrl = getBadgeUrl(workflowPath, branch)
const actionUrl = `https://github.com/${owner}/${repo}/actions/workflows/${workflowPath.split('/').pop()}`
return `[![${workflowName}](${badgeUrl})](${actionUrl})`
}
const getBadgeMarkdown = useCallback(
(workflowPath: string, workflowName: string, branch?: string) => {
const badgeUrl = getBadgeUrl(workflowPath, branch)
const actionUrl = `https://github.com/${owner}/${repo}/actions/workflows/${workflowPath.split('/').pop()}`
return `[![${workflowName}](${badgeUrl})](${actionUrl})`
},
[getBadgeUrl, owner, repo],
)
const copyBadgeMarkdown = (workflowPath: string, workflowName: string, branch?: string) => {
const markdown = getBadgeMarkdown(workflowPath, workflowName, branch)
navigator.clipboard.writeText(markdown)
const key = `${workflowPath}-${branch || defaultBranch}`
setCopiedBadge(key)
toast.success(copy.toast.badgeCopied)
setTimeout(() => setCopiedBadge(null), 2000)
}
const copyBadgeMarkdown = useCallback(
(workflowPath: string, workflowName: string, branch?: string) => {
const markdown = getBadgeMarkdown(workflowPath, workflowName, branch)
navigator.clipboard.writeText(markdown)
const key = `${workflowPath}-${branch || defaultBranch}`
setCopiedBadge(key)
toast.success(copy.toast.badgeCopied)
setTimeout(() => setCopiedBadge(null), 2000)
},
[defaultBranch, getBadgeMarkdown],
)
const formatTime = (dateString: string) => {
const date = new Date(dateString)
const now = new Date()
const diff = now.getTime() - date.getTime()
const minutes = Math.floor(diff / 60000)
const hours = Math.floor(minutes / 60)
const days = Math.floor(hours / 24)
const formatTime = useCallback(
(dateString: string) => {
const date = new Date(dateString)
const now = new Date()
const diff = now.getTime() - date.getTime()
const minutes = Math.floor(diff / 60000)
const hours = Math.floor(minutes / 60)
const days = Math.floor(hours / 24)
if (days > 0) return formatWithCount(copy.time.daysAgo, days)
if (hours > 0) return formatWithCount(copy.time.hoursAgo, hours)
if (minutes > 0) return formatWithCount(copy.time.minutesAgo, minutes)
return copy.time.justNow
}
if (days > 0) return formatWithCount(copy.time.daysAgo, days)
if (hours > 0) return formatWithCount(copy.time.hoursAgo, hours)
if (minutes > 0) return formatWithCount(copy.time.minutesAgo, minutes)
return copy.time.justNow
},
[formatWithCount],
)
const actions = useMemo(
() => ({
refresh: fetchData,
copyBadgeMarkdown,
getBadgeUrl,
getBadgeMarkdown,
formatTime,
}),
[copyBadgeMarkdown, fetchData, formatTime, getBadgeMarkdown, getBadgeUrl],
)
return {
workflows,
allWorkflows,
loading,
error,
workflows,
allWorkflows,
copiedBadge,
fetchData,
copyBadgeMarkdown,
getBadgeUrl,
getBadgeMarkdown,
formatTime,
actions,
}
}