mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-31 01:19:34 +00:00
Adds Zod schemas for client/inbound/xray/node-probe endpoints and wires useNodeMutations, useClients, useInbounds, useXraySetting, useDatepicker through parseMsg. Drops the duplicated per-file ApiMsg<T> interfaces and the local ClientRecord / OutboundTrafficRow / XraySettingsValue / DefaultsPayload declarations in favour of schema-inferred types re-exported from the new src/schemas/ modules. API boundary now validates: clients list/paged, clients onlines, clients lastOnline, clients get/hydrate, inbounds slim, inbounds get, inbounds options, defaultSettings, xray config, xray outbounds traffic, xray testOutbound, xray getXrayResult, getDefaultJsonConfig, nodes probe, nodes test. Mutation responses that consume obj (bulkAdjust, delDepleted, nodes probe / test) get response validation; pass-through mutations stay agnostic. NodeFormModal type-aligned to Msg<ProbeResult>.
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' | 'jalalian';
|
|
|
|
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/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 };
|
|
}
|