Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Production build
build/
dist/

# Test files
test_email.py

# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local

# Python cache
__pycache__/
*.pyc
*.pyo
*.pyd
.Python

# IDE files
.vscode/
.idea/
*.swp
*.swo
*~

# OS files
.DS_Store
Thumbs.db

# Logs
*.log
131 changes: 131 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# TalentSync Email Integration

A React-based email integration system for scheduling interviews and sending personalized emails to candidates.

## Features

- **React Frontend**: Modern web interface for managing interview scheduling
- **Email Template Generation**: Uses React components to generate HTML emails
- **FastAPI Backend**: Python-based API for email processing and database integration
- **Server-Side Rendering**: React components are rendered server-side for email generation

## Technology Stack

- **Frontend**: React 18, Material-UI
- **Backend**: FastAPI, Python 3
- **Email Generation**: React Server-Side Rendering (Node.js)
- **Database**: MongoDB
- **Email Service**: SMTP (Gmail)

## Project Structure

```
├── src/ # React frontend source
│ ├── App.js # Main React application
│ ├── EmailTemplate.js # React email template component
│ ├── emailUtils.js # Email utility functions
│ └── index.js # React entry point
├── public/ # Static assets
├── generateEmail.js # Node.js script for email generation
├── main.py # FastAPI backend
├── requirements.txt # Python dependencies
└── package.json # Node.js dependencies
```

## Setup

### 1. Install Dependencies

Install Python dependencies:
```bash
pip install -r requirements.txt
```

Install Node.js dependencies:
```bash
npm install
```

### 2. Environment Variables

Create a `.env` file with:
```
MONGODB_URI=your_mongodb_connection_string
SENDER_EMAIL=your_email@gmail.com
EMAIL_PASSWORD=your_app_password
```

### 3. Build React Frontend

```bash
npm run build
```

### 4. Run the Application

```bash
python main.py
```

The application will be available at `http://localhost:8000`

## How It Works

1. **Email Template**: The `EmailTemplate.js` React component defines the email structure
2. **Server-Side Rendering**: The `generateEmail.js` script renders React components to HTML
3. **Python Integration**: The FastAPI backend calls the Node.js script to generate emails
4. **Email Sending**: Generated HTML is sent via SMTP to candidates

## API Endpoints

- `GET /` - Serves the React frontend
- `POST /schedule-interviews/` - Schedules interviews and sends emails

## Email Generation Flow

1. Python backend calls `node generateEmail.js <name> <time>`
2. Node.js renders the React EmailTemplate component
3. Resulting HTML is returned to Python
4. Python sends the HTML email via SMTP

## Development

To run in development mode:

```bash
# Start React development server
npm start

# Start FastAPI backend (in another terminal)
uvicorn main:app --reload
```

## Converting from HTML to React

This project demonstrates converting from hardcoded HTML strings to a React-based template system:

**Before (HTML strings in Python):**
```python
html = f"""
<html>
<body>
<p>Dear {candidate['name']},</p>
<!-- ... more HTML ... -->
</body>
</html>
"""
```

**After (React components):**
```javascript
const EmailTemplate = ({ candidateName, interviewTime }) => {
return (
<div>
<p>Dear {candidateName},</p>
{/* ... more JSX ... */}
</div>
);
};
```

This approach provides better maintainability, reusability, and allows for complex templating logic.
65 changes: 65 additions & 0 deletions generateEmail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const React = require('react');
const { renderToStaticMarkup } = require('react-dom/server');

// React component definition in Node.js
const EmailTemplate = ({ candidateName, interviewTime }) => {
return React.createElement('div', {
style: { fontFamily: 'Arial, sans-serif', maxWidth: '600px', margin: '0 auto' }
}, [
React.createElement('p', { key: 'greeting' }, `Dear ${candidateName},`),
React.createElement('p', { key: 'intro' },
`We are pleased to inform you that your interview with NeonAI has been scheduled for ${interviewTime}.`
),
React.createElement('p', { key: 'instructions' },
'Please ensure you are prepared and join the interview at the scheduled time. Further details regarding the interview process will be provided soon.'
),
React.createElement('p', { key: 'chatbot' }, [
'For any questions or assistance, you may reach out via our chatbot: ',
React.createElement('a', {
href: 'https://chatbot-ui-five-cyan-56.vercel.app/',
style: { color: '#0066cc', textDecoration: 'none' },
key: 'link'
}, 'TalentSync Chatbot'),
'.'
]),
React.createElement('p', { key: 'closing' }, 'We look forward to speaking with you.'),
React.createElement('p', { key: 'signature' }, [
'Best regards,',
React.createElement('br', { key: 'br' }),
'The NeonAI Team'
])
]);
};

