From e39a3f4239b46310c160ae797c464b3301822dd5 Mon Sep 17 00:00:00 2001 From: Aewing Date: Sat, 29 Nov 2025 13:31:53 -0600 Subject: [PATCH] db server and front end comms work card render basic works --- src/App.tsx | 51 +++++++----------- src/components/DynamicArrayField.tsx | 61 +++++++++++++++++++++ src/components/ui/StepCard.tsx | 16 ++++++ src/db.ts | 1 - src/index.html | 9 ++-- src/main.tsx | 16 ++++++ src/schema/intakeStepSchema.ts | 19 +++++++ src/server.ts | 66 ++--------------------- src/testsetup.ts | 0 src/types.ts | 28 ++++++++++ src/workflow/test.js | 81 ---------------------------- 11 files changed, 167 insertions(+), 181 deletions(-) create mode 100644 src/components/DynamicArrayField.tsx create mode 100644 src/components/ui/StepCard.tsx create mode 100644 src/main.tsx create mode 100644 src/schema/intakeStepSchema.ts create mode 100644 src/testsetup.ts create mode 100644 src/types.ts diff --git a/src/App.tsx b/src/App.tsx index c3f1d53..1e9ff9c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,39 +1,24 @@ -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { APITester } from "./APITester"; -import "./index.css"; +import { useEffect, useState } from "react"; +import StepCard from "./components/ui/StepCard"; +import type { FlowStep } from "./types"; // types only -import logo from "./logo.svg"; -import reactLogo from "./react.svg"; +export default function App() { + const [steps, setSteps] = useState([]); + + useEffect(() => { + fetch("http://localhost:3001/steps") + .then(res => res.json()) + .then(data => setSteps(data)) + .catch(err => console.error("Failed to fetch steps:", err)); + }, []); -export function App() { return ( -
-
- Bun Logo - React Logo -
- - - Bun + React - - Edit src/App.tsx and save to - test HMR - - - - - - +
+ {steps.length === 0 ? ( +

Loading steps...

+ ) : ( + steps.map(step => ) + )}
); } - -export default App; diff --git a/src/components/DynamicArrayField.tsx b/src/components/DynamicArrayField.tsx new file mode 100644 index 0000000..058b24a --- /dev/null +++ b/src/components/DynamicArrayField.tsx @@ -0,0 +1,61 @@ +import { useState } from "react"; + +// --- Types --- +export type FieldType = { + id: string; + label: string; + type: "textarea" | "array"; +}; + +export type Item = { + id?: number; + text?: string; + followUp?: string; + comment?: string; + flagged?: boolean; +}; + +// --- Props --- +type DynamicArrayFieldProps = { + field: FieldType; + stepId: string; // keep for future use + items: Item[]; + onAdd: (item: Item) => void; +}; + +export default function DynamicArrayField({ field, stepId: _stepId, items, onAdd }: DynamicArrayFieldProps) { + const [input, setInput] = useState(""); + + const handleAdd = () => { + if (!input) return; + onAdd({ text: input }); + setInput(""); + }; + + return ( +
+ + {items.map((item, index) => ( +
+ {item.text || item.comment} +
+ ))} +
+ setInput(e.target.value)} + placeholder={`Add ${field.label}`} + className="border rounded px-2 py-1 flex-1" + /> + +
+
+ ); +} diff --git a/src/components/ui/StepCard.tsx b/src/components/ui/StepCard.tsx new file mode 100644 index 0000000..0c9b1ff --- /dev/null +++ b/src/components/ui/StepCard.tsx @@ -0,0 +1,16 @@ +import type{ FlowStep } from "../../types"; + +type StepCardProps = { + step: FlowStep; +}; + +export default function StepCard({ step }: StepCardProps) { + return ( +
+

{step.stepNumber}: {step.description}

+

+ Stage: {step.stage} | Role: {step.role} | Handoff: {step.handoffTo} via {step.handoffChannel} +

+
+ ); +} diff --git a/src/db.ts b/src/db.ts index 94f15e9..d73b17a 100644 --- a/src/db.ts +++ b/src/db.ts @@ -176,4 +176,3 @@ export function getConcern(stepId: string): Concern | null { }; } -//export default db; diff --git a/src/index.html b/src/index.html index 2f2e89f..546dc88 100644 --- a/src/index.html +++ b/src/index.html @@ -1,13 +1,12 @@ - + - - Bun + React - + StepCard Test + - +
diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..8e7edeb --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,16 @@ +import React from "react"; +import { createRoot } from "react-dom/client"; +import App from "./App"; + +const container = document.getElementById("root"); +if (!container) throw new Error("Root container not found"); + +// Only create root if it doesn't already exist (HMR safe) +const root = (window as any)._root || createRoot(container); +(window as any)._root = root; + +root.render( + + + +); diff --git a/src/schema/intakeStepSchema.ts b/src/schema/intakeStepSchema.ts new file mode 100644 index 0000000..4e8cfc3 --- /dev/null +++ b/src/schema/intakeStepSchema.ts @@ -0,0 +1,19 @@ +export const intakeStepSchema = [ + { + id: "extendedDesc", + label: "Extended Description", + type: "textarea" + }, + { + id: "questions", + label: "Questions", + type: "array", + itemLabel: "Question" + }, + { + id: "concerns", + label: "Concerns", + type: "array", + itemLabel: "Concern" + } +] as const; diff --git a/src/server.ts b/src/server.ts index 58c7820..4faec7c 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,4 +1,3 @@ -// src/server.ts import { serve } from "bun"; import { createStep, @@ -10,7 +9,7 @@ import { getQuestions, flagConcern, getConcern -} from "./db.ts"; +} from "./db.ts"; // server-only const corsHeaders = { "Access-Control-Allow-Origin": "*", @@ -27,79 +26,24 @@ async function getJSON(req: Request) { } serve({ - port: 3000, + port: 3001, fetch: async (req: Request) => { const { method } = req; const path = new URL(req.url).pathname; - if (method === "OPTIONS") { - return new Response(null, { headers: corsHeaders }); - } + if (method === "OPTIONS") return new Response(null, { headers: corsHeaders }); // --- Steps --- - if (path === "/steps" && method === "GET") { + 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"); +console.log("Server running at http://localhost:3001"); diff --git a/src/testsetup.ts b/src/testsetup.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..5a7fd8f --- /dev/null +++ b/src/types.ts @@ -0,0 +1,28 @@ +// src/types.ts +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 Question = { + id: number; + stepId: string; + question: string; + followUp: string | null; + createdAt: string; +}; + +export type Concern = { + stepId: string; + flagged: boolean; + comment: string; + createdAt: string; +}; diff --git a/src/workflow/test.js b/src/workflow/test.js index 486ecf9..e69de29 100644 --- a/src/workflow/test.js +++ b/src/workflow/test.js @@ -1,81 +0,0 @@ -// 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();