@pega/react-sdk-overrides 0.23.19 → 0.23.21

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.
@@ -1,19 +1,19 @@
1
1
  /* eslint-disable no-nested-ternary */
2
2
  /* eslint-disable camelcase */
3
- import React, { useState, useEffect, useContext, createElement } from "react";
4
- import PropTypes from "prop-types";
3
+ import React, { useState, useEffect, useContext, createElement } from 'react';
4
+ import PropTypes from 'prop-types';
5
5
  import { makeStyles } from '@material-ui/core/styles';
6
- import { Card, CardHeader, Avatar, Typography } from "@material-ui/core";
6
+ import { Card, CardHeader, Avatar, Typography } from '@material-ui/core';
7
7
  import { Utils } from '@pega/react-sdk-components/lib/components/helpers/utils';
8
8
  import { Alert } from '@material-ui/lab';
9
9
 
10
10
  import Assignment from '@pega/react-sdk-components/lib/components/infra/Assignment';
11
- import ToDo from "@pega/react-sdk-components/lib/components/widget/ToDo";
11
+ import ToDo from '@pega/react-sdk-components/lib/components/widget/ToDo';
12
12
 
13
13
  import createPConnectComponent from '@pega/react-sdk-components/lib/bridge/react_pconnect';
14
- import StoreContext from "@pega/react-sdk-components/lib/bridge/Context/StoreContext";
15
- import DayjsUtils from "@date-io/dayjs";
16
- import { MuiPickersUtilsProvider } from "@material-ui/pickers";
14
+ import StoreContext from '@pega/react-sdk-components/lib/bridge/Context/StoreContext';
15
+ import DayjsUtils from '@date-io/dayjs';
16
+ import { MuiPickersUtilsProvider } from '@material-ui/pickers';
17
17
 
18
18
  import { addContainerItem, getToDoAssignments } from './helpers';
19
19
 
@@ -25,8 +25,7 @@ declare const PCore;
25
25
  // is totally at your own risk.
26
26
  //
27
27
 
