Learn how to build a scheduling app with Lovable in our step-by-step guide. Simplify bookings, boost productivity, and enhance your user experience.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Creating a New Lovable Project
Setting Up Your File Structure
main.lov
– This will be the primary file where your app initializes.scheduler.lov
– This file will contain your scheduling logic.lovable.json
– Use this file to declare any dependency requirements.
Adding Dependencies
lovable.json
file.lovable.json
to install the scheduling library (for example, using the Python "schedule" module) and any other dependencies you might need:
{
"dependencies": {
"schedule": "latest"
}
}
Writing the Scheduling Logic
scheduler.lov
file and insert the following code snippet. This code sets up a task that prints a message every minute:
# scheduler.lov
# Import the schedule library and time module.
import schedule
import time
def job():
# This function contains code for the scheduled task.
print("Scheduled task executed.")
Schedule the job to run every 1 minute.
schedule.every(1).minutes.do(job)
def run_scheduler():
# This function continuously checks for scheduled tasks.
while True:
schedule.run_pending()
time.sleep(1)
Integrating the Scheduler with the Main App
main.lov
file and paste the following code. This will import the scheduler module and call its loop, ensuring that your scheduled task runs while the app is active:
# main.lov
# Import the scheduler module that you created
import scheduler
def main():
# Insert any initialization or UI setup code here.
print("Scheduling App is starting.")
# Start the scheduler loop to run scheduled tasks.
scheduler.run\_scheduler()
if name == "main":
main()
Testing Your Scheduling App
job()
function or create additional scheduled jobs in the scheduler.lov
file.
Deploying and Sharing Your App
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
mongoose.connect('mongodb://localhost:27017/lovable', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const AppointmentSchema = new mongoose.Schema({
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
startTime: { type: Date, required: true },
endTime: { type: Date, required: true },
recurring: {
repeatType: { type: String, enum: ['daily', 'weekly', 'monthly'], default: null },
count: { type: Number, default: 0 }
},
createdAt: { type: Date, default: Date.now }
});
const Appointment = mongoose.model('Appointment', AppointmentSchema);
const app = express();
app.use(bodyParser.json());
app.post('/api/appointments', async (req, res) => {
try {
const { userId, startTime, endTime, recurring } = req.body;
// Check for overlapping appointments for the same user.
const overlapping = await Appointment.findOne({
userId,
$or: [
{
startTime: { $lt: new Date(endTime) },
endTime: { $gt: new Date(startTime) }
}
]
});
if (overlapping) {
return res.status(400).json({ error: 'Time slot overlaps with an existing appointment' });
}
const appointment = new Appointment({ userId, startTime, endTime, recurring });
await appointment.save();
res.status(201).json({ success: true, appointment });
} catch (err) {
res.status(500).json({ error: 'Internal server error' });
}
});
app.listen(3000, () => {
console.log('Scheduling API running on port 3000');
});
const express = require('express');
const axios = require('axios');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/lovable', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const ExternalEventSchema = new mongoose.Schema({
externalId: { type: String, required: true, unique: true },
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
title: { type: String, required: true },
startTime: { type: Date, required: true },
endTime: { type: Date, required: true }
});
const ExternalEvent = mongoose.model('ExternalEvent', ExternalEventSchema);
const app = express();
app.use(bodyParser.json());
app.post('/api/webhooks/external-calendar', async (req, res) => {
try {
const event = req.body;
// Assume validation of the webhook signature is done here
const filter = { externalId: event.id };
const update = {
userId: event.user\_id,
title: event.title,
startTime: new Date(event.start\_time),
endTime: new Date(event.end\_time)
};
const options = { upsert: true, new: true };
const savedEvent = await ExternalEvent.findOneAndUpdate(filter, update, options);
res.status(200).json({ success: true, savedEvent });
} catch (error) {
res.status(500).json({ error: 'Error syncing external event' });
}
});
async function syncUserExternalEvents(userId) {
try {
const response = await axios.get(`https://api.externalcalendar.com/users/${userId}/events`, {
headers: { Authorization: 'Bearer YOUR_API_TOKEN' }
});
const events = response.data.events;
for (const event of events) {
await ExternalEvent.findOneAndUpdate(
{ externalId: event.id },
{
userId,
title: event.title,
startTime: new Date(event.start\_time),
endTime: new Date(event.end\_time)
},
{ upsert: true, new: true }
);
}
} catch (err) {
console.error('Failed to sync events:', err.message);
}
}
app.listen(3000, () => {
console.log('Scheduling app API running on port 3000');
});
const express = require('express');
const bodyParser = require('body-parser');
const moment = require('moment');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/lovable', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const AppointmentSchema = new mongoose.Schema({
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
startTime: { type: Date, required: true },
endTime: { type: Date, required: true }
});
const Appointment = mongoose.model('Appointment', AppointmentSchema);
const app = express();
app.use(bodyParser.json());
// This endpoint calculates common available time slots for a set of users on a given day.
app.post('/api/common-availability', async (req, res) => {
const { userIds, date, durationInMinutes } = req.body;
try {
const dayStart = moment(date).startOf('day');
const dayEnd = moment(date).endOf('day');
// Fetch all appointments for the given users on that day.
const appointments = await Appointment.find({
userId: { $in: userIds },
startTime: { $gte: dayStart.toDate() },
endTime: { $lte: dayEnd.toDate() }
}).sort({ startTime: 1 }).exec();
// Build busy time slots for every user.
const busyForUser = userIds.reduce((acc, id) => {
acc[id] = [];
return acc;
}, {});
appointments.forEach(appt => {
busyForUser[appt.userId.toString()].push({
start: moment(appt.startTime),
end: moment(appt.endTime)
});
});
// Calculate free slots for one user given their busy intervals.
function calculateFreeSlots(busyIntervals, startOfDay, endOfDay, minDuration) {
busyIntervals.sort((a, b) => a.start - b.start);
const free = [];
let current = startOfDay.clone();
busyIntervals.forEach(interval => {
if (current.isBefore(interval.start)) {
const freeSlot = { start: current.clone(), end: interval.start.clone() };
if (freeSlot.end.diff(freeSlot.start, 'minutes') >= minDuration) {
free.push(freeSlot);
}
}
if (current.isBefore(interval.end)) {
current = interval.end.clone();
}
});
if (current.isBefore(endOfDay)) {
const freeSlot = { start: current.clone(), end: endOfDay.clone() };
if (freeSlot.end.diff(freeSlot.start, 'minutes') >= minDuration) {
free.push(freeSlot);
}
}
return free;
}
// Build free slots per user.
const freeSlotsByUser = {};
userIds.forEach(id => {
freeSlotsByUser[id] = calculateFreeSlots(busyForUser[id], dayStart, dayEnd, durationInMinutes);
});
// Function to compute intersection between two lists of free slots.
function intersectTwoSlotLists(slotsA, slotsB, minDuration) {
let i = 0, j = 0;
const intersections = [];
while (i < slotsA.length && j < slotsB.length) {
const start = moment.max(slotsA[i].start, slotsB[j].start);
const end = moment.min(slotsA[i].end, slotsB[j].end);
if (end.diff(start, 'minutes') >= minDuration) {
intersections.push({ start, end });
}
if (slotsA[i].end.isBefore(slotsB[j].end)) {
i++;
} else {
j++;
}
}
return intersections;
}
// Intersection of free slots across all users.
let commonSlots = freeSlotsByUser[userIds[0]];
for (let idx = 1; idx < userIds.length; idx++) {
commonSlots = intersectTwoSlotLists(commonSlots, freeSlotsByUser[userIds[idx]], durationInMinutes);
}
const availableSlots = commonSlots.map(slot => ({
startTime: slot.start.toISOString(),
endTime: slot.end.toISOString()
}));
res.json({ availableSlots });
} catch (error) {
res.status(500).json({ error: 'Failed to compute common availability.' });
}
});
app.listen(3000, () => {
console.log('Common availability API running on port 3000');
});
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
Overview and Introduction
Prerequisites
Defining App Requirements and Features
Setting Up Your Development Environment
Integrating AI Code Generators
# Example: Test request to AI Code Generator API
import requests
api_key = "YOUR_API_KEY"
url = "https://api.example.com/generate"
payload = {"prompt": "Generate a simple scheduling function in Python"}
headers = {"Authorization": f"Bearer {api_key}"}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
Designing the Scheduling App Architecture
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.