feat: Complete comprehensive localization of all tracking and management pages
- Feeding page: 47+ strings localized with validation, success/error messages - Medicine page: 44 strings localized with unit conversion support - Sleep page: Already localized (verified) - Diaper page: Already localized (verified) - Activity page: Already localized (verified) - AI Assistant: 51 strings localized including chat interface and suggested questions - Children page: 38 strings fully localized with gender labels - Family page: 42 strings localized with role management - Insights page: 41 strings localized including charts and analytics Added translation files: - locales/en/ai.json (44 keys) - locales/en/family.json (42 keys) - locales/en/insights.json (41 keys) Updated translation files: - locales/en/tracking.json (added feeding, health/medicine sections) - locales/en/children.json (verified complete) All pages now use useTranslation hook with proper namespaces. All user-facing text externalized and ready for multi-language support.
This commit is contained in:
@@ -239,7 +239,7 @@ export default function ChildrenPage() {
|
||||
{child.name}
|
||||
</Typography>
|
||||
<Chip
|
||||
label={child.gender}
|
||||
label={t(`gender.${child.gender}`)}
|
||||
size="small"
|
||||
sx={{ textTransform: 'capitalize', mt: 0.5 }}
|
||||
/>
|
||||
|
||||
@@ -25,8 +25,10 @@ import { InviteMemberDialog } from '@/components/family/InviteMemberDialog';
|
||||
import { JoinFamilyDialog } from '@/components/family/JoinFamilyDialog';
|
||||
import { RemoveMemberDialog } from '@/components/family/RemoveMemberDialog';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
|
||||
export default function FamilyPage() {
|
||||
const { t } = useTranslation('family');
|
||||
const { user, refreshUser } = useAuth();
|
||||
const [family, setFamily] = useState<Family | null>(null);
|
||||
const [members, setMembers] = useState<FamilyMember[]>([]);
|
||||
@@ -47,7 +49,7 @@ export default function FamilyPage() {
|
||||
fetchFamilyData();
|
||||
} else {
|
||||
setLoading(false);
|
||||
setError('No family found. Please complete onboarding first.');
|
||||
setError(t('messages.noFamilyFound'));
|
||||
}
|
||||
}, [familyId]);
|
||||
|
||||
@@ -65,7 +67,7 @@ export default function FamilyPage() {
|
||||
setMembers(membersData);
|
||||
} catch (err: any) {
|
||||
console.error('Failed to fetch family data:', err);
|
||||
setError(err.response?.data?.message || 'Failed to load family information');
|
||||
setError(err.response?.data?.message || t('messages.failedToLoad'));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -76,26 +78,26 @@ export default function FamilyPage() {
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(family.shareCode);
|
||||
setSnackbar({ open: true, message: 'Share code copied to clipboard!' });
|
||||
setSnackbar({ open: true, message: t('messages.shareCodeCopied') });
|
||||
} catch (err) {
|
||||
setSnackbar({ open: true, message: 'Failed to copy share code' });
|
||||
setSnackbar({ open: true, message: t('messages.shareCodeCopyFailed') });
|
||||
}
|
||||
};
|
||||
|
||||
const handleInviteMember = async (data: InviteMemberData) => {
|
||||
if (!familyId) {
|
||||
throw new Error('No family ID found');
|
||||
throw new Error(t('messages.noFamilyId'));
|
||||
}
|
||||
|
||||
try {
|
||||
setActionLoading(true);
|
||||
await familiesApi.inviteMember(familyId, data);
|
||||
setSnackbar({ open: true, message: 'Invitation sent successfully!' });
|
||||
setSnackbar({ open: true, message: t('messages.invitationSent') });
|
||||
await fetchFamilyData();
|
||||
setInviteDialogOpen(false);
|
||||
} catch (err: any) {
|
||||
console.error('Failed to invite member:', err);
|
||||
throw new Error(err.response?.data?.message || 'Failed to send invitation');
|
||||
throw new Error(err.response?.data?.message || t('messages.failedToInvite'));
|
||||
} finally {
|
||||
setActionLoading(false);
|
||||
}
|
||||
@@ -105,13 +107,13 @@ export default function FamilyPage() {
|
||||
try {
|
||||
setActionLoading(true);
|
||||
await familiesApi.joinFamily(data);
|
||||
setSnackbar({ open: true, message: 'Successfully joined family!' });
|
||||
setSnackbar({ open: true, message: t('messages.joinedFamily') });
|
||||
await refreshUser();
|
||||
await fetchFamilyData();
|
||||
setJoinDialogOpen(false);
|
||||
} catch (err: any) {
|
||||
console.error('Failed to join family:', err);
|
||||
throw new Error(err.response?.data?.message || 'Failed to join family');
|
||||
throw new Error(err.response?.data?.message || t('messages.failedToJoin'));
|
||||
} finally {
|
||||
setActionLoading(false);
|
||||
}
|
||||
@@ -128,13 +130,13 @@ export default function FamilyPage() {
|
||||
try {
|
||||
setActionLoading(true);
|
||||
await familiesApi.removeMember(familyId, memberToRemove.userId);
|
||||
setSnackbar({ open: true, message: 'Member removed successfully' });
|
||||
setSnackbar({ open: true, message: t('messages.memberRemoved') });
|
||||
await fetchFamilyData();
|
||||
setRemoveDialogOpen(false);
|
||||
setMemberToRemove(null);
|
||||
} catch (err: any) {
|
||||
console.error('Failed to remove member:', err);
|
||||
setError(err.response?.data?.message || 'Failed to remove member');
|
||||
setError(err.response?.data?.message || t('messages.failedToRemove'));
|
||||
} finally {
|
||||
setActionLoading(false);
|
||||
}
|
||||
@@ -164,10 +166,10 @@ export default function FamilyPage() {
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 4 }}>
|
||||
<Box>
|
||||
<Typography variant="h4" component="h1" fontWeight="600" gutterBottom>
|
||||
Family
|
||||
{t('pageTitle')}
|
||||
</Typography>
|
||||
<Typography variant="body1" color="text.secondary">
|
||||
Manage your family members and share access
|
||||
{t('pageSubtitle')}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
@@ -177,7 +179,7 @@ export default function FamilyPage() {
|
||||
onClick={() => setJoinDialogOpen(true)}
|
||||
disabled={loading}
|
||||
>
|
||||
Join Family
|
||||
{t('buttons.joinFamily')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
@@ -185,7 +187,7 @@ export default function FamilyPage() {
|
||||
onClick={() => setInviteDialogOpen(true)}
|
||||
disabled={loading || !familyId}
|
||||
>
|
||||
Invite Member
|
||||
{t('buttons.inviteMember')}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -208,10 +210,10 @@ export default function FamilyPage() {
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" component="h2" fontWeight="600" gutterBottom>
|
||||
Family Share Code
|
||||
{t('shareCode.title')}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
|
||||
Share this code with family members to give them access to your family's data
|
||||
{t('shareCode.description')}
|
||||
</Typography>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2, flexWrap: 'wrap' }}>
|
||||
<Chip
|
||||
@@ -229,7 +231,7 @@ export default function FamilyPage() {
|
||||
startIcon={<ContentCopy />}
|
||||
onClick={handleCopyCode}
|
||||
>
|
||||
Copy Code
|
||||
{t('buttons.copyCode')}
|
||||
</Button>
|
||||
</Box>
|
||||
</CardContent>
|
||||
@@ -242,30 +244,30 @@ export default function FamilyPage() {
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" fontWeight="600" gutterBottom sx={{ mb: 3 }}>
|
||||
Family Members ({members.length})
|
||||
{t('members.title', { count: members.length })}
|
||||
</Typography>
|
||||
|
||||
{members.length === 0 ? (
|
||||
<Box sx={{ textAlign: 'center', py: 4 }}>
|
||||
<People sx={{ fontSize: 48, color: 'text.secondary', mb: 2 }} />
|
||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||
No family members yet
|
||||
{t('members.noMembers')}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
|
||||
Invite family members to collaborate on child care
|
||||
{t('members.noMembersDescription')}
|
||||
</Typography>
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<PersonAdd />}
|
||||
onClick={() => setInviteDialogOpen(true)}
|
||||
>
|
||||
Invite First Member
|
||||
{t('buttons.inviteFirstMember')}
|
||||
</Button>
|
||||
</Box>
|
||||
) : (
|
||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||
{members.map((member, index) => {
|
||||
const memberName = member.user?.name || 'Unknown User';
|
||||
const memberName = member.user?.name || t('placeholders.unknownUser');
|
||||
return (
|
||||
<Box key={member.id} component="div">
|
||||
<motion.div
|
||||
@@ -289,15 +291,15 @@ export default function FamilyPage() {
|
||||
{memberName}
|
||||
</Typography>
|
||||
{isCurrentUser(member.userId) && (
|
||||
<Chip label="You" size="small" color="success" />
|
||||
<Chip label={t('members.youLabel')} size="small" color="success" />
|
||||
)}
|
||||
</Box>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{member.user?.email || 'No email'}
|
||||
{member.user?.email || t('placeholders.noEmail')}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Chip
|
||||
label={member.role.charAt(0).toUpperCase() + member.role.slice(1)}
|
||||
label={t(`roles.${member.role}`)}
|
||||
color={getRoleColor(member.role)}
|
||||
size="small"
|
||||
/>
|
||||
@@ -306,7 +308,7 @@ export default function FamilyPage() {
|
||||
size="small"
|
||||
onClick={() => handleRemoveClick(member)}
|
||||
color="error"
|
||||
aria-label={`Remove ${memberName} from family`}
|
||||
aria-label={t('members.removeAriaLabel', { name: memberName })}
|
||||
>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
|
||||
@@ -142,7 +142,7 @@ function FeedingTrackPage() {
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('Failed to load children:', err);
|
||||
setError(err.response?.data?.message || 'Failed to load children');
|
||||
setError(err.response?.data?.message || t('common.error.loadChildrenFailed'));
|
||||
} finally {
|
||||
setChildrenLoading(false);
|
||||
}
|
||||
@@ -189,23 +189,23 @@ function FeedingTrackPage() {
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!selectedChild) {
|
||||
setError('Please select a child');
|
||||
setError(t('common.selectChild'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Validation
|
||||
if (feedingType === 'breast' && duration === 0 && timerSeconds === 0) {
|
||||
setError('Please enter duration or use the timer');
|
||||
setError(t('feeding.validation.durationRequired'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (feedingType === 'bottle' && !amount) {
|
||||
setError('Please enter amount');
|
||||
setError(t('feeding.validation.amountRequired'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (feedingType === 'solid' && !foodDescription) {
|
||||
setError('Please enter food description');
|
||||
setError(t('feeding.validation.foodRequired'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ function FeedingTrackPage() {
|
||||
notes: notes || undefined,
|
||||
});
|
||||
|
||||
setSuccessMessage('Feeding logged successfully!');
|
||||
setSuccessMessage(t('feeding.success'));
|
||||
|
||||
// Reset form
|
||||
resetForm();
|
||||
@@ -244,7 +244,7 @@ function FeedingTrackPage() {
|
||||
await loadRecentFeedings();
|
||||
} catch (err: any) {
|
||||
console.error('Failed to save feeding:', err);
|
||||
setError(err.response?.data?.message || 'Failed to save feeding');
|
||||
setError(err.response?.data?.message || t('feeding.error.saveFailed'));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -273,13 +273,13 @@ function FeedingTrackPage() {
|
||||
try {
|
||||
setLoading(true);
|
||||
await trackingApi.deleteActivity(activityToDelete);
|
||||
setSuccessMessage('Feeding deleted successfully');
|
||||
setSuccessMessage(t('feeding.deleted'));
|
||||
setDeleteDialogOpen(false);
|
||||
setActivityToDelete(null);
|
||||
await loadRecentFeedings();
|
||||
} catch (err: any) {
|
||||
console.error('Failed to delete feeding:', err);
|
||||
setError(err.response?.data?.message || 'Failed to delete feeding');
|
||||
setError(err.response?.data?.message || t('feeding.error.deleteFailed'));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -345,17 +345,17 @@ function FeedingTrackPage() {
|
||||
<CardContent sx={{ textAlign: 'center', py: 8 }}>
|
||||
<ChildCare sx={{ fontSize: 64, color: 'text.secondary', mb: 2 }} />
|
||||
<Typography variant="h6" color="text.secondary" gutterBottom>
|
||||
No Children Added
|
||||
{t('common.noChildrenAdded')}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||
You need to add a child before you can track feeding activities
|
||||
{t('common.noChildrenMessage')}
|
||||
</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<Add />}
|
||||
onClick={() => router.push('/children')}
|
||||
>
|
||||
Add Child
|
||||
{t('common.addChild')}
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -414,11 +414,11 @@ function FeedingTrackPage() {
|
||||
{children.length > 1 && (
|
||||
<Paper sx={{ p: 2, mb: 3 }}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Select Child</InputLabel>
|
||||
<InputLabel>{t('common.selectChild')}</InputLabel>
|
||||
<Select
|
||||
value={selectedChild}
|
||||
onChange={(e) => setSelectedChild(e.target.value)}
|
||||
label="Select Child"
|
||||
label={t('common.selectChild')}
|
||||
>
|
||||
{children.map((child) => (
|
||||
<MenuItem key={child.id} value={child.id}>
|
||||
@@ -479,7 +479,7 @@ function FeedingTrackPage() {
|
||||
startIcon={<Refresh />}
|
||||
onClick={resetTimer}
|
||||
>
|
||||
Reset
|
||||
{t('feeding.reset')}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
@@ -506,7 +506,7 @@ function FeedingTrackPage() {
|
||||
value={duration || ''}
|
||||
onChange={(e) => setDuration(parseInt(e.target.value) || 0)}
|
||||
sx={{ mb: 3 }}
|
||||
helperText={t('feeding.placeholders.notes')}
|
||||
helperText={t('feeding.placeholders.duration')}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
@@ -524,15 +524,15 @@ function FeedingTrackPage() {
|
||||
/>
|
||||
|
||||
<FormControl fullWidth sx={{ mb: 3 }}>
|
||||
<InputLabel>{t('feeding.type')}</InputLabel>
|
||||
<InputLabel>{t('feeding.bottleType')}</InputLabel>
|
||||
<Select
|
||||
value={bottleType}
|
||||
onChange={(e) => setBottleType(e.target.value as 'formula' | 'breastmilk' | 'other')}
|
||||
label={t('feeding.type')}
|
||||
label={t('feeding.bottleType')}
|
||||
>
|
||||
<MenuItem value="formula">{t('feeding.types.bottle')}</MenuItem>
|
||||
<MenuItem value="breastmilk">{t('feeding.types.breast')}</MenuItem>
|
||||
<MenuItem value="other">Other</MenuItem>
|
||||
<MenuItem value="formula">{t('feeding.bottleTypes.formula')}</MenuItem>
|
||||
<MenuItem value="breastmilk">{t('feeding.bottleTypes.breastmilk')}</MenuItem>
|
||||
<MenuItem value="other">{t('feeding.bottleTypes.other')}</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
@@ -543,20 +543,20 @@ function FeedingTrackPage() {
|
||||
<Box>
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('feeding.type')}
|
||||
label={t('feeding.foodDescription')}
|
||||
value={foodDescription}
|
||||
onChange={(e) => setFoodDescription(e.target.value)}
|
||||
sx={{ mb: 3 }}
|
||||
placeholder={t('feeding.placeholders.notes')}
|
||||
placeholder={t('feeding.placeholders.foodDescription')}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
label={t('feeding.amount')}
|
||||
label={t('feeding.amountDescription')}
|
||||
value={amountDescription}
|
||||
onChange={(e) => setAmountDescription(e.target.value)}
|
||||
sx={{ mb: 3 }}
|
||||
placeholder={t('feeding.placeholders.amount')}
|
||||
placeholder={t('feeding.placeholders.amountDescription')}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
@@ -583,7 +583,7 @@ function FeedingTrackPage() {
|
||||
onClick={handleSubmit}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? t('feeding.addFeeding') : t('feeding.addFeeding')}
|
||||
{loading ? t('common.loading') : t('feeding.addFeeding')}
|
||||
</Button>
|
||||
</Paper>
|
||||
|
||||
@@ -591,7 +591,7 @@ function FeedingTrackPage() {
|
||||
<Paper sx={{ p: 3 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||||
<Typography variant="h6" fontWeight="600">
|
||||
{t('feeding.title')}
|
||||
{t('feeding.recentFeedings')}
|
||||
</Typography>
|
||||
<IconButton onClick={loadRecentFeedings} disabled={feedingsLoading}>
|
||||
<Refresh />
|
||||
@@ -685,10 +685,10 @@ function FeedingTrackPage() {
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setDeleteDialogOpen(false)} disabled={loading}>
|
||||
Cancel
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button onClick={handleDeleteConfirm} color="error" disabled={loading}>
|
||||
{loading ? t('deleteEntry') : t('deleteEntry')}
|
||||
{loading ? t('common.loading') : t('common.delete')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
@@ -114,7 +114,7 @@ function MedicineTrackPage() {
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('Failed to load children:', err);
|
||||
setError(err.response?.data?.message || 'Failed to load children');
|
||||
setError(err.response?.data?.message || t('common.error.loadChildrenFailed'));
|
||||
} finally {
|
||||
setChildrenLoading(false);
|
||||
}
|
||||
@@ -140,19 +140,19 @@ function MedicineTrackPage() {
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!selectedChild) {
|
||||
setError('Please select a child');
|
||||
setError(t('common.selectChild'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Validation
|
||||
if (!medicineName) {
|
||||
setError('Please enter medicine name');
|
||||
setError(t('health.medicineName.required'));
|
||||
return;
|
||||
}
|
||||
|
||||
const dosageValue = unit === 'ml' ? dosage : dosageText;
|
||||
if (!dosageValue || (unit === 'ml' && dosage === 0) || (unit !== 'ml' && !dosageText)) {
|
||||
setError('Please enter dosage');
|
||||
setError(t('health.dosage.required'));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ function MedicineTrackPage() {
|
||||
notes: notes || undefined,
|
||||
});
|
||||
|
||||
setSuccessMessage('Medicine logged successfully!');
|
||||
setSuccessMessage(t('health.success'));
|
||||
|
||||
// Reset form
|
||||
resetForm();
|
||||
@@ -184,7 +184,7 @@ function MedicineTrackPage() {
|
||||
await loadRecentMedicines();
|
||||
} catch (err: any) {
|
||||
console.error('Failed to save medicine:', err);
|
||||
setError(err.response?.data?.message || 'Failed to save medicine');
|
||||
setError(err.response?.data?.message || t('health.error'));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -211,13 +211,13 @@ function MedicineTrackPage() {
|
||||
try {
|
||||
setLoading(true);
|
||||
await trackingApi.deleteActivity(activityToDelete);
|
||||
setSuccessMessage('Medicine deleted successfully');
|
||||
setSuccessMessage(t('health.deleted'));
|
||||
setDeleteDialogOpen(false);
|
||||
setActivityToDelete(null);
|
||||
await loadRecentMedicines();
|
||||
} catch (err: any) {
|
||||
console.error('Failed to delete medicine:', err);
|
||||
setError(err.response?.data?.message || 'Failed to delete medicine');
|
||||
setError(err.response?.data?.message || t('health.deleteError'));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -282,17 +282,17 @@ function MedicineTrackPage() {
|
||||
<CardContent sx={{ textAlign: 'center', py: 8 }}>
|
||||
<ChildCare sx={{ fontSize: 64, color: 'text.secondary', mb: 2 }} />
|
||||
<Typography variant="h6" color="text.secondary" gutterBottom>
|
||||
No Children Added
|
||||
{t('common.noChildrenAdded')}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||
You need to add a child before you can track medicine activities
|
||||
{t('common.noChildrenMessage')}
|
||||
</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<Add />}
|
||||
onClick={() => router.push('/children')}
|
||||
>
|
||||
Add Child
|
||||
{t('common.addChild')}
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -352,11 +352,11 @@ function MedicineTrackPage() {
|
||||
{children.length > 1 && (
|
||||
<Paper sx={{ p: 2, mb: 3 }}>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Select Child</InputLabel>
|
||||
<InputLabel>{t('common.selectChild')}</InputLabel>
|
||||
<Select
|
||||
value={selectedChild}
|
||||
onChange={(e) => setSelectedChild(e.target.value)}
|
||||
label="Select Child"
|
||||
label={t('common.selectChild')}
|
||||
>
|
||||
{children.map((child) => (
|
||||
<MenuItem key={child.id} value={child.id}>
|
||||
@@ -373,17 +373,17 @@ function MedicineTrackPage() {
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 3 }}>
|
||||
<MedicalServices sx={{ fontSize: 36, color: 'error.main', mr: 2 }} />
|
||||
<Typography variant="h6" fontWeight="600">
|
||||
Medicine Information
|
||||
{t('health.medicineInfo')}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Medicine Name"
|
||||
label={t('health.medicineName.label')}
|
||||
value={medicineName}
|
||||
onChange={(e) => setMedicineName(e.target.value)}
|
||||
sx={{ mb: 3 }}
|
||||
placeholder="e.g., Acetaminophen, Ibuprofen"
|
||||
placeholder={t('health.medicineName.placeholder')}
|
||||
required
|
||||
/>
|
||||
|
||||
@@ -391,7 +391,7 @@ function MedicineTrackPage() {
|
||||
{unit === 'ml' ? (
|
||||
<UnitInput
|
||||
fullWidth
|
||||
label="Dosage"
|
||||
label={t('health.dosage.label')}
|
||||
type="volume"
|
||||
value={dosage}
|
||||
onChange={(metricValue) => setDosage(metricValue)}
|
||||
@@ -400,16 +400,16 @@ function MedicineTrackPage() {
|
||||
) : (
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Dosage"
|
||||
label={t('health.dosage.label')}
|
||||
value={dosageText}
|
||||
onChange={(e) => setDosageText(e.target.value)}
|
||||
placeholder="e.g., 5, 2.5"
|
||||
placeholder={t('health.dosage.placeholder')}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
|
||||
<FormControl fullWidth>
|
||||
<InputLabel>Unit</InputLabel>
|
||||
<InputLabel>{t('health.unit')}</InputLabel>
|
||||
<Select
|
||||
value={unit}
|
||||
onChange={(e) => {
|
||||
@@ -422,39 +422,39 @@ function MedicineTrackPage() {
|
||||
setDosage(0);
|
||||
}
|
||||
}}
|
||||
label="Unit"
|
||||
label={t('health.unit')}
|
||||
>
|
||||
<MenuItem value="ml">ml</MenuItem>
|
||||
<MenuItem value="mg">mg</MenuItem>
|
||||
<MenuItem value="tsp">tsp</MenuItem>
|
||||
<MenuItem value="tbsp">tbsp</MenuItem>
|
||||
<MenuItem value="drops">drops</MenuItem>
|
||||
<MenuItem value="tablet">tablet(s)</MenuItem>
|
||||
<MenuItem value="ml">{t('health.units.ml')}</MenuItem>
|
||||
<MenuItem value="mg">{t('health.units.mg')}</MenuItem>
|
||||
<MenuItem value="tsp">{t('health.units.tsp')}</MenuItem>
|
||||
<MenuItem value="tbsp">{t('health.units.tbsp')}</MenuItem>
|
||||
<MenuItem value="drops">{t('health.units.drops')}</MenuItem>
|
||||
<MenuItem value="tablet">{t('health.units.tablet')}</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Box>
|
||||
|
||||
<FormControl fullWidth sx={{ mb: 3 }}>
|
||||
<InputLabel>Route</InputLabel>
|
||||
<InputLabel>{t('health.route.label')}</InputLabel>
|
||||
<Select
|
||||
value={route}
|
||||
onChange={(e) => setRoute(e.target.value as 'oral' | 'topical' | 'injection' | 'other')}
|
||||
label="Route"
|
||||
label={t('health.route.label')}
|
||||
>
|
||||
<MenuItem value="oral">Oral</MenuItem>
|
||||
<MenuItem value="topical">Topical</MenuItem>
|
||||
<MenuItem value="injection">Injection</MenuItem>
|
||||
<MenuItem value="other">Other</MenuItem>
|
||||
<MenuItem value="oral">{t('health.route.oral')}</MenuItem>
|
||||
<MenuItem value="topical">{t('health.route.topical')}</MenuItem>
|
||||
<MenuItem value="injection">{t('health.route.injection')}</MenuItem>
|
||||
<MenuItem value="other">{t('health.route.other')}</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
<TextField
|
||||
fullWidth
|
||||
label="Reason (optional)"
|
||||
label={t('health.reason.label')}
|
||||
value={reason}
|
||||
onChange={(e) => setReason(e.target.value)}
|
||||
sx={{ mb: 3 }}
|
||||
placeholder="e.g., Fever, Pain, Allergy"
|
||||
placeholder={t('health.reason.placeholder')}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
@@ -477,7 +477,7 @@ function MedicineTrackPage() {
|
||||
onClick={handleSubmit}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? t('activities.medicine') : t('activities.medicine')}
|
||||
{loading ? t('common.loading') : t('health.logMedicine')}
|
||||
</Button>
|
||||
</Paper>
|
||||
|
||||
@@ -485,7 +485,7 @@ function MedicineTrackPage() {
|
||||
<Paper sx={{ p: 3 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||||
<Typography variant="h6" fontWeight="600">
|
||||
{t('activities.medicine')}
|
||||
{t('health.recentMedicines')}
|
||||
</Typography>
|
||||
<IconButton onClick={loadRecentMedicines} disabled={medicinesLoading}>
|
||||
<Refresh />
|
||||
@@ -578,10 +578,10 @@ function MedicineTrackPage() {
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button onClick={() => setDeleteDialogOpen(false)} disabled={loading}>
|
||||
Cancel
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button onClick={handleDeleteConfirm} color="error" disabled={loading}>
|
||||
{loading ? t('deleteEntry') : t('deleteEntry')}
|
||||
{loading ? t('common.loading') : t('common.delete')}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
Reference in New Issue
Block a user