skip to Main Content

I’m a basic developer working on a pet project and getting myself in knots on the best approach for displaying this in a React Native app via Flatlist.

First off, this is the format of the JSON file. There are approx 7,000 of these records in the file and many are in a variety of different timezones.

id:         1
name:       "Meeting 1"
timezone:   "America/Los_Angeles"
day:        2
time:       "19:00"
url:        "https://teams.meetings.com/xyz321"

id:         2
name:       "Meeting 2"
timezone:   "America/New_York"
day:        4
time:       "11:30"
url:        "https://teams.meetings.com/xyz567"

id:         3
name:       "Meeting 3"
timezone:   "Australia/Sydney"
day:        1
time:       "15:45"
url:        "https://teams.meetings.com/abc987"

What I would like to do is;

  1. Get the local timezone of the user and
  2. filter all meetings occurring on the current day only and
  3. filter these meetings that are happening within the next hour and
  4. display these meeting details in the user’s local date / time as individual items within a React Native Flatlist.

I’d really appreciate if someone could offer some guidance. My getTzHourfunction only fires once in the filter process (returning the time of the first JSON record timezone only). This is incorrect as I need to get the timezone of each proceeding record to return that record’s time.

import React, { useEffect, useState, useMemo, useCallback } from 'react';
import { FlatList, StyleSheet, View, Text } from 'react-native';
// import DeviceInfo from 'react-native-device-info';

// Assuming meetingsData is an array of objects parsed from the JSON file
const MeetingData = require('../data/Meetings.json');

const MeetingList = () => {

    const date = new Date;
    let getTzHour = ( tzName ) => {
        let tzTime = (new Intl.DateTimeFormat('en-AU',
            {
                timeZone: tzName,
                hour: '2-digit',
                hour12: false,
            }
        ).format(date));
        let tzHour = tzTime + ':00' // zero the minutes to round the hour to 'hh:00' which matches the json time format
        return tzHour;
    };

    const Meetings = MeetingData.reduce(item =>
        (item.time === getTzHour(item.timezone)) // this only fires the getTzHour function once. How do I get it to loop for every item.timezone it finds?
    );

    console.log(Meetings.length);

    const renderMeetingItem = ({ item }) => {
        return (
            <View style={styles.item}>
                <Text style={styles.title}>Name: {item.name}</Text>
                <Text style={styles.title}>Local Time: {item.time}</Text>
                <Text style={styles.title}>- - - - - - </Text>
                <Text style={styles.title}>Meeting URL: {item.url}</Text>
            </View>
        )
    };
  
  return (
    <View style={styles.container}>
        <FlatList
        data={Meetings}
        renderItem={renderMeetingItem}
        keyExtractor={(item, index) => index.toString()}
        />
    </View>
  );
};

export default MeetingList;

const styles = StyleSheet.create({
    container: {
        flex: 1,
        flexDirection: 'column',
        justifyContent: 'space-between',
    },
    item: {
        backgroundColor: '#DDD',
        padding: 20,
        marginVertical: 8,
        marginHorizontal: 16,
      },
      title: {
        fontSize: 18,
        color: '#000000'
      },
});

2

Answers


  1. meetings I would suggest to use a date lib to simplify the code a lot as luxon.

    Here is how I would achieve this:

    import { useMemo } from 'react'
    import { DateTime } from 'luxon'
    
    import { useMeetings } from '../queries/meetings'
    import { Meeting } from '../types'
    
    export function Meetings() {
      const { data: meetings, isLoading } = useMeetings()
    
      const nextMeetings = useMemo(() => {
        return meetings?.filter((meeting) => {
          const meetingDate = DateTime.fromISO(meeting.date)
          const diff = meetingDate.diffNow('hours').hours
    
          return diff > 0 && diff <= 1
        })
      }, [meetings])
    
      function _renderMeeting(meeting: Meeting, idx: number) {
        const time = DateTime.fromISO(meeting.date).toFormat('hh:mm');
    
        return (
          <div key={idx}>
            <div>Name: {meeting.name}</div>
            <div>Time: {time}</div>
            <div>URL: {meeting.url}</div>
          </div>
        )
      }
    
      if (isLoading) return <div>Loading...</div>
    
      return (
        nextMeetings?.map(_renderMeeting)
      )
    }
    
    export default Meetings
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
    Login or Signup to reply.
  2. I think it is possible to do this in native React:

     import React, { useEffect, useState } from 'react';
     import { FlatList, StyleSheet, View, Text } from 'react-native';
     import moment from 'moment-timezone'; // Import the moment-timezone library
    
     const MeetingData = require('../data/Meetings.json');
    
     const MeetingList = () => {
         const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
         const currentDate = moment().tz(userTimezone);
    
         const filteredMeetings = MeetingData.filter(meeting =>
             meeting. Day === currentDate.day() && // Filter by current day
             moment.tz(meeting.time, 'HH:mm', meeting.timezone).isBetween(currentDate, currentDate.clone().add(1, 'hour')) // Filter by next hour
    );
    
    const renderMeetingItem = ({ item }) => {
        const localTime = moment.tz(item.time, 'HH:mm', item.timezone).tz(userTimezone).format('HH:mm');
        
        return (
            <View style={styles.item}>
                <Text style={styles.title}>Name: {item.name}</Text>
                <Text style={styles.title}>Local Time: {localTime}</Text>
                <Text style={styles.title}>- - - - - - </Text>
                <Text style={styles.title}>Meeting URL: {item.url}</Text>
            </View>
        );
    };
    
    return (
        <View style={styles.container}>
            <FlatList
                data={filteredMeetings}
                renderItem={renderMeetingItem}
                keyExtractor={(item, index) => index.toString()}
            />
        </View>
    );
    };
    
    export default MeetingList;
    
         const styles = StyleSheet.create({
             container: {
                 flex: 1,
                 flexDirection: 'column',
                 justifyContent: 'space-between',
    },
         item: {
             backgroundColor: '#DDD',
             padding: 20,
             marginVertical: 8,
             marginHorizontal: 16,
    },
         title: {
             fontSize: 18,
             color: '#000000'
    },
    });
    

    What I did

    • I use moment-timezone to handle timezone conversions.
    • Filter meetings based on the current day and time within the next hour.
    • Converted meeting time to the user’s local timezone before displaying it in the FlatList.
      I hope it helps you achieve your goal in your React Native app.
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search