Skip to content

Commit

Permalink
Implementa a busca utilizando o endpoint de querystring-search
Browse files Browse the repository at this point in the history
  • Loading branch information
ericof committed Nov 4, 2024
1 parent e6a723f commit ab76987
Show file tree
Hide file tree
Showing 10 changed files with 283 additions and 12 deletions.
4 changes: 3 additions & 1 deletion frontend/packages/portalbrasil-intranet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@
},
"peerDependencies": {
"react": "18.2.0",
"react-dom": "18.2.0"
"react-dom": "18.2.0",
"@internationalized/date": "*",
"react-aria-components": "*"
},
"devDependencies": {
"@plone/scripts": "^3.6.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,44 @@
import React from 'react';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { Calendar } from '@plone/components';
import { injectIntl } from 'react-intl';
import { Container } from '@plone/components';
import CalendarioEventos from '../../CalendarioEventos/CalendarioEventos';
import { When } from '@plone/volto/components/theme/View/EventDatesInfo';
import '@plone/components/src/styles/basic/Calendar.css';

const Evento = ({ item }) => {
return (
<Container className={'evento'}>
<h3>{item.title}</h3>
<When start={item.start} end={item.end} />
</Container>
);
};

const EventosLista = ({ items }) => {
return (
<Container className={'eventos-lista'}>
{items && items.map((item, idx) => <Evento key={idx} item={item} />)}
</Container>
);
};

const CalendarioView = (props) => {
const { heading, className } = props;
const { className, data, items } = props;
const { heading } = data;
const [date, setDate] = useState();
const dateItems = date && items && items[date.toString()];
return (
<div className={`block calendarioBlock ${className}`}>
<h2>{heading}</h2>
<Calendar />
<Container className={'wrapper'}>
<div className={'calendario column'}>
<CalendarioEventos items={items} onChange={setDate} />
</div>
<div className={'eventos column'}>
{dateItems && <EventosLista items={dateItems} />}
</div>
</Container>
</div>
);
};
Expand All @@ -31,4 +61,4 @@ CalendarioView.defaultProps = {
heading: 'Eventos',
};

export default CalendarioView;
export default injectIntl(CalendarioView);
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
import React from 'react';
import { withBlockExtensions } from '@plone/volto/helpers';
import CalendarioView from './DefaultView';
import { parseDate } from '@internationalized/date';
import withQuerystringResults from './withQuerystringResults';

const CalendarioBlockView = (props) => {
const { data, isEditMode, className } = props;
const groupByDate = (items) => {
return items.reduce((map, obj) => {
const key = obj.start ? parseDate(obj.start.slice(0, 10)).toString() : null;
if (key) {
if (map[key] === undefined) {
map[key] = [];
}
map[key].push(obj);
}
return map;
}, {});
};

const CalendarioBlockView = withQuerystringResults((props) => {
const { data, isEditMode, path, pathname, className, listingItems } = props;
const items = listingItems ? groupByDate(listingItems) : {};
return (
<CalendarioView {...data} isEditMode={isEditMode} className={className} />
<CalendarioView
data={data}
path={path ?? pathname}
isEditMode={isEditMode}
className={className}
items={items}
/>
);
};
});

export default withBlockExtensions(CalendarioBlockView);
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,46 @@ const messages = defineMessages({
id: 'Título',
defaultMessage: 'Título',
},
querystring: {
id: 'Query',
defaultMessage: 'Query',
},
});

// Consulta padrão dos eventos
const defaultQueryString = {
query: [
{
i: 'portal_type',
o: 'plone.app.querystring.operation.selection.any',
v: ['Event'],
},
],
sort_on: 'start',
sort_order: 'ascending',
};

