aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/lib
diff options
context:
space:
mode:
authorLibravatarLibravatar Biswa Kalyan Bhuyan <[email protected]> 2025-04-26 15:31:33 +0530
committerLibravatarLibravatar Biswa Kalyan Bhuyan <[email protected]> 2025-04-26 15:31:33 +0530
commit8c9677ffc5aef95964b42c03690eb5ea1b912b13 (patch)
tree8d1941b0e591e601288387c464db098e66e9b365 /app/src/lib
downloadrealtimeloc-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.ts113
-rw-r--r--app/src/lib/socket.ts76
-rw-r--r--app/src/lib/utils.ts6
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))
+}