REPLIT TASK — Delete “Guest Icon (Outlined)” card from Icons
Goal

Remove the “Guest Icon (Outlined)” card from the Icons Library everywhere.

Keep the rest of the icons intact.

Do both:

Immediate FE blocklist (fast no-risk hide).

Backend soft-delete + (optional) file cleanup so it never comes back from /api/icons/list.

1) Frontend — quick, safe hide (blocklist)

File: client/src/pages/**/Icons.tsx (where the grid is rendered)

Add a small blocklist and filter before rendering:

// top of file (or near other constants)
const HIDE_ICON_IDS = new Set(["guest_icon"]);
const HIDE_ICON_NAMES = new Set(["Guest Icon"]); // exact name match
function stripStoragePrefix(id: string) {
  return id?.startsWith("storage-") ? id.slice("storage-".length) : id;
}

// wherever `allIcons` is reduced to `data`, keep the existing filters and add this guard:
const data = useMemo(() => {
  const q = query.trim().toLowerCase();
  return allIcons
    .filter((i) => {
      const rawId = stripStoragePrefix(i.id);
      // hide if id or name matches, and style is outlined (exactly the card we want gone)
      const shouldHide =
        HIDE_ICON_IDS.has(rawId) ||
        (HIDE_ICON_NAMES.has(i.name) && i.style === "outlined");
      if (shouldHide) return false;

      if (style && i.style !== style) return false;
      if (!q) return true;
      return (
        i.name.toLowerCase().includes(q) ||
        i.tags.some((t) => t.toLowerCase().includes(q))
      );
    });
}, [allIcons, query, style]);


✅ This hides the bad card immediately, even if the backend still returns it.

2) Backend — soft-delete it from /api/icons/list

File: server/routes/iconLibraryRoutes.js (or wherever /api/icons/list is defined)

A) Ensure the list endpoint skips disabled/hidden records

Inside the GET list handler, add a guard:

// after you load icons array from DB/file/service:
const icons = await loadIconsSomehow();
// ensure we skip hidden/deleted records
const visible = icons.filter(
  (x) => !x.hidden && !x.disabled && !x.deleted
);
res.json({ icons: visible });

B) Add a tiny admin route to disable an icon (soft-delete)
const fs = require("fs");
const path = require("path");

// Example JSON DB path; adjust if needed
const ICON_DB_PATH = path.join(process.cwd(), "uploads", "icons-db.json");

router.post("/admin/icons/:id/disable", async (req, res) => {
  try {
    const id = req.params.id; // expected raw id like "guest_icon"
    const db = JSON.parse(fs.readFileSync(ICON_DB_PATH, "utf8"));
    const rec = db.icons.find((x) => x.id === id);
    if (!rec) return res.status(404).json({ error: "Icon not found" });

    rec.hidden = true; // or rec.disabled = true
    fs.writeFileSync(ICON_DB_PATH, JSON.stringify(db, null, 2));
    res.json({ ok: true, id, status: "hidden" });
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "Failed to disable icon" });
  }
});


Call once:

POST /api/icons/admin/icons/guest_icon/disable


If the ID is prefixed (e.g., storage-guest_icon), use the raw ID guest_icon.

3) (Optional) File cleanup for that icon

If we want it physically removed from local storage after soft-delete:

router.post("/admin/icons/:id/purge-files", async (req, res) => {
  try {
    const id = req.params.id;
    const base = path.join(process.cwd(), "uploads", "icons");
    // Remove SVG/PNG/preview folders for this icon id
    for (const dir of ["svg", "png", "preview"]) {
      fs.rmSync(path.join(base, dir, id), { recursive: true, force: true });
    }
    res.json({ ok: true, id, purged: true });
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "Failed to purge files" });
  }
});


Call once after disabling:

POST /api/icons/admin/icons/guest_icon/purge-files

4) Acceptance criteria

“Guest Icon (Outlined)” never appears in the Icons grid.

/api/icons/list no longer returns that record.

Other icons (including “Guest Icon Filled”) still show normally.

No UI regressions on Copy/Download/Attribution.

If you prefer permanent hard delete instead of soft-delete, you can splice the record from the DB and run the purge route. The blocklist stays as a protective belt-and-suspenders but can be removed after backend delete is verified.