// Main layout for gallery page. import { useCallback, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { Link as RouterLink } from 'react-router-dom' import PropTypes from 'prop-types' import { Button, Card, CardActionArea, CardActions, CardContent, CardMedia, Container, CssBaseline, FormControl, Grid, Input, InputLabel, MenuItem, Select, Typography } from '@material-ui/core' import { makeStyles } from '@material-ui/core/styles' import { fetchGallery } from '../redux/dashboardSlice' import api from '../utils/Api' const useStyles = makeStyles((theme) => ({ mainHead: { width: '100%', backgroundColor: '#404040', color: '#fff' }, title: { fontSize: 18, color: '#80ff80' }, header: { padding: theme.spacing(5, 0, 6, 0) }, root: { display: 'flex', minHeight: '100vh', backgroundColor: '#f4f6f8' }, media: { marginTop: theme.spacing(3), height: 170 } })) const images = require.context('../static/gallery', true) // Card displaying overview of gallery sample schematics. const SchematicCard = ({ sch }) => { const classes = useStyles() useEffect(() => { document.title = 'Gallery - ' + process.env.REACT_APP_NAME }, []) const imageName = images('./' + sch.media) return ( <> {sch.name} {sch.description} ) } SchematicCard.propTypes = { sch: PropTypes.object } // Card displaying gallery page header. const MainCard = () => { const classes = useStyles() const typography = process.env.REACT_APP_NAME + ' Gallery' const diagramTypography = 'Sample ' + process.env.REACT_APP_SMALL_DIAGRAMS_NAME + ' are listed below...' return ( {typography} {diagramTypography} ) } const BookDropdown = ({ onBookChange }) => { const [books, setBooks] = useState([]) // To store books from the backend const [selectedBook, setSelectedBook] = useState('') // Fetch books from the backend (optional, or use static data) const fetchBooks = useCallback(() => { api.get('save/books') .then((res) => { if (res.status !== 200) { throw new Error(`HTTP error! Status: ${res.status}`) } setBooks(res.data) // Assuming the API returns an array of books }) .catch(err => { console.error('Error fetching books:', err) }) }, []) useEffect(() => { fetchBooks() return () => { setBooks([]) } }, [fetchBooks]) // Handle dropdown selection change const handleChange = (evt) => { const selectedValue = evt.target.value setSelectedBook(selectedValue) onBookChange(selectedValue) // Notify the parent component } return ( Book ) } BookDropdown.propTypes = { onBookChange: PropTypes.func.isRequired } const SearchComponent = ({ onSearch }) => { const [searchTerm, setSearchTerm] = useState('') const handleSearch = (event) => { const value = event.target.value.trimStart() setSearchTerm(value) onSearch(value) } return ( Search ) } SearchComponent.propTypes = { onSearch: PropTypes.func.isRequired } const Gallery = () => { const classes = useStyles() const GallerySchSample = useSelector(state => state.dashboard.gallery) // State to store the selected book ID const [selectedBook, setSelectedBook] = useState('') const [searchTerm, setSearchTerm] = useState('') const dispatch = useDispatch() useEffect(() => { dispatch(fetchGallery()) }, [dispatch]) // Handle dropdown selection change const handleBookChange = (book) => { setSelectedBook(book) } // Handle search term change const handleSearch = (term) => { setSearchTerm(term) } const filteredSchematics = (() => { if (!selectedBook) return [] if (selectedBook === 'all') return GallerySchSample const selectedBookId = Number(selectedBook) return GallerySchSample.filter((sch) => sch.book_id === selectedBookId) })() const NOBLOCK = /^no./ const SCE = /^(sce|sci|script)/ const NOSCE = /^no(sce|sci|script)/ const terms = searchTerm.trim().toLowerCase().split(/\s+/).filter(Boolean) // Then, filter based on the search term (independent from book selection) const finalfilteredSchematics = terms.length === 0 ? filteredSchematics : filteredSchematics.filter((sch) => { return terms.every((st) => sch.lcname.includes(st) || sch.lcdescription.includes(st) || (!NOBLOCK.test(st) && (';' + sch.blocks).includes(';' + st)) || (NOBLOCK.test(st) && !(';' + sch.blocks + ';').includes(';' + st.substring(2) + ';')) || sch.save_id.startsWith('gallery' + st) || (SCE.test(st) && sch.has_script) || (NOSCE.test(st) && !sch.has_script) ) }) return (
{/* Gallery Header */} {/* BookDropdown */} {/* SearchComponent */} {/* Display a message or blank gallery */} { finalfilteredSchematics.length === 0 ? `No ${process.env.REACT_APP_SMALL_DIAGRAMS_NAME} to display. ${selectedBook === '' ? 'Please select a book.' : selectedBook === 'all' ? 'Please try another search term.' : 'Please select another book or try another search term.' }` : `${finalfilteredSchematics.length} ${finalfilteredSchematics.length !== 1 ? `${process.env.REACT_APP_SMALL_DIAGRAMS_NAME}` : `${process.env.REACT_APP_SMALL_DIAGRAM_NAME}`}` } { finalfilteredSchematics.map((sch) => ( )) }
) } export default Gallery