Per SETTINGS-AUDIT (all three tiers approved 2026-10-23): Dead settings: - panelOutbound, ipLimitAllowlist (+ orphan parser job), outboundDownThreshold - tg fake events outbound.down/outbound.up/xray.crash (no publisher in lite) - phantom routing sub-tabs (Happ/Clash/Incy) and subJsonRules direct-rules tab (no backend keys); subHideSettings moved to the subscription info tab first Upstream remnants: - ldap* / smtp* model+schema keys, EmailNotifications orphan component - twoFactorEnable/twoFactorToken + login-page probe (no backend handler) - externalTrafficInform* Newly approved removals: - JSON subscription family (producer, routes, UA auto-detect, mux/finalmask/ observatory) and Clash subscription family (producer, routes, UA detect) - SubBalancer (table, service, controller, settings tab) - subThemeDir (subscription page falls back to the built-in template) - datepicker jalalian option (gregorian only; Persian picker removed) JSON/Clash endpoints now 404; link-format output pinned by regression tests. Guarded keys untouched: webListen/webPort/webBasePath/certs, tg* chain, expireDiff/trafficDiff/tgBotProxy, subHideSettings, pageSize/tgLang.
58 lines
1.4 KiB
TypeScript
58 lines
1.4 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { HttpUtil } from '@/utils';
|
|
import { parseMsg } from '@/utils/zodValidate';
|
|
import { DefaultsPayloadSchema } from '@/schemas/defaults';
|
|
|
|
type Calendar = 'gregorian';
|
|
|
|
let cachedValue: Calendar = 'gregorian';
|
|
let fetched = false;
|
|
let pending: Promise<void> | null = null;
|
|
const listeners = new Set<(value: Calendar) => void>();
|
|
|
|
function notify(value: Calendar) {
|
|
listeners.forEach((fn) => fn(value));
|
|
}
|
|
|
|
async function loadOnce(): Promise<void> {
|
|
if (fetched) return;
|
|
if (pending) {
|
|
await pending;
|
|
return;
|
|
}
|
|
pending = (async () => {
|
|
try {
|
|
const msg = await HttpUtil.post('/panel/api/setting/defaultSettings');
|
|
if (msg?.success) {
|
|
const validated = parseMsg(msg, DefaultsPayloadSchema, 'setting/defaultSettings');
|
|
cachedValue = validated.obj?.datepicker || 'gregorian';
|
|
notify(cachedValue);
|
|
}
|
|
} finally {
|
|
fetched = true;
|
|
pending = null;
|
|
}
|
|
})();
|
|
await pending;
|
|
}
|
|
|
|
export function setDatepicker(value: Calendar) {
|
|
fetched = true;
|
|
cachedValue = value || 'gregorian';
|
|
notify(cachedValue);
|
|
}
|
|
|
|
export function useDatepicker() {
|
|
const [datepicker, setLocal] = useState<Calendar>(cachedValue);
|
|
|
|
useEffect(() => {
|
|
listeners.add(setLocal);
|
|
loadOnce();
|
|
return () => {
|
|
listeners.delete(setLocal);
|
|
};
|
|
}, []);
|
|
|
|
return { datepicker };
|
|
}
|