UNPKG

@gorgo/medusa-feed-yandex

Version:

A Medusa plugin that generates a product feed in YML (Yandex Market Language) format

1,276 lines 54.3 kB
"use strict"; const jsxRuntime = require("react/jsx-runtime"); const adminSdk = require("@medusajs/admin-sdk"); const icons = require("@medusajs/icons"); const ui = require("@medusajs/ui"); const reactQuery = require("@tanstack/react-query"); const React = require("react"); const reactRouterDom = require("react-router-dom"); const i18n = require("i18next"); const LanguageDetector = require("i18next-browser-languagedetector"); const reactI18next = require("react-i18next"); const Medusa = require("@medusajs/js-sdk"); const dateFns = require("date-fns"); const locale = require("date-fns/locale"); const _interopDefault = (e) => e && e.__esModule ? e : { default: e }; const React__default = /* @__PURE__ */ _interopDefault(React); const i18n__default = /* @__PURE__ */ _interopDefault(i18n); const LanguageDetector__default = /* @__PURE__ */ _interopDefault(LanguageDetector); const Medusa__default = /* @__PURE__ */ _interopDefault(Medusa); const SingleColumnLayout = ({ children }) => { return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-y-3", children }); }; const TwoColumnLayout = ({ firstCol, secondCol }) => { return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 xl:flex-row xl:gap-x-4 xl:items-start", children: [ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col w-full gap-y-3", children: firstCol }), /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col w-full xl:max-w-[440px] gap-y-3 xl:mt-0", children: secondCol }) ] }); }; const $schema$1 = "./$schema.json"; const general$1 = { active: "Active", inactive: "Inactive", error: "Error", success: "Success", of: "of", results: "results", pages: "pages", next: "Next", prev: "Previous" }; const actions$1 = { create: "Create", edit: "Edit", "delete": "Delete", deleteFile: "Delete file", save: "Save", cancel: "Cancel", launchNow: "Launch now" }; const dateTime$1 = { days: "d", hours: "h", minutes: "min" }; const feeds$1 = { domain: "Feeds", subtitle: "Create feeds for scheduled data exports", create: { title: "Create feed", description: "Create and manage feed settings." }, fields: { title: "Title", fileName: "File name", filePath: "File path", lastExport: "Last export", status: "Status", schedule: "Export interval", id: "ID", feedUrl: "Feed link", created: "Created", updated: "Updated" }, edit: { title: "Edit feed", description: "Update feed configuration." }, toasts: { exportLaunched: "Feed successfully launched", categoriesSaved: "Categories saved successfully", categoriesSaveFailed: "Failed to save categories" }, prompts: { deleteFeed: { title: "Are you sure?", description: "You are about to delete the feed. This action cannot be undone." }, deleteFeedFile: { title: "Are you sure?", description: "You are about to delete the feed file. This action cannot be undone." } }, tooltips: { schedule: "Set the feed export interval" }, activityContainer: { title: "Activity", subtitle: "If unchecked, the feed will not be exported on schedule." } }; const settings$1 = { shop: { title: "Shop", subtitle: "Shop data for the feed file", fields: { name: "Shop name", company: "Company", url: "Shop URL", platform: "Platform" }, edit: { title: "Edit shop", description: "Update shop data" } }, categories: { title: "Product categories", subtitle: "Select product categories for export" } }; const en = { $schema: $schema$1, general: general$1, actions: actions$1, dateTime: dateTime$1, feeds: feeds$1, settings: settings$1 }; const $schema = "./$schema.json"; const general = { active: "Активен", inactive: "Неактивен", error: "Ошибка", success: "Успешно", of: "из", results: "результатов", pages: "страниц", next: "Далее", prev: "Назад" }; const actions = { create: "Создать", edit: "Редактировать", "delete": "Удалить", deleteFile: "Удалить файл", save: "Сохранить", cancel: "Отмена", launchNow: "Запустить сейчас" }; const dateTime = { days: "д", hours: "ч", minutes: "мин" }; const feeds = { domain: "Фиды", subtitle: "Создавайте фиды для выгрузки данных по расписанию", create: { title: "Создать фид", description: "Создавайте и управляйте настройками фида." }, fields: { title: "Название", fileName: "Имя файла", filePath: "Путь к файлу", lastExport: "Последний экспорт", status: "Статус", schedule: "Интервал экспорта", id: "ID", feedUrl: "Ссылка на фид", created: "Создано", updated: "Обновлено" }, edit: { title: "Редактировать фид", description: "Обновить конфигурацию фида." }, toasts: { exportLaunched: "Фид успешно запущен", categoriesSaved: "Категории успешно сохранены", categoriesSaveFailed: "Не получучилось сохранить категории" }, prompts: { deleteFeed: { title: "Вы уверены?", description: "Вы собираетесь удалить фид. Это действие нельзя отменить." }, deleteFeedFile: { title: "Вы уверены?", description: "Вы собираетесь удалить файл фида. Это действие нельзя отменить." } }, tooltips: { schedule: "Установите интервал для экспорта фида" }, activityContainer: { title: "Активность", subtitle: "Если флаг снят, фид не будет экспортироваться по расписанию." } }; const settings = { shop: { title: "Магазин", subtitle: "Данные магазина для файла фида", fields: { name: "Название магазина", company: "Компания", url: "URL магазина", platform: "Платформа" }, edit: { title: "Редактировать магазин", description: "Обновить данные магазина" } }, categories: { title: "Категории товаров", subtitle: "Выберите категории товаров для экспорта" } }; const ru = { $schema, general, actions, dateTime, feeds, settings }; const i18nTranslations0 = { en: { translation: en }, ru: { translation: ru } }; const defaultI18nOptions = { debug: process.env.NODE_ENV === "development", fallbackLng: "en", interpolation: { escapeValue: false }, detection: { caches: ["cookie", "localStorage", "header"], lookupCookie: "lng", lookupLocalStorage: "lng", order: ["cookie", "localStorage", "header"] }, resources: i18nTranslations0, supportedLngs: Object.keys(i18nTranslations0) }; const i18nInstance = i18n__default.default.createInstance(); if (!i18n__default.default.isInitialized) { i18nInstance.use( new LanguageDetector__default.default(null, { lookupCookie: "lng", lookupLocalStorage: "lng" }) ).use(reactI18next.initReactI18next).init(defaultI18nOptions); } const I18n = () => null; const sdk = new Medusa__default.default({ baseUrl: __BACKEND_URL__ || "/", auth: { type: "session" } }); const ActionMenu = ({ groups }) => { return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", variant: "transparent", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisHorizontal, {}) }) }), /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Content, { children: groups.map((group, groupIdx) => { if (!group.actions.length) return null; const commonItemClasses = "[&_svg]:text-ui-fg-subtle flex items-center gap-x-2"; const isLastGroup = groupIdx === groups.length - 1; return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Group, { children: [ group.actions.map((action, actionIdx) => { const itemClasses = ui.clx(commonItemClasses, { "[&_svg]:text-ui-fg-disabled": action.disabled }); if (action.onClick) { return /* @__PURE__ */ jsxRuntime.jsxs( ui.DropdownMenu.Item, { disabled: action.disabled, onClick: (e) => { e.stopPropagation(); action.onClick(); }, className: itemClasses, children: [ action.icon, /* @__PURE__ */ jsxRuntime.jsx("span", { children: action.label }) ] }, actionIdx ); } return /* @__PURE__ */ jsxRuntime.jsx( ui.DropdownMenu.Item, { asChild: true, disabled: action.disabled, className: itemClasses, children: /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Link, { to: action.to, onClick: (e) => e.stopPropagation(), children: [ action.icon, /* @__PURE__ */ jsxRuntime.jsx("span", { children: action.label }) ] }) }, actionIdx ); }), !isLastGroup && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}) ] }, groupIdx); }) }) ] }); }; const Header = ({ title, subtitle, status, actions: actions2 = [] }) => { return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: title }), subtitle && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", size: "small", children: subtitle }) ] }), (status || actions2.length > 0) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-x-2", children: [ status && /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: status.color, children: status.text }), actions2.map((action, idx) => { switch (action.type) { case "button": return action.link ? /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { ...action.link, children: /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { ...action.props, size: action.props.size || "small" } ) }, idx) : /* @__PURE__ */ jsxRuntime.jsx( ui.Button, { ...action.props, size: action.props.size || "small" }, idx ); case "action-menu": return /* @__PURE__ */ jsxRuntime.jsx(ActionMenu, { ...action.props }, idx); case "custom": return /* @__PURE__ */ jsxRuntime.jsx(React__default.default.Fragment, { children: action.children }, idx); default: return null; } }) ] }) ] }); }; const PlaceholderCell = () => { return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full w-full items-center", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-muted", children: "-" }) }); }; const languages = [ { code: "en", date_locale: locale.enUS }, { code: "ru", date_locale: locale.ru } ]; const useDate = () => { var _a; const { i18n: i18n2 } = reactI18next.useTranslation(); const locale$1 = ((_a = languages.find((l) => l.code === i18n2.language)) == null ? void 0 : _a.date_locale) || locale.enUS; const getFullDate = ({ date, includeTime = false }) => { const ensuredDate = new Date(date); if (isNaN(ensuredDate.getTime())) { return ""; } const timeFormat = includeTime ? "p" : ""; return dateFns.format(ensuredDate, `PP ${timeFormat}`, { locale: locale$1 }); }; function getRelativeDate(date) { const now = /* @__PURE__ */ new Date(); return dateFns.formatDistance(dateFns.sub(new Date(date), { minutes: 0 }), now, { addSuffix: true, locale: locale$1 }); } return { getFullDate, getRelativeDate }; }; const DateCell = ({ date, mode = "full" }) => { const { getFullDate, getRelativeDate } = useDate(); if (!date) { return /* @__PURE__ */ jsxRuntime.jsx(PlaceholderCell, {}); } let displayDate; switch (mode) { case "full": displayDate = getFullDate({ date, includeTime: false }); break; case "relative": displayDate = getRelativeDate(date); break; } return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full w-full items-center overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx( ui.Tooltip, { className: "z-10", content: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-pretty", children: `${getFullDate({ date, includeTime: true })}` }), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: displayDate }) } ) }); }; const scheduleIntervals = [ 10, 30, 60, 120, 180, 360, 720, 1440 ]; const fileExtension = ".xml"; const getScheduleLabel = (minutes) => { if (minutes === void 0 || minutes < 0) { return "-"; } const hours = Math.floor(minutes / 60); switch (true) { case hours == 0: return `${minutes} ${i18nInstance.t("dateTime.minutes")}`; case (hours >= 1 && hours < 24): return `${hours} ${i18nInstance.t("dateTime.hours")}`; case hours >= 24: return `${Math.floor(hours / 24)} ${i18nInstance.t("dateTime.days")}`; } }; const PAGE_SIZE = 20; const FeedListTable = ({ stateModal, openModal }) => { const columnHelper = ui.createDataTableColumnHelper(); const navigate = reactRouterDom.useNavigate(); const limit = PAGE_SIZE; const [pagination, setPagination] = React.useState({ pageSize: limit, pageIndex: 0 }); const offset = React.useMemo(() => pagination.pageIndex * limit, [pagination]); const { data, isLoading } = reactQuery.useQuery({ queryFn: () => sdk.client.fetch(`/admin/feeds`, { query: { limit, offset } }), queryKey: [["feeds"]] }); const columns = [ columnHelper.accessor("title", { header: i18nInstance.t("feeds.fields.title") }), columnHelper.accessor("file_name", { header: i18nInstance.t("feeds.fields.fileName"), cell: ({ row }) => { return row.original.file_name + fileExtension; } }), columnHelper.accessor("file_path", { header: i18nInstance.t("feeds.fields.feedUrl"), cell: ({ row }) => { const filePath = row.original.file_path; const id = row.original.id; const fileName = row.original.file_name; if (!filePath || !id || !fileName) { return /* @__PURE__ */ jsxRuntime.jsx(PlaceholderCell, {}); } try { const fullLink = `${window.location.origin}/feeds/${id}/${fileName}${fileExtension}`; return /* @__PURE__ */ jsxRuntime.jsx("a", { href: fullLink, target: "_blank", rel: "noopener noreferrer", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-interactive", children: fullLink }) }) }); } catch { return /* @__PURE__ */ jsxRuntime.jsx(PlaceholderCell, {}); } } }), columnHelper.accessor("last_export_at", { header: i18nInstance.t("feeds.fields.lastExport"), cell: ({ getValue }) => { const rawDate = getValue(); return /* @__PURE__ */ jsxRuntime.jsx(DateCell, { date: rawDate, mode: "relative" }); } }), columnHelper.accessor("is_active", { header: i18nInstance.t("feeds.fields.status"), cell: ({ getValue }) => { const isActive = getValue(); if (isActive) { return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [ /* @__PURE__ */ jsxRuntime.jsx(icons.SquareGreenSolid, {}), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "whitespace-pre-line text-pretty", children: i18nInstance.t("general.active") }) ] }); } else { return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [ /* @__PURE__ */ jsxRuntime.jsx(icons.SquareRedSolid, {}), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "whitespace-pre-line text-pretty", children: i18nInstance.t("general.inactive") }) ] }); } } }), columnHelper.accessor("schedule", { header: i18nInstance.t("feeds.fields.schedule"), cell: ({ getValue }) => { const value = getValue(); return /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", leading: "compact", children: getScheduleLabel(value) }) }); } }) ]; const table = ui.useDataTable({ columns, data: (data == null ? void 0 : data.feeds) || [], getRowId: (row) => row.id, rowCount: (data == null ? void 0 : data.count) || 0, isLoading, pagination: { state: pagination, onPaginationChange: setPagination }, onRowClick(_, row) { navigate(`${row.id}`); } }); return /* @__PURE__ */ jsxRuntime.jsxs(ui.DataTable, { instance: table, children: [ /* @__PURE__ */ jsxRuntime.jsx( Header, { title: i18nInstance.t("feeds.domain"), actions: [ { type: "button", props: { children: i18nInstance.t("actions.create"), variant: "secondary", onClick: () => openModal() } } ] }, stateModal ? "create-open" : "create-closed" ), /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Table, {}), /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Pagination, {}) ] }); }; const FeedCreateModal = ({ stateModal, closeModal }) => { const [title, setTitle] = React.useState(""); const [fileName, setFileName] = React.useState(""); const [schedule, setSchedule] = React.useState(scheduleIntervals[1]); const [isActive, setIsActive] = React.useState(false); const queryClient = reactQuery.useQueryClient(); const { mutate } = reactQuery.useMutation({ mutationFn: async (newFeed) => { return sdk.client.fetch(`/admin/feeds`, { method: "POST", body: newFeed, headers: { "Content-Type": "application/json" } }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: [["feeds"]] }); setTitle(""); setFileName(""); setSchedule(scheduleIntervals[1]); setIsActive(false); }, onError: (error) => { console.error("Error creating feed:", error); } }); const saveFeed = () => { const newFeed = [{ title, file_name: fileName, is_active: isActive, schedule: Number(schedule) }]; mutate({ feeds: newFeed }); closeModal(); }; return /* @__PURE__ */ jsxRuntime.jsx(ui.FocusModal, { open: stateModal, onOpenChange: (open) => { if (!open) closeModal(); }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.FocusModal.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.FocusModal.Header, {}), /* @__PURE__ */ jsxRuntime.jsx(ui.FocusModal.Body, { className: "flex flex-col items-center py-16", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full max-w-lg flex-col gap-y-8", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: i18nInstance.t("feeds.create.title") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "text-ui-fg-subtle", children: i18nInstance.t("feeds.create.description") }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "title", size: "small", children: i18nInstance.t("feeds.fields.title") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { id: "title", value: title, onChange: (e) => setTitle(e.target.value) }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "file_name", size: "small", children: i18nInstance.t("feeds.fields.fileName") }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { id: "file_name", value: fileName, onChange: (e) => setFileName(e.target.value) }), /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 z-10 flex w-12 items-center justify-center border-l", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium font-sans txt-compact-small text-ui-fg-muted", children: fileExtension }) }) ] }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "schedule_selector", size: "small", children: i18nInstance.t("feeds.fields.schedule") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Tooltip, { content: i18nInstance.t("feeds.tooltips.schedule"), children: /* @__PURE__ */ jsxRuntime.jsx(icons.InformationCircleSolid, { className: "text-ui-fg-subtle" }) }) ] }), /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { onValueChange: (v) => setSchedule(Number(v)), value: String(schedule), children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, {}) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { sideOffset: 100, children: scheduleIntervals.map((value) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: String(value), children: getScheduleLabel(value) }, value)) }) ] }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "is-active-switch", size: "small", children: i18nInstance.t("feeds.activityContainer.title") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-4", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Switch, { id: "is-active-switch", checked: isActive, onCheckedChange: () => setIsActive((prev) => !prev) }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", htmlFor: "is-active-switch", children: i18nInstance.t("general.active") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: i18nInstance.t("feeds.activityContainer.subtitle") }) ] }) ] }) }) ] }) ] }) }), /* @__PURE__ */ jsxRuntime.jsxs(ui.FocusModal.Footer, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.FocusModal.Close, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { variant: "secondary", children: i18nInstance.t("actions.cancel") }) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { onClick: saveFeed, children: i18nInstance.t("actions.save") }) ] }) ] }) }); }; const FeedsPage = () => { const [stateModal, openModal, closeModal] = ui.useToggleState(); return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [ /* @__PURE__ */ jsxRuntime.jsx(I18n, {}), /* @__PURE__ */ jsxRuntime.jsx(SingleColumnLayout, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "p-0", children: [ /* @__PURE__ */ jsxRuntime.jsx(FeedListTable, { stateModal, openModal }), /* @__PURE__ */ jsxRuntime.jsx(FeedCreateModal, { stateModal, closeModal }) ] }) }) ] }); }; const config = adminSdk.defineRouteConfig({ label: i18nInstance.t("feeds.domain"), icon: icons.Rss }); const handle$1 = { breadcrumb: () => i18nInstance.t("feeds.domain") }; const SectionRow = ({ title, value, actions: actions2, className }) => { const isSimpleText = typeof value === "string" || value === null || value === void 0; const hasActions = Boolean(actions2); const containerClasses = ui.clx( "text-ui-fg-subtle grid items-center px-6 py-4", hasActions ? "grid-cols-[1fr_1fr_28px]" : "grid-cols-2" ); const textClasses = ui.clx( className, isSimpleText ? "whitespace-pre-line text-pretty" : "flex flex-wrap gap-1" ); return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: containerClasses, children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: title }), isSimpleText ? /* @__PURE__ */ jsxRuntime.jsx( ui.Text, { size: "small", leading: "compact", className: textClasses, children: value ?? "-" } ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: textClasses, children: value }), hasActions && /* @__PURE__ */ jsxRuntime.jsx("div", { children: actions2 }) ] }); }; const FeedGeneralSection = () => { const { id } = reactRouterDom.useParams(); const navigate = reactRouterDom.useNavigate(); const [deleteFeedOpen, openDeleteFeed, closeDeleteFeed] = ui.useToggleState(); const [deleteFeedFileOpen, openDeleteFeedFile, closeDeleteFeedFile] = ui.useToggleState(); const [editOpen, openEdit, closeEdit] = ui.useToggleState(); const [title, setTitle] = React.useState(""); const [fileName, setFileName] = React.useState(""); const [schedule, setSchedule] = React.useState(); const [isActive, setIsActive] = React.useState(true); const { getFullDate, getRelativeDate } = useDate(); const { data, isError, error } = reactQuery.useQuery({ queryFn: () => sdk.client.fetch(`/admin/feeds/${id}`), queryKey: ["feed", id] }); if (isError) { throw error; } React.useEffect(() => { if (data == null ? void 0 : data.feed) { setTitle(data.feed.title); setFileName(data.feed.file_name); setIsActive(data.feed.is_active); setSchedule(String(data.feed.schedule)); } }, [data]); const feed = data == null ? void 0 : data.feed; const queryClient = reactQuery.useQueryClient(); const { mutate: updateFeedMutate } = reactQuery.useMutation({ mutationFn: async (updatedFeed) => { return sdk.client.fetch(`/admin/feeds/${updatedFeed.id}`, { method: "PATCH", body: updatedFeed, headers: { "Content-Type": "application/json" } }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["feed", id] }); queryClient.invalidateQueries({ queryKey: [["feeds"]] }); }, onError: (error2) => { console.error("Error updating feed:", error2); } }); const { mutate: deleteFeedMutate } = reactQuery.useMutation({ mutationFn: async (feedId) => { return sdk.client.fetch(`/admin/feeds/${feedId.ids[0]}`, { method: "DELETE", body: feedId, headers: { "Content-Type": "application/json" } }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["feed", id] }); queryClient.invalidateQueries({ queryKey: [["feeds"]] }); }, onError: (error2) => { console.error("Error deleting feed:", error2); } }); const { mutate: deleteFeedFileMutate } = reactQuery.useMutation({ mutationFn: async (feedId) => { return sdk.client.fetch(`/admin/feeds/${feedId}/delete-file`, { method: "DELETE", headers: { "Content-Type": "application/json" } }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["feed", id] }); queryClient.invalidateQueries({ queryKey: [["feeds"]] }); }, onError: (error2) => { console.error("Error deleting file:", error2); } }); const { mutate: launchFeedMutate } = reactQuery.useMutation({ mutationFn: async (feedId) => { return sdk.client.fetch(`/admin/feeds/${feedId}/launch`, { method: "POST", headers: { "Content-Type": "application/json" } }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["feed", id] }); queryClient.invalidateQueries({ queryKey: [["feeds"]] }); ui.toast.success(i18nInstance.t("general.success"), { description: i18nInstance.t("feeds.toasts.exportLaunched") }); }, onError: (error2) => { console.error("Error launching feed:", error2); } }); const saveFeedSettings = () => { const updatedFeed = { id, title, file_name: fileName, is_active: isActive, schedule: Number(schedule) }; updateFeedMutate(updatedFeed); closeEdit(); }; const deleteFeed = () => { const deletedFeed = { ids: [id] }; deleteFeedMutate(deletedFeed); navigate(`../`); }; const deleteFeedFile = () => { deleteFeedFileMutate(id); closeDeleteFeedFile(); }; const launchFeed = async () => { await launchFeedMutate(id); }; return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [ /* @__PURE__ */ jsxRuntime.jsx( Header, { title: feed == null ? void 0 : feed.title, status: { color: (feed == null ? void 0 : feed.is_active) ? "green" : "red", text: (feed == null ? void 0 : feed.is_active) ? i18nInstance.t("general.active") : i18nInstance.t("general.inactive") }, actions: [ { type: "button", props: { children: i18nInstance.t("actions.launchNow"), variant: "secondary", onClick: () => { launchFeed(); } } }, { type: "action-menu", props: { groups: [ { actions: [ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {}), label: i18nInstance.t("actions.edit"), onClick: () => openEdit() }, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Folder, {}), label: i18nInstance.t("actions.deleteFile"), onClick: () => openDeleteFeedFile() }, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}), label: i18nInstance.t("actions.delete"), onClick: () => openDeleteFeed() } ] } ] } } ] }, `${editOpen ? "edit-open" : "edit-closed"}-${deleteFeedOpen ? "delete-feed-open" : "delete-feed-closed"}-${deleteFeedFileOpen ? "delete-feed-file-open" : "delete-feed-file-closed"}` ), /* @__PURE__ */ jsxRuntime.jsx( SectionRow, { title: i18nInstance.t("feeds.fields.id"), value: (feed == null ? void 0 : feed.id) || "-" } ), /* @__PURE__ */ jsxRuntime.jsx( SectionRow, { title: i18nInstance.t("feeds.fields.fileName"), value: (feed == null ? void 0 : feed.file_name) + fileExtension || "-", className: "break-all" } ), /* @__PURE__ */ jsxRuntime.jsx( SectionRow, { title: i18nInstance.t("feeds.fields.feedUrl"), value: (feed == null ? void 0 : feed.file_path) && (feed == null ? void 0 : feed.id) && (feed == null ? void 0 : feed.file_name) ? (() => { const feedViewUrl = `${window.location.origin}/feeds/${feed.id}/${feed.file_name}${fileExtension}`; return /* @__PURE__ */ jsxRuntime.jsx("a", { href: feedViewUrl, target: "_blank", rel: "noopener noreferrer", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "base", className: "h-full", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-interactive break-all", children: feedViewUrl }) }) }); })() : "" } ), /* @__PURE__ */ jsxRuntime.jsx( SectionRow, { title: i18nInstance.t("feeds.fields.filePath"), value: (feed == null ? void 0 : feed.file_path) ? /* @__PURE__ */ jsxRuntime.jsx("a", { href: feed.file_path, target: "_blank", rel: "noopener noreferrer", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "base", className: "h-full", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-interactive break-all", children: feed.file_path }) }) }) : "" } ), /* @__PURE__ */ jsxRuntime.jsx( SectionRow, { title: i18nInstance.t("feeds.fields.schedule"), value: (feed == null ? void 0 : feed.schedule) ? (() => { const interval = scheduleIntervals.find( (value) => value === feed.schedule ); return /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", children: getScheduleLabel(interval || feed.schedule) }) }); })() : "" } ), /* @__PURE__ */ jsxRuntime.jsx( SectionRow, { title: i18nInstance.t("feeds.fields.lastExport"), value: (feed == null ? void 0 : feed.last_export_at) ? /* @__PURE__ */ jsxRuntime.jsx( ui.Tooltip, { className: "z-10", content: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-pretty", children: `${getFullDate({ date: feed.last_export_at, includeTime: true })}` }), children: /* @__PURE__ */ jsxRuntime.jsx( ui.Text, { size: "small", leading: "compact", className: "whitespace-pre-line text-pretty", children: getRelativeDate(feed.last_export_at) } ) } ) : "" } ), /* @__PURE__ */ jsxRuntime.jsx( SectionRow, { title: i18nInstance.t("feeds.fields.created"), value: (feed == null ? void 0 : feed.created_at) ? getFullDate({ date: feed.created_at, includeTime: true }) : "" } ), /* @__PURE__ */ jsxRuntime.jsx( SectionRow, { title: i18nInstance.t("feeds.fields.updated"), value: (feed == null ? void 0 : feed.updated_at) ? getFullDate({ date: feed.updated_at, includeTime: true }) : "" } ), /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: editOpen, onOpenChange: (open) => { if (!open) closeEdit(); }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: i18nInstance.t("feeds.edit.title") }) }) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-4", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Switch, { id: "is-active-switch", checked: isActive, onCheckedChange: () => setIsActive((prev) => !prev) }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", htmlFor: "is-active-switch", children: i18nInstance.t("general.active") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: i18nInstance.t("feeds.activityContainer.subtitle") }) ] }) ] }) }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { htmlFor: "title", size: "small", children: i18nInstance.t("feeds.fields.title") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { id: "title", value: title, onChange: (e) => setTitle(e.target.value) }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", htmlFor: "feed-file-name-input", children: i18nInstance.t("feeds.fields.fileName") }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { className: "pr-14", id: "feed-file-name-input", value: fileName, onChange: (e) => setFileName(e.target.value) }), /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 z-10 flex w-12 items-center justify-center border-l", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium font-sans txt-compact-small text-ui-fg-muted", children: fileExtension }) }) ] }) ] }), /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "small", htmlFor: "schedule-selector", children: i18nInstance.t("feeds.fields.schedule") }), /* @__PURE__ */ jsxRuntime.jsxs(ui.Select, { value: schedule, onValueChange: setSchedule, children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, {}) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { sideOffset: 100, children: scheduleIntervals.map((value) => /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: String(value), children: getScheduleLabel(value) }, value)) }) ] }) ] }) ] }) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-x-2", children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: i18nInstance.t("actions.cancel") }) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", type: "submit", onClick: saveFeedSettings, children: i18nInstance.t("actions.save") }) ] }) }) ] }) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt, { open: deleteFeedOpen, onOpenChange: (open) => { if (!open) closeDeleteFeed(); }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Header, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: i18nInstance.t("feeds.prompts.deleteFeed.title") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Description, { children: i18nInstance.t("feeds.prompts.deleteFeed.description") }) ] }), /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Footer, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Cancel, { children: i18nInstance.t("actions.cancel") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Action, { onClick: () => deleteFeed(), children: i18nInstance.t("actions.delete") }) ] }) ] }) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt, { open: deleteFeedFileOpen, onOpenChange: (open) => { if (!open) closeDeleteFeedFile(); }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Header, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Title, { children: i18nInstance.t("feeds.prompts.deleteFeedFile.title") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Description, { children: i18nInstance.t("feeds.prompts.deleteFeedFile.description") }) ] }), /* @__PURE__ */ jsxRuntime.jsxs(ui.Prompt.Footer, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Cancel, { children: i18nInstance.t("actions.cancel") }), /* @__PURE__ */ jsxRuntime.jsx(ui.Prompt.Action, { onClick: () => deleteFeedFile(), children: i18nInstance.t("actions.delete") }) ] }) ] }) }) ] }); }; function buildCategoryTree(categories) { const map = /* @__PURE__ */ new Map(); const roots = []; categories.forEach((cat) => { map.set(cat.id, { ...cat, children: [] }); }); categories.forEach((cat) => { const node = map.get(cat.id); if (cat.parent_category_id && map.has(cat.parent_category_id)) { map.get(cat.parent_category_id).children.push(node); } else { roots.push(node); } }); return roots; } function flattenCategoryTree(tree, level = 0) { const result = []; for (const node of tree) { result.push({ ...node, name: `${"  ".repeat(level)}${node.name}` }); if (node.children.length) { result.push(...flattenCategoryTree(node.children, level + 1)); } } return result; } const ProductCategoriesSection = () => { var _a, _b; const { id } = reactRouterDom.useParams(); const [rowSelection, setRowSelection] = React.useState({}); const { data: feedData, isError, error } = reactQuery.useQuery({ queryFn: () => sdk.client.fetch(`/admin/feeds/${id}`), queryKey: ["feed", id] }); if (isError) { throw error; } const feed = feedData == null ? void 0 : feedData.feed; const selectedIds = ((_b = (_a = feed == null ? void 0 : feed.settings) == null ? void 0 : _a.categories) == null ? void 0 : _b.map((c) => c.id)) ?? []; const columnHelper = ui.createDataTableColumnHelper(); const columns = [ columnHelper.select(), columnHelper.accessor("name", { header: "Name", cell: ({ getValue }) => /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { className: "whitespace-pre h-12 flex items-center", children: getValue() }) }) ]; const { data: categoriesData, isLoading } = reactQuery.useQuery({ queryKey: ["categories"], queryFn: async () => { const { product_categories } = await sdk.admin.productCategory.list({ is_active: true, fields: "id,name,rank,parent_category_id" }); const tree = buildCategoryTree(product_categories); return flattenCategoryTree(tree); } }); React.useEffect(() => { if (categoriesData && selectedIds.length > 0) { setRowSelection( Object.fromEntries(selectedIds.map((id2) => [id2, true])) ); } }, [categoriesData, feedData]); const isModified = React.useMemo(() => { return JSON.stringify(rowSelection) !== JSON.stringify(Object.fromEntries(selectedIds.map((id2) => [id2, true]))); }, [rowSelection, selectedIds]); const table = ui.useDataTable({ columns, data: categoriesData || [], getRowId: (row) => row.id, isLoading, rowSelection: { state: rowSelection, onRowSelectionChange: setRowSelection } }); const selectedCategories = React.useMemo(() => { if (!categoriesData) return []; return categoriesData.filter((cat) => rowSelection[cat.id]).map((cat) => ({ id: cat.id, parentId: cat.parent_category_id || void 0, value: cat.name.trim() })); }, [rowSelection, categoriesData]); const queryClient = reactQuery.useQueryClient(); const { mutate: updateFeedMutate } = reactQuery.useMutation({ mutationFn: async (updatedFeed) => { return sdk.client.fetch(`/admin/feeds/${updatedFeed.id}`, { method: "PATCH", body: updatedFeed, headers: { "Content-Type": "application/json" } }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["feed", feed == null ? void 0 : feed.id] }); queryClient.invalidateQueries({ queryKey: [["feeds"]] }); }, onError: (error2) => { console.error("Error updating feed:", error2); } }); const saveFeedCategories = (selectedCategories2) => { const updatedFeed = { id: feed == null ? void 0 : feed.id, settings: { categories: selectedCategories2 } }; updateFeedMutate(updatedFeed); }; return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "divide-y p-0", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.DataTable, { instance: table, children: [ /* @__PURE__ */ jsxRuntime.jsx( Header, { title: i18nInstance.t("settings.categories.title"), subtitle: i18nInstance.t("settings.categories.subtitle"), actions: [ { type: "button", props: { children: i18nInstance.t("actions.save"), variant: "secondary", onClick: () => { try { saveFeedCategories(selectedCategories); ui.toast.success(i18nInstance.t("general.success"), { description: i18nInstance.t("feeds.toasts.categoriesSaved") }); } catch (e) { console.error(e); ui.toast.error(i18nInstance.t("general.error"), { description: i18nInstance.t("feeds.toasts.categoriesSaveFailed") }); } }, disabled: !isModified } } ] } ), /* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Table, {}) ] }) }) }); }; const ShopSettingsSection = () => { var _a, _b, _c; const { id } = reactRouterDom.useParams(); const [editShopOpen, openEditShop, closeEditShop] = ui.useToggleState(); const [shopName, setShopName] = React.useState(""); const [shopCompany, setShopCompany] = React.useState(""); const [shopUrl, setShopUrl] = React.useState(""); const { data, isError, error } = reactQuery.useQuery({ queryFn: () => sdk.client.fetch(`/admin/feeds/${id}`), queryKey: ["feed", id] }); if (isError) { throw error; } React.useEffect(() => { var _a2, _b2, _c2; if (data == null ? void 0 : data.feed) { setShopName((_a2 = data.feed.settings) == null ? void 0 : _a2.name); setShopCompany((_b2 = data.feed.settings) == null ? void 0 : _b2.company); setShopUrl((_c2 = data.feed.settings) == null ? void 0 : _c2.url); } }, [data]); const feed = data == null ? void 0 : data.feed; const queryClient = reactQuery.useQueryClient(); const { mutate: updateFeedMutate } = reactQuery.useMutation({ mutationFn: async (updatedFeed) => { return sdk.client.fetch(`/admin/feeds/${updatedFeed.id}`, { method: "PATCH", body: updatedFeed, headers: { "Content-Type": "application/json" } }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["feed", feed == null ? void 0 : feed.id] }); queryClient.invalidateQueries({ queryKey: [["feeds"]] }); }, onError: (error2) => { console.error("Error updating feed:", error2); } }); const saveShopSettings = () => { const updatedFeed = { id: feed == null ? void 0 : feed.id, settings: { name: shopName, company: shopCompany, url: shopUrl, platform: "Medusa" } }; updateFeedMutate(updatedFeed); closeEditShop(); }; return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [ /* @__PURE__ */ jsxRuntime.jsx( Header, { title: i18nInstance.t("settings.shop.title"), subtitle: i18nInstance.t("settings.shop.subtitle"), actions: [ { type: "action-menu", props: { groups: [ { actions: [ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Pencil, {}), label: i18nInstance.t("actions.edit"), onClick: () => openEditShop() } ] } ] } } ] }, `${editShopOpen ? "edit-shop-open" : "edit-shop-closed"}` ), /* @__PURE__ */ jsxRuntime.jsx(SectionRow, { title: i18nInstance.t("settings.shop.fields.name"), value: ((_a = feed == null ? void 0 : feed.settings) == null ? void 0 : _a.name) || "-" }), /* @__PURE__ */ jsxRuntime.jsx(SectionRow, { title: i18nInstance.t("settings.shop.fields.company"), value: ((_b = feed == null ? void 0 : feed.settings) == null ? void 0 : _b.company) || "-" }), /* @__PURE__ */ jsxRuntime.jsx(SectionRow, { title: i18nInstance.t("settings.shop.fields.url"), value: ((_c = feed == null ? void 0 : feed.settings) == null ? void 0 : _c.url) || "-" }), /* @__PURE__ */ jsxRuntime.jsx(SectionRow, { title: i18nInstance.t("settings.shop.fields.platform"), value: "Medusa" }), /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: editShopOpen, onOpenChange: (open) => { if (!open) closeEditShop(); }, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [ /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: i18nInstance.t("feeds.edit.title") }) }) }), /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-4", children: [ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: