feat(admin-sdk,admin-bundler,admin-shared,medusa): Restructure admin packages (#8988)

**What**
- Renames /admin-next -> /admin
- Renames @medusajs/admin-sdk -> @medusajs/admin-bundler
- Creates a new package called @medusajs/admin-sdk that will hold all tooling relevant to creating admin extensions. This is currently `defineRouteConfig` and `defineWidgetConfig`, but will eventually also export methods for adding custom fields, register translation, etc. 
  - cc: @shahednasser we should update the examples in the docs so these functions are imported from `@medusajs/admin-sdk`. People will also need to install the package in their project, as it's no longer a transient dependency.
  - cc: @olivermrbl we might want to publish a changelog when this is merged, as it is a breaking change, and will require people to import the `defineXConfig` from the new package instead of `@medusajs/admin-shared`.
- Updates CODEOWNERS so /admin packages does not require a review from the UI team.
This commit is contained in:
Kasper Fabricius Kristensen
2024-09-04 21:00:25 +02:00
committed by GitHub
parent beaa851302
commit 0fe1201435
1440 changed files with 122 additions and 86 deletions
@@ -0,0 +1,26 @@
type CellProps = {
code: string
}
type HeaderProps = {
text: string
}
export const CodeCell = ({ code }: CellProps) => {
return (
<div className="flex h-full w-full items-center gap-x-3 overflow-hidden">
{/* // TODO: border color inversion*/}
<span className="bg-ui-tag-neutral-bg truncate rounded-md border border-neutral-200 p-1 text-xs">
{code}
</span>
</div>
)
}
export const CodeHeader = ({ text }: HeaderProps) => {
return (
<div className=" flex h-full w-full items-center ">
<span>{text}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./code-cell"
@@ -0,0 +1,46 @@
import { Tooltip } from "@medusajs/ui"
import format from "date-fns/format"
import { useTranslation } from "react-i18next"
import { PlaceholderCell } from "../placeholder-cell"
type DateCellProps = {
date: Date | string | undefined
}
export const CreatedAtCell = ({ date }: DateCellProps) => {
if (!date) {
return <PlaceholderCell />
}
const value = new Date(date)
value.setMinutes(value.getMinutes() - value.getTimezoneOffset())
const hour12 = Intl.DateTimeFormat().resolvedOptions().hour12
const timestampFormat = hour12 ? "dd MMM yyyy hh:MM a" : "dd MMM yyyy HH:MM"
return (
<div className="flex h-full w-full items-center overflow-hidden">
<Tooltip
className="z-10"
content={
<span className="text-pretty">{`${format(
value,
timestampFormat
)}`}</span>
}
>
<span className="truncate">{format(value, "dd MMM yyyy")}</span>
</Tooltip>
</div>
)
}
export const CreatedAtHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.createdAt")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./created-at-cell"
@@ -0,0 +1,46 @@
import { Tooltip } from "@medusajs/ui"
import { format } from "date-fns/format"
import { useTranslation } from "react-i18next"
import { PlaceholderCell } from "../placeholder-cell"
type DateCellProps = {
date?: Date | string | null
}
export const DateCell = ({ date }: DateCellProps) => {
if (!date) {
return <PlaceholderCell />
}
const value = new Date(date)
value.setMinutes(value.getMinutes() - value.getTimezoneOffset())
const hour12 = Intl.DateTimeFormat().resolvedOptions().hour12
const timestampFormat = hour12 ? "dd MMM yyyy hh:MM a" : "dd MMM yyyy HH:MM"
return (
<div className="flex h-full w-full items-center overflow-hidden">
<Tooltip
className="z-10"
content={
<span className="text-pretty">{`${format(
value,
timestampFormat
)}`}</span>
}
>
<span className="truncate">{format(value, "dd MMM yyyy")}</span>
</Tooltip>
</div>
)
}
export const DateHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.date")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./date-cell"
@@ -0,0 +1,28 @@
import { useTranslation } from "react-i18next"
import { PlaceholderCell } from "../placeholder-cell"
type EmailCellProps = {
email?: string | null
}
export const EmailCell = ({ email }: EmailCellProps) => {
if (!email) {
return <PlaceholderCell />
}
return (
<div className="flex h-full w-full items-center overflow-hidden">
<span className="truncate">{email}</span>
</div>
)
}
export const EmailHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.email")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./email-cell"
@@ -0,0 +1 @@
export * from "./money-amount-cell"
@@ -0,0 +1,38 @@
import { clx } from "@medusajs/ui"
import { getStylizedAmount } from "../../../../../lib/money-amount-helpers"
import { PlaceholderCell } from "../placeholder-cell"
type MoneyAmountCellProps = {
currencyCode: string
amount?: number | null
align?: "left" | "right"
className?: string
}
export const MoneyAmountCell = ({
currencyCode,
amount,
align = "left",
className,
}: MoneyAmountCellProps) => {
if (typeof amount === "undefined" || amount === null) {
return <PlaceholderCell />
}
const formatted = getStylizedAmount(amount, currencyCode)
return (
<div
className={clx(
"flex h-full w-full items-center overflow-hidden",
{
"justify-start text-left": align === "left",
"justify-end text-right": align === "right",
},
className
)}
>
<span className="truncate">{formatted}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./name-cell"
@@ -0,0 +1,31 @@
import { useTranslation } from "react-i18next"
import { PlaceholderCell } from "../placeholder-cell"
type NameCellProps = {
firstName?: string | null
lastName?: string | null
}
export const NameCell = ({ firstName, lastName }: NameCellProps) => {
if (!firstName && !lastName) {
return <PlaceholderCell />
}
const name = [firstName, lastName].filter(Boolean).join(" ")
return (
<div className="flex h-full w-full items-center overflow-hidden">
<span className="truncate">{name}</span>
</div>
)
}
export const NameHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.name")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./placeholder-cell"
@@ -0,0 +1,7 @@
export const PlaceholderCell = () => {
return (
<div className="flex h-full w-full items-center">
<span className="text-ui-fg-muted">-</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./status-cell"
@@ -0,0 +1,32 @@
import { clx } from "@medusajs/ui"
import { PropsWithChildren } from "react"
type StatusCellProps = PropsWithChildren<{
color?: "green" | "red" | "blue" | "orange" | "grey" | "purple"
}>
export const StatusCell = ({ color, children }: StatusCellProps) => {
return (
<div className="txt-compact-small text-ui-fg-subtle flex h-full w-full items-center gap-x-2 overflow-hidden">
<div
role="presentation"
className="flex h-5 w-2 items-center justify-center"
>
<div
className={clx(
"h-2 w-2 rounded-sm shadow-[0px_0px_0px_1px_rgba(0,0,0,0.12)_inset]",
{
"bg-ui-tag-neutral-icon": color === "grey",
"bg-ui-tag-green-icon": color === "green",
"bg-ui-tag-red-icon": color === "red",
"bg-ui-tag-blue-icon": color === "blue",
"bg-ui-tag-orange-icon": color === "orange",
"bg-ui-tag-purple-icon": color === "purple",
}
)}
/>
</div>
<span className="truncate">{children}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./text-cell"
@@ -0,0 +1,49 @@
import { clx } from "@medusajs/ui"
import { ConditionalTooltip } from "../../../../common/conditional-tooltip"
import { PlaceholderCell } from "../placeholder-cell"
type CellProps = {
text?: string | number
align?: "left" | "center" | "right"
maxWidth?: number
}
type HeaderProps = {
text: string
align?: "left" | "center" | "right"
}
export const TextCell = ({ text, align = "left", maxWidth = 220 }: CellProps) => {
if (!text) {
return <PlaceholderCell />
}
const stringLength = text.toString().length
return (
<ConditionalTooltip content={text} showTooltip={stringLength > 20}>
<div className={clx("flex h-full w-full items-center gap-x-3 overflow-hidden", {
"justify-start text-start": align === "left",
"justify-center text-center": align === "center",
"justify-end text-end": align === "right",
})}
style={{
maxWidth: maxWidth,
}}>
<span className="truncate">{text}</span>
</div>
</ConditionalTooltip>
)
}
export const TextHeader = ({ text, align = "left" }: HeaderProps) => {
return (
<div className={clx("flex h-full w-full items-center", {
"justify-start text-start": align === "left",
"justify-center text-center": align === "center",
"justify-end text-end": align === "right",
})}>
<span className="truncate">{text}</span>
</div>
)
}
@@ -0,0 +1,27 @@
import { useTranslation } from "react-i18next"
import { StatusCell } from "../../common/status-cell"
type AccountCellProps = {
hasAccount: boolean
}
export const AccountCell = ({ hasAccount }: AccountCellProps) => {
const { t } = useTranslation()
const color = hasAccount ? "green" : ("orange" as const)
const text = hasAccount
? t("customers.fields.registered")
: t("customers.fields.guest")
return <StatusCell color={color}>{text}</StatusCell>
}
export const AccountHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.account")}</span>
</div>
)
}
@@ -0,0 +1,25 @@
import { useTranslation } from "react-i18next"
import { DateCell } from "../../common/date-cell"
import { PlaceholderCell } from "../../common/placeholder-cell"
type FirstSeenCellProps = {
createdAt?: Date | string | null
}
export const FirstSeenCell = ({ createdAt }: FirstSeenCellProps) => {
if (!createdAt) {
return <PlaceholderCell />
}
return <DateCell date={createdAt} />
}
export const FirstSeenHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.createdAt")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./first-seen-cell"
@@ -0,0 +1,32 @@
import { Tooltip } from "@medusajs/ui"
import ReactCountryFlag from "react-country-flag"
import { PlaceholderCell } from "../../common/placeholder-cell"
import { HttpTypes } from "@medusajs/types"
export const CountryCell = ({
country,
}: {
country?: HttpTypes.AdminRegionCountry | null
}) => {
if (!country) {
return <PlaceholderCell />
}
return (
<div className="flex size-5 items-center justify-center">
<Tooltip content={country.display_name}>
<div className="flex size-4 items-center justify-center overflow-hidden rounded-sm">
<ReactCountryFlag
countryCode={country.iso_2!.toUpperCase()}
svg
style={{
width: "16px",
height: "16px",
}}
aria-label={country.display_name}
/>
</div>
</Tooltip>
</div>
)
}
@@ -0,0 +1 @@
export * from "./country-cell"
@@ -0,0 +1,31 @@
import { HttpTypes } from "@medusajs/types"
import { useTranslation } from "react-i18next"
export const CustomerCell = ({
customer,
}: {
customer: HttpTypes.AdminCustomer | null
}) => {
if (!customer) {
return <span className="text-ui-fg-muted">-</span>
}
const { first_name, last_name, email } = customer
const name = [first_name, last_name].filter(Boolean).join(" ")
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{name || email}</span>
</div>
)
}
export const CustomerHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.customer")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./customer-cell"
@@ -0,0 +1,24 @@
import { useTranslation } from "react-i18next"
import { PlaceholderCell } from "../../common/placeholder-cell"
export const DisplayIdCell = ({ displayId }: { displayId?: number | null }) => {
if (!displayId) {
return <PlaceholderCell />
}
return (
<div className="text-ui-fg-subtle txt-compact-small flex h-full w-full items-center overflow-hidden">
<span className="truncate">#{displayId}</span>
</div>
)
}
export const DisplayIdHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.order")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./display-id-cell"
@@ -0,0 +1,35 @@
import { useTranslation } from "react-i18next"
import { FulfillmentStatus } from "@medusajs/types"
import { getOrderFulfillmentStatus } from "../../../../../lib/order-helpers"
import { StatusCell } from "../../common/status-cell"
type FulfillmentStatusCellProps = {
status: FulfillmentStatus
}
export const FulfillmentStatusCell = ({
status,
}: FulfillmentStatusCellProps) => {
const { t } = useTranslation()
if (!status) {
// TODO: remove this once fulfillment<>order link is added
return "-"
}
const { label, color } = getOrderFulfillmentStatus(t, status)
return <StatusCell color={color}>{label}</StatusCell>
}
export const FulfillmentStatusHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.fulfillment")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./fulfillment-status-cell"
@@ -0,0 +1 @@
export * from "./payment-status-cell"
@@ -0,0 +1,25 @@
import { useTranslation } from "react-i18next"
import { getOrderPaymentStatus } from "../../../../../lib/order-helpers"
import { StatusCell } from "../../common/status-cell"
type PaymentStatusCellProps = {
status: PaymentStatus
}
export const PaymentStatusCell = ({ status }: PaymentStatusCellProps) => {
const { t } = useTranslation()
const { label, color } = getOrderPaymentStatus(t, status)
return <StatusCell color={color}>{label}</StatusCell>
}
export const PaymentStatusHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.payment")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./sales-channel-cell"
@@ -0,0 +1,30 @@
import { HttpTypes } from "@medusajs/types"
import { useTranslation } from "react-i18next"
export const SalesChannelCell = ({
channel,
}: {
channel: HttpTypes.AdminSalesChannel | null
}) => {
if (!channel) {
return <span className="text-ui-fg-muted">-</span>
}
const { name } = channel
return (
<div className="flex h-full w-full items-center overflow-hidden">
<span className="truncate">{name}</span>
</div>
)
}
export const SalesChannelHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.salesChannel")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./total-cell"
@@ -0,0 +1,28 @@
import { useTranslation } from "react-i18next"
import { MoneyAmountCell } from "../../common/money-amount-cell"
import { PlaceholderCell } from "../../common/placeholder-cell"
type TotalCellProps = {
currencyCode: string
total: number | null
}
export const TotalCell = ({ currencyCode, total }: TotalCellProps) => {
if (!total) {
return <PlaceholderCell />
}
return (
<MoneyAmountCell currencyCode={currencyCode} amount={total} align="right" />
)
}
export const TotalHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center justify-end">
<span className="truncate">{t("fields.total")}</span>
</div>
)
}
@@ -0,0 +1,30 @@
import { useTranslation } from "react-i18next"
import { PlaceholderCell } from "../../common/placeholder-cell"
import { HttpTypes } from "@medusajs/types"
type CollectionCellProps = {
collection?: HttpTypes.AdminCollection | null
}
export const CollectionCell = ({ collection }: CollectionCellProps) => {
if (!collection) {
return <PlaceholderCell />
}
return (
<div className="flex h-full w-full items-center overflow-hidden">
<span className="truncate">{collection.title}</span>
</div>
)
}
export const CollectionHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span>{t("fields.collection")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./collection-cell"
@@ -0,0 +1 @@
export * from "./product-cell"
@@ -0,0 +1,29 @@
import { useTranslation } from "react-i18next"
import { Thumbnail } from "../../../../common/thumbnail"
import { HttpTypes } from "@medusajs/types"
type ProductCellProps = {
product: HttpTypes.AdminProduct
}
export const ProductCell = ({ product }: ProductCellProps) => {
return (
<div className="flex h-full w-full items-center gap-x-3 overflow-hidden">
<div className="w-fit flex-shrink-0">
<Thumbnail src={product.thumbnail} />
</div>
<span className="truncate">{product.title}</span>
</div>
)
}
export const ProductHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span>{t("fields.product")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./product-status-cell"
@@ -0,0 +1,31 @@
import { useTranslation } from "react-i18next"
import { StatusCell } from "../../common/status-cell"
import { HttpTypes } from "@medusajs/types"
type ProductStatusCellProps = {
status: HttpTypes.AdminProductStatus
}
export const ProductStatusCell = ({ status }: ProductStatusCellProps) => {
const { t } = useTranslation()
const [color, text] = {
draft: ["grey", t("products.productStatus.draft")],
proposed: ["orange", t("products.productStatus.proposed")],
published: ["green", t("products.productStatus.published")],
rejected: ["red", t("products.productStatus.rejected")],
}[status] as ["grey" | "orange" | "green" | "red", string]
return <StatusCell color={color}>{text}</StatusCell>
}
export const ProductStatusHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span>{t("fields.status")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./sales-channels-cell"
@@ -0,0 +1,65 @@
import { Tooltip } from "@medusajs/ui"
import { useTranslation } from "react-i18next"
import { SalesChannelDTO } from "@medusajs/types"
import { PlaceholderCell } from "../../common/placeholder-cell"
type SalesChannelsCellProps = {
salesChannels?: SalesChannelDTO[] | null
}
export const SalesChannelsCell = ({
salesChannels,
}: SalesChannelsCellProps) => {
const { t } = useTranslation()
if (!salesChannels || !salesChannels.length) {
return <PlaceholderCell />
}
if (salesChannels.length > 2) {
return (
<div className="flex h-full w-full items-center gap-x-1 overflow-hidden">
<span className="truncate">
{salesChannels
.slice(0, 2)
.map((sc) => sc.name)
.join(", ")}
</span>
<Tooltip
content={
<ul>
{salesChannels.slice(2).map((sc) => (
<li key={sc.id}>{sc.name}</li>
))}
</ul>
}
>
<span className="text-xs">
{t("general.plusCountMore", {
count: salesChannels.length - 2,
})}
</span>
</Tooltip>
</div>
)
}
return (
<div className="flex h-full w-full items-center overflow-hidden">
<span className="truncate">
{salesChannels.map((sc) => sc.name).join(", ")}
</span>
</div>
)
}
export const SalesChannelHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span>{t("fields.salesChannels")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./variant-cell"
@@ -0,0 +1,34 @@
import { useTranslation } from "react-i18next"
import { PlaceholderCell } from "../../common/placeholder-cell"
import { HttpTypes } from "@medusajs/types"
type VariantCellProps = {
variants?: HttpTypes.AdminProductVariant[] | null
}
export const VariantCell = ({ variants }: VariantCellProps) => {
const { t } = useTranslation()
if (!variants || !variants.length) {
return <PlaceholderCell />
}
return (
<div className="flex h-full w-full items-center overflow-hidden">
<span className="truncate">
{t("products.variantCount", { count: variants.length })}
</span>
</div>
)
}
export const VariantHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span>{t("fields.variants")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./status-cell"
@@ -0,0 +1,28 @@
import { PromotionDTO } from "@medusajs/types"
import { useTranslation } from "react-i18next"
import {
getPromotionStatus,
PromotionStatus,
} from "../../../../../lib/promotions"
import { StatusCell as StatusCell_ } from "../../common/status-cell"
type PromotionCellProps = {
promotion: PromotionDTO
}
type StatusColors = "grey" | "orange" | "green" | "red"
type StatusMap = Record<string, [StatusColors, string]>
export const StatusCell = ({ promotion }: PromotionCellProps) => {
const { t } = useTranslation()
const statusMap: StatusMap = {
[PromotionStatus.DISABLED]: ["grey", t("statuses.disabled")],
[PromotionStatus.ACTIVE]: ["green", t("statuses.active")],
[PromotionStatus.SCHEDULED]: ["orange", t("statuses.scheduled")],
[PromotionStatus.EXPIRED]: ["red", t("statuses.expired")],
}
const [color, text] = statusMap[getPromotionStatus(promotion)]
return <StatusCell_ color={color}>{text}</StatusCell_>
}
@@ -0,0 +1,39 @@
import { RegionCountryDTO } from "@medusajs/types"
import { useTranslation } from "react-i18next"
import { countries as COUNTRIES } from "../../../../../lib/data/countries"
import { ListSummary } from "../../../../common/list-summary"
import { PlaceholderCell } from "../../common/placeholder-cell"
type CountriesCellProps = {
countries?: RegionCountryDTO[] | null
}
export const CountriesCell = ({ countries }: CountriesCellProps) => {
const { t } = useTranslation()
if (!countries || countries.length === 0) {
return <PlaceholderCell />
}
return (
<div className="flex size-full items-center overflow-hidden">
<ListSummary
list={countries.map(
(country) =>
COUNTRIES.find((c) => c.iso_2 === country.iso_2)!.display_name
)}
/>
</div>
)
}
export const CountriesHeader = () => {
const { t } = useTranslation()
return (
<div className="flex size-full items-center">
<span>{t("fields.countries")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./countries-cell"
@@ -0,0 +1,49 @@
import { useTranslation } from "react-i18next"
import { formatProvider } from "../../../../../lib/format-provider"
import { PlaceholderCell } from "../../common/placeholder-cell"
import { HttpTypes } from "@medusajs/types"
type FulfillmentProvidersCellProps = {
fulfillmentProviders?: HttpTypes.AdminFulfillmentProvider[] | null
}
export const FulfillmentProvidersCell = ({
fulfillmentProviders,
}: FulfillmentProvidersCellProps) => {
const { t } = useTranslation()
if (!fulfillmentProviders || fulfillmentProviders.length === 0) {
return <PlaceholderCell />
}
const displayValue = fulfillmentProviders
.slice(0, 2)
.map((p) => formatProvider(p.id))
.join(", ")
const additionalProviders = fulfillmentProviders.slice(2).length
const text = `${displayValue}${
additionalProviders > 0
? ` ${t("general.plusCountMore", {
count: additionalProviders,
})}`
: ""
}`
return (
<div className="flex size-full items-center overflow-hidden">
<span className="truncate">{text}</span>
</div>
)
}
export const FulfillmentProvidersHeader = () => {
const { t } = useTranslation()
return (
<div className="flex size-full items-center overflow-hidden">
<span className="truncate">{t("fields.fulfillmentProviders")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./fulfillment-providers-cell"
@@ -0,0 +1 @@
export * from "./payment-providers-cell"
@@ -0,0 +1,36 @@
import { useTranslation } from "react-i18next"
import { PaymentProviderDTO } from "@medusajs/types"
import { formatProvider } from "../../../../../lib/format-provider"
import { PlaceholderCell } from "../../common/placeholder-cell"
import { ListSummary } from "../../../../common/list-summary"
type PaymentProvidersCellProps = {
paymentProviders?: PaymentProviderDTO[] | null
}
export const PaymentProvidersCell = ({
paymentProviders,
}: PaymentProvidersCellProps) => {
if (!paymentProviders || paymentProviders.length === 0) {
return <PlaceholderCell />
}
const displayValues = paymentProviders.map((p) => formatProvider(p.id))
return (
<div className="flex size-full items-center overflow-hidden">
<ListSummary list={displayValues} />
</div>
)
}
export const PaymentProvidersHeader = () => {
const { t } = useTranslation()
return (
<div className="flex size-full items-center overflow-hidden">
<span className="truncate">{t("fields.paymentProviders")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./region-cell"
@@ -0,0 +1,23 @@
import { useTranslation } from "react-i18next"
type RegionCellProps = {
name: string
}
export const RegionCell = ({ name }: RegionCellProps) => {
return (
<div className="flex h-full w-full items-center overflow-hidden">
<span className="truncate">{name}</span>
</div>
)
}
export const RegionHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.name")}</span>
</div>
)
}
@@ -0,0 +1,28 @@
import { useTranslation } from "react-i18next"
import { PlaceholderCell } from "../../common/placeholder-cell"
type DescriptionCellProps = {
description?: string | null
}
export const DescriptionCell = ({ description }: DescriptionCellProps) => {
if (!description) {
return <PlaceholderCell />
}
return (
<div className="flex h-full w-full items-center overflow-hidden">
<span className="truncate">{description}</span>
</div>
)
}
export const DescriptionHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.description")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./description-cell"
@@ -0,0 +1 @@
export * from "./name-cell"
@@ -0,0 +1,28 @@
import { useTranslation } from "react-i18next"
import { PlaceholderCell } from "../../common/placeholder-cell"
type NameCellProps = {
name?: string | null
}
export const NameCell = ({ name }: NameCellProps) => {
if (!name) {
return <PlaceholderCell />
}
return (
<div className="flex h-full w-full items-center overflow-hidden">
<span className="truncate">{name}</span>
</div>
)
}
export const NameHeader = () => {
const { t } = useTranslation()
return (
<div className="flex h-full w-full items-center">
<span className="truncate">{t("fields.name")}</span>
</div>
)
}
@@ -0,0 +1,25 @@
import { useTranslation } from "react-i18next"
import { StatusCell } from "../../common/status-cell"
type AdminOnlyCellProps = {
adminOnly: boolean
}
export const AdminOnlyCell = ({ adminOnly }: AdminOnlyCellProps) => {
const { t } = useTranslation()
const color = adminOnly ? "blue" : "green"
const text = adminOnly ? t("general.admin") : t("general.store")
return <StatusCell color={color}>{text}</StatusCell>
}
export const AdminOnlyHeader = () => {
const { t } = useTranslation()
return (
<div className="flex items-center overflow-hidden">
<span className="truncate">{t("fields.availability")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./admin-only-cell"
@@ -0,0 +1 @@
export * from "./is-return-cell"
@@ -0,0 +1,27 @@
import { useTranslation } from "react-i18next"
type IsReturnCellProps = {
isReturn?: boolean
}
export const IsReturnCell = ({ isReturn }: IsReturnCellProps) => {
const { t } = useTranslation()
return (
<div className="flex items-center overflow-hidden">
<span className="truncate">
{isReturn ? t("regions.return") : t("regions.outbound")}
</span>
</div>
)
}
export const IsReturnHeader = () => {
const { t } = useTranslation()
return (
<div className="flex items-center overflow-hidden">
<span className="truncate">{t("fields.type")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./price-type-cell"
@@ -0,0 +1,34 @@
import { useTranslation } from "react-i18next"
import { PlaceholderCell } from "../../common/placeholder-cell"
type PriceTypeCellProps = {
priceType?: "flat_rate" | "calculated"
}
export const PriceTypeCell = ({ priceType }: PriceTypeCellProps) => {
const { t } = useTranslation()
if (!priceType) {
return <PlaceholderCell />
}
const isFlatRate = priceType === "flat_rate"
return (
<div className="flex items-center overflow-hidden">
<span className="truncate">
{isFlatRate ? t("regions.flatRate") : t("regions.calculated")}
</span>
</div>
)
}
export const PriceTypeHeader = () => {
const { t } = useTranslation()
return (
<div className="flex items-center overflow-hidden">
<span className="truncate">{t("regions.priceType")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./shipping-option-cell"
@@ -0,0 +1,28 @@
import { useTranslation } from "react-i18next"
import { PlaceholderCell } from "../../common/placeholder-cell"
type ShippingOptionCellProps = {
name?: string | null
}
export const ShippingOptionCell = ({ name }: ShippingOptionCellProps) => {
if (!name) {
return <PlaceholderCell />
}
return (
<div className="flex size-full items-center overflow-hidden">
<span className="truncate">{name}</span>
</div>
)
}
export const ShippingOptionHeader = () => {
const { t } = useTranslation()
return (
<div className="flex items-center overflow-hidden">
<span className="truncate">{t("fields.name")}</span>
</div>
)
}
@@ -0,0 +1,31 @@
import { useTranslation } from "react-i18next"
import { MoneyAmountCell } from "../../common/money-amount-cell"
import { PlaceholderCell } from "../../common/placeholder-cell"
type ShippingPriceCellProps = {
isCalculated: boolean
price?: number | null
currencyCode: string
}
export const ShippingPriceCell = ({
price,
currencyCode,
isCalculated,
}: ShippingPriceCellProps) => {
if (isCalculated || !price) {
return <PlaceholderCell />
}
return <MoneyAmountCell currencyCode={currencyCode} amount={price} />
}
export const ShippingPriceHeader = () => {
const { t } = useTranslation()
return (
<div className="flex items-center overflow-hidden">
<span className="truncate">{t("fields.price")}</span>
</div>
)
}
@@ -0,0 +1 @@
export * from "./type-cell"
@@ -0,0 +1,33 @@
import { Badge } from "@medusajs/ui"
type CellProps = {
is_combinable: boolean
}
type HeaderProps = {
text: string
}
export const TypeCell = ({ is_combinable }: CellProps) => {
return (
<div className="flex h-full w-full items-center gap-x-3 overflow-hidden">
<span className="truncate">
{is_combinable ? (
<Badge size="2xsmall" color="green">
Combinable
</Badge>
) : (
""
)}
</span>
</div>
)
}
export const TypeHeader = ({ text }: HeaderProps) => {
return (
<div className=" flex h-full w-full items-center">
<span>{text}</span>
</div>
)
}