Refactor/display input part 2 (#1555)

* Email - Money - Number

* Date
This commit is contained in:
Lucas Bordeau
2023-09-12 20:04:26 +02:00
committed by GitHub
parent 9b495ae2e8
commit 9b5e24105b
33 changed files with 348 additions and 295 deletions

View File

@ -1,6 +1,7 @@
import { useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { DateDisplay } from '@/ui/content-display/components/DateDisplay';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { EditableFieldDefinitionContext } from '../contexts/EditableFieldDefinitionContext';
@ -11,7 +12,6 @@ import { FieldDefinition } from '../types/FieldDefinition';
import { FieldDateMetadata } from '../types/FieldMetadata';
import { EditableField } from './EditableField';
import { GenericEditableDateFieldDisplayMode } from './GenericEditableDateFieldDisplayMode';
import { GenericEditableDateFieldEditMode } from './GenericEditableDateFieldEditMode';
export function GenericEditableDateField() {
@ -34,7 +34,7 @@ export function GenericEditableDateField() {
<EditableField
IconLabel={currentEditableFieldDefinition.Icon}
editModeContent={<GenericEditableDateFieldEditMode />}
displayModeContent={<GenericEditableDateFieldDisplayMode />}
displayModeContent={<DateDisplay value={fieldValue} />}
isDisplayModeContentEmpty={!fieldValue}
/>
</RecoilScope>

View File

@ -1,33 +0,0 @@
import { useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { DateInputDisplay } from '@/ui/input/components/DateInputDisplay';
import { parseDate } from '~/utils/date-utils';
import { EditableFieldDefinitionContext } from '../contexts/EditableFieldDefinitionContext';
import { EditableFieldEntityIdContext } from '../contexts/EditableFieldEntityIdContext';
import { genericEntityFieldFamilySelector } from '../states/selectors/genericEntityFieldFamilySelector';
import { FieldDefinition } from '../types/FieldDefinition';
import { FieldDateMetadata } from '../types/FieldMetadata';
export function GenericEditableDateFieldDisplayMode() {
const currentEditableFieldEntityId = useContext(EditableFieldEntityIdContext);
const currentEditableFieldDefinition = useContext(
EditableFieldDefinitionContext,
) as FieldDefinition<FieldDateMetadata>;
const fieldValue = useRecoilValue<string>(
genericEntityFieldFamilySelector({
entityId: currentEditableFieldEntityId ?? '',
fieldName: currentEditableFieldDefinition
? currentEditableFieldDefinition.metadata.fieldName
: '',
}),
);
const internalDateValue = fieldValue
? parseDate(fieldValue).toJSDate()
: null;
return <DateInputDisplay value={internalDateValue} />;
}

View File

@ -1,13 +1,17 @@
import { useContext } from 'react';
import { useRecoilState } from 'recoil';
import { DateInput } from '@/ui/input/components/DateInput';
import { Nullable } from '~/types/Nullable';
import { EditableFieldDefinitionContext } from '../contexts/EditableFieldDefinitionContext';
import { EditableFieldEntityIdContext } from '../contexts/EditableFieldEntityIdContext';
import { useFieldInputEventHandlers } from '../hooks/useFieldInputEventHandlers';
import { useUpdateGenericEntityField } from '../hooks/useUpdateGenericEntityField';
import { genericEntityFieldFamilySelector } from '../states/selectors/genericEntityFieldFamilySelector';
import { EditableFieldHotkeyScope } from '../types/EditableFieldHotkeyScope';
import { FieldDefinition } from '../types/FieldDefinition';
import { FieldDateMetadata } from '../types/FieldMetadata';
import { EditableFieldEditModeDate } from '../variants/components/EditableFieldEditModeDate';
export function GenericEditableDateFieldEditMode() {
const currentEditableFieldEntityId = useContext(EditableFieldEntityIdContext);
@ -27,7 +31,21 @@ export function GenericEditableDateFieldEditMode() {
const updateField = useUpdateGenericEntityField();
function handleSubmit(newDateISO: string) {
function handleSubmit(newDate: Nullable<Date>) {
if (!newDate) {
setFieldValue('');
if (currentEditableFieldEntityId && updateField) {
updateField(
currentEditableFieldEntityId,
currentEditableFieldDefinition,
'',
);
}
}
const newDateISO = newDate?.toISOString();
if (newDateISO === fieldValue || !newDateISO) return;
setFieldValue(newDateISO);
@ -41,7 +59,18 @@ export function GenericEditableDateFieldEditMode() {
}
}
const { handleEnter, handleEscape, handleClickOutside } =
useFieldInputEventHandlers({
onSubmit: handleSubmit,
});
return (
<EditableFieldEditModeDate value={fieldValue} onChange={handleSubmit} />
<DateInput
hotkeyScope={EditableFieldHotkeyScope.EditableField}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
value={fieldValue ? new Date(fieldValue) : null}
/>
);
}

View File

@ -1,6 +1,7 @@
import { useContext } from 'react';
import { useRecoilValue } from 'recoil';
import { TextDisplay } from '@/ui/content-display/components/TextDisplay';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { EditableFieldDefinitionContext } from '../contexts/EditableFieldDefinitionContext';
@ -33,7 +34,7 @@ export function GenericEditableNumberField() {
<EditableField
IconLabel={currentEditableFieldDefinition.Icon}
editModeContent={<GenericEditableNumberFieldEditMode />}
displayModeContent={fieldValue}
displayModeContent={<TextDisplay text={fieldValue} />}
isDisplayModeContentEmpty={!fieldValue}
/>
</RecoilScope>

View File

@ -1,7 +1,7 @@
import { useContext, useRef, useState } from 'react';
import { useContext } from 'react';
import { useRecoilState } from 'recoil';
import { TextInputEdit } from '@/ui/input/text/components/TextInputEdit';
import { TextInput } from '@/ui/input/components/TextInput';
import {
canBeCastAsIntegerOrNull,
castAsIntegerOrNull,
@ -9,9 +9,10 @@ import {
import { EditableFieldDefinitionContext } from '../contexts/EditableFieldDefinitionContext';
import { EditableFieldEntityIdContext } from '../contexts/EditableFieldEntityIdContext';
import { useRegisterCloseFieldHandlers } from '../hooks/useRegisterCloseFieldHandlers';
import { useFieldInputEventHandlers } from '../hooks/useFieldInputEventHandlers';
import { useUpdateGenericEntityField } from '../hooks/useUpdateGenericEntityField';
import { genericEntityFieldFamilySelector } from '../states/selectors/genericEntityFieldFamilySelector';
import { EditableFieldHotkeyScope } from '../types/EditableFieldHotkeyScope';
import { FieldDefinition } from '../types/FieldDefinition';
import { FieldNumberMetadata } from '../types/FieldMetadata';
@ -30,51 +31,43 @@ export function GenericEditableNumberFieldEditMode() {
: '',
}),
);
const [internalValue, setInternalValue] = useState(
fieldValue ? fieldValue.toString() : '',
);
const updateField = useUpdateGenericEntityField();
const wrapperRef = useRef(null);
useRegisterCloseFieldHandlers(wrapperRef, handleSubmit, onCancel);
function handleSubmit() {
if (!canBeCastAsIntegerOrNull(internalValue)) {
function handleSubmit(newValue: string) {
if (!canBeCastAsIntegerOrNull(newValue)) {
return;
}
if (internalValue === fieldValue) return;
setFieldValue(castAsIntegerOrNull(internalValue));
if (newValue === fieldValue) return;
const castedValue = castAsIntegerOrNull(newValue);
setFieldValue(castedValue);
if (currentEditableFieldEntityId && updateField) {
updateField(
currentEditableFieldEntityId,
currentEditableFieldDefinition,
castAsIntegerOrNull(internalValue),
castedValue,
);
}
}
function onCancel() {
setFieldValue(fieldValue);
}
function handleChange(newValue: string) {
setInternalValue(newValue);
}
const { handleEnter, handleEscape, handleClickOutside } =
useFieldInputEventHandlers({
onSubmit: handleSubmit,
});
return (
<div ref={wrapperRef}>
<TextInputEdit
autoFocus
placeholder={currentEditableFieldDefinition.metadata.placeHolder}
value={internalValue ? internalValue.toString() : ''}
onChange={(newValue: string) => {
handleChange(newValue);
}}
/>
</div>
<TextInput
autoFocus
placeholder={currentEditableFieldDefinition.metadata.placeHolder}
hotkeyScope={EditableFieldHotkeyScope.EditableField}
value={fieldValue ? fieldValue.toString() : ''}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
/>
);
}

View File

@ -1,7 +1,7 @@
import { DateDisplay } from '@/ui/content-display/components/DateDisplay';
import { EditableField } from '@/ui/editable-field/components/EditableField';
import { FieldRecoilScopeContext } from '@/ui/editable-field/states/recoil-scope-contexts/FieldRecoilScopeContext';
import { IconComponent } from '@/ui/icon/types/IconComponent';
import { DateInputDisplay } from '@/ui/input/components/DateInputDisplay';
import { RecoilScope } from '@/ui/utilities/recoil-scope/components/RecoilScope';
import { parseDate } from '~/utils/date-utils';
@ -12,9 +12,16 @@ type OwnProps = {
label?: string;
value: string | null | undefined;
onSubmit?: (newValue: string) => void;
hotkeyScope: string;
};
export function DateEditableField({ Icon, value, label, onSubmit }: OwnProps) {
export function DateEditableField({
Icon,
value,
label,
onSubmit,
hotkeyScope,
}: OwnProps) {
async function handleChange(newValue: string) {
onSubmit?.(newValue);
}
@ -24,8 +31,6 @@ export function DateEditableField({ Icon, value, label, onSubmit }: OwnProps) {
return (
<RecoilScope SpecificContext={FieldRecoilScopeContext}>
<EditableField
// onSubmit={handleSubmit}
// onCancel={handleCancel}
IconLabel={Icon}
label={label}
editModeContent={
@ -34,9 +39,10 @@ export function DateEditableField({ Icon, value, label, onSubmit }: OwnProps) {
onChange={(newValue: string) => {
handleChange(newValue);
}}
parentHotkeyScope={hotkeyScope}
/>
}
displayModeContent={<DateInputDisplay value={internalDateValue} />}
displayModeContent={<DateDisplay value={internalDateValue} />}
isDisplayModeContentEmpty={!value}
/>
</RecoilScope>

View File

@ -1,7 +1,7 @@
import { useEffect, useState } from 'react';
import { DateInputEdit } from '@/ui/input/components/DateInputEdit';
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
import { DateInput } from '@/ui/input/components/DateInput';
import { Nullable } from '~/types/Nullable';
import { parseDate } from '~/utils/date-utils';
import { useEditableField } from '../../hooks/useEditableField';
@ -9,10 +9,15 @@ import { useEditableField } from '../../hooks/useEditableField';
type OwnProps = {
value: string;
onChange?: (newValue: string) => void;
parentHotkeyScope?: HotkeyScope;
parentHotkeyScope: string;
};
export function EditableFieldEditModeDate({ value, onChange }: OwnProps) {
// TODO: refactor this component to use the same logic as the GenericDateField component
export function EditableFieldEditModeDate({
value,
onChange,
parentHotkeyScope,
}: OwnProps) {
const [internalValue, setInternalValue] = useState(value);
useEffect(() => {
@ -21,17 +26,26 @@ export function EditableFieldEditModeDate({ value, onChange }: OwnProps) {
const { closeEditableField } = useEditableField();
function handleChange(newValue: string) {
onChange?.(newValue);
function handleClickOutside() {
closeEditableField();
}
function handleEnter(newValue: Nullable<Date>) {
onChange?.(newValue?.toISOString() ?? '');
closeEditableField();
}
function handleEscape() {
closeEditableField();
}
return (
<DateInputEdit
<DateInput
value={internalValue ? parseDate(internalValue).toJSDate() : new Date()}
onChange={(newDate: Date) => {
handleChange(newDate.toISOString());
}}
hotkeyScope={parentHotkeyScope}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
/>
);
}