Tutorial: Erstellung einer Museumsbuchungs-App mit Next.js und Timerise API

Dieses Tutorial führt Sie durch die Erstellung einer Museumsbuchungs-App mit Next.js, TypeScript, Timerise API, Apollo Client und Tailwind CSS. Wir werden uns auf die Integration der Headless Timerise API konzentrieren und die Vorteile einer solchen Lösung aufzeigen.

Voraussetzungen

  • Grundkenntnisse in TypeScript und React
  • Node.js installiert
  • Zugang zur Timerise-API

Schritt 1: Einrichten des Next.js-Projekts

Der erste Schritt bei der Erstellung unserer Museumsbuchungs-App besteht darin, ein neues Next.js-Projekt einzurichten. Next.js führt einen verbesserten Einrichtungsprozess ein, der es Ihnen ermöglicht, wichtige Funktionen wie Tailwind CSS, ESLint und mehr von Anfang an zu konfigurieren. Dieser schlanke Ansatz vereinfacht die anfängliche Einrichtung des Projekts, so dass wir uns auf die Entwicklung der Kernfunktionen der App konzentrieren können.

Eine neue Next.js-App erstellen
Führen Sie den Befehl aus, um die Erstellung einer neuen Next.js-App zu initiieren. Sie werden aufgefordert, verschiedene Konfigurationsoptionen auszuwählen, darunter die Integration von Tailwind CSS, das wir für das Styling unserer App verwenden werden.

Bash
npx create-next-app@latest museum-booking-app --typescript
cd museum-booking-app

Wenn Sie dazu aufgefordert werden, wählen Sie Ihre bevorzugten Konfigurationen:

  • ESLint: Wählen Sie‚Ja‚ für Code-Qualitätsprüfungen.
  • Tailwind CSS: Wählen Sie„Ja„, um Tailwind CSS automatisch einzurichten.
  • Verwenden Sie das Verzeichnis src/: Wählen Sie„Ja“ für eine saubere Projektstruktur.
  • App-Router: Wählen Sie„Ja„, um die neue App-Router-Funktion zu nutzen.
  • Standard-Import-Alias anpassen: Wählen Sie„Ja„, wenn Sie die Importpfade anpassen möchten.

Schritt 2: Installation der Abhängigkeiten

Mit dem erweiterten Next.js-Setup sind wichtige Abhängigkeiten wie Tailwind CSS bereits integriert. Wir müssen jedoch noch weitere Pakete installieren, die für unsere Anwendung wichtig sind, insbesondere Apollo Client für die Bearbeitung von GraphQL-Abfragen und Mutationen mit der Timerise-API.

Apollo-Client installieren
Apollo Client ist eine umfassende State-Management-Bibliothek für JavaScript, mit der Sie sowohl lokale als auch entfernte Daten mit GraphQL verwalten können. Dies wird unser wichtigstes Werkzeug für die Interaktion mit der Timerise-API sein.

Bash
npm install @apollo/client graphql

Überprüfen der Tailwind-CSS-Konfiguration (optional)
Da Tailwind CSS während der Projektinitialisierung eingerichtet wurde, überprüfen Sie die Konfigurationsdateien (tailwind.config.js und postcss.config.js), um sicherzustellen, dass sie den Styling-Anforderungen Ihres Projekts entsprechen. Sie können bei Bedarf Anpassungen vornehmen, um die Tailwind-Einrichtung zu individualisieren.

Zusätzliche Abhängigkeiten
Je nach den Anforderungen Ihres Projekts benötigen Sie möglicherweise weitere Abhängigkeiten. Wenn Sie z. B. planen, Daten und Zeiten zu verarbeiten (häufig in einer Buchungs-App), sollten Sie die Installation von date-fns in Betracht ziehen:

Bash
npm install date-fns

Schritt 3: Apollo Client konfigurieren

Nun, da unser Projekt mit den notwendigen Abhängigkeiten eingerichtet ist, ist es an der Zeit, Apollo Client zu konfigurieren. Apollo Client ist ein leistungsfähiges und flexibles Werkzeug zur Verwaltung lokaler und entfernter Daten in JavaScript-Anwendungen. Es vereinfacht den Prozess der Interaktion mit GraphQL-APIs, wie der von uns verwendeten Timerise-API. Durch die Einrichtung von Apollo Client ermöglichen wir unserer Anwendung die effiziente Ausführung von Abfragen und Mutationen, die Verwaltung von Ladezuständen, die Zwischenspeicherung von Daten und die Behandlung von Fehlern, was wesentliche Aspekte der Interaktion mit unserem Buchungssystem sind.

