Skip to content

Commit

Permalink
FEATURE : Include an existing image into an existing collection
Browse files Browse the repository at this point in the history
  • Loading branch information
Nizreenana committed Jul 18, 2024
1 parent 5a6e9be commit 1fe818a
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 22 deletions.
5 changes: 5 additions & 0 deletions backend/src/views/all_collection/map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function (doc) {
if ( doc.links.filter(e => e.verb === 'includes').length > 0 ){
emit(doc.dc_title, doc);
}
}
61 changes: 61 additions & 0 deletions frontend/src/components/CollectionList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {FolderPlus} from 'react-bootstrap-icons';
import Card from 'react-bootstrap/Card';
import {useState} from 'react';
import ExistingCollection from './ExistingCollection';
import FutureCollection from './FutureCollection';

function CollectionList({relatedTo, setLastUpdate, backend, collections}) {
const [showList, setShowList] = useState(false);
const [searchQuery, setSearchQuery] = useState('');

const handleShowList = () => {
setShowList(!showList);
};

const handleSearchChange = (event) => {
setSearchQuery(event.target.value);
};

const filteredCollections = collections.filter(collection =>
collection.value.dc_title.toLowerCase().includes(searchQuery.toLowerCase())
);

return (
<div>
<Card className="h-100">
<Card.Body className="text-center">
<FolderPlus
className="icon addCollection" onClick={handleShowList}
/>
</Card.Body>
</Card>
{showList && (
<div>
<Card className="h-100">
<Card.Body>
<input
type="text"
placeholder="Search collections"
value={searchQuery}
onChange={handleSearchChange}
className="form-control"
/>
</Card.Body>
</Card>
<FutureCollection relatedTo={relatedTo} {...{setLastUpdate, backend}} />
{filteredCollections.map(collection => (
<ExistingCollection
key={collection.id}
relatedTo={relatedTo}
collection={collection}
setShowList={setShowList}
{...{setLastUpdate, backend}}
/>
))}
</div>
)}
</div>
);
}

export default CollectionList;
5 changes: 3 additions & 2 deletions frontend/src/components/DocumentsCards.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import Row from 'react-bootstrap/Row';
import Metadata from './Metadata';
import BrowseTools from './BrowseTools';
import FutureDocument from './FutureDocument';
import CollectionList from './CollectionList';
import { TypeBadge } from './Type';

