@aarhus-university/au-lib-react-components 9.11.19 → 10.0.2

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.
Files changed (165) hide show
  1. package/.eslintrc.js +44 -0
  2. package/README.md +19 -20
  3. package/babel.config.js +7 -6
  4. package/build/umd/all.css +1 -1
  5. package/build/umd/all.css.map +1 -1
  6. package/build/umd/all.js +1 -1
  7. package/build/umd/all.js.map +1 -1
  8. package/build/umd/alphabox.js +1 -1
  9. package/build/umd/alphabox.js.map +1 -1
  10. package/build/umd/databox.js +1 -2
  11. package/build/umd/databox.js.map +1 -1
  12. package/build/umd/diagramme.js +1 -1
  13. package/build/umd/diagramme.js.map +1 -1
  14. package/build/umd/flowbox.js +1 -1
  15. package/build/umd/flowbox.js.map +1 -1
  16. package/build/umd/universe.js +1 -1
  17. package/build/umd/universe.js.map +1 -1
  18. package/package.json +66 -60
  19. package/src/components/{delphinus/AUAlertComponent.js → AUAlertComponent.tsx} +70 -85
  20. package/src/components/{AutoSuggestComponent.js → AUAutoSuggestComponent.js} +45 -19
  21. package/src/components/AUCalendarComponent.tsx +493 -0
  22. package/src/components/AUContentToggleComponent.tsx +33 -0
  23. package/src/components/AUDatepickerComponent.tsx +117 -0
  24. package/src/components/AUMobilePrefixComponent.tsx +15 -0
  25. package/src/components/{delphinus/AUModalComponent.js → AUModalComponent.tsx} +80 -94
  26. package/src/components/{form/AUReceiptComponent.js → AUReceiptComponent.tsx} +33 -40
  27. package/src/components/AUSpinnerComponent.tsx +67 -0
  28. package/src/components/{delphinus/AUSubNavComponent.js → AUSubNavComponent.tsx} +38 -53
  29. package/src/components/{form/AUSubmitButtonContainerComponent.js → AUSubmitButtonContainerComponent.tsx} +31 -39
  30. package/src/components/{delphinus/AUTabbedContentComponent.js → AUTabbedContentComponent.tsx} +145 -150
  31. package/src/components/{delphinus/AUTableComponent.js → AUTableComponent.tsx} +24 -28
  32. package/src/components/{delphinus/AUToastComponent.js → AUToastComponent.tsx} +104 -91
  33. package/src/components/{delphinus/AUToolbarComponent.js → AUToolbarComponent.tsx} +45 -48
  34. package/src/components/profile/AUProfileActions.js +128 -128
  35. package/src/components/profile/AUProfileAvatarComponent.js +83 -83
  36. package/src/components/profile/AUProfileAvatarV2Component.js +91 -91
  37. package/src/components/profile/AUProfileAvatarV3Component.tsx +42 -0
  38. package/src/components/profile/AUProfileContainerComponent.js +283 -283
  39. package/src/components/profile/AUProfileHooks.js +30 -30
  40. package/src/components/profile/AUProfileItemComponent.js +54 -54
  41. package/src/components/profile/AUProfileLanguageComponent.js +131 -131
  42. package/src/components/profile/{AUProfileLoginComponent.js → AUProfileLoginComponent.tsx} +3 -18
  43. package/src/components/profile/AUProfileMailComponent.js +307 -307
  44. package/src/components/profile/AUProfileMobileComponent.js +164 -164
  45. package/src/components/profile/AUProfileNameComponent.js +253 -253
  46. package/src/components/profile/AUProfileNextOfKinComponent.js +216 -216
  47. package/src/components/profile/AUProfileReducer.js +230 -230
  48. package/src/components/profile/AUProfileWidgetComponent.js +95 -95
  49. package/src/components/profile/AUProfileWidgetV2Component.js +116 -116
  50. package/src/components/profile/{AUProfileWidgetV3Component.js → AUProfileWidgetV3Component.tsx} +122 -130
  51. package/src/components/wrapping/AUEmbedComponent.js +47 -47
  52. package/src/{components → layout-2016/components}/alphabox/AlphaBoxComponent.js +28 -25
  53. package/src/{components → layout-2016/components}/alphabox/AlphaBoxContentComponent.js +25 -14
  54. package/src/{components → layout-2016/components/common}/AUCollapsibleComponent.js +1 -22
  55. package/src/{components → layout-2016/components/common}/AUSpinnerComponent.js +2 -24
  56. package/src/{components → layout-2016/components}/databox/DataBoxAlphabetComponent.js +1 -1
  57. package/src/{components → layout-2016/components}/databox/DataBoxAssociationComponent.js +2 -2
  58. package/src/{components → layout-2016/components}/databox/DataBoxButtonComponent.js +7 -3
  59. package/src/{components → layout-2016/components}/databox/DataBoxComponent.js +2 -2
  60. package/src/{components → layout-2016/components}/databox/DataBoxGroupingComponent.js +2 -0
  61. package/src/{components → layout-2016/components}/databox/DataBoxSearchResultComponent.js +1 -5
  62. package/src/{components → layout-2016/components}/databox/DataBoxStackedAssociationComponent.js +1 -5
  63. package/src/{components → layout-2016/components}/databox/DataBoxSuggestionComponent.js +0 -0
  64. package/src/{components → layout-2016/components/diagramme}/AUDiagrammeComponent.js +5 -6
  65. package/src/{components → layout-2016/components}/flowbox/FlowBoxComponent.js +8 -8
  66. package/src/{components → layout-2016/components}/flowbox/FlowBoxPhoneComponent.js +3 -5
  67. package/src/{components → layout-2016/components}/profile/AUProfileAvatar2016Component.js +6 -2
  68. package/src/{components → layout-2016/components}/universe/StaffTopComponent.js +4 -3
  69. package/src/{components → layout-2016/components}/universe/StudentTopComponent.js +0 -0
  70. package/src/{components → layout-2016/components}/universe/UniverseContainerComponent.js +11 -8
  71. package/src/layout-2016/lib/all.js +3 -0
  72. package/src/{lib → layout-2016/lib}/au-alphabox.js +1 -3
  73. package/src/{lib → layout-2016/lib}/au-databox.js +6 -9
  74. package/src/{lib → layout-2016/lib}/au-diagramme.js +2 -4
  75. package/src/{lib → layout-2016/lib}/au-flowbox.js +1 -3
  76. package/src/{lib → layout-2016/lib}/universe.js +0 -0
  77. package/src/lib/{helpers.js → helpers.ts} +31 -59
  78. package/src/{components/delphinus/hooks.js → lib/hooks.ts} +33 -28
  79. package/src/lib/{i18n.js → i18n.ts} +600 -601
  80. package/src/lib/{tracking.js → tracking.ts} +69 -65
  81. package/src/lib/{wrapping.js → wrapping.ts} +21 -16
  82. package/src/styles/_settings.scss +10 -10
  83. package/src/styles/alphabox.scss +222 -208
  84. package/src/styles/app.scss +7 -13
  85. package/src/styles/autosuggest.scss +57 -57
  86. package/src/styles/databox.scss +563 -563
  87. package/src/styles/diagramme.scss +119 -119
  88. package/src/styles/flowbox.scss +72 -72
  89. package/src/styles/maps.scss +395 -395
  90. package/tsconfig.json +47 -0
  91. package/types/common/interfaces/gui.d.ts +63 -0
  92. package/types/common/interfaces/model.d.ts +29 -0
  93. package/types/common/main.d.ts +5 -0
  94. package/types/common/package.json +5 -0
  95. package/types/common/payloads.d.ts +0 -0
  96. package/types/common/props.d.ts +165 -0
  97. package/{src/config/webpack.umd.config.js → webpack.config.js} +20 -16
  98. package/.eslintrc +0 -19
  99. package/build/dev.html +0 -329
  100. package/build/umd/auAuth.js +0 -2
  101. package/build/umd/auAuth.js.map +0 -1
  102. package/build/umd/databox.js.LICENSE.txt +0 -5
  103. package/build/umd/news.js +0 -2
  104. package/build/umd/news.js.map +0 -1
  105. package/src/all.js +0 -3
  106. package/src/app.js +0 -263
  107. package/src/components/AUAlertComponent.js +0 -158
  108. package/src/components/AUAmountComponent.js +0 -84
  109. package/src/components/AUBannerComponent.js +0 -99
  110. package/src/components/AUCalendarComponent.js +0 -393
  111. package/src/components/AUDatepickerComponent.js +0 -105
  112. package/src/components/AUFilterCheckboxComponent.js +0 -122
  113. package/src/components/AUFocusComponent.js +0 -55
  114. package/src/components/AUModalComponent.js +0 -94
  115. package/src/components/AUPaginationComponent.js +0 -103
  116. package/src/components/context/AUUserContextComponent.js +0 -91
  117. package/src/components/context/ImpersonateComponent.js +0 -54
  118. package/src/components/delphinus/AUCalendarComponent.js +0 -487
  119. package/src/components/delphinus/AUContentToggleComponent.js +0 -32
  120. package/src/components/delphinus/AUDatepickerComponent.js +0 -164
  121. package/src/components/delphinus/AULoginComponent.js +0 -65
  122. package/src/components/delphinus/AUSpinnerComponent.js +0 -114
  123. package/src/components/form/AUMobilePrefixComponent.js +0 -18
  124. package/src/components/news/EventLayout1Component.js +0 -94
  125. package/src/components/news/EventLayout2Component.js +0 -90
  126. package/src/components/news/EventLayout3Component.js +0 -68
  127. package/src/components/news/NewsCategoriesComponent.js +0 -21
  128. package/src/components/news/NewsCollageBannerComponent.js +0 -71
  129. package/src/components/news/NewsCollageBannerRSSComponent.js +0 -79
  130. package/src/components/news/NewsColumnsComponent.js +0 -125
  131. package/src/components/news/NewsLanguageChangeComponent.js +0 -74
  132. package/src/components/news/NewsLayout1Component.js +0 -80
  133. package/src/components/news/NewsLayout2Component.js +0 -80
  134. package/src/components/news/NewsLayout3Component.js +0 -81
  135. package/src/components/news/NewsLayout4Component.js +0 -80
  136. package/src/components/news/NewsLayout5Component.js +0 -61
  137. package/src/components/news/NewsLayout6Component.js +0 -55
  138. package/src/components/news/NewsLayout7Component.js +0 -58
  139. package/src/components/news/NewsLayout8Component.js +0 -57
  140. package/src/components/news/NewsListComponent.js +0 -291
  141. package/src/components/news/NewsPopUpComponent.js +0 -591
  142. package/src/components/news/NewsRSSComponent.js +0 -74
  143. package/src/components/news/NewsSocialComponent.js +0 -104
  144. package/src/components/news/NewsSubHeaderComponent.js +0 -19
  145. package/src/components/password/AUChangePasswordComponent.js +0 -177
  146. package/src/components/password/AUCurrentPasswordComponent.js +0 -72
  147. package/src/components/password/AUNewPasswordComponent.js +0 -143
  148. package/src/components/password/AUPasswordActions.js +0 -101
  149. package/src/components/password/AUPasswordHooks.js +0 -47
  150. package/src/components/password/AUPasswordReducer.js +0 -78
  151. package/src/components/password/AUPasswordRequirementsComponent.js +0 -29
  152. package/src/components/profile/AUProfileAvatarV3Component.js +0 -80
  153. package/src/config/webpack.dev.config.js +0 -47
  154. package/src/index.js +0 -6
  155. package/src/lib/au-auth.js +0 -227
  156. package/src/lib/au-news.js +0 -371
  157. package/src/lib/menu.js +0 -10
  158. package/src/lib/urlHandler.js +0 -63
  159. package/src/lib/validation.js +0 -181
  160. package/src/styles/alert.scss +0 -39
  161. package/src/styles/calendar.scss +0 -112
  162. package/src/styles/filtercheckbox.scss +0 -5
  163. package/src/styles/modal.scss +0 -35
  164. package/src/styles/pagination.scss +0 -11
  165. package/src/styles/spinner.scss +0 -30
