cover me email request routine
This commit is contained in:
1
package-lock.json
generated
1
package-lock.json
generated
@ -80,6 +80,7 @@
|
||||
"tailwindcss": "^3.4.1",
|
||||
"tw-elements": "^1.1.0",
|
||||
"typescript": "^5",
|
||||
"uuid": "^9.0.1",
|
||||
"webpack-bundle-analyzer": "^4.10.1",
|
||||
"winston": "^3.11.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz",
|
||||
|
@ -97,6 +97,7 @@
|
||||
"tailwindcss": "^3.4.1",
|
||||
"tw-elements": "^1.1.0",
|
||||
"typescript": "^5",
|
||||
"uuid": "^9.0.1",
|
||||
"webpack-bundle-analyzer": "^4.10.1",
|
||||
"winston": "^3.11.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.19.1/xlsx-0.19.1.tgz",
|
||||
@ -109,4 +110,4 @@
|
||||
"depcheck": "^1.4.7",
|
||||
"prisma": "^5.11.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { createRouter, expressWrapper } from "next-connect";
|
||||
const common = require('../../src/helpers/common');
|
||||
const emailHelper = require('../../src/helpers/email');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
@ -24,125 +25,60 @@ const router = createRouter<NextApiRequest, NextApiResponse>();
|
||||
export default async function handler(req, res) {
|
||||
const prisma = common.getPrismaClient();
|
||||
|
||||
var action = req.query.action;
|
||||
const action = req.query.action;
|
||||
const emailaction = req.query.emailaction;
|
||||
// Retrieve and validate the JWT token
|
||||
const token = await getToken({ req: req });
|
||||
|
||||
//response is a special action that does not require a token
|
||||
if (action !== "email_response") {
|
||||
if (!token) {
|
||||
// If no token or invalid token, return unauthorized status
|
||||
return res.status(401).json({ message: "Unauthorized to call this API endpoint" });
|
||||
}
|
||||
}
|
||||
|
||||
var userId = req.query.userId;
|
||||
var email = req.query.email;
|
||||
let date = new Date();
|
||||
|
||||
if (!userId && !email) {
|
||||
return res.status(400).json({ message: "User ID or email is not provided" });
|
||||
}
|
||||
// Retrieve the user
|
||||
const user = await prisma.publisher.findUnique({
|
||||
where: {
|
||||
id: userId,
|
||||
email: email
|
||||
}
|
||||
});
|
||||
if (!user) {
|
||||
return res.status(404).json({ message: "User not found" });
|
||||
}
|
||||
var emailaction = req.query.emailaction;
|
||||
switch (action) {
|
||||
case "send_coverme_request":
|
||||
// Send CoverMe request to the user
|
||||
//get from POST data: shiftId, assignmentId, date
|
||||
let shiftId = req.body.shiftId;
|
||||
let assignmentId = req.body.assignmentId;
|
||||
let date = req.body.date;
|
||||
|
||||
console.log("User: " + user.email + " sent a CoverMe request: " +
|
||||
shiftId + " " + assignmentId + " " + date);
|
||||
|
||||
//get all subscribed publisers
|
||||
const subscribedPublishers = await prisma.publisher.findMany({
|
||||
where: {
|
||||
isSubscribedToCoverMe: true
|
||||
}
|
||||
});
|
||||
//send email to all subscribed publishers
|
||||
for (let i = 0; i < subscribedPublishers.length; i++) {
|
||||
//send email to subscribed publisher
|
||||
let shift = await prisma.shift.findUnique({
|
||||
where: {
|
||||
id: parseInt(shiftId)
|
||||
},
|
||||
include: {
|
||||
cartEvent: {
|
||||
include: {
|
||||
location: true
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
let acceptUrl = process.env.NEXTAUTH_URL + "/api/emailActions?action=coverme_accept&userId=" + user.id + "&shiftId=" + shiftId + "&assignmentId=" + assignmentId;
|
||||
|
||||
let model = {
|
||||
user: user,
|
||||
shiftId: shiftId,
|
||||
assignmentId: assignmentId,
|
||||
acceptUrl: acceptUrl,
|
||||
prefix: subscribedPublishers[i].isMale ? "Брат" : "Сестра",
|
||||
firstName: subscribedPublishers[i].firstName,
|
||||
lastName: subscribedPublishers[i].lastName,
|
||||
placeName: shift.cartEvent.location.name,
|
||||
dateStr: date.toLocaleDateString(),
|
||||
sentDate: date.toLocaleTimeString()
|
||||
};
|
||||
emailHelper.SendEmailHandlebars(subscribedPublishers[i].email, "coverMe", model);
|
||||
}
|
||||
|
||||
break;
|
||||
case "email_response":
|
||||
//get email action
|
||||
if (!emailaction) {
|
||||
return res.status(400).json({ message: "Email action is not provided" });
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return res.status(400).json({ message: "Invalid action" });
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (action !== "email_response") {
|
||||
if (action == "email_response") {
|
||||
switch (emailaction) {
|
||||
case "coverme_accept":
|
||||
// Update the user status to accepted
|
||||
console.log("User: " + user.firstName + " " + user.lastName + " accepted the CoverMe request");
|
||||
case "coverMeAccept":
|
||||
//validate shiftId and assignmentId
|
||||
let shiftId = req.query.shiftId;
|
||||
let assignmentId = req.query.assignmentId;
|
||||
if (!shiftId || !assignmentId) {
|
||||
return res.status(400).json({ message: "Shift ID or Assignment ID is not provided" });
|
||||
}
|
||||
|
||||
//get the assignment
|
||||
const assignment = await prisma.assignment.findUnique({
|
||||
let userId = req.query.userId;
|
||||
let user = await prisma.publisher.findUnique({
|
||||
where: {
|
||||
id: parseInt(assignmentId)
|
||||
id: userId
|
||||
}
|
||||
});
|
||||
// Update the user status to accepted
|
||||
console.log("User: " + user.firstName + " " + user.lastName + " accepted the CoverMe request");
|
||||
|
||||
let assignmentPID = req.query.assignmentPID;
|
||||
if (!shiftId) {
|
||||
return res.status(400).json({ message: "Shift ID is not provided" });
|
||||
}
|
||||
if (!assignmentPID) {
|
||||
return res.status(400).json({ message: "Assignment PID is not provided" });
|
||||
}
|
||||
//check if the assignment request is still open
|
||||
const assignment = await prisma.assignment.findFirst({
|
||||
where: {
|
||||
publicGuid: assignmentPID,
|
||||
shiftId: parseInt(shiftId),
|
||||
isConfirmed: false
|
||||
},
|
||||
include: {
|
||||
shift: {
|
||||
include: {
|
||||
cartEvent: {
|
||||
include: {
|
||||
location: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!assignment) {
|
||||
return res.status(404).json({ message: "Assignment not found" });
|
||||
}
|
||||
if (assignment.shiftId != parseInt(shiftId)) {
|
||||
return res.status(400).json({ message: "Shift ID does not match" });
|
||||
const messagePageUrl = `/message?message=${encodeURIComponent('Някой друг вече е отговорил на рази заявка за заместване')}&type=info&caption=${encodeURIComponent('Заявката е вече обработена')}`;
|
||||
res.redirect(messagePageUrl);
|
||||
return;
|
||||
}
|
||||
|
||||
emailHelper.SendEmail_NewShifts(user, [assignment.shift]);
|
||||
|
||||
// await prisma.user.update({
|
||||
// where: {
|
||||
// id: parseInt(userId)
|
||||
@ -189,13 +125,109 @@ export default async function handler(req, res) {
|
||||
// const emailResponse = await common.sendEmail(user.email, "Email Action Processed",
|
||||
// "Your email action was processed successfully");
|
||||
}
|
||||
return res.status(200).json({ message: "User action processed" });
|
||||
}
|
||||
else {
|
||||
|
||||
const token = await getToken({ req: req });
|
||||
if (!token) {
|
||||
// If no token or invalid token, return unauthorized status
|
||||
return res.status(401).json({ message: "Unauthorized to call this API endpoint" });
|
||||
}
|
||||
|
||||
const user = await prisma.publisher.findUnique({
|
||||
where: {
|
||||
email: token.email
|
||||
}
|
||||
});
|
||||
|
||||
switch (action) {
|
||||
case "sendCoverMeRequestByEmail":
|
||||
// Send CoverMe request to the user
|
||||
//get from POST data: shiftId, assignmentId, date
|
||||
//let shiftId = req.body.shiftId;
|
||||
let assignmentId = req.body.assignmentId;
|
||||
let date = req.body.date;
|
||||
|
||||
console.log("User: " + user.email + " sent a 'CoverMe' request for his assignment " + assignmentId + " " + date);
|
||||
|
||||
let assignment = await prisma.assignment.findUnique({
|
||||
where: {
|
||||
id: parseInt(assignmentId)
|
||||
},
|
||||
include: {
|
||||
shift: {
|
||||
include: {
|
||||
cartEvent: {
|
||||
include: {
|
||||
location: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// update the assignment. generate new publicGuid, isConfirmed to false
|
||||
let newPublicGuid = uuidv4();
|
||||
await prisma.assignment.update({
|
||||
where: {
|
||||
id: parseInt(assignmentId)
|
||||
},
|
||||
data: {
|
||||
publicGuid: newPublicGuid, // if this exists, we consider the request open
|
||||
isConfirmed: false
|
||||
}
|
||||
});
|
||||
|
||||
//get all subscribed publisers
|
||||
const subscribedPublishers = await prisma.publisher.findMany({
|
||||
where: {
|
||||
isSubscribedToCoverMe: true
|
||||
}
|
||||
});
|
||||
//send email to all subscribed publishers
|
||||
for (let i = 0; i < subscribedPublishers.length; i++) {
|
||||
if (subscribedPublishers[i].id == user.id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//send email to subscribed publisher
|
||||
let acceptUrl = process.env.NEXTAUTH_URL + "/api/email?action=email_response&emailaction=coverMeAccept&userId=" + subscribedPublishers[i].id + "&shiftId=" + assignment.shiftId + "&assignmentPID=" + newPublicGuid;
|
||||
|
||||
let model = {
|
||||
user: user,
|
||||
shiftId: assignment.shiftId,
|
||||
acceptUrl: acceptUrl,
|
||||
prefix: user.isMale ? "Брат" : "Сестра",
|
||||
firstName: subscribedPublishers[i].firstName,
|
||||
lastName: subscribedPublishers[i].lastName,
|
||||
placeName: assignment.shift.cartEvent.location.name,
|
||||
dateStr: common.getDateFormated(assignment.shift.startTime),
|
||||
time: common.formatTimeHHmm(assignment.shift.startTime),
|
||||
sentDate: common.getDateFormated(new Date())
|
||||
};
|
||||
let results = emailHelper.SendEmailHandlebars(
|
||||
{
|
||||
name: subscribedPublishers[i].firstName + " " + subscribedPublishers[i].lastName,
|
||||
email: subscribedPublishers[i].email
|
||||
}, "coverMe", model);
|
||||
// if (results) {
|
||||
// console.log("Error sending email: " + error);
|
||||
// return res.status(500).json({ message: "Error sending email:" + error });
|
||||
//}
|
||||
|
||||
if (results) {
|
||||
console.log("Email sent to: " + subscribedPublishers[i].email);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return res.status(400).json({ message: "Invalid action" });
|
||||
}
|
||||
|
||||
return res.status(200).json({ message: "User action processed" });
|
||||
}
|
||||
|
||||
}
|
||||
router.use(expressWrapper(handler));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -51,6 +51,23 @@ export default function MySchedulePage({ assignments }) {
|
||||
console.log("error", error);
|
||||
});
|
||||
};
|
||||
|
||||
const searchReplacement = (assignmentId) => {
|
||||
axiosInstance.post('/api/email?action=sendCoverMeRequestByEmail', {
|
||||
assignmentId: assignmentId,
|
||||
}).then(response => {
|
||||
console.log("response", response);
|
||||
//toast success and confirm the change
|
||||
toast.success("Заявката за заместник е изпратена!", {
|
||||
onClose: () => {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}).catch(error => {
|
||||
console.log("error", error);
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<ProtectedRoute allowedRoles={[UserRole.ADMIN, UserRole.POWERUSER, UserRole.USER]}>
|
||||
@ -101,14 +118,14 @@ export default function MySchedulePage({ assignments }) {
|
||||
setIsModalOpen(true)
|
||||
}}
|
||||
>
|
||||
Заместник
|
||||
Избери Заместник
|
||||
</button>
|
||||
{/* <button
|
||||
className="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
<button
|
||||
className="inline-flex items-center px-3 mx-2 py-2 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||
onClick={() => searchReplacement(assignment.id)}
|
||||
>
|
||||
Търси заместник
|
||||
</button> */}
|
||||
</button>
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
27
pages/message.tsx
Normal file
27
pages/message.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
// pages/message.js
|
||||
|
||||
import { useRouter } from 'next/router';
|
||||
import Layout from "../components/layout";
|
||||
|
||||
export default function MessagePage() {
|
||||
const router = useRouter();
|
||||
const messageStyles = {
|
||||
error: "text-red-500",
|
||||
warning: "text-yellow-500",
|
||||
info: "text-blue-500",
|
||||
};
|
||||
const { message, type = messageStyles.info, caption } = router.query;
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<div className="text-center">
|
||||
<h1 className={`text-2xl font-bold mb-4 ${messageStyles[type]}`}>{caption || 'Информация'}</h1>
|
||||
<p className="mb-6">
|
||||
{message || 'Така ще получавате различни съобщения.'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
@ -525,7 +525,9 @@ exports.getCurrentYearMonth = () => {
|
||||
const month = String(currentDate.getMonth() + 1).padStart(2, '0'); // Month is 0-indexed
|
||||
return `${year}-${month}`;
|
||||
}
|
||||
|
||||
exports.getTimeFormated = function (date) {
|
||||
return this.formatTimeHHmm(date);
|
||||
}
|
||||
// format date to 'HH:mm' time string required by the time picker
|
||||
exports.formatTimeHHmm = function (input) {
|
||||
// Check if the input is a string or a Date object
|
||||
@ -729,3 +731,7 @@ exports.getLocalStorage = function (key, defaultValue) {
|
||||
}
|
||||
return defaultValue;
|
||||
};
|
||||
|
||||
exports.root = function (req) {
|
||||
return process.env.NEXT_PUBLIC_PUBLIC_URL;
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
// helper module to send emails with nodemailer
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require('path');
|
||||
const { MailtrapClient } = require("mailtrap");
|
||||
const nodemailer = require("nodemailer");
|
||||
const CON = require("./const");
|
||||
const CAL = require("./calendar");
|
||||
const Handlebars = require('handlebars');
|
||||
|
||||
// const { google } = require("googleapis");
|
||||
// const OAuth2 = google.auth.OAuth2;
|
||||
@ -12,14 +14,42 @@ const CAL = require("./calendar");
|
||||
const { Shift, Publisher, PrismaClient } = require("@prisma/client");
|
||||
|
||||
const TOKEN = process.env.TOKEN || "a7d7147a530235029d74a4c2f228e6ad";
|
||||
const SENDER_EMAIL = "pw@d-popov.com";
|
||||
const sender = { name: "JW Cart: Shift Info", email: SENDER_EMAIL };
|
||||
const SENDER_EMAIL = "sofia@mwitnessing.com";
|
||||
const sender = { name: "Специално Свидетелстване София", email: SENDER_EMAIL };
|
||||
const client = new MailtrapClient({ token: TOKEN });
|
||||
const mailtrapTestClient = new MailtrapClient({
|
||||
username: '8ec69527ff2104',//not working now
|
||||
password: 'c7bc05f171c96c'
|
||||
});
|
||||
let mailtrapTestClient = null;
|
||||
// const mailtrapTestClient = new MailtrapClient({
|
||||
// username: '8ec69527ff2104',//not working now
|
||||
// password: 'c7bc05f171c96c'
|
||||
// });
|
||||
|
||||
//test
|
||||
var transporter = nodemailer.createTransport({
|
||||
host: "sandbox.smtp.mailtrap.io",
|
||||
port: 2525,
|
||||
auth: {
|
||||
user: "8ec69527ff2104",
|
||||
pass: "c7bc05f171c96c"
|
||||
}
|
||||
});
|
||||
// production
|
||||
// var transporter = nodemailer.createTransport({
|
||||
// host: "live.smtp.mailtrap.io",
|
||||
// port: 587,
|
||||
// auth: {
|
||||
// user: "api",
|
||||
// pass: "1cfe82e747b8dc3390ed08bb16e0f48d"
|
||||
// }
|
||||
// });
|
||||
|
||||
var transporterBulk = nodemailer.createTransport({
|
||||
host: "bulk.smtp.mailtrap.io",
|
||||
port: 587,
|
||||
auth: {
|
||||
user: "api",
|
||||
pass: "1cfe82e747b8dc3390ed08bb16e0f48d"
|
||||
}
|
||||
});
|
||||
// ------------------ Email sending ------------------
|
||||
var lastResult = null;
|
||||
function setResult(result) {
|
||||
@ -29,91 +59,173 @@ exports.GetLastResult = function () {
|
||||
return lastResult;
|
||||
};
|
||||
|
||||
exports.SendEmail = async function (to, subject, text, html) {
|
||||
exports.SendEmail = async function (to, subject, text, html, attachments = []) {
|
||||
let sender = '"Специално Свидетелстване София - тест" <demo@mwitnessing.com>';
|
||||
to = Array.isArray(to) ? to : [to];
|
||||
const emailAddresses = to.map(item => `"${item.name}" <${item.email}>`).join(', ');
|
||||
|
||||
const message = {
|
||||
from: sender,
|
||||
to,
|
||||
to: emailAddresses,
|
||||
subject,
|
||||
text,
|
||||
html,
|
||||
attachments
|
||||
};
|
||||
|
||||
if (mailtrapTestClient !== null) {
|
||||
// Assuming mailtrapTestClient is correctly set up to send emails
|
||||
await mailtrapTestClient
|
||||
.send(message)
|
||||
.then(console.log)
|
||||
.catch(console.error);
|
||||
|
||||
} else {
|
||||
|
||||
let result = await transporter
|
||||
.sendMail(message)
|
||||
.then(console.log)
|
||||
.catch(console.error);
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.SendEmailHandlebars = async function (to, templateName, model) {
|
||||
// Ensure the sender and mailtrapTestClient are correctly defined or imported
|
||||
exports.SendEmailHandlebars = async function (to, templateName, model, attachments = []) {
|
||||
try {
|
||||
// Ensure the sender and mailtrapTestClient are correctly defined or imported
|
||||
|
||||
// Load and compile the main template
|
||||
const mainTemplateSource = fs.readFileSync(path.join(__dirname, 'src', 'templates', 'emails', 'main.hbs'), 'utf8');
|
||||
const mainTemplate = Handlebars.compile(mainTemplateSource);
|
||||
// Load and compile the main template
|
||||
const mainTemplateSource = fs.readFileSync(path.join(process.cwd(), 'src', 'templates', 'emails', 'main.hbs'), 'utf8');
|
||||
const mainTemplate = Handlebars.compile(mainTemplateSource);
|
||||
|
||||
// Dynamically load and compile the specified template
|
||||
const templateSource = fs.readFileSync(path.join(__dirname, 'src', 'templates', 'emails', `${templateName}.hbs`), 'utf8');
|
||||
// Dynamically load and compile the specified template
|
||||
const templateSource = fs.readFileSync(path.join(process.cwd(), 'src', 'templates', 'emails', `${templateName}.hbs`), 'utf8');
|
||||
|
||||
// Extract subject and optional text version from the template source
|
||||
const subjectMatch = templateSource.match(/{{!-- Subject: (.*) --}}/);
|
||||
const textMatch = templateSource.match(/{{!-- Text: ([\s\S]*?) --}}/);
|
||||
// Extract subject and optional text version from the template source
|
||||
const subjectMatch = templateSource.match(/{{!-- Subject: (.*) --}}/);
|
||||
const textMatch = templateSource.match(/{{!-- Text: ([\s\S]*?) --}}/);
|
||||
|
||||
const subject = subjectMatch ? subjectMatch[1].trim() : 'Default Subject';
|
||||
const textVersion = textMatch ? textMatch[1].trim() : null;
|
||||
const subject = subjectMatch ? subjectMatch[1].trim() : 'Default Subject';
|
||||
const textVersion = textMatch ? textMatch[1].trim() : null;
|
||||
|
||||
// Remove the subject and text annotations from the template source
|
||||
const cleanTemplateSource = templateSource.replace(/{{!-- Subject: .* --}}/, '').replace(/{{!-- Text: [\s\S]*? --}}/, '');
|
||||
// Remove the subject and text annotations from the template source
|
||||
const cleanTemplateSource = templateSource.replace(/{{!-- Subject: .* --}}/, '').replace(/{{!-- Text: [\s\S]*? --}}/, '');
|
||||
|
||||
// Compile the cleaned template
|
||||
const template = Handlebars.compile(cleanTemplateSource);
|
||||
// Compile the cleaned template
|
||||
const template = Handlebars.compile(cleanTemplateSource);
|
||||
|
||||
// Render the specified template with the provided model
|
||||
const templateHtml = template(model);
|
||||
// Render the specified template with the provided model
|
||||
const templateHtml = template(model);
|
||||
|
||||
// Render the main template, inserting the specific template HTML
|
||||
const html = mainTemplate({ body: templateHtml });
|
||||
// Render the main template, inserting the specific template HTML
|
||||
const html = mainTemplate({ body: templateHtml });
|
||||
|
||||
// Generate a plain text version if not explicitly provided
|
||||
const text = textVersion || html.replace(/<[^>]*>?/gm, ''); // Simple regex to strip HTML tags. Might need refinement.
|
||||
// Generate a plain text version if not explicitly provided
|
||||
const text = textVersion || html.replace(/<[^>]*>?/gm, ''); // Simple regex to strip HTML tags. Might need refinement.
|
||||
|
||||
const message = {
|
||||
from: sender, // Ensure 'sender' is defined
|
||||
to,
|
||||
subject,
|
||||
text,
|
||||
html,
|
||||
};
|
||||
let results = this.SendEmail(to, subject, text, html, attachments);
|
||||
return results;
|
||||
|
||||
// Assuming mailtrapTestClient is correctly set up to send emails
|
||||
await mailtrapTestClient
|
||||
.send(message)
|
||||
.then(console.log)
|
||||
.catch(console.error);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return new Error('Error sending email');
|
||||
}
|
||||
};
|
||||
|
||||
exports.SendEmail_Test = async function (to, subject, text, html) {
|
||||
const message = {
|
||||
from: sender,
|
||||
to,
|
||||
subject,
|
||||
text,
|
||||
html,
|
||||
|
||||
exports.SendEmail_NewShifts = async function (publisher, shifts) {
|
||||
if (shifts.length === 0) return;
|
||||
|
||||
var date = new Date(shifts[0].startTime);
|
||||
|
||||
// Generate ICS calendar links for all shifts
|
||||
const icsLink = CAL.GenerateICS(shifts);
|
||||
|
||||
// Prepare the shifts string
|
||||
const shiftStr = shifts.map((s) => {
|
||||
return `${CON.weekdaysBG[s.startTime.getDay()]} ${CON.GetDateFormat(s.startTime)} at ${s.cartEvent.location.name} from ${CON.GetTimeFormat(s.startTime)} to ${CON.GetTimeFormat(s.endTime)}`;
|
||||
}).join("<br>");
|
||||
|
||||
// Define the model for the Handlebars template
|
||||
const model = {
|
||||
publisherFirstName: publisher.firstName,
|
||||
publisherLastName: publisher.lastName,
|
||||
month: CON.monthNamesBG[date.getMonth()],
|
||||
shifts: shiftStr,
|
||||
sentDate: new Date().toLocaleDateString() // Assuming you want to include the sent date in the email
|
||||
};
|
||||
|
||||
await mailtrapTestClient
|
||||
.send(message)
|
||||
.then(console.log, console.error, setResult);
|
||||
}
|
||||
// Call the refactored function to send the email with Handlebars template rendering
|
||||
await exports.SendEmailHandlebars(
|
||||
publisher.email, // Assuming the publisher's email is to be used
|
||||
"newShifts", // The name of your Handlebars template for new shifts notification
|
||||
model,
|
||||
[{
|
||||
filename: "calendar.ics",
|
||||
content: icsLink,
|
||||
contentType: 'text/calendar' // Ensure this is correctly set for the ICS file
|
||||
}]
|
||||
).then(console.log).catch(console.error);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//----------------------- OLD -----------------------------
|
||||
|
||||
// exports.SendEmail_NewShifts = async function (publisher, shifts) {
|
||||
// if (shifts.length == 0) return;
|
||||
|
||||
// var date = new Date(shifts[0].startTime);
|
||||
|
||||
// //generate ICS calendar links for all shifts
|
||||
// const icsLink = CAL.GenerateICS(shifts);
|
||||
|
||||
// const shftStr = shifts
|
||||
// .map((s) => {
|
||||
// return ` ${CON.weekdaysBG[s.startTime.getDay()]
|
||||
// } ${CON.GetDateFormat(s.startTime)} ${s.cartEvent.location.name
|
||||
// } ${CON.GetTimeFormat(s.startTime)} - ${CON.GetTimeFormat(
|
||||
// s.endTime
|
||||
// )}`;
|
||||
// })
|
||||
// .join("\n");
|
||||
|
||||
// await client.send({
|
||||
// from: sender,
|
||||
// to: [
|
||||
// {
|
||||
// email: "dobromir.popov@gmail.com",//publisher.email,
|
||||
// name: publisher.firstName + " " + publisher.lastName,
|
||||
// },
|
||||
// ],
|
||||
// subject: "[CCC]: вашите смени през " + CON.monthNamesBG[date.getMonth()],
|
||||
// text:
|
||||
// "Здравейте, " + publisher.firstName + " " + publisher.lastName + "!\n\n" +
|
||||
// "Ти регистриран да получавате известия за нови смени на количка.\n" +
|
||||
// `За месец ${CON.monthNamesBG[date.getMonth()]} имате следните смени:\n` +
|
||||
// ` ${shftStr} \n\n\n` +
|
||||
// "Поздрави,\n" +
|
||||
// "Специално Свидетелстване София",
|
||||
// attachments: [
|
||||
// {
|
||||
// filename: "calendar.ics",
|
||||
// content_id: "calendar.ics",
|
||||
// disposition: "inline",
|
||||
// content: icsLink,
|
||||
// },
|
||||
// ],
|
||||
// })
|
||||
// .then(console.log, console.error, setResult);
|
||||
// };
|
||||
|
||||
|
||||
// https://mailtrap.io/blog/sending-emails-with-nodemailer/
|
||||
exports.SendTestEmail = async function (to) {
|
||||
// await client
|
||||
// .send({
|
||||
// from: sender,
|
||||
// to: [{ email: RECIPIENT_EMAIL }],
|
||||
// subject: "Hello from Mailtrap!",
|
||||
// text: "Welcome to Mailtrap Sending!",Shift Info"
|
||||
// })
|
||||
// .then(console.log, console.error, setResult);
|
||||
|
||||
// return lastResult;
|
||||
|
||||
exports.SendEmail_Example = async function (to) {
|
||||
const welcomeImage = fs.readFileSync(
|
||||
path.join(CON.contentPath, "welcome.png")
|
||||
);
|
||||
@ -160,50 +272,3 @@ exports.SendTestEmail = async function (to) {
|
||||
})
|
||||
.then(console.log, console.error, setResult);
|
||||
};
|
||||
|
||||
|
||||
exports.SendEmail_NewShifts = async function (publisher, shifts) {
|
||||
if (shifts.length == 0) return;
|
||||
|
||||
var date = new Date(shifts[0].startTime);
|
||||
|
||||
//generate ICS calendar links for all shifts
|
||||
const icsLink = CAL.GenerateICS(shifts);
|
||||
|
||||
const shftStr = shifts
|
||||
.map((s) => {
|
||||
return ` ${CON.weekdaysBG[s.startTime.getDay()]
|
||||
} ${CON.GetDateFormat(s.startTime)} ${s.cartEvent.location.name
|
||||
} ${CON.GetTimeFormat(s.startTime)} - ${CON.GetTimeFormat(
|
||||
s.endTime
|
||||
)}`;
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
await client.send({
|
||||
from: sender,
|
||||
to: [
|
||||
{
|
||||
email: "dobromir.popov@gmail.com",//publisher.email,
|
||||
name: publisher.firstName + " " + publisher.lastName,
|
||||
},
|
||||
],
|
||||
subject: "[CCC]: вашите смени през " + CON.monthNamesBG[date.getMonth()],
|
||||
text:
|
||||
"Здравейте, " + publisher.firstName + " " + publisher.lastName + "!\n\n" +
|
||||
"Ти регистриран да получавате известия за нови смени на количка.\n" +
|
||||
`За месец ${CON.monthNamesBG[date.getMonth()]} имате следните смени:\n` +
|
||||
` ${shftStr} \n\n\n` +
|
||||
"Поздрави,\n" +
|
||||
"Специално Свидетелстване София",
|
||||
attachments: [
|
||||
{
|
||||
filename: "calendar.ics",
|
||||
content_id: "calendar.ics",
|
||||
disposition: "inline",
|
||||
content: icsLink,
|
||||
},
|
||||
],
|
||||
})
|
||||
.then(console.log, console.error, setResult);
|
||||
};
|
||||
|
24
src/templates/emails/coverMe copy.hbs
Normal file
24
src/templates/emails/coverMe copy.hbs
Normal file
@ -0,0 +1,24 @@
|
||||
{{!-- Subject: ССС: Нужен е заместник--}}
|
||||
{{!-- Text: Plain text version of your email. If not provided, HTML tags will be stripped from the HTML version for the
|
||||
text version. --}}
|
||||
|
||||
<section>
|
||||
<h3>Търси се зместник за смяна на {{placeName}} за {{dateStr}}!</h3>
|
||||
<p>Здравейте,</p>
|
||||
<p>{{prefix}} {{firstName}} {{lastName}} търси заместник.</p>
|
||||
{{!-- <p><strong>Shift Details:</strong></p> --}}
|
||||
<p>Дата: {{dateStr}} <br>Час: {{time}}<br>Място: {{placeName}}</p>
|
||||
<p>С натискането на бутона по-долу можете да премете да го замествате. Вие, той/тя и останалите участници в смяната
|
||||
ще бъдат уведумени чрез имейл за промяната. Вашата помощ е много ценна.</p>
|
||||
<p style="text-align: center;">
|
||||
<a href="{{acceptUrl}}"
|
||||
target="_blank"
|
||||
style="background-color: #4CAF50; color: white; padding: 10px 20px; text-decoration: none; display: inline-block; border-radius: 5px;">Ще
|
||||
поема смяната</a>
|
||||
</p>
|
||||
{{!-- <p>Thank you very much for considering my request.</p>
|
||||
<p>Best regards,<br>{{name}}</p> --}}
|
||||
</section>
|
||||
<footer style="margin-top: 20px; text-align: center;">
|
||||
<p>Изпратено на: {{sentDate}}</p>
|
||||
</footer>
|
@ -1,24 +1,24 @@
|
||||
{{!-- Subject: Your email subject here --}}
|
||||
{{!-- Text: Plain text version of your email. If not provided, HTML tags will be stripped from the HTML version for the
|
||||
text version. --}}
|
||||
{{!-- Subject: ССС: Нужен е заместник--}}
|
||||
|
||||
<section>
|
||||
<h3>{{firstName}} {{lastName}} търси зместник за {{placeName}}!</h3>
|
||||
<p>Здравейте,</p>
|
||||
<p>{{prefix}} {{firstName}} {{lastName}} търси заместник за своята смяна на {{dateStr}} на {{placeName}}.</p>
|
||||
<h3>Търси се зместник за смяна на {{placeName}} за {{dateStr}}!</h3>
|
||||
<p>Здравей {{firstName}},</p>
|
||||
<p>{{prefix}} {{user.firstName}} {{user.lastName}} търси заместник.</p>
|
||||
{{!-- <p><strong>Shift Details:</strong></p> --}}
|
||||
{{!-- <p>Date: {{date}}<br>Time: {{time}}<br>Location: {{placeName}}</p> --}}
|
||||
<p>С натискането на бутона по-долу можете да премете да го замествате. Вие, той/тя и останалите участници в смяната
|
||||
ще бъдат уведумени чрез имейл за промяната. Вашата помощ е високо ценена.</p>
|
||||
<p>Дата: {{dateStr}} <br>Час: {{time}}<br>Място: {{placeName}}</p>
|
||||
<p>С натискането на бутона по-долу можеш да премеш да го заместваш.
|
||||
{{!-- Ти, той/тя и останалите участници в смяната ще
|
||||
получат имейл за промяната. Твоята помощ е много ценна. --}}
|
||||
</p>
|
||||
<p style="text-align: center;">
|
||||
<a href="{{acceptUrl}}"
|
||||
target="_blank"
|
||||
style="background-color: #4CAF50; color: white; padding: 10px 20px; text-decoration: none; display: inline-block; border-radius: 5px;">Приеми
|
||||
смяната</a>
|
||||
style="background-color: #4CAF50; color: white; padding: 10px 20px; text-decoration: none; display: inline-block; border-radius: 5px;">Ще
|
||||
поема смяната</a>
|
||||
</p>
|
||||
{{!-- <p>Thank you very much for considering my request.</p>
|
||||
<p>Best regards,<br>{{name}}</p> --}}
|
||||
</section>
|
||||
<footer style="margin-top: 20px; text-align: center;">
|
||||
<p>Изпратено на: {{sentDate}}</p>
|
||||
<p>Изпратено до {{firstName}} {{lastName}} на {{sentDate}}</p>
|
||||
</footer>
|
@ -10,7 +10,7 @@
|
||||
|
||||
<body>
|
||||
<header style="background-color: #f3f3f3; padding: 20px; text-align: center;">
|
||||
<h2>Company Name</h2>
|
||||
<h2>Cпециално Свидетелстване София</h2>
|
||||
</header>
|
||||
|
||||
<main style="margin: 20px;">
|
||||
@ -18,7 +18,7 @@
|
||||
</main>
|
||||
|
||||
<footer style="background-color: #f3f3f3; padding: 20px; text-align: center;">
|
||||
© 2024 Company Name. All rights reserved.
|
||||
© 2024 ССС. All rights reserved.
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
|
14
src/templates/emails/newShifts.hbs
Normal file
14
src/templates/emails/newShifts.hbs
Normal file
@ -0,0 +1,14 @@
|
||||
{{!-- Subject: ССС: Нужен е заместник--}}
|
||||
|
||||
<section>
|
||||
<h2>Здравейте, {{publisherFirstName}} {{publisherLastName}}!</h2>
|
||||
<p>Ти регистриран да получавате известия за нови смени на количка.</p>
|
||||
<p>За месец {{month}} имате следните смени:</p>
|
||||
<div>
|
||||
{{{shifts}}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="footer">
|
||||
Изпратено на: {{sentDate}}
|
||||
</footer>
|
Reference in New Issue
Block a user