diff --git a/README.md b/README.md index 71831bc..a3369a2 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,8 @@ The backend environment variables are configured in `backend/env.json`: | USE_INTERMEDIARY | `true` | Set to `true` to route ETASU checks through the REMS intermediary instead of directly to REMS admin. | | INTERMEDIARY_FHIR_URL | `http://localhost:3003/4_0_0` | Base URL of the REMS intermediary FHIR server. Used when `USE_INTERMEDIARY` is true. | | REMS_ADMIN_NCPDP | `http://localhost:8090/ncpdp/script` | URL endpoint for sending NCPDP Script messages directly to REMS admin. | +| INTERMEDIARY_URL | `http://localhost:3003` | Base URL of the REMS intermediary. Used when `USE_INTERMEDIARY` is true to route NCPDP Script and RxFill messages. | +| EHR_NCPDP_URL | `http://localhost:8080/ncpdp/script` | URL endpoint for sending NCPDP Script messages directly to the EHR system. Used when `USE_INTERMEDIARY` is false. | ## Setup @@ -119,5 +121,4 @@ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and -limitations under the License. - +limitations under the License. \ No newline at end of file diff --git a/backend/env.json b/backend/env.json index 18462d2..4d265bd 100644 --- a/backend/env.json +++ b/backend/env.json @@ -57,10 +57,10 @@ }, "INTERMEDIARY_URL": { "type": "string", - "default": "http://localhost:8090/ncpdp/script" + "default": "http://localhost:3003" }, "EHR_NCPDP_URL": { "type": "string", - "default": "|| 'http://localhost:8080/ncpdp/script'" + "default": "http://localhost:8080/ncpdp/script" } -} +} \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json index 3b83609..3af915e 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -3354,6 +3354,21 @@ "dev": true, "license": "ISC" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "license": "MIT", diff --git a/backend/src/lib/pharmacyConfig.js b/backend/src/lib/pharmacyConfig.js index dd3fbd7..f60d458 100644 --- a/backend/src/lib/pharmacyConfig.js +++ b/backend/src/lib/pharmacyConfig.js @@ -1,21 +1,27 @@ +import env from 'var'; // Configuration state let config = { - useIntermediary: process.env.USE_INTERMEDIARY, - intermediaryUrl: process.env.INTERMEDIARY_URL, - remsAdminUrl: process.env.REMS_ADMIN_NCPDP, - ehrUrl: process.env.EHR_NCPDP_URL + useIntermediary: env.USE_INTERMEDIARY, + intermediaryUrl: env.INTERMEDIARY_URL, + remsAdminUrl: env.REMS_ADMIN_NCPDP, + ehrUrl: env.EHR_NCPDP_URL }; - - export function getConfig() { return { ...config }; } export function updateConfig(newConfig) { - config = { ...config, ...newConfig }; + const sanitized = { ...newConfig }; + + if ('useIntermediary' in sanitized) { + const val = sanitized.useIntermediary; + sanitized.useIntermediary = val === true || val === 'true'; + } + + config = { ...config, ...sanitized }; console.log('Configuration updated:', config); return { ...config }; } diff --git a/backend/src/routes/doctorOrders.js b/backend/src/routes/doctorOrders.js index cd23700..630cfa8 100644 --- a/backend/src/routes/doctorOrders.js +++ b/backend/src/routes/doctorOrders.js @@ -5,7 +5,7 @@ import axios from 'axios'; // XML Parsing Middleware used for NCPDP SCRIPT import bodyParser from 'body-parser'; import bpx from 'body-parser-xml'; -import { parseStringPromise } from "xml2js"; +import { parseStringPromise } from 'xml2js'; import env from 'var'; import { buildRxStatus, @@ -385,7 +385,7 @@ const isRemsDrug = order => { const getEtasuUrl = order => { let baseUrl; - if (env.USE_INTERMEDIARY) { + if (getConfig().useIntermediary) { baseUrl = env.INTERMEDIARY_FHIR_URL; } else { const remsDrug = medicationRequestToRemsAdmins.find(entry => { @@ -419,7 +419,7 @@ const getGuidanceResponse = async order => { // Make the etasu call with the case number if it exists, if not call with patient and medication let body = {}; - if (order.caseNumber && !env.USE_INTERMEDIARY) { + if (order.caseNumber && !getConfig().useIntermediary) { body = { resourceType: 'Parameters', parameter: [ diff --git a/backend/src/server.ts b/backend/src/server.ts index 1627125..374f8aa 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -9,7 +9,6 @@ import env from 'var'; import https from 'https'; import fs from 'fs'; -//middleware and configurations import bodyParser from 'body-parser'; main().catch(err => console.log(err)); @@ -23,6 +22,7 @@ async function main() { console.log('CORS OPTIONS: ' + JSON.stringify(options)); + app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cors(options)); app.use('/doctorOrders', doctorOrders); @@ -48,4 +48,4 @@ async function main() { user: env.MONGO_USERNAME, pass: env.MONGO_PASSWORD }); -} +} \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8045496..3477c50 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -19518,9 +19518,10 @@ } }, "node_modules/vite-tsconfig-paths/node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "license": "Apache-2.0", "optional": true, "peer": true, "bin": { diff --git a/frontend/src/components/ConfigToggle.tsx b/frontend/src/components/ConfigToggle.tsx index 70598c4..0235fe2 100644 --- a/frontend/src/components/ConfigToggle.tsx +++ b/frontend/src/components/ConfigToggle.tsx @@ -1,19 +1,30 @@ -import { IconButton, Menu, MenuItem, Switch, Typography, Box, Divider } from '@mui/material'; +import { IconButton, Menu, MenuItem, Switch, Typography, Box, Divider, TextField, Button } from '@mui/material'; import SettingsIcon from '@mui/icons-material/Settings'; import { useState, useEffect } from 'react'; import axios from 'axios'; +interface PharmacyConfig { + useIntermediary: boolean; + intermediaryUrl: string; + remsAdminUrl: string; + ehrUrl: string; +} + export default function ConfigToggle() { const [anchorEl, setAnchorEl] = useState(null); - const [useIntermediary, setUseIntermediary] = useState(false); + const [config, setConfig] = useState({ + useIntermediary: false, + intermediaryUrl: '', + remsAdminUrl: '', + ehrUrl: '', + }); const open = Boolean(anchorEl); - // Load config on mount + // Load config from backend on mount useEffect(() => { - const saved = localStorage.getItem('useIntermediary'); - if (saved !== null) { - setUseIntermediary(saved === 'true'); - } + axios.get('/doctorOrders/api/config') + .then(({ data }) => setConfig(data)) + .catch(() => console.error('Failed to load config')); }, []); const handleClick = (event: React.MouseEvent) => { @@ -24,15 +35,15 @@ export default function ConfigToggle() { setAnchorEl(null); }; - const handleToggle = async () => { - const newValue = !useIntermediary; - setUseIntermediary(newValue); - localStorage.setItem('useIntermediary', String(newValue)); + const handleToggle = () => { + setConfig(prev => ({ ...prev, useIntermediary: !prev.useIntermediary })); + }; - // Update backend + const handleSave = async () => { try { - await axios.post('/doctorOrders/api/config', { useIntermediary: newValue }); - console.log('Configuration updated:', newValue ? 'Using Intermediary' : 'Direct Connection'); + await axios.post('/doctorOrders/api/config', config); + console.log('Configuration updated:', config); + handleClose(); } catch (error) { console.error('Failed to update backend config:', error); } @@ -55,7 +66,7 @@ export default function ConfigToggle() { open={open} onClose={handleClose} PaperProps={{ - sx: { minWidth: 280, p: 1 } + sx: { minWidth: 300, p: 1 } }} > @@ -66,19 +77,44 @@ export default function ConfigToggle() { - + Use Intermediary - {useIntermediary - ? 'Routing via intermediary' - : 'Direct to REMS Admin'} + {config.useIntermediary ? 'Routing via intermediary' : 'Direct to REMS Admin'} + + + setConfig(prev => ({ ...prev, intermediaryUrl: e.target.value }))} + /> + setConfig(prev => ({ ...prev, remsAdminUrl: e.target.value }))} + /> + setConfig(prev => ({ ...prev, ehrUrl: e.target.value }))} + /> + + );