import * as RadixPopover from "@radix-ui/react-popover" import { Cell, Row, TableRowProps, usePagination, useTable } from "react-table" import React, { useEffect, useMemo, useRef, useState } from "react" import { ReservationItemDTO, StockLocationDTO } from "@medusajs/types" import { useAdminDeleteReservation, useAdminReservations, useAdminStockLocations, useAdminStore, } from "medusa-react" import { useTranslation } from "react-i18next" import BuildingsIcon from "../../fundamentals/icons/buildings-icon" import Button from "../../fundamentals/button" import DeletePrompt from "../../organisms/delete-prompt" import EditIcon from "../../fundamentals/icons/edit-icon" import EditReservationDrawer from "../../../domain/orders/details/reservation/edit-reservation-modal" import Fade from "../../atoms/fade-wrapper" import NewReservation from "./new" import { Option } from "../../../types/shared" import ReservationsFilters from "./components/reservations-filter" import Table from "../../molecules/table" import TableContainer from "../../../components/organisms/table-container" import TagDotIcon from "../../fundamentals/icons/tag-dot-icon" import Tooltip from "../../atoms/tooltip" import TrashIcon from "../../fundamentals/icons/trash-icon" import clsx from "clsx" import { isEmpty } from "lodash" import qs from "qs" import { useLocation } from "react-router-dom" import { useReservationFilters } from "./use-reservation-filters" import useReservationsTableColumns from "./use-reservations-columns" import useToggleState from "../../../hooks/use-toggle-state" const DEFAULT_PAGE_SIZE = 15 type ReservationsTableProps = {} const LocationDropdown = ({ selectedLocation, onChange, }: { selectedLocation: string onChange: (id: string) => void }) => { const [open, setOpen] = useState(false) const ref = useRef(null) const { stock_locations: locations, isLoading } = useAdminStockLocations() const locationOptions = useMemo(() => { let locationOptions: { label: string; value?: string }[] = [] if (!isLoading && locations) { locationOptions = locations.map((l: StockLocationDTO) => ({ label: l.name, value: l.id, })) } locationOptions.unshift({ label: "All locations", value: undefined }) return locationOptions }, [isLoading, locations]) const selectedLocObj = useMemo(() => { if (locationOptions?.length) { return ( locationOptions.find( (l: { value?: string; label: string }) => l.value === selectedLocation ) ?? locationOptions[0] ) } }, [selectedLocation, locationOptions]) const isEllipsisActive = ( e: { offsetWidth: number; scrollWidth: number } | null ) => { if (!e) { return false } return e.offsetWidth < e.scrollWidth } if (isLoading || !locationOptions?.length) { return null } return (
{selectedLocObj?.label}
} > {locationOptions.map((o, i) => (
{ setOpen(false) onChange(o!.value) }} >
{selectedLocObj?.value === o.value && ( )}

{o.label}

))}
) } const ReservationsTable: React.FC = () => { const { t } = useTranslation() const { store } = useAdminStore() const { state: createReservationState, close: closeReservationCreate, open: openReservationCreate, } = useToggleState() const location = useLocation() const defaultQuery = useMemo(() => { if (store) { return { location_id: store.default_location_id, } } return {} }, [store]) const { reset, paginate, setLocationFilter, setQuery: setFreeText, queryObject, representationObject, filters, setFilters, setDefaultFilters, } = useReservationFilters(location.search, defaultQuery) const offs = parseInt(queryObject.offset) || 0 const limit = parseInt(queryObject.limit) const [query, setQuery] = useState(queryObject.query) const [numPages, setNumPages] = useState(0) const { reservations, isLoading, count } = useAdminReservations( { ...queryObject, expand: "line_item,inventory_item", }, { enabled: !!store, } ) useEffect(() => { const controlledPageCount = Math.ceil(count! / queryObject.limit) setNumPages(controlledPageCount) }, [reservations]) const updateUrlFromFilter = (obj = {}) => { const stringified = qs.stringify(obj) window.history.replaceState(`/a/reservations`, "", `${`?${stringified}`}`) } const refreshWithFilters = () => { const filterObj = representationObject if (isEmpty(filterObj)) { updateUrlFromFilter({ offset: 0, limit: DEFAULT_PAGE_SIZE }) } else { updateUrlFromFilter(filterObj) } } useEffect(() => { refreshWithFilters() }, [representationObject]) const [columns] = useReservationsTableColumns() const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow, gotoPage, canPreviousPage, canNextPage, pageCount, nextPage, previousPage, // Get the state from the instance state: { pageIndex }, } = useTable( { columns, data: reservations || [], manualPagination: true, initialState: { pageIndex: Math.floor(offs / limit), pageSize: limit, }, pageCount: numPages, autoResetPage: false, }, usePagination ) // Debounced search useEffect(() => { const delayDebounceFn = setTimeout(() => { if (query) { setFreeText(query) gotoPage(0) } else { if (typeof query !== "undefined") { // if we delete query string, we reset the table view reset() } } }, 400) return () => clearTimeout(delayDebounceFn) }, [query]) const handleNext = () => { if (canNextPage) { paginate(1) nextPage() } } const handlePrev = () => { if (canPreviousPage) { paginate(-1) previousPage() } } return ( <> { setLocationFilter(id) gotoPage(0) }} /> } {...getTableProps()} > {headerGroups?.map((headerGroup) => { const { key, ...rest } = headerGroup.getHeaderGroupProps() return ( {headerGroup.headers.map((col) => { const { key, ...rest } = col.getHeaderProps() return ( {col.render("Header")} ) })} ) })} {rows.map((row) => { prepareRow(row) const { key, ...rest } = row.getRowProps() return })}
) } const ReservationRow = ({ row, ...rest }: { row: Row } & TableRowProps) => { const inventory = row.original const { t } = useTranslation() const { mutate: deleteReservation } = useAdminDeleteReservation(inventory.id) const [showEditReservation, setShowEditReservation] = useState(null) const [showDeleteReservation, setShowDeleteReservation] = useState(false) const getRowActionables = () => { const actions = [ { label: t("reservations-table-edit", "Edit"), onClick: () => setShowEditReservation(row.original), icon: , }, { label: t("reservations-table-delete", "Delete"), variant: "danger", icon: , onClick: () => setShowDeleteReservation(true), }, ] return actions } return ( <> {row.cells.map((cell: Cell, index: number) => { const { key, ...rest } = cell.getCellProps() return ( {cell.render("Cell", { index })} ) })} {showEditReservation && ( setShowEditReservation(null)} reservation={row.original} /> )} {showDeleteReservation && ( await deleteReservation(undefined)} handleClose={() => setShowDeleteReservation(false)} /> )} ) } export default ReservationsTable