feat(dashboard): add transactions and users management pages with CRUD functionality
feat(auth): implement login page and authentication middleware feat(sidebar): create sidebar component with user info and navigation links feat(api): establish API client for interacting with backend services
This commit is contained in:
92
apps/csms/src/routes/charge-points.ts
Normal file
92
apps/csms/src/routes/charge-points.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { Hono } from "hono";
|
||||
import { desc, eq, sql } from "drizzle-orm";
|
||||
import { useDrizzle } from "@/lib/db.js";
|
||||
import { chargePoint, connector } from "@/db/schema.js";
|
||||
|
||||
const app = new Hono();
|
||||
|
||||
/** GET /api/charge-points — list all charge points with connectors */
|
||||
app.get("/", async (c) => {
|
||||
const db = useDrizzle();
|
||||
|
||||
const cps = await db.select().from(chargePoint).orderBy(desc(chargePoint.createdAt));
|
||||
|
||||
// Attach connectors (connectorId > 0 only, excludes the main-controller row)
|
||||
const connectors = cps.length
|
||||
? await db
|
||||
.select()
|
||||
.from(connector)
|
||||
.where(
|
||||
sql`${connector.chargePointId} = any(${sql.raw(`array[${cps.map((cp) => `'${cp.id}'`).join(",")}]`)}) and ${connector.connectorId} > 0`,
|
||||
)
|
||||
: [];
|
||||
|
||||
const connectorsByCP: Record<string, typeof connectors> = {};
|
||||
for (const conn of connectors) {
|
||||
if (!connectorsByCP[conn.chargePointId]) connectorsByCP[conn.chargePointId] = [];
|
||||
connectorsByCP[conn.chargePointId].push(conn);
|
||||
}
|
||||
|
||||
return c.json(
|
||||
cps.map((cp) => ({
|
||||
...cp,
|
||||
connectors: connectorsByCP[cp.id] ?? [],
|
||||
})),
|
||||
);
|
||||
});
|
||||
|
||||
/** GET /api/charge-points/:id — single charge point */
|
||||
app.get("/:id", async (c) => {
|
||||
const db = useDrizzle();
|
||||
const id = c.req.param("id");
|
||||
|
||||
const [cp] = await db.select().from(chargePoint).where(eq(chargePoint.id, id)).limit(1);
|
||||
|
||||
if (!cp) return c.json({ error: "Not found" }, 404);
|
||||
|
||||
const connectors = await db.select().from(connector).where(eq(connector.chargePointId, id));
|
||||
|
||||
return c.json({ ...cp, connectors });
|
||||
});
|
||||
|
||||
/** PATCH /api/charge-points/:id — update feePerKwh */
|
||||
app.patch("/:id", async (c) => {
|
||||
const db = useDrizzle();
|
||||
const id = c.req.param("id");
|
||||
const body = await c.req.json<{ feePerKwh?: number }>();
|
||||
|
||||
if (
|
||||
typeof body.feePerKwh !== "number" ||
|
||||
body.feePerKwh < 0 ||
|
||||
!Number.isInteger(body.feePerKwh)
|
||||
) {
|
||||
return c.json({ error: "feePerKwh must be a non-negative integer (unit: fen/kWh)" }, 400);
|
||||
}
|
||||
|
||||
const [updated] = await db
|
||||
.update(chargePoint)
|
||||
.set({ feePerKwh: body.feePerKwh, updatedAt: new Date() })
|
||||
.where(eq(chargePoint.id, id))
|
||||
.returning();
|
||||
|
||||
if (!updated) return c.json({ error: "Not found" }, 404);
|
||||
|
||||
return c.json({ feePerKwh: updated.feePerKwh });
|
||||
});
|
||||
|
||||
/** DELETE /api/charge-points/:id — delete a charge point (cascades to connectors, transactions, meter values) */
|
||||
app.delete("/:id", async (c) => {
|
||||
const db = useDrizzle();
|
||||
const id = c.req.param("id");
|
||||
|
||||
const [deleted] = await db
|
||||
.delete(chargePoint)
|
||||
.where(eq(chargePoint.id, id))
|
||||
.returning({ id: chargePoint.id });
|
||||
|
||||
if (!deleted) return c.json({ error: "Not found" }, 404);
|
||||
|
||||
return c.json({ success: true });
|
||||
});
|
||||
|
||||
export default app;
|
||||
Reference in New Issue
Block a user