diff --git a/gui/src/App.tsx b/gui/src/App.tsx index 4fb420c7a6..9bc629ce72 100644 --- a/gui/src/App.tsx +++ b/gui/src/App.tsx @@ -11,6 +11,7 @@ import ErrorPage from "./pages/error"; import GUI from "./pages/gui"; import { default as Help, default as HelpPage } from "./pages/help"; import History from "./pages/history"; +import Feedback from "./pages/feedback" import MigrationPage from "./pages/migration"; import MonacoPage from "./pages/monaco"; import ApiKeyAutocompleteOnboarding from "./pages/onboarding/apiKeyAutocompleteOnboarding"; @@ -83,6 +84,10 @@ const router = createMemoryRouter( path: "/help", element: , }, + { + path: "/feedback", + element: , + }, { path: "/monaco", element: , @@ -132,6 +137,7 @@ const router = createMemoryRouter( function App() { const dispatch = useDispatch(); + useSetup(dispatch); const vscTheme = useVscTheme(); diff --git a/gui/src/components/Layout.tsx b/gui/src/components/Layout.tsx index f59117e1bd..0fcee8ab17 100644 --- a/gui/src/components/Layout.tsx +++ b/gui/src/components/Layout.tsx @@ -1,4 +1,4 @@ -import { QuestionMarkCircleIcon } from "@heroicons/react/24/outline"; +import { QuestionMarkCircleIcon, InboxStackIcon } from "@heroicons/react/24/outline"; import { IndexingProgressUpdate } from "core"; import { useContext, useEffect, useState, useCallback } from "react"; import { useDispatch, useSelector } from "react-redux"; @@ -364,6 +364,19 @@ const Layout = () => { > + { + if (location.pathname === "/feedback") { + navigate("/"); + } else { + navigate("/feedback"); + } + }} + > + + )} diff --git a/gui/src/pages/feedback.tsx b/gui/src/pages/feedback.tsx new file mode 100644 index 0000000000..0317cf9e1f --- /dev/null +++ b/gui/src/pages/feedback.tsx @@ -0,0 +1,123 @@ +/* eslint-disable header/header */ +import { useState, useEffect, useContext } from 'react'; +import { Button, vscEditorBackground, vscBackground, vscInputBackground, vscForeground } from '../components'; +import styled from 'styled-components'; +import { useNavigate } from "react-router-dom"; +import { useNavigationListener } from "../hooks/useNavigationListener"; +import { IdeMessengerContext } from '../context/IdeMessenger'; +import { getHeaders } from '../../../core/pearaiServer/stubs/headers'; +import { SERVER_URL } from '../../../core/util/parameters'; + +const GridDiv = styled.div` + display: grid; + padding: 2rem; + justify-items: center; + align-items: center; + overflow-y: auto; +`; + +const TextArea = styled.textarea` + width: 100%; + padding: 8px; + margin: 4px 0; + background-color: ${vscInputBackground}; + color: ${vscForeground}; + border: 1px solid ${vscInputBackground}; + border-radius: 4px; + &:focus { + outline: none; + border-color: #007acc; + } +`; + +const FormGroup = styled.div` + margin-bottom: 1rem; + width: 100%; +`; + +const Label = styled.label` + display: block; + margin-bottom: 4px; + color: ${vscForeground}; +`; + +function Feedback() { + useNavigationListener(); + const navigate = useNavigate(); + const [feedback, setFeedback] = useState(''); + const ideMessenger = useContext(IdeMessengerContext); + const [accessToken, setAccessToken] = useState(null); + + useEffect(() => { + const initializeAuth = async () => { + try { + const auth = await ideMessenger.request('getPearAuth', undefined); + if (auth?.accessToken) { + setAccessToken(auth.accessToken); + } else { + ideMessenger.ide.errorPopup("Please login to PearAI"); + } + } catch (error) { + console.error("Error initializing authentication:", error); + ideMessenger.ide.errorPopup("Failed to retrieve authentication. Please try again."); + } + }; + initializeAuth(); + }, [ideMessenger]); + + const handleSubmit = async (e) => { + e.preventDefault(); + if (!accessToken) { + ideMessenger.ide.errorPopup("Please login to PearAI"); + return; + } + + const response = await fetch(`${SERVER_URL}/client_feedback`, { + method: 'POST', + headers: { + ...(await getHeaders()), + 'Authorization': `Bearer ${accessToken}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ feedback }) + }); + + if (!response.ok) { + const errorMessage = `Status: ${response.status} - ${response.statusText}`; + ideMessenger.ide.errorPopup(`Failed to send feedback. ${errorMessage}`); + return; + } + + ideMessenger.ide.infoPopup('Feedback sent successfully!'); + navigate("/"); + }; + + return ( + + + Send Feedback + Help us improve PearAI by sharing your thoughts + + + + Your Feedback + setFeedback(e.target.value)} + className='h-32' + placeholder='Enter your feedback here...' + /> + + + + Submit Feedback + + + + + ); +} + +export default Feedback;
Help us improve PearAI by sharing your thoughts