1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-28 17:55:15 +02:00
unleash.unleash/frontend/src/component/context/ContextForm/ContextForm.tsx
olav 24c11332b5 chore: update MUI to v5 (#923)
* refactor: update mui packages

* refactor: run mui codemods

* refactor: format files after codemods

* refactor: fix broken types

* refactor: clean up theme

* refactor: fix broken tests

* refactor: replace @mui/styles with tss-react

* refactor: move breakpoints into classes for tss

* refactor: fix crash on missing feature description

* refactor: remove void classNames

* refactor: adjust styles to new defaults

* refactor: remove broken rollout slider e2e test

* refactor: fix duplicate e2e testid

* refactor: update makeStyles after rebase

* refactor: add missing snapshot after rebase

* refactor: fix TableCellSortable focus styles

* refactor: use 1.4 as the default line-height

* refactor: hide webkit search field icons

* refactor: fix select box label

* refactor: make AutocompleteBox smaller

* refactor: make heading smaller

* refactor: fix toast close icon color

* refactor: update snapshots

* refactor: add missing test event awaits

* refactor: fix default button line-height
2022-05-02 15:52:41 +02:00

224 lines
8.2 KiB
TypeScript

import Input from 'component/common/Input/Input';
import { TextField, Button, Switch, Typography } from '@mui/material';
import { useStyles } from './ContextForm.styles';
import React, { useState, useEffect } from 'react';
import { Add } from '@mui/icons-material';
import { ILegalValue } from 'interfaces/context';
import { ContextFormChip } from 'component/context/ContectFormChip/ContextFormChip';
import { ContextFormChipList } from 'component/context/ContectFormChip/ContextFormChipList';
interface IContextForm {
contextName: string;
contextDesc: string;
legalValues: ILegalValue[];
stickiness: boolean;
setContextName: React.Dispatch<React.SetStateAction<string>>;
setContextDesc: React.Dispatch<React.SetStateAction<string>>;
setStickiness: React.Dispatch<React.SetStateAction<boolean>>;
setLegalValues: React.Dispatch<React.SetStateAction<ILegalValue[]>>;
handleSubmit: (e: any) => void;
onCancel: () => void;
errors: { [key: string]: string };
mode: 'Create' | 'Edit';
clearErrors: (key?: string) => void;
validateContext?: () => void;
setErrors: React.Dispatch<React.SetStateAction<Object>>;
}
const ENTER = 'Enter';
export const ContextForm: React.FC<IContextForm> = ({
children,
handleSubmit,
onCancel,
contextName,
contextDesc,
legalValues,
stickiness,
setContextName,
setContextDesc,
setLegalValues,
setStickiness,
errors,
mode,
validateContext,
setErrors,
clearErrors,
}) => {
const { classes: styles } = useStyles();
const [value, setValue] = useState('');
const [valueDesc, setValueDesc] = useState('');
const [valueFocused, setValueFocused] = useState(false);
const isMissingValue = valueDesc.trim() && !value.trim();
const isDuplicateValue = legalValues.some(legalValue => {
return legalValue.value.trim() === value.trim();
});
useEffect(() => {
setErrors(prev => ({
...prev,
tag: isMissingValue
? 'Value cannot be empty'
: isDuplicateValue
? 'Duplicate value'
: undefined,
}));
}, [setErrors, isMissingValue, isDuplicateValue]);
const onSubmit = (event: React.SyntheticEvent) => {
event.preventDefault();
handleSubmit(event);
};
const onKeyDown = (event: React.KeyboardEvent) => {
if (event.key === ENTER) {
event.preventDefault();
if (valueFocused) {
addLegalValue();
} else {
handleSubmit(event);
}
}
};
const sortLegalValues = (a: ILegalValue, b: ILegalValue) => {
return a.value.toLowerCase().localeCompare(b.value.toLowerCase());
};
const addLegalValue = () => {
const next: ILegalValue = {
value: value.trim(),
description: valueDesc.trim(),
};
if (next.value && !isDuplicateValue) {
setValue('');
setValueDesc('');
setLegalValues(prev => [...prev, next].sort(sortLegalValues));
}
};
const removeLegalValue = (value: ILegalValue) => {
setLegalValues(prev => prev.filter(p => p.value !== value.value));
};
return (
<form onSubmit={onSubmit} className={styles.form}>
<div className={styles.container}>
<p className={styles.inputDescription}>
What is your context name?
</p>
<Input
className={styles.input}
label="Context name"
value={contextName}
disabled={mode === 'Edit'}
onChange={e => setContextName(e.target.value.trim())}
error={Boolean(errors.name)}
errorText={errors.name}
onFocus={() => clearErrors('name')}
onBlur={validateContext}
autoFocus
/>
<p className={styles.inputDescription}>
What is this context for?
</p>
<TextField
className={styles.input}
label="Context description (optional)"
variant="outlined"
multiline
maxRows={4}
value={contextDesc}
size="small"
onChange={e => setContextDesc(e.target.value)}
/>
<p className={styles.inputDescription}>
Which values do you want to allow?
</p>
<div className={styles.tagContainer}>
<TextField
label="Legal value (optional)"
name="value"
className={styles.tagInput}
value={value}
error={Boolean(errors.tag)}
helperText={errors.tag}
variant="outlined"
size="small"
onChange={e => setValue(e.target.value)}
onKeyPress={e => onKeyDown(e)}
onBlur={() => setValueFocused(false)}
onFocus={() => setValueFocused(true)}
inputProps={{ maxLength: 100 }}
/>
<TextField
label="Value description (optional)"
className={styles.tagInput}
value={valueDesc}
variant="outlined"
size="small"
onChange={e => setValueDesc(e.target.value)}
onKeyPress={e => onKeyDown(e)}
onBlur={() => setValueFocused(false)}
onFocus={() => setValueFocused(true)}
inputProps={{ maxLength: 100 }}
/>
<Button
className={styles.tagButton}
startIcon={<Add />}
onClick={addLegalValue}
variant="outlined"
color="primary"
disabled={!value.trim() || isDuplicateValue}
>
Add
</Button>
</div>
<ContextFormChipList>
{legalValues.map(legalValue => {
return (
<ContextFormChip
key={legalValue.value}
label={legalValue.value}
description={legalValue.description}
onRemove={() => removeLegalValue(legalValue)}
/>
);
})}
</ContextFormChipList>
<p className={styles.inputHeader}>Custom stickiness</p>
<p>
By enabling stickiness on this context field you can use it
together with the flexible-rollout strategy. This will
guarantee a consistent behavior for specific values of this
context field. PS! Not all client SDK's support this feature
yet!{' '}
<a
href="https://docs.getunleash.io/advanced/stickiness"
target="_blank"
rel="noreferrer"
>
Read more
</a>
</p>
<div className={styles.switchContainer}>
<Switch
checked={stickiness}
value={stickiness}
onChange={() => setStickiness(!stickiness)}
/>
<Typography>{stickiness ? 'On' : 'Off'}</Typography>
</div>
</div>
<div className={styles.buttonContainer}>
{children}
<Button onClick={onCancel} className={styles.cancelButton}>
Cancel
</Button>
</div>
</form>
);
};