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