Skip to content

Commit

Permalink
feat(orders): change order status
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikadows committed Jun 1, 2022
1 parent 8e83d97 commit 3df488b
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 69 deletions.
11 changes: 10 additions & 1 deletion public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,16 @@
"checkbox-label": "Show delivered orders",
"createdAt": "Ordered at",
"pickupDate": "Recovery date",
"totalPrice": "Total price"
"totalPrice": "Total price",
"status-modal": {
"client-ref": "Order reference",
"client-contact": "Contact",
"status-selector" : "Status",
"submit" : "Update",
"cancel" : "Cancel",
"alert_success": "Status updated",
"alert_failed": "Status update failed"
}
},
"products": {
"add_btn": "Add Product",
Expand Down
13 changes: 11 additions & 2 deletions public/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,20 @@
"logout": "Se déconnecter"
},
"orders": {
"title" : "Commandes en cours",
"title": "Commandes en cours",
"checkbox-label": "Afficher les commandes réceptionnés",
"createdAt": "Commandé le",
"pickupDate": "Commande prévue pour le",
"totalPrice": "Prix total"
"totalPrice": "Prix total",
"status-modal": {
"client-ref": "Référence commande",
"client-contact": "Contact",
"status-selector": "Status",
"submit": "Mettre à jour",
"cancel": "Annuler",
"alert_success": "Status mis à jour",
"alert_failed": "Status non mis à jour"
}
},
"products": {
"add_btn": "Ajouter un produit",
Expand Down
141 changes: 96 additions & 45 deletions src/components/Orders/OrderCard.tsx
Original file line number Diff line number Diff line change
@@ -1,72 +1,123 @@
import React from 'react';
import React, { Fragment, useState } from 'react';
import { useTranslation } from 'react-i18next';
import OrderedProductModel from './models/OrderedProductModel';
import OrderModel from './models/OrderModel';
import OrderStatus from './OrderStatus';
import { Dialog, Transition } from '@headlessui/react';
import OrderChangeStatusModal from './OrderChangeStatusModal';

interface OrderCardProps {
order: OrderModel;
}

const OrderCard: React.FC<OrderCardProps> = ({ order }) => {
const { t } = useTranslation();
const [updateStatusModal, setUpdateStatusModal] = useState(false);

function formatDate(date: string) {
const [year, month, day] = date.split('-');
[day, month, year].join('/');
return (
<span className="font-semibold ml-1">{[day, month, year].join('/')}</span>
);
}

return (
<>
<div className="mx-auto p-6 bg-white border my-2 rounded w-full shadow">
<div className="flex justify-between ">
<h3>
{order.firstName} {order.lastName}
</h3>
<h3>
{order.createdAt ? (
<>
{t('orders.createdAt')} : {formatDate(order.createdAt)}{' '}
</>
) : (
<></>
)}
</h3>
<div className="flex justify-end">
{order.pickupDate ? (
<>
{t('orders.pickupDate')} : {formatDate(order.pickupDate)}{' '}
</>
) : (
<></>
)}
<button onClick={() => setUpdateStatusModal(true)}>
<div className="mx-auto p-6 bg-white border my-2 rounded w-full shadow">
<div className="flex justify-between ">
<h3>
{order.firstName} {order.lastName}
</h3>
<h3>
{order.createdAt ? (
<>
{t('orders.createdAt')} : {formatDate(order.createdAt)}{' '}
</>
) : (
<></>
)}
</h3>
<div className="flex justify-end">
{order.pickupDate ? (
<>
{t('orders.pickupDate')} : {formatDate(order.pickupDate)}{' '}
</>
) : (
<></>
)}
</div>
</div>
</div>
<div className="flex justify-between ">
<h3>
{order.email} {order.phone}
</h3>
<div className="flex items-center justify-end">
<OrderStatus status={order?.status ? order.status : ''} />
<div className="flex justify-between ">
<h3>
{order.email} {order.phone}
</h3>
<div className="flex items-center justify-end">
<OrderStatus status={order?.status ? order.status : ''} />
</div>
</div>
</div>

<div>
<p>
{order?.products!.map((product: OrderedProductModel) => (
<>
<span>{product.name + ' × ' + product.quantity}</span>
<br />
</>
))}
</p>
</div>
<div className="flex justify-end">
<span className="text-gold-100 mr-1">{t('orders.totalPrice')}</span>
{order.totalPrice + '€'}
<div>
<p>
{order?.products!.map((product: OrderedProductModel) => (
<>
<span>{product.name + ' × ' + product.quantity}</span>
<br />
</>
))}
</p>
</div>
<div className="flex justify-end">
<span className="text-gold-100 mr-1">{t('orders.totalPrice')}</span>
{order.totalPrice + '€'}
</div>
</div>
</div>
</button>

<Transition.Root show={updateStatusModal} as={Fragment}>
<Dialog
as="div"
className="fixed z-10 inset-0 overflow-y-auto"
onClose={setUpdateStatusModal}
>
<div className="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
</Transition.Child>
<span
className="hidden sm:inline-block sm:align-middle sm:h-screen"
aria-hidden="true"
>
&#8203;
</span>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<div className="inline-block align-bottom bg-white rounded-lg text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full">
<OrderChangeStatusModal
order={order}
setOpenedModal={setUpdateStatusModal}
/>
</div>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
</>
);
};
Expand Down
93 changes: 93 additions & 0 deletions src/components/Orders/OrderChangeStatusModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';
import { useToasts } from 'react-toast-notifications';
import UpdateOrderStatusRequest from '../../hooks/orders/requests/UpdateOrderStatusRequest';
import OrderModel from './models/OrderModel';
import { updateOrderStatus } from '../../hooks/orders/ordersHooks';

interface OrderChangeStatusModalProps {
order: OrderModel;
setOpenedModal: (openedModal: boolean) => void;
}

const OrderChangeStatusModal: React.FC<OrderChangeStatusModalProps> = ({
order,
setOpenedModal,
}) => {
const { t } = useTranslation();
const queryClient = useQueryClient();
const { addToast } = useToasts();

async function handleOrderStatusUpdate(event: any) {
event.preventDefault();
const request = new UpdateOrderStatusRequest(event.target.status.value);

const response = await updateOrderStatus(
order?.id ? order.id : '',
request,
);
if (response) {
addToast(`${t('orders.status-modal.alert_success')}: ${order?.id}`, {
appearance: 'success',
autoDismiss: true,
});
await queryClient.invalidateQueries('all-orders');
setOpenedModal(false);
} else {
addToast(`${t('orders.status-modal.alert_failed')}: ${order?.id}`, {
appearance: 'error',
autoDismiss: true,
});
}
}

return (
<div className="overflow-x-auto">
<div className="grid bg-white rounded-lg shadow-xl w-fit">
<form onSubmit={handleOrderStatusUpdate}>
<h3 className="pl-4 pt-4">
{t('orders.status-modal.client-ref')} : {order.id}
</h3>
<h3 className="pl-4 pt-4">
{t('orders.status-modal.client-contact')} : {order.email} |{' '}
{order.phone}
</h3>

<div className="flex item-center justify-center pt-10">
<label className="uppercase md:text-sm text-xs text-gray-500 text-light font-semibold pt-4 pr-3">
{t('orders.status-modal.status-selector')}
</label>
<select
id="status"
className="py-2 px-3 rounded-lg border-2 border-purple-300 mt-1 focus:outline-none focus:ring-2 focus:ring-purple-600 focus:border-transparent"
>
<option>PAID</option>
<option>CANCELED</option>
<option>READY</option>
<option>DELIVERED</option>
</select>
</div>
<div className="flex items-center justify-center md:gap-8 gap-4 pt-5 pb-5">
<button
type="button"
onClick={() => {
setOpenedModal(false);
}}
className="w-auto bg-gray-500 hover:bg-gray-700 rounded-lg shadow-xl font-medium text-white px-4 py-2"
>
{t('orders.status-modal.cancel')}
</button>
<input
type="submit"
value={t('orders.status-modal.submit')}
className="w-auto bg-purple-500 hover:bg-purple-700 rounded-lg shadow-xl font-medium text-white px-4 py-2"
/>
</div>
</form>
</div>
</div>
);
};

export default OrderChangeStatusModal;
21 changes: 0 additions & 21 deletions src/components/Products/ProductList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -261,27 +261,6 @@ const ProductTableRow: React.FC<ProductRowProps> = ({ _id, product }) => {
</td>
<td className="py-3 px-6 text-center">
<div className="flex item-center justify-center">
<div className="w-4 mr-2 transform hover:text-purple-500 hover:scale-110">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
/>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"
/>
</svg>
</div>
<div
onClick={() => setModifyModalState(true)}
className="w-4 mr-2 transform hover:text-purple-500 hover:scale-110"
Expand Down
13 changes: 13 additions & 0 deletions src/hooks/orders/ordersHooks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useQuery } from 'react-query';
import { authenticatedRequest } from '../common/request';
import OrderModel from '../../components/Orders/models/OrderModel';
import UpdateOrderStatusRequest from './requests/UpdateOrderStatusRequest';

export function useOrders() {
return useQuery<OrderModel[], Error>(`all-orders`, async () => {
Expand All @@ -10,3 +11,15 @@ export function useOrders() {
return data;
});
}

export async function updateOrderStatus(
id: string,
request: UpdateOrderStatusRequest,
) {
const { data } = await authenticatedRequest({
url: `admin/order/${id}`,
method: 'PUT',
data: request,
});
return data;
}
7 changes: 7 additions & 0 deletions src/hooks/orders/requests/UpdateOrderStatusRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default class UpdateOrderStatusRequest {
status: string;

constructor(status: string) {
this.status = status;
}
}

0 comments on commit 3df488b

Please sign in to comment.