100 lines
3.3 KiB
TypeScript
100 lines
3.3 KiB
TypeScript
"use client"
|
|||
|
|
|
||
|
|
import { useRef, useState } from "react"
|
||
|
|
import { useRouter } from "next/navigation"
|
||
|
|
import { toast } from "sonner"
|
||
|
|
import { FileText, Upload, ExternalLink, Loader2 } from "lucide-react"
|
||
|
|
import { setLeaseDocument } from "@/app/actions/esign"
|
||
|
|
|
||
|
|
export function LeaseDocument({
|
||
|
|
leaseId,
|
||
|
|
documentUrl,
|
||
|
|
canWrite,
|
||
|
|
}: {
|
||
|
|
leaseId: string
|
||
|
|
documentUrl: string | null
|
||
|
|
canWrite: boolean
|
||
|
|
}) {
|
||
|
|
const router = useRouter()
|
||
|
|
const inputRef = useRef<HTMLInputElement>(null)
|
||
|
|
const [uploading, setUploading] = useState(false)
|
||
|
|
|
||
|
|
async function onPick(e: React.ChangeEvent<HTMLInputElement>) {
|
||
|
|
const file = e.target.files?.[0]
|
||
|
|
if (!file) return
|
||
|
|
if (!/\.(pdf|docx?)$/i.test(file.name)) {
|
||
|
|
toast.error("Upload a PDF or Word document")
|
||
|
|
if (inputRef.current) inputRef.current.value = ""
|
||
|
|
return
|
||
|
|
}
|
||
|
|
setUploading(true)
|
||
|
|
try {
|
||
|
|
const fd = new FormData()
|
||
|
|
fd.append("file", file)
|
||
|
|
fd.append("scope", "documents")
|
||
|
|
const res = await fetch("/api/upload", { method: "POST", body: fd })
|
||
|
|
if (!res.ok) {
|
||
|
|
const j = await res.json().catch(() => ({}))
|
||
|
|
throw new Error(j?.error || "Upload failed")
|
||
|
|
}
|
||
|
|
const { url } = (await res.json()) as { url: string }
|
||
|
|
await setLeaseDocument(leaseId, url)
|
||
|
|
toast.success(documentUrl ? "Lease document replaced" : "Lease document attached")
|
||
|
|
router.refresh()
|
||
|
|
} catch (err) {
|
||
|
|
toast.error(err instanceof Error ? err.message : "Upload failed")
|
||
|
|
} finally {
|
||
|
|
setUploading(false)
|
||
|
|
if (inputRef.current) inputRef.current.value = ""
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="rounded-xl border border-white/[0.06] bg-[#16161f] p-5">
|
||
|
|
<div className="flex items-center justify-between gap-3">
|
||
|
|
<div className="flex min-w-0 items-center gap-2 text-sm font-medium text-white">
|
||
|
|
<FileText className="h-4 w-4 shrink-0 text-indigo-400" />
|
||
|
|
{documentUrl ? "Lease document" : "No lease document yet"}
|
||
|
|
</div>
|
||
|
|
{documentUrl && (
|
||
|
|
<a
|
||
|
|
href={documentUrl}
|
||
|
|
target="_blank"
|
||
|
|
rel="noopener noreferrer"
|
||
|
|
className="inline-flex shrink-0 items-center gap-1 text-xs text-indigo-400 transition hover:text-indigo-300"
|
||
|
|
>
|
||
|
|
View <ExternalLink className="h-3.5 w-3.5" />
|
||
|
|
</a>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{!documentUrl && (
|
||
|
|
<p className="mt-1.5 text-xs text-white/40">Upload the lease PDF to enable sending it for e-signature.</p>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{canWrite && (
|
||
|
|
<div className="mt-3">
|
||
|
|
<input
|
||
|
|
ref={inputRef}
|
||
|
|
type="file"
|
||
|
|
accept=".pdf,.doc,.docx"
|
||
|
|
onChange={onPick}
|
||
|
|
disabled={uploading}
|
||
|
|
className="hidden"
|
||
|
|
id={`lease-doc-${leaseId}`}
|
||
|
|
/>
|
||
|
|
<label
|
||
|
|
htmlFor={`lease-doc-${leaseId}`}
|
||
|
|
className={`inline-flex cursor-pointer items-center gap-1.5 rounded-lg border border-white/10 px-3 py-1.5 text-xs font-medium text-white/70 transition hover:bg-white/[0.06] hover:text-white ${
|
||
|
|
uploading ? "pointer-events-none opacity-50" : ""
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
{uploading ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Upload className="h-3.5 w-3.5" />}
|
||
|
|
{documentUrl ? "Replace document" : "Upload lease document"}
|
||
|
|
</label>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|