Skip to content

Commit 146be13

Browse files
committed
refactor: Use formik and yup, and simplify hooks
This change converts the Image Editor Modal to typescript and simplifies the hooks switching to Formik + Yup for form validation. It updates the tests to check the behaviour of the component as a whole rather than testing small components.
1 parent 79307d7 commit 146be13

9 files changed

Lines changed: 475 additions & 951 deletions

File tree

src/editors/sharedComponents/ImageUploadModal/ImageSettingsModal/AltTextControls.test.tsx

Lines changed: 0 additions & 62 deletions
This file was deleted.

src/editors/sharedComponents/ImageUploadModal/ImageSettingsModal/AltTextControls.tsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
<<<<<<< Updated upstream
12
import React from 'react';
23
import PropTypes from 'prop-types';
34

@@ -67,6 +68,60 @@ AltTextControls.propTypes = {
6768
show: PropTypes.bool,
6869
}).isRequired,
6970
value: PropTypes.string.isRequired,
71+
||||||| Stash base
72+
=======
73+
import { useFormikContext } from 'formik';
74+
import React from 'react';
75+
76+
import { Form } from '@openedx/paragon';
77+
import { useIntl } from '@edx/frontend-platform/i18n';
78+
import {
79+
ImageConfig,
80+
} from './types';
81+
82+
import messages from './messages';
83+
84+
const AltTextControls = () => {
85+
const intl = useIntl();
86+
const formik = useFormikContext<ImageConfig>();
87+
return (
88+
<>
89+
<Form.Group className="mt-1.5">
90+
<Form.Label>
91+
{intl.formatMessage(messages.accessibilityLabel)}
92+
</Form.Label>
93+
<Form.Control
94+
name="altText"
95+
className="mt-1.5"
96+
floatingLabel={intl.formatMessage(messages.altTextFloatingLabel)}
97+
disabled={formik.values.isDecorative}
98+
isInvalid={formik.errors.altText}
99+
onChange={formik.handleChange}
100+
type="input"
101+
value={formik.values.altText}
102+
/>
103+
{formik.errors.altText
104+
&& (
105+
<Form.Control.Feedback type="invalid">
106+
{formik.errors.altText}
107+
</Form.Control.Feedback>
108+
)}
109+
</Form.Group>
110+
<Form.Group>
111+
<Form.Checkbox
112+
name="isDecorative"
113+
checked={formik.values.isDecorative}
114+
className="mt-2.5 decorative-control-label"
115+
onChange={formik.handleChange}
116+
>
117+
<Form.Label>
118+
{intl.formatMessage(messages.decorativeAltTextCheckboxLabel)}
119+
</Form.Label>
120+
</Form.Checkbox>
121+
</Form.Group>
122+
</>
123+
);
124+
>>>>>>> Stashed changes
70125
};
71126

72127
export const AltTextControlsInternal = AltTextControls; // For testing only

src/editors/sharedComponents/ImageUploadModal/ImageSettingsModal/DimensionControls.test.tsx

Lines changed: 0 additions & 111 deletions
This file was deleted.

src/editors/sharedComponents/ImageUploadModal/ImageSettingsModal/DimensionControls.tsx

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
<<<<<<< Updated upstream
12
import React from 'react';
23
import PropTypes from 'prop-types';
34
import {
@@ -88,5 +89,103 @@ DimensionControls.propTypes = ({
8889
unlock: PropTypes.func.isRequired,
8990
updateDimensions: PropTypes.func.isRequired,
9091
});
92+
||||||| Stash base
93+
=======
94+
import { useFormikContext } from 'formik';
95+
import React from 'react';
96+
import {
97+
Form,
98+
Icon,
99+
IconButton,
100+
} from '@openedx/paragon';
101+
import {
102+
Locked,
103+
Unlocked,
104+
} from '@openedx/paragon/icons';
105+
import { useIntl } from '@edx/frontend-platform/i18n';
106+
import {
107+
ImageConfig,
108+
} from './types';
109+
110+
import messages from './messages';
111+
112+
/**
113+
* Wrapper for image dimension inputs and the lock checkbox.
114+
* @param {ImageDimensions} originalDimensions - original dimensions of the image
115+
*/
116+
const DimensionControls = ({ originalWidth, originalHeight }: {
117+
originalWidth: number,
118+
originalHeight: number,
119+
}) => {
120+
const intl = useIntl();
121+
const formik = useFormikContext<ImageConfig>();
122+
if (!(originalWidth && originalHeight)) {
123+
return null;
124+
}
125+
const handleUpdateDimensions = async ({ target }) => {
126+
const { name } = target;
127+
let { value } = target;
128+
// If dimensions are locked just set the value and return.
129+
await formik.setFieldValue(name, value);
130+
if (!formik.values.isLocked) {
131+
return;
132+
}
133+
// For percentages, both values need to be ratio is locked
134+
if (value.trim().endsWith('%')) {
135+
await formik.setFieldValue('width', value);
136+
await formik.setFieldValue('height', value);
137+
return;
138+
}
139+
// For numerical values we calculate the other dimension based on the original ratio.
140+
value = parseInt(value, 10);
141+
if (name === 'height') {
142+
await formik.setFieldValue('width', Math.round((value / originalHeight) * originalWidth));
143+
} else if (name === 'width') {
144+
await formik.setFieldValue('height', Math.round((value / originalWidth) * originalHeight));
145+
}
146+
};
147+
return (
148+
<>
149+
<Form.Label>
150+
{intl.formatMessage(messages.imageDimensionsLabel)}
151+
</Form.Label>
152+
<div className="mb-4.5 d-flex">
153+
<Form.Group>
154+
<Form.Control
155+
name="width"
156+
className="dimension-input"
157+
value={formik.values.width}
158+
onChange={handleUpdateDimensions}
159+
onBlur={formik.handleBlur}
160+
floatingLabel={intl.formatMessage(messages.widthFloatingLabel)}
161+
/>
162+
</Form.Group>
163+
<Form.Group>
164+
<Form.Control
165+
name="height"
166+
className="dimension-input"
167+
value={formik.values.height}
168+
onChange={handleUpdateDimensions}
169+
onBlur={formik.handleBlur}
170+
floatingLabel={intl.formatMessage(messages.heightFloatingLabel)}
171+
/>
172+
</Form.Group>
173+
<IconButton
174+
name="isLocked"
175+
className="d-inline-block"
176+
alt={
177+
formik.values.isLocked
178+
? intl.formatMessage(messages.unlockDimensionsLabel)
179+
: intl.formatMessage(messages.lockDimensionsLabel)
180+
}
181+
iconAs={Icon}
182+
src={formik.values.isLocked ? Locked : Unlocked}
183+
onClick={() => formik.setFieldValue('isLocked', !formik.values.isLocked)}
184+
/>
185+
</div>
186+
</>
187+
);
188+
};
189+
>>>>>>> Stashed changes
91190

92191
export default DimensionControls;

0 commit comments

Comments
 (0)