Skip to content

Commit

Permalink
✨(frontend) add formik time input component
Browse files Browse the repository at this point in the history
Add a component which enables the user to select a time
and give it to formik context, with a suggestions dropdown
  • Loading branch information
karabij committed Nov 30, 2022
1 parent 303d7e9 commit f12976b
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ const customDateInputTheme = (theme: ThemeType) => {
day: { extend: () => `border-radius: 2em; color: brand` },
extend: `border-radius: 1em; padding: 1em`,
},
maskedInput: {
extend: `font-family: roboto`,
},
};
};

Expand All @@ -34,16 +37,17 @@ export interface formikDatePickerProps {
onChange: (date: string) => void;
}

const nextYear = new Date();
nextYear.setFullYear(new Date().getFullYear() + 1);
const today = new Date();
today.setHours(0, 0, 0, 0);

const FormikDatePicker: FunctionComponent<formikDatePickerProps> = ({ ...props }) => {
const [field] = useField(props.name);
const [startingAtError, setStartingAtError] = useState(false);

const formikContext = useFormikContext();
const nextYear = new Date();
nextYear.setFullYear(new Date().getFullYear() + 1);
const intl = useIntl();
const today = new Date();
today.setHours(0, 0, 0, 0);

const theme = useTheme();
const onDateChange = (event: { value: string | string[] }) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import withFormik from '@bbbtech/storybook-formik';
import { ComponentMeta, ComponentStory } from '@storybook/react';
import { Time } from 'grommet-icons';
import React from 'react';
import FormikTimePicker from './FormikTimePicker';

export default {
title: 'Formik/TimePicker',
component: FormikTimePicker,
decorators: [withFormik],
} as ComponentMeta<typeof FormikTimePicker>;

const Template: ComponentStory<typeof FormikTimePicker> = (args, context) => (
<div>
{context.parameters.title}
<FormikTimePicker {...args} />
</div>
);

export const basicTimePicker = Template.bind({});

basicTimePicker.args = {
name: 'time',
isToday: true,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { useField, useFormikContext } from 'formik';
import { Box, TextInput, ThemeContext, ThemeType } from 'grommet';
import { Grommet } from 'grommet-icons';
import { normalizeColor } from 'grommet/utils';
import React, { FunctionComponent, useState } from 'react';
import { useTheme } from 'styled-components';
import { ArrayHelper } from '../../../../utils/helpers/array';

export interface FormikTimePickerProps {
name: string;
isToday: boolean;
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
}

const customTheme = (theme: ThemeType) => {
return {
global: {
focus: {
outline: {
color: normalizeColor('brand', theme),
},
},
},
};
};

const computeFirstSuggestion = (isToday: boolean, suggestionsArray: string[]): number => {
let result = null;

if (isToday) {
const today = new Date();
const minuteQuarter = Math.floor(today.getMinutes() / 15);
if (minuteQuarter != 3) {
result = ArrayHelper.findElementIndex(
suggestionsArray,
`${today.getHours()}:${(minuteQuarter + 1) * 15}`,
);
} else {
result = ArrayHelper.findElementIndex(suggestionsArray, `${today.getHours() + 1}:00`);
}
}
let firstSuggestionIndex = result ? result : 0;
return firstSuggestionIndex;
};

const computeSuggestions = (): string[] => {
let suggestions = ['00:00'];
let minutes: string = '00';
let hours: string = '00';

while (`${hours}:${minutes}` < '23:45') {
console.log(`${hours}:${minutes}`);
if (minutes == '45') {
hours = +hours >= 9 ? (+hours + 1).toString() : `0${(+hours + 1).toString()}`;
minutes = '00';
} else {
minutes = (+minutes + 15).toString();
}
suggestions.push(`${hours}:${minutes}`);
}
return suggestions;
};

const allSuggestions = computeSuggestions();

const FormikTimePicker: FunctionComponent<FormikTimePickerProps> = ({ ...props }) => {
const [field] = useField(props.name);
const formikContext = useFormikContext();
const theme = useTheme();
const [suggestions, setSuggestions] = useState(allSuggestions);

const onTimeInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const nextValue = event.target.value;
formikContext.setFieldValue(props.name, nextValue);
if (!nextValue) setSuggestions(allSuggestions);
else {
const regexp = new RegExp(`^${nextValue}`);
setSuggestions(allSuggestions.filter((s) => regexp.test(s)));
}
};

const onTimeSelectChange = (event: { target: HTMLElement | null; suggestion: any }) => {
const nextValue = event.suggestion;
formikContext.setFieldValue(props.name, nextValue);
};

const firstSuggestion = computeFirstSuggestion(props.isToday, suggestions);

return (
<ThemeContext.Extend value={customTheme(theme)}>
<Box>
<TextInput
defaultSuggestion={firstSuggestion}
onChange={onTimeInputChange}
onSuggestionSelect={onTimeSelectChange}
placeholder={suggestions[firstSuggestion]}
suggestions={suggestions}
value={field.value}
></TextInput>
</Box>
</ThemeContext.Extend>
);
};

export default FormikTimePicker;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default, FormikTimePickerProps } from './FormikTimePicker';

0 comments on commit f12976b

Please sign in to comment.