fix: admin panel loading

This commit is contained in:
3252a8
2026-05-21 10:43:55 +03:00
parent db3611487e
commit b3f67a5398
4 changed files with 116 additions and 33 deletions
+69 -31
View File
@@ -119,9 +119,12 @@
let scrollLockApplied = false; let scrollLockApplied = false;
let adminI18nLoaded = false; let adminI18nLoaded = false;
let adminI18nPromise = null; let adminI18nPromise = null;
let AdminPanelComponent = null; let adminBundleApi = null;
let adminBundlePromise = null; let adminBundlePromise = null;
let adminBundleError = ""; let adminBundleError = "";
let adminMountTarget = null;
let adminMountHandle = null;
let adminPanelProps = {};
let tg = null; let tg = null;
const telegramSdk = createTelegramSdk({ const telegramSdk = createTelegramSdk({
scriptUrl: TELEGRAM_WEBAPP_SCRIPT_URL, scriptUrl: TELEGRAM_WEBAPP_SCRIPT_URL,
@@ -527,6 +530,7 @@
supportStore.closePolling(); supportStore.closePolling();
clearLanguageClickGuard(); clearLanguageClickGuard();
syncBodyScrollLock(false); syncBodyScrollLock(false);
destroyAdminMount();
}; };
}); });
@@ -647,13 +651,18 @@
}); });
} }
function readAdminBundleApi() {
const bundle = window.SubscriptionWebAppAdmin;
return bundle?.mount ? bundle : null;
}
async function ensureAdminBundle() { async function ensureAdminBundle() {
if (AdminPanelComponent) return true; if (adminBundleApi) return true;
if (adminBundlePromise) return adminBundlePromise; if (adminBundlePromise) return adminBundlePromise;
const existing = window.SubscriptionWebAppAdminPanel; const existing = readAdminBundleApi();
if (existing) { if (existing) {
AdminPanelComponent = existing.default || existing; adminBundleApi = existing;
return true; return true;
} }
@@ -663,9 +672,9 @@
const jsSrc = resolveWebappAssetPath(CFG.adminJsAsset, "subscription_webapp_admin.js"); const jsSrc = resolveWebappAssetPath(CFG.adminJsAsset, "subscription_webapp_admin.js");
await appendStylesheetOnce("subscription-webapp-admin-css", cssHref); await appendStylesheetOnce("subscription-webapp-admin-css", cssHref);
await appendScriptOnce("subscription-webapp-admin-js", jsSrc); await appendScriptOnce("subscription-webapp-admin-js", jsSrc);
const loaded = window.SubscriptionWebAppAdminPanel; const loaded = readAdminBundleApi();
if (!loaded) throw new Error("admin_bundle_missing_component"); if (!loaded) throw new Error("admin_bundle_missing_mount");
AdminPanelComponent = loaded.default || loaded; adminBundleApi = loaded;
return true; return true;
})() })()
.catch((error) => { .catch((error) => {
@@ -679,6 +688,57 @@
return adminBundlePromise; 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() { async function boot() {
await runWebappBoot({ await runWebappBoot({
MOCK, MOCK,
@@ -1221,30 +1281,8 @@
setPasswordLoginMode={(enabled) => setPasswordLoginMode(enabled)} setPasswordLoginMode={(enabled) => setPasswordLoginMode(enabled)}
/> />
{:else if screen === "admin" && isAdmin} {:else if screen === "admin" && isAdmin}
{#if AdminPanelComponent} {#if adminBundleApi}
<svelte:component <div class="admin-mount" bind:this={adminMountTarget}></div>
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}
/>
{:else} {:else}
<div class="loader"> <div class="loader">
<BrandMark {brand} size="md" /> <BrandMark {brand} size="md" />
+37 -1
View File
@@ -1,9 +1,45 @@
import { mount, unmount } from "svelte";
import AdminPanel from "./admin/AdminPanel.svelte"; import AdminPanel from "./admin/AdminPanel.svelte";
import "./styles-admin.css"; 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.SubscriptionWebAppAdminPanel = AdminPanel;
window.dispatchEvent( window.dispatchEvent(
new CustomEvent("subscription-webapp-admin-ready", { new CustomEvent("subscription-webapp-admin-ready", {
detail: { AdminPanel }, detail: window.SubscriptionWebAppAdmin,
}) })
); );
+4
View File
@@ -1,3 +1,7 @@
@import "./styles/admin.css"; @import "./styles/admin.css";
@import "./styles/admin-controls.css"; @import "./styles/admin-controls.css";
@import "./styles/admin-dialogs.css"; @import "./styles/admin-dialogs.css";
.admin-mount {
display: contents;
}
+6 -1
View File
@@ -19,7 +19,12 @@ export default defineConfig(({ mode }) => {
$components: path.resolve(__dirname, "src/lib/components"), $components: path.resolve(__dirname, "src/lib/components"),
}, },
}, },
plugins: [tailwindcss(), svelte()], plugins: [
tailwindcss(),
svelte({
compilerOptions: isAdminBuild ? { compatibility: { componentApi: 4 } } : {},
}),
],
build: { build: {
outDir: templateDir, outDir: templateDir,
emptyOutDir: false, emptyOutDir: false,