feat: public events/polls, friends graph, captcha, SSE hardening, and admin UX
Ship product gaps: register/vote pages, friend add/accept/decline/remove, email verify TTL, captcha on login/forgot, soft-fail user actions, SSE abort/shared client, Commando Centrum error toasts, admin delete for events/polls, and IT/NL i18n fills. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
2ff08e5127
commit
ed7db6e048
76 files changed
+4834
-1376
No files matched your search
@@ -18,6 +18,7 @@ import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { adminFetch } from "@/lib/admin-fetch";
|
||||
import { readSseStream } from "@/lib/sse-client";
|
||||
|
||||
interface PetItem {
|
||||
lib: string;
|
||||
@@ -109,34 +110,22 @@ export function ImportPetsClient() {
|
||||
setBatchProgress(null);
|
||||
return;
|
||||
}
|
||||
const reader = res.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buf = "";
|
||||
let done = 0;
|
||||
let succeeded = 0;
|
||||
let failed = 0;
|
||||
while (true) {
|
||||
const { value, done: streamDone } = await reader.read();
|
||||
if (streamDone) break;
|
||||
buf += decoder.decode(value, { stream: true });
|
||||
const parts = buf.split("\n\n");
|
||||
buf = parts.pop() ?? "";
|
||||
for (const part of parts) {
|
||||
if (!part.startsWith("data: ")) continue;
|
||||
const evt = JSON.parse(part.slice(6));
|
||||
if (evt.type === "item_progress" && evt.status === "done") {
|
||||
done++;
|
||||
markDone(evt.classname);
|
||||
setBatchProgress({ done, total: items.length });
|
||||
} else if (evt.type === "item_progress" && evt.status === "failed") {
|
||||
done++;
|
||||
setBatchProgress({ done, total: items.length });
|
||||
} else if (evt.type === "batch_complete") {
|
||||
succeeded = evt.succeeded;
|
||||
failed = evt.failed;
|
||||
}
|
||||
await readSseStream(res.body, (evt) => {
|
||||
if (evt.type === "item_progress" && evt.status === "done") {
|
||||
done++;
|
||||
markDone(String(evt.classname ?? ""));
|
||||
setBatchProgress({ done, total: items.length });
|
||||
} else if (evt.type === "item_progress" && evt.status === "failed") {
|
||||
done++;
|
||||
setBatchProgress({ done, total: items.length });
|
||||
} else if (evt.type === "batch_complete") {
|
||||
succeeded = Number(evt.succeeded ?? 0);
|
||||
failed = Number(evt.failed ?? 0);
|
||||
}
|
||||
}
|
||||
});
|
||||
setBatchProgress(null);
|
||||
setSelected(new Set());
|
||||
if (succeeded > 0) toast.success(`${succeeded} pet(s) imported`);
|
||||
|
||||
Reference in new issue
Block a user