diff --git a/make-practiceapp-deployready.md b/make-practiceapp-deployready.md index c88a190..e257c9a 100644 --- a/make-practiceapp-deployready.md +++ b/make-practiceapp-deployready.md @@ -98,8 +98,10 @@ This guide details the comprehensive changes implemented to prepare the SWA Prac - Modified the `evaluateWithGemini` function to accept the `ai` instance as a parameter, ensuring it uses the dynamically created `GoogleGenAI` instance. - Added a check within `handleSubmit` in `ExerciseSheet` to verify the `ai` instance and its `models.generateContent` method before making API calls, providing a user-friendly error message if the API key is missing or invalid. - **Template Literal Escaping Fixes**: - - Crucially, fixed syntax errors within the `systemInstruction` and `contents` template literals in `evaluateWithGemini`. The original code had issues with unescaped backticks (``` ` ```) and newlines (`\n`) when they were part of the string content itself, leading to build failures. - - **Specific Fix**: All literal backticks within the template strings (e.g., for code blocks like ``` ```c ```) were escaped as``` \`\`\` ```. All literal newlines (`\n`) within the template strings were escaped as `\\n`. This ensures they are interpreted as literal characters within the string rather than JavaScript syntax. + - Crucially, fixed syntax errors within the `systemInstruction` and `contents` template literals in `evaluateWithGemini`. The original code had issues with unescaped backticks (``` ` ```) and newlines (` +`) when they were part of the string content itself, leading to build failures. + - **Specific Fix**: All literal backticks within the template strings (e.g., for code blocks like ``` ```c ```) were escaped as``` \`\`\` ```. All literal newlines (` +`) within the template strings were escaped as `\\n`. This ensures they are interpreted as literal characters within the string rather than JavaScript syntax. **Step-by-step Actions**: @@ -525,3 +527,215 @@ CMD [ "serve", "-s", "dist", "-l", "8000" ] This enhancement makes the application more suitable for software architecture exercises that require diagram creation and visualization. --- + +### 6. Optional: Implementing Sentry User Feedback + +**Objective**: To provide a simple and effective way for users to provide feedback, report issues, or suggest new ideas directly from within the application. + +**Previous State**: The application had no built-in feedback mechanism. + +**Changes Made**: + +- **Sentry SDK Update**: Replaced `@sentry/browser` with `@sentry/react` to leverage React-specific features. +- **Sentry Initialization**: Configured the Sentry SDK in `index.tsx` to include the `feedbackIntegration`, enabling the user feedback features. +- **Custom Feedback Dialog**: + - Instead of using the default Sentry feedback widget, a custom feedback dialog was implemented in `App.tsx` for a more integrated user experience. + - A "Feedback" button with a `ChatBubbleLeftRightIcon` was added to the top-right corner of the application. + - Clicking the button opens a `Dialog` (modal) from `@headlessui/react`. + - The modal contains a textarea for the user to enter their feedback, with German placeholder text. + - When the user submits the feedback, `Sentry.captureFeedback` is called to send the feedback to Sentry. + +**Step-by-step Actions**: + +1. Remove `@sentry/browser` and add `@sentry/react` to `package.json`. +2. Update `index.tsx` to import from `@sentry/react` and add the `feedbackIntegration` to the `Sentry.init` call. +3. In `App.tsx`, import `ChatBubbleLeftRightIcon` from `@heroicons/react/24/outline` and `* as Sentry from "@sentry/react"`. +4. Add state variables for the feedback dialog visibility and the feedback message. +5. Add a "Feedback" button next to the "Settings" button. +6. Implement the custom feedback `Dialog` component with a textarea and submit/cancel buttons. +7. Create a handler function that calls `Sentry.captureFeedback` with the user's message. +8. Write the modified content back to the respective files. + +**Code Changes (package.json)**: + +```diff +--- a/package.json ++++ b/package.json +@@ -10,7 +10,7 @@ + "dependencies": { + "@google/genai": "latest", + "@headlessui/react": "^2.2.4", +- "@heroicons/react": "^2.2.0", +- "@sentry/browser": "^9.36.0", ++ "@heroicons/react": "^2.2.0", ++ "@sentry/react": "9.36.0", + "diff": "5.2.0", + "mermaid": "^11.8.1", + "prismjs": "1.29.0", + +``` + +**Code Changes (index.tsx)**: + +```diff +--- a/index.tsx ++++ b/index.tsx +@@ -1,8 +1,15 @@ + import React from 'react'; + import ReactDOM from 'react-dom/client'; + import App from './App'; +-import * as Sentry from "@sentry/browser"; ++import * as Sentry from "@sentry/react"; + +-Sentry.init({ dsn: "https://2851a11b9f1b4715b389979628da322f@glitchtip.yandrik.dev/3" }); ++Sentry.init({ ++ dsn: "https://2851a11b9f1b4715b389979628da322f@glitchtip.yandrik.dev/3", ++ integrations: [ ++ Sentry.feedbackIntegration({ ++ colorScheme: "system", ++ }), ++ ], ++}); + + const rootElement = document.getElementById('root'); + if (!rootElement) { + +``` + +**Code Changes (App.tsx)**: + +```diff +--- a/App.tsx ++++ b/App.tsx +@@ -1,7 +1,8 @@ + import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react'; + import { Dialog } from "@headlessui/react"; +-import { Cog6ToothIcon } from "@heroicons/react/24/outline"; ++import { Cog6ToothIcon, ChatBubbleLeftRightIcon } from "@heroicons/react/24/outline"; + import { Exercise, CheckResult, ExercisePartType } from './types'; ++import * as Sentry from "@sentry/react"; + import { swaExercises1 } from './data/swa_exercises.1'; + import { swaExercises2 } from './data/swa_exercises.2'; + import { swaExercises3 } from './data/swa_exercises.3'; +@@ -564,6 +565,18 @@ + const [exercises, setExercises] = useState([]); + const [currentIndex, setCurrentIndex] = useState(0); + ++ const [showFeedback, setShowFeedback] = useState(false); ++ const [feedbackMessage, setFeedbackMessage] = useState(''); ++ ++ const handleFeedbackSubmit = () => { ++ Sentry.captureFeedback({ ++ message: feedbackMessage, ++ }); ++ setFeedbackMessage(''); ++ setShowFeedback(false); ++ }; ++ ++ + // --- API KEY STATE --- + const [apiKey, setApiKey] = useState(''); + const [showSettings, setShowSettings] = useState(false); +@@ -604,12 +617,60 @@ + + return ( +
++ {/* Feedback Button */} ++ + {/* Settings Button */} + + {/* Settings Modal */} + setShowSettings(false)} className="relative z-50"> ++ ++ {/* Feedback Modal */} ++ setShowFeedback(false)} className="relative z-50"> ++