feat(medusa,dashboard,admin-sdk): Run admin dashboard from Medusa instance (#7330)
This commit is contained in:
@@ -1,14 +1,18 @@
|
||||
import { Toaster } from "@medusajs/ui"
|
||||
import { QueryClientProvider } from "@tanstack/react-query"
|
||||
|
||||
import { I18n } from "./components/utilities/i18n"
|
||||
import { queryClient } from "./lib/medusa"
|
||||
import { RouterProvider } from "./providers/router-provider"
|
||||
import { ThemeProvider } from "./providers/theme-provider"
|
||||
|
||||
import "./index.css"
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<ThemeProvider>
|
||||
<I18n />
|
||||
<RouterProvider />
|
||||
<Toaster />
|
||||
</ThemeProvider>
|
||||
|
||||
@@ -64,9 +64,11 @@ export const FileUpload = ({
|
||||
|
||||
const fileList = Array.from(files)
|
||||
const fileObj = fileList.map((file) => {
|
||||
const id = Math.random().toString(36).substring(7)
|
||||
|
||||
const previewUrl = URL.createObjectURL(file)
|
||||
return {
|
||||
id: crypto.randomUUID(),
|
||||
id: id,
|
||||
url: previewUrl,
|
||||
file,
|
||||
}
|
||||
|
||||
@@ -13,13 +13,12 @@ import { Avatar, Text } from "@medusajs/ui"
|
||||
import * as Collapsible from "@radix-ui/react-collapsible"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import { ComponentType } from "react"
|
||||
import { useStore } from "../../../hooks/api/store"
|
||||
import { Skeleton } from "../../common/skeleton"
|
||||
import { NavItem, NavItemProps } from "../../layout/nav-item"
|
||||
import { Shell } from "../../layout/shell"
|
||||
|
||||
import extensions from "medusa-admin:routes/links"
|
||||
|
||||
export const MainLayout = () => {
|
||||
return (
|
||||
<Shell>
|
||||
@@ -167,6 +166,10 @@ const CoreRouteSection = () => {
|
||||
)
|
||||
}
|
||||
|
||||
const extensions = {
|
||||
links: null as { path: string; label: string; icon?: ComponentType }[] | null,
|
||||
}
|
||||
|
||||
const ExtensionRouteSection = () => {
|
||||
if (!extensions.links || extensions.links.length === 0) {
|
||||
return null
|
||||
|
||||
+4
-3
@@ -1,7 +1,7 @@
|
||||
import { DatePicker } from "@medusajs/ui"
|
||||
import { ComponentPropsWithoutRef } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { languages } from "../../../i18n/config"
|
||||
import { languages } from "../../../i18n/languages"
|
||||
|
||||
type LocalizedDatePickerProps = Omit<
|
||||
ComponentPropsWithoutRef<typeof DatePicker>,
|
||||
@@ -14,8 +14,9 @@ export const LocalizedDatePicker = ({
|
||||
}: LocalizedDatePickerProps) => {
|
||||
const { i18n, t } = useTranslation()
|
||||
|
||||
const locale = languages.find((lang) => lang.code === i18n.language)
|
||||
?.date_locale
|
||||
const locale = languages.find(
|
||||
(lang) => lang.code === i18n.language
|
||||
)?.date_locale
|
||||
|
||||
const translations = {
|
||||
cancel: t("actions.cancel"),
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import i18n from "i18next"
|
||||
import LanguageDetector from "i18next-browser-languagedetector"
|
||||
import { initReactI18next } from "react-i18next"
|
||||
|
||||
import { defaultI18nOptions } from "../../../i18n/config"
|
||||
|
||||
export const I18n = () => {
|
||||
if (i18n.isInitialized) {
|
||||
return null
|
||||
}
|
||||
|
||||
i18n
|
||||
.use(
|
||||
new LanguageDetector(null, {
|
||||
lookupCookie: "lng",
|
||||
lookupLocalStorage: "lng",
|
||||
})
|
||||
)
|
||||
.use(initReactI18next)
|
||||
.init(defaultI18nOptions)
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./i18n"
|
||||
@@ -2,7 +2,7 @@ import { format, formatDistance, sub } from "date-fns"
|
||||
import { enUS } from "date-fns/locale"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import { languages } from "../i18n/config"
|
||||
import { languages } from "../i18n/languages"
|
||||
|
||||
export const useDate = () => {
|
||||
const { i18n } = useTranslation()
|
||||
|
||||
@@ -1,34 +1,19 @@
|
||||
import { enUS } from "date-fns/locale"
|
||||
import i18n from "i18next"
|
||||
import LanguageDetector from "i18next-browser-languagedetector"
|
||||
import Backend, { type HttpBackendOptions } from "i18next-http-backend"
|
||||
import { initReactI18next } from "react-i18next"
|
||||
import { InitOptions } from "i18next"
|
||||
|
||||
import { Language } from "./types"
|
||||
import translations from "./translations"
|
||||
|
||||
void i18n
|
||||
.use(Backend)
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.init<HttpBackendOptions>({
|
||||
fallbackLng: "en-US",
|
||||
load: "languageOnly",
|
||||
debug: process.env.NODE_ENV === "development",
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
backend: {
|
||||
loadPath: "/locales/{{lng}}/{{ns}}.json",
|
||||
},
|
||||
})
|
||||
|
||||
export const languages: Language[] = [
|
||||
{
|
||||
code: "en-US",
|
||||
display_name: "English (US)",
|
||||
ltr: true,
|
||||
date_locale: enUS,
|
||||
export const defaultI18nOptions: InitOptions = {
|
||||
debug: process.env.NODE_ENV === "development",
|
||||
detection: {
|
||||
caches: ["cookie", "localStorage", "header"],
|
||||
lookupCookie: "lng",
|
||||
lookupLocalStorage: "lng",
|
||||
order: ["cookie", "localStorage", "header"],
|
||||
},
|
||||
]
|
||||
|
||||
export default i18n
|
||||
fallbackLng: "en",
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
resources: translations,
|
||||
supportedLngs: Object.keys(translations),
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { enUS } from "date-fns/locale"
|
||||
import { Language } from "./types"
|
||||
|
||||
export const languages: Language[] = [
|
||||
{
|
||||
code: "en-US",
|
||||
display_name: "English (US)",
|
||||
ltr: true,
|
||||
date_locale: enUS,
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1,315 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"$schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"general": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"cancel": {
|
||||
"type": "string"
|
||||
},
|
||||
"save": {
|
||||
"type": "string"
|
||||
},
|
||||
"create": {
|
||||
"type": "string"
|
||||
},
|
||||
"delete": {
|
||||
"type": "string"
|
||||
},
|
||||
"edit": {
|
||||
"type": "string"
|
||||
},
|
||||
"extensions": {
|
||||
"type": "string"
|
||||
},
|
||||
"details": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"cancel",
|
||||
"save",
|
||||
"create",
|
||||
"createItem",
|
||||
"delete",
|
||||
"deleteItem",
|
||||
"edit",
|
||||
"editItem",
|
||||
"extensions",
|
||||
"details"
|
||||
]
|
||||
},
|
||||
"products": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
},
|
||||
"variants": {
|
||||
"type": "string"
|
||||
},
|
||||
"availableInSalesChannels": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain", "variants", "availableInSalesChannels"]
|
||||
},
|
||||
"categories": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"collections": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"inventory": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"customers": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"customerGroups": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"orders": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"draftOrders": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"discounts": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"promotions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"taxRegions": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"taxRates": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
},
|
||||
"fields": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"campaigns": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"giftCards": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"pricing": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["domain"]
|
||||
},
|
||||
"users": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"domain": {
|
||||
"type": "string"
|
||||
},
|
||||
"role": {
|
||||
"type": "string"
|
||||
},
|
||||
"roles": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"admin": {
|
||||
"type": "string"
|
||||
},
|
||||
"member": {
|
||||
"type": "string"
|
||||
},
|
||||
"developer": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["admin", "member", "developer"]
|
||||
}
|
||||
},
|
||||
"required": ["domain", "role", "roles"]
|
||||
},
|
||||
"statuses": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"scheduled": {
|
||||
"type": "string"
|
||||
},
|
||||
"expired": {
|
||||
"type": "string"
|
||||
},
|
||||
"active": {
|
||||
"type": "string"
|
||||
},
|
||||
"disabled": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fields": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"subtitle": {
|
||||
"type": "string"
|
||||
},
|
||||
"handle": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"category": {
|
||||
"type": "string"
|
||||
},
|
||||
"categories": {
|
||||
"type": "string"
|
||||
},
|
||||
"collection": {
|
||||
"type": "string"
|
||||
},
|
||||
"discountable": {
|
||||
"type": "string"
|
||||
},
|
||||
"tags": {
|
||||
"type": "string"
|
||||
},
|
||||
"sales_channels": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"title",
|
||||
"description",
|
||||
"name",
|
||||
"email",
|
||||
"password",
|
||||
"subtitle",
|
||||
"handle",
|
||||
"type",
|
||||
"category",
|
||||
"categories",
|
||||
"collection",
|
||||
"discountable",
|
||||
"tags",
|
||||
"sales_channels"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"general",
|
||||
"products",
|
||||
"categories",
|
||||
"collections",
|
||||
"inventory",
|
||||
"customers",
|
||||
"customerGroups",
|
||||
"orders",
|
||||
"draftOrders",
|
||||
"discounts",
|
||||
"giftCards",
|
||||
"pricing",
|
||||
"users",
|
||||
"fields"
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
import en from "./en.json"
|
||||
|
||||
export default {
|
||||
en: {
|
||||
translation: en,
|
||||
},
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { Locale } from "date-fns"
|
||||
import en from "../../public/locales/en-US/translation.json"
|
||||
import enUS from "./translations/en.json"
|
||||
|
||||
const resources = {
|
||||
translation: en,
|
||||
translation: enUS,
|
||||
} as const
|
||||
|
||||
export type Resources = typeof resources
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { stringify } from "qs"
|
||||
|
||||
const baseUrl =
|
||||
import.meta.env.VITE_MEDUSA_ADMIN_BACKEND_URL || "http://localhost:9000"
|
||||
const baseUrl = __BACKEND_URL__ ?? "http://localhost:9000"
|
||||
|
||||
const commonHeaders: HeadersInit = {
|
||||
Accept: "application/json",
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import Medusa from "@medusajs/medusa-js"
|
||||
import { QueryClient } from "@tanstack/react-query"
|
||||
|
||||
export const MEDUSA_BACKEND_URL =
|
||||
import.meta.env.VITE_MEDUSA_ADMIN_BACKEND_URL || "http://localhost:9000"
|
||||
export const MEDUSA_BACKEND_URL = __BACKEND_URL__ ?? "http://localhost:9000"
|
||||
|
||||
export const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import React from "react"
|
||||
import ReactDOM from "react-dom/client"
|
||||
import App from "./app.js"
|
||||
import "./i18n/config.js"
|
||||
import "./index.css"
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root")!).render(
|
||||
<React.StrictMode>
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
import { RouteObject } from "react-router-dom"
|
||||
|
||||
import routes from "medusa-admin:routes/pages"
|
||||
// import routes from "medusa-admin:routes/pages"
|
||||
|
||||
export const RouteExtensions: RouteObject[] = []
|
||||
|
||||
/**
|
||||
* UI Route extensions.
|
||||
*/
|
||||
export const RouteExtensions: RouteObject[] = routes.pages.map((ext) => {
|
||||
return {
|
||||
path: ext.path,
|
||||
async lazy() {
|
||||
const { default: Component } = await import(/* @vite-ignore */ ext.file)
|
||||
return { Component }
|
||||
},
|
||||
}
|
||||
})
|
||||
// export const RouteExtensions: RouteObject[] = routes.pages.map((ext) => {
|
||||
// return {
|
||||
// path: ext.path,
|
||||
// async lazy() {
|
||||
// const { default: Component } = await import(/* @vite-ignore */ ext.file)
|
||||
// return { Component }
|
||||
// },
|
||||
// }
|
||||
// })
|
||||
|
||||
@@ -15,9 +15,9 @@ import {
|
||||
import { Outlet, RouteObject } from "react-router-dom"
|
||||
|
||||
import { ProtectedRoute } from "../../components/authentication/protected-route"
|
||||
import { ErrorBoundary } from "../../components/error/error-boundary"
|
||||
import { MainLayout } from "../../components/layout/main-layout"
|
||||
import { SettingsLayout } from "../../components/layout/settings-layout"
|
||||
import { ErrorBoundary } from "../../components/utilities/error-boundary"
|
||||
import { InventoryItemRes, PriceListRes } from "../../types/api-responses"
|
||||
|
||||
import { RouteExtensions } from "./route-extensions"
|
||||
|
||||
@@ -5,7 +5,9 @@ import {
|
||||
|
||||
import { RouteMap } from "./route-map"
|
||||
|
||||
const router = createBrowserRouter(RouteMap)
|
||||
const router = createBrowserRouter(RouteMap, {
|
||||
basename: __BASE__ || "/",
|
||||
})
|
||||
|
||||
export const RouterProvider = () => {
|
||||
return <Provider router={router} />
|
||||
|
||||
+14
-10
@@ -1,15 +1,19 @@
|
||||
import settings from "medusa-admin:settings/pages"
|
||||
import { RouteObject } from "react-router-dom"
|
||||
|
||||
// import settings from "medusa-admin:settings/pages"
|
||||
|
||||
/**
|
||||
* UI Settings extensions.
|
||||
*/
|
||||
export const SettingsExtensions: RouteObject[] = settings.pages.map((ext) => {
|
||||
return {
|
||||
path: `/settings${ext.path}`,
|
||||
async lazy() {
|
||||
const { default: Component } = await import(/* @vite-ignore */ ext.file)
|
||||
return { Component }
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
export const SettingsExtensions: RouteObject[] = []
|
||||
|
||||
// export const SettingsExtensions: RouteObject[] = settings.pages.map((ext) => {
|
||||
// return {
|
||||
// path: `/settings${ext.path}`,
|
||||
// async lazy() {
|
||||
// const { default: Component } = await import(/* @vite-ignore */ ext.file)
|
||||
// return { Component }
|
||||
// },
|
||||
// }
|
||||
// })
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
import { Container, Heading } from "@medusajs/ui";
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
|
||||
import after from "medusa-admin:widgets/product_category/details/after";
|
||||
import before from "medusa-admin:widgets/product_category/details/before";
|
||||
// import after from "medusa-admin:widgets/product_category/details/after"
|
||||
// import before from "medusa-admin:widgets/product_category/details/before"
|
||||
|
||||
export const CategoryDetails = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => {
|
||||
{/* {before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
)
|
||||
})} */}
|
||||
|
||||
<Container>
|
||||
<Heading>Category</Heading>
|
||||
</Container>
|
||||
{after.widgets.map((w, i) => {
|
||||
|
||||
{/* {after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
)
|
||||
})} */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
import { Container, Heading } from "@medusajs/ui";
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
|
||||
import after from "medusa-admin:widgets/product_category/list/after";
|
||||
import before from "medusa-admin:widgets/product_category/list/before";
|
||||
// import after from "medusa-admin:widgets/product_category/list/after"
|
||||
// import before from "medusa-admin:widgets/product_category/list/before"
|
||||
|
||||
export const CategoriesList = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => {
|
||||
{/* {before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
)
|
||||
})} */}
|
||||
|
||||
<Container>
|
||||
<Heading>Categories</Heading>
|
||||
</Container>
|
||||
{after.widgets.map((w, i) => {
|
||||
|
||||
{/* {after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
)
|
||||
})} */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
)
|
||||
}
|
||||
|
||||
+9
-6
@@ -10,8 +10,8 @@ import { DiscountConditionsSection } from "./components/discount-conditions-sect
|
||||
import { RedemptionsSection } from "./components/discount-redemptions-section"
|
||||
import { discountLoader, expand } from "./loader"
|
||||
|
||||
import after from "medusa-admin:widgets/discount/details/after"
|
||||
import before from "medusa-admin:widgets/discount/details/before"
|
||||
// import after from "medusa-admin:widgets/discount/details/after"
|
||||
// import before from "medusa-admin:widgets/discount/details/before"
|
||||
|
||||
export const DiscountDetail = () => {
|
||||
const initialData = useLoaderData() as Awaited<
|
||||
@@ -33,13 +33,14 @@ export const DiscountDetail = () => {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => {
|
||||
{/* {before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
})} */}
|
||||
|
||||
<div className="flex flex-col gap-x-4 xl:flex-row xl:items-start">
|
||||
<div className="flex w-full flex-col gap-y-2">
|
||||
<DiscountGeneralSection discount={discount} />
|
||||
@@ -49,13 +50,15 @@ export const DiscountDetail = () => {
|
||||
<RedemptionsSection redemptions={discount.usage_count} />
|
||||
<DetailsSection discount={discount} />
|
||||
</div>
|
||||
{after.widgets.map((w, i) => {
|
||||
|
||||
{/* {after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
})} */}
|
||||
|
||||
<JsonViewSection data={discount} />
|
||||
</div>
|
||||
<div className="hidden w-full max-w-[400px] flex-col gap-y-2 xl:flex">
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import after from "medusa-admin:widgets/discount/list/after"
|
||||
import before from "medusa-admin:widgets/discount/list/before"
|
||||
// import after from "medusa-admin:widgets/discount/list/after"
|
||||
// import before from "medusa-admin:widgets/discount/list/before"
|
||||
|
||||
import { DiscountListTable } from "./components/discount-list-table"
|
||||
|
||||
export const DiscountsList = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => (
|
||||
{/* {before.widgets.map((w, i) => (
|
||||
<w.Component key={i} />
|
||||
))}
|
||||
))} */}
|
||||
|
||||
<DiscountListTable />
|
||||
{after.widgets.map((w, i) => (
|
||||
|
||||
{/* {after.widgets.map((w, i) => (
|
||||
<w.Component key={i} />
|
||||
))}
|
||||
))} */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
+16
-15
@@ -9,12 +9,13 @@ import { ProductSalesChannelSection } from "./components/product-sales-channel-s
|
||||
import { ProductVariantSection } from "./components/product-variant-section"
|
||||
import { productLoader } from "./loader"
|
||||
|
||||
import after from "medusa-admin:widgets/product/details/after"
|
||||
import before from "medusa-admin:widgets/product/details/before"
|
||||
import sideAfter from "medusa-admin:widgets/product/details/side/after"
|
||||
import sideBefore from "medusa-admin:widgets/product/details/side/before"
|
||||
import { ProductOrganizationSection } from "./components/product-organization-section"
|
||||
// import after from "medusa-admin:widgets/product/details/after"
|
||||
// import before from "medusa-admin:widgets/product/details/before"
|
||||
// import sideAfter from "medusa-admin:widgets/product/details/side/after"
|
||||
// import sideBefore from "medusa-admin:widgets/product/details/side/before"
|
||||
|
||||
import { useProduct } from "../../../hooks/api/products"
|
||||
import { ProductOrganizationSection } from "./components/product-organization-section"
|
||||
|
||||
// TODO: Use product domain translations only
|
||||
export const ProductDetail = () => {
|
||||
@@ -37,50 +38,50 @@ export const ProductDetail = () => {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => {
|
||||
{/* {before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
})} */}
|
||||
|
||||
<div className="flex flex-col gap-x-4 lg:flex-row lg:items-start">
|
||||
<div className="w-full flex flex-col gap-y-2">
|
||||
<div className="flex w-full flex-col gap-y-2">
|
||||
<ProductGeneralSection product={product} />
|
||||
<ProductMediaSection product={product} />
|
||||
<ProductOptionSection product={product} />
|
||||
<ProductVariantSection product={product} />
|
||||
{after.widgets.map((w, i) => {
|
||||
{/* {after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
})} */}
|
||||
|
||||
<div className="hidden lg:block">
|
||||
<JsonViewSection data={product} root="product" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full lg:max-w-[400px] max-w-[100%] mt-2 lg:mt-0 flex flex-col gap-y-2">
|
||||
{sideBefore.widgets.map((w, i) => {
|
||||
<div className="mt-2 flex w-full max-w-[100%] flex-col gap-y-2 lg:mt-0 lg:max-w-[400px]">
|
||||
{/* {sideBefore.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
})} */}
|
||||
<ProductSalesChannelSection product={product} />
|
||||
<ProductOrganizationSection product={product} />
|
||||
<ProductAttributeSection product={product} />
|
||||
{sideAfter.widgets.map((w, i) => {
|
||||
{/* {sideAfter.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
})} */}
|
||||
|
||||
<div className="lg:hidden">
|
||||
<JsonViewSection data={product} root="product" />
|
||||
|
||||
@@ -1,18 +1,9 @@
|
||||
import after from "medusa-admin:widgets/product/list/after"
|
||||
import before from "medusa-admin:widgets/product/list/before"
|
||||
|
||||
import { ProductListTable } from "./components/product-list-table"
|
||||
|
||||
export const ProductList = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => (
|
||||
<w.Component key={i} />
|
||||
))}
|
||||
<ProductListTable />
|
||||
{after.widgets.map((w, i) => (
|
||||
<w.Component key={i} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
+7
-5
@@ -9,15 +9,15 @@ import { useTranslation } from "react-i18next"
|
||||
import { z } from "zod"
|
||||
|
||||
import { Link } from "react-router-dom"
|
||||
import {
|
||||
FileType,
|
||||
FileUpload,
|
||||
} from "../../../../../components/common/file-upload"
|
||||
import { Form } from "../../../../../components/common/form"
|
||||
import {
|
||||
RouteFocusModal,
|
||||
useRouteModal,
|
||||
} from "../../../../../components/route-modal"
|
||||
import {
|
||||
FileType,
|
||||
FileUpload,
|
||||
} from "../../../../../components/common/file-upload"
|
||||
import { useUpdateProduct } from "../../../../../hooks/api/products"
|
||||
|
||||
type ProductMediaViewProps = {
|
||||
@@ -400,8 +400,10 @@ const getDefaultValues = (images: Image[] | null, thumbnail: string | null) => {
|
||||
})) || []
|
||||
|
||||
if (thumbnail && !media.some((mediaItem) => mediaItem.url === thumbnail)) {
|
||||
const id = Math.random().toString(36).substring(7)
|
||||
|
||||
media.unshift({
|
||||
id: crypto.randomUUID(),
|
||||
id: id,
|
||||
url: thumbnail,
|
||||
isThumbnail: true,
|
||||
file: null,
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { UserDTO } from "@medusajs/types"
|
||||
import { Button, Container, Heading, StatusBadge, Text } from "@medusajs/ui"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { Link } from "react-router-dom"
|
||||
import { languages } from "../../../../../i18n/config"
|
||||
import { languages } from "../../../../../i18n/languages"
|
||||
|
||||
type ProfileGeneralSectionProps = {
|
||||
user: UserDTO
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import {
|
||||
useRouteModal,
|
||||
} from "../../../../../components/route-modal"
|
||||
import { useUpdateUser } from "../../../../../hooks/api/users"
|
||||
import { languages } from "../../../../../i18n/config"
|
||||
import { languages } from "../../../../../i18n/languages"
|
||||
|
||||
type EditProfileProps = {
|
||||
user: Partial<Omit<UserDTO, "password_hash">>
|
||||
|
||||
-19
@@ -7,9 +7,6 @@ import { PromotionConditionsSection } from "./components/promotion-conditions-se
|
||||
import { PromotionGeneralSection } from "./components/promotion-general-section"
|
||||
import { promotionLoader } from "./loader"
|
||||
|
||||
import after from "medusa-admin:widgets/promotion/details/after"
|
||||
import before from "medusa-admin:widgets/promotion/details/before"
|
||||
|
||||
export const PromotionDetail = () => {
|
||||
const initialData = useLoaderData() as Awaited<
|
||||
ReturnType<typeof promotionLoader>
|
||||
@@ -27,14 +24,6 @@ export const PromotionDetail = () => {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
|
||||
<div className="flex flex-col gap-x-4 xl:flex-row xl:items-start">
|
||||
<div className="flex w-full flex-col gap-y-2">
|
||||
<PromotionGeneralSection promotion={promotion} />
|
||||
@@ -57,14 +46,6 @@ export const PromotionDetail = () => {
|
||||
<CampaignSection campaign={promotion.campaign!} />
|
||||
</div>
|
||||
|
||||
{after.widgets.map((w, i) => {
|
||||
return (
|
||||
<div key={i}>
|
||||
<w.Component />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
|
||||
<JsonViewSection data={promotion as any} />
|
||||
</div>
|
||||
|
||||
|
||||
-11
@@ -1,20 +1,9 @@
|
||||
import after from "medusa-admin:widgets/promotion/list/after"
|
||||
import before from "medusa-admin:widgets/promotion/list/before"
|
||||
|
||||
import { PromotionListTable } from "./components/promotion-list-table"
|
||||
|
||||
export const PromotionsList = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-y-2">
|
||||
{before.widgets.map((w, i) => (
|
||||
<w.Component key={i} />
|
||||
))}
|
||||
|
||||
<PromotionListTable />
|
||||
|
||||
{after.widgets.map((w, i) => (
|
||||
<w.Component key={i} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,3 +8,6 @@ interface ImportMetaEnv {
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv
|
||||
}
|
||||
|
||||
declare const __BACKEND_URL__: string | undefined
|
||||
declare const __BASE__: string
|
||||
|
||||
Reference in New Issue
Block a user