export const calendarioSchema = (props) => {
return {
title: props.intl.formatMessage(messages.blockTitle),
fieldsets: [
{
id: 'default',
title: 'Default',
fields: ['heading'],
fields: ['heading', 'querystring'],
},
],
properties: {
heading: {
title: props.intl.formatMessage(messages.heading),
default: 'Eventos',
},
querystring: {
title: props.intl.formatMessage(messages.querystring),
widget: 'querystring',
default: defaultQueryString,
},
},
required: ['heading'],
required: ['heading', 'querystring'],
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import React, { useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import hoistNonReactStatics from 'hoist-non-react-statics';
import useDeepCompareEffect from 'use-deep-compare-effect';

import { getQueryStringResults } from '@plone/volto/actions';
import { usePagination, getBaseUrl } from '@plone/volto/helpers';

import config from '@plone/volto/registry';

function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}

export default function withQuerystringResults(WrappedComponent) {
function WithQuerystringResults(props) {
const {
data = {},
id = data.block,
properties: content,
path,
variation,
} = props;
const { settings } = config;
const querystring = data.querystring || {};
const subrequestID = content?.UID ? `${content?.UID}-${id}` : id;
const { b_size = settings.defaultPageSize } = querystring; // batchsize

// save the path so it won't trigger dispatch on eager router location change
const [initialPath] = React.useState(getBaseUrl(path));

const copyFields = ['limit', 'query', 'sort_on', 'sort_order', 'depth'];
const { currentPage, setCurrentPage } = usePagination(id, 1);
const adaptedQuery = Object.assign(
variation?.fullobjects ? { fullobjects: 1 } : { metadata_fields: '_all' },
{
b_size: b_size,
},
...copyFields.map((name) =>
Object.keys(querystring).includes(name)
? { [name]: querystring[name] }
: {},
),
);
const adaptedQueryRef = useRef(adaptedQuery);
const currentPageRef = useRef(currentPage);

const querystringResults = useSelector(
(state) => state.querystringsearch.subrequests,
);
const dispatch = useDispatch();

const hasQuery = querystring?.query?.length > 0;
const hasLoaded = hasQuery
? querystringResults?.[subrequestID]?.loaded
: true;

const listingItems =
hasQuery && (querystringResults?.[subrequestID]?.items || []);

const showAsQueryListing =
hasQuery && querystringResults?.[subrequestID]?.total > b_size;

const totalPages = showAsQueryListing
? Math.ceil(querystringResults[subrequestID].total / b_size)
: 0;

const prevBatch = showAsQueryListing
? querystringResults[subrequestID].batching?.prev
: null;
const nextBatch = showAsQueryListing
? querystringResults[subrequestID].batching?.next
: null;

useDeepCompareEffect(() => {
if (hasQuery) {
dispatch(
getQueryStringResults(
initialPath,
adaptedQuery,
subrequestID,
currentPage,
),
);
}
adaptedQueryRef.current = adaptedQuery;
currentPageRef.current = currentPage;
}, [
subrequestID,
adaptedQuery,
hasQuery,
initialPath,
dispatch,
currentPage,
]);

return (
<WrappedComponent
{...props}
onPaginationChange={(e, { activePage }) => setCurrentPage(activePage)}
total={querystringResults?.[subrequestID]?.total}
batch_size={b_size}
currentPage={currentPage}
totalPages={totalPages}
prevBatch={prevBatch}
nextBatch={nextBatch}
listingItems={listingItems}
hasLoaded={hasLoaded}
/>
);
}

WithQuerystringResults.displayName = `WithQuerystringResults(${getDisplayName(
WrappedComponent,
)})`;

return hoistNonReactStatics(WithQuerystringResults, WrappedComponent);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {
Calendar as RACCalendar,
CalendarCell,
CalendarGrid,
Heading,
} from 'react-aria-components';

const CalendarioEventos = (props) => {
const { items } = props;
const hasEvents = Object.keys(items);
return (
<div className={'calendarioEventos'}>
<RACCalendar {...props}>
<header>
<Heading />
</header>
<CalendarGrid>
{(date) => {
const className =
hasEvents.indexOf(date.toString()) > -1 ? 'hasEvents' : '';
return (
<CalendarCell
date={date}
className={`${className} react-aria-CalendarCell`}
/>
);
}}
</CalendarGrid>
</RACCalendar>
</div>
);
};

export default CalendarioEventos;
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@import 'components/_barraacessibilidade';
@import 'components/breadcrumbs';
@import 'components/areasummary';
@import 'components/calendarioeventos';
@import 'components/colaboradorsummary';
@import 'components/footer';
@import 'components/header';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,29 @@
// Estilos do bloco de calendário
.block.calendarioBlock {
padding: $spacing-small;
.wrapper {
display: flex;
width: 100%;
flex-direction: row;
flex-wrap: wrap;
.column {
display: flex;
max-height: 310px;
flex: 1;
flex-direction: column;
}
.calendario {
h2:last-child {
margin: unset;
}
}
.eventos {
display: flex;
flex: 3;
overflow-y: auto;
.eventos-lista {
display: block;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.calendarioEventos {
.react-aria-Calendar {
.react-aria-CalendarGridBody {
.react-aria-CalendarCell {
&.hasEvents {
text-decoration: underline;
}
}
}
}
}
6 changes: 6 additions & 0 deletions frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit ab76987

Please sign in to comment.