Add Daily Digest notification preferences with custom time support
- Add daily_digest boolean and daily_digest_hour fields to NotificationPreference model - Update HandleDailyDigest to check user preferences and custom notification times - Change Daily Digest scheduler to run hourly (supports per-user custom times) - Update notification service DTOs for new fields - Add Daily Digest toggle and custom time to admin notification prefs page - Fix notification handlers to only notify users at their designated hour 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -164,6 +164,16 @@ export default function NotificationPrefsPage() {
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'daily_digest',
|
||||
header: 'Daily Digest',
|
||||
cell: ({ row }) => (
|
||||
<Switch
|
||||
checked={row.original.daily_digest}
|
||||
onCheckedChange={() => handleToggle(row.original.id, 'daily_digest', row.original.daily_digest)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
accessorKey: 'email_task_completed',
|
||||
header: 'Email: Completed',
|
||||
@@ -183,8 +193,8 @@ export default function NotificationPrefsPage() {
|
||||
</div>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const { task_due_soon_hour, task_overdue_hour, warranty_expiring_hour } = row.original;
|
||||
const hasCustomTimes = task_due_soon_hour !== null || task_overdue_hour !== null || warranty_expiring_hour !== null;
|
||||
const { task_due_soon_hour, task_overdue_hour, warranty_expiring_hour, daily_digest_hour } = row.original;
|
||||
const hasCustomTimes = task_due_soon_hour !== null || task_overdue_hour !== null || warranty_expiring_hour !== null || daily_digest_hour !== null;
|
||||
|
||||
if (!hasCustomTimes) {
|
||||
return <span className="text-muted-foreground text-sm">Default</span>;
|
||||
@@ -207,6 +217,11 @@ export default function NotificationPrefsPage() {
|
||||
<span className="text-muted-foreground">Warranty:</span> {formatHour(warranty_expiring_hour)}
|
||||
</div>
|
||||
)}
|
||||
{daily_digest_hour !== null && (
|
||||
<div className="text-xs">
|
||||
<span className="text-muted-foreground">Daily Digest:</span> {formatHour(daily_digest_hour)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -597,12 +597,14 @@ export interface NotificationPreference {
|
||||
task_assigned: boolean;
|
||||
residence_shared: boolean;
|
||||
warranty_expiring: boolean;
|
||||
daily_digest: boolean;
|
||||
// Email preferences
|
||||
email_task_completed: boolean;
|
||||
// Custom notification times (UTC hour 0-23, null means use system default)
|
||||
task_due_soon_hour: number | null;
|
||||
task_overdue_hour: number | null;
|
||||
warranty_expiring_hour: number | null;
|
||||
daily_digest_hour: number | null;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
@@ -622,8 +624,11 @@ export interface UpdateNotificationPrefRequest {
|
||||
task_assigned?: boolean;
|
||||
residence_shared?: boolean;
|
||||
warranty_expiring?: boolean;
|
||||
daily_digest?: boolean;
|
||||
// Email preferences
|
||||
email_task_completed?: boolean;
|
||||
// Custom notification times
|
||||
daily_digest_hour?: number | null;
|
||||
}
|
||||
|
||||
// Notification Preferences API
|
||||
|
||||
Reference in New Issue
Block a user