Next-gen travel app. Vercel ai sdk, claude haiku and RxDB allow you to generate complete travel itineraries. Store your data locally using RxDB and retrieve it offline when your international data plan runs out.
Data is stored locally in your browser, ensuring that users can access and interact with the app even without an internet connection.
Implement RxDB for robust offline-first data management, ensuring seamless sync between local and remote databases.
Utilize React Query for efficient state management and data fetching across multiple devices and network conditions.
Implement service workers and a web app manifest for a native app-like experience, enabling offline functionality and home screen installation.
Cult Offline Travel Stash is an offline-first travel planning application designed to help users manage their itineraries and travel lists seamlessly.
Unzip the repository:
shunzip cult-offline-travel-stash.zip cd cult-offline-travel-stash
Install dependencies:
shpnpm install
Create an .env
file:
Only one of the following environment variables is required.
plaintextOPENAI_API_KEY=your-openai-api-key GROQ_API_KEY=your-groq-api-key ANTHROPIC_API_KEY=your-anthropic-api-key
Run the development server:
shpnpm dev
The application will run at http://localhost:3000
.
.
├── app
│ ├── [id]
│ │ ├── page.tsx
│ ├── api
│ │ ├── create-itinerary
│ │ │ ├── route.ts
│ │ ├── edit-itinerary
│ │ │ ├── route.ts
│ │ ├── ai-json-completion.ts
│ │ ├── prompts.ts
│ │ ├── schemas.ts
│ ├── share
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx
│ ├── page.tsx
│ ├── provider.tsx
├── components
│ ├── cult
│ ├── forms
│ ├── ui
│ │ ├── action-button-drawer.tsx
│ │ ├── cards.tsx
│ │ ├── dashboard.tsx
│ │ ├── grouped-list.tsx
│ │ ├── list-filter.tsx
│ │ ├── list-item-card.tsx
│ │ ├── list-tabs.tsx
│ │ ├── loading-button.tsx
│ │ ├── logo.tsx
│ │ ├── nav.tsx
│ │ ├── trip-overview-card.tsx
│ │ ├── trip-overview-list.tsx
├── db
│ ├── initialize.ts
│ ├── model.tsx
├── lib
├── node_modules
├── public
├── .env.example
├── .eslintrc.json
├── .gitignore
├── components.json
├── next-env.d.ts
├── next.config.js
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── README.md
├── tailwind.config.ts
└── tsconfig.json
Your documentation looks great! Here's a slightly refined version to ensure clarity and flow:
An offline-first application ensures that users can access and interact with the app even without an internet connection. This is achieved using technologies like service workers and offline storage mechanisms.
RxDB (Reactive Database) is a NoSQL database for JavaScript applications. It provides real-time capabilities and supports offline functionality, making it a perfect choice for building offline-first applications. Here's a detailed look at how RxDB is used in this project:
The tripsSchema
defines the structure of the trips collection:
typescriptconst tripsSchema = { version: 0, primaryKey: "tripId", type: "object", properties: { tripId: { type: "string", maxLength: 100 }, tripName: { type: "string", maxLength: 100 }, }, required: ["tripId", "tripName"], };
The travelItinerarySchema
defines the structure of the travel itinerary collection:
typescriptconst travelItinerarySchema = { version: 0, primaryKey: "id", type: "object", properties: { id: { type: "string", maxLength: 100 }, tripId: { type: "string", maxLength: 100, ref: "trips_v0" }, // Reference to the trips_v0 table tripName: { type: "string", maxLength: 100 }, title: { type: "string", maxLength: 100 }, description: { type: "string", maxLength: 500 }, image: { type: "string", format: "uri" }, location: { type: "object", properties: { name: { type: "string", maxLength: 100 }, address: { type: "string", maxLength: 200 }, latitude: { type: "number", minimum: -90, maximum: 90 }, longitude: { type: "number", minimum: -180, maximum: 180 }, placeId: { type: "string" }, }, required: ["name", "address"], }, day: { type: "string" }, timeOfDay: { type: "string", maxLength: 50 }, mapLink: { type: "string", format: "uri" }, status: { type: "string", enum: ["done", "not done", "later"] }, priority: { type: "string", enum: ["low", "medium", "high"] }, notes: { type: "string", maxLength: 1000 }, dueDate: { type: "string", format: "date" }, estimatedTime: { type: "string", maxLength: 50 }, reminderEnabled: { type: "boolean" }, reminderTime: { type: "string", format: "date-time" }, createdBy: { type: "string" }, lastUpdatedBy: { type: "string" }, category: { type: "string", maxLength: 50 }, startDateTime: { type: "string", format: "date-time" }, sequence: { type: "integer", minimum: 0 }, }, required: ["id", "title", "status", "startDateTime", "sequence"], };
The initialize
function sets up the database and adds the required collections:
typescriptexport const initialize = async () => { // Add plugins required for RxDB await addRxPlugin(RxDBDevModePlugin); await addRxPlugin(RxDBQueryBuilderPlugin); await addRxPlugin(RxDBUpdatePlugin); // Create RxDB const db = await createRxDatabase({ name: "mydatabase", // Change this to whatever database name you want storage: getRxStorageDexie(), ignoreDuplicate: true, }); await db.addCollections({ trips_v0: { schema: tripsSchema, }, trip_itinerary_v0: { schema: travelItinerarySchema, }, }); return db; };
Progressive Web Apps (PWAs) are web applications that combine the best features of web and mobile apps. They are designed to be reliable, fast, and engaging, providing a native app-like experience on the web.
In the context of Next.js, PWAs are integrated using plugins like @ducanh2912/next-pwa
, which simplifies the process of setting up service workers and caching strategies. By configuring the plugin, you can enhance your Next.js app with PWA capabilities, providing a reliable, fast, and engaging user experience even in offline scenarios.
This project uses @ducanh2912/next-pwa
to add PWA capabilities, ensuring the application can work offline and provide a native app-like experience. Here's how it is integrated:
Install @ducanh2912/next-pwa
:
shpnpm install @ducanh2912/next-pwa
Configure next.config.js
:
javascriptconst withPWA = require("@ducanh2912/next-pwa").default({ cacheOnFrontEndNav: true, aggressiveFrontEndNavCaching: true, reloadOnOnline: true, swcMinify: true, dest: "public", fallbacks: { document: "/offline", // Custom offline fallback page }, workboxOptions: { disableDevLogs: true, }, }); /** @type {import('next').NextConfig} */ const nextConfig = { // Other Next.js configurations }; module.exports = withPWA(nextConfig);
cacheOnFrontEndNav: true
: This option caches navigations on the frontend, enhancing performance by reducing server requests for frequently visited pages.aggressiveFrontEndNavCaching: true
: Implements more aggressive caching strategies for frontend navigation, ensuring faster load times and improved offline capabilities.reloadOnOnline: true
: Forces a reload of the page when the network connection is restored, ensuring that users see the latest content when they come back online.swcMinify: true
: Enables SWC-based minification for faster build times and optimized performance.dest: "public"
: Specifies the directory where the service worker and other PWA assets are generated.fallbacks
: Defines fallback assets to use when the network is unavailable. In this case:
document: "/offline"
: Specifies a custom offline fallback page to be served when the user is offline.workboxOptions
: Provides additional configurations for Workbox, the tool used by next-pwa
to generate service workers.
disableDevLogs: true
: Disables Workbox logs in the development environment to keep the console clean.By setting up PWA, the app can cache resources and work offline, enhancing the user experience, especially in areas with limited or no internet connectivity.
If you run into any issues or have any questions, feel free to reach out on Twitter @nolansym.
One-time payment, lifetime access
One-time payment, 1 year of updates