diff options
author | 2025-04-26 15:31:33 +0530 | |
---|---|---|
committer | 2025-04-26 15:31:33 +0530 | |
commit | 8c9677ffc5aef95964b42c03690eb5ea1b912b13 (patch) | |
tree | 8d1941b0e591e601288387c464db098e66e9b365 /app/src/lib | |
download | realtimeloc-8c9677ffc5aef95964b42c03690eb5ea1b912b13.tar.gz realtimeloc-8c9677ffc5aef95964b42c03690eb5ea1b912b13.tar.bz2 realtimeloc-8c9677ffc5aef95964b42c03690eb5ea1b912b13.zip |
testing location tracker
Diffstat (limited to 'app/src/lib')
-rw-r--r-- | app/src/lib/email.ts | 113 | ||||
-rw-r--r-- | app/src/lib/socket.ts | 76 | ||||
-rw-r--r-- | app/src/lib/utils.ts | 6 |
3 files changed, 195 insertions, 0 deletions
diff --git a/app/src/lib/email.ts b/app/src/lib/email.ts new file mode 100644 index 0000000..16eca63 --- /dev/null +++ b/app/src/lib/email.ts @@ -0,0 +1,113 @@ +import nodemailer from 'nodemailer'; + +// Email configuration +// Required environment variables: +// - SMTP_HOST: Your SMTP server host (e.g. smtp.gmail.com) +// - SMTP_PORT: Your SMTP server port (e.g. 587 for TLS, 465 for SSL) +// - SMTP_USER: Your SMTP server username/email +// - SMTP_PASSWORD: Your SMTP server password or app password +// - EMAIL_FROM: The email address that will appear as sender +const smtpConfig = { + host: process.env.SMTP_HOST, + port: parseInt(process.env.SMTP_PORT || '587'), + secure: process.env.SMTP_PORT === '465', // true for 465, false for other ports + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASSWORD, + }, +}; + +// For development, if SMTP credentials aren't provided, log messages instead of sending +const devMode = process.env.NODE_ENV !== 'production' && + (!process.env.SMTP_HOST || !process.env.SMTP_USER || !process.env.SMTP_PASSWORD); + +// Create a reusable transporter object +let transporter: nodemailer.Transporter; + +// Initialize the transporter +export const initializeEmailTransporter = () => { + if (devMode) { + console.log('Email dev mode active: emails will be logged instead of sent'); + // Use Nodemailer's testing account for development + return nodemailer.createTransport({ + jsonTransport: true // This outputs the email to the console instead of sending it + }); + } + + if (!transporter) { + transporter = nodemailer.createTransport(smtpConfig); + } + return transporter; +}; + +// Send location sharing email +export const sendLocationSharingEmail = async ({ + to, + senderName, + locationUrl, + expiryTime, +}: { + to: string; + senderName: string; + locationUrl: string; + expiryTime?: Date; +}) => { + const emailTransporter = initializeEmailTransporter(); + + const expiryMessage = expiryTime + ? `This location share will expire on ${expiryTime.toLocaleString()}.` + : 'This location share does not expire.'; + + const mailOptions = { + from: process.env.EMAIL_FROM || `"Location Tracker" <${process.env.SMTP_USER || '[email protected]'}>`, + to, + subject: `${senderName} shared their location with you`, + text: ` + ${senderName} has shared their real-time location with you. + + Click the link below to view their current location: + ${locationUrl} + + ${expiryMessage} + + This is an automated message, please do not reply. + `, + html: ` + <div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;"> + <h2 style="color: #4a5568;">Location Shared with You</h2> + <p>${senderName} has shared their real-time location with you.</p> + + <div style="margin: 20px 0;"> + <a href="${locationUrl}" style="background-color: #4299e1; color: white; padding: 10px 15px; text-decoration: none; border-radius: 5px; display: inline-block;"> + View Location + </a> + </div> + + <p style="color: #718096; font-size: 14px;">${expiryMessage}</p> + + <hr style="border: none; border-top: 1px solid #e2e8f0; margin: 20px 0;" /> + + <p style="color: #a0aec0; font-size: 12px;"> + This is an automated message from Real-Time Location Tracker. Please do not reply. + </p> + </div> + `, + }; + + try { + if (devMode) { + // In dev mode, log the email details instead of sending + console.log('DEV MODE: Email would be sent with the following details:'); + console.log('To:', to); + console.log('Subject:', mailOptions.subject); + console.log('Location URL:', locationUrl); + return { success: true, messageId: 'dev-mode-email', devMode: true }; + } + + const info = await emailTransporter.sendMail(mailOptions); + return { success: true, messageId: info.messageId }; + } catch (error) { + console.error('Error sending email:', error); + throw new Error('Failed to send email. Please check your SMTP settings.'); + } +};
\ No newline at end of file diff --git a/app/src/lib/socket.ts b/app/src/lib/socket.ts new file mode 100644 index 0000000..97b38c3 --- /dev/null +++ b/app/src/lib/socket.ts @@ -0,0 +1,76 @@ +import { Server as NetServer } from 'http'; +import { Server as SocketIOServer } from 'socket.io'; +import { NextApiRequest } from 'next'; +import { NextApiResponse } from 'next'; + +export type NextApiResponseWithSocket = NextApiResponse & { + socket: { + server: NetServer & { + io?: SocketIOServer; + }; + }; +}; + +// Initialize Socket.IO server +export const initSocketIO = (res: NextApiResponseWithSocket) => { + if (!res.socket.server.io) { + console.log('Initializing new Socket.IO server...'); + + // Create new Socket.IO server instance + const io = new SocketIOServer(res.socket.server, { + path: '/api/socket', + addTrailingSlash: false, + }); + + // Store Socket.IO server instance on the response object + res.socket.server.io = io; + + // Set up Socket.IO event handlers + io.on('connection', (socket) => { + console.log(`Client connected: ${socket.id}`); + + // Handle client disconnection + socket.on('disconnect', () => { + console.log(`Client disconnected: ${socket.id}`); + }); + + // Handle location updates + socket.on('location:update', (data) => { + console.log(`Received location update from ${socket.id}:`, data); + + // If a share token is provided, broadcast to that specific room + if (data.shareToken) { + socket.to(`share:${data.shareToken}`).emit('location:updated', { + latitude: data.latitude, + longitude: data.longitude, + accuracy: data.accuracy, + timestamp: data.timestamp || new Date().toISOString(), + }); + } + }); + + // Join a location share room + socket.on('share:join', (shareToken) => { + if (shareToken) { + socket.join(`share:${shareToken}`); + console.log(`Client ${socket.id} joined room share:${shareToken}`); + } + }); + + // Leave a location share room + socket.on('share:leave', (shareToken) => { + if (shareToken) { + socket.leave(`share:${shareToken}`); + console.log(`Client ${socket.id} left room share:${shareToken}`); + } + }); + }); + } + + return res.socket.server.io; +}; + +// Get the Socket.IO server instance +export const getSocketIO = (res: NextApiResponseWithSocket) => { + return res.socket.server.io || initSocketIO(res); +};
\ No newline at end of file diff --git a/app/src/lib/utils.ts b/app/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/app/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} |