From f93f5d1d7c3c0b8473147cade277863d238aff96 Mon Sep 17 00:00:00 2001 From: Sean Date: Sat, 4 May 2024 13:45:12 -0700 Subject: [PATCH] fulfill selected --- .../admin/store/PickupOrder/index.tsx | 55 +++++++++++++------ .../admin/store/PickupOrder/style.module.scss | 6 ++ .../store/PickupOrder/style.module.scss.d.ts | 1 + .../PickupOrdersPrepareDisplay/index.tsx | 17 ++---- .../style.module.scss | 8 +++ src/lib/utils.ts | 17 ++++-- 6 files changed, 72 insertions(+), 32 deletions(-) diff --git a/src/components/admin/store/PickupOrder/index.tsx b/src/components/admin/store/PickupOrder/index.tsx index 81bd1e63..c23bc937 100644 --- a/src/components/admin/store/PickupOrder/index.tsx +++ b/src/components/admin/store/PickupOrder/index.tsx @@ -1,9 +1,11 @@ import { Button, Typography } from '@/components/common'; import { OrderStatusIndicator } from '@/components/store'; import { StoreAPI } from '@/lib/api'; -import { PublicOrderItemWithQuantity, PublicOrderWithItems } from '@/lib/types/apiResponses'; +import { UUID } from '@/lib/types'; +import { PublicOrderWithItems } from '@/lib/types/apiResponses'; import { OrderStatus } from '@/lib/types/enums'; -import { getOrderItemQuantities, reportError } from '@/lib/utils'; +import { getOrderItemQuantities, itemToString, reportError } from '@/lib/utils'; +import { useState } from 'react'; import styles from './style.module.scss'; interface PickupOrderProps { @@ -13,27 +15,23 @@ interface PickupOrderProps { onOrderUpdate: (orders: PublicOrderWithItems) => void; } -const itemToString = (item: PublicOrderItemWithQuantity): string => { - if (item.option.metadata !== null) - return `${item.option.item.itemName} (${item.option.metadata.type}: ${item.option.metadata.value})`; - return item.option.item.itemName; -}; - const PickupOrder = ({ token, canFulfill, order, onOrderUpdate }: PickupOrderProps) => { - const showFulfill = canFulfill && order.status === OrderStatus.PLACED; const itemQuantities = getOrderItemQuantities(order.items); + const [unselected, setUnselected] = useState(new Set()); + return ( {`${order.user.firstName} ${order.user.lastName}`} - {showFulfill && itemQuantities.length > 1 ? ( + {canFulfill ? ( ) : null} @@ -53,10 +51,33 @@ const PickupOrder = ({ token, canFulfill, order, onOrderUpdate }: PickupOrderPro
    {itemQuantities.map(item => { return ( -
  • - {`${item.quantity} x ${itemToString( - item - )}`} +
  • + + {`${item.quantity} x ${itemToString(item)}`}{' '} + {(order.status === OrderStatus.FULFILLED || + order.status === OrderStatus.PARTIALLY_FULFILLED) && + !item.fulfilled ? ( + Not fulfilled + ) : null} + + {canFulfill + ? item.uuids.map(uuid => ( + { + const copy = new Set(unselected); + if (e.currentTarget.checked) { + copy.delete(uuid); + } else { + copy.add(uuid); + } + setUnselected(copy); + }} + /> + )) + : null}
  • ); })} diff --git a/src/components/admin/store/PickupOrder/style.module.scss b/src/components/admin/store/PickupOrder/style.module.scss index 20869336..c75d6b8b 100644 --- a/src/components/admin/store/PickupOrder/style.module.scss +++ b/src/components/admin/store/PickupOrder/style.module.scss @@ -1,3 +1,5 @@ +@use 'src/styles/vars.scss' as vars; + .row { border-top: 1px solid var(--theme-accent-line-2); @@ -13,6 +15,10 @@ display: flex; flex-wrap: wrap; gap: 10px; + + .notFulfilled { + color: vars.$red; + } } } } diff --git a/src/components/admin/store/PickupOrder/style.module.scss.d.ts b/src/components/admin/store/PickupOrder/style.module.scss.d.ts index 7e31b756..85e9c3bb 100644 --- a/src/components/admin/store/PickupOrder/style.module.scss.d.ts +++ b/src/components/admin/store/PickupOrder/style.module.scss.d.ts @@ -1,5 +1,6 @@ export type Styles = { itemList: string; + notFulfilled: string; row: string; }; diff --git a/src/components/admin/store/PickupOrdersPrepareDisplay/index.tsx b/src/components/admin/store/PickupOrdersPrepareDisplay/index.tsx index b1352574..ea6268c7 100644 --- a/src/components/admin/store/PickupOrdersPrepareDisplay/index.tsx +++ b/src/components/admin/store/PickupOrdersPrepareDisplay/index.tsx @@ -1,7 +1,8 @@ import PickupOrder from '@/components/admin/store/PickupOrder'; import { Typography } from '@/components/common'; -import { PublicOrderItemWithQuantity, PublicOrderWithItems } from '@/lib/types/apiResponses'; -import { getOrderItemQuantities } from '@/lib/utils'; +import { PublicOrderWithItems } from '@/lib/types/apiResponses'; +import { OrderStatus } from '@/lib/types/enums'; +import { OrderItemQuantity, getOrderItemQuantities, itemToString } from '@/lib/utils'; import { useMemo } from 'react'; import styles from './style.module.scss'; @@ -12,19 +13,13 @@ interface PickupOrdersDisplayPrepareProps { onOrderUpdate: (orders: PublicOrderWithItems[]) => void; } -const itemToString = (item: PublicOrderItemWithQuantity): string => { - if (item.option.metadata !== null) - return `${item.option.item.itemName} (${item.option.metadata.type}: ${item.option.metadata.value})`; - return item.option.item.itemName; -}; - const PickupOrdersPrepareDisplay = ({ token, canFulfill, orders, onOrderUpdate, }: PickupOrdersDisplayPrepareProps) => { - const itemBreakdown: PublicOrderItemWithQuantity[] = useMemo(() => { + const itemBreakdown: OrderItemQuantity[] = useMemo(() => { // Concatenate all items together into one large order to display the item breakdown. const allItems = orders.flatMap(a => a.items); return getOrderItemQuantities(allItems); @@ -48,7 +43,7 @@ const PickupOrdersPrepareDisplay = ({ {itemBreakdown.map(item => { return ( - + {item.quantity} @@ -77,7 +72,7 @@ const PickupOrdersPrepareDisplay = ({ {orders.map(order => ( onOrderUpdate( diff --git a/src/components/admin/store/PickupOrdersPrepareDisplay/style.module.scss b/src/components/admin/store/PickupOrdersPrepareDisplay/style.module.scss index e57b1d91..c9cc255d 100644 --- a/src/components/admin/store/PickupOrdersPrepareDisplay/style.module.scss +++ b/src/components/admin/store/PickupOrdersPrepareDisplay/style.module.scss @@ -22,4 +22,12 @@ padding: 1rem 1.5rem; text-align: left; } + + td { + padding: 1.5rem; + } + + tbody tr { + border-top: 1px solid var(--theme-accent-line-2); + } } diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 6eb99ef0..d54b9856 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,7 +1,7 @@ import defaultProfilePictures from '@/lib/constants/profilePictures'; import ranks from '@/lib/constants/ranks'; import showToast from '@/lib/showToast'; -import type { URL } from '@/lib/types'; +import type { URL, UUID } from '@/lib/types'; import type { ApiResponse, CustomErrorBody, @@ -388,25 +388,34 @@ export const isOrderPickupEvent = ( event: PublicOrderPickupEvent | PublicEvent ): event is PublicOrderPickupEvent => 'status' in event; +export type OrderItemQuantity = Omit & { uuids: UUID[] }; + /** * Condenses a list of ordered items into unique items with quantities. */ -export const getOrderItemQuantities = (items: PublicOrderItem[]): PublicOrderItemWithQuantity[] => { - const itemMap = new Map(); +export const getOrderItemQuantities = (items: PublicOrderItem[]): OrderItemQuantity[] => { + const itemMap = new Map(); items.forEach(item => { const hash = `${item.option.uuid} ${item.fulfilled}`; const existingItem = itemMap.get(hash); if (existingItem) { existingItem.quantity += 1; + existingItem.uuids.push(item.uuid); } else { - itemMap.set(hash, { ...item, quantity: 1 }); + itemMap.set(hash, { ...item, quantity: 1, uuids: [item.uuid] }); } }); return Array.from(itemMap.values()); }; +export const itemToString = (item: Pick): string => { + if (item.option.metadata !== null) + return `${item.option.item.itemName} (${item.option.metadata.type}: ${item.option.metadata.value})`; + return item.option.item.itemName; +}; + export function isEnum>( Enum: T, value: string