Skip to content

Commit

Permalink
feat(TimeRangeSelector): added new input Time Range Selector (#216)
Browse files Browse the repository at this point in the history
  • Loading branch information
NasgulNexus authored Aug 12, 2024
1 parent 075e48b commit 2acde25
Show file tree
Hide file tree
Showing 38 changed files with 771 additions and 0 deletions.
135 changes: 135 additions & 0 deletions src/lib/kit/components/Inputs/TimeRangeSelector/TimeRangeSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import React from 'react';

import {Text} from '@gravity-ui/uikit';

import isString from 'lodash/isString';
import set from 'lodash/set';

import {
FieldValue,
ObjectIndependentInput,
StringSpec,
ValidateError,
isStringSpec,
} from '../../../../core';
import {END_TIME, START_TIME} from '../../../constants/common';

import {TimeRangeSelect} from './components';
import {filterTimeArray, validateArray} from './utils';

export const TimeRangeSelector: ObjectIndependentInput = (props) => {
const {spec, input, name, Layout} = props;

const [startTimeSpec, endTimeSpec] = React.useMemo(
() =>
[START_TIME, END_TIME].map((key) =>
isStringSpec(spec.properties?.[key])
? (spec.properties?.[key] as StringSpec<any, undefined, undefined>)
: undefined,
),
[spec.properties],
);

const {initialStartTimeOptions, initialEndTimeOptions, canBeFiltered} = React.useMemo(() => {
const [initialStartTimeOptions, initialEndTimeOptions] = [startTimeSpec, endTimeSpec].map(
(spec) => {
if (spec && spec.enum) {
return spec.enum.map((id) => ({
id,
value: id,
content: spec.viewSpec.selectParams?.meta?.[id] ? (
<div key={id}>
<Text>{spec.description?.[id] || id}</Text>
<Text color="secondary" as="div">
{spec.viewSpec.selectParams.meta[id]}
</Text>
</div>
) : (
spec.description?.[id] || id
),
key: id,
}));
}

return undefined;
},
);

const canBeFiltered =
initialStartTimeOptions &&
initialEndTimeOptions &&
validateArray(initialStartTimeOptions) &&
validateArray(initialEndTimeOptions);

return {
initialStartTimeOptions,
initialEndTimeOptions,
canBeFiltered,
};
}, [endTimeSpec, startTimeSpec]);

const {startTimeOptions, endTimeOptions} = React.useMemo(() => {
let startTimeOptions = initialStartTimeOptions;
let endTimeOptions = initialEndTimeOptions;

[START_TIME, END_TIME].forEach((key) => {
const time = input.value?.[key];

if (
isString(time) &&
canBeFiltered &&
initialEndTimeOptions &&
initialStartTimeOptions
) {
if (START_TIME === key) {
endTimeOptions = filterTimeArray(initialEndTimeOptions, time, 'greater');
} else {
startTimeOptions = filterTimeArray(initialStartTimeOptions, time, 'less');
}
}
});

return {startTimeOptions, endTimeOptions};
}, [canBeFiltered, initialEndTimeOptions, initialStartTimeOptions, input.value]);

const parentOnChange = React.useCallback(
(childName: string, childValue: FieldValue, childErrors?: Record<string, ValidateError>) =>
input.onChange(
(currentValue) =>
set({...currentValue}, childName.split(`${name}.`).join(''), childValue),
childErrors,
),
[input, name],
);

if (!startTimeSpec || !endTimeSpec || !startTimeOptions || !endTimeOptions) {
return null;
}

const content = (
<React.Fragment>
<TimeRangeSelect
spec={startTimeSpec}
name={`${name}.${START_TIME}`}
options={startTimeOptions}
value={input.value?.[START_TIME]}
handleChange={(value) => parentOnChange(START_TIME, value[0])}
props={props}
/>
<TimeRangeSelect
spec={endTimeSpec}
name={`${name}.${END_TIME}`}
options={endTimeOptions}
value={input.value?.[END_TIME]}
handleChange={(value) => parentOnChange(END_TIME, value[0])}
props={props}
/>
</React.Fragment>
);

if (Layout) {
return <Layout {...props}>{content}</Layout>;
}

return <React.Fragment>{content}</React.Fragment>;
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';

import {TIME_RANGE_SELECTOR, VALUE} from './helpers';

import {test} from '~playwright/core';
import {DynamicForm} from '~playwright/core/DynamicForm';
import {DynamicView} from '~playwright/core/DynamicView';

test.describe('TimeRangeSelector', () => {
test('default', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={TIME_RANGE_SELECTOR.default} />);

await expectScreenshot();
});

test('default value', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={TIME_RANGE_SELECTOR.defaultValue} />);

await expectScreenshot();
});