Apollo-Client in lib/apolloClient.ts einrichten

Wir müssen eine Instanz von Apollo Client erstellen, die auf unseren GraphQL API Endpunkt zeigt. Diese Instanz wird in der gesamten Anwendung zur Interaktion mit der Timerise-API verwendet.

TypScript
import { ApolloClient, InMemoryCache } from '@apollo/client';

const apolloClient = new ApolloClient({
  uri: 'https://sandbox-api.timerise.io/v1',
  cache: new InMemoryCache(),
});

export default apolloClient;
  • Die Website uri wird auf den Endpunkt der Timerise-API gesetzt.
  • InMemoryCache wird verwendet, um Abfrageergebnisse nach dem Abruf zwischenzuspeichern. Dies trägt dazu bei, die Leistung unserer Anwendung zu optimieren, indem die Anzahl der erforderlichen API-Aufrufe verringert wird.

Diese Konfiguration ist ein wichtiger Schritt, damit unsere Anwendung effektiv mit der Timerise-API kommunizieren kann. Damit ist der Grundstein für die nächsten Schritte gelegt, in denen wir GraphQL-Abfragen und -Mutationen zur Bearbeitung von Buchungen erstellen und ausführen werden.

Umhüllen Sie Ihre Anwendung mit ApolloProvider
Importieren Sie in Ihrer app/page.tsx-Datei den ApolloProvider von @apollo/client und Ihre Apollo-Client-Instanz. Dann umhüllen Sie die Stammkomponente Ihrer Anwendung mit und übergeben die Client-Instanz an sie.

TypScript
'use client'
import { ApolloProvider } from '@apollo/client';
import apolloClient from '../lib/apolloClient';
import SlotSelection from "@/components/SlotSelection";

export default function Home() {
  return (
    <ApolloProvider client={apolloClient}>
      <SlotSelection serviceId="YourServiceId" />
    </ApolloProvider>
  );
};

Schritt 4: Erstellen von GraphQL-Abfragen und Mutationen

Mit GraphQL-Abfragen können wir Daten abrufen, und mit Mutationen können wir Daten ändern. Hier definieren wir die GraphQL-Abfragen und Mutationen, die für die Interaktion mit der Timerise-API zum Abrufen von Diensten und Buchen von Slots erforderlich sind.

Definieren Sie GraphQL-Operationen in graphql/queries.ts

TypScript
import { gql } from '@apollo/client';

export const SERVICE_QUERY = gql`
  query Service($serviceId: ID!, $slotType: SlotType!) {
    service(serviceId: $serviceId) {
      serviceId
      title
      description
      media {
        title
        url
      }
      slots(slotType: $slotType) {
        slotId
        dateTimeFrom
        dateTimeTo
        duration
        quantity
      }
    }
  }
`;

export const BOOKING_QUERY = gql`
  query Booking($bookingId: ID!) {
    booking(bookingId: $bookingId) {
      bookingId
      shortId
      shortUrl
      qrUrl
      status
    }
  }
`;

Definieren Sie Mutation in graphql/mutations.ts

TypScript
import { gql } from '@apollo/client';

export const BOOKING_CREATE_MUTATION = gql`
  mutation BookingCreate($serviceId: ID!, $slots: [ID]) {
    bookingCreate(serviceId: $serviceId, slots: $slots) {
      bookingId
      qrUrl
      shortUrl
      status
    }
  }
`;

Schritt 5: Aufbau der Anwendungskomponenten

Nachdem wir unsere API-Interaktionen definiert haben, konzentrieren wir uns nun auf die Erstellung der React-Komponenten. Diese Komponenten bilden die Schnittstelle für die Auswahl von Zeitnischen und die Bestätigung von Buchungen, wobei die von uns eingerichteten Abfragen und Mutationen verwendet werden.

Slot-Auswahl-Komponente (SlotSelection.tsx)
Code und Erklärung für die Erstellung einer Komponente zur Auswahl verfügbarer Slots.

TypScript
import React, { useState } from 'react';
import { useRouter } from 'next/navigation'
import { useQuery, useMutation } from '@apollo/client';
import { SERVICE_QUERY } from '../graphql/queries';
import { BOOKING_CREATE_MUTATION } from '../graphql/mutations';

