Skip to content

Commit

Permalink
Fix issues with the buyer flow
Browse files Browse the repository at this point in the history
implement coupons table

fix build & lint error's

fix testing errors

rebase from develop
  • Loading branch information
wayneleon1 authored and niyobern committed Jul 26, 2024
1 parent 9cd870c commit bb158d3
Show file tree
Hide file tree
Showing 14 changed files with 3,014 additions and 1,268 deletions.
3,804 changes: 2,657 additions & 1,147 deletions package-lock.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/__test__/Checkout/checkout.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ describe('checkoutSlice', () => {
it('should handle initial state', () => {
expect(store.getState().checkout).toEqual({
checkout: {
id: 31,
totalAmount: 160,
id: -1,
totalAmount: 0,
status: 'Pending',
couponCode: '',
deliveryInfo: {
Expand Down Expand Up @@ -91,7 +91,7 @@ describe('checkoutSlice', () => {
city: 'Anytown',
zip: '12345',
},
id: 31,
id: -1,
orderDetails: [
{
id: 41,
Expand All @@ -102,7 +102,7 @@ describe('checkoutSlice', () => {
paid: true,
paymentInfo: null,
status: 'Pending',
totalAmount: 160,
totalAmount: 0,
trackingNumber: 'Tr280585',
updatedAt: '2024-07-22T11:01:20.291Z',
},
Expand Down
2 changes: 1 addition & 1 deletion src/__test__/home/productCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ describe('ProductCard Component', () => {
expect(halfStar.length).toBe(1);

const emptyStar = screen.getAllByTestId('emptyStar');
expect(emptyStar.length).toBe(Math.floor(4 - mockProduct.averageRating));
expect(emptyStar.length).toBe(Math.floor(5 - mockProduct.averageRating));

const addToCartIcon = screen.getByTestId('addToCart');
expect(addToCartIcon).toBeInTheDocument();
Expand Down
2 changes: 1 addition & 1 deletion src/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import checkoutSlice from '@/features/Checkout/checkoutSlice';

import ordersSliceReducer from '@/features/Orders/ordersSlice';
import contactReducer from '@/features/contact/contactSlice';
import couponsSliceReducer from '@/features/Coupons/CouponsFeature';
import userRoleSlice from '@/features/userRole/userRoleSlice';
import couponsSliceReducer from '@/features/Coupons/CouponsFeature';

export const store = configureStore({
reducer: {
Expand Down
17 changes: 12 additions & 5 deletions src/components/Cart/Cart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,18 @@ export default function Cart() {
/>
))}
<div className="flex justify-end gap-20 py-6 items-center sticky bottom-0 bg-white">
<div className="flex gap-2 items-center">
<h2 className="text-2xl font-bold text-gray-900">Total:</h2>
<span className="text-xl font-medium text-primary">${total}</span>
</div>
<HSButton title="CHECKOUT" path="/checkout" />
{cartItems.length > 0 && (
<div className="flex gap-2 items-center">
<h2 className="text-2xl font-bold text-gray-900">Total:</h2>
<span className="text-xl font-medium text-primary">${total}</span>
</div>
)}
{cartItems.length === 0 && (
<h2 className="text-2xl font-bold text-gray-900">Cart Empty</h2>
)}
{cartItems.length > 0 && (
<HSButton title="CHECKOUT" path="/checkout" />
)}
</div>
</div>
<div className="flex flex-col gap-12">
Expand Down
38 changes: 32 additions & 6 deletions src/components/Checkout/Checkout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import CardInput, { Card } from './CardInput';
import { RootState } from '@/app/store';
import { fetchCartItems } from '@/features/Cart/cartSlice';
import { fetchCartItems, selectCartItems } from '@/features/Cart/cartSlice';
import { Checkout as CheckoutType } from '@/interfaces/checkout';
import {
selectCheckout,
placeOrder,
makePayment,
updateStatus,
resetState,
} from '@/features/Checkout/checkoutSlice';
import { useAppDispatch, useAppSelector } from '@/app/hooks';
import {
Expand Down Expand Up @@ -46,6 +47,12 @@ function Checkout() {
const dispatch = useAppDispatch();
const navigate = useNavigate();
const user = useAppSelector((state) => state.signIn.user);
const cartItems = useAppSelector((state: RootState) =>
selectCartItems(state)
);
const total = cartItems.reduce((acc, curr) => {
return acc + curr.product.salesPrice * curr.quantity;
}, 0);
function handleAdding() {
setAdding(!adding);
}
Expand All @@ -56,14 +63,17 @@ function Checkout() {
const { loading, error, paying } = checkoutState;
function handleSave(newCard: Card) {
setCards((prev) => [...prev, newCard]);
}

function applyCoupon(e: React.ChangeEvent<HTMLInputElement>) {
setCoupon(e.target.value);
const checkout: CheckoutType = {
deliveryInfo: {
address,
city,
zip: '12345',
},
couponCode: coupon,
couponCode: e.target.value,
email: user?.email || '',
firstName: user?.firstName || '',
lastName: user?.lastName || '',
Expand All @@ -72,7 +82,22 @@ function Checkout() {
}

function handlePayment() {
dispatch(makePayment(order.id));
if (order.id === -1) {
const checkout: CheckoutType = {
deliveryInfo: {
address,
city,
zip: '12345',
},
couponCode: '',
email: user?.email || '',
firstName: user?.firstName || '',
lastName: user?.lastName || '',
};
dispatch(placeOrder(checkout)).then((res) =>
dispatch(makePayment(res.payload.id))
);
} else dispatch(makePayment(order.id));
}

useEffect(() => {
Expand All @@ -82,6 +107,7 @@ function Checkout() {
showSuccessToast('Succesfully Paid');
dispatch(updateStatus(false));
dispatch(fetchCartItems());
dispatch(resetState());
navigate('/');
} else if (paying && error) {
showErrorToast(error || 'failed');
Expand Down Expand Up @@ -313,7 +339,7 @@ function Checkout() {
<input
type="text"
className="border border-gray-300 p-2 rounded-lg flex-grow mr-2 outline-none"
onChange={(e) => setCoupon(e.target.value)}
onChange={applyCoupon}
value={coupon}
/>
<button
Expand Down Expand Up @@ -369,7 +395,7 @@ function Checkout() {
<div className="mb-2">
<div className="flex justify-between py-2 text-xl">
<span className="text-gray-600">Total</span>
<span>${order.totalAmount}</span>
<span>${order.totalAmount || total}</span>
</div>
</div>

Expand All @@ -383,7 +409,7 @@ function Checkout() {
<div className="font-bold">
<div className="flex justify-between py-2 text-xl">
<span className="text-gray-600">Total Cost</span>
<span>${order.totalAmount}</span>
<span>${order.totalAmount || total}</span>
</div>
</div>
</div>
Expand Down
140 changes: 115 additions & 25 deletions src/components/Orders/OrderDetailsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
import { useState } from 'react';
import Order from '@/interfaces/order';
import { updateOrderStatus } from '@/features/Orders/ordersSlice';
import { useAppDispatch } from '@/app/hooks';

interface ModalPropsb {
order: Order;
close: () => void;
cancel: (id: number) => void;
edit: () => void;
status: string;
}
interface ModalProps {
order: Order;
close: () => void;
cancel: (id: number) => void;
}

function OrderDetailsModal({ close, order }: ModalProps) {
function Modal({ close, order, cancel, edit, status }: ModalPropsb) {
const billigDetails = order.deliveryInfo;
return (
<div className="p-8 bg-white rounded-lg shadow-lg max-w-3xl mx-auto">
<div className="p-8 bg-white rounded-lg shadow-lg max-w-3xl mx-auto relative">
<div className="flex justify-between items-start mb-4">
<h2 className="text-xl font-bold">Order #234</h2>
<div className="flex items-center">
<span className="bg-green-100 text-green-700 px-2 py-1 rounded-md">
{order.status}
{status}
</span>
<button
onClick={() => close()}
Expand Down Expand Up @@ -62,32 +73,18 @@ function OrderDetailsModal({ close, order }: ModalProps) {
<thead>
<tr className="bg-gray-100">
<th className="px-4 py-2 text-left">No</th>
<th className="px-4 py-2 text-left">PRODUCT</th>
<th className="px-4 py-2 text-left">Quantity</th>
<th className="px-4 py-2 text-left">PRICE</th>
</tr>
</thead>
<tbody>
<tr>
<td className="border px-4 py-2">1</td>
<td className="border px-4 py-2">Hisense 43 inch 4K Smart TV</td>
<td className="border px-4 py-2">2</td>
<td className="border px-4 py-2">450,000</td>
</tr>
<tr>
<td className="border px-4 py-2">2</td>
<td className="border px-4 py-2">
LG TOP Load Washers Silver 8 KGS Vietnam
</td>
<td className="border px-4 py-2">12</td>
<td className="border px-4 py-2">210,000</td>
</tr>
<tr>
<td className="border px-4 py-2">3</td>
<td className="border px-4 py-2">Crystal Sunflower Oil /5l</td>
<td className="border px-4 py-2">23</td>
<td className="border px-4 py-2">42,000</td>
</tr>
{order.orderDetails.map((item) => (
<tr key={item.id}>
<td className="border px-4 py-2">{item.id}</td>
<td className="border px-4 py-2">{item.quantity}</td>
<td className="border px-4 py-2">{item.price}</td>
</tr>
))}
</tbody>
</table>
</div>
Expand All @@ -96,12 +93,14 @@ function OrderDetailsModal({ close, order }: ModalProps) {
<button
type="button"
className="px-4 py-1 bg-primary text-sm text-white rounded-md"
onClick={edit}
>
Edit
</button>
<button
type="button"
className="px-4 py-1 bg-red-500 text-sm text-white rounded-md"
onClick={() => cancel(order.id)}
>
Delete
</button>
Expand All @@ -110,4 +109,95 @@ function OrderDetailsModal({ close, order }: ModalProps) {
);
}

export default OrderDetailsModal;
function Edit({
edit,
order,
status,
}: {
edit: () => void;
order: Order;
status: (nstat: string) => void;
}) {
const validStatuses = [
'Pending',
'Failed',
'Canceled',
'Paid',
'Shipping',
'Delivered',
'Returned',
'Completed',
];
const dispatch = useAppDispatch();
return (
<div className="fixed inset-0 flex items-center justify-center bg-gray-500 bg-opacity-50">
<div className="bg-white p-6 rounded shadow-md w-1/3">
<h2 className="text-lg font-bold mb-4 text-primary">
Edit Order Status
</h2>
<label htmlFor="status" className="block mb-2 text-gray-700">
Status:
</label>
<select
id="status"
className="block w-full p-2 border border-gray-300 rounded mb-4 text-gray-700 outline-none"
>
{validStatuses.map((stat) => (
<option key={stat} value={stat}>
{stat}
</option>
))}
</select>
<div className="flex justify-end space-x-4">
<button
type="submit"
className="px-4 py-1 bg-primary text-sm text-white rounded-md"
onClick={() => {
edit();
status(document.querySelector('select')?.value || 'pending');
dispatch(
updateOrderStatus({
id: order.id,
status: document.querySelector('select')?.value || 'pending',
})
);
}}
>
Save
</button>
<button
type="button"
onClick={edit}
className="px-4 py-1 bg-red-500 text-sm text-white rounded-md"
>
Cancel
</button>
</div>
</div>
</div>
);
}

export default function OrderDetailsModal({
close,
order,
cancel,
}: ModalProps) {
const [edit, setEdit] = useState(false);
const [status, setStatus] = useState(order.status);
return edit ? (
<Edit
edit={() => setEdit(false)}
order={order}
status={(nstat) => setStatus(nstat)}
/>
) : (
<Modal
close={close}
order={order}
cancel={cancel}
edit={() => setEdit(true)}
status={status}
/>
);
}
1 change: 1 addition & 0 deletions src/components/Orders/Orders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ export function Orders() {
<OrderDetailsModal
close={() => setSelected(-1)}
order={orders.find((order) => order.id === selected) as Order}
cancel={(id: number) => dispatch(cancelOrder(id))}
/>
</div>
)}
Expand Down
Loading

0 comments on commit bb158d3

Please sign in to comment.