Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions client/src/pages/admin/HomeAdmin.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import Box from '@mui/material/Box';
import UploadDialogAdmin from './UploadDialogAdmin';

function Home() {
return (
<Box>
<Box
textAlign="center"
sx={{
margin: '0 auto', marginTop: '5vh', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center',
}}
>
<Box width="80%">
<UploadDialogAdmin />
</Box>
</Box>

</Box>
);
}

export default Home;
221 changes: 221 additions & 0 deletions client/src/pages/admin/UploadDialogAdmin.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import {
TextField, Typography, Box, Card,
} from '@mui/material';
import axios from 'axios';
import Button from '@mui/material/Button';
import Snackbar from '@mui/material/Snackbar';
import CloudUploadIcon from '@mui/icons-material/CloudUpload';
import PictureAsPdfOutlinedIcon from '@mui/icons-material/PictureAsPdfOutlined';
import { v4 as uuidv4 } from 'uuid';
import convertSize from '../../utils/unitConverter';
import { Languages } from '../../constants';
/**
* Renders a non-modal dialog to upload new document.
*/
export default function UploadDialogAdmin({ sx }) {
const [isbn, setISBN] = useState('');
const [description, setDescription] = useState('');
const [title, setTitle] = useState('');
const [author, setAuthor] = useState('');
const [showToast, setShowToast] = useState(false);
const [snackbarMessage, setSnackbarMessage] = useState('');
const [bookFile, setBookFile] = useState(null);
const [bookCoverUrl, setBookCoverUrl] = useState('');

const validateForm = () => {
const newErrors = {};
if (!isbn) newErrors.field1 = 'ISBN is required';
if (!title) newErrors.field2 = 'Title is required';
if (!author) newErrors.field3 = 'Author is required';
if (!description) newErrors.field3 = 'Description is required';
if (!bookFile) newErrors.field4 = 'Book file is required';
return newErrors;
};

const handleUpload = async () => {
try {
const newErrors = validateForm();
if (Object.keys(newErrors).length === 0) {
setSnackbarMessage('Book uploaded successfully!');
setShowToast(true);
// Perform book uploading logic here
const formData = new FormData();
formData.append('file', bookFile);
formData.append('file-book', JSON.stringify({
id: uuidv4(),
title,
content: null,
language: Languages.English,
isbn,
author,
description,
cover: bookCoverUrl,
}));
const uploadApi = `${process.env.REACT_APP_SERVER_URL}/api/admin/uploadBook`;
await axios.post(uploadApi, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
// console.log(response);
} else {
setSnackbarMessage('Please fill in all required fields.');
setShowToast(true);
}
} catch (error) {
console.log(error);
setSnackbarMessage('Failed to upload book!');
setShowToast(true);
}
};

const handleCloseToast = () => {
setShowToast(false);
};

const handleISBN = async () => {
try {
const response = await axios.get(`https://openlibrary.org/api/books?bibkeys=ISBN:${isbn}&format=json&jscmd=data`);
const { data } = response;
const bookKey = `ISBN:${isbn}`;
if (data[bookKey]) {
const book = data[bookKey];
setTitle(book.title);
setAuthor(book.authors ? book.authors.map((authorr) => authorr.name).join(', ') : 'N/A');
setDescription(book.notes || '');
setBookCoverUrl(book.cover ? book.cover.medium : '');
}
} catch (error) {
console.log(error);
}
};

useEffect(
() => {
if (isbn !== '') handleISBN();
else {
setTitle('');
setAuthor('');
setDescription('');
}
},
[isbn],
);

return (
<Card
sx={{
width: '100%', height: '650px', padding: '2rem', borderRadius: '1rem', ...sx,
}}
variant="outlined"
>
<Typography variant="h6" align="left" gutterBottom>
Add a book
</Typography>
<Box display="flex" flexDirection="column">
<TextField
required
label="ISBN"
variant="filled"
fullWidth
value={isbn}
onChange={(e) => setISBN(e.target.value)}
/>
<TextField
required
label="Title"
variant="filled"
fullWidth
margin="normal"
value={title}
onChange={(e) => setTitle(e.target.value)}
/>
<TextField
required
label="Author"
variant="filled"
fullWidth
margin="normal"
value={author}
onChange={(e) => setAuthor(e.target.value)}
/>
<TextField
required
label="Description"
variant="filled"
fullWidth
margin="normal"
multiline
rows={5}
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
{/* Display uploaded file */}
{bookFile && (
<Box display="flex" gap={2} width="50%" alignItems="center">
<PictureAsPdfOutlinedIcon sx={{ width: '2rem', height: '2rem' }} />
<Typography
width="70%"
whiteSpace="nowrap"
overflow="hidden"
textOverflow="ellipsis"
align="left"
>
{bookFile.name}
</Typography>
<Typography>
{convertSize(bookFile.size)}

</Typography>
</Box>
)}
{/* Upload button */}
<div style={{ display: 'flex', alignItems: 'center' }}>
<Button
component="label"
role={undefined}
variant="contained"
color="secondary"
style={{
marginRight: '10px', marginTop: '10px', height: '50px',
}}
startIcon={<CloudUploadIcon />}
>
Choose File
<input
type="file"
hidden
onChange={(e) => setBookFile(e.target.files[0])}
/>
</Button>
<Button
variant="contained"
size="large"
color="primary"
style={{ marginTop: '10px', height: '50px' }}
onClick={handleUpload}
>
Upload
</Button>
</div>
<Snackbar
open={showToast}
autoHideDuration={3000}
onClose={handleCloseToast}
message={snackbarMessage}
/>

</Box>
</Card>
);
}

UploadDialogAdmin.propTypes = {
sx: PropTypes.instanceOf(Object),
};

UploadDialogAdmin.defaultProps = {
sx: {},
};
8 changes: 8 additions & 0 deletions client/src/routes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Home from './pages/Home';
import Reader from './pages/Reader';
import Library from './pages/Library';
import NotFound from './pages/NotFound';
import HomeAdmin from './pages/admin/HomeAdmin';

const routes = [
{
Expand Down Expand Up @@ -33,6 +34,13 @@ const routes = [
wrapInMainLayout: true,
showInNavbar: false,
},
{
name: 'Home Admin',
path: '/admin',
element: <HomeAdmin />,
wrapInMainLayout: true,
showInNavbar: false,
},
];

export default routes;
2 changes: 2 additions & 0 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const indexRouter = require('./routes/index');
const uploadRouter = require('./routes/upload');
const downloadRouter = require('./routes/download');
const summarizeRouter = require('./routes/summarize');
const uploadBook = require('./routes/uploadBook');

const app = express();

Expand All @@ -31,6 +32,7 @@ app.use('/', indexRouter);
app.use('/api/upload', uploadRouter);
app.use('/api/download', downloadRouter);
app.use('/api/summarize', summarizeRouter);
app.use('/api/admin', uploadBook);

// catch 404 and forward to error handler
app.use((req, res, next) => {
Expand Down
Loading