feat(dashboard): Draft orders create (#6680)

**What**
- Adds Create draft order form
- Updates draft order details page to also display "custom" items.

**Note**
- Currently, the form is missing a way to input a discount code. Need to rethink this a bit, as the we can't implement the design in Figma.
- The current design is missing a way to select from a customers existing shipping addresses, we should add that to keep the features we have today.
- This PR uses `useInfiniteQuery` which does not work on our staging (due to duplicate dependencies as a result of building straight from the monorepo), so you will need to test locally.
This commit is contained in:
Kasper Fabricius Kristensen
2024-03-25 17:18:24 +00:00
committed by GitHub
parent 20132d7cea
commit 26531c5a38
54 changed files with 3414 additions and 536 deletions
@@ -180,7 +180,7 @@ const ComboboxImpl = <T extends Value = string>(
const results = isSearchControlled ? options : matches
return (
<Popover.Root open={open} onOpenChange={setOpen}>
<Popover.Root modal open={open} onOpenChange={setOpen}>
<PrimitiveComboboxProvider
open={open}
setOpen={setOpen}
@@ -199,7 +199,7 @@ const ComboboxImpl = <T extends Value = string>(
"bg-ui-bg-field transition-fg shadow-borders-base",
"hover:bg-ui-bg-field-hover",
"has-[input:focus]:shadow-borders-interactive-with-active",
"has-[:invalid]:shadow-borders-error",
"has-[:invalid]:shadow-borders-error has-[[aria-invalid=true]]:shadow-borders-error",
"has-[:disabled]:bg-ui-bg-disabled has-[:disabled]:text-ui-fg-disabled has-[:disabled]:cursor-not-allowed",
{
"pl-0.5": hasValue && isArrayValue,
@@ -0,0 +1,19 @@
import { Tooltip } from "@medusajs/ui"
import { PropsWithChildren, ReactNode } from "react"
type ConditionalTooltipProps = PropsWithChildren<{
content: ReactNode
showTooltip?: boolean
}>
export const ConditionalTooltip = ({
children,
content,
showTooltip = false,
}: ConditionalTooltipProps) => {
if (showTooltip) {
return <Tooltip content={content}>{children}</Tooltip>
}
return children
}
@@ -0,0 +1 @@
export * from "./conditional-tooltip"
@@ -2,6 +2,7 @@ import { Address, Cart, Order } from "@medusajs/medusa"
import { Avatar, Copy, Text } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom"
import { getFormattedAddress, isSameAddress } from "../../../lib/addresses"
const ID = ({ data }: { data: Cart | Order }) => {
const { t } = useTranslation()
@@ -182,74 +183,6 @@ export const CustomerInfo = Object.assign(
}
)
const isSameAddress = (a: Address | null, b: Address | null) => {
if (!a || !b) {
return false
}
return (
a.first_name === b.first_name &&
a.last_name === b.last_name &&
a.address_1 === b.address_1 &&
a.address_2 === b.address_2 &&
a.city === b.city &&
a.postal_code === b.postal_code &&
a.province === b.province &&
a.country_code === b.country_code
)
}
const getFormattedAddress = ({ address }: { address: Address }) => {
const {
first_name,
last_name,
company,
address_1,
address_2,
city,
postal_code,
province,
country,
country_code,
} = address
const name = [first_name, last_name].filter(Boolean).join(" ")
const formattedAddress = []
if (name) {
formattedAddress.push(name)
}
if (company) {
formattedAddress.push(company)
}
if (address_1) {
formattedAddress.push(address_1)
}
if (address_2) {
formattedAddress.push(address_2)
}
const cityProvincePostal = [city, province, postal_code]
.filter(Boolean)
.join(" ")
if (cityProvincePostal) {
formattedAddress.push(cityProvincePostal)
}
if (country) {
formattedAddress.push(country.display_name)
} else if (country_code) {
formattedAddress.push(country_code.toUpperCase())
}
return formattedAddress
}
const getCartOrOrderCustomer = (obj: Cart | Order) => {
const { first_name: sFirstName, last_name: sLastName } =
obj.shipping_address || {}
@@ -0,0 +1,31 @@
import { clx } from "@medusajs/ui"
import { ComponentPropsWithoutRef } from "react"
interface DividerProps
extends Omit<ComponentPropsWithoutRef<"div">, "children"> {
orientation?: "horizontal" | "vertical"
variant?: "dashed" | "solid"
}
export const Divider = ({
orientation = "horizontal",
variant = "solid",
className,
...props
}: DividerProps) => {
return (
<div
aria-orientation={orientation}
role="separator"
className={clx(
{
"w-full border-t": orientation === "horizontal",
"h-full border-l": orientation === "vertical",
"border-dashed": variant === "dashed",
},
className
)}
{...props}
/>
)
}
@@ -0,0 +1 @@
export * from "./divider"
@@ -1,9 +1,9 @@
import { Photo } from "@medusajs/icons";
import { Photo } from "@medusajs/icons"
type ThumbnailProps = {
src?: string | null;
alt?: string;
};
src?: string | null
alt?: string
}
export const Thumbnail = ({ src, alt }: ThumbnailProps) => {
return (
@@ -15,8 +15,8 @@ export const Thumbnail = ({ src, alt }: ThumbnailProps) => {
className="h-full w-full object-cover object-center"
/>
) : (
<Photo />
<Photo className="text-ui-fg-subtle" />
)}
</div>
);
};
)
}