A trip planner built for CSC 470 at the University of Illinois Springfield. It keeps everything about a trip in one place: the dates, a day-by-day itinerary, flights, and hotels, with the confirmation numbers you always end up hunting for.
The problem
Trip details scatter across email confirmations, notes, and screenshots. The goal was a simple app where a traveler creates a trip once and every day of it, plus the bookings around it, lives on a single page.
How it works
The interface is a Streamlit app. Creating a trip generates an itinerary with a section for every day between the start and end dates. Each day takes activities with a time, cost, address, and confirmation number; flights record airline, flight number, seat, and cost; hotels record address, rooms, and cost. Adding anything happens in modal dialogs, and session state handles moving between the trip list and a trip's detail view.
Persistence is SQLite, in four tables that all reference the trip they belong to. All database access lives in its own module, separate from the UI, which kept the Streamlit code focused on layout and made the data layer testable on its own.
Tested data layer
A unittest suite covers the core operations: creating a trip, fetching it by id, attaching flights and hotels, adding and reading back activities, and deleting a trip.
def test_create_trip(self):
title = "Test Trip"
start_date = datetime.now().date()
end_date = start_date + timedelta(days=7)
create_trip(title, start_date, end_date)
trips = get_all_trips()
self.assertEqual(len(trips), 1)
self.assertEqual(trips[0].title, title)What I'd change next
- Isolate the tests. They clean and reuse the real trips.db file; pointing them at an in-memory database would make them safe to run anywhere.
- Reuse one database connection instead of opening a new one for every query.
- Move from st.experimental_dialog to Streamlit's stable dialog API, and show a per-trip total cost from the costs already being recorded.