Hello! Welcome back.
In our last session, we constructed a fantastic multi-step checkout form using React Hook Form and Material-UI. The form is user-friendly and collects all the necessary shipping and payment information, but the final "Place Order" button is still just a placeholder.
Today, we'll bring it to life. Our goal is to submit the final order data from React to a new order-creation endpoint in your Laravel API. This is the moment where the frontend and backend of your e-commerce application truly connect, turning a user's cart into a confirmed order.
1. Creating the Order Endpoint in Laravel
First things first, our React application needs a destination to send the order data. As a Laravel developer, this part will be very familiar to you. We need to define a new API route and a controller method to handle the incoming request.
Let's create a POST endpoint at /api/orders.
1. Define the Route
Open your Laravel project and add the following line to your routes/api.php file.
// routes/api.php
use App\Http\Controllers\OrderController;
// ... other routes
Route::post('/orders', [OrderController::class, 'store']);
If you don't have an OrderController yet, you can create one with the artisan command: php artisan make:controller OrderController.
2. Create the Controller Method
Now, in app/Http/Controllers/OrderController.php, let's create the store method. For this lesson, we will keep it simple. We'll receive the request, log its contents to see if it's arriving correctly, and return a success response. In a full production application, this is where you would perform validation and save the order details to your database.
// app/Http/Controllers/OrderController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log; // Import the Log facade
class OrderController extends Controller
{
/**
* Store a newly created order in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function store(Request $request)
{
// Log the incoming data for debugging
Log::info('Order creation request received:', $request->all());
// Here you would typically validate the data:
// $validatedData = $request->validate([
// 'cartItems' => 'required|array',
// 'shippingInfo.firstName' => 'required|string',
// // ... other validation rules
// ]);
// And then create the order in your database:
// $order = Order::create([...]);
// For now, just return a success response with a mock order ID.
return response()->json([
'message' => 'Order created successfully!',
'orderId' => uniqid() // Generate a dummy order ID
], 201); // 201 Created status
}
}
With this in place, your Laravel backend is now ready to accept order creation requests.
2. Preparing React for Submission
Back in your React application, we need to make two key changes to the Checkout.jsx component:
- Install
axios, a popular library for making HTTP requests. - Update the form submission logic to differentiate between navigating to the next step and submitting the final order.
First, open your terminal in the React project's root directory and install axios:
npm install axios
Next, let's modify the onSubmit handler in Checkout.jsx. Currently, it calls handleNext() on every submission. We need to change it so that on the final step, it calls a new function, processOrder, instead.
Update your Checkout.jsx file:
// src/pages/Checkout.jsx
import React, { useState, useContext } from 'react'; // Add useContext
import axios from 'axios'; // Import axios
import { useForm, FormProvider } from 'react-hook-form';
import { Container, Paper, Stepper, /*...,*/ Box } from '@mui/material';
import { CartContext } from '../context/CartContext'; // Import your CartContext
// ... (imports for ShippingForm, PaymentForm, etc.)
const steps = ['Shipping address', 'Payment details', 'Review your order'];
// ... (getStepContent function remains the same)
export default function Checkout() {
const [activeStep, setActiveStep] = useState(0);
const { cart, clearCart } = useContext(CartContext); // Get cart data and clear function
const methods = useForm();
const handleNext = () => {
setActiveStep(activeStep + 1);
};
const handleBack = () => {
setActiveStep(activeStep - 1);
};
// The new function to handle final submission
async function processOrder(formData) {
console.log('Final form data:', formData);
// We'll implement the API call here in the next section
// For now, let's just proceed to the thank you page
handleNext();
}
// The updated submit handler
const handleFormSubmit = (data) => {
if (activeStep === steps.length - 1) {
// If it's the last step, process the order
processOrder(data);
} else {
// Otherwise, just go to the next step
handleNext();
}
};
return (
<Container /* ...props */>
<Paper /* ...props */>
{/* ... Stepper and Typography */}
{activeStep === steps.length ? (
// ... Thank you message
) : (
<FormProvider {...methods}>
{/* The key change is here: */}
<form onSubmit={methods.handleSubmit(handleFormSubmit)}>
{getStepContent(activeStep)}
<Box /* ...props */>
{/* ... Back button */}
<Button
variant="contained"
type="submit"
sx={{ mt: 3, ml: 1 }}
>
{activeStep === steps.length - 1 ? 'Place order' : 'Next'}
</Button>
</Box>
</form>
</FormProvider>
)}
</Paper>
</Container>
);
}
By wrapping our logic in handleFormSubmit, we now have a clear distinction. react-hook-form's handleSubmit will pass the collected form data to our function, which then decides whether to advance the stepper or trigger the final API call.
3. Sending the POST Request with Axios
Now for the final piece: implementing the processOrder function to send the data to Laravel. This involves structuring the payload and making the axios.post call.
The pattern for sending a POST request from a React component to a Laravel backend is quite standard. The following resource demonstrates this exact interaction, albeit with a simpler example.
How to Use Laravel With React.js: An Easy-to-Follow Tutorial
This article, 'How to Use Laravel With React.js', demonstrates the core pattern of sending data from a React component to a Laravel backend using Axios. Focus on how it sets up a POST request.
Read the section titled 'Communicating With the Back-End'. Notice how it defines a simple POST route in Laravel and then uses axios.post in the React component to send data to that endpoint. This is the same principle we will apply to our order submission.
Now, let's apply that principle to our processOrder function. We need to combine the formData from our checkout form with the items from our CartContext.
Update the processOrder function in Checkout.jsx:
// src/pages/Checkout.jsx ... inside the Checkout component
async function processOrder(formData) {
const orderPayload = {
shippingInfo: {
firstName: formData.firstName,
lastName: formData.lastName,
address1: formData.address1,
// Add other shipping fields from your form
},
paymentInfo: {
cardName: formData.cardName,
cardNumber: formData.cardNumber,
// Add other payment fields
},
cartItems: cart.items, // Assuming cart.items is an array of cart item objects
total: cart.total, // Assuming you have a total in your cart context
};
try {
// Remember to use your full backend URL
const response = await axios.post('http://127.0.0.1:8000/api/orders', orderPayload);
console.log('Server response:', response.data);
// If the order is successful:
clearCart(); // Clear the shopping cart from context
handleNext(); // Move to the "Thank you" step
} catch (error) {
console.error('Failed to submit order:', error);
// In the next lesson, we will set an error state here to show a message
alert('There was an error placing your order. Please try again.');
}
}
// ... rest of the component
A few important notes on this implementation:
- Payload Structure: We've created a
orderPayloadobject. This structured format makes the data easy for your Laravel backend to parse and validate. - API URL: I've used
http://127.0.0.1:8000/api/orders. You must replace this with the actual URL of your running Laravel development server. - Error Handling: The
try...catchblock is essential. It allows you to handle network failures or errors sent back from your API gracefully. For now, we're just using a simplealert(). - State Cleanup: On success, we call
clearCart()to empty the user's cart andhandleNext()to show the confirmation UI. This is a crucial step for a clean user experience.
Conclusion
Congratulations! You have successfully connected your React frontend to your Laravel backend, completing the core checkout functionality. The "Place Order" button now triggers a real API request that sends all the relevant form and cart data for processing.
Key Takeaways:
- API Endpoint is Key: A well-defined API endpoint in your backend (like
POST /api/orders) is the necessary entry point for frontend actions. - Conditional Form Submission: In multi-step forms, you need logic to differentiate the final "submit" action from intermediate "next step" actions.
- Axios for API Calls:
axios.postis a standard and effective way to send data to an API. Usingasync/awaitwithtry/catchmakes the asynchronous code clean and robust. - Data Payload: Structuring the data sent to the API (the payload) is important for clarity and makes validation on the backend easier.
Preview of the Next Lesson:
Currently, our error handling is a simple alert, and the success message is part of the stepper component. To improve the user experience, we need to provide more specific feedback. In our next and final lesson of this module, we will handle the API response to display a proper order confirmation or a helpful error message to the user, making the application feel more polished and professional.