diff --git a/.gitignore b/.gitignore
index 500da9a..4edd951 100644
--- a/.gitignore
+++ b/.gitignore
@@ -40,3 +40,6 @@ next-env.d.ts
# mongo
/mongo
+
+# Local Netlify folder
+.netlify
diff --git a/netlify/functions/notif.mts b/netlify/functions/notif.mts
new file mode 100644
index 0000000..80655ce
--- /dev/null
+++ b/netlify/functions/notif.mts
@@ -0,0 +1,116 @@
+// netlify/functions/hello.mts
+import { Handler } from '@netlify/functions';
+import { Config } from '@netlify/functions';
+import juno from "juno-sdk";
+import NotificationModel from "../../src/server/db/models/NotificationModel";
+import dbConnect from "../../src/server/db/dbConnect";
+import CommentModel from "../../src/server/db/models/CommentModel";
+import PostModel from "../../src/server/db/models/PostModel";
+import UserModel from "../../src/server/db/models/UserModel";
+import { deleteNotification } from "../../src/server/db/actions/NotificationActions";
+import { PopulatedComment } from "../../src/utils/types/comment";
+
+async function generateEmailContents(commentIds: string[]) {
+ const postsToComments: { [postId: string]: PopulatedComment[] } = {};
+ let content = "";
+ const comments = await CommentModel.find({ _id: { $in: commentIds } }).populate('author');
+ for (const comment of comments) {
+ const postId = comment.post._id.toString();
+ if (!postsToComments[postId]) {
+ postsToComments[postId] = [];
+ }
+ postsToComments[postId].push(comment);
+ }
+ for (const postId in postsToComments) {
+ const post = await PostModel.findById(postId); // Fetch the post title
+ if (post) {
+ content += `${post.title}
`;
+ const postComments = postsToComments[postId];
+ for (const comment of postComments) {
+ content += `${comment.author?.lastName} family commented: ${comment.content}
`;
+ }
+ content += "
";
+ }
+ }
+ return {
+ type: "text/html",
+ value: content,
+ };
+}
+
+const handler: Handler = async (event, context) => {
+ try {
+ juno.init({
+ apiKey: process.env.JUNO_API_KEY as string,
+ baseURL: "https://api-gateway.whitesmoke-cea9a269.eastus.azurecontainerapps.io"
+ });
+
+ await dbConnect();
+ const notifications = await NotificationModel.find({});
+ const usersToNotify: { [userId: string]: string[] } = {};
+
+ for (const notification of notifications) {
+ const userId = notification.author.toString();
+ if (!usersToNotify[userId]) {
+ usersToNotify[userId] = [];
+ }
+ usersToNotify[userId].push(notification.comment.toString());
+ }
+
+ for (const userId in usersToNotify) {
+ const user = await UserModel.findById(userId);
+ if (!user || !user.email || !user.notificationPreference) {
+ for (const commentId of usersToNotify[userId]) {
+ try {
+ await deleteNotification(commentId);
+ } catch (error) {
+ console.error(`Failed to delete notification for comment ${commentId}:`, error);
+ }
+ }
+ } else {
+ const emailContents = await generateEmailContents(usersToNotify[userId]);
+ const response = await juno.email.sendEmail({
+ recipients: [
+ {
+ email: `{user.email}`,
+ name: `{user.lastName} Family`,
+ },
+ ],
+ bcc: [],
+ cc: [],
+ sender: {
+ email: process.env.JUNO_SENDER_EMAIL as string,
+ name: process.env.JUNO_SENDER_NAME as string,
+ },
+ subject: "FOCUS Community Updates", // TODO: update
+ contents: [emailContents],
+ });
+
+ // delete notifications associated with successfully sent emails
+ for (const commentId of usersToNotify[userId]) {
+ try {
+ await deleteNotification(commentId);
+ } catch (error) {
+ console.error(`Failed to delete notification for comment ${commentId}:`, error);
+ }
+ }
+ }
+ }
+
+ return {
+ statusCode: 200,
+ body: JSON.stringify({ message: "Successfully sent email" }),
+ };
+ } catch (error) {
+ console.error("Error occurred:", error);
+ return {
+ statusCode: 500,
+ body: JSON.stringify({ error: "Internal Server Error" }),
+ };
+ }
+};
+export { handler };
+
+export const config: Config = {
+ schedule: "0 17 * * *" // schedule function to run at 5pm UTC every day
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index d374f07..12731be 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,6 +10,7 @@
"dependencies": {
"@heroicons/react": "^2.1.5",
"@mdxeditor/editor": "^3.11.5",
+ "@netlify/functions": "^2.8.2",
"@radix-ui/react-alert-dialog": "^1.1.2",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
@@ -33,6 +34,7 @@
"cmdk": "^1.0.0",
"html-to-react": "^1.7.0",
"iron-session": "^8.0.3",
+ "juno-sdk": "^0.0.5",
"lucide-react": "^0.441.0",
"markdown-it": "^14.1.0",
"markdown-it-fancy-lists": "^1.3.0",
@@ -522,6 +524,14 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@bitauth/libauth": {
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/@bitauth/libauth/-/libauth-1.19.1.tgz",
+ "integrity": "sha512-R524tD5VwOt3QRHr7N518nqTVR/HKgfWL4LypekcGuNQN8R4PWScvuRcRzrY39A28kLztMv+TJdiKuMNbkU1ug==",
+ "engines": {
+ "node": ">=8.9"
+ }
+ },
"node_modules/@bitwarden/cli": {
"version": "2024.8.1",
"resolved": "https://registry.npmjs.org/@bitwarden/cli/-/cli-2024.8.1.tgz",
@@ -1767,6 +1777,37 @@
"sparse-bitfield": "^3.0.3"
}
},
+ "node_modules/@netlify/functions": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/@netlify/functions/-/functions-2.8.2.tgz",
+ "integrity": "sha512-DeoAQh8LuNPvBE4qsKlezjKj0PyXDryOFJfJKo3Z1qZLKzQ21sT314KQKPVjfvw6knqijj+IO+0kHXy/TJiqNA==",
+ "dependencies": {
+ "@netlify/serverless-functions-api": "1.26.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@netlify/node-cookies": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@netlify/node-cookies/-/node-cookies-0.1.0.tgz",
+ "integrity": "sha512-OAs1xG+FfLX0LoRASpqzVntVV/RpYkgpI0VrUnw2u0Q1qiZUzcPffxRK8HF3gc4GjuhG5ahOEMJ9bswBiZPq0g==",
+ "engines": {
+ "node": "^14.16.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@netlify/serverless-functions-api": {
+ "version": "1.26.1",
+ "resolved": "https://registry.npmjs.org/@netlify/serverless-functions-api/-/serverless-functions-api-1.26.1.tgz",
+ "integrity": "sha512-q3L9i3HoNfz0SGpTIS4zTcKBbRkxzCRpd169eyiTuk3IwcPC3/85mzLHranlKo2b+HYT0gu37YxGB45aD8A3Tw==",
+ "dependencies": {
+ "@netlify/node-cookies": "^0.1.0",
+ "urlpattern-polyfill": "8.0.2"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/@next/eslint-plugin-next": {
"version": "14.2.5",
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.5.tgz",
@@ -3953,7 +3994,6 @@
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -4234,6 +4274,22 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/asn1": {
+ "version": "0.2.6",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
+ "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
+ "dependencies": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "node_modules/assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/ast-types-flow": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
@@ -4243,8 +4299,7 @@
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
- "dev": true
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/available-typed-arrays": {
"version": "1.0.7",
@@ -4261,6 +4316,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/aws4": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz",
+ "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="
+ },
"node_modules/axe-core": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz",
@@ -4312,6 +4380,14 @@
}
]
},
+ "node_modules/bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
+ "dependencies": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
"node_modules/big-integer": {
"version": "1.6.51",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
@@ -4542,6 +4618,11 @@
}
]
},
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
+ },
"node_modules/ccount": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
@@ -5251,7 +5332,6 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
- "dev": true,
"dependencies": {
"delayed-stream": "~1.0.0"
},
@@ -5432,6 +5512,17 @@
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
"dev": true
},
+ "node_modules/dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/data-urls": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
@@ -5652,7 +5743,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
- "dev": true,
"engines": {
"node": ">=0.4.0"
}
@@ -5840,6 +5930,15 @@
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
},
+ "node_modules/ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
+ "dependencies": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -6673,6 +6772,14 @@
"node": ">=4"
}
},
+ "node_modules/extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
+ "engines": [
+ "node >=0.6.0"
+ ]
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -6707,8 +6814,7 @@
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
@@ -6854,6 +6960,14 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
@@ -7036,6 +7150,14 @@
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
}
},
+ "node_modules/getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ }
+ },
"node_modules/glob": {
"version": "10.3.10",
"resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
@@ -7164,6 +7286,27 @@
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
"dev": true
},
+ "node_modules/har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/har-validator": {
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+ "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+ "deprecated": "this library is no longer supported",
+ "dependencies": {
+ "ajv": "^6.12.3",
+ "har-schema": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/has-bigints": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
@@ -7418,6 +7561,20 @@
"node": ">= 14"
}
},
+ "node_modules/http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ },
+ "engines": {
+ "node": ">=0.8",
+ "npm": ">=1.3.7"
+ }
+ },
"node_modules/https-proxy-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz",
@@ -8192,6 +8349,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
+ },
"node_modules/is-unicode-supported": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
@@ -8277,6 +8439,11 @@
"url": "https://github.com/sponsors/dmonad"
}
},
+ "node_modules/isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
+ },
"node_modules/iterator.prototype": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz",
@@ -8331,6 +8498,11 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
+ },
"node_modules/jsdom": {
"version": "24.1.1",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.1.tgz",
@@ -8427,11 +8599,15 @@
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"dev": true
},
+ "node_modules/json-schema": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
+ },
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"node_modules/json-stable-stringify-without-jsonify": {
"version": "1.0.1",
@@ -8442,8 +8618,7 @@
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
- "dev": true
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
},
"node_modules/json5": {
"version": "1.0.2",
@@ -8457,6 +8632,20 @@
"json5": "lib/cli.js"
}
},
+ "node_modules/jsprim": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
+ "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
+ "dependencies": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.4.0",
+ "verror": "1.10.0"
+ },
+ "engines": {
+ "node": ">=0.6.0"
+ }
+ },
"node_modules/jsx-ast-utils": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
@@ -8484,6 +8673,18 @@
"setimmediate": "^1.0.5"
}
},
+ "node_modules/juno-sdk": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/juno-sdk/-/juno-sdk-0.0.5.tgz",
+ "integrity": "sha512-JJayvnYeuF8sjRV4HFtpMslZIwsWvCPcW3WxY1TXr4IM+tUpMc4sEhW02haBQJ5YEKCG/1HjLcPP9FjufpyZ4g==",
+ "dependencies": {
+ "@bitauth/libauth": "^1.17.1",
+ "request": "^2.88.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/kareem": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
@@ -10154,7 +10355,6 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dev": true,
"dependencies": {
"mime-db": "1.52.0"
},
@@ -10611,6 +10811,14 @@
"integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==",
"dev": true
},
+ "node_modules/oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "engines": {
+ "node": "*"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -11078,6 +11286,11 @@
"node": ">=8"
}
},
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
+ },
"node_modules/picocolors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
@@ -11532,8 +11745,7 @@
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
- "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==",
- "dev": true
+ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
},
"node_modules/punycode": {
"version": "2.3.1",
@@ -11972,6 +12184,79 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/request": {
+ "version": "2.88.2",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
+ "dependencies": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/request/node_modules/form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/request/node_modules/qs": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
+ "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/request/node_modules/tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dependencies": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/request/node_modules/uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -12182,7 +12467,6 @@
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -12218,8 +12502,7 @@
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
- "dev": true
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sass": {
"version": "1.79.3",
@@ -12471,6 +12754,30 @@
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="
},
+ "node_modules/sshpk": {
+ "version": "1.18.0",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz",
+ "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==",
+ "dependencies": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ },
+ "bin": {
+ "sshpk-conv": "bin/sshpk-conv",
+ "sshpk-sign": "bin/sshpk-sign",
+ "sshpk-verify": "bin/sshpk-verify"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/static-browser-server": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/static-browser-server/-/static-browser-server-1.0.3.tgz",
@@ -13129,6 +13436,22 @@
"node": ">=0.6.x"
}
},
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
+ },
"node_modules/type": {
"version": "2.7.3",
"resolved": "https://registry.npmjs.org/type/-/type-2.7.3.tgz",
@@ -13448,7 +13771,6 @@
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
"dependencies": {
"punycode": "^2.1.0"
}
@@ -13463,6 +13785,11 @@
"requires-port": "^1.0.0"
}
},
+ "node_modules/urlpattern-polyfill": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz",
+ "integrity": "sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ=="
+ },
"node_modules/use-callback-ref": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.2.tgz",
@@ -13534,6 +13861,24 @@
"node": ">= 0.8"
}
},
+ "node_modules/verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "node_modules/verror/node_modules/core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
+ },
"node_modules/vfile": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
diff --git a/package.json b/package.json
index aebed41..9a88faa 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"dependencies": {
"@heroicons/react": "^2.1.5",
"@mdxeditor/editor": "^3.11.5",
+ "@netlify/functions": "^2.8.2",
"@radix-ui/react-alert-dialog": "^1.1.2",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
@@ -24,7 +25,6 @@
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.1",
- "@radix-ui/react-alert-dialog": "^1.1.2",
"@radix-ui/react-toast": "^1.2.1",
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
@@ -40,6 +40,7 @@
"cmdk": "^1.0.0",
"html-to-react": "^1.7.0",
"iron-session": "^8.0.3",
+ "juno-sdk": "^0.0.5",
"lucide-react": "^0.441.0",
"markdown-it": "^14.1.0",
"markdown-it-fancy-lists": "^1.3.0",
diff --git a/src/app/(auth)/layout.tsx b/src/app/(auth)/layout.tsx
index f55c083..7aa8ff9 100644
--- a/src/app/(auth)/layout.tsx
+++ b/src/app/(auth)/layout.tsx
@@ -1,7 +1,7 @@
import type { Metadata } from "next";
import "@/app/globals.css";
import { ReactNode } from "react";
-import { FOCUS_FONT } from "@/utils/consts";
+import { FOCUS_FONT } from "@/utils/styles";
export const metadata: Metadata = {
title: "Focus Community Platform",
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index e599788..b845b7c 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,7 +1,7 @@
import type { Metadata } from "next";
import "./globals.css";
import { ReactNode } from "react";
-import { FOCUS_FONT } from "@/utils/consts";
+import { FOCUS_FONT } from "@/utils/styles";
import Head from 'next/head';
export const metadata: Metadata = {
diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx
index 8a1a149..df92a6a 100644
--- a/src/app/not-found.tsx
+++ b/src/app/not-found.tsx
@@ -1,7 +1,7 @@
import ErrorPageButtons from "@/components/ErrorPageButtons";
import Image from 'next/image';
import focusLogo from "../../public/focus-logo.png";
-import { FOCUS_FONT } from "@/utils/consts";
+import { FOCUS_FONT } from "@/utils/styles";
import { Metadata } from "next";
export const metadata: Metadata = {
diff --git a/src/server/db/actions/NotificationActions.ts b/src/server/db/actions/NotificationActions.ts
new file mode 100644
index 0000000..db70a8e
--- /dev/null
+++ b/src/server/db/actions/NotificationActions.ts
@@ -0,0 +1,36 @@
+'use server'
+
+import { NotificationInput, notificationSchema } from "@/utils/types/notification";
+import NotificationModel from "../models/NotificationModel";
+import dbConnect from "../dbConnect";
+import mongoose from "mongoose";
+
+export async function createNotification(notification: NotificationInput): Promise {
+ try {
+ await dbConnect();
+ const parsedData = notificationSchema.parse(notification);
+ const createdNotification = await NotificationModel.create(parsedData);
+
+ return createdNotification.toObject();
+ } catch (e) {
+ console.log(e)
+ throw new Error("Failed to create notification");
+ }
+}
+
+export async function deleteNotification(comment_id: string): Promise {
+ try {
+ await dbConnect();
+ if (!mongoose.Types.ObjectId.isValid(comment_id)) {
+ throw new Error("Invalid comment ID");
+ }
+
+ const result = await NotificationModel.findOneAndDelete({ comment: comment_id });
+
+ if (!result) {
+ throw new Error("Notification not found");
+ }
+ } catch (e) {
+ throw new Error("Failed to delete notification");
+ }
+}
\ No newline at end of file
diff --git a/src/server/db/models/CommentModel.ts b/src/server/db/models/CommentModel.ts
index 08427da..7ac880f 100644
--- a/src/server/db/models/CommentModel.ts
+++ b/src/server/db/models/CommentModel.ts
@@ -1,14 +1,35 @@
import mongoose, { Schema } from "mongoose";
import { Comment } from "@/utils/types/comment";
+import PostModel from "./PostModel";
+import { createNotification } from "../actions/NotificationActions";
const CommentSchema = new Schema({
- author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
- post: { type: Schema.Types.ObjectId, ref: 'Post', required: true },
- date: { type: Date, default: Date.now() },
- content: { type: String, required: true },
- likes: { type: Number, default: 0 },
- replyTo: { type: Schema.Types.ObjectId, ref: 'Comment', default: null },
- isDeleted: { type: Boolean, default: false }
+ author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
+ post: { type: Schema.Types.ObjectId, ref: 'Post', required: true },
+ date: { type: Date, default: Date.now() },
+ content: { type: String, required: true },
+ likes: { type: Number, default: 0 },
+ replyTo: { type: Schema.Types.ObjectId, ref: 'Comment', default: null },
+ isDeleted: { type: Boolean, default: false }
+});
+
+CommentSchema.post("save", async function (comment) {
+ try {
+ const post = await PostModel.findById(comment.post).populate("author");
+ if (post?.author && post.author.notificationPreference && post.author._id.toString() != comment.author.toString()) {
+ // Create a notification
+ await createNotification({
+ author: post.author._id.toString(),
+ post: post._id.toString(),
+ comment: comment._id.toString(),
+ commenter: comment.author.toString(),
+ createdAt: comment.date,
+ });
+ }
+
+ } catch (error) {
+ console.error("Error in post save hook:", error);
+ }
});
const CommentModel = mongoose.models.Comment || mongoose.model("Comment", CommentSchema);
diff --git a/src/server/db/models/NotificationModel.ts b/src/server/db/models/NotificationModel.ts
new file mode 100644
index 0000000..91d4b82
--- /dev/null
+++ b/src/server/db/models/NotificationModel.ts
@@ -0,0 +1,14 @@
+import mongoose, { Schema } from "mongoose";
+import { AppNotification } from "@/utils/types/notification";
+
+const NotificationSchema = new Schema({
+ author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
+ post: { type: Schema.Types.ObjectId, ref: 'Post', required: true },
+ comment: { type: Schema.Types.ObjectId, ref: 'Comment', required: true},
+ commenter: { type: Schema.Types.ObjectId, ref: 'User', required: true},
+ createdAt: { type: Date, default: Date.now() },
+})
+
+const NotificationModel = mongoose.models.Notification || mongoose.model("Notification", NotificationSchema);
+
+export default NotificationModel;
\ No newline at end of file
diff --git a/src/utils/consts.ts b/src/utils/consts.ts
index 2470771..47ed8f7 100644
--- a/src/utils/consts.ts
+++ b/src/utils/consts.ts
@@ -7,11 +7,6 @@ export const MAX_FILTER_DISABILITY_TAGS = 3;
export const PAGINATION_LIMIT = 10;
-export const FOCUS_FONT = Lato({
- subsets: ['latin'],
- weight: ['100', '300', '400', '700', '900'],
-});
-
export enum PostDeletionTimeline {
OneMonth = '1 month',
ThreeMonths = '3 months',
diff --git a/src/utils/styles.ts b/src/utils/styles.ts
new file mode 100644
index 0000000..be8cc66
--- /dev/null
+++ b/src/utils/styles.ts
@@ -0,0 +1,6 @@
+import { Lato } from "next/font/google";
+
+export const FOCUS_FONT = Lato({
+ subsets: ['latin'],
+ weight: ['100', '300', '400', '700', '900'],
+});
diff --git a/src/utils/types/notification.ts b/src/utils/types/notification.ts
new file mode 100644
index 0000000..7de5a82
--- /dev/null
+++ b/src/utils/types/notification.ts
@@ -0,0 +1,14 @@
+import { z } from "zod";
+import { Types } from "mongoose";
+import { ExtendId } from "./common";
+
+export const notificationSchema = z.object({
+ author: z.string().transform(id => new Types.ObjectId(id)),
+ post: z.string().transform(id => new Types.ObjectId(id)),
+ comment: z.string().transform(id => new Types.ObjectId(id)),
+ commenter: z.string().transform(id => new Types.ObjectId(id)),
+ createdAt: z.date().default(new Date()),
+})
+
+export type AppNotification = ExtendId>;
+export type NotificationInput = z.input;
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 7b28589..f33544b 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -21,6 +21,6 @@
"@/*": ["./src/*"]
}
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ""],
"exclude": ["node_modules"]
}