Сортировать и сгруппировать Собственный список разделов по ключу - PullRequest
0 голосов
/ 05 января 2019

У меня есть SectionList, который я заполняю данными из firebase. В списке отображается информация о событии, сгруппированная по дате, с текущим месяцем, видимым как THIS MONTH, а с другими датами используется сокращенное значение JAN, FEB и т. Д.

Я получаю данные в порядке и могу отображать их нормально, но не могу понять, как сгруппировать массив данных по датам. К вашему сведению, даты сохраняются в БД в виде строк дат 2019-01-05, и я использую момент для их форматирования следующим способом:

 formatDateToMonth(date) {
  let fullDate = moment(date);
  fullDate.month();
  const month = fullDate.format('MMM');
  return month.toUpperCase();
}

Что возвращает JAN. Я запускаю простой оператор if, чтобы сравнить значение заголовка с текущим месяцем, который я форматирую с моментом, и, если он совпадает, я изменяю отображаемое имя заголовка на THIS MONTH.

Данные помещаются в массив следующим образом:

listData.push({
  data: [
    {
      id: event,
      eventName: eventObj.eventName,
      location: eventObj.location,
      description: eventObj.description,
      creatorsName: eventObj.creatorsName,
      date: eventObj.date,
      discipline: eventObj.discipline
    }
  ],
  title
});

С названием, являющимся названием месяца и ключом, который мне нужно отсортировать и сгруппировать по.

Вот как это выглядит в настоящее время:

enter image description here

Вот как я бы хотел, чтобы это выглядело: (использовали фиктивные данные для правильного представления) enter image description here

Мне бы хотелось, чтобы каждое событие того же месяца было в одном разделе.

Любая помощь будет потрясающей!

ПОЛНЫЙ КОМПОНЕНТ:

import React from 'react';
import {View, StyleSheet, SectionList, TouchableOpacity} from 'react-native';
import { Container, Content , Text, Icon, Spinner } from 'native-base';
import Collapsible from 'react-native-collapsible';
import {f, auth, database} from '../../config/config';
import _ from 'lodash';

import CustomIcon from '../utilities/CustomIcon';

import Month from './Month';
import moment from 'moment';
import Day from './Day';

let today = moment();
let now = today.format("YYYY-MM-DD");
let getCurrentMonth = today.month('MMM');

const monthOrder = [
  'JAN',
  'FEB',
  'MAR',
  'APR',
  'MAY',
  'JUN',
  'JUL',
  'AUG',
  'SEPT',
  'OCT',
  'NOV',
  'DEC'
];

class SectionListItem extends React.Component {

  state = {
    descriptionCollapsed: true
  };

  toggleDescription = () => {
    this.setState({ descriptionCollapsed: !this.state.descriptionCollapsed
    });
  };

  render() {
    let fullDay = moment(this.props.item.date);
    fullDay.day();
    const day = fullDay.format('DD')
    return (
      <View style={styles.sectionListItemContainer}>
      <View style={styles.eventInfoContainer}>
      <View>
      <Day day={day}/>
    </View>
    <TouchableOpacity onPress={this.toggleDescription}>
      <View style={styles.info}>
      <Text style={styles.eventName}>{this.props.item.eventName.toUpperCase()}</Text>
      <Text style={styles.creatorsName}>Coached by {this.props.item.creatorsName}</Text>
    <Text style={styles.location}>{this.props.item.location}</Text>
      </View>
      </TouchableOpacity>
      </View>
      <Collapsible collapsed={this.state.descriptionCollapsed}>
      <EventDescription description={this.props.item.description} discipline={this.props.item.discipline}/>
    </Collapsible>
    </View>
  );
  }
}

class EventDescription extends React.Component {

  render() {
    return (
      <View style={styles.descriptionDropdown}>
      <View >
      <Icon name='arrow-up' type="SimpleLineIcons" style={styles.upArrow} />
    </View>
    <View style={styles.descriptionContainer}>
      <Text style={styles.description}>{this.props.description}</Text>
      </View>
      <View style={styles.iconContainer}>
      {!!this.props.discipline ? (this.props.discipline.map((item, index) => {
      return <View key={index} style={styles.iconMargin}><CustomIcon name={item} size={20} style={styles.iconStyle}/></View>
    })) : null}
  </View>
    </View>
  );
  }
}

class SectionHeader extends React.Component {
  render() {
    return (
      <View style={styles.monthHeader}>
      <Month month={this.props.section.title}/>
    </View>
  );
  }
}