const SlotSelection = ({ serviceId }: { serviceId: string }) => {
  const router = useRouter();
  const [selectedSlot, setSelectedSlot] = useState<string|null>(null);
  const { loading, error, data } = useQuery(SERVICE_QUERY, {
    variables: { serviceId: serviceId, slotType: "AVAILABLE" },
  });
  const [createBooking, { data: bookingData, loading: bookingLoading, error: bookingError }] = useMutation(BOOKING_CREATE_MUTATION);

  if (loading || bookingLoading) return <p>Loading...</p>;
  if (error || bookingError) return <p>Error loading.</p>;

  const handleSlotSelect = async (slotId: string) => {
    setSelectedSlot(slotId);
    try {
      const { data } = await createBooking({
        variables: { serviceId, slots: [slotId] }
      });
      if (data.bookingCreate && data.bookingCreate.bookingId) {
        router.push(`/confirmation/${data.bookingCreate.bookingId}`);
      }
    } catch (error) {
      console.error("Error creating booking:", error);
      // Handle booking error
    }
  };

  return (
    <div className="p-4">
      <h2 className="text-lg font-semibold">Select a Slot</h2>
      <ul>
        {data.service.slots.map((slot: { slotId: string, dateTimeFrom: Date }) => (
          <li key={slot.slotId} className="my-2">
            <button
              className={`p-2 border ${selectedSlot === slot.slotId ? 'border-blue-500' : 'border-gray-300'}`}
              onClick={() => handleSlotSelect(slot.slotId)}>
              {new Date(slot.dateTimeFrom).toLocaleString()}
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default SlotSelection;

Bestätigungskomponente (ConfirmationView.tsx)
Code und Erklärung für die Erstellung einer Komponente, die Details zur Buchungsbestätigung anzeigt, einschließlich des QR-Codes.

TypScript
import React from 'react';
import { useQuery } from '@apollo/client';
import { BOOKING_QUERY } from '@/graphql/queries';

const ConfirmationView = ({ bookingId }: { bookingId: string }) => {
  const { loading, error, data } = useQuery(BOOKING_QUERY, {
    variables: { bookingId: bookingId },
  });

  if (loading) return <p>Loading booking...</p>;
  if (error) return <p>Error loading booking.</p>;
  return (
    <div className="p-4">
      <h2 className="text-lg font-semibold">Booking status: {data.booking.status}</h2>
      <p className="my-2">Booking ID: {data.booking.shortId}</p>
      <div className="my-2">
        <img src={data.booking.qrUrl} alt="QR Code" className="w-32 h-32" />
      </div>
      <a href={data.booking.shortUrl} target="_blank" className="text-blue-500">View booking page</a>
    </div>
  );
};

export default ConfirmationView;

Schritt 6: Front-End-Entwicklung mit Tailwind CSS

In diesem Schritt geht es um das Styling unserer Anwendung. Tailwind CSS, ein Utility-First-CSS-Framework, wird für die Gestaltung einer sauberen und reaktionsfähigen Benutzeroberfläche verwendet. Dieser Ansatz ermöglicht es uns, schnell und effizient ein visuell ansprechendes Frontend zu erstellen, das die Benutzerfreundlichkeit erhöht.

In SlotSelection.tsx werden wir die Tailwind-Klassen für Layout, Abstände und Ästhetik anwenden.

TypScript
return (
  <div className="p-4 max-w-md mx-auto">
    <h2 className="text-2xl font-bold text-center text-white-800 mb-4">Select a Slot</h2>
    <ul className="list-none space-y-3">
        {data.service.slots.map((slot: { slotId: string, dateTimeFrom: Date }) => (
          <li key={slot.slotId} className="flex justify-between items-center p-3 border rounded-lg shadow-sm">
            <span className="text-white-600">{new Date(slot.dateTimeFrom).toLocaleString()}</span>
            <button
              className={`px-4 py-2 rounded-lg text-black ${selectedSlot === slot.slotId ? 'bg-blue-500' : 'bg-gray-300'}`}
              onClick={() => handleSlotSelect(slot.slotId)}>
              Select
            </button>
          </li>
        ))}
    </ul>
  </div>
);

Geben Sie in ConfirmationView.tsx die Details der Buchungsbestätigung ein.

TypScript
return (
  <div className="p-4 max-w-md mx-auto">
    <h2 className="text-2xl font-bold text-center text-white-800 mb-4">BOOKING {data.booking.status}</h2>
    <div className="bg-white shadow overflow-hidden sm:rounded-lg p-4">
      <p className="text-center text-gray-600 mb-2">ID: <span className="text-gray-800 font-semibold">{data.booking.shortId}</span></p>
      <div className="text-center">
        <img src={data.booking.qrUrl} alt="QR Code" className="w-32 h-32 inline-block mb-3" />
        <p className="text-sm text-gray-600">Scan this QR code at the entrance</p>
      </div>
      <a href={data.booking.shortUrl} target="_blank" rel="noopener noreferrer" className="text-blue-500 hover:text-blue-700 text-center block mt-4">
        View booking page
      </a>
    </div>
  </div>
);

Schritt 8: Einsatz mit Vercel

Durch die Bereitstellung unserer Anwendung wird sie für Benutzer im Internet zugänglich. Vercel, das gut mit Next.js harmoniert, bietet eine nahtlose Bereitstellung. Es automatisiert den Prozess vom Code-Push bis zur Produktion, handhabt serverlose Funktionen, statisches File-Serving und mehr und sorgt für optimale Leistung und Skalierbarkeit.

Veröffentlichen Sie Ihren Code auf GitHub
Stellen Sie vor der Bereitstellung sicher, dass Ihr Projekt in ein GitHub-Repository übertragen wird:

Bash
git init
git add .
git commit -m "Init commit"
git branch -M main
git remote add origin https://github.com/your-username/your-repo-name.git
git push -u origin main

Bereitstellung auf Vercel einrichten

  1. Melden Sie sich bei Vercel an und verbinden Sie Ihr GitHub-Konto.
  2. Wählen Sie das Repository, das Sie gerade verschoben haben.
  3. Vercel erkennt automatisch, dass es sich um eine Next.js-App handelt und schlägt Build-Einstellungen vor. Akzeptieren Sie sie oder ändern Sie sie nach Bedarf.
  4. Klicken Sie auf„Bereitstellen„, um den Bereitstellungsprozess zu starten. Vercel kümmert sich um die Erstellung und Bereitstellung und stellt Ihnen eine Live-URL zur Verfügung.

Vercel bietet Funktionen wie automatisches HTTPS, Unterstützung für benutzerdefinierte Domains und Echtzeit-Analysen. Sie können auch Umgebungsvariablen setzen und andere Einstellungen direkt über das Vercel-Dashboard verwalten.

Zugriff auf den vollständigen Anwendungscode

Um dieses Tutorial zu ergänzen und Ihre Lernerfahrung zu verbessern, haben wir den vollständigen Quellcode der Museumsbuchungsanwendung auf GitHub zur Verfügung gestellt. Dies ist eine großartige Gelegenheit für Sie, die Codebasis zu erkunden, mit Änderungen zu experimentieren und die Struktur und Funktionalität der Anwendung im Detail zu verstehen.

Zugriff auf das Repository
Der gesamte Quellcode für die Museumsbuchungsanwendung wird auf GitHub gehostet. Sie können sie unter der folgenden URL aufrufen: https://github.com/timerise-io/museum-booking-app

Klonen des Repositorys
Um mit dem Code auf Ihrem lokalen Rechner zu arbeiten, klonen Sie das Repository mit Git:

Bash
git clone https://github.com/timerise-io/museum-booking-app.git
cd museum-booking-app

Erforschen und Ändern
Sobald Sie den Code haben, können Sie ihn erforschen und verändern. Egal, ob Sie bestimmte Funktionen verstehen, neue Funktionen hinzufügen oder die Benutzeroberfläche anpassen möchten, diese Codebasis kann als praktischer Ausgangspunkt dienen.

Besuchen Sie die Demo
Sie können die Live-Demo der Museum Booking App unter der folgenden URL aufrufen: https://museum-booking-app.vercel.app/

Schlussfolgerung

Dieses Tutorial bietet eine Schritt-für-Schritt-Anleitung für das Einrichten einer Next.js-Anwendung, die Integration mit einer Headless-API wie Timerise und deren Bereitstellung. Die Codeschnipsel sind wichtige Teile der Anwendung, die zeigen, wie man die Timerise-API mit einer Next.js-Anwendung unter Verwendung von Apollo Client for GraphQL integriert.