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:
committed by
GitHub
parent
beaa851302
commit
0fe1201435
+26
@@ -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"
|
||||
+46
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./created-at-cell"
|
||||
+46
@@ -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"
|
||||
+28
@@ -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"
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./money-amount-cell"
|
||||
+38
@@ -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"
|
||||
+31
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./placeholder-cell"
|
||||
+7
@@ -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"
|
||||
+32
@@ -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"
|
||||
+49
@@ -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>
|
||||
)
|
||||
}
|
||||
+27
@@ -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>
|
||||
)
|
||||
}
|
||||
+25
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./first-seen-cell"
|
||||
+32
@@ -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"
|
||||
+31
@@ -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"
|
||||
+24
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./display-id-cell"
|
||||
+35
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./fulfillment-status-cell"
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./payment-status-cell"
|
||||
+25
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./sales-channel-cell"
|
||||
+30
@@ -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"
|
||||
+28
@@ -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>
|
||||
)
|
||||
}
|
||||
+30
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./collection-cell"
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./product-cell"
|
||||
+29
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./product-status-cell"
|
||||
+31
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./sales-channels-cell"
|
||||
+65
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./variant-cell"
|
||||
+34
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./status-cell"
|
||||
+28
@@ -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_>
|
||||
}
|
||||
+39
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./countries-cell"
|
||||
+49
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./fulfillment-providers-cell"
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./payment-providers-cell"
|
||||
+36
@@ -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"
|
||||
+23
@@ -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>
|
||||
)
|
||||
}
|
||||
+28
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./description-cell"
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./name-cell"
|
||||
+28
@@ -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>
|
||||
)
|
||||
}
|
||||
+25
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./admin-only-cell"
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./is-return-cell"
|
||||
+27
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./price-type-cell"
|
||||
+34
@@ -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>
|
||||
)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
export * from "./shipping-option-cell"
|
||||
+28
@@ -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>
|
||||
)
|
||||
}
|
||||
+31
@@ -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"
|
||||
+33
@@ -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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user