fix: preserve admin view on language change
This commit is contained in:
+91
-23
@@ -187,7 +187,9 @@
|
|||||||
let adminBundleError = "";
|
let adminBundleError = "";
|
||||||
let adminMountTarget = null;
|
let adminMountTarget = null;
|
||||||
let adminMountHandle = null;
|
let adminMountHandle = null;
|
||||||
|
let adminMountedTarget = null;
|
||||||
let adminPanelProps = {};
|
let adminPanelProps = {};
|
||||||
|
let adminActiveSection = "stats";
|
||||||
let tg = null;
|
let tg = null;
|
||||||
const telegramSdk = createTelegramSdk({
|
const telegramSdk = createTelegramSdk({
|
||||||
scriptUrl: TELEGRAM_WEBAPP_SCRIPT_URL,
|
scriptUrl: TELEGRAM_WEBAPP_SCRIPT_URL,
|
||||||
@@ -767,7 +769,11 @@
|
|||||||
void boot();
|
void boot();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const section = sectionFromPath(window.location.pathname);
|
const currentQuery = currentSearchParams();
|
||||||
|
const section =
|
||||||
|
isDocsDemo && currentQuery.get("screen")
|
||||||
|
? normalizeSection(currentQuery.get("screen"))
|
||||||
|
: sectionFromPath(window.location.pathname);
|
||||||
if (mode === "login") {
|
if (mode === "login") {
|
||||||
setPasswordLoginMode(isPasswordLoginPath(), true);
|
setPasswordLoginMode(isPasswordLoginPath(), true);
|
||||||
screen = "login";
|
screen = "login";
|
||||||
@@ -775,6 +781,9 @@
|
|||||||
}
|
}
|
||||||
if (mode === "app") {
|
if (mode === "app") {
|
||||||
if (section === "admin" && isAdmin) {
|
if (section === "admin" && isAdmin) {
|
||||||
|
adminActiveSection = isDocsDemo
|
||||||
|
? initialAdminSectionFromLocation()
|
||||||
|
: adminSectionFromPath(window.location.pathname);
|
||||||
const pathAtStart = window.location.pathname;
|
const pathAtStart = window.location.pathname;
|
||||||
void Promise.all([ensureI18nScope("admin"), ensureAdminBundle()])
|
void Promise.all([ensureI18nScope("admin"), ensureAdminBundle()])
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@@ -1022,20 +1031,54 @@
|
|||||||
if (!adminMountHandle) return;
|
if (!adminMountHandle) return;
|
||||||
adminMountHandle.destroy?.();
|
adminMountHandle.destroy?.();
|
||||||
adminMountHandle = null;
|
adminMountHandle = null;
|
||||||
|
adminMountedTarget = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function currentSearchParams() {
|
||||||
|
return new URLSearchParams(window.location.search);
|
||||||
}
|
}
|
||||||
|
|
||||||
function initialAdminSectionFromLocation() {
|
function initialAdminSectionFromLocation() {
|
||||||
if (MOCK && query.get("admin_section")) {
|
const currentQuery = currentSearchParams();
|
||||||
return normalizeAdminSection(query.get("admin_section"));
|
if (MOCK && currentQuery.get("admin_section")) {
|
||||||
|
return normalizeAdminSection(currentQuery.get("admin_section"));
|
||||||
}
|
}
|
||||||
return adminSectionFromPath(window.location.pathname);
|
return adminSectionFromPath(window.location.pathname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function syncDocsDemoSection(section, replace = false, adminSection = null) {
|
||||||
|
if (!isDocsDemo || window.location.protocol === "file:") return false;
|
||||||
|
const normalized = normalizeSection(section);
|
||||||
|
const currentQuery = currentSearchParams();
|
||||||
|
currentQuery.set("screen", normalized);
|
||||||
|
if (normalized === "admin") {
|
||||||
|
currentQuery.set(
|
||||||
|
"admin_section",
|
||||||
|
normalizeAdminSection(
|
||||||
|
adminSection || adminActiveSection || initialAdminSectionFromLocation()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
currentQuery.delete("admin_section");
|
||||||
|
}
|
||||||
|
const nextSearch = currentQuery.toString();
|
||||||
|
const nextUrl = `${window.location.pathname}${nextSearch ? `?${nextSearch}` : ""}${window.location.hash}`;
|
||||||
|
if (nextUrl !== `${window.location.pathname}${window.location.search}${window.location.hash}`) {
|
||||||
|
window.history[replace ? "replaceState" : "pushState"](null, "", nextUrl);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncAppSectionPath(section, replace = false, adminSection = null, adminUserId = null) {
|
||||||
|
if (syncDocsDemoSection(section, replace, adminSection)) return;
|
||||||
|
syncSectionPath(section, replace, adminSection, adminUserId);
|
||||||
|
}
|
||||||
|
|
||||||
$: adminPanelProps = {
|
$: adminPanelProps = {
|
||||||
api,
|
api,
|
||||||
onClose: closeAdminPanel,
|
onClose: closeAdminPanel,
|
||||||
onToast: (text) => showToast(text),
|
onToast: (text) => showToast(text),
|
||||||
initialSection: initialAdminSectionFromLocation(),
|
initialSection: screen === "admin" ? adminActiveSection : initialAdminSectionFromLocation(),
|
||||||
initialPaymentId: adminPaymentIdFromPath(window.location.pathname),
|
initialPaymentId: adminPaymentIdFromPath(window.location.pathname),
|
||||||
initialPaymentUserId: adminPaymentsUserIdFromPath(window.location.pathname),
|
initialPaymentUserId: adminPaymentsUserIdFromPath(window.location.pathname),
|
||||||
initialUserId: adminUserIdFromPath(window.location.pathname),
|
initialUserId: adminUserIdFromPath(window.location.pathname),
|
||||||
@@ -1063,11 +1106,13 @@
|
|||||||
|
|
||||||
if (shouldMountAdmin) {
|
if (shouldMountAdmin) {
|
||||||
try {
|
try {
|
||||||
if (adminMountHandle) {
|
if (adminMountHandle && adminMountedTarget === adminMountTarget) {
|
||||||
adminMountHandle.update?.(props);
|
adminMountHandle.update?.(props);
|
||||||
} else {
|
} else {
|
||||||
|
destroyAdminMount();
|
||||||
adminMountTarget.replaceChildren();
|
adminMountTarget.replaceChildren();
|
||||||
adminMountHandle = adminBundleApi.mount(adminMountTarget, props);
|
adminMountHandle = adminBundleApi.mount(adminMountTarget, props);
|
||||||
|
adminMountedTarget = adminMountTarget;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
adminBundleError = error?.message || "admin_bundle_mount_failed";
|
adminBundleError = error?.message || "admin_bundle_mount_failed";
|
||||||
@@ -1161,6 +1206,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loadData(options = {}) {
|
async function loadData(options = {}) {
|
||||||
|
const preserveView = options?.preserveView === true;
|
||||||
|
const preservedSection = preserveView
|
||||||
|
? normalizeSection(options?.section || screen || activeTab)
|
||||||
|
: null;
|
||||||
|
const preservedAdminSection =
|
||||||
|
preserveView && preservedSection === "admin"
|
||||||
|
? normalizeAdminSection(
|
||||||
|
options?.adminSection || adminActiveSection || initialAdminSectionFromLocation()
|
||||||
|
)
|
||||||
|
: null;
|
||||||
const payload = await api(options?.fresh ? "/me?fresh=1" : "/me");
|
const payload = await api(options?.fresh ? "/me?fresh=1" : "/me");
|
||||||
if (!payload.ok) throw new Error(payload.error || "load_failed");
|
if (!payload.ok) throw new Error(payload.error || "load_failed");
|
||||||
data = payload;
|
data = payload;
|
||||||
@@ -1171,9 +1226,11 @@
|
|||||||
paymentStep: "tariff",
|
paymentStep: "tariff",
|
||||||
selectedMethod: payload.payment_methods?.[0]?.id || "",
|
selectedMethod: payload.payment_methods?.[0]?.id || "",
|
||||||
}));
|
}));
|
||||||
let section =
|
const currentQuery = currentSearchParams();
|
||||||
MOCK && query.get("screen")
|
let section = preserveView
|
||||||
? normalizeSection(query.get("screen"))
|
? preservedSection
|
||||||
|
: MOCK && currentQuery.get("screen")
|
||||||
|
? normalizeSection(currentQuery.get("screen"))
|
||||||
: sectionFromPath(window.location.pathname);
|
: sectionFromPath(window.location.pathname);
|
||||||
if (section === "admin" && !payload.user?.is_admin) section = "settings";
|
if (section === "admin" && !payload.user?.is_admin) section = "settings";
|
||||||
if (section === "devices" && !payload.settings?.my_devices_enabled) section = "home";
|
if (section === "devices" && !payload.settings?.my_devices_enabled) section = "home";
|
||||||
@@ -1186,11 +1243,13 @@
|
|||||||
) {
|
) {
|
||||||
section = "home";
|
section = "home";
|
||||||
}
|
}
|
||||||
const initialAdminSection = section === "admin" ? initialAdminSectionFromLocation() : null;
|
const initialAdminSection =
|
||||||
|
section === "admin" ? preservedAdminSection || initialAdminSectionFromLocation() : null;
|
||||||
if (section === "admin" && payload.user?.is_admin) {
|
if (section === "admin" && payload.user?.is_admin) {
|
||||||
try {
|
try {
|
||||||
await ensureI18nScope("admin");
|
await ensureI18nScope("admin");
|
||||||
await ensureAdminBundle();
|
await ensureAdminBundle();
|
||||||
|
adminActiveSection = initialAdminSection || "stats";
|
||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
void _error;
|
void _error;
|
||||||
section = "settings";
|
section = "settings";
|
||||||
@@ -1228,7 +1287,7 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
syncSectionPath(section, true, initialAdminSection);
|
syncAppSectionPath(section, true, initialAdminSection);
|
||||||
}
|
}
|
||||||
if (section === "devices" && payload.settings?.my_devices_enabled) {
|
if (section === "devices" && payload.settings?.my_devices_enabled) {
|
||||||
await devicesStore.loadDevices(true);
|
await devicesStore.loadDevices(true);
|
||||||
@@ -1443,12 +1502,12 @@
|
|||||||
activeTab = "home";
|
activeTab = "home";
|
||||||
if (useInstallGuides) {
|
if (useInstallGuides) {
|
||||||
screen = "install";
|
screen = "install";
|
||||||
syncSectionPath("install", replace);
|
syncAppSectionPath("install", replace);
|
||||||
installGuidesStore.load(true);
|
installGuidesStore.load(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
screen = "home";
|
screen = "home";
|
||||||
syncSectionPath("home", replace);
|
syncAppSectionPath("home", replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleSubscriptionActivated(context = {}) {
|
async function handleSubscriptionActivated(context = {}) {
|
||||||
@@ -1551,7 +1610,7 @@
|
|||||||
billingStore.closePaymentModal();
|
billingStore.closePaymentModal();
|
||||||
activeTab = "home";
|
activeTab = "home";
|
||||||
screen = "home";
|
screen = "home";
|
||||||
syncSectionPath("home");
|
syncAppSectionPath("home");
|
||||||
}
|
}
|
||||||
|
|
||||||
function goInstall() {
|
function goInstall() {
|
||||||
@@ -1562,7 +1621,7 @@
|
|||||||
billingStore.closePaymentModal();
|
billingStore.closePaymentModal();
|
||||||
activeTab = "home";
|
activeTab = "home";
|
||||||
screen = "install";
|
screen = "install";
|
||||||
syncSectionPath("install");
|
syncAppSectionPath("install");
|
||||||
installGuidesStore.load(true);
|
installGuidesStore.load(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1570,7 +1629,7 @@
|
|||||||
billingStore.closePaymentModal();
|
billingStore.closePaymentModal();
|
||||||
activeTab = "invite";
|
activeTab = "invite";
|
||||||
screen = "invite";
|
screen = "invite";
|
||||||
syncSectionPath("invite");
|
syncAppSectionPath("invite");
|
||||||
}
|
}
|
||||||
|
|
||||||
function goDevices() {
|
function goDevices() {
|
||||||
@@ -1578,7 +1637,7 @@
|
|||||||
billingStore.closePaymentModal();
|
billingStore.closePaymentModal();
|
||||||
activeTab = "devices";
|
activeTab = "devices";
|
||||||
screen = "devices";
|
screen = "devices";
|
||||||
syncSectionPath("devices");
|
syncAppSectionPath("devices");
|
||||||
devicesStore.loadDevices(devicesEnabled);
|
devicesStore.loadDevices(devicesEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1587,7 +1646,7 @@
|
|||||||
billingStore.closePaymentModal();
|
billingStore.closePaymentModal();
|
||||||
activeTab = "support";
|
activeTab = "support";
|
||||||
screen = "support";
|
screen = "support";
|
||||||
syncSectionPath("support");
|
syncAppSectionPath("support");
|
||||||
supportStore.loadList();
|
supportStore.loadList();
|
||||||
supportStore.startPolling({ includeList: true });
|
supportStore.startPolling({ includeList: true });
|
||||||
}
|
}
|
||||||
@@ -1643,13 +1702,16 @@
|
|||||||
billingStore.closePaymentModal();
|
billingStore.closePaymentModal();
|
||||||
activeTab = "settings";
|
activeTab = "settings";
|
||||||
screen = "settings";
|
screen = "settings";
|
||||||
syncSectionPath("settings");
|
syncAppSectionPath("settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
async function openAdminPanel() {
|
async function openAdminPanel() {
|
||||||
if (!isAdmin) return;
|
if (!isAdmin) return;
|
||||||
clearLanguageClickGuard();
|
clearLanguageClickGuard();
|
||||||
billingStore.closePaymentModal();
|
billingStore.closePaymentModal();
|
||||||
|
const nextAdminSection = normalizeAdminSection(
|
||||||
|
adminActiveSection || adminSectionFromPath(window.location.pathname)
|
||||||
|
);
|
||||||
try {
|
try {
|
||||||
await ensureI18nScope("admin");
|
await ensureI18nScope("admin");
|
||||||
await ensureAdminBundle();
|
await ensureAdminBundle();
|
||||||
@@ -1660,23 +1722,29 @@
|
|||||||
}
|
}
|
||||||
activeTab = "settings";
|
activeTab = "settings";
|
||||||
screen = "admin";
|
screen = "admin";
|
||||||
syncSectionPath("admin", false, adminSectionFromPath(window.location.pathname));
|
adminActiveSection = nextAdminSection;
|
||||||
|
syncAppSectionPath("admin", false, adminActiveSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeAdminPanel() {
|
function closeAdminPanel() {
|
||||||
screen = "settings";
|
screen = "settings";
|
||||||
activeTab = "settings";
|
activeTab = "settings";
|
||||||
syncSectionPath("settings");
|
syncAppSectionPath("settings");
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleAdminSectionChange(adminSection, adminUserId = null) {
|
function handleAdminSectionChange(adminSection, adminUserId = null) {
|
||||||
if (screen !== "admin") return;
|
if (screen !== "admin") return;
|
||||||
|
const nextAdminSection = normalizeAdminSection(adminSection);
|
||||||
|
adminActiveSection = nextAdminSection;
|
||||||
if (window.location.protocol === "file:") return;
|
if (window.location.protocol === "file:") return;
|
||||||
if (isDocsDemo) return;
|
if (isDocsDemo) {
|
||||||
|
syncDocsDemoSection("admin", false, nextAdminSection);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const targetPath =
|
const targetPath =
|
||||||
adminSection === "users" && adminUserId
|
nextAdminSection === "users" && adminUserId
|
||||||
? `/admin/users/${adminUserId}`
|
? `/admin/users/${adminUserId}`
|
||||||
: `/admin/${adminSection}`;
|
: `/admin/${nextAdminSection}`;
|
||||||
if (window.location.pathname === targetPath) return;
|
if (window.location.pathname === targetPath) return;
|
||||||
window.history.pushState(
|
window.history.pushState(
|
||||||
null,
|
null,
|
||||||
|
|||||||
@@ -211,8 +211,13 @@
|
|||||||
const normalizeSection = (value) => ((VALID_SECTIONS || []).includes(value) ? value : "stats");
|
const normalizeSection = (value) => ((VALID_SECTIONS || []).includes(value) ? value : "stats");
|
||||||
|
|
||||||
let active = normalizeSection(initialSection);
|
let active = normalizeSection(initialSection);
|
||||||
$: if (initialSection) {
|
let lastInitialSection = active;
|
||||||
active = normalizeSection(initialSection);
|
$: {
|
||||||
|
const nextInitialSection = normalizeSection(initialSection);
|
||||||
|
if (nextInitialSection !== lastInitialSection) {
|
||||||
|
active = nextInitialSection;
|
||||||
|
lastInitialSection = nextInitialSection;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let sidebarOpen = false;
|
let sidebarOpen = false;
|
||||||
let isCompact = false;
|
let isCompact = false;
|
||||||
@@ -287,6 +292,10 @@
|
|||||||
onSectionChange(next);
|
onSectionChange(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeLanguage(value) {
|
||||||
|
onLanguageChange(value, { section: "admin", adminSection: active });
|
||||||
|
}
|
||||||
|
|
||||||
function readSectionFromPath() {
|
function readSectionFromPath() {
|
||||||
if (typeof window === "undefined") return "stats";
|
if (typeof window === "undefined") return "stats";
|
||||||
const match = window.location.pathname.match(/^\/admin\/([a-z0-9_-]+)(?:\/.*)?$/i);
|
const match = window.location.pathname.match(/^\/admin\/([a-z0-9_-]+)(?:\/.*)?$/i);
|
||||||
@@ -584,7 +593,7 @@
|
|||||||
items={languageOptions}
|
items={languageOptions}
|
||||||
disabled={languageBusy}
|
disabled={languageBusy}
|
||||||
onOpenChange={setAdminLanguageMenuOpen}
|
onOpenChange={setAdminLanguageMenuOpen}
|
||||||
onValueChange={onLanguageChange}
|
onValueChange={changeLanguage}
|
||||||
>
|
>
|
||||||
<Select.Trigger
|
<Select.Trigger
|
||||||
class="admin-language-trigger"
|
class="admin-language-trigger"
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ export function createAccountStore({
|
|||||||
window.location.assign(buildTelegramOAuthStartUrl("link", getTg()));
|
window.location.assign(buildTelegramOAuthStartUrl("link", getTg()));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateAccountLanguage(nextValue) {
|
async function updateAccountLanguage(nextValue, options = {}) {
|
||||||
const s = get(state);
|
const s = get(state);
|
||||||
const normalize = typeof normalizeLangCode === "function" ? normalizeLangCode : (v) => v;
|
const normalize = typeof normalizeLangCode === "function" ? normalizeLangCode : (v) => v;
|
||||||
const language = normalize(nextValue);
|
const language = normalize(nextValue);
|
||||||
@@ -361,7 +361,7 @@ export function createAccountStore({
|
|||||||
if (typeof updateLocalData === "function") {
|
if (typeof updateLocalData === "function") {
|
||||||
updateLocalData(normalize(response.language || language));
|
updateLocalData(normalize(response.language || language));
|
||||||
}
|
}
|
||||||
await loadData({ fresh: true });
|
await loadData({ fresh: true, preserveView: true, ...options });
|
||||||
} catch {
|
} catch {
|
||||||
showToast(t("wa_settings_language_update_failed"));
|
showToast(t("wa_settings_language_update_failed"));
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user