-
-
-
- {h5Access.enabled ? t('settings.general.h5AccessStatusEnabled') : t('settings.general.h5AccessDisabledValue')}
-
-
+
+ )
+}
-
-
setH5PublicBaseUrlDraft(event.target.value)}
+// ─── H5 Access Settings ──────────────────────────────────────
+
+function H5AccessSettings() {
+ const {
+ h5Access,
+ h5AccessError,
+ enableH5Access,
+ disableH5Access,
+ regenerateH5AccessToken,
+ updateH5AccessSettings,
+ } = useSettingsStore()
+ const t = useTranslation()
+ const [h5PublicBaseUrlDraft, setH5PublicBaseUrlDraft] = useState(h5Access.publicBaseUrl ?? '')
+ const [h5GeneratedToken, setH5GeneratedToken] = useState
(null)
+ const [h5TokenVisible, setH5TokenVisible] = useState(false)
+ const [h5EnableConfirmOpen, setH5EnableConfirmOpen] = useState(false)
+ const [h5QrDataUrl, setH5QrDataUrl] = useState(null)
+ const [h5ActionRunning, setH5ActionRunning] = useState(false)
+ const h5AccessUrl = h5Access.publicBaseUrl
+ const h5LaunchUrl = useMemo(
+ () => buildH5LaunchUrl(h5AccessUrl, h5GeneratedToken),
+ [h5AccessUrl, h5GeneratedToken],
+ )
+ const h5AccessDirty = h5PublicBaseUrlDraft.trim() !== (h5Access.publicBaseUrl ?? '')
+
+ useEffect(() => {
+ setH5PublicBaseUrlDraft(h5Access.publicBaseUrl ?? '')
+ }, [h5Access])
+
+ useEffect(() => {
+ let cancelled = false
+ if (!h5Access.enabled || !h5LaunchUrl || !h5GeneratedToken) {
+ setH5QrDataUrl(null)
+ return () => {
+ cancelled = true
+ }
+ }
+
+ QRCode.toDataURL(h5LaunchUrl, { margin: 1, width: 192 })
+ .then((dataUrl) => {
+ if (!cancelled) setH5QrDataUrl(dataUrl)
+ })
+ .catch(() => {
+ if (!cancelled) setH5QrDataUrl(null)
+ })
+
+ return () => {
+ cancelled = true
+ }
+ }, [h5Access.enabled, h5LaunchUrl, h5GeneratedToken])
+
+ const runH5Action = async (action: () => Promise) => {
+ setH5ActionRunning(true)
+ try {
+ await action()
+ } catch {
+ // The store owns H5-specific error state.
+ } finally {
+ setH5ActionRunning(false)
+ }
+ }
+
+ const handleH5SettingsSave = async () => {
+ await runH5Action(async () => {
+ await updateH5AccessSettings({
+ publicBaseUrl: h5PublicBaseUrlDraft.trim() || null,
+ })
+ })
+ }
+
+ const handleH5UrlCopy = async () => {
+ if (!h5AccessUrl) return
+ await copyTextToClipboard(h5AccessUrl)
+ }
+
+ const handleH5LaunchUrlCopy = async () => {
+ if (!h5LaunchUrl) return
+ await copyTextToClipboard(h5LaunchUrl)
+ }
+
+ const handleH5EnableConfirm = async () => {
+ await runH5Action(async () => {
+ const token = await enableH5Access()
+ setH5GeneratedToken(token)
+ setH5TokenVisible(false)
+ setH5EnableConfirmOpen(false)
+ })
+ }
+
+ const handleH5Disable = async () => {
+ await runH5Action(async () => {
+ await disableH5Access()
+ setH5GeneratedToken(null)
+ setH5TokenVisible(false)
+ })
+ }
+
+ const handleH5Regenerate = async () => {
+ await runH5Action(async () => {
+ const token = await regenerateH5AccessToken()
+ setH5GeneratedToken(token)
+ setH5TokenVisible(false)
+ })
+ }
+
+ return (
+
+
+
+
+
+
+
+
+ {t('settings.general.h5AccessTitle')}
+
+
+ {t('settings.general.h5AccessDescription')}
+
+
+
+
+
+
+