diff --git a/striker-ui/components/FlexBox.tsx b/striker-ui/components/FlexBox.tsx index a910f84a..9d6359b0 100644 --- a/striker-ui/components/FlexBox.tsx +++ b/striker-ui/components/FlexBox.tsx @@ -26,6 +26,7 @@ const FlexBox: FC = ({ row: isRow, sx, ...muiBoxRestProps }) => { if (isRow) { rootSxAppend = { + alignItems: 'center', flexDirection: 'row', }; notFirstChildSxAppend = { diff --git a/striker-ui/components/StrikerInitForm.tsx b/striker-ui/components/StrikerInitForm.tsx index 52ce3431..b0105d12 100644 --- a/striker-ui/components/StrikerInitForm.tsx +++ b/striker-ui/components/StrikerInitForm.tsx @@ -1,6 +1,7 @@ import { Dispatch, FC, SetStateAction, useState } from 'react'; import { Box as MUIBox } from '@mui/material'; +import ContainedButton, { ContainedButtonProps } from './ContainedButton'; import FlexBox from './FlexBox'; import NetworkInitForm from './NetworkInitForm'; import { OutlinedInputProps } from './OutlinedInput'; @@ -37,6 +38,10 @@ export type MapToValueConverter = { [TypeName in keyof MapToType]: (value: unknown) => MapToType[TypeName]; }; +export type MapToValueIsEmptyFunction = { + [TypeName in keyof MapToType]: (value: MapToType[TypeName]) => boolean; +}; + export type InputOnChangeParameters = Parameters< Exclude >; @@ -46,6 +51,11 @@ const MAP_TO_VALUE_CONVERTER: MapToValueConverter = { string: (value) => String(value), }; +const MAP_TO_VALUE_IS_EMPTY_FUNCTION: MapToValueIsEmptyFunction = { + number: (value: number) => value === 0, + string: (value: string) => value.trim().length === 0, +}; + const createInputOnChangeHandler = ({ postSet, @@ -71,6 +81,36 @@ const createInputOnChangeHandler = postSet?.call(null, event); }; +const isEmpty = ( + values: Array, + { not, fn = 'every' }: { not?: boolean; fn?: 'every' | 'some' }, +) => + values[fn]((value) => { + const type = typeof value as TypeName; + + let result = MAP_TO_VALUE_IS_EMPTY_FUNCTION[type](value); + + if (not) { + result = !result; + } + + return result; + }); + +const createFunction = ( + { + conditionFn = () => true, + str = '', + condition = conditionFn() && str.length === 0, + }: { + condition?: boolean; + conditionFn?: (...args: unknown[]) => boolean; + str?: string; + }, + fn: () => unknown, + ...fnArgs: Parameters +) => (condition ? fn.bind(null, ...fnArgs) : undefined); + const buildOrganizationPrefix = (organizationName: string) => { const words: string[] = organizationName .split(/\s/) @@ -87,10 +127,17 @@ const buildHostName = ( hostNumber: number, domainName: string, ) => - organizationPrefix.length > 0 && hostNumber > 0 && domainName.length > 0 + isEmpty([organizationPrefix, hostNumber, domainName], { not: true }) ? `${organizationPrefix}-striker${pad(hostNumber)}.${domainName}` : ''; +const SuggestButton: FC = ({ onClick, ...restProps }) => + onClick ? ( + Suggest + ) : ( + <> + ); + const StrikerInitGeneralForm: FC = () => { const [organizationNameInput, setOrganizationNameInput] = useState(''); @@ -128,36 +175,58 @@ const StrikerInitGeneralForm: FC = () => { }, set: setHostNameInput, }); - const populateOrganizationPrefixInput = () => { - setOrganizationPrefixInput(buildOrganizationPrefix(organizationNameInput)); + const populateOrganizationPrefixInput = ({ + organizationName = organizationNameInput, + } = {}) => { + const organizationPrefix = buildOrganizationPrefix(organizationName); + + setOrganizationPrefixInput(organizationPrefix); + + return organizationPrefix; }; - const populateHostNameInput = () => { - setHostNameInput( - buildHostName(organizationPrefixInput, hostNumberInput, domainNameInput), - ); + const populateHostNameInput = ({ + organizationPrefix = organizationPrefixInput, + hostNumber = hostNumberInput, + domainName = domainNameInput, + } = {}) => { + const hostName = buildHostName(organizationPrefix, hostNumber, domainName); + + setHostNameInput(hostName); + + return hostName; }; - const createPopulateOnBlurHandler = - ( - { - condition = true, - toPopulate = '', - }: { condition?: boolean; toPopulate?: string }, - populate: (...args: unknown[]) => void, - ...populateArgs: Parameters - ) => - () => { - if (condition && toPopulate.length === 0) { - populate(...populateArgs); - } - }; - const populateOrganizationPrefixInputOnBlur = createPopulateOnBlurHandler( + const populateOrganizationPrefixInputOnBlur = createFunction( { condition: !isOrganizationPrefixInputUserChanged }, populateOrganizationPrefixInput, ); - const populateHostNameInputOnBlur = createPopulateOnBlurHandler( + const populateHostNameInputOnBlur = createFunction( { condition: !isHostNameInputUserChanged }, populateHostNameInput, ); + const handleOrganizationPrefixSuggest = createFunction( + { + conditionFn: () => + isOrganizationPrefixInputUserChanged && + isEmpty([organizationNameInput], { not: true }), + }, + () => { + const organizationPrefix = populateOrganizationPrefixInput(); + + if (!isHostNameInputUserChanged) { + populateHostNameInput({ organizationPrefix }); + } + }, + ); + const handlerHostNameSuggest = createFunction( + { + conditionFn: () => + isHostNameInputUserChanged && + isEmpty([organizationPrefixInput, hostNumberInput, domainNameInput], { + not: true, + }), + }, + populateHostNameInput, + ); return ( { onChange={handleOrganizationNameInputOnChange} value={organizationNameInput} /> - + + + + { onChange={handleHostNumberInputOnChange} value={hostNumberInput} /> - + :first-child': { flexGrow: 1 } }}> + + + );