Capstone 3 Added
parent
12b87b8d2f
commit
82a05cde7f
@ -0,0 +1,13 @@
|
|||||||
|
// models/ShippingMethod.js
|
||||||
|
|
||||||
|
const mongoose = require('mongoose');
|
||||||
|
|
||||||
|
const shippingMethodSchema = new mongoose.Schema({
|
||||||
|
name: { type: String, required: true },
|
||||||
|
description: { type: String, required: true },
|
||||||
|
// Add other fields as needed
|
||||||
|
});
|
||||||
|
|
||||||
|
const ShippingMethod = mongoose.model('ShippingMethod', shippingMethodSchema);
|
||||||
|
|
||||||
|
module.exports = ShippingMethod;
|
@ -0,0 +1,134 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Button, Collapse, Col, Row, Table, Form } from "react-bootstrap";
|
||||||
|
import AddressForm from "./AddressForm"; // Assuming the path is correct
|
||||||
|
|
||||||
|
const AddressCollapse = ({
|
||||||
|
addressOpen,
|
||||||
|
setAddressOpen,
|
||||||
|
isCustomerLoggedIn,
|
||||||
|
selectedAddress,
|
||||||
|
setSelectedAddress,
|
||||||
|
handleContinueAddress,
|
||||||
|
addAddressFormOpen,
|
||||||
|
setAddAddressFormOpen,
|
||||||
|
addressFormError,
|
||||||
|
addresses,
|
||||||
|
handleDeleteAddress,
|
||||||
|
}) => {
|
||||||
|
const handleAddressSelect = (addressId) => {
|
||||||
|
// Update the selectedAddressId
|
||||||
|
setSelectedAddress(addressId);
|
||||||
|
|
||||||
|
// If you also want to update the selectedAddress object, find the corresponding address
|
||||||
|
const selected = addresses.find((address) => address._id === addressId);
|
||||||
|
setSelectedAddress(selected);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="border rounded mb-3 p-3">
|
||||||
|
<h3>
|
||||||
|
<div className="d-flex justify-content-between align-items-start">
|
||||||
|
<span className="fs-6">2. Address</span>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
onClick={() => setAddressOpen(!addressOpen)}
|
||||||
|
aria-controls="addressCollapse"
|
||||||
|
aria-expanded={addressOpen}
|
||||||
|
>
|
||||||
|
<i className={`bi bi-chevron-${addressOpen ? "up" : "down"}`}></i>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</h3>
|
||||||
|
<Collapse in={addressOpen}>
|
||||||
|
<div id="addressCollapse">
|
||||||
|
{isCustomerLoggedIn ? (
|
||||||
|
<Row>
|
||||||
|
<span className="mb-2" style={{ fontSize: "16px" }}>
|
||||||
|
The selected address will be used both as your personal address
|
||||||
|
(for invoice) and as your delivery address.
|
||||||
|
</span>
|
||||||
|
<Col className="border rounded mb-3 p-3" md={6}>
|
||||||
|
{/* Left column - Add New Address Form Dropdown */}
|
||||||
|
<div>
|
||||||
|
{addAddressFormOpen && (
|
||||||
|
<AddressForm
|
||||||
|
selectedAddress={selectedAddress}
|
||||||
|
setSelectedAddress={setSelectedAddress}
|
||||||
|
handleContinueAddress={handleContinueAddress}
|
||||||
|
addressFormError={addressFormError}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Button
|
||||||
|
className="my-3"
|
||||||
|
variant="primary"
|
||||||
|
onClick={() => setAddAddressFormOpen(!addAddressFormOpen)}
|
||||||
|
>
|
||||||
|
Add New Address
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col md={6}>
|
||||||
|
{/* Right column - My Addresses from addressForm */}
|
||||||
|
{addresses && addresses.length > 0 ? (
|
||||||
|
<Table striped bordered hover>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>My Addresses</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{addresses.map((address, index) => (
|
||||||
|
<tr key={index}>
|
||||||
|
<td>
|
||||||
|
<div className="d-flex justify-content-between align-items-center">
|
||||||
|
<Form.Check
|
||||||
|
type="radio"
|
||||||
|
id={`addressRadio${index}`}
|
||||||
|
name="addressRadio"
|
||||||
|
checked={
|
||||||
|
selectedAddress &&
|
||||||
|
selectedAddress._id === address._id
|
||||||
|
}
|
||||||
|
onChange={() =>
|
||||||
|
handleAddressSelect(address._id)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p className="mx-3">
|
||||||
|
{address.street}, {address.city},{" "}
|
||||||
|
{address.state}, {address.zipCode},{" "}
|
||||||
|
{address.country}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
className="text-danger"
|
||||||
|
onClick={() => handleDeleteAddress(address._id)}
|
||||||
|
>
|
||||||
|
<i className="bi bi-trash"></i>
|
||||||
|
</Button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</Table>
|
||||||
|
) : (
|
||||||
|
<p>No existing addresses. Add a new address below.</p>
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
) : (
|
||||||
|
<p>User not logged in. Log in to view and manage addresses.</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Collapse>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddressCollapse;
|
@ -0,0 +1,38 @@
|
|||||||
|
const BankOption = ({ totalPrice }) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h4>Bank Payment Details</h4>
|
||||||
|
<div style={{ border: '1px solid #ddd', padding: '10px', borderRadius: '5px', marginBottom: '10px' }}>
|
||||||
|
<p>
|
||||||
|
Please transfer the amount to the following bank account:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<strong>Bank:</strong> BPI Bank
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Account Holder:</strong> istore philippines
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Account Number:</strong> 1234-1234-1234-1234
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Amount:</strong> {new Intl.NumberFormat('en-PH', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'PHP',
|
||||||
|
}).format(totalPrice)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-3">
|
||||||
|
<p>
|
||||||
|
After completing the bank transfer, please submit the reference number{' '}
|
||||||
|
<a href="mailto:customercare@istore.com.ph">customercare@istore.com.ph</a>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BankOption;
|
||||||
|
|
@ -0,0 +1,73 @@
|
|||||||
|
// OrderDetails.js
|
||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
const OrderDetails = ({ orderData }) => {
|
||||||
|
if (!orderData) {
|
||||||
|
// Handle the case where orderData is not available
|
||||||
|
return <div>Loading...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
userDetails,
|
||||||
|
selectedAddress,
|
||||||
|
selectedShippingMethod,
|
||||||
|
cartItems,
|
||||||
|
appliedPromoCode,
|
||||||
|
selectedPaymentOption,
|
||||||
|
termsAgreed,
|
||||||
|
// Include any other necessary data
|
||||||
|
} = orderData;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h2>Order Details</h2>
|
||||||
|
|
||||||
|
<h3>User Details</h3>
|
||||||
|
<pre>{JSON.stringify(userDetails, null, 2)}</pre>
|
||||||
|
|
||||||
|
<h3>Selected Address</h3>
|
||||||
|
<pre>{JSON.stringify(selectedAddress, null, 2)}</pre>
|
||||||
|
|
||||||
|
<h3>Selected Shipping Method</h3>
|
||||||
|
<pre>{selectedShippingMethod}</pre>
|
||||||
|
|
||||||
|
<h3>Cart Items</h3>
|
||||||
|
<ul>
|
||||||
|
{cartItems.map((item, index) => (
|
||||||
|
<li key={index}>
|
||||||
|
<h4>Item {index + 1}</h4>
|
||||||
|
<pre>{JSON.stringify(item, null, 2)}</pre>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Applied Promo Code</h3>
|
||||||
|
<pre>{appliedPromoCode}</pre>
|
||||||
|
|
||||||
|
<h3>Selected Payment Option</h3>
|
||||||
|
<pre>{selectedPaymentOption}</pre>
|
||||||
|
|
||||||
|
<h3>Terms Agreed</h3>
|
||||||
|
<pre>{termsAgreed ? "Agreed" : "Not Agreed"}</pre>
|
||||||
|
|
||||||
|
{/* Include additional sections as needed for other data */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specify PropTypes for the orderData prop
|
||||||
|
OrderDetails.propTypes = {
|
||||||
|
orderData: PropTypes.shape({
|
||||||
|
userDetails: PropTypes.object,
|
||||||
|
selectedAddress: PropTypes.object,
|
||||||
|
selectedShippingMethod: PropTypes.string,
|
||||||
|
cartItems: PropTypes.array,
|
||||||
|
appliedPromoCode: PropTypes.string,
|
||||||
|
selectedPaymentOption: PropTypes.string,
|
||||||
|
termsAgreed: PropTypes.bool,
|
||||||
|
// Include PropTypes for other data properties
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OrderDetails;
|
@ -0,0 +1,86 @@
|
|||||||
|
// components/OrderSummary.js
|
||||||
|
import React from 'react';
|
||||||
|
import { Col, Table, Form, Button } from 'react-bootstrap';
|
||||||
|
|
||||||
|
const OrderSummary = ({
|
||||||
|
cartItems,
|
||||||
|
shippingFee,
|
||||||
|
totalPrice,
|
||||||
|
discountAmount,
|
||||||
|
promoCode,
|
||||||
|
setPromoCode,
|
||||||
|
handleApplyPromoCode,
|
||||||
|
appliedPromoCode,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Col xs={12} md={4} className="text-start">
|
||||||
|
<h3>Order Summary</h3>
|
||||||
|
<Table striped bordered hover>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Total Items</td>
|
||||||
|
<td>
|
||||||
|
{cartItems.reduce((total, item) => total + item.quantity, 0)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Shipping Fee</td>
|
||||||
|
<td>{new Intl.NumberFormat('en-PH', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'PHP',
|
||||||
|
}).format(shippingFee.value)}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Shipping Details</td>
|
||||||
|
<td>{shippingFee.details}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>Total</td>
|
||||||
|
<td>
|
||||||
|
<strong>{new Intl.NumberFormat('en-PH', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'PHP',
|
||||||
|
}).format(totalPrice)}</strong>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Discount</td>
|
||||||
|
<td>
|
||||||
|
<strong>{discountAmount}%</strong>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colSpan="2">
|
||||||
|
<Form.Group controlId="promoCode">
|
||||||
|
<Form.Label>Promo Code</Form.Label>
|
||||||
|
<Form.Control
|
||||||
|
type="text"
|
||||||
|
placeholder="Enter promo code"
|
||||||
|
value={promoCode}
|
||||||
|
onChange={(e) => setPromoCode(e.target.value)}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
className="mt-3"
|
||||||
|
variant="primary"
|
||||||
|
onClick={handleApplyPromoCode}
|
||||||
|
>
|
||||||
|
Apply Promo Code
|
||||||
|
</Button>
|
||||||
|
</Form.Group>
|
||||||
|
{appliedPromoCode && (
|
||||||
|
<div>
|
||||||
|
<p className="mt-2">
|
||||||
|
Applied Promo Code: <strong>{appliedPromoCode}</strong>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</Table>
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OrderSummary;
|
@ -0,0 +1,144 @@
|
|||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
import { Button, Collapse, Form } from "react-bootstrap";
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import PropTypes from "prop-types"; // Import PropTypes
|
||||||
|
import BankOption from "./BankOption";
|
||||||
|
|
||||||
|
const PaymentCollapse = ({
|
||||||
|
totalPrice,
|
||||||
|
userDetails,
|
||||||
|
selectedAddress,
|
||||||
|
selectedShippingMethod,
|
||||||
|
cartItems,
|
||||||
|
appliedPromoCode,
|
||||||
|
}) => {
|
||||||
|
const [paymentOpen, setPaymentOpen] = useState(false);
|
||||||
|
const [selectedPaymentOption, setSelectedPaymentOption] = useState(null);
|
||||||
|
const [termsAgreed, setTermsAgreed] = useState(false);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const handlePaymentOptionChange = (option) => {
|
||||||
|
setSelectedPaymentOption(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTermsAgreementChange = () => {
|
||||||
|
setTermsAgreed(!termsAgreed);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isSubmitButtonDisabled = !termsAgreed || selectedPaymentOption === null;
|
||||||
|
|
||||||
|
const handleOrderSubmission = () => {
|
||||||
|
try {
|
||||||
|
const orderData = {
|
||||||
|
userDetails,
|
||||||
|
selectedAddress,
|
||||||
|
selectedShippingMethod,
|
||||||
|
cartItems,
|
||||||
|
appliedPromoCode,
|
||||||
|
selectedPaymentOption,
|
||||||
|
termsAgreed,
|
||||||
|
// Include any other necessary data
|
||||||
|
};
|
||||||
|
|
||||||
|
// Log the order data to the console for testing
|
||||||
|
console.log("Order Data:", orderData);
|
||||||
|
|
||||||
|
// Display a success message to the user (for testing)
|
||||||
|
console.log("Order submission simulated successfully!");
|
||||||
|
|
||||||
|
// Navigate to the order confirmation page with orderData
|
||||||
|
navigate("/order-confirmation", { state: { orderData } });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error submitting order:", error);
|
||||||
|
|
||||||
|
// Handle general error (for testing)
|
||||||
|
console.log("Order submission simulated failed.");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="border rounded mb-3 p-3">
|
||||||
|
<h3>
|
||||||
|
<div className="d-flex justify-content-between align-items-start">
|
||||||
|
<span className="fs-6">4. Payment</span>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
onClick={() => setPaymentOpen(!paymentOpen)}
|
||||||
|
aria-controls="paymentCollapse"
|
||||||
|
aria-expanded={paymentOpen}
|
||||||
|
>
|
||||||
|
<i className={`bi bi-chevron-${paymentOpen ? "up" : "down"}`}></i>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</h3>
|
||||||
|
<Collapse in={paymentOpen}>
|
||||||
|
<div id="paymentCollapse">
|
||||||
|
<Form.Group className="mb-3">
|
||||||
|
<Form.Label>Select Payment Option:</Form.Label>
|
||||||
|
<Form.Control
|
||||||
|
as="select"
|
||||||
|
value={selectedPaymentOption}
|
||||||
|
onChange={(e) => handlePaymentOptionChange(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="">Select</option>
|
||||||
|
<option value="bank">Bank Option</option>
|
||||||
|
{/* Add other payment options here */}
|
||||||
|
</Form.Control>
|
||||||
|
</Form.Group>
|
||||||
|
|
||||||
|
{selectedPaymentOption === "bank" && (
|
||||||
|
<BankOption totalPrice={totalPrice} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Terms Agreement */}
|
||||||
|
<Form.Group
|
||||||
|
className="mb-3"
|
||||||
|
style={{
|
||||||
|
backgroundColor: "#343a40",
|
||||||
|
padding: "10px",
|
||||||
|
borderRadius: "5px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Form.Check
|
||||||
|
type="checkbox"
|
||||||
|
label="I agree to the terms of service and will adhere to them unconditionally."
|
||||||
|
checked={termsAgreed}
|
||||||
|
onChange={handleTermsAgreementChange}
|
||||||
|
style={{ color: "white" }}
|
||||||
|
/>
|
||||||
|
</Form.Group>
|
||||||
|
|
||||||
|
{/* Payment Button */}
|
||||||
|
<Button
|
||||||
|
variant="primary"
|
||||||
|
onClick={handleOrderSubmission}
|
||||||
|
disabled={isSubmitButtonDisabled}
|
||||||
|
>
|
||||||
|
Submit Order
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{/* Message below the Payment Button */}
|
||||||
|
{!termsAgreed && (
|
||||||
|
<div className="mt-2 text-danger">
|
||||||
|
Please agree to the terms of service before submitting the order.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Collapse>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specify PropTypes for each prop used in the component
|
||||||
|
PaymentCollapse.propTypes = {
|
||||||
|
totalPrice: PropTypes.number.isRequired,
|
||||||
|
userDetails: PropTypes.object,
|
||||||
|
selectedAddress: PropTypes.object,
|
||||||
|
selectedShippingMethod: PropTypes.string,
|
||||||
|
cartItems: PropTypes.array,
|
||||||
|
appliedPromoCode: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PaymentCollapse;
|
@ -0,0 +1,60 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Button, Collapse } from "react-bootstrap";
|
||||||
|
|
||||||
|
const PersonalInfoCollapse = ({ personalInfoOpen, setPersonalInfoOpen, isCustomerLoggedIn, userDetails }) => {
|
||||||
|
return (
|
||||||
|
<div className="border rounded mb-3 p-3">
|
||||||
|
<h3>
|
||||||
|
<div className="d-flex justify-content-between align-items-start">
|
||||||
|
<span className="fs-6">1. Personal Information</span>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
onClick={() => setPersonalInfoOpen(!personalInfoOpen)}
|
||||||
|
aria-controls="personalInfoCollapse"
|
||||||
|
aria-expanded={personalInfoOpen}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className={`bi bi-chevron-${personalInfoOpen ? "up" : "down"}`}
|
||||||
|
></i>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</h3>
|
||||||
|
<Collapse in={personalInfoOpen}>
|
||||||
|
<div id="personalInfoCollapse">
|
||||||
|
{isCustomerLoggedIn ? (
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<strong>Name:</strong> {userDetails?.firstName}{" "}
|
||||||
|
{userDetails?.lastName}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Email:</strong> {userDetails?.email}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Mobile Number:</strong> {userDetails?.mobileNo}
|
||||||
|
</p>
|
||||||
|
<p>If you want to update your information</p>
|
||||||
|
<Button variant="primary" href="/update-profile">
|
||||||
|
Update Information
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="mx-4">
|
||||||
|
<p>
|
||||||
|
You are not logged in. Please log in or register to proceed.
|
||||||
|
</p>
|
||||||
|
<Button variant="primary" href="/register">
|
||||||
|
Register
|
||||||
|
</Button>
|
||||||
|
<Button className="mx-2" variant="primary" href="/login">
|
||||||
|
Login
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Collapse>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PersonalInfoCollapse;
|
@ -0,0 +1,132 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
import { Button, Collapse } from "react-bootstrap";
|
||||||
|
|
||||||
|
const ShippingMethodCollapse = ({ shippingMethodOpen, setShippingMethodOpen, setSelectedShippingMethod }) => {
|
||||||
|
const [selectedOption, setSelectedOption] = useState(null);
|
||||||
|
|
||||||
|
const handleOptionChange = (option) => {
|
||||||
|
setSelectedOption(option);
|
||||||
|
setSelectedShippingMethod(option); // Update the parent component state
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="border rounded mb-3 p-3">
|
||||||
|
<h3>
|
||||||
|
<div className="d-flex justify-content-between align-items-start">
|
||||||
|
<span className="fs-6">3. Shipping Method</span>
|
||||||
|
<Button
|
||||||
|
variant="link"
|
||||||
|
onClick={() => setShippingMethodOpen(!shippingMethodOpen)}
|
||||||
|
aria-controls="shippingMethodCollapse"
|
||||||
|
aria-expanded={shippingMethodOpen}
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
className={`bi bi-chevron-${shippingMethodOpen ? "up" : "down"}`}
|
||||||
|
></i>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</h3>
|
||||||
|
<Collapse in={shippingMethodOpen}>
|
||||||
|
<div id="shippingMethodCollapse">
|
||||||
|
{/* Infographic-style table for Shipping Methods */}
|
||||||
|
<div className="row">
|
||||||
|
{/* Option 1 */}
|
||||||
|
<div className="col-md-4 mb-3">
|
||||||
|
<div
|
||||||
|
className="border p-3 text-center"
|
||||||
|
style={{ height: "auto" }}
|
||||||
|
>
|
||||||
|
<div className="d-grid gap-2 justify-content-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="form-check-input d-flex justify-content-center mx-auto fs-5"
|
||||||
|
id="option1Checkbox"
|
||||||
|
checked={selectedOption === "courier"}
|
||||||
|
onChange={() => handleOptionChange("courier")}
|
||||||
|
/>
|
||||||
|
<i
|
||||||
|
className="bi bi-truck text-primary"
|
||||||
|
style={{ fontSize: "3.7rem" }}
|
||||||
|
></i>
|
||||||
|
<label
|
||||||
|
className="form-check-label"
|
||||||
|
htmlFor="option1Checkbox"
|
||||||
|
>
|
||||||
|
<strong> Pickup by Courier (Lalamove/Grab)</strong>
|
||||||
|
<br />
|
||||||
|
Note: Customer pays for shipping. Wait for us to notify you
|
||||||
|
that your order is ready before you book your courier.
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Option 2 */}
|
||||||
|
<div className="col-md-4 mb-3">
|
||||||
|
<div
|
||||||
|
className="border p-3 text-center"
|
||||||
|
style={{ height: "auto" }}
|
||||||
|
>
|
||||||
|
<div className="d-grid gap-2 justify-content-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="form-check-input d-flex justify-content-center mx-auto fs-5"
|
||||||
|
id="option2Checkbox"
|
||||||
|
checked={selectedOption === "curbside"}
|
||||||
|
onChange={() => handleOptionChange("curbside")}
|
||||||
|
/>
|
||||||
|
<i
|
||||||
|
className="bi bi-shop text-primary"
|
||||||
|
style={{ fontSize: "3.7rem" }}
|
||||||
|
></i>
|
||||||
|
<label
|
||||||
|
className="form-check-label"
|
||||||
|
htmlFor="option2Checkbox"
|
||||||
|
>
|
||||||
|
<strong>Curbside Pickup</strong>
|
||||||
|
<br />
|
||||||
|
Note: Wait for us to notify you that your order is ready
|
||||||
|
before proceeding to our designated pickup area in front of
|
||||||
|
our building.
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Option 3 */}
|
||||||
|
<div className="col-md-4 mb-3">
|
||||||
|
<div
|
||||||
|
className="border p-3 text-center"
|
||||||
|
style={{ height: "auto" }}
|
||||||
|
>
|
||||||
|
<div className="d-grid gap-2 justify-content-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="form-check-input d-flex justify-content-center mx-auto fs-5"
|
||||||
|
id="option3Checkbox"
|
||||||
|
checked={selectedOption === "express"}
|
||||||
|
onChange={() => handleOptionChange("express")}
|
||||||
|
/>
|
||||||
|
<i
|
||||||
|
className="bi bi-clock text-primary"
|
||||||
|
style={{ fontSize: "3.7rem" }}
|
||||||
|
></i>
|
||||||
|
<label
|
||||||
|
className="form-check-label"
|
||||||
|
htmlFor="option3Checkbox"
|
||||||
|
>
|
||||||
|
<strong>Local Express Delivery</strong>
|
||||||
|
<br />
|
||||||
|
within 24 - 48 hours during business days
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Collapse>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ShippingMethodCollapse;
|
@ -0,0 +1,33 @@
|
|||||||
|
// OrderConfirmationPage.js
|
||||||
|
import React from "react";
|
||||||
|
import OrderDetails from "../components/OrderDetails";
|
||||||
|
import { Container } from "react-bootstrap";
|
||||||
|
|
||||||
|
const OrderConfirmationPage = ({ location }) => {
|
||||||
|
// Check if location is undefined
|
||||||
|
if (!location || !location.state) {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Container>
|
||||||
|
<h2>Order Confirmation</h2>
|
||||||
|
<p>Error: No order data found.</p>
|
||||||
|
</Container>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve orderData from location.state
|
||||||
|
const orderData = location.state.orderData;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Container>
|
||||||
|
<h2>Order Confirmation</h2>
|
||||||
|
{/* Use the OrderDetails component to display order details */}
|
||||||
|
<OrderDetails orderData={orderData} />
|
||||||
|
</Container>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default OrderConfirmationPage;
|
Loading…
Reference in New Issue