Replace `catch (e: any)` with `catch (e)` and read the message through a new errorMessage() helper. ApiError.data gets a real type, and useDismissingState's setter keeps one identity across renders. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
"use client";
|
|
|
|
import React, { useRef, useState } from "react";
|
|
import { useAuth } from "@/hooks/useAuth";
|
|
import { apiFetch } from "@/lib/api";
|
|
import { errorMessage } from "@/lib/utils";
|
|
|
|
export function FileUploader({ onUploaded }: { onUploaded: (url: string) => void }) {
|
|
const { token } = useAuth();
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
|
|
|
async function upload(file: File) {
|
|
if (!token) { setError("Please login"); return; }
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
const fd = new FormData();
|
|
fd.append("image", file);
|
|
const data = await apiFetch<{ url: string }>(`/api/uploads/event-image`, {
|
|
method: "POST",
|
|
body: fd,
|
|
authToken: token,
|
|
});
|
|
onUploaded(data.url);
|
|
} catch (e) {
|
|
setError(errorMessage(e) || "Upload failed");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<input
|
|
ref={inputRef}
|
|
type="file"
|
|
accept="image/*"
|
|
className="block w-full text-sm"
|
|
onChange={(e) => {
|
|
const f = e.target.files?.[0];
|
|
if (f) upload(f);
|
|
}}
|
|
/>
|
|
{loading && <p className="text-xs text-gray-600 mt-1">Uploading...</p>}
|
|
{error && <p className="text-xs text-red-600 mt-1">{error}</p>}
|
|
</div>
|
|
);
|
|
}
|