Files
biblical-guide.com/components/subscription/upgrade-modal.tsx
Andrei 9d82e719ed fix: display default reset date when limitResetDate is null
Fixed empty "Resets on" date display for new users:

Issue:
- Users who haven't created any conversations yet have limitResetDate = NULL
- The "Resets on" field was showing empty/blank
- This confused users about when their limit would reset

Solution:
- Updated formatResetDate() in 3 components to calculate default date
- If limitResetDate is NULL, display "1 month from now"
- This gives users a clear expectation of when limits reset

Files Updated:
- app/[locale]/subscription/page.tsx
  * formatResetDate() now returns calculated date if null
- components/subscription/usage-display.tsx
  * formatResetDate() now returns calculated date if null
- components/subscription/upgrade-modal.tsx
  * formatResetDate() now returns calculated date if null
  * Removed conditional check - always show reset date

User Experience:
- New users see "Resets on: [date one month from now]"
- Once they create their first conversation, actual reset date is set
- Consistent messaging across all subscription UI components

Note: The actual limitResetDate is set when the user creates their
first conversation (in incrementConversationCount function). This fix
only affects the UI display for users who haven't chatted yet.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 22:43:31 +00:00

220 lines
6.2 KiB
TypeScript

'use client'
import {
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Box,
Typography,
Button,
LinearProgress,
Chip
} from '@mui/material'
import {
Favorite,
AutoAwesome,
Close as CloseIcon
} from '@mui/icons-material'
import { useTranslations, useLocale } from 'next-intl'
import Link from 'next/link'
interface UpgradeModalProps {
open: boolean
onClose: () => void
limitData?: {
limit: number
remaining: number
tier: string
resetDate: string | null
}
}
export default function UpgradeModal({ open, onClose, limitData }: UpgradeModalProps) {
const locale = useLocale()
const t = useTranslations('subscription.limitReached')
const usagePercentage = limitData ? ((limitData.limit - limitData.remaining) / limitData.limit) * 100 : 100
const formatResetDate = (dateString: string | null) => {
if (!dateString) {
// If no reset date set, calculate 1 month from now
const nextMonth = new Date()
nextMonth.setMonth(nextMonth.getMonth() + 1)
return nextMonth.toLocaleDateString(locale, { year: 'numeric', month: 'long', day: 'numeric' })
}
const date = new Date(dateString)
return date.toLocaleDateString(locale, { year: 'numeric', month: 'long', day: 'numeric' })
}
return (
<Dialog
open={open}
onClose={onClose}
maxWidth="sm"
fullWidth
PaperProps={{
sx: {
borderRadius: 3,
p: 1
}
}}
>
<DialogTitle>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<Typography variant="h5" component="div" fontWeight="700">
{t('title')}
</Typography>
<Button
onClick={onClose}
sx={{ minWidth: 'auto', p: 1 }}
color="inherit"
>
<CloseIcon />
</Button>
</Box>
</DialogTitle>
<DialogContent>
{/* Current Usage */}
{limitData && (
<Box sx={{ mb: 4 }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 1 }}>
<Typography variant="body2" color="text.secondary">
{t('conversationsUsed')}
</Typography>
<Typography variant="body2" fontWeight="600">
{limitData.limit - limitData.remaining} / {limitData.limit}
</Typography>
</Box>
<LinearProgress
variant="determinate"
value={usagePercentage}
sx={{
height: 8,
borderRadius: 1,
bgcolor: 'grey.200',
'& .MuiLinearProgress-bar': {
bgcolor: 'warning.main'
}
}}
/>
<Typography variant="caption" color="text.secondary" sx={{ mt: 1, display: 'block' }}>
{t('resetsOn', { date: formatResetDate(limitData.resetDate) })}
</Typography>
</Box>
)}
{/* Limit Reached Message */}
<Box sx={{ mb: 4, textAlign: 'center' }}>
<Typography variant="body1" sx={{ mb: 2 }}>
{t('message')}
</Typography>
<Typography variant="body2" color="text.secondary">
{t('upgradePrompt')}
</Typography>
</Box>
{/* Premium Benefits */}
<Box
sx={{
bgcolor: 'primary.light',
borderRadius: 2,
p: 3,
mb: 3
}}
>
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
<AutoAwesome sx={{ color: 'primary.main', mr: 1 }} />
<Typography variant="h6" fontWeight="600">
{t('premiumTitle')}
</Typography>
</Box>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5 }}>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Box
sx={{
width: 6,
height: 6,
borderRadius: '50%',
bgcolor: 'primary.main',
mr: 1.5
}}
/>
<Typography variant="body2">
{t('benefits.unlimited')}
</Typography>
</Box>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Box
sx={{
width: 6,
height: 6,
borderRadius: '50%',
bgcolor: 'primary.main',
mr: 1.5
}}
/>
<Typography variant="body2">
{t('benefits.support')}
</Typography>
</Box>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<Box
sx={{
width: 6,
height: 6,
borderRadius: '50%',
bgcolor: 'primary.main',
mr: 1.5
}}
/>
<Typography variant="body2">
{t('benefits.early')}
</Typography>
</Box>
</Box>
<Box sx={{ mt: 2, display: 'flex', alignItems: 'center', gap: 1 }}>
<Typography variant="h5" fontWeight="700" color="primary.main">
$10
</Typography>
<Typography variant="body2" color="text.secondary">
{t('pricing')}
</Typography>
<Chip
label={t('savings')}
size="small"
color="success"
sx={{ ml: 'auto' }}
/>
</Box>
</Box>
</DialogContent>
<DialogActions sx={{ p: 3, pt: 0, flexDirection: 'column', gap: 2 }}>
<Button
variant="contained"
size="large"
fullWidth
startIcon={<Favorite />}
component={Link}
href={`/${locale}/subscription`}
onClick={onClose}
sx={{ py: 1.5 }}
>
{t('upgradeButton')}
</Button>
<Button
variant="text"
size="large"
fullWidth
onClick={onClose}
sx={{ py: 1 }}
>
{t('maybeLater')}
</Button>
</DialogActions>
</Dialog>
)
}