import { SourceAvailable } from "@/components/SourceAvailable" import { Button } from "@/components/ui/button" import { api } from "@/convex/_generated/api" import type { Doc } from "@/convex/_generated/dataModel" import { ArtifactType } from "@/convex/lib/filename" import { useMutation } from "convex/react" import { useState } from "react" import { toast } from "sonner" interface BuildDownloadButtonProps { build: Doc<"builds"> type: ArtifactType variant?: "default" | "outline" className?: string compact?: boolean } export function BuildDownloadButton({ build, type, variant, className, compact = false }: BuildDownloadButtonProps) { const generateDownloadUrl = useMutation(api.builds.generateDownloadUrl) const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) // Default styling based on type const defaultVariant = variant ?? (type === ArtifactType.Firmware ? "default" : "outline") const defaultClassName = className ?? (type === ArtifactType.Firmware ? "bg-cyan-600 hover:bg-cyan-700" : "bg-slate-700 hover:bg-slate-600") const handleDownload = async () => { setError(null) setIsLoading(true) try { const url = await generateDownloadUrl({ buildId: build._id, artifactType: type, }) window.location.href = url } catch (err) { const message = err instanceof Error ? err.message : String(err) const errorMsg = type === ArtifactType.Firmware ? "Failed to generate download link." : "Failed to generate source download link." setError(errorMsg) toast.error(errorMsg, { description: message, }) } finally { setIsLoading(false) } } if (type === ArtifactType.Firmware && !build.buildHash) return null const buttonElement = ( ) if (compact) { return buttonElement } const button = (
{buttonElement} {type === ArtifactType.Firmware && (

Need help flashing?{" "} ESP32 {" "} and{" "} nRF52

)} {error &&

{error}

}
) // For source downloads, only show when sourcePath is available if (type === ArtifactType.Source) { return {button} } return button }