diff --git a/config/env/prod.env.example b/config/env/prod.env.example deleted file mode 100644 index e8e59112..00000000 --- a/config/env/prod.env.example +++ /dev/null @@ -1,16 +0,0 @@ -DEBUG=0 -SECRET_KEY=change_this -DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1 [::1] -SQL_ENGINE=django.db.backends.postgresql -SQL_DATABASE=balancer_prod -SQL_USER=set_me -SQL_PASSWORD=set_me -SQL_HOST=db -SQL_PORT=5432 -DATABASE=postgres -LOGIN_REDIRECT_URL= -OPENAI_API_KEY= -ANTHROPIC_API_KEY= -PINECONE_API_KEY= -EMAIL_HOST_USER= -EMAIL_HOST_PASSWORD= diff --git a/deploy/manifests/balancer/base/secret.template.yaml b/deploy/manifests/balancer/base/secret.template.yaml index bebc8a71..9abb6e3b 100644 --- a/deploy/manifests/balancer/base/secret.template.yaml +++ b/deploy/manifests/balancer/base/secret.template.yaml @@ -15,7 +15,6 @@ type: Opaque stringData: DATABASE: postgres DEBUG: '1' - DJANGO_ALLOWED_HOSTS: localhost 127.0.0.1 [::1] balancer.sandbox.k8s.phl.io LOGIN_REDIRECT_URL: '' OPENAI_API_KEY: openapi_key_here PINECONE_API_KEY: pinecone_key_here diff --git a/docker-compose.yml b/docker-compose.yml index c6238dda..5d2d5884 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,10 @@ services: db: + # Workaround for PostgreSQL crash with pgvector v0.6.1 on ARM64 + # image: pgvector/pgvector:pg15 + # volumes: + # - postgres_data:/var/lib/postgresql/data/ + # - ./db/init-vector-extension.sql:/docker-entrypoint-initdb.d/init-vector-extension.sql build: context: ./db dockerfile: Dockerfile @@ -20,10 +25,6 @@ services: # environment: # PGADMIN_DEFAULT_EMAIL: balancer-noreply@codeforphilly.org # PGADMIN_DEFAULT_PASSWORD: balancer - # # PGADMIN_LISTEN_PORT = 80 - # # volumes: - # # - ./pgadmin-data:/var/lib/pgadmin - # # # PGADMIN_LISTEN_PORT = 80 # ports: # - "5050:80" # networks: @@ -55,7 +56,6 @@ services: - "3000:3000" environment: - CHOKIDAR_USEPOLLING=true - # - VITE_API_BASE_URL=https://balancertestsite.com/ volumes: - "./frontend:/usr/src/app:delegated" - "/usr/src/app/node_modules/" diff --git a/frontend/.env.production b/frontend/.env.production new file mode 100644 index 00000000..a05a022d --- /dev/null +++ b/frontend/.env.production @@ -0,0 +1 @@ +VITE_API_BASE_URL=https://balancer.live.k8s.phl.io/ \ No newline at end of file diff --git a/frontend/src/components/Header/Header.tsx b/frontend/src/components/Header/Header.tsx index f696b614..49798c83 100644 --- a/frontend/src/components/Header/Header.tsx +++ b/frontend/src/components/Header/Header.tsx @@ -101,7 +101,7 @@ const Header: React.FC = ({ isAuthenticated, isSuperuser }) => { return (
-

+