@@ -1,307 +1,307 @@
1
- /* eslint-env browser */
2
- /* eslint-disable max-len */
3
- /* eslint-disable jsx-a11y/label-has-associated-control */
4
- /* eslint-disable jsx-a11y/label-has-for */
5
- import React, { useState, useEffect } from 'react';
6
- import PropTypes from 'prop-types';
7
- import { Link } from 'react-router-dom';
8
- import AUSubmitButtonContainerComponent from '../form/AUSubmitButtonContainerComponent';
9
- import { useProfileForm } from './AUProfileHooks';
10
- import {
11
- setCaretPosition,
12
- scrollTo,
13
- } from '../../lib/helpers';
14
- import { profileLabels } from '../../lib/i18n';
15
- import { renderValidation, validateForm, emailRegex } from '../../lib/validation';
16
-
17
- const AUProfileMailComponent = ({
18
- lang,
19
- routeProps: { history },
20
- path,
21
- studentMailAddress,
22
- studentChosenMailAddress: pStudentChosenMailAddress,
23
- privateMailAddress: pPrivateMailAddress,
24
- workMailAddress: pWorkMailAddress,
25
- workMailDomain,
26
- isStudentAdGroupMember,
27
- onSave,
28
- onSaveAction,
29
- saving,
30
- saved,
31
- dismissMessages,
32
- clear,
33
- }) => {
34
- const [workMail, setWorkMail] = useState(!pWorkMailAddress ? '' : pWorkMailAddress);
35
- const [workMailPrefix, setWorkMailPrefix] = useState(workMail.includes('@') && !workMail.includes('@uni.au.dk') ? workMail.split('@')[0] : '');
36
- const workMailPostfix = `@${workMailDomain}`; // `@${workMail.includes('@') ? workMail.split('@')[1] : ''}`;
37
- const [workMailValidationMessages, setWorkMailValidationMessages] = useState([]);
38
- const [isWorkMailValid, setIsWorkMailValid] = useState(!!pWorkMailAddress && !workMail.includes('@uni.au.dk') || pWorkMailAddress == null);
39
-
40
- const [studentChosenMail, setStudentChosenMail] = useState(pStudentChosenMailAddress);
41
- let initialStudentChosenMailPrefix = '';
42
- if (studentChosenMail.includes('@')) {
43
- [initialStudentChosenMailPrefix] = studentChosenMail.split('@');
44
- } else if (studentMailAddress && studentMailAddress.includes('@')) {
45
- [initialStudentChosenMailPrefix] = studentMailAddress.split('@');
46
- }
47
- const [studentChosenMailPrefix, setStudentChosenMailPrefix] = useState(initialStudentChosenMailPrefix);
48
- const studentChosenMailPostfix = '@post.au.dk';
49
- const [studentChosenMailValidationMessages, setStudentChosenMailValidationMessages] = useState([]);
50
- const [isStudentChosenMailValid, setIsStudentChosenMailValid] = useState(!!pStudentChosenMailAddress || !isStudentAdGroupMember);
51
-
52
- const [privateMail, setPrivateMail] = useState(pPrivateMailAddress);
53
- const [privateMailValidationMessages, setPrivateMailValidationMessages] = useState([]);
54
- const [isPrivateMailValid, setIsPrivateMailValid] = useState(!!pPrivateMailAddress);
55
-
56
- const [onCancel] = useProfileForm(saved, history, lang, clear);
57
-
58
- useEffect(() => {
59
- scrollTo();
60
- dismissMessages();
61
- if (pWorkMailAddress) {
62
- setCaretPosition(document.getElementById('mail-work'), pWorkMailAddress.indexOf('@'));
63
- document.getElementById('mail-work').focus();
64
- } else if (pStudentChosenMailAddress) {
65
- setCaretPosition(document.getElementById('mail-student'), pStudentChosenMailAddress.indexOf('@'));
66
- document.getElementById('mail-student').focus();
67
- } else if (pPrivateMailAddress) {
68
- setCaretPosition(document.getElementById('mail-private'), pPrivateMailAddress.indexOf('@'));
69
- document.getElementById('mail-private').focus();
70
- }
71
- }, []);
72
-
73
- const validationRules = [{
74
- message: profileLabels[lang].validMail,
75
- rule: (fieldValue) => fieldValue.trim().match(emailRegex),
76
- }];
77
-
78
- const validationRulesPrivateMail = [{
79
- message: profileLabels[lang].validMailPrivate,
80
- rule: (fieldValue) => fieldValue.trim().match(emailRegex) && !fieldValue.trim().endsWith(workMailPostfix),
81
- }];
82
-
83
- const validateWorkMail = (value, alert = true) => {
84
- const [valid, messages] = validateForm(lang, value, validationRules);
85
- setWorkMail(value);
86
- setWorkMailValidationMessages(alert ? messages : []);
87
- setIsWorkMailValid(valid);
88
- };
89
-
90
- const validateStudentChosenMail = (value, alert = true) => {
91
- const [valid, messages] = validateForm(lang, value, validationRules);
92
- setStudentChosenMail(value); // Her skal vi lige gøre noget, hvis man har slettet sin selvvalgte og den nulstiller til 20XXXXXXX@post.au.dk
93
- setStudentChosenMailValidationMessages(alert ? messages : []);
94
- setIsStudentChosenMailValid(valid);
95
- };
96
-
97
- const validatePrivateMail = (value, alert = true) => {
98
- const [valid, messages] = validateForm(lang, value, validationRulesPrivateMail);
99
- setPrivateMail(value);
100
- setPrivateMailValidationMessages(alert ? messages : []);
101
- setIsPrivateMailValid(valid);
102
- };
103
-
104
- const submit = (e) => {
105
- e.preventDefault();
106
- validateWorkMail(workMailPrefix + workMailPostfix, !isWorkMailValid);
107
- validateStudentChosenMail(studentChosenMail, !isStudentChosenMailValid);
108
- let valid = true; // Vi tillader tom privatmailadresse
109
- if (privateMail !== '') {
110
- validatePrivateMail(privateMail, !isPrivateMailValid);
111
- valid = isPrivateMailValid;
112
- }
113
- if (isStudentAdGroupMember) {
114
- valid = valid && isStudentChosenMailValid;
115
- }
116
- if (pWorkMailAddress) {
117
- valid = valid && isWorkMailValid;
118
- }
119
- if (valid) {
120
- onSave({
121
- workMailName: workMailPrefix,
122
- studentChosenMailAddress: studentChosenMail === studentMailAddress ? '' : studentChosenMail,
123
- privateMailAddress: privateMail,
124
- }, onSaveAction);
125
- }
126
- };
127
-
128
- let workMailValidationClassName = '';
129
- if (!isWorkMailValid && workMailValidationMessages.length) {
130
- workMailValidationClassName = ' form-info--error';
131
- } else if (isWorkMailValid) {
132
- workMailValidationClassName = ' form-info--confirmed';
133
- }
134
-
135
- let studentChosenMailValidationClassName = '';
136
- if (!isStudentChosenMailValid && studentChosenMailValidationMessages.length) {
137
- studentChosenMailValidationClassName = ' form-info--error';
138
- } else if (isStudentChosenMailValid) {
139
- studentChosenMailValidationClassName = ' form-info--confirmed';
140
- }
141
-
142
- let privateMailValidationClassName = '';
143
- if (!isPrivateMailValid && privateMailValidationMessages.length) {
144
- privateMailValidationClassName = ' form-info--error';
145
- } else if (isPrivateMailValid) {
146
- privateMailValidationClassName = ' form-info--confirmed';
147
- }
148
-
149
- return [
150
- <div key="header" className="list-navigator">
151
- <h1 className="list-navigator__header">{profileLabels[lang].headerMail}</h1>
152
- <Link className="list-navigator__list-name" to={path}>{profileLabels[lang].headerContainer}</Link>
153
- </div>,
154
- <form key="form" className="form" noValidate="novalidate">
155
- {
156
- pWorkMailAddress && (
157
- <div className={`form__field${workMailValidationClassName}`}>
158
- <label key="label" htmlFor="mail-work">
159
- {profileLabels[lang].workMail}
160
- <span className="screenreader-only">{profileLabels[lang].workMailScreenreader.replace('###MAIL###', workMail)}</span>
161
- <div className="form-info__hint">
162
- {profileLabels[lang].workMailHint}
163
- </div>
164
- {renderValidation(workMailValidationMessages)}
165
- </label>
166
- <div className="form__field__shadow-input">
167
- <input
168
- type="text"
169
- id="mail-work"
170
- value={workMailPrefix}
171
- onChange={(e) => {
172
- const trimmed = e.target.value.trim();
173
- setWorkMailPrefix(trimmed);
174
- validateWorkMail(trimmed + workMailPostfix, workMailValidationMessages.length);
175
- }}
176
- onKeyUp={(e) => {
177
- if (e.key === 'Enter') {
178
- const trimmed = e.target.value.trim();
179
- setWorkMailPrefix(trimmed);
180
- validateWorkMail(trimmed + workMailPostfix);
181
- }
182
- }}
183
- disabled={saving}
184
- />
185
- <div className="form__field__shadow-input__content" aria-hidden="true">
186
- <span className="form__field__shadow-input__input">{workMailPrefix}</span>
187
- <span className="form__field__shadow-input__postfix">{workMailPostfix}</span>
188
- </div>
189
- </div>
190
- </div>
191
- )
192
- }
193
- {
194
- isStudentAdGroupMember && (
195
- <div className={`form__field${studentChosenMailValidationClassName}`}>
196
- <label key="label" htmlFor="mail-student">
197
- {profileLabels[lang].studentMail}
198
- <span className="screenreader-only">{profileLabels[lang].studentMailScreenreader.replace('###MAIL###', studentChosenMail)}</span>
199
- {renderValidation(studentChosenMailValidationMessages)}
200
- </label>
201
- <div className="form__field__shadow-input">
202
- <input
203
- type="text"
204
- id="mail-student"
205
- value={studentChosenMailPrefix}
206
- onChange={(e) => {
207
- const trimmed = e.target.value.trim();
208
- setStudentChosenMailPrefix(trimmed);
209
- validateStudentChosenMail(trimmed + studentChosenMailPostfix, studentChosenMailValidationMessages.length);
210
- }}
211
- onKeyUp={(e) => {
212
- if (e.key === 'Enter') {
213
- const trimmed = e.target.value.trim();
214
- setStudentChosenMailPrefix(trimmed);
215
- validateStudentChosenMail(trimmed + studentChosenMailPostfix);
216
- }
217
- }}
218
- disabled={saving}
219
- />
220
- <div className="form__field__shadow-input__content" aria-hidden="true">
221
- <span className="form__field__shadow-input__input">{studentChosenMailPrefix}</span>
222
- <span className="form__field__shadow-input__postfix">{studentChosenMailPostfix}</span>
223
- </div>
224
- </div>
225
- </div>
226
- )
227
- }
228
- <div className={`form__field${privateMailValidationClassName}`}>
229
- <label key="label" htmlFor="mail-private">
230
- {profileLabels[lang].privateMail}
231
- <div className="form-info__hint">
232
- {profileLabels[lang].privateMailHint}
233
- </div>
234
- {renderValidation(privateMailValidationMessages)}
235
- </label>
236
- <input
237
- type="text"
238
- id="mail-private"
239
- value={privateMail || ''}
240
- onChange={(e) => {
241
- validatePrivateMail(e.target.value.trim(), privateMailValidationMessages.length);
242
- }}
243
- onKeyUp={(e) => {
244
- if (e.key === 'Enter') {
245
- validatePrivateMail(e.target.value.trim());
246
- }
247
- }}
248
- disabled={saving}
249
- />
250
- </div>
251
- <AUSubmitButtonContainerComponent
252
- lang={lang}
253
- disabled={saving}
254
- onSubmit={submit}
255
- onCancel={onCancel}
256
- />
257
- </form>,
258
- ];
259
- };
260
-
261
- AUProfileMailComponent.defaultProps = {
262
- onSaveAction: (data, callback) => {
263
- const putData = async () => {
264
- let url = `${window.profileApiUri}/UpdateMailAddresses`;
265
- if (typeof window.API_AUID !== 'undefined') {
266
- url = `${url}?auid=${window.API_AUID}`;
267
- }
268
- const response = await fetch(url, {
269
- method: 'PUT',
270
- credentials: 'include',
271
- headers: {
272
- 'Content-Type': 'application/json',
273
- },
274
- body: JSON.stringify(data),
275
- });
276
- const json = await response.json();
277
- callback(response.ok, response.status, json);
278
-
279
- // clear context cache
280
- // Mail is a litte slow...
281
- // window.auAuth.setUserContext(window.API_AUID || 0, 'profile-clear-cache', true, () => { }, () => { }, true, window.authenticated);
282
- };
283
-
284
- putData();
285
- },
286
- };
287
-
288
- AUProfileMailComponent.propTypes = {
289
- lang: PropTypes.string.isRequired,
290
- routeProps: PropTypes.shape({}).isRequired,
291
- path: PropTypes.string.isRequired,
292
- studentMailAddress: PropTypes.string.isRequired,
293
- studentChosenMailAddress: PropTypes.string.isRequired,
294
- workMailAddress: PropTypes.string.isRequired,
295
- workMailDomain: PropTypes.string.isRequired,
296
- privateMailAddress: PropTypes.string.isRequired,
297
- isStudentAdGroupMember: PropTypes.bool.isRequired,
298
- onSave: PropTypes.func.isRequired,
299
- onSaveAction: PropTypes.func,
300
- saving: PropTypes.bool.isRequired,
301
- saved: PropTypes.bool.isRequired,
302
- dismissMessages: PropTypes.func.isRequired,
303
- clear: PropTypes.func.isRequired,
304
- };
305
-
306
- AUProfileMailComponent.displayName = 'AUProfileMailComponent';
307
- export default AUProfileMailComponent;
1
+ /* eslint-env browser */
2
+ /* eslint-disable max-len */
3
+ /* eslint-disable jsx-a11y/label-has-associated-control */
4
+ /* eslint-disable jsx-a11y/label-has-for */
5
+ import React, { useState, useEffect } from 'react';
6
+ import PropTypes from 'prop-types';
7
+ import { Link } from 'react-router-dom';
8
+ import AUSubmitButtonContainerComponent from '../form/AUSubmitButtonContainerComponent';
9
+ import { useProfileForm } from './AUProfileHooks';
10
+ import {
11
+ setCaretPosition,
12
+ scrollTo,
13
+ } from '../../lib/helpers';
14
+ import { profileLabels } from '../../lib/i18n';
15
+ import { renderValidation, validateForm, emailRegex } from '../../lib/validation';
16
+
17
+ const AUProfileMailComponent = ({
18
+ lang,
19
+ routeProps: { history },
20
+ path,
21
+ studentMailAddress,
22
+ studentChosenMailAddress: pStudentChosenMailAddress,
23
+ privateMailAddress: pPrivateMailAddress,
24
+ workMailAddress: pWorkMailAddress,
25
+ workMailDomain,
26
+ isStudentAdGroupMember,
27
+ onSave,
28
+ onSaveAction,
29
+ saving,
30
+ saved,
31
+ dismissMessages,
32
+ clear,
33
+ }) => {
34
+ const [workMail, setWorkMail] = useState(!pWorkMailAddress ? '' : pWorkMailAddress);
35
+ const [workMailPrefix, setWorkMailPrefix] = useState(workMail.includes('@') && !workMail.includes('@uni.au.dk') ? workMail.split('@')[0] : '');
36
+ const workMailPostfix = `@${workMailDomain}`; // `@${workMail.includes('@') ? workMail.split('@')[1] : ''}`;
37
+ const [workMailValidationMessages, setWorkMailValidationMessages] = useState([]);
38
+ const [isWorkMailValid, setIsWorkMailValid] = useState(!!pWorkMailAddress && !workMail.includes('@uni.au.dk') || pWorkMailAddress == null);
39
+
40
+ const [studentChosenMail, setStudentChosenMail] = useState(pStudentChosenMailAddress);
41
+ let initialStudentChosenMailPrefix = '';
42
+ if (studentChosenMail.includes('@')) {
43
+ [initialStudentChosenMailPrefix] = studentChosenMail.split('@');
44
+ } else if (studentMailAddress && studentMailAddress.includes('@')) {
45
+ [initialStudentChosenMailPrefix] = studentMailAddress.split('@');
46
+ }
47
+ const [studentChosenMailPrefix, setStudentChosenMailPrefix] = useState(initialStudentChosenMailPrefix);
48
+ const studentChosenMailPostfix = '@post.au.dk';
49
+ const [studentChosenMailValidationMessages, setStudentChosenMailValidationMessages] = useState([]);
50
+ const [isStudentChosenMailValid, setIsStudentChosenMailValid] = useState(!!pStudentChosenMailAddress || !isStudentAdGroupMember);
51
+
52
+ const [privateMail, setPrivateMail] = useState(pPrivateMailAddress);
53
+ const [privateMailValidationMessages, setPrivateMailValidationMessages] = useState([]);
54
+ const [isPrivateMailValid, setIsPrivateMailValid] = useState(!!pPrivateMailAddress);
55
+
56
+ const [onCancel] = useProfileForm(saved, history, lang, clear);
57
+
58
+ useEffect(() => {
59
+ scrollTo();
60
+ dismissMessages();
61
+ if (pWorkMailAddress) {
62
+ setCaretPosition(document.getElementById('mail-work'), pWorkMailAddress.indexOf('@'));
63
+ document.getElementById('mail-work').focus();
64
+ } else if (pStudentChosenMailAddress) {
65
+ setCaretPosition(document.getElementById('mail-student'), pStudentChosenMailAddress.indexOf('@'));
66
+ document.getElementById('mail-student').focus();
67
+ } else if (pPrivateMailAddress) {
68
+ setCaretPosition(document.getElementById('mail-private'), pPrivateMailAddress.indexOf('@'));
69
+ document.getElementById('mail-private').focus();
70
+ }
71
+ }, []);
72
+
73
+ const validationRules = [{
74
+ message: profileLabels[lang].validMail,
75
+ rule: (fieldValue) => fieldValue.trim().match(emailRegex),
76
+ }];
77
+
78
+ const validationRulesPrivateMail = [{
79
+ message: profileLabels[lang].validMailPrivate,
80
+ rule: (fieldValue) => fieldValue.trim().match(emailRegex) && !fieldValue.trim().endsWith(workMailPostfix),
81
+ }];
82
+
83
+ const validateWorkMail = (value, alert = true) => {
84
+ const [valid, messages] = validateForm(lang, value, validationRules);
85
+ setWorkMail(value);
86
+ setWorkMailValidationMessages(alert ? messages : []);
87
+ setIsWorkMailValid(valid);
88
+ };
89
+
90
+ const validateStudentChosenMail = (value, alert = true) => {
91
+ const [valid, messages] = validateForm(lang, value, validationRules);
92
+ setStudentChosenMail(value); // Her skal vi lige gøre noget, hvis man har slettet sin selvvalgte og den nulstiller til 20XXXXXXX@post.au.dk
93
+ setStudentChosenMailValidationMessages(alert ? messages : []);
94
+ setIsStudentChosenMailValid(valid);
95
+ };
96
+
97
+ const validatePrivateMail = (value, alert = true) => {
98
+ const [valid, messages] = validateForm(lang, value, validationRulesPrivateMail);
99
+ setPrivateMail(value);
100
+ setPrivateMailValidationMessages(alert ? messages : []);
101
+ setIsPrivateMailValid(valid);
102
+ };
103
+
104
+ const submit = (e) => {
105
+ e.preventDefault();
106
+ validateWorkMail(workMailPrefix + workMailPostfix, !isWorkMailValid);
107
+ validateStudentChosenMail(studentChosenMail, !isStudentChosenMailValid);
108
+ let valid = true; // Vi tillader tom privatmailadresse
109
+ if (privateMail !== '') {
110
+ validatePrivateMail(privateMail, !isPrivateMailValid);
111
+ valid = isPrivateMailValid;
112
+ }
113
+ if (isStudentAdGroupMember) {
114
+ valid = valid && isStudentChosenMailValid;
115
+ }
116
+ if (pWorkMailAddress) {
117
+ valid = valid && isWorkMailValid;
118
+ }
119
+ if (valid) {
120
+ onSave({
121
+ workMailName: workMailPrefix,
122
+ studentChosenMailAddress: studentChosenMail === studentMailAddress ? '' : studentChosenMail,
123
+ privateMailAddress: privateMail,
124
+ }, onSaveAction);
125
+ }
126
+ };
127
+
128
+ let workMailValidationClassName = '';
129
+ if (!isWorkMailValid && workMailValidationMessages.length) {
130
+ workMailValidationClassName = ' form-info--error';
131
+ } else if (isWorkMailValid) {
132
+ workMailValidationClassName = ' form-info--confirmed';
133
+ }
134
+
135
+ let studentChosenMailValidationClassName = '';
136
+ if (!isStudentChosenMailValid && studentChosenMailValidationMessages.length) {
137
+ studentChosenMailValidationClassName = ' form-info--error';
138
+ } else if (isStudentChosenMailValid) {
139
+ studentChosenMailValidationClassName = ' form-info--confirmed';
140
+ }
141
+
142
+ let privateMailValidationClassName = '';
143
+ if (!isPrivateMailValid && privateMailValidationMessages.length) {
144
+ privateMailValidationClassName = ' form-info--error';
145
+ } else if (isPrivateMailValid) {
146
+ privateMailValidationClassName = ' form-info--confirmed';
147
+ }
148
+
149
+ return [
150
+ <div key="header" className="list-navigator">
151
+ <h1 className="list-navigator__header">{profileLabels[lang].headerMail}</h1>
152
+ <Link className="list-navigator__list-name" to={path}>{profileLabels[lang].headerContainer}</Link>
153
+ </div>,
154
+ <form key="form" className="form" noValidate="novalidate">
155
+ {
156
+ pWorkMailAddress && (
157
+ <div className={`form__field${workMailValidationClassName}`}>
158
+ <label key="label" htmlFor="mail-work">
159
+ {profileLabels[lang].workMail}
160
+ <span className="screenreader-only">{profileLabels[lang].workMailScreenreader.replace('###MAIL###', workMail)}</span>
161
+ <div className="form-info__hint">
162
+ {profileLabels[lang].workMailHint}
163
+ </div>
164
+ {renderValidation(workMailValidationMessages)}
165
+ </label>
166
+ <div className="form__field__shadow-input">
167
+ <input
168
+ type="text"
169
+ id="mail-work"
170
+ value={workMailPrefix}
171
+ onChange={(e) => {
172
+ const trimmed = e.target.value.trim();
173
+ setWorkMailPrefix(trimmed);
174
+ validateWorkMail(trimmed + workMailPostfix, workMailValidationMessages.length);
175
+ }}
176
+ onKeyUp={(e) => {
177
+ if (e.key === 'Enter') {
178
+ const trimmed = e.target.value.trim();
179
+ setWorkMailPrefix(trimmed);
180
+ validateWorkMail(trimmed + workMailPostfix);
181
+ }
182
+ }}
183
+ disabled={saving}
184
+ />
185
+ <div className="form__field__shadow-input__content" aria-hidden="true">
186
+ <span className="form__field__shadow-input__input">{workMailPrefix}</span>
187
+ <span className="form__field__shadow-input__postfix">{workMailPostfix}</span>
188
+ </div>
189
+ </div>
190
+ </div>
191
+ )
192
+ }
193
+ {
194
+ isStudentAdGroupMember && (
195
+ <div className={`form__field${studentChosenMailValidationClassName}`}>
196
+ <label key="label" htmlFor="mail-student">
197
+ {profileLabels[lang].studentMail}
198
+ <span className="screenreader-only">{profileLabels[lang].studentMailScreenreader.replace('###MAIL###', studentChosenMail)}</span>
199
+ {renderValidation(studentChosenMailValidationMessages)}
200
+ </label>
201
+ <div className="form__field__shadow-input">
202
+ <input
203
+ type="text"
204
+ id="mail-student"
205
+ value={studentChosenMailPrefix}
206
+ onChange={(e) => {
207
+ const trimmed = e.target.value.trim();
208
+ setStudentChosenMailPrefix(trimmed);
209
+ validateStudentChosenMail(trimmed + studentChosenMailPostfix, studentChosenMailValidationMessages.length);
210
+ }}
211
+ onKeyUp={(e) => {
212
+ if (e.key === 'Enter') {
213
+ const trimmed = e.target.value.trim();
214
+ setStudentChosenMailPrefix(trimmed);
215
+ validateStudentChosenMail(trimmed + studentChosenMailPostfix);
216
+ }
217
+ }}
218
+ disabled={saving}
219
+ />
220
+ <div className="form__field__shadow-input__content" aria-hidden="true">
221
+ <span className="form__field__shadow-input__input">{studentChosenMailPrefix}</span>
222
+ <span className="form__field__shadow-input__postfix">{studentChosenMailPostfix}</span>
223
+ </div>
224
+ </div>
225
+ </div>
226
+ )
227
+ }
228
+ <div className={`form__field${privateMailValidationClassName}`}>
229
+ <label key="label" htmlFor="mail-private">
230
+ {profileLabels[lang].privateMail}
231
+ <div className="form-info__hint">
232
+ {profileLabels[lang].privateMailHint}
233
+ </div>
234
+ {renderValidation(privateMailValidationMessages)}
235
+ </label>
236
+ <input
237
+ type="text"
238
+ id="mail-private"
239
+ value={privateMail || ''}
240
+ onChange={(e) => {
241
+ validatePrivateMail(e.target.value.trim(), privateMailValidationMessages.length);
242
+ }}
243
+ onKeyUp={(e) => {
244
+ if (e.key === 'Enter') {
245
+ validatePrivateMail(e.target.value.trim());
246
+ }
247
+ }}
248
+ disabled={saving}
249
+ />
250
+ </div>
251
+ <AUSubmitButtonContainerComponent
252
+ lang={lang}
253
+ disabled={saving}
254
+ onSubmit={submit}
255
+ onCancel={onCancel}
256
+ />
257
+ </form>,
258
+ ];
259
+ };
260
+
261
+ AUProfileMailComponent.defaultProps = {
262
+ onSaveAction: (data, callback) => {
263
+ const putData = async () => {
264
+ let url = `${window.profileApiUri}/UpdateMailAddresses`;
265
+ if (typeof window.API_AUID !== 'undefined') {
266
+ url = `${url}?auid=${window.API_AUID}`;
267
+ }
268
+ const response = await fetch(url, {
269
+ method: 'PUT',
270
+ credentials: 'include',
271
+ headers: {
272
+ 'Content-Type': 'application/json',
273
+ },
274
+ body: JSON.stringify(data),
275
+ });
276
+ const json = await response.json();
277
+ callback(response.ok, response.status, json);
278
+
279
+ // clear context cache
280
+ // Mail is a litte slow...
281
+ // window.auAuth.setUserContext(window.API_AUID || 0, 'profile-clear-cache', true, () => { }, () => { }, true, window.authenticated);
282
+ };
283
+
284
+ putData();
285
+ },
286
+ };
287
+
288
+ AUProfileMailComponent.propTypes = {
289
+ lang: PropTypes.string.isRequired,
290
+ routeProps: PropTypes.shape({}).isRequired,
291
+ path: PropTypes.string.isRequired,
292
+ studentMailAddress: PropTypes.string.isRequired,
293
+ studentChosenMailAddress: PropTypes.string.isRequired,
294
+ workMailAddress: PropTypes.string.isRequired,
295
+ workMailDomain: PropTypes.string.isRequired,
296
+ privateMailAddress: PropTypes.string.isRequired,
297
+ isStudentAdGroupMember: PropTypes.bool.isRequired,
298
+ onSave: PropTypes.func.isRequired,
299
+ onSaveAction: PropTypes.func,
300
+ saving: PropTypes.bool.isRequired,
301
+ saved: PropTypes.bool.isRequired,
302
+ dismissMessages: PropTypes.func.isRequired,
303
+ clear: PropTypes.func.isRequired,
304
+ };
305
+
306
+ AUProfileMailComponent.displayName = 'AUProfileMailComponent';
307
+ export default AUProfileMailComponent;