// asSource is a flag that indicates whether to create a parent (left) or a glose (right)
function DocumentsCards({docs, expandable, byRow, createOn, setLastUpdate, backend, asSource = false}) {
function DocumentsCards({docs, expandable, byRow, createOn, setLastUpdate, backend, collections, asSource = false}) {
return (
<Row className="gy-4">
{docs.map(x => x._id &&
Expand All @@ -24,7 +25,7 @@ function DocumentsCards({docs, expandable, byRow, createOn, setLastUpdate, backe
</Col>
{(!asSource && createOn.length > 0) &&
<Col>
<FutureDocument relatedTo={createOn} verb="includes" {...{setLastUpdate, backend}} />
<CollectionList relatedTo={createOn} collections={collections} {...{setLastUpdate, backend}} />
</Col>
}
</Row>
Expand Down
44 changes: 44 additions & 0 deletions frontend/src/components/ExistingCollection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import '../styles/ExistingCollection.css';
import Card from 'react-bootstrap/Card';
import { useNavigate } from 'react-router-dom';

function ExistingCollection({relatedTo, collection, setLastUpdate, backend, setShowList}) {
const navigate = useNavigate();
const id = collection._id;
const title = extractSubstring(collection.value.dc_title);

let handleClick = async () => {
let newLink = {verb: 'includes', object: relatedTo[0]};
let updatedLinks = [...collection.value.links, newLink];
backend.putDocument({
...collection.value,
links: updatedLinks
}).then(() => {
setLastUpdate(collection.value._id);
navigate((relatedTo.length ? '#' : '/') + collection.value._id);
});
setShowList(false);
};

return (
<Card onClick={handleClick} className="existingCollection collectionList">
<Card.Body>
<span>{title}</span>
</Card.Body>
</Card>
);
}

function extractSubstring(str) {
if (str.includes('–')) {
str = str.split('–')[0];
}

if (str.length > 25) {
str = str.substring(0, 25) + '...';
}

return str;
}

export default ExistingCollection;
37 changes: 37 additions & 0 deletions frontend/src/components/FutureCollection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useNavigate } from 'react-router-dom';
import Card from 'react-bootstrap/Card';
import { v4 as uuidv4 } from 'uuid';

function FutureCollection({relatedTo, setLastUpdate, backend}) {
const navigate = useNavigate();

let handleClick = async () => {
let _id = uuidv4();
let editors = [backend.credentials.name];
let links = relatedTo.map(object => ({verb: 'includes', object}));
backend.putDocument({
_id,
editors,
dc_creator: '<CREATOR>',
dc_title: '<TITLE>',
dc_issued: new Date(),
text: '',
dc_license: 'https://creativecommons.org/licenses/by-sa/4.0/',
links
})
.then((x) => {
setLastUpdate(_id);
navigate((relatedTo.length ? '#' : '/') + _id);
});
};

return (
<Card className="h-100">
<Card.Body className="creation">
<span title="Create a collection from this document" className="icon create-collection" onClick={handleClick}>Create a new Collection.</span>
</Card.Body>
</Card>
);
}

export default FutureCollection;
23 changes: 7 additions & 16 deletions frontend/src/components/FutureDocument.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import '../styles/FutureDocument.css';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { Card, Form} from 'react-bootstrap';
import { PlusLg, FolderPlus } from 'react-bootstrap-icons';
import { PlusLg } from 'react-bootstrap-icons';
import { v4 as uuid } from 'uuid';

function FutureDocument({relatedTo, verb = 'refersTo', setLastUpdate, backend, asSource = false}) {
const [selectedVerb, setSelectedVerb] = useState(verb);
const fixedType = relatedTo.length === 0 || verb === 'includes' || asSource;
const fixedType = relatedTo.length === 0 || asSource;

const handleSelectChange = (event) => {
setSelectedVerb(event.target.value);
Expand Down Expand Up @@ -80,20 +80,11 @@ function FutureDocumentIcon({relatedTo, verb, setLastUpdate, backend, asSource =
}
};

switch (verb) {
case 'includes':
return (
<FolderPlus title="Create a collection from this document"
className="icon create-collection" onClick={handleClick}
/>
);
default:
return (
<PlusLg title={`Create a document ${asSource ? 'as a source' : relatedTo.length ? 'as a glose' : 'from scratch'}`}
className="icon create-document ms-2" onClick={handleClick}
/>
);
}
return (
<PlusLg title={`Create a document ${asSource ? 'as a source' : relatedTo.length ? 'as a glose' : 'from scratch'}`}
className="icon create-document ms-2" onClick={handleClick}
/>
);
}

export default FutureDocument;
23 changes: 19 additions & 4 deletions frontend/src/routes/Lectern.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ function Lectern({backend}) {
const [scholiaMetadata, setScholiaMetadata] = useState([]);
const [content, setContent] = useState([]);
const [lastUpdate, setLastUpdate] = useState();
const [collections, setCollections] = useState([]);
let {id} = useParams();
let margin = useLocation().hash.slice(1);
let hasRubrics = (id, rows) => rows.some(x => x.key[1] !== 0 && x.value.isPartOf === id && x.value.text);
Expand All @@ -30,6 +31,18 @@ function Lectern({backend}) {
backend.refreshContent(id, setContent);
}, [id, lastUpdate]);

useEffect(() => {
backend.getView({view: 'all_collection'})
.then(
(rows) => {
setCollections(rows);
},
(error) => {
console.log(error.message);
}
);
}, []);

useEffect(() => {
if (metadata.length) {
let focusedDocument = metadata.find(x => (x._id === id));
Expand Down Expand Up @@ -86,29 +99,31 @@ function Lectern({backend}) {
}
}, [id, margin, content, lastUpdate]);

console.log('collections :', collections);

return (
<Container className="screen">
<Row>
<Col md={2} className="sources">
<DocumentsCards docs={sourcesOfSourceMetadata} createOn={[id]} asSource={true} byRow={1} {...{setLastUpdate, backend}} />
<DocumentsCards docs={sourcesOfSourceMetadata} collections={collections} createOn={[id]} asSource={true} byRow={1} {...{setLastUpdate, backend}} />
</Col>
<OpenedDocuments
hasSources={sourcesOfSourceMetadata.length > 0}
{...{backend, lectern, metadata, sourceMetadata, margin, id, setLastUpdate}}
/>
<References scholiaMetadata={scholiaMetadata} active={!margin}
<References scholiaMetadata={scholiaMetadata} active={!margin} collections={collections}
createOn={[id]} {...{setLastUpdate, backend}}
/>
</Row>
</Container>
);
}

function References({scholiaMetadata, active, createOn, setLastUpdate, backend}) {
function References({scholiaMetadata, active, createOn, setLastUpdate, backend, collections}) {
if (!active) return;
return (
<Col className="gloses" >
<DocumentsCards docs={scholiaMetadata} expandable={true} byRow={1}
<DocumentsCards docs={scholiaMetadata} expandable={true} byRow={1} collections={collections}
{...{createOn, setLastUpdate, backend}}
/>
</Col>
Expand Down
8 changes: 8 additions & 0 deletions frontend/src/styles/ExistingCollection.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.existingCollection {
height: 56px !important;
width: inherit;
justify-content: center;
align-items: center;
overflow: hidden; /* hide content outside the container */
white-space: nowrap; /* disallow text wrapping */
}

0 comments on commit 1fe818a

Please sign in to comment.