Files
team-planner/frontend/src/components/IdeasTable/EditableCell.tsx
vigdorov a81b1a8579
All checks were successful
continuous-integration/drone/push Build is passing
fix bus and translate to eus
2025-12-31 10:31:49 +03:00

128 lines
3.0 KiB
TypeScript

import { useState, useEffect, useRef } from 'react';
import {
TextField,
Select,
MenuItem,
Box,
ClickAwayListener,
} from '@mui/material';
import type { Idea } from '../../types/idea';
import { useUpdateIdea } from '../../hooks/useIdeas';
interface EditableCellProps {
idea: Idea;
field: keyof Idea;
value: string | null;
type?: 'text' | 'select';
options?: { value: string; label: string }[];
renderDisplay: (value: string | null) => React.ReactNode;
}
export function EditableCell({
idea,
field,
value,
type = 'text',
options,
renderDisplay,
}: EditableCellProps) {
const [isEditing, setIsEditing] = useState(false);
const [editValue, setEditValue] = useState(value ?? '');
const inputRef = useRef<HTMLInputElement>(null);
const updateIdea = useUpdateIdea();
useEffect(() => {
if (isEditing && inputRef.current) {
inputRef.current.focus();
inputRef.current.select();
}
}, [isEditing]);
const handleDoubleClick = () => {
setIsEditing(true);
setEditValue(value ?? '');
};
const handleSave = async () => {
setIsEditing(false);
if (editValue !== value) {
await updateIdea.mutateAsync({
id: idea.id,
dto: { [field]: editValue || null },
});
}
};
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
void handleSave();
} else if (e.key === 'Escape') {
setIsEditing(false);
setEditValue(value ?? '');
}
};
if (isEditing) {
if (type === 'select' && options) {
return (
<ClickAwayListener onClickAway={handleSave}>
<Select
size="small"
value={editValue}
onChange={(e) => {
setEditValue(e.target.value);
setTimeout(() => {
updateIdea.mutate({
id: idea.id,
dto: { [field]: e.target.value },
});
setIsEditing(false);
}, 0);
}}
onKeyDown={handleKeyDown}
autoFocus
sx={{ minWidth: 100 }}
MenuProps={{ disablePortal: true }}
>
{options.map((opt) => (
<MenuItem key={opt.value} value={opt.value}>
{opt.label}
</MenuItem>
))}
</Select>
</ClickAwayListener>
);
}
return (
<ClickAwayListener onClickAway={handleSave}>
<TextField
inputRef={inputRef}
size="small"
value={editValue}
onChange={(e) => setEditValue(e.target.value)}
onKeyDown={handleKeyDown}
onBlur={handleSave}
sx={{ minWidth: 100 }}
/>
</ClickAwayListener>
);
}
return (
<Box
onDoubleClick={handleDoubleClick}
sx={{
cursor: 'pointer',
minHeight: 24,
'&:hover': {
backgroundColor: 'action.hover',
borderRadius: 0.5,
},
}}
>
{renderDisplay(value)}
</Box>
);
}