The Cruise Drink Calculator is a web application designed to help cruise travelers make informed decisions about purchasing drink packages. By comparing the package price to the estimated cost of individual drinks, users can determine if a drink package offers good value for their specific consumption habits.
Key Features
- Interactive cruise line and ship selection from a database of options
- Departure date picker with automatic itinerary lookup
- Multi-currency support (USD, AUD, CAD, EUR, GBP) with real-time conversion
- Customizable drink package pricing input
- Daily drink consumption estimator for both sea and port days
- Individual drink price adjustment capabilities
- Detailed cost breakdown with per-drink analysis
- Real-time calculation of potential savings
- Mobile-responsive design with intuitive interface
- User feedback system for suggesting changes or improvements
Development Process
The Cruise Drink Calculator was developed to solve a common problem faced by cruise travelers: determining whether a pre-paid drink package is economically worthwhile. The development process involved:
- Research Phase: Gathering data on cruise lines, ships, and typical drink package pricing
- Database Design: Creating a relational database schema to store cruise and pricing information
- User Experience Design: Creating an intuitive interface that guides users through the calculation process
- Frontend Development: Building the interactive calculator with responsive design
- Backend Implementation: Developing API routes for data retrieval and calculation logic
- Testing: Validating calculations and usability across devices
- Deployment: Setting up hosting and continuous integration
Technical Stack
Frontend
- Framework: Next.js 14 with React 18 and TypeScript
- Styling: Tailwind CSS for responsive design and custom styling
- UI Components: Custom React components with icon integration
- State Management: React hooks for local state management
- Currency Conversion: Integration with exchange rate API
- Fonts: Custom Geist font family (variable fonts) for modern typography
Backend
- Framework: Next.js API routes for serverless functions
- Database: PostgreSQL for data storage
- ORM: Prisma for type-safe database queries and migrations
- API Endpoints: RESTful endpoints for cruise data and calculations
- Data Models: Structured models for cruise lines, ships, itineraries, and pricing
Infrastructure
- Hosting: Coolify on self-hosted AWS ec2 Instance
- CI/CD: Automated build and deployment pipeline
- Database Hosting: Managed PostgreSQL instance
- Analytics: Google Tag Manager for usage tracking
- Monetization: Buy Me A Coffee integration for optional user support
Technical Challenges
Dynamic Pricing Logic
The calculation engine needed to account for various factors that affect the value proposition of drink packages:
// Simplified version of the calculation logic
const calculateResults = async () => {
try {
const response = await fetch("/api/calculate", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
cruiseLineId: selectedCruiseLineId,
seaDays,
portDays,
consumption,
packagePrice: packagePriceUSD,
drinkPrices,
}),
});
const data: CalculationResult = await response.json();
setResult(data);
} catch (err) {
setError(err instanceof Error ? err.message : "An unknown error occurred");
}
};
Multi-Currency Support
Implementing currency conversion required integration with an external API and careful handling of exchange rates:
const convertCurrency = async (
amount: number,
from: Currency,
to: Currency
) => {
if (from === to) return amount;
try {
const response = await fetch(
`https://api.exchangerate-api.com/v4/latest/${from}`
);
if (!response.ok) {
throw new Error("Failed to fetch exchange rates");
}
const data = await response.json();
const rate = data.rates[to];
return amount * rate;
} catch (error) {
console.error("Error converting currency:", error);
return amount; // Return original amount if conversion fails
}
};
Cruise Itinerary Management
Creating a system to look up cruise itineraries or allow users to create new ones:
const findCruise = async () => {
if (!selectedCruiseLineId || !selectedShipId || !departureDate) {
setError("Please select a cruise line, ship, and departure date.");
return;
}
try {
const response = await fetch(
`/api/find-cruise?cruiseLineId=${selectedCruiseLineId}&shipId=${selectedShipId}&departureDate=${departureDate}`
);
if (!response.ok) {
if (response.status === 404) {
setCruiseNotFound(true);
setError(
"Cruise not found. Please enter sea days and port days to create a new cruise."
);
return;
}
throw new Error("Failed to find cruise");
}
const data = await response.json();
setSeaDays(data.seaDays);
setPortDays(data.portDays);
setCruiseNotFound(false);
setError(null);
} catch (error) {
setError("Failed to find cruise");
}
};
Future Enhancements
The application roadmap includes several planned improvements:
- Adding more cruise lines and updating ship information
- Implementing user accounts to save calculations
- Creating a comparison feature to evaluate different packages
- Adding multi-language support for international travelers
- Expanding drink types and package options
- Integrating with cruise line APIs for real-time pricing (where available)
- Adding a progressive web app (PWA) capability for offline use
Visit the Cruise Drink Calculator to try it out and see if a drink package would save you money on your next cruise.