Frontend Features: - Add MessageFeedback component with thumbs up/down buttons - Positive feedback submits immediately with success toast - Negative feedback opens dialog for optional text input - Integrate feedback buttons on all AI assistant messages - Add success Snackbar confirmation message - Translation keys added to ai.json (feedback section) Backend Features: - Add POST /api/v1/ai/feedback endpoint - Create FeedbackDto with conversation ID validation - Implement submitFeedback service method - Store feedback in conversation metadata with timestamps - Add audit logging for feedback submissions - Fix conversationId regex validation to support nanoid format Legal & Compliance: - Implement complete EULA acceptance flow with modal - Create reusable legal content components (Terms, Privacy, EULA) - Add LegalDocumentViewer for nested modal viewing - Cookie Consent Banner with GDPR compliance - Legal pages with AppShell navigation - EULA acceptance tracking in user entity Branding Updates: - Rebrand from "Maternal App" to "ParentFlow" - Update all icons (72px to 512px) from high-res source - PWA manifest updated with ParentFlow branding - Contact email: hello@parentflow.com - Address: Serbota 3, Bucharest, Romania Bug Fixes: - Fix chat endpoint validation (support nanoid conversation IDs) - Fix EULA acceptance API call (use apiClient vs hardcoded localhost) - Fix icon loading errors with proper PNG generation Documentation: - Mark 11 high-priority features as complete in REMAINING_FEATURES.md - Update feature statistics: 73/139 complete (53%) - All high-priority features now complete! 🎉 Files Changed: Frontend: 21 files (components, pages, locales, icons) Backend: 6 files (controller, service, DTOs, migrations) Docs: 1 file (REMAINING_FEATURES.md) Co-Authored-By: Claude <noreply@anthropic.com>
237 lines
7.1 KiB
TypeScript
237 lines
7.1 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import {
|
|
Dialog,
|
|
DialogTitle,
|
|
DialogContent,
|
|
DialogActions,
|
|
Button,
|
|
Typography,
|
|
Box,
|
|
Checkbox,
|
|
FormControlLabel,
|
|
Link,
|
|
Alert,
|
|
Divider,
|
|
} from '@mui/material';
|
|
import { Gavel, Warning } from '@mui/icons-material';
|
|
import { LegalDocumentViewer } from './LegalDocumentViewer';
|
|
|
|
interface EULADialogProps {
|
|
open: boolean;
|
|
onAccept: () => void;
|
|
onDecline: () => void;
|
|
}
|
|
|
|
export function EULADialog({ open, onAccept, onDecline }: EULADialogProps) {
|
|
const [agreedToTerms, setAgreedToTerms] = useState(false);
|
|
const [agreedToPrivacy, setAgreedToPrivacy] = useState(false);
|
|
const [agreedToEULA, setAgreedToEULA] = useState(false);
|
|
const [viewingDocument, setViewingDocument] = useState<{
|
|
type: 'terms' | 'privacy' | 'eula' | null;
|
|
title: string;
|
|
}>({ type: null, title: '' });
|
|
|
|
const canAccept = agreedToTerms && agreedToPrivacy && agreedToEULA;
|
|
|
|
const handleAccept = () => {
|
|
if (canAccept) {
|
|
onAccept();
|
|
}
|
|
};
|
|
|
|
const openDocument = (type: 'terms' | 'privacy' | 'eula', title: string) => (e: React.MouseEvent) => {
|
|
e.preventDefault();
|
|
setViewingDocument({ type, title });
|
|
};
|
|
|
|
const closeDocumentViewer = () => {
|
|
setViewingDocument({ type: null, title: '' });
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Dialog
|
|
open={open}
|
|
maxWidth="md"
|
|
fullWidth
|
|
disableEscapeKeyDown
|
|
onClose={(event, reason) => {
|
|
// Prevent closing by clicking outside or pressing ESC
|
|
if (reason === 'backdropClick' || reason === 'escapeKeyDown') {
|
|
return;
|
|
}
|
|
}}
|
|
sx={{
|
|
'& .MuiDialog-paper': {
|
|
borderRadius: 2,
|
|
},
|
|
}}
|
|
>
|
|
<DialogTitle sx={{ pb: 2 }}>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
|
<Gavel sx={{ fontSize: 32, color: 'primary.main' }} />
|
|
<Box>
|
|
<Typography variant="h5" component="div">
|
|
Welcome to ParentFlow
|
|
</Typography>
|
|
<Typography variant="body2" color="text.secondary">
|
|
Please review and accept our legal agreements
|
|
</Typography>
|
|
</Box>
|
|
</Box>
|
|
</DialogTitle>
|
|
|
|
<Divider />
|
|
|
|
<DialogContent sx={{ pt: 3 }}>
|
|
<Alert severity="info" icon={<Warning />} sx={{ mb: 3 }}>
|
|
<Typography variant="body2">
|
|
To use ParentFlow, you must read and accept our Terms of Service, Privacy Policy, and End User License Agreement (EULA).
|
|
Click on each link below to read the full documents.
|
|
</Typography>
|
|
</Alert>
|
|
|
|
<Box sx={{ mb: 3 }}>
|
|
<Typography variant="h6" gutterBottom>
|
|
Important Highlights
|
|
</Typography>
|
|
<Typography component="div" variant="body2" color="text.secondary">
|
|
<ul>
|
|
<li>
|
|
<strong>Medical Disclaimer:</strong> This app is NOT a medical device and does not provide medical advice.
|
|
Always consult qualified healthcare professionals for medical concerns.
|
|
</li>
|
|
<li>
|
|
<strong>AI Features:</strong> AI responses may not always be accurate. You use AI features at your own risk.
|
|
</li>
|
|
<li>
|
|
<strong>Children's Privacy:</strong> We comply with COPPA and GDPR. You control your child's data and can delete it anytime.
|
|
</li>
|
|
<li>
|
|
<strong>Data Collection:</strong> We collect activity data, photos, and AI chat messages to provide the service.
|
|
We do NOT sell your data.
|
|
</li>
|
|
<li>
|
|
<strong>Your Rights:</strong> You can access, export, or delete your data at any time through app settings.
|
|
</li>
|
|
</ul>
|
|
</Typography>
|
|
</Box>
|
|
|
|
<Divider sx={{ my: 3 }} />
|
|
|
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
checked={agreedToTerms}
|
|
onChange={(e) => setAgreedToTerms(e.target.checked)}
|
|
color="primary"
|
|
/>
|
|
}
|
|
label={
|
|
<Typography variant="body2">
|
|
I have read and agree to the{' '}
|
|
<Link
|
|
href="#"
|
|
onClick={openDocument('terms', 'Terms of Service')}
|
|
sx={{ fontWeight: 'bold', textDecoration: 'underline', cursor: 'pointer' }}
|
|
>
|
|
Terms of Service
|
|
</Link>
|
|
</Typography>
|
|
}
|
|
/>
|
|
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
checked={agreedToPrivacy}
|
|
onChange={(e) => setAgreedToPrivacy(e.target.checked)}
|
|
color="primary"
|
|
/>
|
|
}
|
|
label={
|
|
<Typography variant="body2">
|
|
I have read and agree to the{' '}
|
|
<Link
|
|
href="#"
|
|
onClick={openDocument('privacy', 'Privacy Policy')}
|
|
sx={{ fontWeight: 'bold', textDecoration: 'underline', cursor: 'pointer' }}
|
|
>
|
|
Privacy Policy
|
|
</Link>
|
|
</Typography>
|
|
}
|
|
/>
|
|
|
|
<FormControlLabel
|
|
control={
|
|
<Checkbox
|
|
checked={agreedToEULA}
|
|
onChange={(e) => setAgreedToEULA(e.target.checked)}
|
|
color="primary"
|
|
/>
|
|
}
|
|
label={
|
|
<Typography variant="body2">
|
|
I have read and agree to the{' '}
|
|
<Link
|
|
href="#"
|
|
onClick={openDocument('eula', 'End User License Agreement (EULA)')}
|
|
sx={{ fontWeight: 'bold', textDecoration: 'underline', cursor: 'pointer' }}
|
|
>
|
|
End User License Agreement (EULA)
|
|
</Link>
|
|
</Typography>
|
|
}
|
|
/>
|
|
</Box>
|
|
|
|
<Alert severity="warning" sx={{ mt: 3 }}>
|
|
<Typography variant="body2">
|
|
<strong>Emergency Disclaimer:</strong> In case of medical emergencies, call your local emergency number immediately (911 in the US).
|
|
This app is not for emergency situations.
|
|
</Typography>
|
|
</Alert>
|
|
</DialogContent>
|
|
|
|
<Divider />
|
|
|
|
<DialogActions sx={{ p: 3, gap: 1 }}>
|
|
<Button
|
|
onClick={onDecline}
|
|
variant="outlined"
|
|
color="inherit"
|
|
size="large"
|
|
>
|
|
Decline & Exit
|
|
</Button>
|
|
<Button
|
|
onClick={handleAccept}
|
|
variant="contained"
|
|
color="primary"
|
|
size="large"
|
|
disabled={!canAccept}
|
|
sx={{ minWidth: 120 }}
|
|
>
|
|
I Accept
|
|
</Button>
|
|
</DialogActions>
|
|
</Dialog>
|
|
|
|
{/* Legal Document Viewer - appears on top of EULA dialog */}
|
|
{viewingDocument.type && (
|
|
<LegalDocumentViewer
|
|
open={true}
|
|
onClose={closeDocumentViewer}
|
|
documentType={viewingDocument.type}
|
|
title={viewingDocument.title}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|