Skip to content

Add statement description #44

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c47050b
style: renamed tour folder to help center
AlexVOiceover Apr 2, 2025
beeac7f
fix: separate context and provider to make eslint happy
AlexVOiceover Apr 2, 2025
eb9348c
refactor: standardize file naming conventions for components
AlexVOiceover Apr 2, 2025
197490a
fix: update component import paths to match PascalCase filenames
AlexVOiceover Apr 2, 2025
ce89529
fix: file renaming enforcing good practices on naming conventions
AlexVOiceover Apr 2, 2025
d324b50
fix: Typescript error on BetterTooltip
AlexVOiceover Apr 2, 2025
c48414e
fix: simplified buttonVariants
AlexVOiceover Apr 2, 2025
8484933
fix: added type to EventListener on handleMagicLinkVerified
AlexVOiceover Apr 2, 2025
f4b9a45
chore: complete file naming standardization
AlexVOiceover Apr 2, 2025
1698e1f
fix: restore ButtonVariants.ts PascalCase filename
AlexVOiceover Apr 2, 2025
882e8ab
fix: renaming for clarity
AlexVOiceover Apr 2, 2025
8296302
chore: reorganize folder structure for better code organization
AlexVOiceover Apr 2, 2025
2cf8d02
refactor: move ProgressWithFeedback to UI root folder
AlexVOiceover Apr 2, 2025
a01a5b2
refactor: create dedicated progress feature
AlexVOiceover Apr 2, 2025
f756ae0
refactor: remove unnecessary single-export barrel files
AlexVOiceover Apr 2, 2025
143ef30
feat: update types to support statement description field
AlexVOiceover Apr 2, 2025
4458167
feat: implement description step in statement wizard
AlexVOiceover Apr 2, 2025
39ea8c2
fix: improve description step UX and preview
AlexVOiceover Apr 2, 2025
e7dfac5
feat: add real-time preview for description field
AlexVOiceover Apr 2, 2025
bd837f6
fix: change on description triggers activate save button
AlexVOiceover Apr 2, 2025
3b3188a
fix: fixed set original state of description in order to track changes
AlexVOiceover Apr 2, 2025
0fd20dc
feat: show description in mobile
AlexVOiceover Apr 2, 2025
fa5d147
fix: added description to debug test button
AlexVOiceover Apr 2, 2025
2bf08d3
style: simplified style of description
AlexVOiceover Apr 2, 2025
85a4ef6
data: duplicate setQuestions
AlexVOiceover Apr 2, 2025
746d54f
fix: added // Force Redeploy messages
AlexVOiceover Apr 2, 2025
8416a8d
data: added better verbs and categories
AlexVOiceover Apr 2, 2025
8c83091
feat: replaced username for I and My on subject selector
AlexVOiceover Apr 2, 2025
9dc4a0f
fix: modifies verb tratment to adjust to subjewct use of I
AlexVOiceover Apr 3, 2025
0dd467f
Fix: removed username from subjectTiles
AlexVOiceover Apr 3, 2025
9fb0e3a
fix: modified title on Main Page
AlexVOiceover Apr 3, 2025
e4bab99
feat: added progress indicator per category
AlexVOiceover Apr 3, 2025
704f479
style: simplified utils files
AlexVOiceover Apr 3, 2025
f118f3b
test: removed button to have a testing deploy
AlexVOiceover Apr 3, 2025
2392c11
fix: moved progress counter to the side
AlexVOiceover Apr 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ docs
.aider*

CLAUDE.md
better-auth.md
better-auth.md
DescriptionPlan.md
67 changes: 41 additions & 26 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
'use client';

import React, { useEffect } from 'react';
import { TooltipProvider } from './components/ui/better-tooltip';
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/tour';
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 = () => {
Expand All @@ -33,43 +32,59 @@ 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) => {
interface MagicLinkVerifiedEvent extends CustomEvent {
detail: {
user: {
email: string;
[key: string]: unknown;
};
};
}

const handleMagicLinkVerified = (event: MagicLinkVerifiedEvent) => {
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);

window.addEventListener('magicLinkVerified', handleMagicLinkVerified as EventListener);
return () =>
window.removeEventListener('magicLinkVerified', handleMagicLinkVerified as EventListener);
}, []);