// Function to generate HTML
function generateEmailHTML(candidateName, interviewTime) {
const emailComponent = React.createElement(EmailTemplate, {
candidateName,
interviewTime
});

const htmlContent = renderToStaticMarkup(emailComponent);

return `
<html>
<body>
${htmlContent}
</body>
</html>
`;
}

// Command line interface
if (require.main === module) {
const args = process.argv.slice(2);
if (args.length !== 2) {
console.error('Usage: node generateEmail.js <candidateName> <interviewTime>');
process.exit(1);
}

const [candidateName, interviewTime] = args;
const html = generateEmailHTML(candidateName, interviewTime);
console.log(html);
}

module.exports = { generateEmailHTML };
77 changes: 63 additions & 14 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from pydantic import BaseModel
from pymongo import MongoClient
import os
Expand All @@ -9,6 +11,8 @@
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import logging
import subprocess
import json

# Initialize FastAPI app
app = FastAPI()
Expand Down Expand Up @@ -54,6 +58,51 @@ def generate_time_slots(start_date):
current_time += timedelta(minutes=30)
return slots

# Generate email HTML using React component
def generate_email_html(candidate_name, interview_time):
try:
# Call the Node.js script to generate HTML from React component
result = subprocess.run(
['node', 'generateEmail.js', candidate_name, interview_time],
capture_output=True,
text=True,
cwd=os.path.dirname(os.path.abspath(__file__))
)
if result.returncode == 0:
return result.stdout.strip()
else:
logger.error(f"Error generating email HTML: {result.stderr}")
# Fallback to simple HTML if React generation fails
return f"""
<html>
<body>
<p>Dear {candidate_name},</p>
<p>We are pleased to inform you that your interview with NeonAI has been scheduled for {interview_time}.</p>
<p>Please ensure you are prepared and join the interview at the scheduled time. Further details regarding the interview process will be provided soon.</p>
<p>For any questions or assistance, you may reach out via our chatbot: <a href="https://chatbot-ui-five-cyan-56.vercel.app/">TalentSync Chatbot</a>.</p>
<p>We look forward to speaking with you.</p>
<p>Best regards,<br>
The NeonAI Team</p>
</body>
</html>
"""
except Exception as e:
logger.error(f"Exception generating email HTML: {str(e)}")
# Fallback to simple HTML
return f"""
<html>
<body>
<p>Dear {candidate_name},</p>
<p>We are pleased to inform you that your interview with NeonAI has been scheduled for {interview_time}.</p>
<p>Please ensure you are prepared and join the interview at the scheduled time. Further details regarding the interview process will be provided soon.</p>
<p>For any questions or assistance, you may reach out via our chatbot: <a href="https://chatbot-ui-five-cyan-56.vercel.app/">TalentSync Chatbot</a>.</p>
<p>We look forward to speaking with you.</p>
<p>Best regards,<br>
The NeonAI Team</p>
</body>
</html>
"""

# Schedule interviews and send emails
@app.post("/schedule-interviews/")
async def schedule_interviews():
Expand Down Expand Up @@ -86,21 +135,9 @@ async def schedule_interviews():
interview_time = available_slots[slot_index]
slot_index += 1

# Create email content
# Create email content using React component
subject = "Interview Call from NeonAI!!"
html = f"""
<html>
<body>
<p>Dear {candidate['name']},</p>
<p>We are pleased to inform you that your interview with NeonAI has been scheduled for {interview_time}.</p>
<p>Please ensure you are prepared and join the interview at the scheduled time. Further details regarding the interview process will be provided soon.</p>
<p>For any questions or assistance, you may reach out via our chatbot: <a href="https://chatbot-ui-five-cyan-56.vercel.app/">TalentSync Chatbot</a>.</p>
<p>We look forward to speaking with you.</p>
<p>Best regards,<br>
The NeonAI Team</p>
</body>
</html>
"""
html = generate_email_html(candidate['name'], interview_time)

message = MIMEMultipart("alternative")
message["Subject"] = subject
Expand Down Expand Up @@ -132,6 +169,18 @@ async def schedule_interviews():
logger.error(f"Error scheduling interviews: {str(e)}")
raise HTTPException(status_code=500, detail=f"Failed to schedule interviews: {str(e)}")

# Serve React frontend (if build exists)
@app.get("/")
async def serve_frontend():
try:
return FileResponse('build/index.html')
except:
return {"message": "TalentSync Email Integration API", "frontend": "Run 'npm run build' to build React frontend"}

# Mount static files for React build
if os.path.exists("build"):
app.mount("/static", StaticFiles(directory="build/static"), name="static")

# Run the app
if __name__ == "__main__":
import uvicorn
Expand Down
Loading