mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 17:00:15 +01:00
* 🔧 refactor: Improve accessibility and styling in ChatGroupItem and FilterPrompts components * 🔧 fix: Add button type and keyboard accessibility to dropdown menu trigger in ChatGroupItem * 🔧 fix(757): Enhance accessibility by updating aria-labels and adding localization for prompt groups * 🔧 fix(618): Update version to 0.3.1 and enhance accessibility in InfoHoverCard component * 🔧 fix(618): Update aria-label in InfoHoverCard to use dynamic text prop for improved accessibility * 🔧 fix: Enhance accessibility by updating aria-labels and roles in Conversations components * 🔧 fix(620): Enhance accessibility by adding tabIndex to Tabs.Content components in ArtifactTabs, Settings, and Speech components * refactor: remove RevokeKeysButton component and update related components for accessibility - Deleted RevokeKeysButton component. - Updated SharedLinks and General components to use Label for accessibility. - Enhanced Personalization component with aria-labelledby and aria-describedby attributes. - Refactored ConversationModeSwitch to use ToggleSwitch for better state management. - Improved AutoSendTextSelector with local state management and accessibility attributes. - Replaced Switch components with ToggleSwitch in various Speech and TTS components for consistency. - Added aria-labelledby attributes to Dropdown components for better accessibility. - Updated translation.json to include new localization keys and improved existing ones. - Enhanced Slider component to support aria attributes for better accessibility. * 🔧 fix: Enhance user feedback for API key operations with success and error messages * 🔧 fix: Update aria-labels in Avatar component for improved localization and accessibility * 🔧 fix: Refactor handleFile and handleDrop functions for improved readability and maintainability
140 lines
4.2 KiB
TypeScript
140 lines
4.2 KiB
TypeScript
import { LockIcon, Trash } from 'lucide-react';
|
|
import React, { useState, useCallback } from 'react';
|
|
import {
|
|
Label,
|
|
Input,
|
|
Button,
|
|
Spinner,
|
|
OGDialog,
|
|
OGDialogContent,
|
|
OGDialogTrigger,
|
|
OGDialogHeader,
|
|
OGDialogTitle,
|
|
} from '@librechat/client';
|
|
import { useDeleteUserMutation } from '~/data-provider';
|
|
import { useAuthContext } from '~/hooks/AuthContext';
|
|
import { LocalizeFunction } from '~/common';
|
|
import { useLocalize } from '~/hooks';
|
|
import { cn } from '~/utils';
|
|
|
|
const DeleteAccount = ({ disabled = false }: { title?: string; disabled?: boolean }) => {
|
|
const localize = useLocalize();
|
|
const { user, logout } = useAuthContext();
|
|
const { mutate: deleteUser, isLoading: isDeleting } = useDeleteUserMutation({
|
|
onMutate: () => logout(),
|
|
});
|
|
|
|
const [isDialogOpen, setDialogOpen] = useState<boolean>(false);
|
|
const [isLocked, setIsLocked] = useState(true);
|
|
|
|
const handleDeleteUser = () => {
|
|
if (!isLocked) {
|
|
deleteUser(undefined);
|
|
}
|
|
};
|
|
|
|
const handleInputChange = useCallback(
|
|
(newEmailInput: string) => {
|
|
const isEmailCorrect =
|
|
newEmailInput.trim().toLowerCase() === user?.email.trim().toLowerCase();
|
|
setIsLocked(!isEmailCorrect);
|
|
},
|
|
[user?.email],
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<OGDialog open={isDialogOpen} onOpenChange={setDialogOpen}>
|
|
<div className="flex items-center justify-between">
|
|
<Label id="delete-account-label">{localize('com_nav_delete_account')}</Label>
|
|
<OGDialogTrigger asChild>
|
|
<Button
|
|
aria-labelledby="delete-account-label"
|
|
variant="destructive"
|
|
onClick={() => setDialogOpen(true)}
|
|
disabled={disabled}
|
|
>
|
|
{localize('com_ui_delete')}
|
|
</Button>
|
|
</OGDialogTrigger>
|
|
</div>
|
|
<OGDialogContent className="w-11/12 max-w-md">
|
|
<OGDialogHeader>
|
|
<OGDialogTitle className="text-lg font-medium leading-6">
|
|
{localize('com_nav_delete_account_confirm')}
|
|
</OGDialogTitle>
|
|
</OGDialogHeader>
|
|
<div className="mb-8 text-sm text-black dark:text-white">
|
|
<ul className="font-semibold text-amber-600">
|
|
<li>{localize('com_nav_delete_warning')}</li>
|
|
<li>{localize('com_nav_delete_data_info')}</li>
|
|
</ul>
|
|
</div>
|
|
<div className="flex-col items-center justify-center">
|
|
<div className="mb-4">
|
|
{renderInput(
|
|
localize('com_nav_delete_account_email_placeholder'),
|
|
'email-confirm-input',
|
|
user?.email ?? '',
|
|
(e) => handleInputChange(e.target.value),
|
|
)}
|
|
</div>
|
|
{renderDeleteButton(handleDeleteUser, isDeleting, isLocked, localize)}
|
|
</div>
|
|
</OGDialogContent>
|
|
</OGDialog>
|
|
</>
|
|
);
|
|
};
|
|
|
|
const renderInput = (
|
|
label: string,
|
|
id: string,
|
|
value: string,
|
|
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void,
|
|
) => (
|
|
<div className="mb-4">
|
|
<label className="mb-1 block text-sm font-medium text-black dark:text-white" htmlFor={id}>
|
|
{label}
|
|
</label>
|
|
<Input id={id} onChange={onChange} placeholder={value} />
|
|
</div>
|
|
);
|
|
|
|
const renderDeleteButton = (
|
|
handleDeleteUser: () => void,
|
|
isDeleting: boolean,
|
|
isLocked: boolean,
|
|
localize: LocalizeFunction,
|
|
) => (
|
|
<button
|
|
className={cn(
|
|
'mt-4 flex w-full items-center justify-center rounded-lg bg-surface-tertiary px-4 py-2 transition-all duration-200',
|
|
isLocked ? 'cursor-not-allowed opacity-30' : 'bg-destructive text-destructive-foreground',
|
|
)}
|
|
onClick={handleDeleteUser}
|
|
disabled={isDeleting || isLocked}
|
|
>
|
|
{isDeleting ? (
|
|
<div className="flex h-6 justify-center">
|
|
<Spinner className="icon-sm m-auto" />
|
|
</div>
|
|
) : (
|
|
<>
|
|
{isLocked ? (
|
|
<>
|
|
<LockIcon className="size-5" />
|
|
<span className="ml-2">{localize('com_ui_locked')}</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<Trash className="size-5" />
|
|
<span className="ml-2">{localize('com_nav_delete_account_button')}</span>
|
|
</>
|
|
)}
|
|
</>
|
|
)}
|
|
</button>
|
|
);
|
|
|
|
export default DeleteAccount;
|