From 63e8f3e0211d23b1ea4a772fbef164ed1390679f Mon Sep 17 00:00:00 2001 From: John Overton Date: Thu, 2 Apr 2026 14:36:57 -0500 Subject: [PATCH] removed orphaned components --- src/components/forms/FeedbackForm/README.md | 128 ------- .../forms/FeedbackForm/feedback-form.css | 115 ------- src/components/forms/FeedbackForm/index.tsx | 311 ------------------ 3 files changed, 554 deletions(-) delete mode 100644 src/components/forms/FeedbackForm/README.md delete mode 100644 src/components/forms/FeedbackForm/feedback-form.css delete mode 100644 src/components/forms/FeedbackForm/index.tsx diff --git a/src/components/forms/FeedbackForm/README.md b/src/components/forms/FeedbackForm/README.md deleted file mode 100644 index 6aa0643..0000000 --- a/src/components/forms/FeedbackForm/README.md +++ /dev/null @@ -1,128 +0,0 @@ -# FeedbackForm Component - -A form component for collecting user feedback and support requests. This component follows the form-page pattern used throughout the application and automatically captures user context information. - -## Features - -- Collects feedback with subject and message -- Automatically captures submitter information (name, email, family context) -- Form validation for required fields -- Responsive design with dark mode support -- Multi-family support with family ID association -- Success/error handling with user feedback - -## Props - -| Prop | Type | Required | Description | -|------|------|----------|-------------| -| `isOpen` | boolean | Yes | Controls whether the form is visible | -| `onClose` | () => void | Yes | Function to call when the form should be closed | -| `onSuccess` | () => void | No | Optional callback function called after successful submission | - -## Usage - -```tsx -import FeedbackForm from '@/src/components/forms/FeedbackForm'; - -function MyComponent() { - const [showFeedbackForm, setShowFeedbackForm] = useState(false); - - return ( - <> - - - setShowFeedbackForm(false)} - onSuccess={() => { - // Optional: Handle successful feedback submission - console.log('Feedback submitted successfully'); - }} - /> - - ); -} -``` - -## Form Fields - -The component includes the following fields: - -- **Subject**: Brief description of the feedback (required) -- **Message**: Detailed feedback, suggestions, or issue report (required) - -## Automatic Context Capture - -The component automatically captures and displays: - -- **Submitter Name**: Extracted from authentication token (account email prefix or caretaker name) -- **Submitter Email**: Account email if available (account users only) -- **Family Context**: Current family name and ID from family context - -## Implementation Details - -- Uses the FormPage component for consistent UI across the application -- Automatically extracts user information from JWT authentication token -- Supports both account-based and caretaker-based authentication -- Includes form validation for required fields -- Handles API calls for submitting feedback -- Provides user feedback through alerts for success/error states -- Resets form after successful submission -- Uses emerald/green theme colors to indicate positive action (feedback submission) - -### Authentication Context - -The component handles different authentication scenarios: - -1. **Account Authentication**: Extracts email and uses email prefix as name -2. **Caretaker Authentication**: Extracts caretaker name from token -3. **No Authentication**: Falls back to generic "User" name - -### Multi-Family Support - -The component supports multi-family functionality by: -- Automatically using the current family context from `useFamily()` hook -- Including the family ID in the API request payload -- Displaying the current family name in the submitter information - -### API Integration - -The component sends feedback data to `/api/feedback` with the following payload: -```json -{ - "subject": "string", - "message": "string", - "familyId": "string|null", - "submitterName": "string", - "submitterEmail": "string|null" -} -``` - -## Styling - -The component uses: -- Light mode styles defined in the component and CSS classes -- Dark mode overrides in `feedback-form.css` -- Consistent styling with other form components -- Emerald/green accent colors for the submit button -- Info box styling for displaying submitter context - -## Accessibility - -- Proper form labels and required field indicators -- Keyboard navigation support -- Screen reader friendly structure -- Clear error and success messaging -- Disabled states during form submission - -## Error Handling - -The component handles various error scenarios: -- Network errors during submission -- API validation errors -- Authentication token parsing errors -- Missing required fields - -All errors are displayed to the user through alert dialogs with descriptive messages. diff --git a/src/components/forms/FeedbackForm/feedback-form.css b/src/components/forms/FeedbackForm/feedback-form.css deleted file mode 100644 index 6dae1b3..0000000 --- a/src/components/forms/FeedbackForm/feedback-form.css +++ /dev/null @@ -1,115 +0,0 @@ -/* Dark mode overrides for FeedbackForm component */ - -/* Submitter info section in dark mode */ -html.dark .feedback-form-submitter-info { - color: #9ca3af !important; /* gray-400 */ -} - -/* Info container styling in dark mode */ -html.dark .feedback-form-info { - background-color: #374151 !important; /* gray-700 */ - border: 1px solid #4b5563 !important; /* gray-600 */ - border-radius: 0.5rem; - padding: 0.75rem; -} - -/* Input field styling in dark mode */ -html.dark .feedback-form-input { - background-color: #1f2937 !important; /* gray-800 */ - border-color: #4b5563 !important; /* gray-600 */ - color: #e5e7eb !important; /* gray-200 */ -} - -html.dark .feedback-form-input:hover { - background-color: #374151 !important; /* gray-700 */ - border-color: #6b7280 !important; /* gray-500 */ -} - -html.dark .feedback-form-input:focus { - border-color: #10b981 !important; /* emerald-500 */ - background-color: #1f2937 !important; /* gray-800 */ - ring-color: rgba(16, 185, 129, 0.2) !important; /* emerald-500 with opacity */ -} - -html.dark .feedback-form-input::placeholder { - color: #9ca3af !important; /* gray-400 */ -} - -/* Textarea styling in dark mode */ -html.dark .feedback-form-textarea { - background-color: #1f2937 !important; /* gray-800 */ - border-color: #4b5563 !important; /* gray-600 */ - color: #e5e7eb !important; /* gray-200 */ -} - -html.dark .feedback-form-textarea:hover { - background-color: #374151 !important; /* gray-700 */ - border-color: #6b7280 !important; /* gray-500 */ -} - -html.dark .feedback-form-textarea:focus { - border-color: #10b981 !important; /* emerald-500 */ - background-color: #1f2937 !important; /* gray-800 */ - ring-color: rgba(16, 185, 129, 0.2) !important; /* emerald-500 with opacity */ -} - -html.dark .feedback-form-textarea::placeholder { - color: #9ca3af !important; /* gray-400 */ -} - -/* Help text styling in dark mode */ -html.dark .feedback-form-help-text { - color: #9ca3af !important; /* gray-400 */ -} - -/* Light mode styles for info container */ -.feedback-form-info { - background-color: #f8fafc; /* slate-50 */ - border: 1px solid #e2e8f0; /* slate-200 */ - border-radius: 0.5rem; - padding: 0.75rem; -} - -.feedback-form-submitter-info { - color: #64748b; /* slate-500 */ -} - -.feedback-form-help-text { - color: #64748b; /* slate-500 */ -} - -/* Success toast styling */ -.feedback-success-toast { - background-color: #ecfdf5; /* emerald-50 */ - border-color: #a7f3d0; /* emerald-200 */ -} - -.feedback-success-toast-icon { - color: #6ee7b7; /* emerald-300 */ -} - -.feedback-success-toast-title { - color: #065f46; /* emerald-800 */ -} - -.feedback-success-toast-message { - color: #047857; /* emerald-700 */ -} - -/* Dark mode success toast styling */ -html.dark .feedback-success-toast { - background-color: #064e3b !important; /* emerald-900 */ - border-color: #065f46 !important; /* emerald-800 */ -} - -html.dark .feedback-success-toast-icon { - color: #6ee7b7 !important; /* emerald-300 */ -} - -html.dark .feedback-success-toast-title { - color: #a7f3d0 !important; /* emerald-200 */ -} - -html.dark .feedback-success-toast-message { - color: #6ee7b7 !important; /* emerald-300 */ -} diff --git a/src/components/forms/FeedbackForm/index.tsx b/src/components/forms/FeedbackForm/index.tsx deleted file mode 100644 index b8ac0e8..0000000 --- a/src/components/forms/FeedbackForm/index.tsx +++ /dev/null @@ -1,311 +0,0 @@ -'use client'; - -import React, { useState, useEffect } from 'react'; -import { Button } from '@/src/components/ui/button'; -import { Input } from '@/src/components/ui/input'; -import { Textarea } from '@/src/components/ui/textarea'; -import { - FormPage, - FormPageContent, - FormPageFooter -} from '@/src/components/ui/form-page'; -import { useTheme } from '@/src/context/theme';import { useLocalization } from '@/src/context/localization'; - -import './feedback-form.css'; - -interface FeedbackFormProps { - isOpen: boolean; - onClose: () => void; - onSuccess?: () => void; - embedded?: boolean; // If true, renders without FormPage wrapper -} - -export default function FeedbackForm({ - isOpen, - onClose, - onSuccess, - embedded = false, -}: FeedbackFormProps) { - const { t } = useLocalization(); - const { theme } = useTheme(); - const [formData, setFormData] = useState({ - subject: '', - message: '', - }); - const [loading, setLoading] = useState(false); - const [submitterInfo, setSubmitterInfo] = useState({ - name: '', - email: '', - }); - const [family, setFamily] = useState<{ id: string; name: string } | null>(null); - const [showSuccessToast, setShowSuccessToast] = useState(false); - - // Get submitter information from authentication context - useEffect(() => { - const getSubmitterInfo = async () => { - try { - const authToken = localStorage.getItem('authToken'); - if (!authToken) return; - - // Parse JWT token to get user info - const payload = authToken.split('.')[1]; - const decodedPayload = JSON.parse(atob(payload)); - - // Check if this is account authentication - if (decodedPayload.isAccountAuth) { - // For account users, we can get email from the token - setSubmitterInfo({ - name: decodedPayload.accountEmail ? decodedPayload.accountEmail.split('@')[0] : 'Account User', - email: decodedPayload.accountEmail || '', - }); - } else { - // For caretaker users, get name from token - setSubmitterInfo({ - name: decodedPayload.name || 'User', - email: '', // Caretakers don't have email in the token - }); - } - - // Try to get family information if available - if (decodedPayload.familyId && decodedPayload.familySlug) { - // We have family info in the token, try to get family name - try { - const familyResponse = await fetch(`/api/family/by-slug/${decodedPayload.familySlug}`, { - headers: { - 'Authorization': `Bearer ${authToken}` - } - }); - - if (familyResponse.ok) { - const familyData = await familyResponse.json(); - if (familyData.success && familyData.data) { - setFamily({ - id: familyData.data.id, - name: familyData.data.name - }); - } - } - } catch (familyError) { - console.log('Could not fetch family info:', familyError); - // Not a critical error, continue without family info - } - } - } catch (error) { - console.error('Error parsing auth token:', error); - setSubmitterInfo({ - name: 'User', - email: '', - }); - } - }; - - if (isOpen) { - getSubmitterInfo(); - } - }, [isOpen]); - - // Reset form when opening - useEffect(() => { - if (isOpen) { - setFormData({ - subject: '', - message: '', - }); - } - }, [isOpen]); - - const handleInputChange = (e: React.ChangeEvent) => { - const { name, value } = e.target; - setFormData(prev => ({ ...prev, [name]: value })); - }; - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - - // Validate required fields - if (!formData.subject.trim() || !formData.message.trim()) { - alert(t('Please fill in both subject and message fields.')); - return; - } - - setLoading(true); - - try { - const authToken = localStorage.getItem('authToken'); - - const payload = { - subject: formData.subject.trim(), - message: formData.message.trim(), - familyId: family?.id || null, - submitterName: submitterInfo.name, - submitterEmail: submitterInfo.email || null, - }; - - const response = await fetch('/api/feedback', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': authToken ? `Bearer ${authToken}` : '', - }, - body: JSON.stringify(payload), - }); - - const data = await response.json(); - - if (data.success) { - // Show success toast - setShowSuccessToast(true); - - // Auto-close after 3 seconds - setTimeout(() => { - onClose(); - if (onSuccess) onSuccess(); - }, 3000); - } else { - console.error('Error submitting feedback:', data.error); - alert(`Error: ${data.error || 'Failed to submit feedback'}`); - } - } catch (error) { - console.error('Error submitting feedback:', error); - alert(t('An unexpected error occurred. Please try again.')); - } finally { - setLoading(false); - } - }; - - const formContent = ( - <> - {/* Success Toast */} - {showSuccessToast && ( -
-
-
- - - -
-
-

- {t('Thank you for your feedback!')} -

-

- {t('We appreciate your input and will review your message.')} - {submitterInfo.email && ' A confirmation email has been sent to you.'} -

-
-
-
- )} - -
-
- {/* Submitter Info Display */} -
-
-

{t('From:')} {submitterInfo.name}

- {submitterInfo.email && ( -

{t('Email:')} {submitterInfo.email}

- )} - {family && ( -

{t('Family:')} {family.name}

- )} -
-
- - {/* Subject */} -
- - -
- - {/* Message */} -
- -