Update profile selector, new rename functionality, display options in alphabetical order
This commit is contained in:
@@ -21,7 +21,7 @@ import {
|
||||
SelectValue,
|
||||
} from './ui/select';
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from './ui/tooltip';
|
||||
import { Save, Trash2, Plus } from 'lucide-react';
|
||||
import { Save, Trash2, Plus, Pencil } from 'lucide-react';
|
||||
import { IconButtonWithTooltip } from './ui/icon-button-with-tooltip';
|
||||
import { MAX_PROFILES, type ScheduleProfile } from '../constants/defaults';
|
||||
|
||||
@@ -32,6 +32,7 @@ interface ProfileSelectorProps {
|
||||
onSwitchProfile: (profileId: string) => void;
|
||||
onSaveProfile: () => void;
|
||||
onSaveProfileAs: (name: string) => string | null;
|
||||
onRenameProfile: (profileId: string, newName: string) => void;
|
||||
onDeleteProfile: (profileId: string) => boolean;
|
||||
t: (key: string) => string;
|
||||
}
|
||||
@@ -43,20 +44,29 @@ export const ProfileSelector: React.FC<ProfileSelectorProps> = ({
|
||||
onSwitchProfile,
|
||||
onSaveProfile,
|
||||
onSaveProfileAs,
|
||||
onRenameProfile,
|
||||
onDeleteProfile,
|
||||
t,
|
||||
}) => {
|
||||
const [newProfileName, setNewProfileName] = useState('');
|
||||
const [isSaveAsMode, setIsSaveAsMode] = useState(false);
|
||||
const [isRenameMode, setIsRenameMode] = useState(false);
|
||||
const [renameName, setRenameName] = useState('');
|
||||
|
||||
const activeProfile = profiles.find(p => p.id === activeProfileId);
|
||||
const canDelete = profiles.length > 1;
|
||||
const canCreateNew = profiles.length < MAX_PROFILES;
|
||||
|
||||
// Sort profiles alphabetically (case-insensitive)
|
||||
const sortedProfiles = [...profiles].sort((a, b) =>
|
||||
a.name.toLowerCase().localeCompare(b.name.toLowerCase())
|
||||
);
|
||||
|
||||
const handleSelectChange = (value: string) => {
|
||||
if (value === '__new__') {
|
||||
// Enter "save as" mode
|
||||
setIsSaveAsMode(true);
|
||||
setIsRenameMode(false);
|
||||
setNewProfileName('');
|
||||
} else {
|
||||
// Confirm before switching if there are unsaved changes
|
||||
@@ -67,6 +77,7 @@ export const ProfileSelector: React.FC<ProfileSelectorProps> = ({
|
||||
}
|
||||
onSwitchProfile(value);
|
||||
setIsSaveAsMode(false);
|
||||
setIsRenameMode(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -114,6 +125,51 @@ export const ProfileSelector: React.FC<ProfileSelectorProps> = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleStartRename = () => {
|
||||
if (activeProfile) {
|
||||
setIsRenameMode(true);
|
||||
setIsSaveAsMode(false);
|
||||
setRenameName(activeProfile.name);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRename = () => {
|
||||
if (!renameName.trim() || !activeProfile) {
|
||||
return;
|
||||
}
|
||||
|
||||
const trimmedName = renameName.trim();
|
||||
|
||||
// Check if name is unchanged
|
||||
if (trimmedName === activeProfile.name) {
|
||||
setIsRenameMode(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for duplicate names (excluding current profile)
|
||||
const isDuplicate = profiles.some(
|
||||
p => p.id !== activeProfile.id && p.name.toLowerCase() === trimmedName.toLowerCase()
|
||||
);
|
||||
|
||||
if (isDuplicate) {
|
||||
alert(t('profileNameAlreadyExists') || 'A schedule with this name already exists');
|
||||
return;
|
||||
}
|
||||
|
||||
onRenameProfile(activeProfile.id, trimmedName);
|
||||
setIsRenameMode(false);
|
||||
setRenameName('');
|
||||
};
|
||||
|
||||
const handleRenameKeyDown = (e: React.KeyboardEvent) => {
|
||||
if (e.key === 'Enter') {
|
||||
handleRename();
|
||||
} else if (e.key === 'Escape') {
|
||||
setIsRenameMode(false);
|
||||
setRenameName('');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="mb-4">
|
||||
<CardContent className="pt-6">
|
||||
@@ -135,21 +191,32 @@ export const ProfileSelector: React.FC<ProfileSelectorProps> = ({
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder={t('profileSaveAsPlaceholder')}
|
||||
autoFocus
|
||||
className="h-9 rounded-r-none border-r-0 w-[360px] bg-background"
|
||||
className="h-9 rounded-r-none border-r-0 w-[288px] bg-background"
|
||||
/>
|
||||
) : isRenameMode ? (
|
||||
<Input
|
||||
id="profile-selector"
|
||||
type="text"
|
||||
value={renameName}
|
||||
onChange={(e) => setRenameName(e.target.value)}
|
||||
onKeyDown={handleRenameKeyDown}
|
||||
placeholder={t('profileRenamePlaceholder')}
|
||||
autoFocus
|
||||
className="h-9 rounded-r-none border-r-0 w-[288px] bg-background"
|
||||
/>
|
||||
) : (
|
||||
<Select
|
||||
value={activeProfileId}
|
||||
onValueChange={handleSelectChange}
|
||||
>
|
||||
<SelectTrigger id="profile-selector" className="h-9 rounded-r-none border-r-0 w-[360px] bg-background">
|
||||
<SelectTrigger id="profile-selector" className="h-9 rounded-r-none border-r-0 w-[288px] bg-background">
|
||||
<SelectValue>
|
||||
{activeProfile?.name}
|
||||
{hasUnsavedChanges && ' *'}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{profiles.map(profile => (
|
||||
{sortedProfiles.map(profile => (
|
||||
<SelectItem key={profile.id} value={profile.id}>
|
||||
{profile.name}
|
||||
</SelectItem>
|
||||
@@ -178,10 +245,21 @@ export const ProfileSelector: React.FC<ProfileSelectorProps> = ({
|
||||
|
||||
{/* Save button - integrated */}
|
||||
<IconButtonWithTooltip
|
||||
onClick={isSaveAsMode ? handleSaveAs : onSaveProfile}
|
||||
onClick={isSaveAsMode ? handleSaveAs : isRenameMode ? handleRename : onSaveProfile}
|
||||
icon={<Save className="h-4 w-4" />}
|
||||
tooltip={isSaveAsMode ? t('profileSaveAs') : t('profileSave')}
|
||||
disabled={(isSaveAsMode && !newProfileName.trim()) || (!isSaveAsMode && !hasUnsavedChanges)}
|
||||
tooltip={isSaveAsMode ? t('profileSaveAs') : isRenameMode ? t('profileRename') : t('profileSave')}
|
||||
disabled={(isSaveAsMode && !newProfileName.trim()) || (isRenameMode && !renameName.trim()) || (!isSaveAsMode && !isRenameMode && !hasUnsavedChanges)}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="rounded-none border-r-0"
|
||||
/>
|
||||
|
||||
{/* Rename button - integrated */}
|
||||
<IconButtonWithTooltip
|
||||
onClick={handleStartRename}
|
||||
icon={<Pencil className="h-4 w-4" />}
|
||||
tooltip={t('profileRename')}
|
||||
disabled={isSaveAsMode || isRenameMode}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="rounded-none border-r-0"
|
||||
@@ -192,7 +270,7 @@ export const ProfileSelector: React.FC<ProfileSelectorProps> = ({
|
||||
onClick={handleDelete}
|
||||
icon={<Trash2 className="h-4 w-4" />}
|
||||
tooltip={canDelete ? t('profileDelete') : t('profileDeleteDisabled')}
|
||||
disabled={!canDelete || isSaveAsMode}
|
||||
disabled={!canDelete || isSaveAsMode || isRenameMode}
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="rounded-l-none text-destructive hover:bg-destructive hover:text-destructive-foreground"
|
||||
@@ -216,6 +294,24 @@ export const ProfileSelector: React.FC<ProfileSelectorProps> = ({
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Helper text for rename mode */}
|
||||
{isRenameMode && (
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="text-xs text-muted-foreground flex-1">
|
||||
{t('profileRenameHelp')}
|
||||
</p>
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsRenameMode(false);
|
||||
setRenameName('');
|
||||
}}
|
||||
className="text-xs text-muted-foreground hover:text-foreground underline"
|
||||
>
|
||||
{t('cancel')}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user