v2: global player, infinite scroll, image picker, threaded comments
This commit is contained in:
@@ -20,13 +20,15 @@ type DumpEditState =
|
||||
export function DumpEdit() {
|
||||
const { selectedDump } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const { authFetch } = useRequiredAuth();
|
||||
const { authFetch, token } = useRequiredAuth();
|
||||
|
||||
const [state, setState] = useState<DumpEditState>({ status: "loading" });
|
||||
const [url, setUrl] = useState("");
|
||||
const [comment, setComment] = useState("");
|
||||
const [isPrivate, setIsPrivate] = useState(false);
|
||||
const [newFile, setNewFile] = useState<File | null>(null);
|
||||
const [confirmDelete, setConfirmDelete] = useState(false);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedDump) return;
|
||||
@@ -37,6 +39,7 @@ export function DumpEdit() {
|
||||
try {
|
||||
const res = await fetch(`${API_URL}/api/dumps/${selectedDump}`, {
|
||||
cache: "no-store",
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
});
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
|
||||
@@ -46,6 +49,7 @@ export function DumpEdit() {
|
||||
const dump: Dump = deserializeDump(apiResponse.data);
|
||||
setUrl(dump.url ?? "");
|
||||
setComment(dump.comment ?? "");
|
||||
setIsPrivate(dump.isPrivate);
|
||||
setState({ status: "loaded", dump });
|
||||
} else {
|
||||
setState({ status: "error", error: apiResponse.error.message });
|
||||
@@ -74,8 +78,8 @@ export function DumpEdit() {
|
||||
});
|
||||
} else {
|
||||
const body: UpdateDumpRequest = state.dump.kind === "url"
|
||||
? { url: url.trim() || undefined, comment: comment.trim() || undefined }
|
||||
: { comment: comment.trim() || undefined };
|
||||
? { url: url.trim() || undefined, comment: comment.trim() || undefined, isPrivate }
|
||||
: { comment: comment.trim() || undefined, isPrivate };
|
||||
res = await authFetch(`${API_URL}/api/dumps/${state.dump.id}`, {
|
||||
method: "PUT",
|
||||
body: JSON.stringify(body),
|
||||
@@ -102,6 +106,25 @@ export function DumpEdit() {
|
||||
navigate(`/dumps/${updatedDump.id}`, { state: { dump: updatedDump } });
|
||||
};
|
||||
|
||||
const handleRefreshMetadata = async () => {
|
||||
if (state.status !== "loaded" || state.dump.kind !== "url") return;
|
||||
|
||||
setRefreshing(true);
|
||||
try {
|
||||
const res = await authFetch(
|
||||
`${API_URL}/api/dumps/${state.dump.id}/refresh-metadata`,
|
||||
{ method: "POST" },
|
||||
);
|
||||
const apiResponse = await res.json();
|
||||
if (apiResponse.success) {
|
||||
const updatedDump: Dump = deserializeDump(apiResponse.data);
|
||||
setState({ status: "loaded", dump: updatedDump });
|
||||
}
|
||||
} finally {
|
||||
setRefreshing(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = async () => {
|
||||
if (state.status !== "loaded") return;
|
||||
|
||||
@@ -176,6 +199,16 @@ export function DumpEdit() {
|
||||
{dump.url}
|
||||
</a>
|
||||
)}
|
||||
{dump.kind === "url" && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn-secondary dump-edit-refresh"
|
||||
onClick={handleRefreshMetadata}
|
||||
disabled={refreshing}
|
||||
>
|
||||
{refreshing ? "Refreshing…" : "Refresh metadata"}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<form
|
||||
@@ -230,6 +263,21 @@ export function DumpEdit() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<label className="toggle-row">
|
||||
<span className="toggle-label">Public</span>
|
||||
<span className="toggle-switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={!isPrivate}
|
||||
onChange={(e) => setIsPrivate(!e.target.checked)}
|
||||
/>
|
||||
<span className="toggle-thumb" />
|
||||
</span>
|
||||
{isPrivate && (
|
||||
<span className="toggle-hint">Only visible to you</span>
|
||||
)}
|
||||
</label>
|
||||
|
||||
<div className="form-actions">
|
||||
<button
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user