db.ts and server.ts work confirmed by test.js. moving to cards.
This commit is contained in:
@@ -10,9 +10,11 @@
|
||||
"bun-plugin-tailwind": "^0.1.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"kysely": "^0.28.8",
|
||||
"lucide-react": "^0.545.0",
|
||||
"react": "^19",
|
||||
"react-dom": "^19",
|
||||
"sqlite": "^5.1.1",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -135,6 +137,8 @@
|
||||
|
||||
"get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="],
|
||||
|
||||
"kysely": ["kysely@0.28.8", "", {}, "sha512-QUOgl5ZrS9IRuhq5FvOKFSsD/3+IA6MLE81/bOOTRA/YQpKDza2sFdN5g6JCB9BOpqMJDGefLCQ9F12hRS13TA=="],
|
||||
|
||||
"lucide-react": ["lucide-react@0.545.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-7r1/yUuflQDSt4f1bpn5ZAocyIxcTyVyBBChSVtBKn5M+392cPmI5YJMWOJKk/HUWGm5wg83chlAZtCcGbEZtw=="],
|
||||
|
||||
"react": ["react@19.2.0", "", {}, "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ=="],
|
||||
@@ -149,6 +153,8 @@
|
||||
|
||||
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
||||
|
||||
"sqlite": ["sqlite@5.1.1", "", {}, "sha512-oBkezXa2hnkfuJwUo44Hl9hS3er+YFtueifoajrgidvqsJRQFpc5fKoAkAor1O5ZnLoa28GBScfHXs8j0K358Q=="],
|
||||
|
||||
"tailwind-merge": ["tailwind-merge@3.4.0", "", {}, "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g=="],
|
||||
|
||||
"tailwindcss": ["tailwindcss@4.1.17", "", {}, "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q=="],
|
||||
|
||||
@@ -15,9 +15,11 @@
|
||||
"bun-plugin-tailwind": "^0.1.2",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"kysely": "^0.28.8",
|
||||
"lucide-react": "^0.545.0",
|
||||
"react": "^19",
|
||||
"react-dom": "^19",
|
||||
"sqlite": "^5.1.1",
|
||||
"tailwind-merge": "^3.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
// db.ts
|
||||
import { Database } from "bun:sqlite";
|
||||
|
||||
// --- Initialize Bun SQLite ---
|
||||
const db = new Database("./flow.db");
|
||||
|
||||
// --- Helper functions to bypass TS binding issues ---
|
||||
function getOne<T>(sql: string, ...params: any[]): T | null {
|
||||
const row = db.query(sql).get(...params as any);
|
||||
return row ? (row as T) : null;
|
||||
}
|
||||
|
||||
function getAll<T>(sql: string, ...params: any[]): T[] {
|
||||
const rows = db.query(sql).all(...params as any);
|
||||
return rows.map(r => r as T);
|
||||
}
|
||||
|
||||
function run(sql: string, ...params: any[]) {
|
||||
db.run(sql, ...params as any);
|
||||
}
|
||||
|
||||
// --- Create tables if they do not exist ---
|
||||
run(`
|
||||
CREATE TABLE IF NOT EXISTS flow_steps (
|
||||
id TEXT PRIMARY KEY,
|
||||
stepNumber TEXT,
|
||||
caseCode TEXT,
|
||||
subStep TEXT,
|
||||
stage TEXT,
|
||||
role TEXT,
|
||||
handoffTo TEXT,
|
||||
handoffChannel TEXT,
|
||||
description TEXT,
|
||||
createdAt TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
|
||||
run(`
|
||||
CREATE TABLE IF NOT EXISTS extended_descriptions (
|
||||
stepId TEXT PRIMARY KEY REFERENCES flow_steps(id),
|
||||
content TEXT
|
||||
)
|
||||
`);
|
||||
|
||||
run(`
|
||||
CREATE TABLE IF NOT EXISTS questions (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
stepId TEXT REFERENCES flow_steps(id),
|
||||
question TEXT,
|
||||
followUp TEXT,
|
||||
createdAt TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
|
||||
run(`
|
||||
CREATE TABLE IF NOT EXISTS concerns (
|
||||
stepId TEXT PRIMARY KEY REFERENCES flow_steps(id),
|
||||
flagged INTEGER DEFAULT 0,
|
||||
comment TEXT,
|
||||
createdAt TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
`);
|
||||
|
||||
// --- Types ---
|
||||
export type FlowStep = {
|
||||
id: string;
|
||||
stepNumber: string;
|
||||
caseCode: string;
|
||||
subStep: string;
|
||||
stage: string;
|
||||
role: string;
|
||||
handoffTo: string;
|
||||
handoffChannel: string;
|
||||
description: string;
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
export type ExtendedDescription = {
|
||||
stepId: string;
|
||||
content: string;
|
||||
};
|
||||
|
||||
export type Question = {
|
||||
id: number;
|
||||
stepId: string;
|
||||
question: string;
|
||||
followUp: string | null;
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
export type Concern = {
|
||||
stepId: string;
|
||||
flagged: boolean;
|
||||
comment: string;
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
// --- Flow Steps ---
|
||||
export function createStep(step: Omit<FlowStep, "createdAt">) {
|
||||
run(
|
||||
`INSERT OR IGNORE INTO flow_steps
|
||||
(id, stepNumber, caseCode, subStep, stage, role, handoffTo, handoffChannel, description)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
step.id,
|
||||
step.stepNumber,
|
||||
step.caseCode,
|
||||
step.subStep,
|
||||
step.stage,
|
||||
step.role,
|
||||
step.handoffTo,
|
||||
step.handoffChannel,
|
||||
step.description
|
||||
);
|
||||
}
|
||||
|
||||
export function getStep(id: string): FlowStep | null {
|
||||
return getOne<FlowStep>("SELECT * FROM flow_steps WHERE id = ?", id);
|
||||
}
|
||||
|
||||
export function getAllSteps(): FlowStep[] {
|
||||
return getAll<FlowStep>("SELECT * FROM flow_steps");
|
||||
}
|
||||
|
||||
// --- Extended Descriptions ---
|
||||
export function saveExtendedDescription(stepId: string, content: string) {
|
||||
run(
|
||||
`INSERT OR REPLACE INTO extended_descriptions (stepId, content) VALUES (?, ?)`,
|
||||
stepId,
|
||||
content
|
||||
);
|
||||
}
|
||||
|
||||
export function getExtendedDescription(stepId: string): string | null {
|
||||
const row = getOne<{ content: string }>(
|
||||
"SELECT content FROM extended_descriptions WHERE stepId = ?",
|
||||
stepId
|
||||
);
|
||||
return row ? row.content : null;
|
||||
}
|
||||
|
||||
// --- Questions ---
|
||||
export function addQuestion(stepId: string, question: string, followUp?: string | null) {
|
||||
run(
|
||||
`INSERT INTO questions (stepId, question, followUp) VALUES (?, ?, ?)`,
|
||||
stepId,
|
||||
question,
|
||||
followUp ?? null
|
||||
);
|
||||
}
|
||||
|
||||
export function getQuestions(stepId: string): Question[] {
|
||||
return getAll<Question>("SELECT * FROM questions WHERE stepId = ?", stepId);
|
||||
}
|
||||
|
||||
// --- Concerns ---
|
||||
export function flagConcern(stepId: string, flagged: boolean, comment: string) {
|
||||
run(
|
||||
`INSERT OR REPLACE INTO concerns (stepId, flagged, comment) VALUES (?, ?, ?)`,
|
||||
stepId,
|
||||
flagged ? 1 : 0,
|
||||
comment
|
||||
);
|
||||
}
|
||||
|
||||
export function getConcern(stepId: string): Concern | null {
|
||||
const row = getOne<{ stepId: string; flagged: number; comment: string; createdAt: string }>(
|
||||
"SELECT * FROM concerns WHERE stepId = ?",
|
||||
stepId
|
||||
);
|
||||
if (!row) return null;
|
||||
return {
|
||||
stepId: row.stepId,
|
||||
flagged: row.flagged === 1,
|
||||
comment: row.comment,
|
||||
createdAt: row.createdAt
|
||||
};
|
||||
}
|
||||
|
||||
//export default db;
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
// src/server.ts
|
||||
import { serve } from "bun";
|
||||
import {
|
||||
createStep,
|
||||
getStep,
|
||||
getAllSteps,
|
||||
saveExtendedDescription,
|
||||
getExtendedDescription,
|
||||
addQuestion,
|
||||
getQuestions,
|
||||
flagConcern,
|
||||
getConcern
|
||||
} from "./db.ts";
|
||||
|
||||
const corsHeaders = {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
|
||||
"Access-Control-Allow-Headers": "Content-Type",
|
||||
};
|
||||
|
||||
async function getJSON(req: Request) {
|
||||
try {
|
||||
return await req.json();
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
serve({
|
||||
port: 3000,
|
||||
fetch: async (req: Request) => {
|
||||
const { method } = req;
|
||||
const path = new URL(req.url).pathname;
|
||||
|
||||
if (method === "OPTIONS") {
|
||||
return new Response(null, { headers: corsHeaders });
|
||||
}
|
||||
|
||||
// --- Steps ---
|
||||
if (path === "/steps" && method === "GET") {
|
||||
return new Response(JSON.stringify(getAllSteps()), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
|
||||
}
|
||||
|
||||
if (path.startsWith("/steps/") && method === "GET") {
|
||||
const stepId = String(path.split("/")[2]);
|
||||
return new Response(JSON.stringify(getStep(stepId)), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
|
||||
}
|
||||
|
||||
if (path === "/steps" && method === "POST") {
|
||||
const data = await getJSON(req);
|
||||
createStep({
|
||||
id: String(data.id),
|
||||
stepNumber: String(data.stepNumber),
|
||||
caseCode: String(data.caseCode),
|
||||
subStep: String(data.subStep),
|
||||
stage: String(data.stage),
|
||||
role: String(data.role),
|
||||
handoffTo: String(data.handoffTo),
|
||||
handoffChannel: String(data.handoffChannel),
|
||||
description: String(data.description),
|
||||
});
|
||||
return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
|
||||
}
|
||||
|
||||
// --- Extended Descriptions ---
|
||||
if (path === "/descriptions" && method === "POST") {
|
||||
const { stepId, content } = await getJSON(req);
|
||||
saveExtendedDescription(String(stepId), String(content));
|
||||
return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
|
||||
}
|
||||
|
||||
if (path.startsWith("/descriptions/") && method === "GET") {
|
||||
const stepId = String(path.split("/")[2]);
|
||||
return new Response(JSON.stringify({ stepId, content: getExtendedDescription(stepId) }), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
|
||||
}
|
||||
|
||||
// --- Questions ---
|
||||
if (path === "/questions" && method === "POST") {
|
||||
const { stepId, question, followUp } = await getJSON(req);
|
||||
addQuestion(String(stepId), String(question), followUp ? String(followUp) : null);
|
||||
return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
|
||||
}
|
||||
|
||||
if (path.startsWith("/questions/") && method === "GET") {
|
||||
const stepId = String(path.split("/")[2]);
|
||||
return new Response(JSON.stringify(getQuestions(stepId)), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
|
||||
}
|
||||
|
||||
// --- Concerns ---
|
||||
if (path === "/concerns" && method === "POST") {
|
||||
const { stepId, flagged, comment } = await getJSON(req);
|
||||
flagConcern(String(stepId), Boolean(flagged), String(comment));
|
||||
return new Response(JSON.stringify({ success: true }), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
|
||||
}
|
||||
|
||||
if (path.startsWith("/concerns/") && method === "GET") {
|
||||
const stepId = String(path.split("/")[2]);
|
||||
return new Response(JSON.stringify(getConcern(stepId)), { headers: { ...corsHeaders, "Content-Type": "application/json" } });
|
||||
}
|
||||
|
||||
return new Response("Not Found", { status: 404 });
|
||||
}
|
||||
});
|
||||
|
||||
console.log("Server running at http://localhost:3000");
|
||||
@@ -0,0 +1,81 @@
|
||||
// test-server.ts
|
||||
async function test() {
|
||||
const base = "http://localhost:3000";
|
||||
|
||||
// --- Create a step ---
|
||||
const stepData = {
|
||||
id: "step1",
|
||||
stepNumber: "0.1",
|
||||
caseCode: "caseA",
|
||||
subStep: "a",
|
||||
stage: "Pre-Intake",
|
||||
role: "Estimator",
|
||||
handoffTo: "Office Manager",
|
||||
handoffChannel: "Phone",
|
||||
description: "Initial ITB received",
|
||||
};
|
||||
|
||||
console.log("Creating step...");
|
||||
let res = await fetch(`${base}/steps`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(stepData),
|
||||
});
|
||||
console.log(await res.json());
|
||||
|
||||
// --- Get the step ---
|
||||
console.log("Getting step...");
|
||||
res = await fetch(`${base}/steps/${stepData.id}`);
|
||||
console.log(await res.json());
|
||||
|
||||
// --- Add extended description ---
|
||||
console.log("Adding extended description...");
|
||||
res = await fetch(`${base}/descriptions`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ stepId: stepData.id, content: "Extended info about step1" }),
|
||||
});
|
||||
console.log(await res.json());
|
||||
|
||||
// --- Get extended description ---
|
||||
console.log("Getting extended description...");
|
||||
res = await fetch(`${base}/descriptions/${stepData.id}`);
|
||||
console.log(await res.json());
|
||||
|
||||
// --- Add a question ---
|
||||
console.log("Adding question...");
|
||||
res = await fetch(`${base}/questions`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ stepId: stepData.id, question: "Follow up question?", followUp: "Yes, clarify details" }),
|
||||
});
|
||||
console.log(await res.json());
|
||||
|
||||
// --- Get questions ---
|
||||
console.log("Getting questions...");
|
||||
res = await fetch(`${base}/questions/${stepData.id}`);
|
||||
console.log(await res.json());
|
||||
|
||||
// --- Add a concern ---
|
||||
console.log("Adding concern...");
|
||||
res = await fetch(`${base}/concerns`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ stepId: stepData.id, flagged: true, comment: "Check this step for errors" }),
|
||||
});
|
||||
console.log(await res.json());
|
||||
|
||||
// --- Get concern ---
|
||||
console.log("Getting concern...");
|
||||
res = await fetch(`${base}/concerns/${stepData.id}`);
|
||||
console.log(await res.json());
|
||||
|
||||
// --- Get all steps ---
|
||||
console.log("Getting all steps...");
|
||||
res = await fetch(`${base}/steps`);
|
||||
console.log(await res.json());
|
||||
|
||||
console.log("Test complete.");
|
||||
}
|
||||
|
||||
test();
|
||||
@@ -0,0 +1,5 @@
|
||||
import workflow from "./workflow.json";
|
||||
|
||||
export function useWorkflow() {
|
||||
return workflow;
|
||||
}
|
||||
Reference in New Issue
Block a user