diff --git a/frontend/src/api/apiClient.ts b/frontend/src/api/apiClient.ts index 857c1520..915226d6 100644 --- a/frontend/src/api/apiClient.ts +++ b/frontend/src/api/apiClient.ts @@ -31,7 +31,7 @@ const handleSubmitFeedback = async ( message: FormValues["message"], ) => { try { - const response = await api.post(`/v1/api/feedback/`, { + const response = await publicApi.post(`/v1/api/feedback/`, { feedbacktype: feedbackType, name, email, @@ -49,10 +49,8 @@ const handleSendDrugSummary = async ( guid: string, ) => { try { - const endpoint = guid - ? `/v1/api/embeddings/ask_embeddings?guid=${guid}` - : "/v1/api/embeddings/ask_embeddings"; - const response = await api.post(endpoint, { + const endpoint = guid ? `/v1/api/embeddings/ask_embeddings?guid=${guid}` : '/v1/api/embeddings/ask_embeddings'; + const response = await adminApi.post(endpoint, { message, }); console.log("Response data:", JSON.stringify(response.data, null, 2)); @@ -65,9 +63,7 @@ const handleSendDrugSummary = async ( const handleRuleExtraction = async (guid: string) => { try { - const response = await api.get( - `/v1/api/rule_extraction_openai?guid=${guid}`, - ); + const response = await adminApi.get(`/v1/api/rule_extraction_openai?guid=${guid}`); // console.log("Rule extraction response:", JSON.stringify(response.data, null, 2)); return response.data; } catch (error) { @@ -81,7 +77,7 @@ const fetchRiskDataWithSources = async ( source: "include" | "diagnosis" | "diagnosis_depressed" = "include", ) => { try { - const response = await api.post(`/v1/api/riskWithSources`, { + const response = await publicApi.post(`/v1/api/riskWithSources`, { drug: medication, source: source, }); @@ -210,7 +206,7 @@ const handleSendDrugSummaryStreamLegacy = async ( const fetchConversations = async (): Promise => { try { - const response = await api.get(`/chatgpt/conversations/`); + const response = await publicApi.get(`/chatgpt/conversations/`); return response.data; } catch (error) { console.error("Error(s) during getConversations: ", error); @@ -220,7 +216,7 @@ const fetchConversations = async (): Promise => { const fetchConversation = async (id: string): Promise => { try { - const response = await api.get(`/chatgpt/conversations/${id}/`); + const response = await publicApi.get(`/chatgpt/conversations/${id}/`); return response.data; } catch (error) { console.error("Error(s) during getConversation: ", error); @@ -230,7 +226,7 @@ const fetchConversation = async (id: string): Promise => { const newConversation = async (): Promise => { try { - const response = await api.post(`/chatgpt/conversations/`, { + const response = await adminApi.post(`/chatgpt/conversations/`, { messages: [], }); return response.data; @@ -246,7 +242,7 @@ const continueConversation = async ( page_context?: string, ): Promise<{ response: string; title: Conversation["title"] }> => { try { - const response = await api.post( + const response = await adminApi.post( `/chatgpt/conversations/${id}/continue_conversation/`, { message, @@ -262,7 +258,7 @@ const continueConversation = async ( const deleteConversation = async (id: string) => { try { - const response = await api.delete(`/chatgpt/conversations/${id}/`); + const response = await adminApi.delete(`/chatgpt/conversations/${id}/`); return response.data; } catch (error) { console.error("Error(s) during deleteConversation: ", error); @@ -277,12 +273,9 @@ const updateConversationTitle = async ( { status: string; title: Conversation["title"] } | { error: string } > => { try { - const response = await api.patch( - `/chatgpt/conversations/${id}/update_title/`, - { - title: newTitle, - }, - ); + const response = await adminApi.patch(`/chatgpt/conversations/${id}/update_title/`, { + title: newTitle, + }); return response.data; } catch (error) { console.error("Error(s) during getConversation: ", error); diff --git a/frontend/src/components/Header/FeatureMenuDropDown.tsx b/frontend/src/components/Header/FeatureMenuDropDown.tsx index b1bbf03e..36d72792 100644 --- a/frontend/src/components/Header/FeatureMenuDropDown.tsx +++ b/frontend/src/components/Header/FeatureMenuDropDown.tsx @@ -4,13 +4,13 @@ export const FeatureMenuDropDown = () => { const location = useLocation(); const currentPath = location.pathname; return ( -
-
+
+
    Manage files -
    +
    Manage and chat with files
@@ -19,7 +19,7 @@ export const FeatureMenuDropDown = () => {
    Manage rules -
    +
    Manage list of rules
@@ -28,7 +28,7 @@ export const FeatureMenuDropDown = () => {
    Manage meds -
    +
    Manage list of meds
diff --git a/frontend/src/components/Header/Header.tsx b/frontend/src/components/Header/Header.tsx index f696b614..c6b6375f 100644 --- a/frontend/src/components/Header/Header.tsx +++ b/frontend/src/components/Header/Header.tsx @@ -1,16 +1,12 @@ -import { useState, useRef, useEffect, Fragment } from "react"; -// import { useState, Fragment } from "react"; -import accountLogo from "../../assets/account.svg"; +import { useState, useRef, useEffect } from "react"; import { Link, useNavigate, useLocation } from "react-router-dom"; -import LoginMenuDropDown from "./LoginMenuDropDown"; import "../../components/Header/header.css"; import Chat from "./Chat"; import { FeatureMenuDropDown } from "./FeatureMenuDropDown"; import MdNavBar from "./MdNavBar"; -import { connect, useDispatch } from "react-redux"; +import { connect } from "react-redux"; import { RootState } from "../../services/actions/types"; -import { logout, AppDispatch } from "../../services/actions/auth"; -import { HiChevronDown } from "react-icons/hi"; +import { FaChevronDown, FaSignOutAlt } from "react-icons/fa"; import { useGlobalContext } from "../../contexts/GlobalContext.tsx"; interface LoginFormProps { @@ -24,44 +20,16 @@ const Header: React.FC = ({ isAuthenticated, isSuperuser }) => { const dropdownRef = useRef(null); let delayTimeout: number | null = null; const [showChat, setShowChat] = useState(false); - const [showLoginMenu, setShowLoginMenu] = useState(false); - const [redirect, setRedirect] = useState(false); const { setShowSummary, setEnterNewPatient, triggerFormReset, setIsEditing } = useGlobalContext(); - const dispatch = useDispatch(); - - const logout_user = () => { - dispatch(logout()); - setRedirect(false); - }; - - const guestLinks = () => ( - - ); - const authLinks = () => ( - + + Sign Out + + ); - const handleLoginMenu = () => { - setShowLoginMenu(!showLoginMenu); - }; - const handleMouseEnter = () => { if (delayTimeout !== null) { clearTimeout(delayTimeout); @@ -126,7 +94,7 @@ const Header: React.FC = ({ isAuthenticated, isSuperuser }) => { Balancer -
diff --git a/frontend/src/components/Header/LoginMenuDropDown.tsx b/frontend/src/components/Header/LoginMenuDropDown.tsx deleted file mode 100644 index 427fdf07..00000000 --- a/frontend/src/components/Header/LoginMenuDropDown.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React from "react"; -import { Link } from "react-router-dom"; -import { classNames } from "../../utils/classNames"; - -interface LoginMenuDropDownProps { - showLoginMenu: boolean; - handleLoginMenu: () => void; -} - -const LoginMenuDropDown: React.FC = ({ - showLoginMenu, -}) => { - return ( - <> - - -
- - Balancer - - - -

- Balancer is an interactive and user-friendly research tool for bipolar - medications, powered by Code for Philly volunteers. -

-

- We built Balancer{" "} - - to improve the health and well-being of people with bipolar - disorder. - -

-

- Balancer is currently still being developed, so do not take any - information on the test site as actual medical advice. -

- - {/*

- You can log in or sign up for a Balancer account using your email, - gmail or Facebook account. -

*/} - - - - - {/* - - */} -
- - ); -}; - -const LoginMenu = ({ show }: { show: boolean }) => { - if (!show) return null; - - return
; -}; - -export default LoginMenuDropDown; diff --git a/frontend/src/components/Header/MdNavBar.tsx b/frontend/src/components/Header/MdNavBar.tsx index 926794cf..1ed2cd43 100644 --- a/frontend/src/components/Header/MdNavBar.tsx +++ b/frontend/src/components/Header/MdNavBar.tsx @@ -5,8 +5,6 @@ import Chat from "./Chat"; // import logo from "../../assets/balancer.png"; import closeLogo from "../../assets/close.svg"; import hamburgerLogo from "../../assets/hamburger.svg"; -import {useDispatch} from "react-redux"; -import {logout, AppDispatch} from "../../services/actions/auth"; interface LoginFormProps { isAuthenticated: boolean; @@ -22,13 +20,6 @@ const MdNavBar = (props: LoginFormProps) => { setNav(!nav); }; - const dispatch = useDispatch(); - - const logout_user = () => { - dispatch(logout()); - }; - - return (
{
  • Donate
  • {isAuthenticated && -
  • - - Sign Out - -
  • +
  • + Sign Out + +
  • }
    diff --git a/frontend/src/components/Header/header.css b/frontend/src/components/Header/header.css index 4b0f4a2c..c7e807b9 100644 --- a/frontend/src/components/Header/header.css +++ b/frontend/src/components/Header/header.css @@ -23,7 +23,7 @@ } .header-nav-item { - @apply text-black border-transparent border-b-2 hover:border-blue-600 hover:text-blue-600 hover:border-b-2 hover:border-blue-600; + @apply text-black border-transparent border-b-2 hover:cursor-pointer hover:border-blue-600 hover:text-blue-600 hover:border-b-2 hover:border-blue-600; } .header-nav-item.header-nav-item-selected { @@ -31,7 +31,7 @@ } .subheader-nav-item { - @apply cursor-pointer rounded-lg p-3 transition duration-300 hover:bg-gray-100; + @apply cursor-pointer p-3 transition duration-300 hover:bg-gray-200 border-b border-gray-200; } .subheader-nav-item.subheader-nav-item-selected { diff --git a/frontend/src/pages/DocumentManager/UploadFile.tsx b/frontend/src/pages/DocumentManager/UploadFile.tsx index 35c4b84f..f3d0f477 100644 --- a/frontend/src/pages/DocumentManager/UploadFile.tsx +++ b/frontend/src/pages/DocumentManager/UploadFile.tsx @@ -28,8 +28,7 @@ const UploadFile: React.FC = () => { formData, { headers: { - "Content-Type": "multipart/form-data", - Authorization: `JWT ${localStorage.getItem("access")}`, // Assuming JWT is used for auth + "Content-Type": "multipart/form-data" }, } ); diff --git a/frontend/src/pages/Files/ListOfFiles.tsx b/frontend/src/pages/Files/ListOfFiles.tsx index b53874bf..efed19e5 100644 --- a/frontend/src/pages/Files/ListOfFiles.tsx +++ b/frontend/src/pages/Files/ListOfFiles.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { api } from "../../api/apiClient"; +import { publicApi } from "../../api/apiClient"; import Layout from "../Layout/Layout"; import FileRow from "./FileRow"; import Table from "../../components/Table/Table"; @@ -37,7 +37,7 @@ const ListOfFiles: React.FC<{ showTable?: boolean }> = ({ try { const url = `${baseUrl}/v1/api/uploadFile`; - const { data } = await api.get(url); + const { data } = await publicApi.get(url); if (Array.isArray(data)) { setFiles(data); @@ -63,7 +63,7 @@ const ListOfFiles: React.FC<{ showTable?: boolean }> = ({ const handleDownload = async (guid: string, fileName: string) => { try { setDownloading(guid); - const { data } = await api.get(`/v1/api/uploadFile/${guid}`, { responseType: 'blob' }); + const { data } = await publicApi.get(`/v1/api/uploadFile/${guid}`, { responseType: 'blob' }); const url = window.URL.createObjectURL(new Blob([data])); const link = document.createElement("a"); @@ -84,7 +84,7 @@ const ListOfFiles: React.FC<{ showTable?: boolean }> = ({ const handleOpen = async (guid: string) => { try { setOpening(guid); - const { data } = await api.get(`/v1/api/uploadFile/${guid}`, { responseType: 'arraybuffer' }); + const { data } = await publicApi.get(`/v1/api/uploadFile/${guid}`, { responseType: 'arraybuffer' }); const file = new Blob([data], { type: 'application/pdf' }); const fileURL = window.URL.createObjectURL(file); diff --git a/frontend/src/pages/Layout/Layout.tsx b/frontend/src/pages/Layout/Layout.tsx index 3c12358b..84f9c215 100644 --- a/frontend/src/pages/Layout/Layout.tsx +++ b/frontend/src/pages/Layout/Layout.tsx @@ -1,12 +1,10 @@ // Layout.tsx -import {ReactNode, useState, useEffect} from "react"; +import {ReactNode} from "react"; import Header from "../../components/Header/Header"; import Footer from "../../components/Footer/Footer"; -import LoginMenuDropDown from "../../components/Header/LoginMenuDropDown"; import {connect} from "react-redux"; import {useAuth} from "./authHooks.ts"; import {RootState} from "../../services/actions/types"; -import {useLocation} from "react-router-dom"; interface LayoutProps { children: ReactNode; @@ -17,32 +15,8 @@ interface LoginFormProps { } export const Layout = ({ - children, - isAuthenticated, - }: LayoutProps & LoginFormProps): JSX.Element => { - const [showLoginMenu, setShowLoginMenu] = useState(false); - const location = useLocation(); - - - useEffect(() => { - if (!isAuthenticated) { - if ( - location.pathname === "/login" || - location.pathname === "/resetpassword" || - location.pathname.includes("password") || - location.pathname.includes("reset") - ) { - setShowLoginMenu(false); - } else { - setShowLoginMenu(true); - } - } - }, [isAuthenticated, location.pathname]); - - const handleLoginMenu = () => { - setShowLoginMenu(!showLoginMenu); - }; - + children +}: LayoutProps & LoginFormProps): JSX.Element => { useAuth(); return (
    @@ -50,12 +24,6 @@ export const Layout = ({
    - {!isAuthenticated && showLoginMenu && ( - - )}
    {children}
    diff --git a/frontend/src/pages/Layout/Layout_V2_Header.tsx b/frontend/src/pages/Layout/Layout_V2_Header.tsx index b510c62d..3371cef5 100644 --- a/frontend/src/pages/Layout/Layout_V2_Header.tsx +++ b/frontend/src/pages/Layout/Layout_V2_Header.tsx @@ -1,6 +1,4 @@ -import { useState, useEffect } from "react"; import { Link, useLocation } from "react-router-dom"; -import LoginMenuDropDown from "../../components/Header/LoginMenuDropDown.tsx"; import { useAuth } from "./authHooks.ts"; import { useGlobalContext } from "../../../src/contexts/GlobalContext.tsx"; @@ -8,31 +6,12 @@ interface LoginFormProps { isAuthenticated: boolean; } -const Header: React.FC = ({ isAuthenticated }) => { - const [showLoginMenu, setShowLoginMenu] = useState(false); +const Header: React.FC = () => { const location = useLocation(); const { setShowMetaPanel } = useGlobalContext(); const isOnDrugSummaryPage = location.pathname.includes("/drugsummary"); - useEffect(() => { - // only show the login menu on non‑auth pages - if (!isAuthenticated) { - const path = location.pathname; - const isAuthPage = - path === "/login" || - path === "/resetpassword" || - path.includes("password") || - path.includes("reset"); - - setShowLoginMenu(!isAuthPage); - } - }, [isAuthenticated, location.pathname]); - - const handleLoginMenu = () => { - setShowLoginMenu((prev) => !prev); - }; - useAuth(); return ( @@ -65,14 +44,6 @@ const Header: React.FC = ({ isAuthenticated }) => { )}
    - {!isAuthenticated && showLoginMenu && ( -
    - -
    - )} ); }; diff --git a/frontend/src/pages/Layout/Layout_V2_Sidebar.tsx b/frontend/src/pages/Layout/Layout_V2_Sidebar.tsx index 19163290..bec32d50 100644 --- a/frontend/src/pages/Layout/Layout_V2_Sidebar.tsx +++ b/frontend/src/pages/Layout/Layout_V2_Sidebar.tsx @@ -25,11 +25,7 @@ const Sidebar: React.FC = () => { const fetchFiles = async () => { try { const baseUrl = import.meta.env.VITE_API_BASE_URL; - const response = await axios.get(`${baseUrl}/v1/api/uploadFile`, { - headers: { - Authorization: `JWT ${localStorage.getItem("access")}`, - }, - }); + const response = await axios.get(`${baseUrl}/v1/api/uploadFile`); if (Array.isArray(response.data)) { setFiles(response.data); } diff --git a/frontend/src/pages/ListMeds/useMedications.tsx b/frontend/src/pages/ListMeds/useMedications.tsx index e15cc758..022eb07a 100644 --- a/frontend/src/pages/ListMeds/useMedications.tsx +++ b/frontend/src/pages/ListMeds/useMedications.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from "react"; -import { api } from "../../api/apiClient"; +import { publicApi } from "../../api/apiClient"; export interface MedData { name: string; @@ -18,7 +18,7 @@ export function useMedications() { try { const url = `${baseUrl}/v1/api/get_full_list_med`; - const { data } = await api.get(url); + const { data } = await publicApi.get(url); data.sort((a: MedData, b: MedData) => { const nameA = a.name.toUpperCase(); diff --git a/frontend/src/pages/Login/LoginForm.tsx b/frontend/src/pages/Login/LoginForm.tsx index d4579ead..ce28c62c 100644 --- a/frontend/src/pages/Login/LoginForm.tsx +++ b/frontend/src/pages/Login/LoginForm.tsx @@ -1,12 +1,12 @@ import { useFormik } from "formik"; -// import { Link, useNavigate } from "react-router-dom"; -import { useNavigate } from "react-router-dom"; +import { Link, useNavigate } from "react-router-dom"; import { login, AppDispatch } from "../../services/actions/auth"; import { connect, useDispatch } from "react-redux"; import { RootState } from "../../services/actions/types"; import { useState, useEffect } from "react"; import ErrorMessage from "../../components/ErrorMessage"; import LoadingSpinner from "../../components/LoadingSpinner/LoadingSpinner"; +import { FaExclamationTriangle } from "react-icons/fa"; interface LoginFormProps { isAuthenticated: boolean; @@ -59,11 +59,20 @@ function LoginForm({ isAuthenticated, loginError }: LoginFormProps) { onSubmit={handleSubmit} className="mb-4 rounded-md bg-white px-3 pb-12 pt-6 shadow-md ring-1 md:px-12" > -
    +
    {/* {errorMessage &&
    {errorMessage}
    } */}

    Welcome

    + +
    +
    + +
    +
    +

    This login is for Code for Philly administrators. Providers can use all site features without logging in. Return to Homepage

    +
    +
    @@ -100,11 +109,6 @@ function LoginForm({ isAuthenticated, loginError }: LoginFormProps) {
    - {/* - - */} diff --git a/frontend/src/pages/Logout/Logout.tsx b/frontend/src/pages/Logout/Logout.tsx new file mode 100644 index 00000000..b09f0ca3 --- /dev/null +++ b/frontend/src/pages/Logout/Logout.tsx @@ -0,0 +1,42 @@ +import { useEffect } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useDispatch } from "react-redux"; +import { logout, AppDispatch } from "../../services/actions/auth"; + +const LogoutPage = () => { + const navigate = useNavigate(); + const dispatch = useDispatch(); + + useEffect(() => { + dispatch(logout()); + + const timer = setTimeout(() => { + navigate('/'); + }, 3000); // Redirect after 3 seconds + + // Cleanup the timer on component unmount + return () => clearTimeout(timer); + }, [dispatch, navigate]); + + return ( +
    +
    +

    You’ve been logged out

    +
    +
    +
    +

    + Thank you for using Balancer. You'll be redirected to the homepage shortly. +

    + +
    +
    + ); +}; + +export default LogoutPage; diff --git a/frontend/src/pages/ManageMeds/ManageMeds.tsx b/frontend/src/pages/ManageMeds/ManageMeds.tsx index 071a2690..23493f7e 100644 --- a/frontend/src/pages/ManageMeds/ManageMeds.tsx +++ b/frontend/src/pages/ManageMeds/ManageMeds.tsx @@ -2,7 +2,7 @@ import { useState, useEffect } from "react"; import Layout from "../Layout/Layout"; import Welcome from "../../components/Welcome/Welcome"; import ErrorMessage from "../../components/ErrorMessage"; -import { api } from "../../api/apiClient"; +import { adminApi } from "../../api/apiClient"; function ManageMedications() { interface MedData { id: string; @@ -23,7 +23,7 @@ function ManageMedications() { const fetchMedications = async () => { try { const url = `${baseUrl}/v1/api/get_full_list_med`; - const { data } = await api.get(url); + const { data } = await adminApi.get(url); data.sort((a: MedData, b: MedData) => a.name.localeCompare(b.name)); setMedications(data); } catch (e: unknown) { @@ -36,7 +36,7 @@ function ManageMedications() { // Handle Delete Medication const handleDelete = async (name: string) => { try { - await api.delete(`${baseUrl}/v1/api/delete_med`, { data: { name } }); + await adminApi.delete(`${baseUrl}/v1/api/delete_med`, { data: { name } }); setMedications((prev) => prev.filter((med) => med.name !== name)); setConfirmDelete(null); } catch (e: unknown) { @@ -56,7 +56,7 @@ function ManageMedications() { return; } try { - await api.post(`${baseUrl}/v1/api/add_medication`, { + await adminApi.post(`${baseUrl}/v1/api/add_medication`, { name: newMedName, benefits: newMedBenefits, risks: newMedRisks, diff --git a/frontend/src/pages/PatientManager/NewPatientForm.tsx b/frontend/src/pages/PatientManager/NewPatientForm.tsx index 232ed296..3acdd4dd 100644 --- a/frontend/src/pages/PatientManager/NewPatientForm.tsx +++ b/frontend/src/pages/PatientManager/NewPatientForm.tsx @@ -4,7 +4,7 @@ import { PatientInfo, Diagnosis } from "./PatientTypes"; import { useMedications } from "../ListMeds/useMedications"; import ChipsInput from "../../components/ChipsInput/ChipsInput"; import Tooltip from "../../components/Tooltip"; -import { api } from "../../api/apiClient"; +import { publicApi } from "../../api/apiClient"; import { useGlobalContext } from "../../contexts/GlobalContext.tsx"; // import ErrorMessage from "../../components/ErrorMessage"; @@ -155,7 +155,7 @@ const NewPatientForm = ({ const baseUrl = import.meta.env.VITE_API_BASE_URL; const url = `${baseUrl}/v1/api/get_med_recommend`; - const { data } = await api.post(url, payload); + const { data } = await publicApi.post(url, payload); const categorizedMedications = { first: data.first ?? [], diff --git a/frontend/src/pages/RulesManager/RulesManager.tsx b/frontend/src/pages/RulesManager/RulesManager.tsx index be4980d4..0268a4c8 100644 --- a/frontend/src/pages/RulesManager/RulesManager.tsx +++ b/frontend/src/pages/RulesManager/RulesManager.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react"; import Layout from "../Layout/Layout"; import Welcome from "../../components/Welcome/Welcome"; import ErrorMessage from "../../components/ErrorMessage"; -import { api } from "../../api/apiClient"; +import { adminApi } from "../../api/apiClient"; import { ChevronDown, ChevronUp } from "lucide-react"; interface Medication { @@ -69,7 +69,7 @@ function RulesManager() { const fetchMedRules = async () => { try { const url = `${baseUrl}/v1/api/medRules`; - const { data } = await api.get(url); + const { data } = await adminApi.get(url); if (!data || !Array.isArray(data.results)) { throw new Error("Invalid response format"); diff --git a/frontend/src/routes/routes.tsx b/frontend/src/routes/routes.tsx index 2e6273d4..f96f2574 100644 --- a/frontend/src/routes/routes.tsx +++ b/frontend/src/routes/routes.tsx @@ -1,6 +1,7 @@ import App from "../App"; import RouteError from "../pages/404/404.tsx"; import LoginForm from "../pages/Login/Login.tsx"; +import Logout from "../pages/Logout/Logout.tsx"; import AdminPortal from "../pages/AdminPortal/AdminPortal.tsx"; import ResetPassword from "../pages/Login/ResetPassword.tsx"; import ResetPasswordConfirm from "../pages/Login/ResetPasswordConfirm.tsx"; @@ -50,6 +51,10 @@ const routes = [ path: "login", element: , }, + { + path: "logout", + element: , + }, { path: "resetPassword", element: , diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index bcc1e693..4161a741 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -10,8 +10,15 @@ export default { lora: "'Lora', serif", 'quicksand': ['Quicksand', 'sans-serif'] }, + keyframes: { + 'loading': { + '0%': { left: '-40%' }, + '100%': { left: '100%' }, + }, + }, animation: { - 'pulse-bounce': 'pulse-bounce 2s infinite', // Adjust duration and iteration as needed + 'pulse-bounce': 'pulse-bounce 2s infinite', + 'loading': 'loading 3s infinite', }, plugins: [], }, diff --git a/server/api/views/conversations/views.py b/server/api/views/conversations/views.py index d5921eaf..eeb68809 100644 --- a/server/api/views/conversations/views.py +++ b/server/api/views/conversations/views.py @@ -1,7 +1,7 @@ from rest_framework.response import Response from rest_framework import viewsets, status from rest_framework.decorators import action -from rest_framework.permissions import IsAuthenticated +from rest_framework.permissions import AllowAny from rest_framework.exceptions import APIException from django.http import JsonResponse from bs4 import BeautifulSoup @@ -81,7 +81,7 @@ def __init__(self, detail=None, code=None): class ConversationViewSet(viewsets.ModelViewSet): serializer_class = ConversationSerializer - permission_classes = [IsAuthenticated] + permission_classes = [AllowAny] def get_queryset(self): return Conversation.objects.filter(user=self.request.user) diff --git a/server/api/views/feedback/views.py b/server/api/views/feedback/views.py index dcbef992..d0f0e1da 100644 --- a/server/api/views/feedback/views.py +++ b/server/api/views/feedback/views.py @@ -1,4 +1,4 @@ - +from rest_framework.permissions import AllowAny from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status @@ -8,6 +8,8 @@ class FeedbackView(APIView): + permission_classes = [AllowAny] + def post(self, request, *args, **kwargs): serializer = FeedbackSerializer(data=request.data) if serializer.is_valid(): diff --git a/server/api/views/listMeds/views.py b/server/api/views/listMeds/views.py index 1976458e..fcd0edf2 100644 --- a/server/api/views/listMeds/views.py +++ b/server/api/views/listMeds/views.py @@ -1,4 +1,5 @@ from rest_framework import status +from rest_framework.permissions import AllowAny from rest_framework.response import Response from rest_framework.views import APIView @@ -21,6 +22,8 @@ class GetMedication(APIView): + permission_classes = [AllowAny] + def post(self, request): data = request.data state_query = data.get('state', '') @@ -71,6 +74,8 @@ def post(self, request): class ListOrDetailMedication(APIView): + permission_classes = [AllowAny] + def get(self, request): name_query = request.query_params.get('name', None) if name_query: diff --git a/server/api/views/risk/views_riskWithSources.py b/server/api/views/risk/views_riskWithSources.py index 0be43dbb..c02908fc 100644 --- a/server/api/views/risk/views_riskWithSources.py +++ b/server/api/views/risk/views_riskWithSources.py @@ -1,6 +1,7 @@ from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status +from rest_framework.permissions import AllowAny from api.views.listMeds.models import Medication from api.models.model_medRule import MedRule, MedRuleSource import openai @@ -8,6 +9,8 @@ class RiskWithSourcesView(APIView): + permission_classes = [AllowAny] + def post(self, request): openai.api_key = os.environ.get("OPENAI_API_KEY") diff --git a/server/api/views/uploadFile/views.py b/server/api/views/uploadFile/views.py index 6904e061..69dfb996 100644 --- a/server/api/views/uploadFile/views.py +++ b/server/api/views/uploadFile/views.py @@ -1,5 +1,5 @@ from rest_framework.views import APIView -from rest_framework.permissions import IsAuthenticated +from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.response import Response from rest_framework import status from rest_framework.generics import UpdateAPIView @@ -15,16 +15,15 @@ class UploadFileView(APIView): + def get_permissions(self): + if self.request.method == 'GET': + return [AllowAny()] # Public access + return [IsAuthenticated()] # Auth required for other methods def get(self, request, format=None): print("UploadFileView, get list") - # Get the authenticated user - user = request.user - - # Filter the files uploaded by the authenticated user - files = UploadFile.objects.filter(uploaded_by=user.id).defer( - 'file').order_by('-date_of_upload') + files = UploadFile.objects.all().defer('file').order_by('-date_of_upload') serializer = UploadFileSerializer(files, many=True) return Response(serializer.data) @@ -156,12 +155,11 @@ def delete(self, request, format=None): class RetrieveUploadFileView(APIView): - permission_classes = [IsAuthenticated] + permission_classes = [AllowAny] def get(self, request, guid, format=None): try: - file = UploadFile.objects.get( - guid=guid, uploaded_by=request.user.id) + file = UploadFile.objects.get(guid=guid) response = HttpResponse(file.file, content_type='application/pdf') # print(file.file[:100]) response['Content-Disposition'] = f'attachment; filename="{file.file_name}"'