Files
linsa-linsa-io/web/shared/minimal-tiptap/components/image/image-edit-block.tsx
Aslam a440828f8c chore: Enhancement + New Feature (#185)
* wip

* wip page

* chore: style

* wip pages

* wip pages

* chore: toggle

* chore: link

* feat: topic search

* chore: page section

* refactor: apply tailwind class ordering

* fix: handle loggedIn user for guest route

* feat: folder & image schema

* chore: move utils to shared

* refactor: tailwind class ordering

* feat: img ext for editor

* refactor: remove qa

* fix: tanstack start

* fix: wrong import

* chore: use toast

* chore: schema
2024-10-18 21:18:20 +07:00

126 lines
3.3 KiB
TypeScript

import * as React from "react"
import type { Editor } from "@tiptap/react"
import { Button } from "@/components/ui/button"
import { Label } from "@/components/ui/label"
import { Input } from "@/components/ui/input"
import { cn } from "@/lib/utils"
import { storeImageFn } from "@shared/actions"
import { ZodError } from "zod"
interface ImageEditBlockProps extends React.HTMLAttributes<HTMLDivElement> {
editor: Editor
close: () => void
}
const ImageEditBlock = ({
editor,
className,
close,
...props
}: ImageEditBlockProps) => {
const fileInputRef = React.useRef<HTMLInputElement>(null)
const [link, setLink] = React.useState<string>("")
const [isUploading, setIsUploading] = React.useState<boolean>(false)
const [error, setError] = React.useState<string | null>(null)
const handleClick = (e: React.MouseEvent) => {
e.preventDefault()
e.stopPropagation()
fileInputRef.current?.click()
}
const handleLink = () => {
editor.chain().focus().setImage({ src: link }).run()
close()
}
const handleFile = async (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files
if (!files || files.length === 0) return
setIsUploading(true)
setError(null)
const formData = new FormData()
formData.append("file", files[0])
try {
const response = await storeImageFn(formData)
editor
.chain()
.setImage({ src: response.fileModel.content.src })
.focus()
.run()
close()
} catch (error) {
if (error instanceof Error) {
try {
const errors = JSON.parse(error.message)
if (errors.body.name === "ZodError") {
setError(
(errors.body as ZodError).issues
.map((issue) => issue.message)
.join(", "),
)
} else {
setError(error.message)
}
} catch (parseError) {
setError(error.message)
}
} else {
setError("An unknown error occurred")
}
} finally {
setIsUploading(false)
}
}
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
e.stopPropagation()
handleLink()
}
return (
<form onSubmit={handleSubmit}>
<div className={cn("space-y-6", className)} {...props}>
<div className="space-y-1">
<Label>Attach an image link</Label>
<div className="flex">
<Input
type="url"
required
placeholder="https://example.com"
value={link}
className="grow"
onChange={(e) => setLink(e.target.value)}
/>
<Button type="submit" className="ml-2 inline-block">
Submit
</Button>
</div>
</div>
<Button className="w-full" onClick={handleClick} disabled={isUploading}>
{isUploading ? "Uploading..." : "Upload from your computer"}
</Button>
<input
type="file"
accept="image/jpeg,image/png,image/gif,image/webp"
ref={fileInputRef}
className="hidden"
onChange={handleFile}
/>
{error && (
<div className="rounded bg-destructive/10 p-2 text-sm text-destructive">
{error}
</div>
)}
</div>
</form>
)
}
export { ImageEditBlock }