Files
operify/app/api/forms/route.js
2025-08-11 16:08:29 +05:30

248 lines
9.5 KiB
JavaScript

import { NextResponse } from 'next/server';
import nodemailer from 'nodemailer';
// Email configuration
const emailConfig = {
from_email: process.env.EMAIL_USER || "smukeshsn2000@gmail.com",
from_email_password: process.env.EMAIL_PASS || "swoe hxko uzuc ichj",
from_email_name: process.env.EMAIL_FROM_NAME || "Operify",
to_email: process.env.EMAIL_TO || "smukesh1304@gmail.com",
to_email_name: process.env.EMAIL_TO_NAME || "Mukesh",
};
// Form configurations
const configs = {
contact: {
subject: 'Contact Form Submission',
fields: ['name', 'phone', 'service_interest', 'email', 'Organisation', 'message'],
required: ['name', 'phone', 'service_interest', 'email', 'Organisation', 'message'],
email_fields: ['email'],
successMessage: 'Thank you for your submission. Our team will contact you soon!'
},
career: {
subject: 'Career Application',
fields: ['name', 'phone', 'email', 'Education_Qualification', 'experience', 'Specify_your_interest_in_Genomics', 'message'],
required: ['name', 'phone', 'email', 'Education_Qualification', 'experience', 'Specify_your_interest_in_Genomics', 'message'],
email_fields: ['email'],
file_field: 'resume',
successMessage: 'Thank you for your application. Our team will contact you soon!'
},
sample: {
subject: 'SIF Form received for Project',
fields: [
'Principal_Investigator', 'Email', 'Company_Institution', 'Contact_Number', 'Address', 'City', 'State', 'Pin',
'Secondary_Contact', 'Secondary_Email', 'Secondary_Company_Institution', 'Secondary_Contact_Number',
'Project_Title', 'Number_of_Samples', 'Sample_Type', 'Sample_Type_Other', 'Sample_Source', 'Sample_Source_Other',
'Pathogenicity', 'Sample_Remarks',
'Service_Requested', 'Service_Requested_Other', 'Type_of_Library', 'Type_of_Library_Other',
'Required_Library_Size', 'Required_Library_Size_Other', 'Index_Information', 'Kit_Information',
'Sequencing_Platform', 'Sequencing_Platform_Other', 'Sequencing_Read_Length', 'Sequencing_Read_Length_Other',
'Total_Data_Requirement', 'Service_Remarks',
'Analysis_Requested', 'Analysis_Details', 'Reference_Genome_Available', 'Genome_Size', 'Special_Consideration'
],
required: [
'Principal_Investigator', 'Email', 'Company_Institution', 'Contact_Number', 'Address', 'City', 'State', 'Pin',
'Project_Title', 'Number_of_Samples', 'Sample_Type', 'Sample_Source', 'Pathogenicity', 'Service_Requested',
'Type_of_Library', 'Required_Library_Size', 'Sequencing_Platform', 'Sequencing_Read_Length',
'Total_Data_Requirement', 'Analysis_Requested', 'Reference_Genome_Available', 'Special_Consideration'
],
email_fields: ['Email', 'Secondary_Email'],
successMessage: 'Thank you for your sample initiation form submission. Our team will contact you soon!'
}
};
// Serial number tracker
let serialTracker = {};
function generateSerialNumber() {
const today = new Date();
const dateKey = today.toISOString().slice(0, 10); // "YYYY-MM-DD"
if (!serialTracker[dateKey]) {
serialTracker[dateKey] = 1;
} else {
serialTracker[dateKey] += 1;
}
const serialNum = String(serialTracker[dateKey]).padStart(2, '0');
return {
serialNum,
formatted: `Operify Tech. ${today.getFullYear()}.${String(today.getMonth() + 1).padStart(2, '0')}.${String(today.getDate()).padStart(2, '0')}.${serialNum}`,
dateString: dateKey
};
}
// Utility functions
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
function fieldName(key) {
return key.replace(/[_-]/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
}
export async function GET() {
return NextResponse.json({
message: 'Forms API is working',
timestamp: new Date().toISOString()
});
}
export async function POST(request) {
try {
const formData = await request.formData();
const data = {};
const files = {};
for (const [key, value] of formData.entries()) {
if (value instanceof File) {
files[key] = value;
} else {
data[key] = value;
}
}
const form_type = data.form_type;
if (!form_type || !configs[form_type]) {
return NextResponse.json({
error: 'Invalid form type: ' + (form_type || 'missing')
}, { status: 400 });
}
const config = configs[form_type];
const errors = [];
for (const required_field of config.required) {
if (!data[required_field] || String(data[required_field]).trim() === '') {
errors.push(`The "${fieldName(required_field)}" field is required.`);
} else if (config.email_fields.includes(required_field) && !isValidEmail(data[required_field])) {
errors.push(`The "${fieldName(required_field)}" email is not valid.`);
}
}
if (form_type === 'career') {
const fileField = config.file_field;
const uploadedFile = files[fileField];
if (!uploadedFile || uploadedFile.size === 0) {
errors.push('Please upload your resume.');
} else {
const allowedExtensions = ['pdf', 'doc', 'docx'];
const fileExtension = uploadedFile.name.toLowerCase().split('.').pop();
if (!allowedExtensions.includes(fileExtension)) {
errors.push('Invalid file type. Please upload a PDF, DOC, or DOCX file.');
}
if (uploadedFile.size > 10 * 1024 * 1024) {
errors.push('File is too large. Maximum size is 10MB.');
}
}
}
if (errors.length > 0) {
return NextResponse.json({ error: errors.join(' ') }, { status: 400 });
}
let emailBody = `<h2>${config.subject}</h2><table style="border: 1px solid #b5b5b5; padding: 5px;">`;
for (const [key, value] of Object.entries(data)) {
if (config.fields.includes(key) && key !== 'form_type' && key !== 'sample_details') {
emailBody += `<tr>
<td style="border: 1px solid #b5b5b5; padding: 5px;"><strong>${fieldName(key)}</strong></td>
<td style="border: 1px solid #b5b5b5; padding: 5px;">: ${String(value)}</td>
</tr>`;
}
}
if (form_type === 'career' && files.resume) {
emailBody += `<tr>
<td style="border: 1px solid #b5b5b5; padding: 5px;"><strong>Resume</strong></td>
<td style="border: 1px solid #b5b5b5; padding: 5px;">: ${files.resume.name} (attached)</td>
</tr>`;
}
if (form_type === 'sample' && data.sample_details) {
try {
const sampleDetails = JSON.parse(data.sample_details);
if (sampleDetails.length > 0) {
emailBody += `<tr>
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 10px; background-color: #e8f5f3; text-align: center;"><strong>SAMPLE DETAILS</strong></td>
</tr>`;
sampleDetails.forEach((sample, index) => {
emailBody += `<tr>
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 8px; background-color: #f0f8f5; font-weight: bold;">Sample ${index + 1}</td>
</tr>`;
Object.entries(sample).forEach(([key, value]) => {
if (value && String(value).trim() !== '') {
emailBody += `<tr>
<td style="border: 1px solid #b5b5b5; padding: 5px; background-color: #f9f9f9;"><strong>${fieldName(key)}</strong></td>
<td style="border: 1px solid #b5b5b5; padding: 5px;">: ${String(value)}</td>
</tr>`;
}
});
});
}
} catch {
emailBody += `<tr>
<td colspan="2" style="border: 1px solid #b5b5b5; padding: 5px; color: red;">Error: Could not parse sample details</td>
</tr>`;
}
}
emailBody += '</table>';
let replyToEmail = form_type === 'sample' ? data.Email : data.email;
const transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 587,
secure: false,
auth: {
user: emailConfig.from_email,
pass: emailConfig.from_email_password,
},
});
// SERIAL NUMBER LOGIC
let serialInfo;
if (form_type === 'sample') {
serialInfo = generateSerialNumber();
}
// Internal mail
const mailOptions = {
from: `${emailConfig.from_email_name} <${emailConfig.from_email}>`,
to: `${emailConfig.to_email_name} <${emailConfig.to_email}>`,
replyTo: replyToEmail || emailConfig.from_email,
subject: form_type === 'sample'
? `${data.Company_Institution} | ${data.Principal_Investigator} | ${serialInfo.dateString} | ${serialInfo.formatted}`
: config.subject,
html: emailBody,
text: emailBody.replace(/<[^>]*>/g, '')
};
if (form_type === 'career' && files.resume) {
const fileBuffer = await files.resume.arrayBuffer();
mailOptions.attachments = [{
filename: files.resume.name,
content: Buffer.from(fileBuffer),
}];
}
await transporter.sendMail(mailOptions);
// PI email for sample form
if (form_type === 'sample') {
const piMailOptions = {
from: `${emailConfig.from_email_name} <${emailConfig.from_email}>`,
to: `${data.Principal_Investigator} <${data.Email}>`,
subject: `SIF Form received for Project with - ${serialInfo.formatted}`,
html: emailBody,
text: emailBody.replace(/<[^>]*>/g, '')
};
await transporter.sendMail(piMailOptions);
}
return NextResponse.json({ success: true, message: config.successMessage });
} catch (error) {
console.error('Email sending error:', error);
return NextResponse.json({ error: 'Error sending email. Please try again later.' }, { status: 500 });
}
}