From c47050b292f1f57562045a90d392e739c94a4a98 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 2 Apr 2025 10:53:10 +0100 Subject: [PATCH 01/35] style: renamed tour folder to help center --- src/App.tsx | 43 +++++++++++-------- .../ui/{tour => helpCenter}/HelpButton.tsx | 0 .../ui/{tour => helpCenter}/HelpCenter.tsx | 11 ++++- .../ui/{tour => helpCenter}/HelpProvider.tsx | 0 .../ui/{tour => helpCenter}/WelcomePanel.tsx | 0 .../ui/{tour => helpCenter}/index.ts | 0 src/data/helpContent.json | 2 + 7 files changed, 37 insertions(+), 19 deletions(-) rename src/components/ui/{tour => helpCenter}/HelpButton.tsx (100%) rename src/components/ui/{tour => helpCenter}/HelpCenter.tsx (96%) rename src/components/ui/{tour => helpCenter}/HelpProvider.tsx (100%) rename src/components/ui/{tour => helpCenter}/WelcomePanel.tsx (100%) rename src/components/ui/{tour => helpCenter}/index.ts (100%) diff --git a/src/App.tsx b/src/App.tsx index 476f13e..3f530b6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,7 +7,7 @@ import { TooltipProvider } from './components/ui/better-tooltip'; import { AuthProvider } from './features/auth/AuthProvider'; import { EntriesProvider } from './features/statements/context/EntriesProvider'; import { QuestionsProvider } from './providers/QuestionsProvider'; -import { HelpProvider } from './components/ui/tour'; +import { HelpProvider } from './components/ui/helpCenter'; // Components import LoginPage from './features/auth/components/LoginPage'; @@ -33,43 +33,50 @@ const AppContent: React.FC = () => { verifyToken(); }, []); - + // Force synchronization between auth state and entries state when component mounts useEffect(() => { if (authState.user && authState.isAuthenticated) { - console.log('AppContent: Found authenticated user, dispatching event:', authState.user); + console.log( + 'AppContent: Found authenticated user, dispatching event:', + authState.user + ); // Dispatch event to ensure EntriesProvider gets the user data - window.dispatchEvent(new CustomEvent('authStateChanged', { - detail: { user: authState.user } - })); + window.dispatchEvent( + new CustomEvent('authStateChanged', { + detail: { user: authState.user }, + }) + ); } }, [authState.user, authState.isAuthenticated]); - + // Listen for magic link verification and ensure user email is saved to entries context useEffect(() => { const handleMagicLinkVerified = (event: any) => { if (event.detail?.user?.email) { - console.log('App: Magic link verified with email:', event.detail.user.email); + console.log( + 'App: Magic link verified with email:', + event.detail.user.email + ); // Dispatch event with user email to entries context - window.dispatchEvent(new CustomEvent('authStateChanged', { - detail: { user: { email: event.detail.user.email }} - })); + window.dispatchEvent( + new CustomEvent('authStateChanged', { + detail: { user: { email: event.detail.user.email } }, + }) + ); } }; - + window.addEventListener('magicLinkVerified', handleMagicLinkVerified); - return () => window.removeEventListener('magicLinkVerified', handleMagicLinkVerified); + return () => + window.removeEventListener('magicLinkVerified', handleMagicLinkVerified); }, []); return ( // MainPage and Header receives the username from context. <>
- {data.username ? ( - - ) : ( - - )} + {data.username ? : } ); }; diff --git a/src/components/ui/tour/HelpButton.tsx b/src/components/ui/helpCenter/HelpButton.tsx similarity index 100% rename from src/components/ui/tour/HelpButton.tsx rename to src/components/ui/helpCenter/HelpButton.tsx diff --git a/src/components/ui/tour/HelpCenter.tsx b/src/components/ui/helpCenter/HelpCenter.tsx similarity index 96% rename from src/components/ui/tour/HelpCenter.tsx rename to src/components/ui/helpCenter/HelpCenter.tsx index e101149..5a0e8c1 100644 --- a/src/components/ui/tour/HelpCenter.tsx +++ b/src/components/ui/helpCenter/HelpCenter.tsx @@ -10,7 +10,7 @@ interface HelpCenterProps { initialTab?: string; } -type TabType = 'welcome' | 'tutorials' | 'features' | 'versions'; +type TabType = 'welcome' | 'tutorials' | 'features' | 'resources' | 'versions'; const HelpCenter: React.FC = ({ onClose, @@ -215,6 +215,15 @@ const HelpCenter: React.FC = ({ )} + {/* Resources Tab */} + {activeTab === 'resources' && ( +
+

+ Resources +

+
+ )} + {/* Versions Tab */} {activeTab === 'versions' && (
diff --git a/src/components/ui/tour/HelpProvider.tsx b/src/components/ui/helpCenter/HelpProvider.tsx similarity index 100% rename from src/components/ui/tour/HelpProvider.tsx rename to src/components/ui/helpCenter/HelpProvider.tsx diff --git a/src/components/ui/tour/WelcomePanel.tsx b/src/components/ui/helpCenter/WelcomePanel.tsx similarity index 100% rename from src/components/ui/tour/WelcomePanel.tsx rename to src/components/ui/helpCenter/WelcomePanel.tsx diff --git a/src/components/ui/tour/index.ts b/src/components/ui/helpCenter/index.ts similarity index 100% rename from src/components/ui/tour/index.ts rename to src/components/ui/helpCenter/index.ts diff --git a/src/data/helpContent.json b/src/data/helpContent.json index 65248a8..8f3ee0f 100644 --- a/src/data/helpContent.json +++ b/src/data/helpContent.json @@ -80,6 +80,8 @@ "details": "For each statement, you can choose whether it's private (only visible to you) or public (visible to your line manager). You can change the privacy setting at any time." } ], + + "resources": [{}], "versions": [ { "version": "1.0.0", From beeac7fef8c5e95594269056107039f3fdef589d Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 2 Apr 2025 11:15:06 +0100 Subject: [PATCH 02/35] fix: separate context and provider to make eslint happy --- src/components/ui/helpCenter/HelpCenter.tsx | 38 +++++++++++++++++-- src/components/ui/helpCenter/HelpContext.ts | 9 +++++ src/components/ui/helpCenter/HelpProvider.tsx | 17 +-------- src/components/ui/helpCenter/hooks/index.ts | 1 + src/components/ui/helpCenter/hooks/useHelp.ts | 12 ++++++ src/components/ui/helpCenter/index.ts | 3 +- src/data/helpContent.json | 28 +++++++++++++- 7 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 src/components/ui/helpCenter/HelpContext.ts create mode 100644 src/components/ui/helpCenter/hooks/index.ts create mode 100644 src/components/ui/helpCenter/hooks/useHelp.ts diff --git a/src/components/ui/helpCenter/HelpCenter.tsx b/src/components/ui/helpCenter/HelpCenter.tsx index 5a0e8c1..5a040ee 100644 --- a/src/components/ui/helpCenter/HelpCenter.tsx +++ b/src/components/ui/helpCenter/HelpCenter.tsx @@ -1,7 +1,7 @@ 'use client'; import React, { useState } from 'react'; -import { X, Info, PlayCircle, BookOpen, History } from 'lucide-react'; +import { X, Info, PlayCircle, BookOpen, History, Link as LinkIcon } from 'lucide-react'; import { Button } from '@/components/ui/button'; import helpContent from '@/data/helpContent.json'; @@ -73,7 +73,7 @@ const HelpCenter: React.FC = ({
{/* Tabs - grid for mobile, flex for desktop */} -
+
+ - - ); +const SimpleDialogClose: React.FC<{ + children: React.ReactNode; + className?: string; + asChild?: boolean; +}> = ({ children, className }) => { + return ; }; -const SimpleDialogTitle: React.FC = ({ children, className }) => { +const SimpleDialogTitle: React.FC = ({ + children, + className, +}) => { return ( -

+

{children}

); }; -const SimpleDialogDescription: React.FC = ({ children, className }) => { +const SimpleDialogDescription: React.FC = ({ + children, + className, +}) => { return ( -

+

{children}

); @@ -129,53 +142,61 @@ const SimpleDialogDescription: React.FC = ({ child // Context is now imported from separate file -const SimpleDialogTrigger: React.FC = ({ children }) => { +const SimpleDialogTrigger: React.FC = ({ + children, +}) => { // Get the dialog context to control the dialog's open state const { onOpenChange } = React.useContext(SimpleDialogContext); - + // Create a clickable wrapper that opens the dialog const handleClick = (e: React.MouseEvent) => { e.preventDefault(); console.log('SimpleDialogTrigger: Opening dialog'); onOpenChange(true); }; - + // If asChild is true, we'd clone the child element and add an onClick handler // For simplicity, we'll just wrap the children in a div with an onClick return ( -
+
{children}
); }; -const SimpleDialog: React.FC = ({ - isOpen, +const SimpleDialog: React.FC = ({ + isOpen, open, - onOpenChange, - children, - className + onOpenChange, + children, + className, }) => { // Support both isOpen and open props for compatibility - const isDialogOpen = open !== undefined ? open : isOpen !== undefined ? isOpen : false; - + const isDialogOpen = + open !== undefined ? open : isOpen !== undefined ? isOpen : false; + // Handle ESC key press useEffect(() => { if (!isDialogOpen) return; - + const onKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') { onOpenChange(false); } }; - + window.addEventListener('keydown', onKeyDown); return () => window.removeEventListener('keydown', onKeyDown); }, [isDialogOpen, onOpenChange]); // Provide the dialog state to all children via context return ( - + {isDialogOpen ? (
onOpenChange(false)} /> @@ -190,10 +211,10 @@ const SimpleDialog: React.FC = ({ }; // For compatibility with existing code -const SimpleDialogHeader: React.FC<{ className?: string; children: React.ReactNode }> = ({ - className, - children -}) => ( +const SimpleDialogHeader: React.FC<{ + className?: string; + children: React.ReactNode; +}> = ({ className, children }) => (
); -const SimpleDialogFooter: React.FC<{ className?: string; children: React.ReactNode }> = ({ - className, - children -}) => ( +const SimpleDialogFooter: React.FC<{ + className?: string; + children: React.ReactNode; +}> = ({ className, children }) => (
{ children: React.ReactNode; asChild?: boolean; onClick?: (e: React.MouseEvent) => void; className?: string; - [key: string]: any; // Allow any other props } -interface SimpleDropdownMenuContentProps { +interface SimpleDropdownMenuContentProps extends React.HTMLAttributes { children: React.ReactNode; className?: string; sideOffset?: number; - [key: string]: any; } -interface SimpleDropdownMenuItemProps { +interface SimpleDropdownMenuItemProps extends React.HTMLAttributes { children: React.ReactNode; className?: string; onClick?: (e: React.MouseEvent) => void; - [key: string]: any; } -interface SimpleDropdownMenuSeparatorProps { +interface SimpleDropdownMenuSeparatorProps extends React.HTMLAttributes { className?: string; - [key: string]: any; } // The root dropdown component @@ -58,7 +54,7 @@ const SimpleDropdownMenu: React.FC = ({ children }) => // Pass the open state and toggle function to the children if (child.type === SimpleDropdownMenuTrigger) { - return React.cloneElement(child as React.ReactElement, { + return React.cloneElement(child as React.ReactElement, { onClick: (e: React.MouseEvent) => { e.stopPropagation(); // Prevent event bubbling setIsOpen(!isOpen); @@ -123,14 +119,20 @@ const SimpleDropdownMenuTrigger: React.FC = ({ // The dropdown content container const SimpleDropdownMenuContent = React.forwardRef( ({ children, className, sideOffset = 4, ...props }, ref) => { + // Use sideOffset for positioning + const offsetStyles = { + marginTop: `${sideOffset}px` + }; + return (
{children} diff --git a/src/components/ui/SimpleLabel.tsx b/src/components/ui/Label.tsx similarity index 100% rename from src/components/ui/SimpleLabel.tsx rename to src/components/ui/Label.tsx diff --git a/src/components/ui/SimpleSlot.tsx b/src/components/ui/Slot.tsx similarity index 77% rename from src/components/ui/SimpleSlot.tsx rename to src/components/ui/Slot.tsx index cf335be..eed4f8c 100644 --- a/src/components/ui/SimpleSlot.tsx +++ b/src/components/ui/Slot.tsx @@ -2,11 +2,12 @@ import React from 'react'; // A simple Slot component that just renders its children // This is a simplified version that doesn't try to do ref forwarding -const Slot: React.FC<{ - children?: React.ReactNode; +interface SlotProps extends React.HTMLAttributes { + children?: React.ReactNode; className?: string; - [key: string]: any; -}> = ({ +} + +const Slot: React.FC = ({ children, ...props }) => { diff --git a/src/components/ui/SimpleTooltip.tsx b/src/components/ui/Tooltip.tsx similarity index 100% rename from src/components/ui/SimpleTooltip.tsx rename to src/components/ui/Tooltip.tsx diff --git a/src/features/email/api/emailApi.ts b/src/features/email/api/emailApi.ts index bbf84a4..0bb5c63 100644 --- a/src/features/email/api/emailApi.ts +++ b/src/features/email/api/emailApi.ts @@ -1,9 +1,9 @@ -import { Email } from "../../../types/emails"; +import { Email } from '../../../types/emails'; // Check if we should use mock implementation const shouldUseMock = () => { return ( - import.meta.env.VITE_MOCK_EMAIL_SENDING === 'true' || + import.meta.env.VITE_MOCK_EMAIL_SENDING === 'true' || typeof import.meta.env.VITE_MOCK_EMAIL_SENDING === 'undefined' ); }; @@ -11,15 +11,15 @@ const shouldUseMock = () => { // Mock implementation of sending email const mockSendEmail = async (email: Email) => { console.log('MOCK: Sending email with:', email); - + // Simulate network delay - await new Promise(resolve => setTimeout(resolve, 800)); - + await new Promise((resolve) => setTimeout(resolve, 800)); + // Return mock success response return { success: true, message: 'Email sent successfully (mock)', - id: `mock-email-${Date.now()}` + id: `mock-email-${Date.now()}`, }; }; @@ -29,7 +29,7 @@ export async function sendEmail(email: Email) { if (shouldUseMock()) { return mockSendEmail(email); } - + // Real implementation try { const response = await fetch('/api/email/send', { @@ -39,31 +39,31 @@ export async function sendEmail(email: Email) { }, body: JSON.stringify(email), }); - + if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || 'Failed to send email'); } - + return await response.json(); } catch (error) { - console.error("Error sending email:", error); + console.error('Error sending email:', error); throw error; } } // Mock implementation of sharing statements const mockShareStatements = async (recipientEmail: string) => { - console.log('MOCK: Sharing statements with:', recipientEmail); - + console.log('MOCK: Sharing statements from:', recipientEmail); + // Simulate network delay - await new Promise(resolve => setTimeout(resolve, 800)); - + await new Promise((resolve) => setTimeout(resolve, 800)); + // Return mock success response return { success: true, message: 'Statements shared successfully (mock)', - id: `mock-share-${Date.now()}` + id: `mock-share-${Date.now()}`, }; }; @@ -73,7 +73,7 @@ export async function shareStatements(recipientEmail: string) { if (shouldUseMock()) { return mockShareStatements(recipientEmail); } - + // Real implementation try { const response = await fetch('/api/email/share-statements', { @@ -83,15 +83,15 @@ export async function shareStatements(recipientEmail: string) { }, body: JSON.stringify({ recipientEmail }), }); - + if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.message || 'Failed to share statements'); } - + return await response.json(); } catch (error) { - console.error("Error sharing statements:", error); + console.error('Error sharing statements:', error); throw error; } -} \ No newline at end of file +} diff --git a/src/features/statements/components/ActionLine.tsx b/src/features/statements/components/ActionLine.tsx index 293b683..0d5ee05 100644 --- a/src/features/statements/components/ActionLine.tsx +++ b/src/features/statements/components/ActionLine.tsx @@ -13,7 +13,7 @@ import { SimpleDropdownMenuContent as DropdownMenuContent, SimpleDropdownMenuItem as DropdownMenuItem, SimpleDropdownMenuSeparator as DropdownMenuSeparator, -} from '../../../components/ui/SimpleDropdown'; +} from '../../../components/ui/Dropdown'; import ActionForm from './ActionForm'; import { ConfirmationDialog } from '../../../components/ui/ConfirmationDialog'; import type { Action } from '../../../types/entries'; @@ -253,16 +253,24 @@ const ActionLine: React.FC = ({ {!action.gratitude?.sent && ( <> -
+
{ if (hasManagerEmail) { setGratitudeModal({ isOpen: true, action }); } }} - className={hasManagerEmail ? "text-pink-600" : "text-pink-300 cursor-not-allowed"} + className={ + hasManagerEmail + ? 'text-pink-600' + : 'text-pink-300 cursor-not-allowed' + } disabled={!hasManagerEmail} - title={!hasManagerEmail ? "Manager's email is required to send gratitude" : ""} + title={ + !hasManagerEmail + ? "Manager's email is required to send gratitude" + : '' + } > Send gratitude diff --git a/src/features/statements/components/StatementItem.tsx b/src/features/statements/components/StatementItem.tsx index 6668de1..8a7c38d 100644 --- a/src/features/statements/components/StatementItem.tsx +++ b/src/features/statements/components/StatementItem.tsx @@ -19,7 +19,7 @@ import { SimpleDropdownMenuTrigger as DropdownMenuTrigger, SimpleDropdownMenuContent as DropdownMenuContent, SimpleDropdownMenuItem as DropdownMenuItem, -} from '@/components/ui/SimpleDropdown'; +} from '@/components/ui/Dropdown'; import ActionsCounter from './ActionsCounter'; import ActionLine from './ActionLine'; import { diff --git a/src/features/wizard/components/EditStatementModal.tsx b/src/features/wizard/components/EditStatementModal.tsx index 0bcf58a..f9dc6d7 100644 --- a/src/features/wizard/components/EditStatementModal.tsx +++ b/src/features/wizard/components/EditStatementModal.tsx @@ -4,7 +4,7 @@ import { SimpleDialogContent as DialogContent, SimpleDialogTitle as DialogTitle, SimpleDialogDescription as DialogDescription, -} from '@/components/ui/SimpleDialog'; +} from '@/components/ui/Dialog'; import { Button } from '@/components/ui/Button'; import type { Entry } from '@/types/entries'; import { SubjectStep } from './steps/SubjectStep'; @@ -77,7 +77,7 @@ export const EditStatementModal: React.FC = ({ // Create a completely new object with a deeper clone to ensure React detects the change // Force category to be a string to avoid type issues const categoryValue = localValue ? String(localValue) : ''; - + // Create a new object with the modified category const newStatement = { ...statement, @@ -86,7 +86,7 @@ export const EditStatementModal: React.FC = ({ _needsScroll: true, // Flag to indicate this needs scrolling category: categoryValue, }; - + // Deep clone to ensure all references are fresh updatedStatement = JSON.parse(JSON.stringify(newStatement)); diff --git a/src/features/wizard/components/StatementWizard.tsx b/src/features/wizard/components/StatementWizard.tsx index b274268..700a8ad 100644 --- a/src/features/wizard/components/StatementWizard.tsx +++ b/src/features/wizard/components/StatementWizard.tsx @@ -6,7 +6,7 @@ import { SimpleDialogContent as DialogContent, SimpleDialogDescription as DialogDescription, SimpleDialogTitle as DialogTitle, -} from '@/components/ui/SimpleDialog'; +} from '@/components/ui/Dialog'; import { AnimatePresence, motion } from 'framer-motion'; import { useEntries } from '@/features/statements/hooks/useEntries'; import { postNewEntry } from '@/features/statements/api/entriesApi'; @@ -82,7 +82,7 @@ const StatementWizard: React.FC = ({ presetId: presetQuestion.id, })); } else { - // For custom statements, set default category to "uncategorised" + // For custom statements, set default category to "uncategorised" // but still show the category screen first setSelection((prev) => ({ ...prev, @@ -313,7 +313,7 @@ const StatementWizard: React.FC = ({ )} Wizard Steps Wizard Steps - + {/* Scrollable Content Area */}
@@ -328,7 +328,7 @@ const StatementWizard: React.FC = ({
- + {/* Bottom Section - Always Visible */}
{/* Navigation Panel */} From 8296302c2431b49ade77101c9d243db7815a3445 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 2 Apr 2025 12:33:55 +0100 Subject: [PATCH 12/35] chore: reorganize folder structure for better code organization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create feature-specific folder structure for help, auth, questions, statements, and wizard - Move UI component files to their corresponding feature folders - Create index.ts barrel files for cleaner imports - Update import paths in affected files - Fix TypeScript interface definitions in Dropdown component - Ensure proper file organization following feature-based architecture 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/App.tsx | 11 +++-- .../layout}/Footer.tsx | 0 .../layout}/Header.tsx | 10 ++--- .../layout}/MainPage.tsx | 14 +++--- src/components/layout/index.ts | 10 +++++ src/components/modals/index.ts | 12 +++++ src/components/ui/Dropdown.tsx | 3 ++ src/components/ui/index.ts | 44 +++++++++++++++++++ src/features/auth/api/hooks/useAuth.ts | 2 +- src/features/auth/components/LoginPage.tsx | 2 +- .../auth/{ => context}/AuthContext.ts | 2 +- .../auth/{ => context}/AuthProvider.tsx | 2 +- src/features/auth/index.ts | 20 +++++++++ src/features/auth/{ => utils}/authUtils.ts | 2 +- .../help/components}/HelpButton.tsx | 0 .../help/components}/HelpCenter.tsx | 2 +- .../help/components}/WelcomePanel.tsx | 0 src/features/help/components/index.ts | 3 ++ .../help/context}/HelpContext.ts | 0 .../help/context}/HelpProvider.tsx | 10 ++--- .../help}/hooks/index.ts | 0 .../help}/hooks/useHelp.ts | 2 +- .../ui/helpCenter => features/help}/index.ts | 8 ++-- .../questions/context}/QuestionsContext.ts | 0 .../questions/context}/QuestionsProvider.tsx | 0 src/features/questions/hooks/useQuestions.ts | 2 +- src/features/questions/index.ts | 14 ++++++ src/features/statements/components/index.ts | 7 +++ src/features/statements/index.ts | 3 ++ src/features/wizard/components/index.ts | 10 +++++ src/features/wizard/components/steps/index.ts | 7 +++ src/features/wizard/index.ts | 2 + 32 files changed, 167 insertions(+), 37 deletions(-) rename src/{layouts/components => components/layout}/Footer.tsx (100%) rename src/{layouts/components => components/layout}/Header.tsx (85%) rename src/{layouts/components => components/layout}/MainPage.tsx (88%) create mode 100644 src/components/layout/index.ts create mode 100644 src/components/modals/index.ts create mode 100644 src/components/ui/index.ts rename src/features/auth/{ => context}/AuthContext.ts (95%) rename src/features/auth/{ => context}/AuthProvider.tsx (99%) create mode 100644 src/features/auth/index.ts rename src/features/auth/{ => utils}/authUtils.ts (96%) rename src/{components/ui/helpCenter => features/help/components}/HelpButton.tsx (100%) rename src/{components/ui/helpCenter => features/help/components}/HelpCenter.tsx (99%) rename src/{components/ui/helpCenter => features/help/components}/WelcomePanel.tsx (100%) create mode 100644 src/features/help/components/index.ts rename src/{components/ui/helpCenter => features/help/context}/HelpContext.ts (100%) rename src/{components/ui/helpCenter => features/help/context}/HelpProvider.tsx (92%) rename src/{components/ui/helpCenter => features/help}/hooks/index.ts (100%) rename src/{components/ui/helpCenter => features/help}/hooks/useHelp.ts (81%) rename src/{components/ui/helpCenter => features/help}/index.ts (53%) rename src/{providers => features/questions/context}/QuestionsContext.ts (100%) rename src/{providers => features/questions/context}/QuestionsProvider.tsx (100%) create mode 100644 src/features/questions/index.ts create mode 100644 src/features/statements/components/index.ts create mode 100644 src/features/statements/index.ts create mode 100644 src/features/wizard/components/index.ts create mode 100644 src/features/wizard/components/steps/index.ts create mode 100644 src/features/wizard/index.ts diff --git a/src/App.tsx b/src/App.tsx index d416e5d..11a64ab 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,21 +4,20 @@ import React, { useEffect } from 'react'; import { TooltipProvider } from './components/ui/BetterTooltip'; // Providers -import { AuthProvider } from './features/auth/AuthProvider'; +import { AuthProvider } from './features/auth/context/AuthProvider'; import { EntriesProvider } from './features/statements/context/EntriesProvider'; -import { QuestionsProvider } from './providers/QuestionsProvider'; -import { HelpProvider } from './components/ui/helpCenter'; +import { QuestionsProvider } from './features/questions/context/QuestionsProvider'; +import { HelpProvider } from './features/help'; // Components import LoginPage from './features/auth/components/LoginPage'; -import Header from './layouts/components/Header'; -import MainPage from './layouts/components/MainPage'; +import { Header, MainPage } from './components/layout'; import MockNotification from './features/auth/components/MockNotification'; // Hooks and Utilities import { useEntries } from './features/statements/hooks/useEntries'; import { useAuth } from './features/auth/api/hooks'; -import { handleMagicLinkVerification } from './features/auth/authUtils'; +import { handleMagicLinkVerification } from './features/auth/utils/authUtils'; // Outer Component: Responsible only for setting up the environment (the providers) for the rest of the app. const AppContent: React.FC = () => { diff --git a/src/layouts/components/Footer.tsx b/src/components/layout/Footer.tsx similarity index 100% rename from src/layouts/components/Footer.tsx rename to src/components/layout/Footer.tsx diff --git a/src/layouts/components/Header.tsx b/src/components/layout/Header.tsx similarity index 85% rename from src/layouts/components/Header.tsx rename to src/components/layout/Header.tsx index 920c2ab..9f4469c 100644 --- a/src/layouts/components/Header.tsx +++ b/src/components/layout/Header.tsx @@ -1,9 +1,9 @@ -// src/components/Header.tsx +// src/components/layout/Header.tsx import React, { useState } from 'react'; -import { useEntries } from '../../features/statements/hooks/useEntries'; -import SmallCircularQuestionCounter from '../../components/ui/questionCounter/SmallCircularQuestionCounter'; -import UserDataModal from '../../components/modals/UserDataModal'; -// import { Tooltip, TooltipTrigger, TooltipContent } from '../../components/ui/better-tooltip'; +import { useEntries } from '@/features/statements'; +import { SmallCircularQuestionCounter } from '@/components/ui'; +import { UserDataModal } from '@/components/modals'; +// import { Tooltip, TooltipTrigger, TooltipContent } from '@/components/ui'; const Header: React.FC = () => { const { data } = useEntries(); diff --git a/src/layouts/components/MainPage.tsx b/src/components/layout/MainPage.tsx similarity index 88% rename from src/layouts/components/MainPage.tsx rename to src/components/layout/MainPage.tsx index ee23246..2412857 100644 --- a/src/layouts/components/MainPage.tsx +++ b/src/components/layout/MainPage.tsx @@ -5,14 +5,14 @@ import { Tooltip, TooltipTrigger, TooltipContent, -} from '../../components/ui/BetterTooltip'; -import StatementList from '../../features/statements/components/StatementList'; -import { useEntries } from '../../features/statements/hooks/useEntries'; -import { Button } from '../../components/ui/Button'; + Button +} from '@/components/ui'; +import { StatementList } from '@/features/statements/components'; +import { useEntries } from '@/features/statements'; import { Mail } from 'lucide-react'; -import StatementWizard from '../../features/wizard/components/StatementWizard'; -import ShareEmailModal from '../../components/modals/ShareEmailModal'; -// import TestStatementButton from '../../components/debug/TestButton'; +import { StatementWizard } from '@/features/wizard'; +import { ShareEmailModal } from '@/components/modals'; +// import TestStatementButton from '@/components/debug/TestButton'; import Footer from './Footer'; const MainPage: React.FC = () => { diff --git a/src/components/layout/index.ts b/src/components/layout/index.ts new file mode 100644 index 0000000..3b46c39 --- /dev/null +++ b/src/components/layout/index.ts @@ -0,0 +1,10 @@ +/** + * Layout Components Module + * + * Provides the main structural components for page layout, + * including the overall app container, header, and footer. + */ + +export { default as Header } from './Header'; +export { default as Footer } from './Footer'; +export { default as MainPage } from './MainPage'; \ No newline at end of file diff --git a/src/components/modals/index.ts b/src/components/modals/index.ts new file mode 100644 index 0000000..45dfe8e --- /dev/null +++ b/src/components/modals/index.ts @@ -0,0 +1,12 @@ +/** + * Modal Components Module + * + * Provides reusable modal dialog components for various purposes + * throughout the application. + */ + +export { default as GratitudeModal } from './GratitudeModal'; +export { default as PrivacyModal } from './PrivacyModal'; +export { default as ShareEmailModal } from './ShareEmailModal'; +export { default as TermsModal } from './TermsModal'; +export { default as UserDataModal } from './UserDataModal'; \ No newline at end of file diff --git a/src/components/ui/Dropdown.tsx b/src/components/ui/Dropdown.tsx index 329aff0..4b05374 100644 --- a/src/components/ui/Dropdown.tsx +++ b/src/components/ui/Dropdown.tsx @@ -16,12 +16,15 @@ interface SimpleDropdownMenuContentProps extends React.HTMLAttributes { children: React.ReactNode; className?: string; onClick?: (e: React.MouseEvent) => void; + disabled?: boolean; + title?: string; } interface SimpleDropdownMenuSeparatorProps extends React.HTMLAttributes { diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts new file mode 100644 index 0000000..356b928 --- /dev/null +++ b/src/components/ui/index.ts @@ -0,0 +1,44 @@ +/** + * UI Components Module + * + * Provides reusable UI components that can be used across the application. + * These components are the building blocks for more complex components. + */ + +// Export individual UI components +export { Button } from './Button'; +export { Input } from './Input'; +export { Slot } from './Slot'; +export { ConfirmationDialog } from './ConfirmationDialog'; + +// Export dialog components +export { + SimpleDialog, + SimpleDialogContent, + SimpleDialogTitle, + SimpleDialogDescription, + SimpleDialogFooter, + SimpleDialogHeader +} from './Dialog'; + +// Export dropdown components +export { + SimpleDropdownMenu, + SimpleDropdownMenuTrigger, + SimpleDropdownMenuContent, + SimpleDropdownMenuItem, + SimpleDropdownMenuSeparator +} from './Dropdown'; + +// Export tooltip components +export { + Tooltip, + TooltipTrigger, + TooltipContent, + TooltipProvider +} from './BetterTooltip'; + +// Export question counter components +export { default as QuestionCounter } from './questionCounter/QuestionCounter'; +export { default as LargeCircularQuestionCounter } from './questionCounter/LargeCircularQuestionCounter'; +export { default as SmallCircularQuestionCounter } from './questionCounter/SmallCircularQuestionCounter'; \ No newline at end of file diff --git a/src/features/auth/api/hooks/useAuth.ts b/src/features/auth/api/hooks/useAuth.ts index ebd2031..66815d4 100644 --- a/src/features/auth/api/hooks/useAuth.ts +++ b/src/features/auth/api/hooks/useAuth.ts @@ -1,5 +1,5 @@ import { useContext } from 'react'; -import { AuthContext } from '../../AuthContext'; +import { AuthContext } from '../../context/AuthContext'; export const useAuth = () => { const context = useContext(AuthContext); diff --git a/src/features/auth/components/LoginPage.tsx b/src/features/auth/components/LoginPage.tsx index 7822c4f..a7b9e71 100644 --- a/src/features/auth/components/LoginPage.tsx +++ b/src/features/auth/components/LoginPage.tsx @@ -6,7 +6,7 @@ import { useEntries } from '../../statements/hooks/useEntries'; import MagicLinkForm from './MagicLinkForm'; import { Input } from '../../../components/ui/input'; import { Button } from '../../../components/ui/button'; -import { handleMagicLinkVerification } from '../authUtils'; +import { handleMagicLinkVerification } from '../utils/authUtils'; import { Loader2 } from 'lucide-react'; import PrivacyModal from '../../../components/modals/PrivacyModal'; import TermsModal from '../../../components/modals/TermsModal'; diff --git a/src/features/auth/AuthContext.ts b/src/features/auth/context/AuthContext.ts similarity index 95% rename from src/features/auth/AuthContext.ts rename to src/features/auth/context/AuthContext.ts index 7410e25..707c020 100644 --- a/src/features/auth/AuthContext.ts +++ b/src/features/auth/context/AuthContext.ts @@ -1,5 +1,5 @@ import { createContext } from 'react'; -import { AuthState } from './api/authApi'; +import { AuthState } from '../api/authApi'; // Initial auth state export const initialAuthState: AuthState = { diff --git a/src/features/auth/AuthProvider.tsx b/src/features/auth/context/AuthProvider.tsx similarity index 99% rename from src/features/auth/AuthProvider.tsx rename to src/features/auth/context/AuthProvider.tsx index 8fec6c3..f925166 100644 --- a/src/features/auth/AuthProvider.tsx +++ b/src/features/auth/context/AuthProvider.tsx @@ -5,7 +5,7 @@ import { requestMagicLink as apiRequestMagicLink, signOut as apiSignOut, updateUserProfile -} from './api/authApi'; +} from '../api/authApi'; type AuthAction = | { type: 'AUTH_LOADING' } diff --git a/src/features/auth/index.ts b/src/features/auth/index.ts new file mode 100644 index 0000000..6f333cd --- /dev/null +++ b/src/features/auth/index.ts @@ -0,0 +1,20 @@ +/** + * Auth Feature Module + * + * Centralizes authentication-related functionality including + * context, providers, components, and utilities. + */ + +// Re-export context and provider +export { AuthContext } from './context/AuthContext'; +export { AuthProvider } from './context/AuthProvider'; + +// Re-export hooks +export { useAuth } from './api/hooks'; + +// Re-export utilities +export { handleMagicLinkVerification } from './utils/authUtils'; + +// Re-export components as needed +export { default as LoginPage } from './components/LoginPage'; +export { default as MagicLinkForm } from './components/MagicLinkForm'; \ No newline at end of file diff --git a/src/features/auth/authUtils.ts b/src/features/auth/utils/authUtils.ts similarity index 96% rename from src/features/auth/authUtils.ts rename to src/features/auth/utils/authUtils.ts index 5fd3bff..585bc20 100644 --- a/src/features/auth/authUtils.ts +++ b/src/features/auth/utils/authUtils.ts @@ -1,4 +1,4 @@ -import { verifyMagicLink } from './api/authApi'; +import { verifyMagicLink } from '../api/authApi'; /** * Extract and verify magic link token from URL diff --git a/src/components/ui/helpCenter/HelpButton.tsx b/src/features/help/components/HelpButton.tsx similarity index 100% rename from src/components/ui/helpCenter/HelpButton.tsx rename to src/features/help/components/HelpButton.tsx diff --git a/src/components/ui/helpCenter/HelpCenter.tsx b/src/features/help/components/HelpCenter.tsx similarity index 99% rename from src/components/ui/helpCenter/HelpCenter.tsx rename to src/features/help/components/HelpCenter.tsx index 7d09ede..9f108fd 100644 --- a/src/components/ui/helpCenter/HelpCenter.tsx +++ b/src/features/help/components/HelpCenter.tsx @@ -313,4 +313,4 @@ const HelpCenter: React.FC = ({ ); }; -export default HelpCenter; +export default HelpCenter; \ No newline at end of file diff --git a/src/components/ui/helpCenter/WelcomePanel.tsx b/src/features/help/components/WelcomePanel.tsx similarity index 100% rename from src/components/ui/helpCenter/WelcomePanel.tsx rename to src/features/help/components/WelcomePanel.tsx diff --git a/src/features/help/components/index.ts b/src/features/help/components/index.ts new file mode 100644 index 0000000..3ab2076 --- /dev/null +++ b/src/features/help/components/index.ts @@ -0,0 +1,3 @@ +export { default as HelpButton } from './HelpButton'; +export { default as HelpCenter } from './HelpCenter'; +export { default as WelcomePanel } from './WelcomePanel'; \ No newline at end of file diff --git a/src/components/ui/helpCenter/HelpContext.ts b/src/features/help/context/HelpContext.ts similarity index 100% rename from src/components/ui/helpCenter/HelpContext.ts rename to src/features/help/context/HelpContext.ts diff --git a/src/components/ui/helpCenter/HelpProvider.tsx b/src/features/help/context/HelpProvider.tsx similarity index 92% rename from src/components/ui/helpCenter/HelpProvider.tsx rename to src/features/help/context/HelpProvider.tsx index 0a4bc07..01bbde3 100644 --- a/src/components/ui/helpCenter/HelpProvider.tsx +++ b/src/features/help/context/HelpProvider.tsx @@ -2,9 +2,9 @@ import React, { useState, useEffect } from 'react'; import { HelpContext } from './HelpContext'; -import WelcomePanel from './WelcomePanel'; -import HelpButton from './HelpButton'; -import HelpCenter from './HelpCenter'; +import WelcomePanel from '../components/WelcomePanel'; +import HelpButton from '../components/HelpButton'; +import HelpCenter from '../components/HelpCenter'; interface HelpProviderProps { children: React.ReactNode; @@ -78,6 +78,4 @@ export const HelpProvider: React.FC = ({ children }) => { )} ); -}; - -export default HelpProvider; \ No newline at end of file +}; \ No newline at end of file diff --git a/src/components/ui/helpCenter/hooks/index.ts b/src/features/help/hooks/index.ts similarity index 100% rename from src/components/ui/helpCenter/hooks/index.ts rename to src/features/help/hooks/index.ts diff --git a/src/components/ui/helpCenter/hooks/useHelp.ts b/src/features/help/hooks/useHelp.ts similarity index 81% rename from src/components/ui/helpCenter/hooks/useHelp.ts rename to src/features/help/hooks/useHelp.ts index 02cab8e..8f051e7 100644 --- a/src/components/ui/helpCenter/hooks/useHelp.ts +++ b/src/features/help/hooks/useHelp.ts @@ -1,7 +1,7 @@ 'use client'; import { useContext } from 'react'; -import { HelpContext } from '../HelpContext'; +import { HelpContext } from '../context/HelpContext'; export const useHelp = () => { const context = useContext(HelpContext); diff --git a/src/components/ui/helpCenter/index.ts b/src/features/help/index.ts similarity index 53% rename from src/components/ui/helpCenter/index.ts rename to src/features/help/index.ts index 8b07e87..dcf6103 100644 --- a/src/components/ui/helpCenter/index.ts +++ b/src/features/help/index.ts @@ -6,11 +6,9 @@ * without requiring consumers to know the internal file structure. * * Usage: - * import { HelpProvider, HelpButton, useHelp } from '@/components/ui/helpCenter'; + * import { HelpProvider, HelpButton, useHelp } from '@/features/help'; */ -export { default as HelpProvider } from './HelpProvider'; +export { HelpProvider } from './context/HelpProvider'; export { useHelp } from './hooks'; -export { default as HelpButton } from './HelpButton'; -export { default as HelpCenter } from './HelpCenter'; -export { default as WelcomePanel } from './WelcomePanel'; \ No newline at end of file +export { HelpButton, HelpCenter, WelcomePanel } from './components'; \ No newline at end of file diff --git a/src/providers/QuestionsContext.ts b/src/features/questions/context/QuestionsContext.ts similarity index 100% rename from src/providers/QuestionsContext.ts rename to src/features/questions/context/QuestionsContext.ts diff --git a/src/providers/QuestionsProvider.tsx b/src/features/questions/context/QuestionsProvider.tsx similarity index 100% rename from src/providers/QuestionsProvider.tsx rename to src/features/questions/context/QuestionsProvider.tsx diff --git a/src/features/questions/hooks/useQuestions.ts b/src/features/questions/hooks/useQuestions.ts index 02ce37c..0505e16 100644 --- a/src/features/questions/hooks/useQuestions.ts +++ b/src/features/questions/hooks/useQuestions.ts @@ -1,5 +1,5 @@ import { useContext } from 'react'; -import { QuestionsContext } from '../../../providers/QuestionsContext'; +import { QuestionsContext } from '../context/QuestionsContext'; export function useQuestions() { const context = useContext(QuestionsContext); diff --git a/src/features/questions/index.ts b/src/features/questions/index.ts new file mode 100644 index 0000000..f9bbcde --- /dev/null +++ b/src/features/questions/index.ts @@ -0,0 +1,14 @@ +/** + * Questions Feature Module + * + * Centralizes questions-related functionality including context, + * providers, hooks, and components. + */ + +// Re-export context and provider +export { QuestionsContext } from './context/QuestionsContext'; +export { QuestionsProvider } from './context/QuestionsProvider'; + +// Re-export hooks +export { useQuestions } from './hooks/useQuestions'; +export { useAnsweredCount } from './hooks/useAnsweredCount'; \ No newline at end of file diff --git a/src/features/statements/components/index.ts b/src/features/statements/components/index.ts new file mode 100644 index 0000000..35684c1 --- /dev/null +++ b/src/features/statements/components/index.ts @@ -0,0 +1,7 @@ +// Barrel file for statements components +export { default as ActionForm } from './ActionForm'; +export { default as ActionLine } from './ActionLine'; +export { default as ActionsCounter } from './ActionsCounter'; +export { default as QuestionCard } from './QuestionCard'; +export { default as StatementItem } from './StatementItem'; +export { default as StatementList } from './StatementList'; \ No newline at end of file diff --git a/src/features/statements/index.ts b/src/features/statements/index.ts new file mode 100644 index 0000000..22b1efe --- /dev/null +++ b/src/features/statements/index.ts @@ -0,0 +1,3 @@ +// Barrel file for statements feature exports +export { useEntries } from './hooks/useEntries'; +export { EntriesProvider } from './context/EntriesProvider'; \ No newline at end of file diff --git a/src/features/wizard/components/index.ts b/src/features/wizard/components/index.ts new file mode 100644 index 0000000..68d4534 --- /dev/null +++ b/src/features/wizard/components/index.ts @@ -0,0 +1,10 @@ +// Barrel file for wizard components +export { default as StatementWizard } from './StatementWizard'; +export { default as StatementPreview } from './StatementPreview'; +export { EditStatementModal } from './EditStatementModal'; +export { default as FilterBar } from './FilterBar'; +export { default as SentimentVerbPicker } from './SentimentVerbPicker'; +export { default as StepContainer } from './StepContainer'; +export { default as SubjectTiles } from './SubjectTiles'; +export { default as VerbGrid } from './VerbGrid'; +export { default as VerbSelector } from './VerbSelector'; \ No newline at end of file diff --git a/src/features/wizard/components/steps/index.ts b/src/features/wizard/components/steps/index.ts new file mode 100644 index 0000000..6d4f9e4 --- /dev/null +++ b/src/features/wizard/components/steps/index.ts @@ -0,0 +1,7 @@ +// Barrel file for wizard step components +export { CategoryStep } from './CategoryStep'; +export { ComplementStep } from './ComplementStep'; +export { ObjectStep } from './ObjectStep'; +export { PrivacyStep } from './PrivacyStep'; +export { SubjectStep } from './SubjectStep'; +export { VerbStep } from './VerbStep'; \ No newline at end of file diff --git a/src/features/wizard/index.ts b/src/features/wizard/index.ts new file mode 100644 index 0000000..b567bd6 --- /dev/null +++ b/src/features/wizard/index.ts @@ -0,0 +1,2 @@ +// Barrel file for wizard feature exports +export { default as StatementWizard } from './components/StatementWizard'; \ No newline at end of file From 2cf8d027daf774a38786bd9c6d5682be48e54159 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 2 Apr 2025 12:37:55 +0100 Subject: [PATCH 13/35] refactor: move ProgressWithFeedback to UI root folder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Relocate ProgressWithFeedback from progress subfolder to the UI components directory - Update imports in UserDataModal to use the new path - Update barrel file to export ProgressWithFeedback directly - Remove unnecessary nested folder structure 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/components/modals/UserDataModal.tsx | 11 +++++------ .../ui/{progress => }/ProgressWithFeedback.tsx | 2 +- src/components/ui/index.ts | 5 ++++- 3 files changed, 10 insertions(+), 8 deletions(-) rename src/components/ui/{progress => }/ProgressWithFeedback.tsx (91%) diff --git a/src/components/modals/UserDataModal.tsx b/src/components/modals/UserDataModal.tsx index 7a0e9c6..930fef1 100644 --- a/src/components/modals/UserDataModal.tsx +++ b/src/components/modals/UserDataModal.tsx @@ -1,13 +1,12 @@ 'use client'; import React, { useState, useEffect, useRef } from 'react'; -import { useEntries } from '../../features/statements/hooks/useEntries'; -import { useAuth } from '../../features/auth/api/hooks'; -import { Button } from '../ui/button'; +import { useEntries } from '@/features/statements'; +import { useAuth } from '@/features/auth/api/hooks'; +import { Button } from '@/components/ui/Button'; import { Save, X, User, Mail, Award, Edit2, LogOut } from 'lucide-react'; -import { validateEmail } from '../../lib/utils/validateEmail'; -import QuestionCounter from '../ui/questionCounter/QuestionCounter'; -import ProgressWithFeedback from '../ui/progress/ProgressWithFeedback'; +import { validateEmail } from '@/lib/utils/validateEmail'; +import { QuestionCounter, ProgressWithFeedback } from '@/components/ui'; interface UserDataModalProps { onOpenChange: (open: boolean) => void; diff --git a/src/components/ui/progress/ProgressWithFeedback.tsx b/src/components/ui/ProgressWithFeedback.tsx similarity index 91% rename from src/components/ui/progress/ProgressWithFeedback.tsx rename to src/components/ui/ProgressWithFeedback.tsx index 2d8c950..8cb4499 100644 --- a/src/components/ui/progress/ProgressWithFeedback.tsx +++ b/src/components/ui/ProgressWithFeedback.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { useAnsweredCount } from '@/features/questions/hooks/useAnsweredCount'; import { useProgressFeedback } from '@/hooks/useProgressFeedback'; -import LargeCircularQuestionCounter from '../questionCounter/LargeCircularQuestionCounter'; +import LargeCircularQuestionCounter from './questionCounter/LargeCircularQuestionCounter'; const ProgressWithFeedback: React.FC = () => { const { answered, total } = useAnsweredCount(); diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index 356b928..6b60c2a 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -41,4 +41,7 @@ export { // Export question counter components export { default as QuestionCounter } from './questionCounter/QuestionCounter'; export { default as LargeCircularQuestionCounter } from './questionCounter/LargeCircularQuestionCounter'; -export { default as SmallCircularQuestionCounter } from './questionCounter/SmallCircularQuestionCounter'; \ No newline at end of file +export { default as SmallCircularQuestionCounter } from './questionCounter/SmallCircularQuestionCounter'; + +// Export progress component +export { default as ProgressWithFeedback } from './ProgressWithFeedback'; \ No newline at end of file From a01a5b2a97bedd62765ce5ccf6de69df84302476 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 2 Apr 2025 12:45:53 +0100 Subject: [PATCH 14/35] refactor: create dedicated progress feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create new progress feature folder structure for better organization - Move ProgressWithFeedback component from UI to progress/components - Move useProgressFeedback hook from general hooks to progress/hooks - Create barrel files for cleaner imports and exports - Update import paths in affected files - Fix import path for shareStatements in ShareEmailModal 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/components/modals/GratitudeModal.tsx | 2 +- src/components/modals/ShareEmailModal.tsx | 10 +++++----- src/components/modals/UserDataModal.tsx | 3 ++- src/components/ui/index.ts | 5 +---- .../api/{gratitudeApi.ts => emailGratitudeApi.ts} | 0 .../email/api/{emailApi.ts => emailStatementsApi.ts} | 0 .../progress/components}/ProgressWithFeedback.tsx | 4 ++-- src/features/progress/components/index.ts | 1 + src/features/progress/hooks/index.ts | 1 + .../progress}/hooks/useProgressFeedback.ts | 0 src/features/progress/index.ts | 9 +++++++++ src/features/statements/components/ActionLine.tsx | 2 +- 12 files changed, 23 insertions(+), 14 deletions(-) rename src/features/email/api/{gratitudeApi.ts => emailGratitudeApi.ts} (100%) rename src/features/email/api/{emailApi.ts => emailStatementsApi.ts} (100%) rename src/{components/ui => features/progress/components}/ProgressWithFeedback.tsx (84%) create mode 100644 src/features/progress/components/index.ts create mode 100644 src/features/progress/hooks/index.ts rename src/{ => features/progress}/hooks/useProgressFeedback.ts (100%) create mode 100644 src/features/progress/index.ts diff --git a/src/components/modals/GratitudeModal.tsx b/src/components/modals/GratitudeModal.tsx index 01fbd27..7f2a6a7 100644 --- a/src/components/modals/GratitudeModal.tsx +++ b/src/components/modals/GratitudeModal.tsx @@ -8,7 +8,7 @@ import { } from '../ui/Dialog'; import { Button } from '../ui/Button'; import { Loader2, Heart } from 'lucide-react'; -import { sendGratitude } from '../../features/email/api/gratitudeApi'; +import { sendGratitude } from '../../features/email/api/emailGratitudeApi'; import { useEntries } from '../../features/statements/hooks/useEntries'; import { Action } from '../../types/entries'; diff --git a/src/components/modals/ShareEmailModal.tsx b/src/components/modals/ShareEmailModal.tsx index 9857152..9ed8988 100644 --- a/src/components/modals/ShareEmailModal.tsx +++ b/src/components/modals/ShareEmailModal.tsx @@ -5,12 +5,12 @@ import { SimpleDialog as Dialog, SimpleDialogContent as DialogContent, SimpleDialogDescription as DialogDescription, -} from '../ui/Dialog'; -import { Button } from '../ui/Button'; -import { useEntries } from '../../features/statements/hooks/useEntries'; -import { shareStatements } from '../../features/email/api/emailApi'; +} from '@/components/ui/Dialog'; +import { Button } from '@/components/ui/Button'; +import { useEntries } from '@/features/statements'; +import { shareStatements } from '@/features/email/api/emailStatementsApi'; import { Loader2 } from 'lucide-react'; -import { getVerbName } from '../../lib/utils/verbUtils'; +import { getVerbName } from '@/lib/utils/verbUtils'; import PrivacyModal from './PrivacyModal'; const ShareEmailModal: React.FC<{ onClose: () => void }> = ({ onClose }) => { diff --git a/src/components/modals/UserDataModal.tsx b/src/components/modals/UserDataModal.tsx index 930fef1..22af170 100644 --- a/src/components/modals/UserDataModal.tsx +++ b/src/components/modals/UserDataModal.tsx @@ -6,7 +6,8 @@ import { useAuth } from '@/features/auth/api/hooks'; import { Button } from '@/components/ui/Button'; import { Save, X, User, Mail, Award, Edit2, LogOut } from 'lucide-react'; import { validateEmail } from '@/lib/utils/validateEmail'; -import { QuestionCounter, ProgressWithFeedback } from '@/components/ui'; +import { QuestionCounter } from '@/components/ui'; +import { ProgressWithFeedback } from '@/features/progress'; interface UserDataModalProps { onOpenChange: (open: boolean) => void; diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index 6b60c2a..356b928 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -41,7 +41,4 @@ export { // Export question counter components export { default as QuestionCounter } from './questionCounter/QuestionCounter'; export { default as LargeCircularQuestionCounter } from './questionCounter/LargeCircularQuestionCounter'; -export { default as SmallCircularQuestionCounter } from './questionCounter/SmallCircularQuestionCounter'; - -// Export progress component -export { default as ProgressWithFeedback } from './ProgressWithFeedback'; \ No newline at end of file +export { default as SmallCircularQuestionCounter } from './questionCounter/SmallCircularQuestionCounter'; \ No newline at end of file diff --git a/src/features/email/api/gratitudeApi.ts b/src/features/email/api/emailGratitudeApi.ts similarity index 100% rename from src/features/email/api/gratitudeApi.ts rename to src/features/email/api/emailGratitudeApi.ts diff --git a/src/features/email/api/emailApi.ts b/src/features/email/api/emailStatementsApi.ts similarity index 100% rename from src/features/email/api/emailApi.ts rename to src/features/email/api/emailStatementsApi.ts diff --git a/src/components/ui/ProgressWithFeedback.tsx b/src/features/progress/components/ProgressWithFeedback.tsx similarity index 84% rename from src/components/ui/ProgressWithFeedback.tsx rename to src/features/progress/components/ProgressWithFeedback.tsx index 8cb4499..895afe4 100644 --- a/src/components/ui/ProgressWithFeedback.tsx +++ b/src/features/progress/components/ProgressWithFeedback.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { useAnsweredCount } from '@/features/questions/hooks/useAnsweredCount'; -import { useProgressFeedback } from '@/hooks/useProgressFeedback'; -import LargeCircularQuestionCounter from './questionCounter/LargeCircularQuestionCounter'; +import { useProgressFeedback } from '../hooks/useProgressFeedback'; +import { LargeCircularQuestionCounter } from '@/components/ui'; const ProgressWithFeedback: React.FC = () => { const { answered, total } = useAnsweredCount(); diff --git a/src/features/progress/components/index.ts b/src/features/progress/components/index.ts new file mode 100644 index 0000000..c681ed4 --- /dev/null +++ b/src/features/progress/components/index.ts @@ -0,0 +1 @@ +export { default as ProgressWithFeedback } from './ProgressWithFeedback'; diff --git a/src/features/progress/hooks/index.ts b/src/features/progress/hooks/index.ts new file mode 100644 index 0000000..8efe8de --- /dev/null +++ b/src/features/progress/hooks/index.ts @@ -0,0 +1 @@ +export { useProgressFeedback } from './useProgressFeedback'; diff --git a/src/hooks/useProgressFeedback.ts b/src/features/progress/hooks/useProgressFeedback.ts similarity index 100% rename from src/hooks/useProgressFeedback.ts rename to src/features/progress/hooks/useProgressFeedback.ts diff --git a/src/features/progress/index.ts b/src/features/progress/index.ts new file mode 100644 index 0000000..b33acce --- /dev/null +++ b/src/features/progress/index.ts @@ -0,0 +1,9 @@ +/** + * Progress Feature Module + * + * Provides functionality for tracking and displaying user progress + * throughout the application. + */ + +export { useProgressFeedback } from './hooks'; +export { ProgressWithFeedback } from './components'; diff --git a/src/features/statements/components/ActionLine.tsx b/src/features/statements/components/ActionLine.tsx index 0d5ee05..d7cd4fa 100644 --- a/src/features/statements/components/ActionLine.tsx +++ b/src/features/statements/components/ActionLine.tsx @@ -19,7 +19,7 @@ import { ConfirmationDialog } from '../../../components/ui/ConfirmationDialog'; import type { Action } from '../../../types/entries'; import { CheckCircle2, XCircle } from 'lucide-react'; import GratitudeModal from '../../../components/modals/GratitudeModal'; -import { markGratitudeSent } from '../../../features/email/api/gratitudeApi'; +import { markGratitudeSent } from '../../email/api/emailGratitudeApi'; import { useEntries } from '../hooks/useEntries'; import { Tooltip, From f756ae054c8bb10629fc81a4f6b98bed5f753cbb Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 2 Apr 2025 13:03:50 +0100 Subject: [PATCH 15/35] refactor: remove unnecessary single-export barrel files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove barrel files with only a single export to reduce indirection - Update imports to point directly to source files - Keep barrel files that export from multiple subdirectories - Simplify codebase by reducing unnecessary abstraction layers 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- src/components/layout/MainPage.tsx | 2 +- src/components/layout/index.ts | 6 +++--- src/components/modals/UserDataModal.tsx | 2 +- src/components/modals/index.ts | 6 +++--- src/components/ui/index.ts | 6 +++--- src/features/auth/api/hooks/index.ts | 6 ++++++ src/features/auth/index.ts | 6 +++--- src/features/help/hooks/index.ts | 1 - src/features/help/index.ts | 12 ++++-------- src/features/progress/components/index.ts | 1 - src/features/progress/hooks/index.ts | 1 - src/features/progress/index.ts | 9 --------- src/features/questions/index.ts | 6 +++--- src/features/statements/index.ts | 7 ++++++- src/features/wizard/index.ts | 2 -- 15 files changed, 33 insertions(+), 40 deletions(-) delete mode 100644 src/features/help/hooks/index.ts delete mode 100644 src/features/progress/components/index.ts delete mode 100644 src/features/progress/hooks/index.ts delete mode 100644 src/features/progress/index.ts delete mode 100644 src/features/wizard/index.ts diff --git a/src/components/layout/MainPage.tsx b/src/components/layout/MainPage.tsx index 2412857..086cc24 100644 --- a/src/components/layout/MainPage.tsx +++ b/src/components/layout/MainPage.tsx @@ -10,7 +10,7 @@ import { import { StatementList } from '@/features/statements/components'; import { useEntries } from '@/features/statements'; import { Mail } from 'lucide-react'; -import { StatementWizard } from '@/features/wizard'; +import StatementWizard from '@/features/wizard/components/StatementWizard'; import { ShareEmailModal } from '@/components/modals'; // import TestStatementButton from '@/components/debug/TestButton'; import Footer from './Footer'; diff --git a/src/components/layout/index.ts b/src/components/layout/index.ts index 3b46c39..8cb505e 100644 --- a/src/components/layout/index.ts +++ b/src/components/layout/index.ts @@ -1,8 +1,8 @@ /** - * Layout Components Module + * Barrel file for layout components * - * Provides the main structural components for page layout, - * including the overall app container, header, and footer. + * Provides unified access to structural page components + * including header, footer, and main content containers. */ export { default as Header } from './Header'; diff --git a/src/components/modals/UserDataModal.tsx b/src/components/modals/UserDataModal.tsx index 22af170..9548d00 100644 --- a/src/components/modals/UserDataModal.tsx +++ b/src/components/modals/UserDataModal.tsx @@ -7,7 +7,7 @@ import { Button } from '@/components/ui/Button'; import { Save, X, User, Mail, Award, Edit2, LogOut } from 'lucide-react'; import { validateEmail } from '@/lib/utils/validateEmail'; import { QuestionCounter } from '@/components/ui'; -import { ProgressWithFeedback } from '@/features/progress'; +import ProgressWithFeedback from '@/features/progress/components/ProgressWithFeedback'; interface UserDataModalProps { onOpenChange: (open: boolean) => void; diff --git a/src/components/modals/index.ts b/src/components/modals/index.ts index 45dfe8e..e6e6b48 100644 --- a/src/components/modals/index.ts +++ b/src/components/modals/index.ts @@ -1,8 +1,8 @@ /** - * Modal Components Module + * Barrel file for modal components * - * Provides reusable modal dialog components for various purposes - * throughout the application. + * Provides unified access to modal dialog components + * for various purposes throughout the application. */ export { default as GratitudeModal } from './GratitudeModal'; diff --git a/src/components/ui/index.ts b/src/components/ui/index.ts index 356b928..41b89ba 100644 --- a/src/components/ui/index.ts +++ b/src/components/ui/index.ts @@ -1,8 +1,8 @@ /** - * UI Components Module + * Barrel file for UI components * - * Provides reusable UI components that can be used across the application. - * These components are the building blocks for more complex components. + * Provides unified access to reusable UI components + * that serve as building blocks across the application. */ // Export individual UI components diff --git a/src/features/auth/api/hooks/index.ts b/src/features/auth/api/hooks/index.ts index cb62303..f5feed4 100644 --- a/src/features/auth/api/hooks/index.ts +++ b/src/features/auth/api/hooks/index.ts @@ -1 +1,7 @@ +/** + * Barrel file for auth hooks exports + * + * Consolidates auth hook exports for cleaner imports. + */ + export * from './useAuth'; \ No newline at end of file diff --git a/src/features/auth/index.ts b/src/features/auth/index.ts index 6f333cd..a02a11a 100644 --- a/src/features/auth/index.ts +++ b/src/features/auth/index.ts @@ -1,8 +1,8 @@ /** - * Auth Feature Module + * Barrel file for auth feature * - * Centralizes authentication-related functionality including - * context, providers, components, and utilities. + * Provides unified access to authentication-related functionality + * including context, providers, hooks, and components. */ // Re-export context and provider diff --git a/src/features/help/hooks/index.ts b/src/features/help/hooks/index.ts deleted file mode 100644 index f03e754..0000000 --- a/src/features/help/hooks/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './useHelp'; diff --git a/src/features/help/index.ts b/src/features/help/index.ts index dcf6103..70eef64 100644 --- a/src/features/help/index.ts +++ b/src/features/help/index.ts @@ -1,14 +1,10 @@ /** - * Help Center Module - Barrel file + * Barrel file for help feature * - * This file serves as a centralized export point for all Help Center components and hooks. - * It enables clean imports throughout the application by providing a single entry point - * without requiring consumers to know the internal file structure. - * - * Usage: - * import { HelpProvider, HelpButton, useHelp } from '@/features/help'; + * Provides unified access to help center functionality + * including context, providers, hooks, and components. */ export { HelpProvider } from './context/HelpProvider'; -export { useHelp } from './hooks'; +export { useHelp } from './hooks/useHelp'; export { HelpButton, HelpCenter, WelcomePanel } from './components'; \ No newline at end of file diff --git a/src/features/progress/components/index.ts b/src/features/progress/components/index.ts deleted file mode 100644 index c681ed4..0000000 --- a/src/features/progress/components/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as ProgressWithFeedback } from './ProgressWithFeedback'; diff --git a/src/features/progress/hooks/index.ts b/src/features/progress/hooks/index.ts deleted file mode 100644 index 8efe8de..0000000 --- a/src/features/progress/hooks/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { useProgressFeedback } from './useProgressFeedback'; diff --git a/src/features/progress/index.ts b/src/features/progress/index.ts deleted file mode 100644 index b33acce..0000000 --- a/src/features/progress/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Progress Feature Module - * - * Provides functionality for tracking and displaying user progress - * throughout the application. - */ - -export { useProgressFeedback } from './hooks'; -export { ProgressWithFeedback } from './components'; diff --git a/src/features/questions/index.ts b/src/features/questions/index.ts index f9bbcde..80d2166 100644 --- a/src/features/questions/index.ts +++ b/src/features/questions/index.ts @@ -1,8 +1,8 @@ /** - * Questions Feature Module + * Barrel file for questions feature * - * Centralizes questions-related functionality including context, - * providers, hooks, and components. + * Provides unified access to questions-related functionality + * including context, providers, hooks, and components. */ // Re-export context and provider diff --git a/src/features/statements/index.ts b/src/features/statements/index.ts index 22b1efe..7a59ed4 100644 --- a/src/features/statements/index.ts +++ b/src/features/statements/index.ts @@ -1,3 +1,8 @@ -// Barrel file for statements feature exports +/** + * Barrel file for statements feature + * + * Provides unified access to statements-related functionality + * including context, providers, hooks, and components. + */ export { useEntries } from './hooks/useEntries'; export { EntriesProvider } from './context/EntriesProvider'; \ No newline at end of file diff --git a/src/features/wizard/index.ts b/src/features/wizard/index.ts deleted file mode 100644 index b567bd6..0000000 --- a/src/features/wizard/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -// Barrel file for wizard feature exports -export { default as StatementWizard } from './components/StatementWizard'; \ No newline at end of file From 143ef300bdba5fb27a8eccec822fab52fd077f52 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 2 Apr 2025 13:31:09 +0100 Subject: [PATCH 16/35] feat: update types to support statement description field --- src/types/entries.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/types/entries.ts b/src/types/entries.ts index ca8ddea..9c5cb22 100644 --- a/src/types/entries.ts +++ b/src/types/entries.ts @@ -23,6 +23,7 @@ export interface Entry { input: string; // The full statement as a single string (headline) isPublic: boolean; atoms: Atoms; // Nested grammatical components + description?: string; // Optional detailed description/expansion of the statement actions?: Action[]; category: string; presetId?: string; @@ -72,6 +73,7 @@ export interface SetQuestion { subject: SetQuestionStep; verb: SetQuestionStep; object: SetQuestionStep; + description?: SetQuestionStep; category?: SetQuestionStep; privacy: SetQuestionStep; }; @@ -96,6 +98,7 @@ export type Step = | 'subject' | 'verb' | 'object' + | 'description' | 'category' | 'privacy' | 'complement'; From 44581670cd9d8cdef5295c08e3f90892f82551e2 Mon Sep 17 00:00:00 2001 From: Alexander Date: Wed, 2 Apr 2025 13:33:33 +0100 Subject: [PATCH 17/35] feat: implement description step in statement wizard - Add new DescriptionStep component for entering optional statement details - Update wizard flow to include description step between object and privacy steps - Add description field to statement preview - Add CSS variables for description input styling - Make description field optional with clear indication to users --- .../wizard/components/StatementPreview.tsx | 7 ++ .../wizard/components/StatementWizard.tsx | 32 ++++++- .../components/steps/DescriptionStep.tsx | 84 +++++++++++++++++++ src/index.css | 2 + 4 files changed, 123 insertions(+), 2 deletions(-) create mode 100644 src/features/wizard/components/steps/DescriptionStep.tsx diff --git a/src/features/wizard/components/StatementPreview.tsx b/src/features/wizard/components/StatementPreview.tsx index b3df1e3..79af1c4 100644 --- a/src/features/wizard/components/StatementPreview.tsx +++ b/src/features/wizard/components/StatementPreview.tsx @@ -130,6 +130,13 @@ const StatementPreview: React.FC = ({ selection }) => { {word} ))} + + {/* Description preview */} + {selection.description && (currentStep === 'description' || currentStep === 'privacy' || currentStep === 'complement') && ( +
+

{selection.description}

+
+ )}
); }; diff --git a/src/features/wizard/components/StatementWizard.tsx b/src/features/wizard/components/StatementWizard.tsx index 700a8ad..5cd5dd0 100644 --- a/src/features/wizard/components/StatementWizard.tsx +++ b/src/features/wizard/components/StatementWizard.tsx @@ -15,6 +15,7 @@ import { SubjectStep } from './steps/SubjectStep'; import { VerbStep } from './steps/VerbStep'; import { ObjectStep } from './steps/ObjectStep'; import { CategoryStep } from './steps/CategoryStep'; +import { DescriptionStep } from './steps/DescriptionStep'; import { PrivacyStep } from './steps/PrivacyStep'; import { ComplementStep } from './steps/ComplementStep'; import StatementPreview from './StatementPreview'; @@ -39,14 +40,15 @@ const StatementWizard: React.FC = ({ // Define steps: if preset, skip "category" and add "complement" // For custom statements, show category first, then subject const steps: Exclude[] = isPreset - ? ['subject', 'verb', 'object', 'privacy', 'complement'] - : ['category', 'subject', 'verb', 'object', 'privacy']; + ? ['subject', 'verb', 'object', 'description', 'privacy', 'complement'] + : ['category', 'subject', 'verb', 'object', 'description', 'privacy']; // Use design tokens for border colors via Tailwind’s arbitrary value syntax: const stepBorderColors: Record, string> = { subject: 'border-[var(--subject-selector)]', verb: 'border-[var(--verb-selector)]', object: 'border-[var(--object-input)]', + description: 'border-[var(--description-input, #8BB8E8)]', category: 'border-[var(--category-selector)]', privacy: 'border-[var(--privacy-selector)]', complement: 'border-gray-400', @@ -173,6 +175,9 @@ const StatementWizard: React.FC = ({ case 'category': // For custom statements (not preset), category must be selected return isPreset || selection.category.trim().length > 0; + case 'description': + // Description is optional; always valid + return true; case 'privacy': // Always valid since it's a boolean toggle. return true; @@ -247,6 +252,29 @@ const StatementWizard: React.FC = ({ }} /> ); + case 'description': + return ( + { + // Always move to the next step since description is optional + if (val === selection.description) { + goNext(); + } else { + // Update the description value + setSelection((prev) => ({ + ...prev, + description: val, + })); + + // If user entered something and pressed Save, move to next step + if (val.trim().length > 0) { + goNext(); + } + } + }} + /> + ); case 'category': return ( void; + currentStep?: number; + totalSteps?: number; +} + +export const DescriptionStep: React.FC = ({ + description = '', + onUpdate, + currentStep = 4, // After subject, verb, object, before privacy + totalSteps = 6, +}) => { + const [inputValue, setInputValue] = useState(description); + const maxLength = 500; // Maximum character limit + + const handleChange = (e: React.ChangeEvent) => { + const newValue = e.target.value; + if (newValue.length <= maxLength) { + setInputValue(newValue); + } + }; + + const handleBlur = () => { + onUpdate(inputValue); + }; + + // Handle Enter key to save + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + onUpdate(inputValue); + } + }; + + const subQuestion = "Add more details to your statement (optional)"; + const charCount = inputValue.length; + const remainingChars = maxLength - charCount; + + return ( + +
+
+

Use this space to provide additional context or details for your statement.

+

This field is optional.

+
+ +
+