The rendered data in react native calendar Agenda component changes when selecting a past date

492 Views Asked by At

I am using react-native-calendar's Agenda component to render the appointments for a user, like on which day he has appointments.

The built logic is here

React native component: -

/* eslint-disable no-nested-ternary */
import { useLazyQuery, useQuery } from "@apollo/client";
import dayjs from "dayjs";
import React, { useContext, useState } from "react";
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
import { Agenda } from "react-native-calendars";
import { useDispatch } from "react-redux";
import { UserContext } from "../context/AuthContextProvider";
import { GET_USER_APPOINTMENTS } from "../graphql/query";
import testIDs from "../testIDs";
import {
  addMissingDates,
  parseAppointmentData,
} from "../utils/calendarDataParser";
import { leadSelected } from "../reducers/leadSlice";
import { appointmentSelected } from "../reducers/appointmentSlice";

function AppointmentCalendar({ route, navigation }) {
  const [items, setItems] = useState({});
  const { authUser } = useContext(UserContext);
  const [variables, setVariables] = useState({
    userIds: [authUser?.id],
    startDate: dayjs()?.startOf("month")?.format("YYYY-MM-DD"),
    endDate: dayjs()?.endOf("month")?.format("YYYY-MM-DD"),
  });
  const dispatch = useDispatch();
  const { loading: appointmentLoader } = useQuery(GET_USER_APPOINTMENTS, {
    variables: { ...variables },
    onCompleted: (res) => {
      setItems((prev) => ({
        ...prev,
        ...addMissingDates(
          parseAppointmentData(res?.getUserAppointment?.data),
          dayjs().format("YYYY-MM-DD")
        ),
      }));
    },
  });

  const loadItems = (day) => {
    setVariables({
      ...variables,
      startDate: dayjs(day.dateString)?.startOf("month")?.format("YYYY-MM-DD"),
      endDate: dayjs(day.dateString)?.endOf("month")?.format("YYYY-MM-DD"),
    });
  };

  const renderEmptyDate = () => (
    <View style={styles?.emptyDate}>
      <Text>No appointment scheduled!</Text>
    </View>
  );
  const RenderItem = React.memo((props) => {
    const { reservation, isFirst, dispatch, navigation, route, styles } = props;
    const fontSize = isFirst ? 16 : 14;
    const color = isFirst ? "black" : "#43515c";
    const appointmentColor =
      reservation.appointmentStatus === "SCHEDULED"
        ? "#1890ff"
        : reservation.appointmentStatus === "RESCHEDULED"
        ? "#13c2c2"
        : reservation.appointmentStatus === "CANCELLED"
        ? "#f5222d"
        : "#52c41a";
    return (
      <TouchableOpacity
        testID={testIDs.agenda.ITEM}
        style={[
          styles.item,
          { height: reservation.height, backgroundColor: appointmentColor },
        ]}
        onPress={() => {
          navigation.navigate("EditAppointment", {
            ...route?.params,
            mode: "EDIT",
          });
          dispatch(appointmentSelected(reservation?.appointment));
        }}
      >
        <Text style={{ fontSize, color: "#fff" }}>{reservation?.name}</Text>
      </TouchableOpacity>
    );
  }, []);
  const rowHasChanged = (r1, r2) => r1?.appointment?.id !== r2?.appointment?.id;

  const timeToDate = (time) => {
    const date = new Date(time);
    return date.toISOString().split("T")[0];
  };

  const timeToString = (time) => {
    const date = new Date(time);
    return dayjs(date)?.format("hh:mm A");
  };
  return (
    <View style={styles?.container}>
      <Agenda
        testID={testIDs?.agenda?.CONTAINER}
        items={items}
        loadItemsForMonth={loadItems}
        selected={new Date()}
        onDayChange={(day) => console.log(day.dateString)}
        renderItem={(reservation, isFirst) => (
          <RenderItem
            isFirst={isFirst}
            key={reservation?.appointment?.id}
            reservation={reservation}
            dispatch={dispatch}
            navigation={navigation}
            route={route}
            styles={styles}
          />
        )}
        renderEmptyDate={renderEmptyDate}
        rowHasChanged={rowHasChanged}
        showClosingKnob
      />
    </View>
  );
}

export default AppointmentCalendar;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    // backgroundColor: "#a9addf",
  },
  boxContainer: {
    backgroundColor: "#a9addf",
    paddingTop: 10,
    paddingBottom: 10,
  },
  listItem: {
    marginTop: 5,
    padding: 10,
    backgroundColor: "#FFF",
    width: "98%",
    flex: 1,
    alignSelf: "center",
    flexDirection: "row",
    borderRadius: 5,
  },
  viewRow: {
    flex: 1,
    flexDirection: "row",
  },
  textGray: {
    color: "gray",
    fontSize: 14,
    marginBottom: 2,
  },
  textCapitalGray: {
    color: "gray",
    fontSize: 16,
    marginBottom: 2,
  },
  item: {
    backgroundColor: "white",
    flex: 1,
    borderRadius: 5,
    padding: 10,
    marginRight: 10,
    marginTop: 17,
  },
  emptyDate: {
    height: 15,
    flex: 1,
    paddingTop: 30,
  },
});

Here are the helper functions as required for the Agenda component: -

export const parseAppointmentData = (input) => {
  try {
    const systemTimezone = dayjs?.tz?.guess();
    const output = {};
    input?.forEach((item) => {
      const date = dayjs(item?.startDatetime)
        ?.tz(systemTimezone)
        ?.format("YYYY-MM-DD");
      const time = dayjs(item?.startDatetime)
        ?.tz(systemTimezone)
        ?.format("HH:mm A");
      const name = `${time} - ${item?.summary}`;

      if (!output[date]) {
        output[date] = [];
      }

      output[date]?.push({
        name,
        height: 50,
        day: date,
        appointmentStatus: item?.appointmentStatus,
        appointment: item,
      });
    });

    return output;
  } catch (err) {
    console?.log(err);
  }
};

export function addMissingDates(json, date) {
  const systemTimezone = dayjs?.tz?.guess();
  const missingDates = [];
  // Get the starting date of the current month
  const startingDate = dayjs(date)?.tz(systemTimezone)?.startOf("month");

  // Get the ending date of the current month
  const endingDate = dayjs(date)?.tz(systemTimezone)?.endOf("month");

  // Initialize the current date with the starting date
  let currentDate = startingDate;
  const datesWithAppointments = Object?.keys(json);
  // Loop until the current date reaches the ending date
  while (currentDate?.isSameOrBefore(endingDate, "day")) {
    // Output the current date
    if (!datesWithAppointments?.includes(currentDate?.format("YYYY-MM-DD"))) {
      missingDates?.push(currentDate?.format("YYYY-MM-DD"));
    }
    // Increment the current date by one day
    currentDate = currentDate?.add(1, "day");
  }
  missingDates?.forEach((missedDate) => {
    const formattedDate = missedDate;
    json[formattedDate] = [];
  });

  return json;
}

Now, the main problem that i am facing is when the user switches to the previous date from the date that has multiple appointments, the data changes abnormally

Please check the video link that i shared https://screenrec.com/share/YndIusWQgC

I have been scratching my head from the last 1 week, but couldn't find the solution to it, kindly help me if anyone find some issue here.

Thankyou in advance

0

There are 0 best solutions below