export default class EventList extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      filterCollapsed: true,
      listData: [],
      loading: true,
      refreshing: false
    }
  }

  componentDidMount() {
    this.loadEvents();
  }

  onRefresh = () => {
    this.setState({refreshing: true})
    this.loadEvents();
  }

  formatDateToMonth(date) {
    let fullDate = moment(date);
    fullDate.month();
    const month = fullDate.format('MMM');
    return month.toUpperCase();
  }

  getDateMatches = (date) => {
    return database
      .ref('events')
      .orderByChild('date')
      .startAt(date)
      .once("value")
      .then((snapshot) => {
        let matches = [];
        snapshot.forEach((child) => {
          let val = child.val();
          const valMonth = this.formatDateToMonth(val.date);
          const dateMonth = this.formatDateToMonth(date);
          if (dateMonth === valMonth) {
            matches.push(val);
          }
        });
        return matches;
      });
  }

  loadEvents = () => {
    this.setState({listData: []});
    const that = this;

    database.ref('events').once('value').then((snapshot) => {
      const exists = (snapshot.val() !== null);
      if (exists) {
        data = snapshot.val();
      }
      const listData = that.state.listData;

      let monthData = {title: '', data: []};

      const thisMonth = { title: 'THIS MONTH', data: []};
      const otherMonth = { title: '', data: []};

      for(var event in data) {
        const eventObj = data[event];

        const month = this.formatDateToMonth(eventObj.date);
        let title;

        getCurrentMonth.month();
        const currentMonth = getCurrentMonth.format('MMM');


        if (month === currentMonth.toUpperCase()) {
          title = 'THIS MONTH';
        } else {
          title = month;
        }

        listData.push(
          {
            data: [
              {
                id: event,
                eventName: eventObj.eventName,
                location: eventObj.location,
                description: eventObj.description,
                creatorsName: eventObj.creatorsName,
                date: eventObj.date,
                discipline: eventObj.discipline,
              }
            ],
            title
          }
        );

        // listData.sort((a, b) => {
        //     return (a.title - b.title) || (monthOrder.indexOf(a.title) - monthOrder.indexOf(b.title))
        // });



        that.setState({loading: false, refreshing: false});

      }

    }).catch(error => console.log('error: ', error));
  }


  toggleFilter = () => {
    this.setState({ filterCollapsed: !this.state.filterCollapsed });
  };

  render() {

    if (!!this.state.loading) {
      return (
        <View style={styles.spinner}>
        <Spinner color="#81e6fc"/>
        </View>
    )
    }

    return (
      <Container style={styles.container}>
      <TouchableOpacity style={styles.filterTextContainer} onPress={this.toggleFilter}>
      <Text style={styles.filterText}>FILTER</Text>
      </TouchableOpacity>
      <Collapsible collapsed={this.state.filterCollapsed}>
      <CustomIcon name="Rate" size={50} style={styles.iconStyle}/>
    </Collapsible>
    <Content contentContainerStyle={styles.list}
    onRefresh={this.onRefresh}
    refreshing={this.state.refreshing}
      >
      <SectionList
    renderItem={({item, index}) => {
      return <SectionListItem item={item} index={index}/>
    }}
    renderSectionHeader={({section}) => {
      return <SectionHeader section={section}/>
    }}
    sections={dummyData}
    keyExtractor={(item, index) => item + index}
  >
  </SectionList>
    </Content>
    </Container>
  );
  }
}

1 Ответ

0 голосов
/ 06 января 2019

Полагаю, вам нет дела до лет в вашей группе, потому что в этом случае 2018-01 и 2019-01 оба будут JAN. Но в любом случае, посмотрите на пример ниже, я попытался прокомментировать каждый шаг в коде:

// define your flat list of events
const events = [
	{name: 'dummy one', date: '2019-01-05'},
	{name: 'dummy some', date: '2019-02-04'},
	{name: 'dummy another', date: '2019-01-07'},
	{name: 'dummy really dummy', date: '2019-04-05'},
	{name: 'dummy and funny', date: '2019-06-05'},
	{name: 'dummy not funny', date: '2019-06-22'}
].sort((a, b) => a.date < b.date ? -1 : 1)
// remember to sort them early so you will not have to worry about it anytime later on

// extract distinct names from available events, we are using Set constructor to make sure any key won't be doubled and also that there won't be any empty month
const groupNames = Array.from(new Set(events.map(k => k.date.split('-')[1]))) // split date by hyphen and return only month part

// define place for groups
let groups = {}

// create groups containers from names
groupNames.forEach(k => {
	groups[k] = []
})

// iterate by events and attach every to given group based on its month
events.forEach(k => {
	const month = k.date.split('-')[1]
  groups[month].push(k)
})

// container for demo purposes
let resultHTML = ''

// iterate by groups, if you are unsure about 'for in' loop, use groupNames for that part, and then iterate by events in every group
for(let key in groups) {
	resultHTML += `<h2>${key}</h2>`
  for (let event of groups[key]) {
  	resultHTML += `<p>${event.date} &mdash; ${event.name}</p>`
  }
}

// display results for demo purposes
document.querySelector('.result').innerHTML = resultHTML
<div class="result"></div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...