return (
// MainPage and Header receives the username from context.
<>
<Header />
{data.username ? (
<MainPage />
) : (
<LoginPage />
)}
{data.username ? <MainPage /> : <LoginPage />}
</>
);
};
Expand Down
5 changes: 4 additions & 1 deletion src/components/debug/TestButton.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
// TestStatementButton.tsx
import React from 'react';
import { Button } from '../ui/button';
import { Button } from '../ui/Button';
import type { Entry } from '@/types/entries';
import { useEntries } from '../../features/statements/hooks/useEntries'; // CHANGE: Import useEntries to update context

// Force Redeploy

const TestStatementButton: React.FC = () => {
// Create a valid test statement with one sample action.
const createTestStatement = (): Entry => ({
Expand All @@ -15,6 +17,7 @@ const TestStatementButton: React.FC = () => {
verb: 'supports',
object: 'the project',
},
description: 'El perro de San Roque no tiene rabo, porque ramon ramirez se lo ha cortado',
category: 'wellbeing',
actions: [
{
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@ import {
Tooltip,
TooltipTrigger,
TooltipContent,
} from '../../components/ui/better-tooltip';
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/components/StatementWizard';
import { ShareEmailModal } from '@/components/modals';
// import TestStatementButton from '@/components/debug/TestButton';
import Footer from './Footer';

const MainPage: React.FC = () => {
const { data } = useEntries();
const { username, managerName, managerEmail, entries } = data;
const { username, managerEmail, entries } = data;
const [isWizardOpen, setIsWizardOpen] = useState(false);
const [isShareModalOpen, setIsShareModalOpen] = useState(false);

Expand All @@ -42,9 +42,10 @@ const MainPage: React.FC = () => {
{/* Fixed header layout with 1 or 2 rows */}
<div className='flex flex-col md:flex-row md:justify-between md:items-center'>
<h1 id='page-title' className='text-2xl md:text-3xl font-bold'>
{managerName
{/* {managerName
? `Beacons for ${managerName}`
: `${username}'s Beacons`}
: `${username}'s Beacons`} */}
My Dashboard
</h1>
</div>
</div>
Expand Down
10 changes: 10 additions & 0 deletions src/components/layout/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Barrel file for layout components
*
* Provides unified access to structural page components
* including header, footer, and main content containers.
*/

export { default as Header } from './Header';
export { default as Footer } from './Footer';
export { default as MainPage } from './MainPage';
42 changes: 34 additions & 8 deletions src/components/modals/GratitudeModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@ import {
SimpleDialog as Dialog,
SimpleDialogContent as DialogContent,
SimpleDialogDescription as DialogDescription,
} from '../ui/simple-dialog';
import { Button } from '../ui/button';
} 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';

interface GratitudeModalProps {
onClose: () => void;
statementId: string;
action: Action;
statement?: {
input: string;
description?: string;
};
onGratitudeSent: (
statementId: string,
actionId: string,
Expand All @@ -27,6 +31,7 @@ const GratitudeModal: React.FC<GratitudeModalProps> = ({
onClose,
statementId,
action,
statement,
onGratitudeSent,
}) => {
const { data } = useEntries();
Expand Down Expand Up @@ -115,8 +120,8 @@ const GratitudeModal: React.FC<GratitudeModalProps> = ({
>
{/* Heart decoration - smaller on mobile */}
<div className='absolute top-2 right-2 sm:top-4 sm:right-4 text-pink-400 opacity-20 pointer-events-none'>
<Heart size={24} className="sm:hidden" />
<Heart size={40} className="hidden sm:block" />
<Heart size={24} className='sm:hidden' />
<Heart size={40} className='hidden sm:block' />
</div>

<DialogDescription className='mt-0 text-center text-sm'>
Expand All @@ -140,11 +145,32 @@ const GratitudeModal: React.FC<GratitudeModalProps> = ({
</div>
)}

{/* If statement is provided, show it */}
{statement && (
<div className='mb-4 sm:mb-6 p-3 sm:p-4 bg-white rounded-md shadow-sm border border-pink-100'>
<h3 className='font-semibold text-gray-700 mb-1 sm:mb-2 flex items-center text-sm sm:text-base'>
Statement
</h3>
<p className='text-gray-600 text-xs sm:text-sm break-words font-medium'>
{statement.input}
</p>

{/* Display description if available */}
{statement.description && statement.description.trim() !== '' && (
<div className='mt-2 text-gray-600 text-xs sm:text-sm bg-gray-50 p-2 rounded-sm border-l-2 border-[var(--description-input,#8BB8E8)] italic whitespace-pre-line'>
{statement.description}
</div>
)}
</div>
)}

<div className='mb-4 sm:mb-6 p-3 sm:p-4 bg-white rounded-md shadow-sm border border-pink-100'>
<h3 className='font-semibold text-gray-700 mb-1 sm:mb-2 flex items-center text-sm sm:text-base'>
Action
</h3>
<p className='text-gray-600 text-xs sm:text-sm break-words'>{action.action}</p>
<p className='text-gray-600 text-xs sm:text-sm break-words'>
{action.action}
</p>
{action.byDate && (
<p className='text-xs text-gray-500 mt-1'>
Due by: {action.byDate}
Expand Down Expand Up @@ -191,8 +217,8 @@ const GratitudeModal: React.FC<GratitudeModalProps> = ({
</>
)}
</Button>
<Button
variant='outline'
<Button
variant='outline'
onClick={onClose}
className='text-xs sm:text-sm px-2 sm:px-4 py-1 sm:py-2'
>
Expand Down
3 changes: 2 additions & 1 deletion src/components/modals/PrivacyModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

import React from 'react';
// import { SimpleDialog as Dialog, SimpleDialogContent as DialogContent } from '../ui/simple-dialog';
import { Button } from '../ui/button';
import { Button } from '../ui/Button';
import { X, Shield, CheckCircle, Lock, Eye } from 'lucide-react';

// Force Redeploy
interface PrivacyModalProps {
onClose: () => void;
}
Expand Down
20 changes: 13 additions & 7 deletions src/components/modals/ShareEmailModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import {
SimpleDialog as Dialog,
SimpleDialogContent as DialogContent,
SimpleDialogDescription as DialogDescription,
} from '../ui/simple-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 { getEmailFormattedStatement } from '@/lib/utils/verbUtils';
import PrivacyModal from './PrivacyModal';

const ShareEmailModal: React.FC<{ onClose: () => void }> = ({ onClose }) => {
Expand Down Expand Up @@ -124,10 +124,16 @@ const ShareEmailModal: React.FC<{ onClose: () => void }> = ({ onClose }) => {
className='p-3 sm:p-4 border bg-white shadow-sm rounded-sm'
>
<p className='text-sm sm:text-base font-semibold break-words'>
{entry.atoms.subject} {getVerbName(entry.atoms.verb)}{' '}
{entry.atoms.object}
{getEmailFormattedStatement(entry, data.username || 'User')}
</p>

{/* Display description if available */}
{entry.description && entry.description.trim() !== '' && (
<div className='mt-2 text-sm text-gray-700 bg-gray-50 p-2 rounded-sm border-l-2 border-[var(--description-input,#8BB8E8)] italic whitespace-pre-line'>
{entry.description}
</div>
)}

{entry.actions && entry.actions.length > 0 && (
<div className='mt-2 sm:mt-3'>
<div className='text-xs uppercase text-gray-500 font-semibold border-b border-gray-200 pb-1 mb-1 sm:mb-2'>
Expand Down
3 changes: 2 additions & 1 deletion src/components/modals/TermsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

import React from 'react';
// import { SimpleDialog as Dialog, SimpleDialogContent as DialogContent } from '../ui/simple-dialog';
import { Button } from '../ui/button';
import { Button } from '../ui/Button';
import { X, FileText, Check, AlertTriangle, Scale } from 'lucide-react';

// Force Redeploy
interface TermsModalProps {
onClose: () => void;
}
Expand Down
12 changes: 6 additions & 6 deletions src/components/modals/UserDataModal.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
'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 } from '@/components/ui';
import ProgressWithFeedback from '@/features/progress/components/ProgressWithFeedback';

interface UserDataModalProps {
onOpenChange: (open: boolean) => void;
Expand Down
12 changes: 12 additions & 0 deletions src/components/modals/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Barrel file for modal components
*
* Provides unified access to 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';
Loading