Welcome to Balancer’s first release! Found a bug or have feedback? Let us know {" "} = ({ isAuthenticated, isSuperuser }) => { .

+

+ App is in beta; report issues to {" "} + + balancerteam@codeforphilly.org + + . +

-
+
diff --git a/frontend/src/pages/PatientManager/PatientSummary.tsx b/frontend/src/pages/PatientManager/PatientSummary.tsx index 16966360..7456178c 100644 --- a/frontend/src/pages/PatientManager/PatientSummary.tsx +++ b/frontend/src/pages/PatientManager/PatientSummary.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect, useRef } from "react"; import { PatientInfo } from "./PatientTypes"; import Tooltip from "../../components/Tooltip"; import TypingAnimation from "../../components/Header/components/TypingAnimation.tsx"; -import { FaPencilAlt, FaPrint, FaMinus, FaRegThumbsDown } from "react-icons/fa"; +import { FaPencilAlt, FaPrint, FaMinus, FaRegThumbsDown, FaAngleDown, FaAngleUp } from "react-icons/fa"; import FeedbackForm from "../Feedback/FeedbackForm"; import Modal from "../../components/Modal/Modal"; import { EllipsisVertical } from "lucide-react"; @@ -45,22 +45,17 @@ const truncate = (s = "", n = 220) => const MedicationItem = ({ medication, - isClicked, riskData, loading, - onSourcesClick, - onBenefitsRisksClick, - activePanel, + onTierClick, }: { medication: string; source: string; isClicked: boolean; riskData: RiskData | null; loading: boolean; - onSourcesClick: () => void; - onBenefitsRisksClick: () => void; - activePanel: "sources" | "benefits-risks" | null; + onTierClick: () => void; }) => { if (medication === "None") { return ( @@ -76,7 +71,7 @@ const MedicationItem = ({ return (
-
  • +
  • {medication} @@ -88,108 +83,103 @@ const MedicationItem = ({
    - - Sources - -
    -
    - - Benefits and risks - + {isClicked ? : }
  • - {isClicked && riskData && activePanel === "benefits-risks" && ( + {isClicked && riskData && (
    -
    +

    Benefits:

    -
      - {riskData.benefits.map((b, i) => ( -
    • - {b} -
    • - ))} -
    + { + riskData.benefits?.length ? ( +
      + {riskData.benefits.map((r, i) => ( +
    • + {r} +
    • + ))} +
    + ) : ( +

    + No benefits identified. +

    + ) + }

    Risks:

    -
      - {riskData.risks.map((r, i) => ( -
    • - {r} -
    • - ))} -
    + { + riskData.risks?.length ? ( +
      + {riskData.risks.map((r, i) => ( +
    • + {r} +
    • + ))} +
    + ) : ( +

    + No risks identified. +

    + ) + }
    -
    -
    - )} - - {isClicked && riskData && activePanel === "sources" && ( -
    -
    -

    Sources

    -
    - - {riskData.sources?.length ? ( -
      - {riskData.sources.map((s, idx) => ( -
    • -
      - {s.title || "Untitled source"} - - {s.link_url && ( - - View PDF - - )} -
      +
      +

      + Sources: +

      + {riskData.sources?.length ? ( +
        + {riskData.sources.map((s, idx) => ( +
      • +
        + {s.title || "Untitled source"} + + {s.link_url && ( + + View PDF + + )} +
        - {s.publication && ( -
        {s.publication}
        - )} + {s.publication && ( +
        {s.publication}
        + )} -

        - {truncate(s.text)} -

        +

        + {truncate(s.text)} +

        - {s.page && ( -
        - Page {s.page} -
        - )} -
      • - ))} -
      - ) : ( -

      - No sources available for this medication. -

      - )} + {s.page && ( +
      + Page {s.page} +
      + )} +
    • + ))} +
    + ) : ( +

    + No sources available for this medication. +

    + )} +
    +
    )} + +
    ); }; @@ -201,9 +191,7 @@ const MedicationTier = ({ clickedMedication, riskData, loading, - onSourcesClick, - onBenefitsRisksClick, - activePanel, + onTierClick, }: { title: string; tier: string; @@ -211,9 +199,7 @@ const MedicationTier = ({ clickedMedication: string | null; riskData: RiskData | null; loading: boolean; - onSourcesClick: (medication: MedicationWithSource) => void; - onBenefitsRisksClick: (medication: MedicationWithSource) => void; - activePanel: "sources" | "benefits-risks" | null; + onTierClick: (medication: MedicationWithSource) => void; }) => ( <>
    @@ -229,9 +215,7 @@ const MedicationTier = ({ isClicked={medicationObj.name === clickedMedication} riskData={riskData} loading={loading} - onSourcesClick={() => onSourcesClick(medicationObj)} - onBenefitsRisksClick={() => onBenefitsRisksClick(medicationObj)} - activePanel={activePanel} + onTierClick={() => onTierClick(medicationObj)} /> ))} @@ -254,9 +238,6 @@ const PatientSummary = ({ const [clickedMedication, setClickedMedication] = useState( null ); - const [activePanel, setActivePanel] = useState< - "sources" | "benefits-risks" | null - >(null); const [isModalOpen, setIsModalOpen] = useState({ status: false, id: "" }); @@ -276,67 +257,28 @@ const PatientSummary = ({ setLoading(false); setRiskData(null); setClickedMedication(null); - setActivePanel(null); } }, [isPatientDeleted, setShowSummary]); useEffect(() => { setRiskData(null); setClickedMedication(null); - setActivePanel(null); }, [patientInfo]); const handleClickSummary = () => { setShowSummary(!showSummary); }; - const handleSourcesClick = async (medicationObj: MedicationWithSource) => { - const { name: medication, source } = medicationObj; - - if (clickedMedication === medication && activePanel === "sources") { - setClickedMedication(null); - setActivePanel(null); - setRiskData(null); - return; - } - - setClickedMedication(medication); - setActivePanel("sources"); - setLoading(true); - try { - // Map source based on patient's diagnosis - let apiSource: "include" | "diagnosis" | "diagnosis_depressed" = source; - if (source === "diagnosis" && patientInfo.Diagnosis === "Depressed") { - apiSource = "diagnosis_depressed"; - } - - const data = await fetchRiskDataWithSources(medication, apiSource); - console.log("Risk data received for", medication, "with source", apiSource, ":", data); - console.log("Sources array:", data.sources); - console.log("Sources length:", data.sources?.length); - setRiskData(data as RiskData); - } catch (error) { - console.error("Error fetching risk data: ", error); - setRiskData(null); - } finally { - setLoading(false); - } - }; - - const handleBenefitsRisksClick = async ( - medicationObj: MedicationWithSource - ) => { + const handleTierClick = async (medicationObj: MedicationWithSource) => { const { name: medication, source } = medicationObj; - if (clickedMedication === medication && activePanel === "benefits-risks") { + if (clickedMedication === medication) { setClickedMedication(null); - setActivePanel(null); setRiskData(null); return; } setClickedMedication(medication); - setActivePanel("benefits-risks"); setLoading(true); try { @@ -347,10 +289,13 @@ const PatientSummary = ({ } const data = await fetchRiskDataWithSources(medication, apiSource); + // console.log("Risk data received for", medication, "with source", apiSource, ":", data); + // console.log("Sources array:", data.sources); + // console.log("Sources length:", data.sources?.length); setRiskData(data as RiskData); } catch (error) { console.error("Error fetching risk data: ", error); - setRiskData(null); + setRiskData({ benefits: [], risks: [], source: "", sources: []}); } finally { setLoading(false); } @@ -428,9 +373,7 @@ const PatientSummary = ({ clickedMedication={clickedMedication} riskData={riskData} loading={loading} - onSourcesClick={handleSourcesClick} - onBenefitsRisksClick={handleBenefitsRisksClick} - activePanel={activePanel} + onTierClick={handleTierClick} />
    @@ -453,9 +394,7 @@ const PatientSummary = ({ clickedMedication={clickedMedication} riskData={riskData} loading={loading} - onSourcesClick={handleSourcesClick} - onBenefitsRisksClick={handleBenefitsRisksClick} - activePanel={activePanel} + onTierClick={handleTierClick} />
    diff --git a/frontend/src/services/actions/auth.tsx b/frontend/src/services/actions/auth.tsx index 2573c223..bfbfbe41 100644 --- a/frontend/src/services/actions/auth.tsx +++ b/frontend/src/services/actions/auth.tsx @@ -76,6 +76,7 @@ export const checkAuthenticated = () => async (dispatch: AppDispatch) => { const body = JSON.stringify({ token: localStorage.getItem("access") }); const baseUrl = import.meta.env.VITE_API_BASE_URL; + console.log(baseUrl); const url = `${baseUrl}/auth/jwt/verify/`; try { const res = await axios.post(url, body, config); @@ -113,6 +114,7 @@ export const load_user = (): ThunkType => async (dispatch: AppDispatch) => { }, }; const baseUrl = import.meta.env.VITE_API_BASE_URL; + console.log(baseUrl); const url = `${baseUrl}/auth/users/me/`; try { const res = await axios.get(url, config); @@ -144,6 +146,7 @@ export const login = const body = JSON.stringify({ email, password }); const baseUrl = import.meta.env.VITE_API_BASE_URL; + console.log(baseUrl); const url = `${baseUrl}/auth/jwt/create/`; try { const res = await axios.post(url, body, config); @@ -170,8 +173,8 @@ export const login = export const logout = () => async (dispatch: AppDispatch) => { // Clear chat conversation data on logout for security - sessionStorage.removeItem('currentConversation'); - + sessionStorage.removeItem("currentConversation"); + dispatch({ type: LOGOUT, });