- Unified localStorage key to 'theme-preference' across all components
- Fixed header.tsx using wrong localStorage key ('theme' instead of 'theme-preference')
- Added localStorage hybrid persistence for instant theme changes
- Removed router.refresh() which was causing stale data revert
- Replaced Blue theme with Sepia
- Consolidated auth() calls to prevent race conditions
- Updated UserSettingsData types to include all themes
351 lines
9.2 KiB
JSON
351 lines
9.2 KiB
JSON
{
|
|
"name": "Keep Notes - Reminder Notifications",
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"rule": {
|
|
"interval": [
|
|
{
|
|
"field": "cronExpression",
|
|
"expression": "0 */30 * * * *"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"id": "schedule-1",
|
|
"name": "Schedule (Every 30 min)",
|
|
"type": "n8n-nodes-base.scheduleTrigger",
|
|
"typeVersion": 1.2,
|
|
"position": [250, 300],
|
|
"description": "Check for reminders every 30 minutes"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "http://localhost:3000/api/notes",
|
|
"method": "GET",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
]
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "get-all-notes-1",
|
|
"name": "Get All Notes",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [500, 300]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "strict"
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "condition-1",
|
|
"leftValue": "={{ $json.reminder }}",
|
|
"rightValue": "true",
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "isNotEmpty"
|
|
}
|
|
},
|
|
{
|
|
"id": "condition-2",
|
|
"leftValue": "={{ $json.isReminderDone }}",
|
|
"rightValue": "false",
|
|
"operator": {
|
|
"type": "boolean",
|
|
"operation": "equals"
|
|
}
|
|
},
|
|
{
|
|
"id": "condition-3",
|
|
"leftValue": "={{ $json.reminder }}",
|
|
"rightValue": "={{ $now }}",
|
|
"operator": {
|
|
"type": "date",
|
|
"operation": "before"
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "filter-reminders-1",
|
|
"name": "Filter Active Reminders",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.1,
|
|
"position": [750, 300]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"fieldToSplitOut": "data",
|
|
"options": {}
|
|
},
|
|
"id": "split-1",
|
|
"name": "Split Reminders",
|
|
"type": "n8n-nodes-base.splitOut",
|
|
"typeVersion": 1,
|
|
"position": [1000, 300]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"channel": "={{ $json.notificationChannel || 'slack' }}",
|
|
"text": "🔔 **Reminder:** {{ $json.title || 'Untitled Note' }}\n\n{{ $json.content }}\n\n📍 Location: {{ $json.reminderLocation || 'N/A' }}\n🔗 View in Keep Notes: http://localhost:3000\n\n⏰ Reminder Time: {{ $json.reminder }}",
|
|
"otherOptions": {}
|
|
},
|
|
"id": "send-notification-1",
|
|
"name": "Send Notification",
|
|
"type": "n8n-nodes-base.slack",
|
|
"typeVersion": 2.1,
|
|
"position": [1250, 300],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"channel": "={{ $json.notificationEmail }}",
|
|
"subject": "🔔 Reminder: {{ $json.title || 'Untitled Note' }}",
|
|
"emailType": "html",
|
|
"message": "<h2>🔔 Reminder</h2>\n\n<h3>{{ $json.title || 'Untitled Note' }}</h3>\n\n<p>{{ $json.content }}</p>\n\n<strong>Location:</strong> {{ $json.reminderLocation || 'N/A' }}<br>\n<strong>Reminder Time:</strong> {{ $json.reminder }}<br>\n<br>\n<a href=\"http://localhost:3000\">View in Keep Notes</a>",
|
|
"options": {}
|
|
},
|
|
"id": "send-email-1",
|
|
"name": "Send Email",
|
|
"type": "n8n-nodes-base.emailSend",
|
|
"typeVersion": 2.1,
|
|
"position": [1250, 450],
|
|
"continueOnFail": true
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "http://localhost:3000/api/notes/{{ $json.id }}",
|
|
"method": "PUT",
|
|
"bodyParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "isReminderDone",
|
|
"value": "true"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"id": "mark-done-1",
|
|
"name": "Mark Reminder as Done",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [1500, 300],
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "strict"
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "condition-4",
|
|
"leftValue": "={{ $json.reminderRecurrence }}",
|
|
"rightValue": "",
|
|
"operator": {
|
|
"type": "string",
|
|
"operation": "isNotEmpty"
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "check-recurrence-1",
|
|
"name": "Check Recurrence",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.1,
|
|
"position": [1750, 300]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"jsCode": "// Calculate next reminder date based on recurrence\nconst { reminderRecurrence, reminder } = $input.item.json;\nconst reminderDate = new Date(reminder);\n\nlet nextReminder;\nswitch (reminderRecurrence) {\n case 'daily':\n nextReminder = new Date(reminderDate.setDate(reminderDate.getDate() + 1));\n break;\n case 'weekly':\n nextReminder = new Date(reminderDate.setDate(reminderDate.getDate() + 7));\n break;\n case 'monthly':\n nextReminder = new Date(reminderDate.setMonth(reminderDate.getMonth() + 1));\n break;\n case 'yearly':\n nextReminder = new Date(reminderDate.setFullYear(reminderDate.getFullYear() + 1));\n break;\n default:\n nextReminder = reminderDate;\n}\n\nreturn {\n json: {\n ...$input.item.json,\n nextReminder: nextReminder.toISOString(),\n isReminderDone: false\n }\n};"
|
|
},
|
|
"id": "calculate-next-1",
|
|
"name": "Calculate Next Reminder",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [2000, 300]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"url": "http://localhost:3000/api/notes/{{ $json.id }}",
|
|
"method": "PUT",
|
|
"bodyParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "reminder",
|
|
"value": "={{ $json.nextReminder }}"
|
|
},
|
|
{
|
|
"name": "isReminderDone",
|
|
"value": "false"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"id": "update-recurrence-1",
|
|
"name": "Update Recurring Reminder",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.2,
|
|
"position": [2250, 300],
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Content-Type",
|
|
"value": "application/json"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
],
|
|
"connections": {
|
|
"Schedule (Every 30 min)": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Get All Notes",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Get All Notes": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Filter Active Reminders",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Filter Active Reminders": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Split Reminders",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Split Reminders": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Send Notification",
|
|
"type": "main",
|
|
"index": 0
|
|
},
|
|
{
|
|
"node": "Send Email",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Send Notification": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Mark Reminder as Done",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Send Email": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Mark Reminder as Done",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Mark Reminder as Done": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Check Recurrence",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Check Recurrence": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Calculate Next Reminder",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Calculate Next Reminder": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Update Recurring Reminder",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"pinData": {},
|
|
"settings": {
|
|
"executionOrder": "v1"
|
|
},
|
|
"staticData": null,
|
|
"tags": [
|
|
{
|
|
"createdAt": "2026-01-18T00:00:00.000Z",
|
|
"id": "keep-notes-mcp",
|
|
"name": "Keep Notes MCP"
|
|
}
|
|
],
|
|
"triggerCount": 0,
|
|
"updatedAt": "2026-01-18T00:00:00.000Z",
|
|
"versionId": "1"
|
|
}
|