|
|
|
@ -11,27 +11,27 @@ interface UseBackupReminderOptions { |
|
|
|
} |
|
|
|
|
|
|
|
interface ReminderState { |
|
|
|
suppressed: boolean; |
|
|
|
lastShown: string; |
|
|
|
expires: string; |
|
|
|
} |
|
|
|
|
|
|
|
const TOAST_APPEAR_DELAY = 10_000; // 10 seconds
|
|
|
|
const TOAST_DURATION = 30_000; // 30 seconds
|
|
|
|
const ON_ACCEPT_REMINDER_DAYS = 365; |
|
|
|
const REMINDER_DAYS_ONE_WEEK = 7; |
|
|
|
const REMINDER_DAYS_ONE_YEAR = 365; |
|
|
|
const REMINDER_DAYS_FOREVER = 3650; |
|
|
|
const STORAGE_KEY = "key_backup_reminder"; |
|
|
|
|
|
|
|
function isReminderExpired(lastShown: string): boolean { |
|
|
|
const lastShownDate = new Date(lastShown); |
|
|
|
const now = new Date(); |
|
|
|
const daysSinceLastShown = (now.getTime() - lastShownDate.getTime()) / (1000 * 60 * 60 * 24); |
|
|
|
return daysSinceLastShown >= 7; |
|
|
|
function isReminderExpired(expires?: string): boolean { |
|
|
|
if (!expires) return true; |
|
|
|
const expiryDate = new Date(expires); |
|
|
|
return isNaN(expiryDate.getTime()) || new Date() >= expiryDate; |
|
|
|
} |
|
|
|
|
|
|
|
export function useBackupReminder({ |
|
|
|
reminderInDays = 7, |
|
|
|
enabled, |
|
|
|
message, |
|
|
|
onAccept = () => { }, |
|
|
|
reminderInDays = REMINDER_DAYS_ONE_WEEK, |
|
|
|
}: UseBackupReminderOptions) { |
|
|
|
const { toast } = useToast(); |
|
|
|
const toastShownRef = useRef(false); |
|
|
|
@ -40,24 +40,16 @@ export function useBackupReminder({ |
|
|
|
null |
|
|
|
); |
|
|
|
|
|
|
|
// Suppress reminder for 10 years if not specified
|
|
|
|
const suppressReminder = useCallback((days: number = 3563) => { |
|
|
|
const setReminderExpiry = useCallback((days: number) => { |
|
|
|
const expiryDate = new Date(); |
|
|
|
expiryDate.setDate(expiryDate.getDate() + days); |
|
|
|
|
|
|
|
setReminderState({ |
|
|
|
suppressed: true, |
|
|
|
lastShown: new Date().toISOString(), |
|
|
|
}); |
|
|
|
setReminderState({ expires: expiryDate.toISOString() }); |
|
|
|
}, [setReminderState]); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
if (!enabled || toastShownRef.current) return; |
|
|
|
|
|
|
|
const shouldShowReminder = |
|
|
|
!reminderState?.suppressed || isReminderExpired(reminderState.lastShown); |
|
|
|
|
|
|
|
if (!shouldShowReminder) return; |
|
|
|
if (!isReminderExpired(reminderState?.expires)) return; |
|
|
|
|
|
|
|
toastShownRef.current = true; |
|
|
|
|
|
|
|
@ -69,14 +61,13 @@ export function useBackupReminder({ |
|
|
|
action: ( |
|
|
|
<div className="flex flex-col gap-2"> |
|
|
|
<div className="flex gap-2"> |
|
|
|
|
|
|
|
<Button |
|
|
|
type="button" |
|
|
|
variant="outline" |
|
|
|
className="p-1" |
|
|
|
onClick={() => { |
|
|
|
dismiss(); |
|
|
|
suppressReminder(reminderInDays); |
|
|
|
setReminderExpiry(reminderInDays); |
|
|
|
}} |
|
|
|
> |
|
|
|
Remind me in {reminderInDays} days |
|
|
|
@ -87,42 +78,33 @@ export function useBackupReminder({ |
|
|
|
className="p-1" |
|
|
|
onClick={() => { |
|
|
|
dismiss(); |
|
|
|
suppressReminder(); |
|
|
|
setReminderExpiry(REMINDER_DAYS_FOREVER); |
|
|
|
}} |
|
|
|
> |
|
|
|
Never remind me |
|
|
|
</Button> |
|
|
|
</div> |
|
|
|
<div className="flex"> |
|
|
|
<Button |
|
|
|
type="button" |
|
|
|
variant="default" |
|
|
|
className="w-full" |
|
|
|
onClick={() => { |
|
|
|
onAccept(); |
|
|
|
dismiss(); |
|
|
|
suppressReminder(ON_ACCEPT_REMINDER_DAYS); |
|
|
|
}} |
|
|
|
> |
|
|
|
Back up now |
|
|
|
</Button> |
|
|
|
</div> |
|
|
|
<Button |
|
|
|
type="button" |
|
|
|
variant="default" |
|
|
|
className="w-full" |
|
|
|
onClick={() => { |
|
|
|
onAccept(); |
|
|
|
dismiss(); |
|
|
|
setReminderExpiry(REMINDER_DAYS_ONE_YEAR); |
|
|
|
}} |
|
|
|
> |
|
|
|
Back up now |
|
|
|
</Button> |
|
|
|
</div> |
|
|
|
), |
|
|
|
}); |
|
|
|
|
|
|
|
return () => { |
|
|
|
if (!toastShownRef.current) { |
|
|
|
dismiss(); |
|
|
|
} |
|
|
|
}; |
|
|
|
return () => dismiss(); |
|
|
|
}, [ |
|
|
|
enabled, |
|
|
|
message, |
|
|
|
onAccept, |
|
|
|
reminderInDays, |
|
|
|
suppressReminder, |
|
|
|
toast, |
|
|
|
reminderState, |
|
|
|
|
|
|
|
]); |
|
|
|
} |
|
|
|
}; |