28
-
29
- const useStyles = makeStyles((theme) => ({
28
+ const useStyles = makeStyles(theme => ({
30
29
  root: {
31
30
  paddingRight: theme.spacing(2),
32
31
  paddingLeft: theme.spacing(2),
@@ -35,28 +34,26 @@ const useStyles = makeStyles((theme) => ({
35
34
  marginRight: theme.spacing(1),
36
35
  marginLeft: theme.spacing(1),
37
36
  marginTop: theme.spacing(1),
38
- marginBottom: theme.spacing(1),
37
+ marginBottom: theme.spacing(1)
39
38
  },
40
39
  alert: {
41
40
  marginRight: theme.spacing(1),
42
- marginLeft: theme.spacing(1),
41
+ marginLeft: theme.spacing(1)
43
42
  },
44
43
  avatar: {
45
44
  backgroundColor: theme.palette.primary.light,
46
- color: theme.palette.getContrastText(theme.palette.primary.light),
45
+ color: theme.palette.getContrastText(theme.palette.primary.light)
47
46
  }
48
47
  }));
49
48
 
50
-
51
-
52
49
  export default function FlowContainer(props) {
53
50
  const pCoreConstants = PCore.getConstants();
54
51
  const { TODO } = pCoreConstants;
55
- const todo_headerText = "To do";
52
+ const todo_headerText = 'To do';
56
53
 
57
54
  const { getPConnect, routingInfo } = props;
58
55
 
59
- const {displayOnlyFA} = useContext(StoreContext);
56
+ const { displayOnlyFA } = useContext(StoreContext);
60
57
 
61
58
  const thePConn = getPConnect();
62
59
 
@@ -66,39 +63,36 @@ export default function FlowContainer(props) {
66
63
  const [arNewChildrenAsReact, setArNewChildrenAsReact] = useState<Array<any>>([]);
67
64
 
68
65
  const [todo_showTodo, setShowTodo] = useState(false);
69
- const [todo_caseInfoID, setCaseInfoID] = useState("");
66
+ const [todo_caseInfoID, setCaseInfoID] = useState('');
70
67
  const [todo_showTodoList, setShowTodoList] = useState(false);
71
68
  const [todo_datasource, setTodoDatasource] = useState({});
72
69
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars
73
- const [todo_context, setTodoContext] = useState("");
70
+ const [todo_context, setTodoContext] = useState('');
74
71
 
75
-
76
- const [caseMessages, setCaseMessages] = useState("");
72
+ const [caseMessages, setCaseMessages] = useState('');
77
73
  const [bHasCaseMessages, setHasCaseMessages] = useState(false);
78
74
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars
79
- const [checkSvg, setCheckSvg] = useState("");
80
-
75
+ const [checkSvg, setCheckSvg] = useState('');
81
76
 
82
- const [itemKey, setItemKey] = useState("");
83
- const [containerName, setContainerName] = useState("");
84
- const [buildName, setBuildName] = useState("");
77
+ const [itemKey, setItemKey] = useState('');
78
+ const [containerName, setContainerName] = useState('');
79
+ const [buildName, setBuildName] = useState('');
80
+ const [bShowConfirm, setShowConfirm] = useState(false);
85
81
 
86
82
  const classes = useStyles();
87
83
 
88
84
  function initContainer() {
89
-
90
85
  const ourPConn = getPConnect();
91
86
  const containerMgr = ourPConn.getContainerManager();
92
87
  const baseContext = ourPConn.getContextName();
93
88
  const theContainerName = ourPConn.getContainerName();
94
- const containerType = "single";
89
+ const containerType = 'single';
95
90
 
96
91
  const flowContainerTarget = `${baseContext}/${theContainerName}`;
97
- const isContainerItemAvailable = PCore.getContainerUtils().getActiveContainerItemName(
98
- flowContainerTarget
99
- );
92
+ const isContainerItemAvailable =
93
+ PCore.getContainerUtils().getActiveContainerItemName(flowContainerTarget);
100
94
 
101
- window.sessionStorage.setItem("okToInitFlowContainer", "false");
95
+ window.sessionStorage.setItem('okToInitFlowContainer', 'false');
102
96
 
103
97
  if (!isContainerItemAvailable) {
104
98
  containerMgr.initializeContainers({
@@ -110,7 +104,6 @@ export default function FlowContainer(props) {
110
104
  }
111
105
  }
112
106
 
113
-
114
107
  function getBuildName(): string {
115
108
  const ourPConn = getPConnect();
116
109
 
@@ -118,27 +111,24 @@ export default function FlowContainer(props) {
118
111
  const context = ourPConn.getContextName();
119
112
  let viewContainerName = ourPConn.getContainerName();
120
113
 
121
- if (!viewContainerName) viewContainerName = "";
114
+ if (!viewContainerName) viewContainerName = '';
122
115
  return `${context.toUpperCase()}/${viewContainerName.toUpperCase()}`;
123
116
  }
124
117
 
125
-
126
118
  function getTodoVisibility() {
127
- const caseViewMode = getPConnect().getValue("context_data.caseViewMode");
128
- if (caseViewMode && caseViewMode === "review") {
119
+ const caseViewMode = getPConnect().getValue('context_data.caseViewMode');
120
+ if (caseViewMode && caseViewMode === 'review') {
129
121
  return true;
130
122
  }
131
123
  // eslint-disable-next-line sonarjs/prefer-single-boolean-return
132
- if (caseViewMode && caseViewMode === "perform") {
124
+ if (caseViewMode && caseViewMode === 'perform') {
133
125
  return false;
134
126
  }
135
127
 
136
128
  return true;
137
129
  }
138
130
 
139
-
140
131
  function initComponent(bLoadChildren: boolean) {
141
-
142
132
  const ourPConn = getPConnect();
143
133
 
144
134
  // when true, update arChildren from pConn, otherwise, arChilren will be updated in updateSelf()
@@ -166,39 +156,34 @@ export default function FlowContainer(props) {
166
156
  const acName = ourPConn.getContainerName();
167
157
 
168
158
  // for now, in general this should be overridden by updateSelf(), and not be blank
169
- if (itemKey === "") {
159
+ if (itemKey === '') {
170
160
  // debugger;
171
- setItemKey(baseContext.concat("/").concat(acName));
161
+ setItemKey(baseContext.concat('/').concat(acName));
172
162
  }
173
163
 
174
-
175
164
  ourPConn.isBoundToState();
176
165
 
177
-
178
166
  // inside
179
167
  // get fist kid, get the name and displa
180
168
  // pass first kid to a view container, which will disperse it to a view which will use one column, two column, etc.
181
- const oWorkItem = arNewChildren[0].getPConnect(); // child0_getPConnect;
169
+ const oWorkItem = arNewChildren[0].getPConnect(); // child0_getPConnect;
182
170
  const oWorkData = oWorkItem.getDataObject();
183
171
 
184
172
  if (bLoadChildren && oWorkData) {
185
173
  // debugger;
186
- setContainerName(oWorkData.caseInfo.assignments[0].name);
174
+ setContainerName(oWorkData.caseInfo.assignments?.[0].name);
187
175
  }
188
176
 
189
177
  // debugger;
190
178
  setBuildName(getBuildName());
191
-
192
179
  }
193
180
 
194
-
195
181
  useEffect(() => {
196
182
  // from WC SDK connectedCallback (mount)
197
183
  initComponent(true);
198
184
  initContainer();
199
185
  }, []);
200
186
 
201
-
202
187
  function isCaseWideLocalAction() {
203
188
  const ourPConn = getPConnect();
204
189
 
@@ -206,17 +191,14 @@ export default function FlowContainer(props) {
206
191
  const caseActions = ourPConn.getValue(pCoreConstants.CASE_INFO.AVAILABLEACTIONS);
207
192
  let bCaseWideAction = false;
208
193
  if (caseActions && actionID) {
209
- const actionObj = caseActions.find(
210
- (caseAction) => caseAction.ID === actionID
211
- );
194
+ const actionObj = caseActions.find(caseAction => caseAction.ID === actionID);
212
195
  if (actionObj) {
213
- bCaseWideAction = actionObj.type === "Case";
196
+ bCaseWideAction = actionObj.type === 'Case';
214
197
  }
215
198
  }
216
199
  return bCaseWideAction;
217
200
  }
218
201
 
219
-
220
202
  function hasChildCaseAssignments() {
221
203
  const ourPConn = getPConnect();
222
204
 
@@ -229,12 +211,13 @@ export default function FlowContainer(props) {
229
211
  return false;
230
212
  }
231
213
 
232
-
233
214
  function hasAssignments() {
234
215
  const ourPConn = getPConnect();
235
216
 
236
217
  let bHasAssignments = false;
237
- const assignmentsList: Array<any> = ourPConn.getValue(pCoreConstants.CASE_INFO.D_CASE_ASSIGNMENTS_RESULTS);
218
+ const assignmentsList: Array<any> = ourPConn.getValue(
219
+ pCoreConstants.CASE_INFO.D_CASE_ASSIGNMENTS_RESULTS
220
+ );
238
221
  const thisOperator = PCore.getEnvironmentInfo().getOperatorIdentifier();
239
222
  // 8.7 includes assignments in Assignments List that may be assigned to
240
223
  // a different operator. So, see if there are any assignments for
@@ -247,45 +230,36 @@ export default function FlowContainer(props) {
247
230
  }
248
231
 
249
232
  for (const assignment of assignmentsList) {
250
- if (assignment["assigneeInfo"]["ID"] === thisOperator) {
233
+ if (assignment['assigneeInfo']['ID'] === thisOperator) {
251
234
  bAssignmentsForThisOperator = true;
252
235
  }
253
236
  }
254
237
 
255
238
  const bHasChildCaseAssignments = hasChildCaseAssignments();
256
239
 
257
- if (
258
- bAssignmentsForThisOperator ||
259
- bHasChildCaseAssignments ||
260
- isCaseWideLocalAction()
261
- ) {
240
+ if (bAssignmentsForThisOperator || bHasChildCaseAssignments || isCaseWideLocalAction()) {
262
241
  bHasAssignments = true;
263
242
  }
264
243
 
265
244
  return bHasAssignments;
266
245
  }
267
246
 
268
-
269
-
270
247
  function getActiveViewLabel() {
271
248
  const ourPConn = getPConnect();
272
249
 
273
- let activeActionLabel = "";
250
+ let activeActionLabel = '';
274
251
 
275
252
  const { CASE_INFO: CASE_CONSTS } = pCoreConstants;
276
253
 
277
254
  const caseActions = ourPConn.getValue(CASE_CONSTS.CASE_INFO_ACTIONS);
278
255
  const activeActionID = ourPConn.getValue(CASE_CONSTS.ACTIVE_ACTION_ID);
279
- const activeAction = caseActions.find(
280
- (action) => action.ID === activeActionID
281
- );
256
+ const activeAction = caseActions?.find(action => action.ID === activeActionID);
282
257
  if (activeAction) {
283
258
  activeActionLabel = activeAction.name;
284
259
  }
285
260
  return activeActionLabel;
286
261
  }
287
262
 
288
-
289
263
  // From SDK-WC updateSelf - so do this in useEffect that's run only when the props change...
290
264
  useEffect(() => {
291
265
  const localPConn = arNewChildren[0].getPConnect();
@@ -298,8 +272,7 @@ export default function FlowContainer(props) {
298
272
  let loadingInfo: any;
299
273
  try {
300
274
  loadingInfo = thePConn.getLoadingStatus();
301
- }
302
- catch (ex) {
275
+ } catch (ex) {
303
276
  // eslint-disable-next-line no-console
304
277
  console.error(`${thePConn.getComponentName()}: loadingInfo catch block`);
305
278
  }
@@ -311,9 +284,9 @@ export default function FlowContainer(props) {
311
284
  // this.psService.sendMessage(false);
312
285
  }
313
286
 
314
- const caseViewMode = thePConn.getValue("context_data.caseViewMode");
287
+ const caseViewMode = thePConn.getValue('context_data.caseViewMode');
315
288
  const { CASE_INFO: CASE_CONSTS } = pCoreConstants;
316
- if (caseViewMode && caseViewMode === "review") {
289
+ if (caseViewMode && caseViewMode === 'review') {
317
290
  setTimeout(() => {
318
291
  // updated for 8.7 - 30-Mar-2022
319
292
  const todoAssignments = getToDoAssignments(thePConn);
@@ -328,45 +301,71 @@ export default function FlowContainer(props) {
328
301
  // in React, when cancel is called, somehow the constructor for flowContainer is called which
329
302
  // does init/add of containers. This mimics that
330
303
  initContainer();
331
- }
332
- else if (caseViewMode && caseViewMode === "perform") {
304
+ } else if (caseViewMode && caseViewMode === 'perform') {
333
305
  // perform
334
306
  // debugger;
335
307
  setShowTodo(false);
336
308
 
337
309
  // this is different than Angular SDK, as we need to initContainer if root container reloaded
338
- if (window.sessionStorage.getItem("okToInitFlowContainer") === "true") {
310
+ if (window.sessionStorage.getItem('okToInitFlowContainer') === 'true') {
339
311
  initContainer();
340
312
  }
313
+ }
341
314
 
342
- // this check in routingInfo, mimic React to check and get the internals of the
315
+
316
+ // if have caseMessage show message and end
317
+ const theCaseMessages = thePConn.getValue('caseMessages');
318
+
319
+ if (theCaseMessages || !hasAssignments()) {
320
+ // Temp fix for 8.7 change: confirmationNote no longer coming through in caseMessages$.
321
+ // So, if we get here and caseMessages$ is empty, use default value in DX API response
322
+ setCaseMessages(
323
+ theCaseMessages || 'Thank you! The next step in this case has been routed appropriately.'
324
+ );
325
+ setHasCaseMessages(true);
326
+ setShowConfirm(true);
327
+
328
+ // publish this "assignmentFinished" for mashup, need to get approved as a standard
329
+ PCore.getPubSubUtils().publish('assignmentFinished');
330
+
331
+ // debugger;
332
+ setCheckSvg(Utils.getImageSrc('check', PCore.getAssetLoader().getStaticServerUrl()));
333
+ } else {
334
+ // debugger;
335
+ setHasCaseMessages(false);
336
+ setShowConfirm(false);
337
+ }
338
+
339
+ // this check in routingInfo, mimic React to check and get the internals of the
343
340
  // flowContainer and force updates to pConnect/redux
344
341
  if (routingInfo && loadingInfo !== undefined) {
345
-
346
342
  // debugging/investigation help
347
343
  // console.log(`${thePConn.getComponentName()}: >>routingInfo: ${JSON.stringify(routingInfo)}`);
348
344
 
349
345
  const currentOrder = routingInfo.accessedOrder;
350
346
  const currentItems = routingInfo.items;
351
347
  const type = routingInfo.type;
352
- if (currentOrder && currentItems) { // JA - making more similar to React version
348
+ if (currentOrder && currentItems) {
349
+ // JA - making more similar to React version
353
350
  const key = currentOrder[currentOrder.length - 1];
354
351
 
355
352
  // save off itemKey to be used for finishAssignment, etc.
356
353
  // debugger;
357
354
  setItemKey(key);
358
355
 
359
- if (currentOrder.length > 0 &&
356
+ if (
357
+ currentOrder.length > 0 &&
360
358
  currentItems[key] &&
361
359
  currentItems[key].view &&
362
- type === "single" &&
363
- !Utils.isEmptyObject(currentItems[key].view)) {
360
+ type === 'single' &&
361
+ !Utils.isEmptyObject(currentItems[key].view)
362
+ ) {
364
363
  const currentItem = currentItems[key];
365
364
  const rootView = currentItem.view;
366
365
  const { context } = rootView.config;
367
366
  const config = { meta: rootView };
368
367
 
369
- config["options"] = {
368
+ config['options'] = {
370
369
  context: currentItem.context,
371
370
  pageReference: context || localPConn.getPageReference(),
372
371
  hasForm: true,
@@ -380,7 +379,7 @@ export default function FlowContainer(props) {
380
379
 
381
380
  // Since we're setting an array, need to add in an appropriate key
382
381
  // to remove React warning.
383
- configObject["key"] = config["options"].parentPageReference;
382
+ configObject['key'] = config['options'].parentPageReference;
384
383
 
385
384
  // keep track of these changes
386
385
  const theNewChildren: Array<Object> = [];
@@ -394,102 +393,87 @@ export default function FlowContainer(props) {
394
393
  const oWorkItem = configObject.getPConnect(); // was theNewChildren[0].getPConnect()
395
394
  const oWorkData = oWorkItem.getDataObject();
396
395
 
397
-
398
396
  // check if have oWorkData, there are times due to timing of state change, when this
399
397
  // may not be available
400
398
  if (oWorkData) {
401
- setContainerName(getActiveViewLabel() || oWorkData.caseInfo.assignments[0].name);
399
+ setContainerName(getActiveViewLabel() || oWorkData.caseInfo.assignments?.[0].name);
402
400
  }
403
401
  }
404
402
  }
405
-
406
403
  }
407
- }
408
-
409
- // if have caseMessage show message and end
410
- const theCaseMessages = thePConn.getValue("caseMessages");
411
-
412
- if (theCaseMessages || !hasAssignments()) {
413
-
414
- // Temp fix for 8.7 change: confirmationNote no longer coming through in caseMessages$.
415
- // So, if we get here and caseMessages$ is empty, use default value in DX API response
416
- setCaseMessages(theCaseMessages || "Thank you! The next step in this case has been routed appropriately.");
417
- setHasCaseMessages(true);
418
-
419
-
420
- // publish this "assignmentFinished" for mashup, need to get approved as a standard
421
- PCore.getPubSubUtils().publish(
422
- "assignmentFinished");
423
-
424
-
425
- // debugger;
426
- setCheckSvg(Utils.getImageSrc("check", PCore.getAssetLoader().getStaticServerUrl()));
427
- }
428
- else {
429
- // debugger;
430
- setHasCaseMessages(false);
431
- }
432
404
  }, [props]);
433
405
 
434
406
  const caseId = thePConn.getCaseSummary().content.pyID;
435
- const urgency = getPConnect().getCaseSummary().assignments ? getPConnect().getCaseSummary().assignments[0].urgency : "";
407
+ const urgency = getPConnect().getCaseSummary().assignments
408
+ ? getPConnect().getCaseSummary().assignments?.[0].urgency
409
+ : '';
436
410
  const operatorInitials = Utils.getInitials(PCore.getEnvironmentInfo().getOperatorName());
437
411
  let instructionText = thePConn.getCaseSummary()?.assignments?.[0]?.instructions;
438
412
  if (instructionText === undefined) {
439
- instructionText = "";
413
+ instructionText = '';
440
414
  }
441
415
 
442
416
  return (
443
- <div style={{ textAlign: "left" }} id={buildName} className="psdk-flow-container-top">
444
- {!bHasCaseMessages ?
445
- (!todo_showTodo) ?
446
- (!displayOnlyFA) ?
417
+ <div style={{ textAlign: 'left' }} id={buildName} className='psdk-flow-container-top'>
418
+ {!bShowConfirm &&
419
+ (!todo_showTodo ? (
420
+ !displayOnlyFA ? (
447
421
  <Card className={classes.root}>
448
422
  <CardHeader
449
- title={<Typography variant="h6">{containerName}</Typography>}
423
+ title={<Typography variant='h6'>{containerName}</Typography>}
450
424
  subheader={`Task in ${caseId} \u2022 Priority ${urgency}`}
451
- avatar={
452
- <Avatar className={classes.avatar}>
453
- {operatorInitials}
454
- </Avatar>
455
- }
425
+ avatar={<Avatar className={classes.avatar}>{operatorInitials}</Avatar>}
456
426
  ></CardHeader>
457
- { instructionText !== '' ? <Typography variant="caption">{instructionText}</Typography> : null }
427
+ {instructionText !== '' ? (
428
+ <Typography variant='caption'>{instructionText}</Typography>
429
+ ) : null}
458
430
  <MuiPickersUtilsProvider utils={DayjsUtils}>
459
431
  <Assignment getPConnect={getPConnect} itemKey={itemKey}>
460
432
  {arNewChildrenAsReact}
461
433
  </Assignment>
462
434
  </MuiPickersUtilsProvider>
463
435
  </Card>
464
- :
436
+ ) : (
465
437
  <Card className={classes.root}>
466
- <Typography variant="h6">{containerName}</Typography>
467
- { instructionText !== '' ? <Typography variant="caption">{instructionText}</Typography> : null }
438
+ <Typography variant='h6'>{containerName}</Typography>
439
+ {instructionText !== '' ? (
440
+ <Typography variant='caption'>{instructionText}</Typography>
441
+ ) : null}
468
442
  <MuiPickersUtilsProvider utils={DayjsUtils}>
469
443
  <Assignment getPConnect={getPConnect} itemKey={itemKey}>
470
444
  {arNewChildrenAsReact}
471
445
  </Assignment>
472
446
  </MuiPickersUtilsProvider>
473
447
  </Card>
474
- :
448
+ )
449
+ ) : (
475
450
  <div>
476
- <ToDo getPConnect={getPConnect} caseInfoID={todo_caseInfoID} datasource={todo_datasource}
477
- showTodoList={todo_showTodoList} headerText={todo_headerText} type={TODO}
478
- context={todo_context} itemKey={itemKey}></ToDo>
451
+ <ToDo
452
+ getPConnect={getPConnect}
453
+ caseInfoID={todo_caseInfoID}
454
+ datasource={todo_datasource}
455
+ showTodoList={todo_showTodoList}
456
+ headerText={todo_headerText}
457
+ type={TODO}
458
+ context={todo_context}
459
+ itemKey={itemKey}
460
+ ></ToDo>
479
461
  </div>
480
- :
462
+ ))}
463
+ {bHasCaseMessages && (
481
464
  <div className={classes.alert}>
482
- <Alert severity="success">{caseMessages}</Alert>
465
+ <Alert severity='success'>{caseMessages}</Alert>
483
466
  </div>
484
- }
467
+ )}
468
+ {bShowConfirm && <div>{arNewChildrenAsReact}</div>}
485
469
  </div>
486
- )
470
+ );
487
471
  }
488
472
 
489
473
  FlowContainer.defaultProps = {
490
474
  children: null,
491
475
  getPConnect: null,
492
- name: "",
476
+ name: '',
493
477
  routingInfo: null,
494
478
  pageMessages: null
495
479
  };
@@ -25,7 +25,8 @@ const NO_HEADER_TEMPLATES = [
25
25
  'DetailsTwoColumn',
26
26
  'DetailsThreeColumn',
27
27
  'NarrowWideDetails',
28
- 'WideNarrowDetails'
28
+ 'WideNarrowDetails',
29
+ 'Confirmation'
29
30
  ];
30
31
 
31
32
  export default function View(props) {