diff --git a/app/routes/analyze.tsx b/app/routes/analyze.tsx
index 941830e..8c8fa53 100644
--- a/app/routes/analyze.tsx
+++ b/app/routes/analyze.tsx
@@ -221,7 +221,25 @@ export default function Analyze() {
updatePositions();
}, [stocks.length]);
- const removeStock = (id: string) => {
+ const removeStock = async (id: string) => {
+ const stock = stocks.find((s) => s.id === id);
+ if (!stock) return;
+
+ // Delete from database if this was a manually added stock (db- prefix)
+ if (id.startsWith("db-")) {
+ try {
+ const formData = new FormData();
+ formData.append("_method", "DELETE");
+ formData.append("ticker", stock.ticker);
+ await fetch("/api/stocks", {
+ method: "POST",
+ body: formData,
+ });
+ } catch (err) {
+ console.error("[analyze] Error deleting stock from DB:", err);
+ }
+ }
+
setStocks((s) => s.filter((stock) => stock.id !== id));
};
@@ -346,12 +364,16 @@ export default function Analyze() {
>
{stock.loading ? "Running..." : "Analyze"}
-
+
diff --git a/app/routes/api/stocks/index.ts b/app/routes/api/stocks/index.ts
index a7765ee..f2d58e6 100644
--- a/app/routes/api/stocks/index.ts
+++ b/app/routes/api/stocks/index.ts
@@ -10,11 +10,19 @@ export async function loader() {
export async function action({ request }: { request: Request }) {
const formData = await request.formData();
const ticker = formData.get("ticker")?.toString().toUpperCase();
+ const method = formData.get("_method")?.toString() || "POST";
if (!ticker) {
return Response.json({ error: "Ticker is required" }, { status: 400 });
}
+ if (method === "DELETE") {
+ await db.stock.deleteMany({
+ where: { ticker },
+ });
+ return Response.json({ success: true });
+ }
+
const stock = await db.stock.create({
data: { ticker },
});
diff --git a/prisma/dev.db b/prisma/dev.db
index a4c8a0e..292d186 100644
Binary files a/prisma/dev.db and b/prisma/dev.db differ
diff --git a/tests/stock-db.spec.ts b/tests/stock-db.spec.ts
index f011200..a00ff58 100644
--- a/tests/stock-db.spec.ts
+++ b/tests/stock-db.spec.ts
@@ -1,31 +1,40 @@
import { test, expect } from "@playwright/test";
test.describe("Stock Database", () => {
- test("should add and list stocks", async ({ request }) => {
+ test("should add and list stocks", async ({ page }) => {
const uniqueTicker = `TEST${Date.now()}`;
-
- const createRes = await request.post("/api/stocks", {
- form: { ticker: uniqueTicker },
+
+ const createRes = await page.request.post("/api/stocks", {
+ data: new URLSearchParams({ ticker: uniqueTicker }).toString(),
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
});
expect(createRes.ok()).toBeTruthy();
-
- const listRes = await request.get("/api/stocks");
+
+ const listRes = await page.request.get("/api/stocks");
const stocks = await listRes.json();
expect(stocks).toContainEqual(expect.objectContaining({ ticker: uniqueTicker }));
});
- test("should persist tickers after page reload", async ({ request, page }) => {
- const uniqueTicker = `PERSIST${Date.now()}`;
-
- await request.post("/api/stocks", {
- form: { ticker: uniqueTicker },
+ test("should delete stock from database", async ({ page }) => {
+ const uniqueTicker = `DEL${Date.now()}`;
+
+ await page.request.post("/api/stocks", {
+ data: new URLSearchParams({ ticker: uniqueTicker }).toString(),
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
});
- await page.goto("/stocks");
- await page.waitForLoadState("networkidle");
-
- const listRes = await request.get("/api/stocks");
- const stocks = await listRes.json();
+ let listRes = await page.request.get("/api/stocks");
+ let stocks = await listRes.json();
expect(stocks).toContainEqual(expect.objectContaining({ ticker: uniqueTicker }));
+
+ const delRes = await page.request.post("/api/stocks", {
+ data: new URLSearchParams({ ticker: uniqueTicker, _method: "DELETE" }).toString(),
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
+ });
+ expect(delRes.ok()).toBeTruthy();
+
+ listRes = await page.request.get("/api/stocks");
+ stocks = await listRes.json();
+ expect(stocks).not.toContainEqual(expect.objectContaining({ ticker: uniqueTicker }));
});
});
\ No newline at end of file