@atlaskit/feedback-collector 14.3.3 → 14.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @atlaskit/feedback-collector
2
2
 
3
+ ## 14.3.4
4
+
5
+ ### Patch Changes
6
+
7
+ - [`94ba8d27dba35`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/94ba8d27dba35) -
8
+ [ux] enable the submit button by default for a11y, validate and prevent submission if required
9
+ fields are not complete
10
+
3
11
  ## 14.3.3
4
12
 
5
13
  ### Patch Changes
@@ -163,7 +163,7 @@ var FeedbackCollector = exports.default = /*#__PURE__*/function (_Component) {
163
163
  }, {
164
164
  key: "getPackageVersion",
165
165
  value: function getPackageVersion() {
166
- return "14.3.2" || 'Unknown, at least 11.0.0';
166
+ return "14.3.3" || 'Unknown, at least 11.0.0';
167
167
  }
168
168
  }, {
169
169
  key: "getEntitlementInformation",
@@ -19,6 +19,7 @@ var _checkbox = require("@atlaskit/checkbox");
19
19
  var _form = _interopRequireWildcard(require("@atlaskit/form"));
20
20
  var _link = _interopRequireDefault(require("@atlaskit/link"));
21
21
  var _modalDialog = _interopRequireWildcard(require("@atlaskit/modal-dialog"));
22
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
22
23
  var _sectionMessage = _interopRequireDefault(require("@atlaskit/section-message"));
23
24
  var _select = _interopRequireDefault(require("@atlaskit/select"));
24
25
  var _textarea = _interopRequireDefault(require("@atlaskit/textarea"));
@@ -74,6 +75,10 @@ var FeedbackForm = function FeedbackForm(_ref) {
74
75
  _useState0 = (0, _slicedToArray2.default)(_useState9, 2),
75
76
  isSubmitting = _useState0[0],
76
77
  setIsSubmitting = _useState0[1];
78
+ var _useState1 = (0, _react.useState)({}),
79
+ _useState10 = (0, _slicedToArray2.default)(_useState1, 2),
80
+ validationErrors = _useState10[0],
81
+ setValidationErrors = _useState10[1];
77
82
  var _useIntl = (0, _reactIntlNext.useIntl)(),
78
83
  formatMessage = _useIntl.formatMessage;
79
84
  var isTypeSelected = function isTypeSelected() {
@@ -81,7 +86,26 @@ var FeedbackForm = function FeedbackForm(_ref) {
81
86
  };
82
87
  var canShowTextField = isTypeSelected() || !showTypeField;
83
88
  var hasDescription = description || hasDescriptionDefaultValue;
84
- var isDisabled = disableSubmitButton || (showTypeField ? !isTypeSelected() || !hasDescription : !hasDescription);
89
+
90
+ // Feature flag determines validation behavior
91
+ var useNewValidation = (0, _platformFeatureFlags.fg)('feedback-collector-custom-validation');
92
+ var isDisabled = useNewValidation ? isSubmitting || disableSubmitButton // New: only disable when submitting or explicitly disabled
93
+ : disableSubmitButton || (showTypeField ? !isTypeSelected() || !hasDescription : !hasDescription); // Old: disable based on form validation
94
+
95
+ var getValidationErrors = function getValidationErrors() {
96
+ var errors = {};
97
+
98
+ // Validate type selection if showTypeField is true
99
+ if (showTypeField && !isTypeSelected()) {
100
+ errors.type = formatMessage(_messages.messages.validationErrorTypeRequired);
101
+ }
102
+
103
+ // Validate description if showDefaultTextFields is true
104
+ if (showDefaultTextFields && !hasDescription) {
105
+ errors.description = formatMessage(_messages.messages.validationErrorDescriptionRequired);
106
+ }
107
+ return errors;
108
+ };
85
109
  var getFieldLabels = function getFieldLabels(record) {
86
110
  var _record$bug, _record$comment, _record$suggestion, _record$question, _record$empty, _record$not_relevant, _record$not_accurate, _record$too_slow, _record$unhelpful_lin, _record$other;
87
111
  return {
@@ -127,24 +151,42 @@ var FeedbackForm = function FeedbackForm(_ref) {
127
151
  shouldScrollInViewport: true
128
152
  }, /*#__PURE__*/_react.default.createElement(_form.default, {
129
153
  onSubmit: /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
154
+ var errors;
130
155
  return _regenerator.default.wrap(function _callee$(_context) {
131
156
  while (1) switch (_context.prev = _context.next) {
132
157
  case 0:
158
+ if (!useNewValidation) {
159
+ _context.next = 5;
160
+ break;
161
+ }
162
+ // New validation: validate on submit and show errors
163
+ errors = getValidationErrors(); // If there are validation errors, show them and don't submit
164
+ if (!(Object.keys(errors).length > 0)) {
165
+ _context.next = 5;
166
+ break;
167
+ }
168
+ setValidationErrors(errors);
169
+ return _context.abrupt("return");
170
+ case 5:
171
+ // Submit the form (both old and new validation paths reach here)
133
172
  setIsSubmitting(true);
134
- _context.next = 3;
173
+ _context.prev = 6;
174
+ _context.next = 9;
135
175
  return onSubmit({
136
176
  canBeContacted: canBeContacted,
137
177
  description: description,
138
178
  enrollInResearchGroup: enrollInResearchGroup,
139
179
  type: type
140
180
  });
141
- case 3:
181
+ case 9:
182
+ _context.prev = 9;
142
183
  setIsSubmitting(false);
143
- case 4:
184
+ return _context.finish(9);
185
+ case 12:
144
186
  case "end":
145
187
  return _context.stop();
146
188
  }
147
- }, _callee);
189
+ }, _callee, null, [[6,, 9, 12]]);
148
190
  }))
149
191
  }, function (_ref3) {
150
192
  var formProps = _ref3.formProps;
@@ -166,12 +208,20 @@ var FeedbackForm = function FeedbackForm(_ref) {
166
208
  var _ref4$fieldProps = _ref4.fieldProps,
167
209
  id = _ref4$fieldProps.id,
168
210
  restProps = (0, _objectWithoutProperties2.default)(_ref4$fieldProps, _excluded);
169
- return /*#__PURE__*/_react.default.createElement(_select.default, (0, _extends2.default)({}, restProps, {
211
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_select.default, (0, _extends2.default)({}, restProps, {
170
212
  onChange: function onChange(option) {
171
213
  if (!option || option instanceof Array) {
172
214
  return;
173
215
  }
174
216
  setType(option.value);
217
+ // Clear validation error when user selects a type (only for new validation)
218
+ if (useNewValidation && validationErrors.type) {
219
+ setValidationErrors(function (prev) {
220
+ return _objectSpread(_objectSpread({}, prev), {}, {
221
+ type: undefined
222
+ });
223
+ });
224
+ }
175
225
  },
176
226
  menuPortalTarget: document.body,
177
227
  styles: {
@@ -187,22 +237,30 @@ var FeedbackForm = function FeedbackForm(_ref) {
187
237
  ref: focusRef,
188
238
  placeholder: getDefaultPlaceholder(feedbackGroupLabels),
189
239
  inputId: id
190
- }));
240
+ })), useNewValidation && validationErrors.type && /*#__PURE__*/_react.default.createElement(_form.ErrorMessage, null, validationErrors.type));
191
241
  }) : null, showDefaultTextFields && canShowTextField && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_form.Field, {
192
242
  label: showTypeField ? getFieldLabels(feedbackGroupLabels)[type] : customTextAreaLabel || formatMessage(_messages.messages.defaultCustomTextAreaLabel),
193
243
  isRequired: true,
194
244
  name: "description"
195
245
  }, function (_ref5) {
196
246
  var fieldProps = _ref5.fieldProps;
197
- return /*#__PURE__*/_react.default.createElement(_textarea.default, (0, _extends2.default)({}, fieldProps, {
247
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_textarea.default, (0, _extends2.default)({}, fieldProps, {
198
248
  name: "foo",
199
249
  minimumRows: 6,
200
250
  placeholder: summaryPlaceholder || undefined,
201
251
  onChange: function onChange(e) {
202
- return setDescription(e.target.value);
252
+ setDescription(e.target.value);
253
+ // Clear validation error when user types
254
+ if (useNewValidation && validationErrors.description) {
255
+ setValidationErrors(function (prev) {
256
+ return _objectSpread(_objectSpread({}, prev), {}, {
257
+ description: undefined
258
+ });
259
+ });
260
+ }
203
261
  },
204
262
  value: description
205
- }));
263
+ })), useNewValidation && validationErrors.description && /*#__PURE__*/_react.default.createElement(_form.ErrorMessage, null, validationErrors.description));
206
264
  }), !anonymousFeedback && /*#__PURE__*/_react.default.createElement(_form.Fieldset, null, /*#__PURE__*/_react.default.createElement("legend", {
207
265
  "aria-hidden": false,
208
266
  hidden: true
@@ -155,5 +155,15 @@ var messages = exports.messages = (0, _reactIntlNext.defineMessages)({
155
155
  id: 'feedback-collector.default.custom.textarea.label',
156
156
  defaultMessage: "What's on your mind?",
157
157
  description: 'The textarea label where users can write their suggestion for custom feedback collector'
158
+ },
159
+ validationErrorTypeRequired: {
160
+ id: 'feedback-collector.validation.type.required',
161
+ defaultMessage: 'Please select a feedback type',
162
+ description: 'Error message when feedback type is not selected'
163
+ },
164
+ validationErrorDescriptionRequired: {
165
+ id: 'feedback-collector.validation.description.required',
166
+ defaultMessage: 'Please provide a description',
167
+ description: 'Error message when description is not provided'
158
168
  }
159
169
  });
@@ -91,7 +91,7 @@ export default class FeedbackCollector extends Component {
91
91
  return FeedbackCollector.defaultProps.url;
92
92
  }
93
93
  getPackageVersion() {
94
- return "14.3.2" || 'Unknown, at least 11.0.0';
94
+ return "14.3.3" || 'Unknown, at least 11.0.0';
95
95
  }
96
96
  async getEntitlementInformation() {
97
97
  var _entitlementDetails, _entitlementDetails2, _productName, _entitlement, _productEntitlement;
@@ -3,9 +3,10 @@ import React, { useRef, useState } from 'react';
3
3
  import { FormattedMessage, useIntl } from 'react-intl-next';
4
4
  import Button from '@atlaskit/button/standard-button';
5
5
  import { Checkbox } from '@atlaskit/checkbox';
6
- import Form, { Field, Fieldset, RequiredAsterisk } from '@atlaskit/form';
6
+ import Form, { ErrorMessage, Field, Fieldset, RequiredAsterisk } from '@atlaskit/form';
7
7
  import Link from '@atlaskit/link';
8
8
  import Modal, { ModalBody, ModalFooter, ModalHeader, ModalTitle } from '@atlaskit/modal-dialog';
9
+ import { fg } from '@atlaskit/platform-feature-flags';
9
10
  import SectionMessage from '@atlaskit/section-message';
10
11
  import Select from '@atlaskit/select';
11
12
  import TextArea from '@atlaskit/textarea';
@@ -39,13 +40,33 @@ const FeedbackForm = ({
39
40
  const [enrollInResearchGroup, setEnrollInResearchGroup] = useState(false);
40
41
  const [type, setType] = useState('empty');
41
42
  const [isSubmitting, setIsSubmitting] = useState(false);
43
+ const [validationErrors, setValidationErrors] = useState({});
42
44
  const {
43
45
  formatMessage
44
46
  } = useIntl();
45
47
  const isTypeSelected = () => type !== 'empty';
46
48
  const canShowTextField = isTypeSelected() || !showTypeField;
47
49
  const hasDescription = description || hasDescriptionDefaultValue;
48
- const isDisabled = disableSubmitButton || (showTypeField ? !isTypeSelected() || !hasDescription : !hasDescription);
50
+
51
+ // Feature flag determines validation behavior
52
+ const useNewValidation = fg('feedback-collector-custom-validation');
53
+ const isDisabled = useNewValidation ? isSubmitting || disableSubmitButton // New: only disable when submitting or explicitly disabled
54
+ : disableSubmitButton || (showTypeField ? !isTypeSelected() || !hasDescription : !hasDescription); // Old: disable based on form validation
55
+
56
+ const getValidationErrors = () => {
57
+ const errors = {};
58
+
59
+ // Validate type selection if showTypeField is true
60
+ if (showTypeField && !isTypeSelected()) {
61
+ errors.type = formatMessage(messages.validationErrorTypeRequired);
62
+ }
63
+
64
+ // Validate description if showDefaultTextFields is true
65
+ if (showDefaultTextFields && !hasDescription) {
66
+ errors.description = formatMessage(messages.validationErrorDescriptionRequired);
67
+ }
68
+ return errors;
69
+ };
49
70
  const getFieldLabels = record => {
50
71
  var _record$bug, _record$comment, _record$suggestion, _record$question, _record$empty, _record$not_relevant, _record$not_accurate, _record$too_slow, _record$unhelpful_lin, _record$other;
51
72
  return {
@@ -91,14 +112,29 @@ const FeedbackForm = ({
91
112
  shouldScrollInViewport: true
92
113
  }, /*#__PURE__*/React.createElement(Form, {
93
114
  onSubmit: async () => {
115
+ if (useNewValidation) {
116
+ // New validation: validate on submit and show errors
117
+ const errors = getValidationErrors();
118
+
119
+ // If there are validation errors, show them and don't submit
120
+ if (Object.keys(errors).length > 0) {
121
+ setValidationErrors(errors);
122
+ return;
123
+ }
124
+ }
125
+
126
+ // Submit the form (both old and new validation paths reach here)
94
127
  setIsSubmitting(true);
95
- await onSubmit({
96
- canBeContacted,
97
- description,
98
- enrollInResearchGroup,
99
- type
100
- });
101
- setIsSubmitting(false);
128
+ try {
129
+ await onSubmit({
130
+ canBeContacted,
131
+ description,
132
+ enrollInResearchGroup,
133
+ type
134
+ });
135
+ } finally {
136
+ setIsSubmitting(false);
137
+ }
102
138
  }
103
139
  }, ({
104
140
  formProps
@@ -121,12 +157,19 @@ const FeedbackForm = ({
121
157
  id,
122
158
  ...restProps
123
159
  }
124
- }) => /*#__PURE__*/React.createElement(Select, _extends({}, restProps, {
160
+ }) => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Select, _extends({}, restProps, {
125
161
  onChange: option => {
126
162
  if (!option || option instanceof Array) {
127
163
  return;
128
164
  }
129
165
  setType(option.value);
166
+ // Clear validation error when user selects a type (only for new validation)
167
+ if (useNewValidation && validationErrors.type) {
168
+ setValidationErrors(prev => ({
169
+ ...prev,
170
+ type: undefined
171
+ }));
172
+ }
130
173
  },
131
174
  menuPortalTarget: document.body,
132
175
  styles: {
@@ -141,19 +184,28 @@ const FeedbackForm = ({
141
184
  ref: focusRef,
142
185
  placeholder: getDefaultPlaceholder(feedbackGroupLabels),
143
186
  inputId: id
144
- }))) : null, showDefaultTextFields && canShowTextField && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Field, {
187
+ })), useNewValidation && validationErrors.type && /*#__PURE__*/React.createElement(ErrorMessage, null, validationErrors.type))) : null, showDefaultTextFields && canShowTextField && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Field, {
145
188
  label: showTypeField ? getFieldLabels(feedbackGroupLabels)[type] : customTextAreaLabel || formatMessage(messages.defaultCustomTextAreaLabel),
146
189
  isRequired: true,
147
190
  name: "description"
148
191
  }, ({
149
192
  fieldProps
150
- }) => /*#__PURE__*/React.createElement(TextArea, _extends({}, fieldProps, {
193
+ }) => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(TextArea, _extends({}, fieldProps, {
151
194
  name: "foo",
152
195
  minimumRows: 6,
153
196
  placeholder: summaryPlaceholder || undefined,
154
- onChange: e => setDescription(e.target.value),
197
+ onChange: e => {
198
+ setDescription(e.target.value);
199
+ // Clear validation error when user types
200
+ if (useNewValidation && validationErrors.description) {
201
+ setValidationErrors(prev => ({
202
+ ...prev,
203
+ description: undefined
204
+ }));
205
+ }
206
+ },
155
207
  value: description
156
- }))), !anonymousFeedback && /*#__PURE__*/React.createElement(Fieldset, null, /*#__PURE__*/React.createElement("legend", {
208
+ })), useNewValidation && validationErrors.description && /*#__PURE__*/React.createElement(ErrorMessage, null, validationErrors.description))), !anonymousFeedback && /*#__PURE__*/React.createElement(Fieldset, null, /*#__PURE__*/React.createElement("legend", {
157
209
  "aria-hidden": false,
158
210
  hidden: true
159
211
  }, "Atlassian opt-in options"), /*#__PURE__*/React.createElement(Field, {
@@ -149,5 +149,15 @@ export const messages = defineMessages({
149
149
  id: 'feedback-collector.default.custom.textarea.label',
150
150
  defaultMessage: "What's on your mind?",
151
151
  description: 'The textarea label where users can write their suggestion for custom feedback collector'
152
+ },
153
+ validationErrorTypeRequired: {
154
+ id: 'feedback-collector.validation.type.required',
155
+ defaultMessage: 'Please select a feedback type',
156
+ description: 'Error message when feedback type is not selected'
157
+ },
158
+ validationErrorDescriptionRequired: {
159
+ id: 'feedback-collector.validation.description.required',
160
+ defaultMessage: 'Please provide a description',
161
+ description: 'Error message when description is not provided'
152
162
  }
153
163
  });
@@ -154,7 +154,7 @@ var FeedbackCollector = /*#__PURE__*/function (_Component) {
154
154
  }, {
155
155
  key: "getPackageVersion",
156
156
  value: function getPackageVersion() {
157
- return "14.3.2" || 'Unknown, at least 11.0.0';
157
+ return "14.3.3" || 'Unknown, at least 11.0.0';
158
158
  }
159
159
  }, {
160
160
  key: "getEntitlementInformation",
@@ -12,9 +12,10 @@ import React, { useRef, useState } from 'react';
12
12
  import { FormattedMessage, useIntl } from 'react-intl-next';
13
13
  import Button from '@atlaskit/button/standard-button';
14
14
  import { Checkbox } from '@atlaskit/checkbox';
15
- import Form, { Field, Fieldset, RequiredAsterisk } from '@atlaskit/form';
15
+ import Form, { ErrorMessage, Field, Fieldset, RequiredAsterisk } from '@atlaskit/form';
16
16
  import Link from '@atlaskit/link';
17
17
  import Modal, { ModalBody, ModalFooter, ModalHeader, ModalTitle } from '@atlaskit/modal-dialog';
18
+ import { fg } from '@atlaskit/platform-feature-flags';
18
19
  import SectionMessage from '@atlaskit/section-message';
19
20
  import Select from '@atlaskit/select';
20
21
  import TextArea from '@atlaskit/textarea';
@@ -65,6 +66,10 @@ var FeedbackForm = function FeedbackForm(_ref) {
65
66
  _useState0 = _slicedToArray(_useState9, 2),
66
67
  isSubmitting = _useState0[0],
67
68
  setIsSubmitting = _useState0[1];
69
+ var _useState1 = useState({}),
70
+ _useState10 = _slicedToArray(_useState1, 2),
71
+ validationErrors = _useState10[0],
72
+ setValidationErrors = _useState10[1];
68
73
  var _useIntl = useIntl(),
69
74
  formatMessage = _useIntl.formatMessage;
70
75
  var isTypeSelected = function isTypeSelected() {
@@ -72,7 +77,26 @@ var FeedbackForm = function FeedbackForm(_ref) {
72
77
  };
73
78
  var canShowTextField = isTypeSelected() || !showTypeField;
74
79
  var hasDescription = description || hasDescriptionDefaultValue;
75
- var isDisabled = disableSubmitButton || (showTypeField ? !isTypeSelected() || !hasDescription : !hasDescription);
80
+
81
+ // Feature flag determines validation behavior
82
+ var useNewValidation = fg('feedback-collector-custom-validation');
83
+ var isDisabled = useNewValidation ? isSubmitting || disableSubmitButton // New: only disable when submitting or explicitly disabled
84
+ : disableSubmitButton || (showTypeField ? !isTypeSelected() || !hasDescription : !hasDescription); // Old: disable based on form validation
85
+
86
+ var getValidationErrors = function getValidationErrors() {
87
+ var errors = {};
88
+
89
+ // Validate type selection if showTypeField is true
90
+ if (showTypeField && !isTypeSelected()) {
91
+ errors.type = formatMessage(messages.validationErrorTypeRequired);
92
+ }
93
+
94
+ // Validate description if showDefaultTextFields is true
95
+ if (showDefaultTextFields && !hasDescription) {
96
+ errors.description = formatMessage(messages.validationErrorDescriptionRequired);
97
+ }
98
+ return errors;
99
+ };
76
100
  var getFieldLabels = function getFieldLabels(record) {
77
101
  var _record$bug, _record$comment, _record$suggestion, _record$question, _record$empty, _record$not_relevant, _record$not_accurate, _record$too_slow, _record$unhelpful_lin, _record$other;
78
102
  return {
@@ -118,24 +142,42 @@ var FeedbackForm = function FeedbackForm(_ref) {
118
142
  shouldScrollInViewport: true
119
143
  }, /*#__PURE__*/React.createElement(Form, {
120
144
  onSubmit: /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
145
+ var errors;
121
146
  return _regeneratorRuntime.wrap(function _callee$(_context) {
122
147
  while (1) switch (_context.prev = _context.next) {
123
148
  case 0:
149
+ if (!useNewValidation) {
150
+ _context.next = 5;
151
+ break;
152
+ }
153
+ // New validation: validate on submit and show errors
154
+ errors = getValidationErrors(); // If there are validation errors, show them and don't submit
155
+ if (!(Object.keys(errors).length > 0)) {
156
+ _context.next = 5;
157
+ break;
158
+ }
159
+ setValidationErrors(errors);
160
+ return _context.abrupt("return");
161
+ case 5:
162
+ // Submit the form (both old and new validation paths reach here)
124
163
  setIsSubmitting(true);
125
- _context.next = 3;
164
+ _context.prev = 6;
165
+ _context.next = 9;
126
166
  return onSubmit({
127
167
  canBeContacted: canBeContacted,
128
168
  description: description,
129
169
  enrollInResearchGroup: enrollInResearchGroup,
130
170
  type: type
131
171
  });
132
- case 3:
172
+ case 9:
173
+ _context.prev = 9;
133
174
  setIsSubmitting(false);
134
- case 4:
175
+ return _context.finish(9);
176
+ case 12:
135
177
  case "end":
136
178
  return _context.stop();
137
179
  }
138
- }, _callee);
180
+ }, _callee, null, [[6,, 9, 12]]);
139
181
  }))
140
182
  }, function (_ref3) {
141
183
  var formProps = _ref3.formProps;
@@ -157,12 +199,20 @@ var FeedbackForm = function FeedbackForm(_ref) {
157
199
  var _ref4$fieldProps = _ref4.fieldProps,
158
200
  id = _ref4$fieldProps.id,
159
201
  restProps = _objectWithoutProperties(_ref4$fieldProps, _excluded);
160
- return /*#__PURE__*/React.createElement(Select, _extends({}, restProps, {
202
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Select, _extends({}, restProps, {
161
203
  onChange: function onChange(option) {
162
204
  if (!option || option instanceof Array) {
163
205
  return;
164
206
  }
165
207
  setType(option.value);
208
+ // Clear validation error when user selects a type (only for new validation)
209
+ if (useNewValidation && validationErrors.type) {
210
+ setValidationErrors(function (prev) {
211
+ return _objectSpread(_objectSpread({}, prev), {}, {
212
+ type: undefined
213
+ });
214
+ });
215
+ }
166
216
  },
167
217
  menuPortalTarget: document.body,
168
218
  styles: {
@@ -178,22 +228,30 @@ var FeedbackForm = function FeedbackForm(_ref) {
178
228
  ref: focusRef,
179
229
  placeholder: getDefaultPlaceholder(feedbackGroupLabels),
180
230
  inputId: id
181
- }));
231
+ })), useNewValidation && validationErrors.type && /*#__PURE__*/React.createElement(ErrorMessage, null, validationErrors.type));
182
232
  }) : null, showDefaultTextFields && canShowTextField && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Field, {
183
233
  label: showTypeField ? getFieldLabels(feedbackGroupLabels)[type] : customTextAreaLabel || formatMessage(messages.defaultCustomTextAreaLabel),
184
234
  isRequired: true,
185
235
  name: "description"
186
236
  }, function (_ref5) {
187
237
  var fieldProps = _ref5.fieldProps;
188
- return /*#__PURE__*/React.createElement(TextArea, _extends({}, fieldProps, {
238
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(TextArea, _extends({}, fieldProps, {
189
239
  name: "foo",
190
240
  minimumRows: 6,
191
241
  placeholder: summaryPlaceholder || undefined,
192
242
  onChange: function onChange(e) {
193
- return setDescription(e.target.value);
243
+ setDescription(e.target.value);
244
+ // Clear validation error when user types
245
+ if (useNewValidation && validationErrors.description) {
246
+ setValidationErrors(function (prev) {
247
+ return _objectSpread(_objectSpread({}, prev), {}, {
248
+ description: undefined
249
+ });
250
+ });
251
+ }
194
252
  },
195
253
  value: description
196
- }));
254
+ })), useNewValidation && validationErrors.description && /*#__PURE__*/React.createElement(ErrorMessage, null, validationErrors.description));
197
255
  }), !anonymousFeedback && /*#__PURE__*/React.createElement(Fieldset, null, /*#__PURE__*/React.createElement("legend", {
198
256
  "aria-hidden": false,
199
257
  hidden: true
@@ -149,5 +149,15 @@ export var messages = defineMessages({
149
149
  id: 'feedback-collector.default.custom.textarea.label',
150
150
  defaultMessage: "What's on your mind?",
151
151
  description: 'The textarea label where users can write their suggestion for custom feedback collector'
152
+ },
153
+ validationErrorTypeRequired: {
154
+ id: 'feedback-collector.validation.type.required',
155
+ defaultMessage: 'Please select a feedback type',
156
+ description: 'Error message when feedback type is not selected'
157
+ },
158
+ validationErrorDescriptionRequired: {
159
+ id: 'feedback-collector.validation.description.required',
160
+ defaultMessage: 'Please provide a description',
161
+ description: 'Error message when description is not provided'
152
162
  }
153
163
  });
@@ -149,4 +149,14 @@ export declare const messages: {
149
149
  defaultMessage: string;
150
150
  description: string;
151
151
  };
152
+ validationErrorTypeRequired: {
153
+ id: string;
154
+ defaultMessage: string;
155
+ description: string;
156
+ };
157
+ validationErrorDescriptionRequired: {
158
+ id: string;
159
+ defaultMessage: string;
160
+ description: string;
161
+ };
152
162
  };
@@ -149,4 +149,14 @@ export declare const messages: {
149
149
  defaultMessage: string;
150
150
  description: string;
151
151
  };
152
+ validationErrorTypeRequired: {
153
+ id: string;
154
+ defaultMessage: string;
155
+ description: string;
156
+ };
157
+ validationErrorDescriptionRequired: {
158
+ id: string;
159
+ defaultMessage: string;
160
+ description: string;
161
+ };
152
162
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/feedback-collector",
3
- "version": "14.3.3",
3
+ "version": "14.3.4",
4
4
  "description": "A component that collects feedback across Atlassian products.",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org/"
@@ -40,7 +40,7 @@
40
40
  "@atlaskit/button": "^23.4.0",
41
41
  "@atlaskit/checkbox": "^17.1.0",
42
42
  "@atlaskit/flag": "^17.3.0",
43
- "@atlaskit/form": "^12.1.0",
43
+ "@atlaskit/form": "^12.2.0",
44
44
  "@atlaskit/icon": "^28.0.0",
45
45
  "@atlaskit/link": "^3.2.0",
46
46
  "@atlaskit/modal-dialog": "^14.3.0",
@@ -90,6 +90,9 @@
90
90
  },
91
91
  "dst-a11y__replace-anchor-with-link__belugas-feedba": {
92
92
  "type": "boolean"
93
+ },
94
+ "feedback-collector-custom-validation": {
95
+ "type": "boolean"
93
96
  }
94
97
  }
95
98
  }