aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/newlightbox
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-05-08 21:03:08 -0400
committerbobzel <zzzman@gmail.com>2024-05-08 21:03:08 -0400
commitb858bd3cad81da41e63b9f8e807e41421ca4aa34 (patch)
tree99355f0595194e136494d50c527c859209935191 /src/client/views/newlightbox
parentb8907e69160d97d919fcd83eb86d60e3634205ca (diff)
lots of api cleanup and cycle removal
Diffstat (limited to 'src/client/views/newlightbox')
-rw-r--r--src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx22
-rw-r--r--src/client/views/newlightbox/ExploreView/ExploreView.tsx30
-rw-r--r--src/client/views/newlightbox/Header/LightboxHeader.tsx8
-rw-r--r--src/client/views/newlightbox/NewLightboxView.tsx62
-rw-r--r--src/client/views/newlightbox/RecommendationList/RecommendationList.tsx134
5 files changed, 112 insertions, 144 deletions
diff --git a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
index e48e993cf..3eb99f47a 100644
--- a/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
+++ b/src/client/views/newlightbox/ButtonMenu/ButtonMenu.tsx
@@ -1,24 +1,27 @@
+/* eslint-disable jsx-a11y/no-static-element-interactions */
+/* eslint-disable jsx-a11y/click-events-have-key-events */
import { action } from 'mobx';
import * as React from 'react';
import { Doc } from '../../../../fields/Doc';
import { InkTool } from '../../../../fields/InkField';
import { SnappingManager } from '../../../util/SnappingManager';
import { CollectionDockingView } from '../../collections/CollectionDockingView';
+import { DocumentView } from '../../nodes/DocumentView';
import { OpenWhereMod } from '../../nodes/OpenWhere';
import { NewLightboxView } from '../NewLightboxView';
import './ButtonMenu.scss';
-import { IButtonMenu } from './utils';
-export const ButtonMenu = (props: IButtonMenu) => {
+export function ButtonMenu() {
return (
- <div className={`newLightboxButtonMenu-container`}>
+ <div className="newLightboxButtonMenu-container">
<div
className="newLightboxView-navBtn"
title="toggle fit width"
onClick={e => {
e.stopPropagation();
NewLightboxView.LightboxDoc!._fitWidth = !NewLightboxView.LightboxDoc!._fitWidth;
- }}></div>
+ }}
+ />
<div
className="newLightboxView-tabBtn"
title="open in tab"
@@ -27,7 +30,8 @@ export const ButtonMenu = (props: IButtonMenu) => {
CollectionDockingView.AddSplit(NewLightboxView.LightboxDoc || NewLightboxView.LightboxDoc!, OpenWhereMod.none);
DocumentView.DeselectAll();
NewLightboxView.SetNewLightboxDoc(undefined);
- }}></div>
+ }}
+ />
<div
className="newLightboxView-penBtn"
title="toggle pen annotation"
@@ -35,7 +39,8 @@ export const ButtonMenu = (props: IButtonMenu) => {
onClick={e => {
e.stopPropagation();
Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen;
- }}></div>
+ }}
+ />
<div
className="newLightboxView-exploreBtn"
title="toggle explore mode to navigate among documents only"
@@ -43,7 +48,8 @@ export const ButtonMenu = (props: IButtonMenu) => {
onClick={action(e => {
e.stopPropagation();
SnappingManager.SetExploreMode(!SnappingManager.ExploreMode);
- })}></div>
+ })}
+ />
</div>
);
-};
+}
diff --git a/src/client/views/newlightbox/ExploreView/ExploreView.tsx b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
index a1d6375c4..f8c07cc43 100644
--- a/src/client/views/newlightbox/ExploreView/ExploreView.tsx
+++ b/src/client/views/newlightbox/ExploreView/ExploreView.tsx
@@ -1,32 +1,34 @@
-import './ExploreView.scss';
-import { IBounds, IExploreView, emptyBounds } from './utils';
-import { IRecommendation } from '../components';
+/* eslint-disable jsx-a11y/no-static-element-interactions */
+/* eslint-disable jsx-a11y/click-events-have-key-events */
import * as React from 'react';
-import { NewLightboxView } from '../NewLightboxView';
import { StrCast } from '../../../../fields/Types';
+import { NewLightboxView } from '../NewLightboxView';
+import './ExploreView.scss';
+import { IExploreView, emptyBounds } from './utils';
-export const ExploreView = (props: IExploreView) => {
+export function ExploreView(props: IExploreView) {
const { recs, bounds = emptyBounds } = props;
return (
- <div className={`exploreView-container`}>
+ <div className="exploreView-container">
{recs &&
recs.map(rec => {
- const x_bound: number = Math.max(Math.abs(bounds.max_x), Math.abs(bounds.min_x));
- const y_bound: number = Math.max(Math.abs(bounds.max_y), Math.abs(bounds.min_y));
+ const xBound: number = Math.max(Math.abs(bounds.max_x), Math.abs(bounds.min_x));
+ const yBound: number = Math.max(Math.abs(bounds.max_y), Math.abs(bounds.min_y));
if (rec.embedding) {
- const x = (rec.embedding.x / x_bound) * 50;
- const y = (rec.embedding.y / y_bound) * 50;
+ const x = (rec.embedding.x / xBound) * 50;
+ const y = (rec.embedding.y / yBound) * 50;
return (
- <div className={`exploreView-doc`} onClick={() => {}} style={{ top: `calc(50% + ${y}%)`, left: `calc(50% + ${x}%)` }}>
+ <div className="exploreView-doc" onClick={() => {}} style={{ top: `calc(50% + ${y}%)`, left: `calc(50% + ${x}%)` }}>
{rec.title}
</div>
);
- } else return null;
+ }
+ return null;
})}
- <div className={`exploreView-doc`} style={{ top: `calc(50% + ${0}%)`, left: `calc(50% + ${0}%)`, background: '#073763', color: 'white' }}>
+ <div className="exploreView-doc" style={{ top: `calc(50% + ${0}%)`, left: `calc(50% + ${0}%)`, background: '#073763', color: 'white' }}>
{StrCast(NewLightboxView.LightboxDoc?.title)}
</div>
</div>
);
-};
+}
diff --git a/src/client/views/newlightbox/Header/LightboxHeader.tsx b/src/client/views/newlightbox/Header/LightboxHeader.tsx
index 51bfaa4e5..882d28fba 100644
--- a/src/client/views/newlightbox/Header/LightboxHeader.tsx
+++ b/src/client/views/newlightbox/Header/LightboxHeader.tsx
@@ -4,8 +4,8 @@ import { BsBookmark, BsBookmarkFill } from 'react-icons/bs';
import { MdTravelExplore } from 'react-icons/md';
import { Doc } from '../../../../fields/Doc';
import { StrCast } from '../../../../fields/Types';
-import { LightboxView } from '../../LightboxView';
import { Colors } from '../../global/globalEnums';
+import { DocumentView } from '../../nodes/DocumentView';
import { NewLightboxView } from '../NewLightboxView';
import { EditableText } from '../components/EditableText';
import { getType } from '../utils';
@@ -14,11 +14,11 @@ import { INewLightboxHeader } from './utils';
export function NewLightboxHeader(props: INewLightboxHeader) {
const { height = 100, width } = props;
- const [doc, setDoc] = React.useState<Doc | undefined>(LightboxView.LightboxDoc);
+ const [doc, setDoc] = React.useState<Doc | undefined>(DocumentView.LightboxDoc());
const [editing, setEditing] = React.useState<boolean>(false);
const [title, setTitle] = React.useState<JSX.Element | null>(null);
React.useEffect(() => {
- const lbDoc = LightboxView.LightboxDoc;
+ const lbDoc = DocumentView.LightboxDoc();
setDoc(lbDoc);
if (lbDoc) {
setTitle(
@@ -32,7 +32,7 @@ export function NewLightboxHeader(props: INewLightboxHeader) {
/>
);
}
- }, [LightboxView.LightboxDoc]);
+ }, [DocumentView.LightboxDoc()]);
const [saved, setSaved] = React.useState<boolean>(false);
diff --git a/src/client/views/newlightbox/NewLightboxView.tsx b/src/client/views/newlightbox/NewLightboxView.tsx
index 558ce7e38..c86ddb745 100644
--- a/src/client/views/newlightbox/NewLightboxView.tsx
+++ b/src/client/views/newlightbox/NewLightboxView.tsx
@@ -1,6 +1,5 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable jsx-a11y/click-events-have-key-events */
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
@@ -12,7 +11,6 @@ import { Cast, NumCast, StrCast, toList } from '../../../fields/Types';
import { SnappingManager } from '../../util/SnappingManager';
import { Transform } from '../../util/Transform';
import { GestureOverlay } from '../GestureOverlay';
-import { LightboxView } from '../LightboxView';
import { DefaultStyleProvider } from '../StyleProvider';
import { DocumentView } from '../nodes/DocumentView';
import { OpenWhere } from '../nodes/OpenWhere';
@@ -108,7 +106,7 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
DocumentView.CurrentlyPlaying?.forEach(dv => dv.ComponentView?.Pause?.());
// DocumentView.PinDoc(doc, { hidePresBox: true });
this._history ? this._history.push({ doc, target }) : (this._history = [{ doc, target }]);
- if (doc !== LightboxView.LightboxDoc) {
+ if (doc !== DocumentView.LightboxDoc()) {
this._savedState = {
layout_fieldKey: StrCast(doc.layout_fieldKey),
panX: Cast(doc.freeform_panX, 'number', null),
@@ -151,11 +149,12 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
if (NewLightboxView._history?.lastElement().target !== target) NewLightboxView._history?.push({ doc, target });
} else if (!target && NewLightboxView.path.length) {
const saved = NewLightboxView._savedState;
- if (LightboxView.LightboxDoc && saved) {
- LightboxView.LightboxDoc._freeform_panX = saved.panX;
- LightboxView.LightboxDoc._freeform_panY = saved.panY;
- LightboxView.LightboxDoc._freeform_scale = saved.scale;
- LightboxView.LightboxDoc._layout_scrollTop = saved.scrollTop;
+ const lightboxDoc = DocumentView.LightboxDoc();
+ if (lightboxDoc && saved) {
+ lightboxDoc._freeform_panX = saved.panX;
+ lightboxDoc._freeform_panY = saved.panY;
+ lightboxDoc._freeform_scale = saved.scale;
+ lightboxDoc._layout_scrollTop = saved.scrollTop;
}
const pop = NewLightboxView.path.pop();
if (pop) {
@@ -176,7 +175,7 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
NewLightboxView.SetNewLightboxDoc(undefined);
return;
}
- const { doc, target } = NewLightboxView._history?.lastElement();
+ const { doc, target } = NewLightboxView._history?.lastElement() ?? { doc: undefined, target: undefined };
const docView = DocumentView.getLightboxDocumentView(target || doc);
if (docView) {
NewLightboxView._docTarget = target;
@@ -248,14 +247,15 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
@computed
get documentView() {
- if (!LightboxView.LightboxDoc) return null;
+ const lightboxDoc = DocumentView.LightboxDoc();
+ if (!lightboxDoc) return null;
return (
<GestureOverlay isActive>
<DocumentView
ref={action((r: DocumentView | null) => {
NewLightboxView._docView = r !== null ? r : undefined;
})}
- Document={LightboxView.LightboxDoc}
+ Document={lightboxDoc}
PanelWidth={this.newLightboxWidth}
PanelHeight={this.newLightboxHeight}
LayoutTemplate={NewLightboxView.LightboxDocTemplate}
@@ -281,50 +281,14 @@ export class NewLightboxView extends React.Component<LightboxViewProps> {
newLightboxWidth = () => this.props.PanelWidth - 420;
newLightboxHeight = () => this.props.PanelHeight - 140;
newLightboxScreenToLocal = () => new Transform(-this.leftBorder, -this.topBorder, 1);
- navBtn = (left: Opt<string | number>, bottom: Opt<number>, top: number, icon: string, display: () => string, click: (e: React.MouseEvent) => void, color?: string) => (
- <div
- className="newLightboxView-navBtn-frame"
- style={{
- display: display(),
- left,
- width: bottom !== undefined ? undefined : Math.min(this.props.PanelWidth / 4, this.props.maxBorder[0]),
- bottom,
- }}>
- <div className="newLightboxView-navBtn" title={color} style={{ top, color: color ? 'red' : 'white', background: color ? 'white' : undefined }} onClick={click}>
- <div style={{ height: 10 }}>{color}</div>
- <FontAwesomeIcon icon={icon as any} size="3x" />
- </div>
- </div>
- );
docFilters = () => NewLightboxView._docFilters || [];
- @action
- stepInto = () => {
- NewLightboxView.path.push({
- doc: LightboxView.LightboxDoc,
- target: NewLightboxView._docTarget,
- future: NewLightboxView._future,
- history: NewLightboxView._history,
- saved: NewLightboxView._savedState,
- });
- const coll = NewLightboxView._docTarget;
- if (coll) {
- const fieldKey = Doc.LayoutFieldKey(coll);
- const contents = [...DocListCast(coll[fieldKey]), ...DocListCast(coll[fieldKey + '_annotations'])];
- const links = Doc.Links(coll)
- .map(link => Doc.getOppositeAnchor(link, coll))
- .filter(doc => doc)
- .map(doc => doc!);
- NewLightboxView.SetNewLightboxDoc(coll, undefined, contents.length ? contents : links);
- }
- };
- future = () => NewLightboxView._future;
render() {
const newLightboxHeaderHeight = 100;
let downx = 0;
let downy = 0;
- return !LightboxView.LightboxDoc ? null : (
+ return !DocumentView.LightboxDoc() ? null : (
<div
className="newLightboxView-frame"
onPointerDown={e => {
@@ -376,7 +340,7 @@ export class NewLightboxTourBtn extends React.Component<NewLightboxTourBtnProps>
0,
0,
'chevron-down',
- () => (LightboxView.LightboxDoc /* && this.props.future()?.length */ ? '' : 'none'),
+ () => (DocumentView.LightboxDoc() /* && this.props.future()?.length */ ? '' : 'none'),
e => {
e.stopPropagation();
this.props.stepInto();
diff --git a/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx b/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx
index 1d502b73f..dc3339cd3 100644
--- a/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx
+++ b/src/client/views/newlightbox/RecommendationList/RecommendationList.tsx
@@ -1,3 +1,7 @@
+/* eslint-disable react/jsx-props-no-spreading */
+/* eslint-disable jsx-a11y/no-static-element-interactions */
+/* eslint-disable jsx-a11y/click-events-have-key-events */
+/* eslint-disable guard-for-in */
import { IconButton, Size, Type } from 'browndash-components';
import * as React from 'react';
import { FaCaretDown, FaCaretUp } from 'react-icons/fa';
@@ -5,17 +9,15 @@ import { GrClose } from 'react-icons/gr';
import { DocListCast, StrListCast } from '../../../../fields/Doc';
import { List } from '../../../../fields/List';
import { StrCast } from '../../../../fields/Types';
-import { LightboxView } from '../../LightboxView';
import { Colors } from '../../global/globalEnums';
+import { DocumentView } from '../../nodes/DocumentView';
import { IBounds } from '../ExploreView/utils';
import { NewLightboxView } from '../NewLightboxView';
import { IRecommendation, Recommendation } from '../components';
import { IDocRequest, fetchKeywords, fetchRecommendations } from '../utils';
import './RecommendationList.scss';
-import { IRecommendationList } from './utils';
-export const RecommendationList = (props: IRecommendationList) => {
- const { loading, keywords } = props;
+export function RecommendationList() {
const [loadingKeywords, setLoadingKeywords] = React.useState<boolean>(true);
const [showMore, setShowMore] = React.useState<boolean>(false);
const [keywordsLoc, setKeywordsLoc] = React.useState<string[]>([]);
@@ -25,21 +27,22 @@ export const RecommendationList = (props: IRecommendationList) => {
React.useEffect(() => {
const getKeywords = async () => {
- let text = StrCast(LightboxView.LightboxDoc?.text);
+ const text = StrCast(DocumentView.LightboxDoc()?.text);
console.log('[1] fetching keywords');
const response = await fetchKeywords(text, 5, true);
console.log('[2] response:', response);
const kw = response.keywords;
console.log(kw);
NewLightboxView.SetKeywords(kw);
- if (LightboxView.LightboxDoc) {
+ const lightboxDoc = DocumentView.LightboxDoc();
+ if (lightboxDoc) {
console.log('setting keywords on doc');
- LightboxView.LightboxDoc.keywords = new List<string>(kw);
+ lightboxDoc.keywords = new List<string>(kw);
setKeywordsLoc(NewLightboxView.Keywords);
}
setLoadingKeywords(false);
};
- let keywordsList = StrListCast(LightboxView.LightboxDoc!.keywords);
+ const keywordsList = StrListCast(DocumentView.LightboxDoc()!.keywords);
if (!keywordsList || keywordsList.length < 2) {
setLoadingKeywords(true);
getKeywords();
@@ -57,14 +60,14 @@ export const RecommendationList = (props: IRecommendationList) => {
console.log('fetching recommendations');
let query = 'undefined';
if (keywordsLoc) query = keywordsLoc.join(',');
- let src = StrCast(NewLightboxView.LightboxDoc?.text);
- let dashDocs: IDocRequest[] = [];
+ const src = StrCast(NewLightboxView.LightboxDoc?.text);
+ const dashDocs: IDocRequest[] = [];
// get linked docs
- let linkedDocs = DocListCast(NewLightboxView.LightboxDoc?.links);
+ const linkedDocs = DocListCast(NewLightboxView.LightboxDoc?.links);
console.log('linked docs', linkedDocs);
// get context docs (docs that are also in the collection)
- // let contextDocs: Doc[] = DocListCast(DocCast(LightboxView.LightboxDoc?.context).data)
- // let docId = LightboxView.LightboxDoc && LightboxView.LightboxDoc[Id]
+ // let contextDocs: Doc[] = DocListCast(DocCast(DocumentView.LightboxDoc()?.context).data)
+ // let docId = DocumentView.LightboxDoc() && DocumentView.LightboxDoc()[Id]
// console.log("context docs", contextDocs)
// contextDocs.forEach((doc: Doc) => {
// if (docId !== doc[Id]){
@@ -79,10 +82,8 @@ export const RecommendationList = (props: IRecommendationList) => {
console.log('dash docs', dashDocs);
if (query !== undefined) {
const response = await fetchRecommendations(src, query, [], true);
- const num_recs = response.num_recommendations;
- const recs = response.recommendations;
- const keywords = response.keywords;
- const response_bounds: IBounds = {
+ const theRecs = response.recommendations;
+ const responseBounds: IBounds = {
max_x: response.max_x,
max_y: response.max_y,
min_x: response.min_x,
@@ -93,22 +94,23 @@ export const RecommendationList = (props: IRecommendationList) => {
// setKeywordsLoc(NewLightboxView.Keywords);
// }
// console.log(response_bounds)
- NewLightboxView.SetBounds(response_bounds);
+ NewLightboxView.SetBounds(responseBounds);
const recommendations: IRecommendation[] = [];
- for (const key in recs) {
+ // eslint-disable-next-line no-restricted-syntax
+ for (const key in theRecs) {
console.log(key);
- const title = recs[key].title;
- const url = recs[key].url;
- const type = recs[key].type;
- const text = recs[key].text;
- const transcript = recs[key].transcript;
- const previewUrl = recs[key].previewUrl;
- const embedding = recs[key].embedding;
- const distance = recs[key].distance;
- const source = recs[key].source;
- const related_concepts = recs[key].related_concepts;
- const docId = recs[key].doc_id;
- related_concepts.length >= 1 &&
+ const { title } = theRecs[key];
+ const { url } = theRecs[key];
+ const { type } = theRecs[key];
+ const { text } = theRecs[key];
+ const { transcript } = theRecs[key];
+ const { previewUrl } = theRecs[key];
+ const { embedding } = theRecs[key];
+ const { distance } = theRecs[key];
+ const { source } = theRecs[key];
+ const { related_concepts: relatedConcepts } = theRecs[key];
+ const docId = theRecs[key].doc_id;
+ relatedConcepts.length >= 1 &&
recommendations.push({
title: title,
data: url,
@@ -119,14 +121,15 @@ export const RecommendationList = (props: IRecommendationList) => {
embedding: embedding,
distance: Math.round(distance * 100) / 100,
source: source,
- related_concepts: related_concepts,
+ related_concepts: relatedConcepts,
docId: docId,
});
}
recommendations.sort((a, b) => {
if (a.distance && b.distance) {
return a.distance - b.distance;
- } else return 0;
+ }
+ return 0;
});
console.log('[rec]: ', recommendations);
NewLightboxView.SetRecs(recommendations);
@@ -138,12 +141,12 @@ export const RecommendationList = (props: IRecommendationList) => {
return (
<div
- className={`recommendationlist-container`}
+ className="recommendationlist-container"
onPointerDown={e => {
e.stopPropagation();
}}>
- <div className={`header`}>
- <div className={`title`}>Recommendations</div>
+ <div className="header">
+ <div className="title">Recommendations</div>
{NewLightboxView.LightboxDoc && (
<div style={{ fontSize: 10 }}>
The recommendations are produced based on the text in the document{' '}
@@ -153,65 +156,58 @@ export const RecommendationList = (props: IRecommendationList) => {
. The following keywords are used to fetch the recommendations.
</div>
)}
- <div className={`lb-label`}>Keywords</div>
+ <div className="lb-label">Keywords</div>
{loadingKeywords ? (
- <div className={`keywords`}>
+ <div className="keywords">
<div className={`keyword ${loadingKeywords && 'loading'}`} />
<div className={`keyword ${loadingKeywords && 'loading'}`} />
<div className={`keyword ${loadingKeywords && 'loading'}`} />
<div className={`keyword ${loadingKeywords && 'loading'}`} />
</div>
) : (
- <div className={`keywords`}>
+ <div className="keywords">
{keywordsLoc &&
- keywordsLoc.map((word, ind) => {
- return (
- <div className={`keyword`}>
- {word}
- <IconButton
- type={Type.PRIM}
- size={Size.XSMALL}
- color={Colors.DARK_GRAY}
- icon={<GrClose />}
- onClick={() => {
- let kw = keywordsLoc;
- kw.splice(ind);
- NewLightboxView.SetKeywords(kw);
- }}
- />
- </div>
- );
- })}
+ keywordsLoc.map((word, ind) => (
+ <div className="keyword">
+ {word}
+ <IconButton
+ type={Type.PRIM}
+ size={Size.XSMALL}
+ color={Colors.DARK_GRAY}
+ icon={<GrClose />}
+ onClick={() => {
+ const kw = keywordsLoc;
+ kw.splice(ind);
+ NewLightboxView.SetKeywords(kw);
+ }}
+ />
+ </div>
+ ))}
</div>
)}
{!showMore ? (
<div
- className={`lb-caret`}
+ className="lb-caret"
onClick={() => {
setShowMore(true);
}}>
More <FaCaretDown />
</div>
) : (
- <div className={`more`}>
+ <div className="more">
<div
- className={`lb-caret`}
+ className="lb-caret"
onClick={() => {
setShowMore(false);
}}>
Less <FaCaretUp />
</div>
- <div className={`lb-label`}>Type</div>
- <div className={`lb-label`}>Sources</div>
+ <div className="lb-label">Type</div>
+ <div className="lb-label">Sources</div>
</div>
)}
</div>
- <div className={`recommendations`}>
- {recs &&
- recs.map((rec: IRecommendation) => {
- return <Recommendation {...rec} />;
- })}
- </div>
+ <div className="recommendations">{recs && recs.map((rec: IRecommendation) => <Recommendation {...rec} />)}</div>
</div>
);
-};
+}