mirror of
https://github.com/aliasvault/aliasvault.git
synced 2026-02-01 09:53:05 -05:00
Tweak folder pill UI in light mode, update auth settings debounce
This commit is contained in:
@@ -21,7 +21,7 @@ const FolderPill: React.FC<IFolderPillProps> = ({ folder, onClick }) => {
|
||||
return (
|
||||
<button
|
||||
onClick={onClick}
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-gray-100 dark:bg-gray-700/50 hover:bg-gray-200 dark:hover:bg-gray-600/50 border border-gray-200 dark:border-gray-600 rounded-full text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-orange-500/50"
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-white dark:bg-gray-700/50 hover:bg-gray-50 dark:hover:bg-gray-600/50 border border-gray-200 dark:border-gray-600 rounded-full text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-orange-500/50"
|
||||
>
|
||||
<svg
|
||||
className="w-3.5 h-3.5 text-orange-500 dark:text-orange-400 flex-shrink-0"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import * as Yup from 'yup';
|
||||
|
||||
@@ -66,6 +66,20 @@ const AuthSettings: React.FC = () => {
|
||||
const { setIsInitialLoading } = useLoading();
|
||||
|
||||
const urlSchema = createUrlSchema(t);
|
||||
const apiUrlDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const clientUrlDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
// Clean up debounce timers on unmount
|
||||
useEffect((): (() => void) => {
|
||||
return (): void => {
|
||||
if (apiUrlDebounceRef.current) {
|
||||
clearTimeout(apiUrlDebounceRef.current);
|
||||
}
|
||||
if (clientUrlDebounceRef.current) {
|
||||
clearTimeout(clientUrlDebounceRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
/**
|
||||
@@ -116,43 +130,57 @@ const AuthSettings: React.FC = () => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle custom API URL change
|
||||
* Handle custom API URL change.
|
||||
* Updates UI state immediately but debounces validation and storage writes to prevent concurrency issues.
|
||||
*/
|
||||
const handleCustomUrlChange = async (e: React.ChangeEvent<HTMLInputElement>) : Promise<void> => {
|
||||
const handleCustomUrlChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) : void => {
|
||||
const value = e.target.value;
|
||||
setCustomUrl(value);
|
||||
|
||||
try {
|
||||
await urlSchema.validateAt('apiUrl', { apiUrl: value });
|
||||
setErrors(prev => ({ ...prev, apiUrl: undefined }));
|
||||
await storage.setItem('local:apiUrl', value);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Yup.ValidationError) {
|
||||
setErrors(prev => ({ ...prev, apiUrl: error.message }));
|
||||
// On error we revert back to the aliasvault.net official hosted instance.
|
||||
await storage.setItem('local:apiUrl', AppInfo.DEFAULT_API_URL);
|
||||
await storage.setItem('local:clientUrl', AppInfo.DEFAULT_CLIENT_URL);
|
||||
}
|
||||
if (apiUrlDebounceRef.current) {
|
||||
clearTimeout(apiUrlDebounceRef.current);
|
||||
}
|
||||
};
|
||||
|
||||
apiUrlDebounceRef.current = setTimeout(async () => {
|
||||
try {
|
||||
await urlSchema.validateAt('apiUrl', { apiUrl: value });
|
||||
setErrors(prev => ({ ...prev, apiUrl: undefined }));
|
||||
await storage.setItem('local:apiUrl', value);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Yup.ValidationError) {
|
||||
setErrors(prev => ({ ...prev, apiUrl: error.message }));
|
||||
// On error we revert back to the aliasvault.net official hosted instance.
|
||||
await storage.setItem('local:apiUrl', AppInfo.DEFAULT_API_URL);
|
||||
await storage.setItem('local:clientUrl', AppInfo.DEFAULT_CLIENT_URL);
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}, [urlSchema]);
|
||||
|
||||
/**
|
||||
* Handle custom client URL change
|
||||
* Handle custom client URL change.
|
||||
* Updates UI state immediately but debounces validation and storage writes to prevent concurrency issues.
|
||||
*/
|
||||
const handleCustomClientUrlChange = async (e: React.ChangeEvent<HTMLInputElement>) : Promise<void> => {
|
||||
const handleCustomClientUrlChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) : void => {
|
||||
const value = e.target.value;
|
||||
setCustomClientUrl(value);
|
||||
|
||||
try {
|
||||
await urlSchema.validateAt('clientUrl', { clientUrl: value });
|
||||
setErrors(prev => ({ ...prev, clientUrl: undefined }));
|
||||
await storage.setItem('local:clientUrl', value);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Yup.ValidationError) {
|
||||
setErrors(prev => ({ ...prev, clientUrl: error.message }));
|
||||
}
|
||||
if (clientUrlDebounceRef.current) {
|
||||
clearTimeout(clientUrlDebounceRef.current);
|
||||
}
|
||||
};
|
||||
|
||||
clientUrlDebounceRef.current = setTimeout(async () => {
|
||||
try {
|
||||
await urlSchema.validateAt('clientUrl', { clientUrl: value });
|
||||
setErrors(prev => ({ ...prev, clientUrl: undefined }));
|
||||
await storage.setItem('local:clientUrl', value);
|
||||
} catch (error: unknown) {
|
||||
if (error instanceof Yup.ValidationError) {
|
||||
setErrors(prev => ({ ...prev, clientUrl: error.message }));
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}, [urlSchema]);
|
||||
|
||||
/**
|
||||
* Toggle global popup.
|
||||
|
||||
Reference in New Issue
Block a user