better UX (valiate on save)

This commit is contained in:
Timo K
2025-12-01 19:33:51 +01:00
parent bd3e91738e
commit ed4517703f
2 changed files with 45 additions and 26 deletions

View File

@@ -28,6 +28,7 @@ import {
InlineField, InlineField,
Label, Label,
RadioControl, RadioControl,
Text,
} from "@vector-im/compound-web"; } from "@vector-im/compound-web";
import { FieldRow, InputField } from "../input/Input"; import { FieldRow, InputField } from "../input/Input";
@@ -41,11 +42,11 @@ import {
matrixRTCMode as matrixRTCModeSetting, matrixRTCMode as matrixRTCModeSetting,
customLivekitUrl as customLivekitUrlSetting, customLivekitUrl as customLivekitUrlSetting,
MatrixRTCMode, MatrixRTCMode,
useSettingWithLastUpdateReason,
} from "./settings"; } from "./settings";
import type { Room as LivekitRoom } from "livekit-client"; import type { Room as LivekitRoom } from "livekit-client";
import styles from "./DeveloperSettingsTab.module.css"; import styles from "./DeveloperSettingsTab.module.css";
import { useUrlParams } from "../UrlParams"; import { useUrlParams } from "../UrlParams";
import { getSFUConfigWithOpenID } from "../livekit/openIDSFU";
interface Props { interface Props {
client: MatrixClient; client: MatrixClient;
@@ -93,8 +94,11 @@ export const DeveloperSettingsTab: FC<Props> = ({
alwaysShowIphoneEarpieceSetting, alwaysShowIphoneEarpieceSetting,
); );
const [customLivekitUrl, setCustomLivekitUrl, customLivekitUrlUpdateReason] = const [customLivekitUrlUpdateError, setCustomLivekitUrlUpdateError] =
useSettingWithLastUpdateReason(customLivekitUrlSetting); useState<string | null>(null);
const [customLivekitUrl, setCustomLivekitUrl] = useSetting(
customLivekitUrlSetting,
);
const [customLivekitUrlTextBuffer, setCustomLivekitUrlTextBuffer] = const [customLivekitUrlTextBuffer, setCustomLivekitUrlTextBuffer] =
useState(customLivekitUrl); useState(customLivekitUrl);
useEffect(() => { useEffect(() => {
@@ -217,11 +221,11 @@ export const DeveloperSettingsTab: FC<Props> = ({
/>{" "} />{" "}
</FieldRow> </FieldRow>
<EditInPlace <EditInPlace
serverInvalid={customLivekitUrlUpdateError !== null}
onSubmit={(e) => e.preventDefault()} onSubmit={(e) => e.preventDefault()}
helpLabel={ helpLabel={
customLivekitUrl === null customLivekitUrl === null
? t("developer_mode.custom_livekit_url.from_config") + ? t("developer_mode.custom_livekit_url.from_config")
(customLivekitUrlUpdateReason ?? "")
: t("developer_mode.custom_livekit_url.current_url") + : t("developer_mode.custom_livekit_url.current_url") +
customLivekitUrl customLivekitUrl
} }
@@ -230,14 +234,36 @@ export const DeveloperSettingsTab: FC<Props> = ({
savingLabel={t("developer_mode.custom_livekit_url.saving")} savingLabel={t("developer_mode.custom_livekit_url.saving")}
cancelButtonLabel={t("developer_mode.custom_livekit_url.reset")} cancelButtonLabel={t("developer_mode.custom_livekit_url.reset")}
onSave={useCallback( onSave={useCallback(
(e: React.FormEvent<HTMLFormElement>) => { async (e: React.FormEvent<HTMLFormElement>): Promise<void> => {
setCustomLivekitUrl( if (
customLivekitUrlTextBuffer === "" customLivekitUrlTextBuffer === "" ||
? null customLivekitUrlTextBuffer === null
: customLivekitUrlTextBuffer, ) {
); setCustomLivekitUrl(null);
return Promise.resolve();
}
try {
logger.debug("try setting");
await getSFUConfigWithOpenID(
client,
customLivekitUrlTextBuffer,
"Test-room-alias-" + Date.now().toString() + client.getUserId(),
);
logger.debug("done setting! Success");
setCustomLivekitUrlUpdateError(null);
setCustomLivekitUrl(customLivekitUrlTextBuffer);
} catch (e) {
logger.error("failed setting", e);
setCustomLivekitUrlUpdateError("invalid URL (did not update)");
// automatically unset the error after 4 seconds (2 seconds will be for the save label)
setTimeout(() => {
logger.debug("unsetting error");
setCustomLivekitUrlUpdateError(null);
}, 2000);
}
}, },
[setCustomLivekitUrl, customLivekitUrlTextBuffer], [customLivekitUrlTextBuffer, setCustomLivekitUrl, client],
)} )}
value={customLivekitUrlTextBuffer ?? ""} value={customLivekitUrlTextBuffer ?? ""}
onChange={useCallback( onChange={useCallback(
@@ -252,7 +278,13 @@ export const DeveloperSettingsTab: FC<Props> = ({
}, },
[setCustomLivekitUrl], [setCustomLivekitUrl],
)} )}
/> >
{customLivekitUrlUpdateError !== null && (
<Text size="sm" priority="low">
{customLivekitUrlUpdateError}
</Text>
)}
</EditInPlace>
<Heading as="h3" type="body" weight="semibold" size="lg"> <Heading as="h3" type="body" weight="semibold" size="lg">
{t("developer_mode.matrixRTCMode.title")} {t("developer_mode.matrixRTCMode.title")}
</Heading> </Heading>

View File

@@ -62,19 +62,6 @@ export function useSetting<T>(setting: Setting<T>): [T, (value: T) => void] {
return [useBehavior(setting.value$), setting.setValue]; return [useBehavior(setting.value$), setting.setValue];
} }
/**
* React hook that returns a settings's current value and a setter.
*/
export function useSettingWithLastUpdateReason<T>(
setting: Setting<T>,
): [T, (value: T) => void, string | null] {
return [
useBehavior(setting.value$),
setting.setValue,
useBehavior(setting.lastUpdateReason$),
];
}
// null = undecided // null = undecided
export const optInAnalytics = new Setting<boolean | null>( export const optInAnalytics = new Setting<boolean | null>(
"opt-in-analytics", "opt-in-analytics",