UNPKG

design-comuni-plone-theme

Version:
335 lines (310 loc) 9.74 kB
import React, { useCallback, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useIntl, defineMessages } from 'react-intl'; import useDeepCompareEffect from 'use-deep-compare-effect'; import { ListingLinkMore, CarouselWrapper, SingleSlideWrapper, NextArrow, PrevArrow, } from 'design-comuni-plone-theme/components/ItaliaTheme'; import { Card, Row, Col, Container, Button } from 'design-react-kit'; import cx from 'classnames'; import { injectLazyLibs } from '@plone/volto/helpers/Loadable/Loadable'; import { getCalendarResults, setOriginalQuery, } from 'design-comuni-plone-theme/actions'; import Item from 'design-comuni-plone-theme/components/ItaliaTheme/Blocks/Calendar/Item'; import { viewDate } from 'design-comuni-plone-theme/helpers'; const messages = defineMessages({ insert_filter: { id: 'insert_filter', defaultMessage: 'Inserire un filtro dal menù laterale per visualizzare i relativi risultati', }, calendar_no_results: { id: 'calendar_no_results', defaultMessage: 'Nessun evento disponibile al momento', }, }); const copyFields = ['limit', 'query', 'sort_on', 'sort_order', 'depth']; const Body = ({ data, block, inEditMode, path, onChangeBlock, reactSlick }) => { const intl = useIntl(); const Slider = reactSlick.default; const [activePage, setActivePage] = useState(0); const [additionalFilters, setAdditionalFilters] = useState([]); let currentLocationFilter = additionalFilters ?.filter((f) => { return f.i === 'event_location'; }) ?.map((f) => { return f.v; }); const [locationFilter, setLocationFilter] = useState( currentLocationFilter?.[0] || null, ); const calendarResults = useSelector( (state) => state.calendarSearch.subrequests, ); const originalQuery = useSelector((state) => state.originalQuery?.[block]?.[block]?.toArray?.(), ); const dispatch = useDispatch(); const getMonth = useCallback(() => { const startIndex = activePage; const months = calendarResults[block]?.items ?.slice(startIndex, startIndex + 4) .reduce((total, date) => { const month = viewDate(intl.locale, date, 'MMMM'); if (!total.includes(month)) { total.push(month); } return total; }, []); return months ?.map((m) => m.charAt(0).toUpperCase() + m.slice(1)) .join(' / '); }, [activePage, block, calendarResults, intl.locale]); const [monthName, setMonthName] = useState(getMonth); const querystring = data.querystring || data; // For backwards compat with data saved before Blocks schema const hasQuery = querystring?.query?.length > 0; //set original query on loading component useEffect(() => { if (!originalQuery && block && hasQuery) { dispatch( setOriginalQuery( block, block, JSON.parse(JSON.stringify(querystring.query)), ), ); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); let query = [ ...(originalQuery && additionalFilters.length > 0 ? JSON.parse(JSON.stringify(originalQuery)) : querystring.query ?? []), ]; //faccio l'override dei filtri di default additionalFilters.forEach((filter) => { let replaced = false; query.forEach((f) => { if (f.i === filter.i && f.o === filter.o) { replaced = true; f.v = filter.v; } }); if (!replaced) { query.push(filter); } }); let _querystring = { ...querystring, query: query }; const adaptedQuery = Object.assign( { fullobjects: 1, sort_on: !Object.keys(_querystring).includes('sort_on') ? 'start' : null, }, ...copyFields.map((name) => Object.keys(_querystring).includes(name) ? { [name]: _querystring[name] } : {}, ), ); useDeepCompareEffect(() => { if (hasQuery || additionalFilters.length > 0) { dispatch(getCalendarResults(path, adaptedQuery, block)); } else { dispatch( getCalendarResults( path, { query: [ { i: 'portal_type', o: 'plone.app.querystring.operation.selection.any', v: ['Event'], }, ], fullobjects: 1, }, block, ), ); } }, [adaptedQuery, block, hasQuery, path, dispatch, additionalFilters]); // Every time the page changes check the name of the month, and // update the month name when the call to getCalendarResults returns useEffect(() => { setMonthName(getMonth); }, [activePage, calendarResults, getMonth]); const addFilters = (filters = []) => { setAdditionalFilters(filters); }; const settings = { dots: true, arrows: true, nextArrow: <NextArrow />, prevArrow: <PrevArrow />, speed: 500, slidesToShow: data.b_size || 4, slidesToScroll: data.b_size || 4, infinite: false, initialSlide: 0, dotsClass: 'slick-dots dot', lazyLoad: true, afterChange: (current, next) => setActivePage(current), responsive: [ { breakpoint: 1025, settings: { slidesToShow: 3, slidesToScroll: 3, }, }, { breakpoint: 1024, settings: { slidesToShow: 2, slidesToScroll: 2, initialSlide: 2, }, }, { breakpoint: 600, settings: { dots: false, slidesToShow: 1, slidesToScroll: 1, }, }, ], }; const location_filters_buttons = data.show_location_filters && data.location_filters ? Object.keys(data.location_filters) .map((k) => { return { label: data.location_filters[k].label, location: data.location_filters[k].location?.[0], }; }) .filter((f) => f.location) : null; const addLocationFilter = (location) => { let new_location = locationFilter === location ? null : location; setLocationFilter(new_location); let filters = []; if (new_location) { filters = [ { i: 'event_location', o: 'plone.app.querystring.operation.selection.any', v: new_location, }, ]; } addFilters(filters); }; return ( <div className={cx('full-width', { 'bg-light py-5': data.show_block_bg, 'public-ui': inEditMode, [data.bg_color]: data.bg_color, })} > <Container className="px-4"> {(data.title || location_filters_buttons) && ( <Row className={cx('template-header', { 'with-filters': location_filters_buttons, })} > {data.title && ( <Col md={location_filters_buttons ? 6 : 12}> <h2 className={cx('', { 'mt-5': !data.show_block_bg, 'mb-4': !location_filters_buttons, })} id={block + 'title'} > {data.title} </h2> </Col> )} {location_filters_buttons && ( <Col md={data.title ? 6 : 12} className="path-filter-buttons"> <div className="path-filter-buttons-wrapper"> {location_filters_buttons.map((button, i) => ( <Button key={i} color="primary" outline={button.location['UID'] !== locationFilter} size="xs" icon={false} tag="button" onClick={(e) => { addLocationFilter(button.location['UID']); }} > {button.label} </Button> ))} </div> </Col> )} </Row> )} <Card className="card-bg rounded"> <div className="text-center calendar-header rounded-top"> <h3>{monthName || <span>&nbsp;</span>}</h3> </div> <div className="calendar-body"> {calendarResults[block]?.items?.length > 0 ? ( <CarouselWrapper> <Slider {...settings}> {calendarResults[block].items.map((day, index) => ( <SingleSlideWrapper index={index} key={index} className="body" > <Item data={data} day={day} query={adaptedQuery} path={path} inEditMode={inEditMode} /> </SingleSlideWrapper> ))} </Slider> </CarouselWrapper> ) : inEditMode ? ( <span className="no-results"> {intl.formatMessage(messages.insert_filter)} </span> ) : ( <span className="no-results"> {intl.formatMessage(messages.calendar_no_results)} </span> )} </div> </Card> <div className="link-more-container"> <ListingLinkMore title={data.linkTitle} href={data.linkHref} linkAlign={data.linkAlign} className="my-4" /> </div> </Container> </div> ); }; export default injectLazyLibs(['reactSlick'])(Body);