fix: admin panel loading
This commit is contained in:
+69
-31
@@ -119,9 +119,12 @@
|
||||
let scrollLockApplied = false;
|
||||
let adminI18nLoaded = false;
|
||||
let adminI18nPromise = null;
|
||||
let AdminPanelComponent = null;
|
||||
let adminBundleApi = null;
|
||||
let adminBundlePromise = null;
|
||||
let adminBundleError = "";
|
||||
let adminMountTarget = null;
|
||||
let adminMountHandle = null;
|
||||
let adminPanelProps = {};
|
||||
let tg = null;
|
||||
const telegramSdk = createTelegramSdk({
|
||||
scriptUrl: TELEGRAM_WEBAPP_SCRIPT_URL,
|
||||
@@ -527,6 +530,7 @@
|
||||
supportStore.closePolling();
|
||||
clearLanguageClickGuard();
|
||||
syncBodyScrollLock(false);
|
||||
destroyAdminMount();
|
||||
};
|
||||
});
|
||||
|
||||
@@ -647,13 +651,18 @@
|
||||
});
|
||||
}
|
||||
|
||||
function readAdminBundleApi() {
|
||||
const bundle = window.SubscriptionWebAppAdmin;
|
||||
return bundle?.mount ? bundle : null;
|
||||
}
|
||||
|
||||
async function ensureAdminBundle() {
|
||||
if (AdminPanelComponent) return true;
|
||||
if (adminBundleApi) return true;
|
||||
if (adminBundlePromise) return adminBundlePromise;
|
||||
|
||||
const existing = window.SubscriptionWebAppAdminPanel;
|
||||
const existing = readAdminBundleApi();
|
||||
if (existing) {
|
||||
AdminPanelComponent = existing.default || existing;
|
||||
adminBundleApi = existing;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -663,9 +672,9 @@
|
||||
const jsSrc = resolveWebappAssetPath(CFG.adminJsAsset, "subscription_webapp_admin.js");
|
||||
await appendStylesheetOnce("subscription-webapp-admin-css", cssHref);
|
||||
await appendScriptOnce("subscription-webapp-admin-js", jsSrc);
|
||||
const loaded = window.SubscriptionWebAppAdminPanel;
|
||||
if (!loaded) throw new Error("admin_bundle_missing_component");
|
||||
AdminPanelComponent = loaded.default || loaded;
|
||||
const loaded = readAdminBundleApi();
|
||||
if (!loaded) throw new Error("admin_bundle_missing_mount");
|
||||
adminBundleApi = loaded;
|
||||
return true;
|
||||
})()
|
||||
.catch((error) => {
|
||||
@@ -679,6 +688,57 @@
|
||||
return adminBundlePromise;
|
||||
}
|
||||
|
||||
function destroyAdminMount() {
|
||||
if (!adminMountHandle) return;
|
||||
adminMountHandle.destroy?.();
|
||||
adminMountHandle = null;
|
||||
}
|
||||
|
||||
$: adminPanelProps = {
|
||||
api,
|
||||
onClose: closeAdminPanel,
|
||||
onToast: (text) => showToast(text),
|
||||
initialSection: adminSectionFromPath(window.location.pathname),
|
||||
initialUserId: adminUserIdFromPath(window.location.pathname),
|
||||
onSectionChange: handleAdminSectionChange,
|
||||
onSettingsSaved: handleAdminPersistedSaved,
|
||||
onTariffsSaved: handleAdminPersistedSaved,
|
||||
onThemesSaved: handleAdminPersistedSaved,
|
||||
brandTitle,
|
||||
brand,
|
||||
appFaviconUrl: CFG.faviconUrl,
|
||||
appFaviconUseCustom: CFG.faviconUseCustom,
|
||||
appVersion: CFG.appVersion,
|
||||
appRepositoryUrl: CFG.appRepositoryUrl,
|
||||
currentLang,
|
||||
languageOptions,
|
||||
languageBusy,
|
||||
onLanguageChange: accountStore.updateAccountLanguage,
|
||||
t,
|
||||
};
|
||||
|
||||
$: {
|
||||
const shouldMountAdmin = screen === "admin" && isAdmin && adminBundleApi && adminMountTarget;
|
||||
const props = adminPanelProps;
|
||||
|
||||
if (shouldMountAdmin) {
|
||||
try {
|
||||
if (adminMountHandle) {
|
||||
adminMountHandle.update?.(props);
|
||||
} else {
|
||||
adminMountTarget.replaceChildren();
|
||||
adminMountHandle = adminBundleApi.mount(adminMountTarget, props);
|
||||
}
|
||||
} catch (error) {
|
||||
adminBundleError = error?.message || "admin_bundle_mount_failed";
|
||||
adminBundleApi = null;
|
||||
destroyAdminMount();
|
||||
}
|
||||
} else {
|
||||
destroyAdminMount();
|
||||
}
|
||||
}
|
||||
|
||||
async function boot() {
|
||||
await runWebappBoot({
|
||||
MOCK,
|
||||
@@ -1221,30 +1281,8 @@
|
||||
setPasswordLoginMode={(enabled) => setPasswordLoginMode(enabled)}
|
||||
/>
|
||||
{:else if screen === "admin" && isAdmin}
|
||||
{#if AdminPanelComponent}
|
||||
<svelte:component
|
||||
this={AdminPanelComponent}
|
||||
{api}
|
||||
onClose={closeAdminPanel}
|
||||
onToast={(text) => showToast(text)}
|
||||
initialSection={adminSectionFromPath(window.location.pathname)}
|
||||
initialUserId={adminUserIdFromPath(window.location.pathname)}
|
||||
onSectionChange={handleAdminSectionChange}
|
||||
onSettingsSaved={handleAdminPersistedSaved}
|
||||
onTariffsSaved={handleAdminPersistedSaved}
|
||||
onThemesSaved={handleAdminPersistedSaved}
|
||||
{brandTitle}
|
||||
{brand}
|
||||
appFaviconUrl={CFG.faviconUrl}
|
||||
appFaviconUseCustom={CFG.faviconUseCustom}
|
||||
appVersion={CFG.appVersion}
|
||||
appRepositoryUrl={CFG.appRepositoryUrl}
|
||||
{currentLang}
|
||||
{languageOptions}
|
||||
{languageBusy}
|
||||
onLanguageChange={accountStore.updateAccountLanguage}
|
||||
{t}
|
||||
/>
|
||||
{#if adminBundleApi}
|
||||
<div class="admin-mount" bind:this={adminMountTarget}></div>
|
||||
{:else}
|
||||
<div class="loader">
|
||||
<BrandMark {brand} size="md" />
|
||||
|
||||
@@ -1,9 +1,45 @@
|
||||
import { mount, unmount } from "svelte";
|
||||
|
||||
import AdminPanel from "./admin/AdminPanel.svelte";
|
||||
import "./styles-admin.css";
|
||||
|
||||
function mountAdminPanel(target, props = {}) {
|
||||
if (!target) throw new Error("admin_mount_target_missing");
|
||||
|
||||
const currentProps = { ...props };
|
||||
const instance = mount(AdminPanel, { target, props: currentProps });
|
||||
let destroyed = false;
|
||||
|
||||
return {
|
||||
update(nextProps = {}) {
|
||||
if (destroyed) return;
|
||||
Object.assign(currentProps, nextProps);
|
||||
|
||||
if (typeof instance.$set === "function") {
|
||||
instance.$set(nextProps);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const [key, value] of Object.entries(nextProps)) {
|
||||
if (key in instance) instance[key] = value;
|
||||
}
|
||||
},
|
||||
destroy() {
|
||||
if (destroyed) return;
|
||||
destroyed = true;
|
||||
void unmount(instance);
|
||||
target.replaceChildren();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
window.SubscriptionWebAppAdmin = {
|
||||
AdminPanel,
|
||||
mount: mountAdminPanel,
|
||||
};
|
||||
window.SubscriptionWebAppAdminPanel = AdminPanel;
|
||||
window.dispatchEvent(
|
||||
new CustomEvent("subscription-webapp-admin-ready", {
|
||||
detail: { AdminPanel },
|
||||
detail: window.SubscriptionWebAppAdmin,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
@import "./styles/admin.css";
|
||||
@import "./styles/admin-controls.css";
|
||||
@import "./styles/admin-dialogs.css";
|
||||
|
||||
.admin-mount {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,12 @@ export default defineConfig(({ mode }) => {
|
||||
$components: path.resolve(__dirname, "src/lib/components"),
|
||||
},
|
||||
},
|
||||
plugins: [tailwindcss(), svelte()],
|
||||
plugins: [
|
||||
tailwindcss(),
|
||||
svelte({
|
||||
compilerOptions: isAdminBuild ? { compatibility: { componentApi: 4 } } : {},
|
||||
}),
|
||||
],
|
||||
build: {
|
||||
outDir: templateDir,
|
||||
emptyOutDir: false,
|
||||
|
||||
Reference in New Issue
Block a user