Skip to content

Commit

Permalink
Fix depart date bug: 7GUIs Flight Booker React (#4850)
Browse files Browse the repository at this point in the history
* Example - 7GUIs Flight Booker

* Fix depart date bug: 7GUIs React

* Remove unused css and null className

* remove unused css rule

* Ensure is latest version

* Fix typo

* Added success notification

* Removed unnecessary import

* Remove unused css
  • Loading branch information
stevebarakat authored May 3, 2024
1 parent a67e99f commit d8877fe
Show file tree
Hide file tree
Showing 21 changed files with 632 additions and 315 deletions.
4 changes: 3 additions & 1 deletion examples/7guis-flight-booker-react/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ Visit the [7GUIs project](https://eugenkiss.github.io/7guis/tasks#flight/ "Fligh

## Screenshots

![App Screenshot](public/flight-booker.jpg)
![App Screenshot](public/flight-booker.png)

[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/statelyai/xstate/tree/main/examples/7guis-flight-booker-react)
74 changes: 53 additions & 21 deletions examples/7guis-flight-booker-react/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion examples/7guis-flight-booker-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
},
"dependencies": {
"@xstate/react": "^4.1.0",
"lucide-react": "^0.366.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"vite-tsconfig-paths": "^4.3.2",
"xstate": "^5.10.0"
},
"devDependencies": {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
122 changes: 50 additions & 72 deletions examples/7guis-flight-booker-react/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,79 +1,57 @@
import { FlightContext } from "./machine";
import { DateInput } from "./DateInput";
import { useRef, useState } from "react";
import { X } from "lucide-react";
import FlightContext from "./machines/flightMachine";
import { BookButton, Header } from "./components";
import { DateSelector, TripSelector } from "./components";
import { TODAY } from "./utils";

const Flight = () => {
const dialogRef = useRef<HTMLDialogElement | null>(null);
export default function App() {
const { send } = FlightContext.useActorRef();
const state = FlightContext.useSelector((state) => state);
const { departDate, returnDate } = state.context;
const isRoundTrip = state.matches({ scheduling: "roundTrip" });
const isBooking = state.matches("booking");
const isBooked = state.matches("booked");

const { startDate, returnDate } = state.context;
const isValidDate = startDate && (!returnDate || returnDate >= startDate);
const canSubmit = state.matches("booking") && isValidDate;

const trip = state.matches({ booking: "roundTrip" }) ? "roundTrip" : "oneWay";
const isValidDepartDate = departDate >= TODAY;
const isValidReturnDate = returnDate >= departDate;

return (
<section>
<button className="open" onClick={() => dialogRef.current?.showModal()}>
Book a flight
</button>
<dialog ref={dialogRef}>
<div style={{ display: "flex", alignItems: "center", gap: "12px" }}>
<h1>
Book Flight
<button
className="close"
onClick={() => {
dialogRef.current?.close();
}}
>
<X />
</button>
</h1>
</div>
<form style={{ display: "flex", flexDirection: "column" }}>
<select
onChange={() => {
send({ type: "CHANGE_TRIP" });
}}
value={trip}
>
<option value="oneWay">one way flight</option>
<option value="roundTrip">return flight</option>
</select>
<DateInput
value={startDate}
onChange={(value: string) =>
send({ type: "CHANGE_START_DATE", value })
}
label="Start date"
/>
<DateInput
value={returnDate}
onChange={(value: string) =>
send({ type: "CHANGE_RETURN_DATE", value })
}
disabled={trip === "oneWay" || !startDate}
label="Return date"
/>
<button
type="button"
onClick={() => send({ type: "BOOK" })}
disabled={!canSubmit}
>
{state.matches("booking") && "Book"}
{state.matches("booked") && "Success!"}
</button>
</form>
</dialog>
</section>
<main>
<Header>Book Flight</Header>
<TripSelector
id="Trip Type"
isBooking={isBooking}
isBooked={isBooked}
tripType={isRoundTrip ? "roundTrip" : "oneWay"}
/>
<DateSelector
id="Depart Date"
value={departDate}
isValidDate={isValidDepartDate}
disabled={isBooking || isBooked}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
send({
type: "CHANGE_DEPART_DATE",
value: e.currentTarget.value,
})
}
/>
<DateSelector
id="Return Date"
value={returnDate}
isValidDate={isValidReturnDate}
disabled={!isRoundTrip}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
send({
type: "CHANGE_RETURN_DATE",
value: e.currentTarget.value,
})
}
/>
<BookButton
eventType={isRoundTrip ? "BOOK_RETURN" : "BOOK_DEPART"}
isBooking={isBooking}
isBooked={isBooked}
/>
</main>
);
};

const App = () => {
return <Flight />;
};

export default App;
}
22 changes: 0 additions & 22 deletions examples/7guis-flight-booker-react/src/DateInput.tsx

This file was deleted.

39 changes: 39 additions & 0 deletions examples/7guis-flight-booker-react/src/components/BookButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import FlightContext from "../machines/flightMachine";

type Props = {
isBooking: boolean;
isBooked: boolean;
eventType: EventType;
};

export default function BookButton({ eventType, isBooking, isBooked }: Props) {
const { send } = FlightContext.useActorRef();
const state = FlightContext.useSelector((state) => state);
const isValidDepartDate = state.can({ type: eventType });
const canBook = !isBooked && isValidDepartDate;

const bookFlight = () => send({ type: eventType });

const successMessage = (
<>
<h2>You booked a flight!</h2>
<p>
<span>Departs:</span> {state.context.departDate}
</p>
<p>
<span>Returns:</span> {state.context.returnDate}
</p>
</>
);

return (
<>
<dialog open={isBooking || isBooked}>
{isBooking ? <p>Booking...</p> : successMessage}
</dialog>
<button onClick={bookFlight} disabled={!canBook}>
{isBooking ? "Booking" : isBooked ? "Booked!" : "Book"}
</button>
</>
);
}
Loading

0 comments on commit d8877fe

Please sign in to comment.