4 changed files with 122 additions and 20 deletions
@ -0,0 +1,80 @@ |
|||||||
|
import { Button } from '@renderer/components/ui/button' |
||||||
|
import { useToast } from '@renderer/hooks/use-toast' |
||||||
|
import { useNostr } from '@renderer/providers/NostrProvider' |
||||||
|
import { ImageUp, LoaderCircle } from 'lucide-react' |
||||||
|
import { useRef, useState } from 'react' |
||||||
|
|
||||||
|
export default function Uploader({ |
||||||
|
setContent |
||||||
|
}: { |
||||||
|
setContent: React.Dispatch<React.SetStateAction<string>> |
||||||
|
}) { |
||||||
|
const [uploading, setUploading] = useState(false) |
||||||
|
const { signHttpAuth } = useNostr() |
||||||
|
const { toast } = useToast() |
||||||
|
const fileInputRef = useRef<HTMLInputElement>(null) |
||||||
|
|
||||||
|
const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => { |
||||||
|
const file = event.target.files?.[0] |
||||||
|
if (!file) return |
||||||
|
|
||||||
|
const formData = new FormData() |
||||||
|
formData.append('file', file) |
||||||
|
|
||||||
|
try { |
||||||
|
setUploading(true) |
||||||
|
const url = 'https://nostr.build/api/v2/nip96/upload' |
||||||
|
const auth = await signHttpAuth(url, 'POST') |
||||||
|
const response = await fetch(url, { |
||||||
|
method: 'POST', |
||||||
|
body: formData, |
||||||
|
headers: { |
||||||
|
Authorization: auth |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
if (!response.ok) { |
||||||
|
throw new Error(response.status.toString()) |
||||||
|
} |
||||||
|
|
||||||
|
const data = await response.json() |
||||||
|
const imageUrl = data.nip94_event?.tags.find(([tagName]) => tagName === 'url')?.[1] |
||||||
|
if (imageUrl) { |
||||||
|
setContent((prevContent) => `${prevContent}\n${imageUrl}`) |
||||||
|
} else { |
||||||
|
throw new Error('No image url found') |
||||||
|
} |
||||||
|
} catch (error) { |
||||||
|
console.error('Error uploading file', error) |
||||||
|
toast({ |
||||||
|
variant: 'destructive', |
||||||
|
title: 'Failed to upload file', |
||||||
|
description: (error as Error).message |
||||||
|
}) |
||||||
|
if (fileInputRef.current) { |
||||||
|
fileInputRef.current.value = '' |
||||||
|
} |
||||||
|
} finally { |
||||||
|
setUploading(false) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const handleUploadClick = () => { |
||||||
|
fileInputRef.current?.click() |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<Button variant="secondary" onClick={handleUploadClick} disabled={uploading}> |
||||||
|
{uploading ? <LoaderCircle className="animate-spin" /> : <ImageUp />} |
||||||
|
</Button> |
||||||
|
<input |
||||||
|
type="file" |
||||||
|
ref={fileInputRef} |
||||||
|
style={{ display: 'none' }} |
||||||
|
onChange={handleFileChange} |
||||||
|
accept="image/*,video/*,audio/*" |
||||||
|
/> |
||||||
|
</> |
||||||
|
) |
||||||
|
} |
||||||
Loading…
Reference in new issue