test('required', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={TIME_RANGE_SELECTOR.required} />);

await expectScreenshot();
});

test('description', async ({mount, expectScreenshot}) => {
await mount(<DynamicForm spec={TIME_RANGE_SELECTOR.desription} />);

await expectScreenshot();
});
});

test('TimeRangeSelector View', async ({mount, expectScreenshot}) => {
await mount(<DynamicView spec={TIME_RANGE_SELECTOR.default} value={VALUE} />);

await expectScreenshot();
});
185 changes: 185 additions & 0 deletions src/lib/kit/components/Inputs/TimeRangeSelector/__tests__/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import {FormValue, ObjectSpec, SpecTypes} from '../../../../../core';

const ENUM_START = [
'00:00',
'01:00',
'02:00',
'03:00',
'04:00',
'05:00',
'06:00',
'07:00',
'08:00',
'09:00',
'10:00',
'11:00',
'12:00',
'13:00',
'14:00',
'15:00',
'16:00',
'17:00',
'18:00',
'19:00',
'20:00',
'21:00',
'22:00',
];

const ENUM_END = [
'01:00',
'02:00',
'03:00',
'04:00',
'05:00',
'06:00',
'07:00',
'08:00',
'09:00',
'10:00',
'11:00',
'12:00',
'13:00',
'14:00',
'15:00',
'16:00',
'17:00',
'18:00',
'19:00',
'20:00',
'21:00',
'22:00',
'23:00',
];

export const TIME_RANGE_SELECTOR: Record<string, ObjectSpec> = {
default: {
type: SpecTypes.Object,
properties: {
start: {
enum: ENUM_START,
type: SpecTypes.String,
viewSpec: {
type: 'select',
layout: 'row',
layoutTitle: 'Start of launch',
placeholder: '00:00',
},
},
end: {
type: SpecTypes.String,
enum: ENUM_END,
viewSpec: {
type: 'select',
layout: 'row',
layoutTitle: 'End of launch',
placeholder: '01:00',
},
},
},
viewSpec: {
type: 'time_range_selector',
layout: 'transparent',
},
},
defaultValue: {
defaultValue: {
start: '03:00',
end: '06:00',
},
type: SpecTypes.Object,
properties: {
start: {
type: SpecTypes.String,
enum: ENUM_START,
viewSpec: {
type: 'select',
layout: 'row',
layoutTitle: 'Start of launch',
placeholder: '00:00',
},
},
end: {
type: SpecTypes.String,
enum: ENUM_END,
viewSpec: {
type: 'select',
layout: 'row',
layoutTitle: 'End of launch',
placeholder: '01:00',
},
},
},
viewSpec: {
type: 'time_range_selector',
layout: 'transparent',
},
},
required: {
type: SpecTypes.Object,
properties: {
start: {
required: true,
type: SpecTypes.String,
enum: ENUM_START,
viewSpec: {
type: 'select',
layout: 'row',
layoutTitle: 'Start of launch',
placeholder: '00:00',
},
},
end: {
required: true,
type: SpecTypes.String,
enum: ENUM_END,
viewSpec: {
type: 'select',
layout: 'row',
layoutTitle: 'End of launch',
placeholder: '01:00',
},
},
},
viewSpec: {
type: 'time_range_selector',
layout: 'transparent',
},
},
desription: {
type: SpecTypes.Object,
properties: {
start: {
type: SpecTypes.String,
enum: ENUM_START,
viewSpec: {
type: 'select',
layout: 'row',
layoutTitle: 'Start of launch',
layoutDescription: 'End of launch Description',
placeholder: '00:00',
},
},
end: {
type: SpecTypes.String,
enum: ENUM_END,
viewSpec: {
type: 'select',
layout: 'row',
layoutTitle: 'End of launch',
layoutDescription: 'End of launch Description',
placeholder: '01:00',
},
},
},
viewSpec: {
type: 'time_range_selector',
layout: 'transparent',
},
},
};

export const VALUE: FormValue = {
start: '10:00',
end: '20:00',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@import '../../../../../styles/variables.scss';

.#{$ns}time-range-select {
&__select {
min-width: 100px;
}

&__select-popup {
max-height: 250px;
}
}
Loading

0 comments on commit 2acde25

Please sign in to comment.