fix: admin panel loading
This commit is contained in:
+69
-31
@@ -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" />
|
||||||
|
|||||||
@@ -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,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user