Search code examples
javascriptreactjsapidatasetreact-router-dom

React - Displaying items that are found in two different APIs and have matching IDs


I'm having issues displaying items in React, I was wondering what would be the best approach to solve this issue. Here are two JSON files, called facilities.JSON

{
    "data": [
      {
        "name": "Ipswich",
        "id": 52,
        "tags": [
          {
            "id": 156,
            "name": "Studio"
          }
        ]
      },
      {
        "name": "Colchester",
        "id": 84,
        "tags": [
          {
            "id": 540,
            "name": "Swimming"
          },
          {
            "id": 854,
            "name": "Gym"
          }
        ]
      },
      {
        "name": "Chelmsford",
        "id": 103,
        "tags": [
          {
            "id": 12,
            "name": "Spin"
          },
          {
            "id": 432,
            "name": "Yoga"
          },
          {
            "id": 854,
            "name": "Gym"
          }
        ]
      }
    ]
  } 

and activities.JSON

{
    "data": [
      {
        "id": 1,
        "name": "Diving",
        "start_time": "9:00",
        "end_time": "10:00",
        "level": "Experienced",
        "location": "Swimming pool 2",
        "facility_id": 84,
        "tags": [
          {
            "id": 540,
            "name": "Swimming"
          }
        ]
      },
      {
        "id": 2,
        "name": "Swimming",
        "start_time": "9:30",
        "end_time": "11:30",
        "level": "Beginner",
        "location": "Swimming pool 1",
        "facility_id": 84,
        "tags": [
          {
            "id": 540,
            "name": "Swimming"
          }
        ]
      },
      {
        "id": 3,
        "name": "Bodypump",
        "start_time": "9:30",
        "end_time": "10:30",
        "level": "Experienced",
        "location": "Gym",
        "facility_id": 84,
        "tags": [
          {
            "id": 854,
            "name": "Gym"
          },
          {
            "id": 65,
            "name": "Bodypump"
          }
        ]
      },
      {
        "id": 4,
        "name": "Strength & Conditioning",
        "start_time": "9:00",
        "end_time": "10:00",
        "level": "Experienced",
        "location": "Gym",
        "facility_id": 84,
        "tags": [
          {
            "id": 854,
            "name": "Gym"
          }
        ]
      },
      {
        "id": 5,
        "name": "Yoga",
        "start_time": "10:00",
        "end_time": "11:00",
        "level": "Beginner",
        "location": "Studio 1",
        "facility_id": 103,
        "tags": [
          {
            "id": 156,
            "name": "Studio"
          }
        ]
      },
      {
        "id": 6,
        "name": "Spin",
        "start_time": "10:30",
        "end_time": "12:00",
        "level": "Beginner",
        "location": "Studio 2",
        "facility_id": 103,
        "tags": [
          {
            "id": 156,
            "name": "Studio"
          },
          {
            "id": 12,
            "name": "Spin"
          }
        ]
      },
      {
        "id": 7,
        "name": "Yoga",
        "start_time": "9:30",
        "end_time": "10:40",
        "level": "Experienced",
        "location": "Studio 1",
        "facility_id": 103,
        "tags": [
          {
            "id": 156,
            "name": "Studio"
          }
        ]
      },
      {
        "id": 8,
        "name": "Spin",
        "start_time": "9:30",
        "end_time": "10:30",
        "level": "Experienced",
        "location": "Studio 2",
        "facility_id": 103,
        "tags": [
          {
            "id": 156,
            "name": "Studio"
          },
          {
            "id": 12,
            "name": "Spin"
          }
        ]
      },
      {
        "id": 9,
        "name": "Pilates",
        "start_time": "9:00",
        "end_time": "10:00",
        "level": "Beginner",
        "location": "Studio A",
        "facility_id": 52,
        "tags": [
          {
            "id": 156,
            "name": "Studio"
          }
        ]
      },
      {
        "id": 10,
        "name": "HIIT",
        "start_time": "9:30",
        "end_time": "10:30",
        "level": "Intermediate",
        "location": "Studio B",
        "facility_id": 52,
        "tags": [
          {
            "id": 156,
            "name": "Studio"
          },
          {
            "id": 174,
            "name": "Interval training"
          }
        ]
      },
      {
        "id": 11,
        "name": "Yoga",
        "start_time": "10:30",
        "end_time": "10:30",
        "level": "Experienced",
        "location": "Studio A",
        "facility_id": 52,
        "tags": [
          {
            "id": 156,
            "name": "Studio"
          }
        ]
      }
    ]
  }
 

Here is what I have to do:

  • display the facilities' locations
  • upon selecting a facility, display todays timetable of activities

Here is what I got so far (I am using react-router-dom and styled-components). This is the App.js file

function App() {
  return (
    <Router>
      <div>
        <Routes>
          <Route exact path="/" element={<Home />} />
          <Route exact path="/activities" element={<Activities />} />
        </Routes>
      </div>
    </Router>
    );
}

here is the Home.js file

const Home = () => {
    
    let locations = structuredClone(facilities.data);

    return(
        <Container>
            <Services facilitiesData={locations} />
        </Container>
    )
};

Here is my Services.js file:

const Services = ({ facilitiesData }) => {

    const [query, setQuery] = useState('')

    const options = {
        keys: [
            "name",
        ],
        includeScore: true
    };

    const fuse = new Fuse(facilitiesData, options);

    const results = fuse.search(query);

    const facilitiesResult = query ? results.map(results => results.item) : facilitiesData;

    return(
        <Container>
            <Heading>Facilities</Heading>
            <FuzzySearchBar query={query} setQuery={setQuery} />
            <Facilities facilitiesResult={facilitiesResult} />
        </Container>
    )
}

Facilities.js:

const Facilities = ({ facilitiesResult }) => {

    let activitiesData = structuredClone(activities.data)
    
    return(
        <Container>

                {facilitiesResult
                    .slice(0, 6)
                    .sort((a, b) => a.name.localeCompare(b.name))
                    .map((facility, value) => (
                        <FacilitiesCard key={value}>
                            <Heading>{facility.name.replaceAll('_', ' ')}</Heading>
                            <Link 
                                to={`/activities/:${activitiesData.facility_id}`}
                                key={activitiesData.facility_id}
                            >
                                <p>View</p>
                            </Link>
                        </FacilitiesCard>
                ))}

        </Container>
    )
}

and Activities.js:

const Activities = () => {

    // const [data, setData] = useState([]);

    let activitiesData = structuredClone(activities.data);
    let facilitiesData = structuredClone(facilities.data)

    // const map = new Map();
    // facilitiesData.forEach(item => map.set(item.id, item));
    // activitiesData.forEach(item => map.set(item.facility_id, {...map.get(item.facility_id), ...item}));
    // const mergedArr = Array.from(map.values());

    // console.log(mergedArr);



    // create a function that compares two data sets
    // match the facilities "id" with activities "facility_id" 
    // connect the "id's" to the Link in Facilities.js
    // some example might be find. forEach. filter. that can connect two data sets
    // think of joining the datasets in parent component

    return(
        <div>

            {activitiesData.map((activity) => {
                if(facilitiesData.id === activities.facility_id)
                        <div key={activity.facility_id}>
                            <h1>{activity.name}</h1>
                            <p>{activity.start_time}</p>
                        </div>
            })}

        </div>
    )
};

Now, I'm not sure how to connect these two data sets with "id" and "facility_id" which should match.

At first, I was thinking to join the two datasets before rendering the data, and after failed attempts to do so, I thought there might be a way to do this using react-router-dom hooks and utilities. Just thinking that joining the two datasets might not be the most efficient solution.

I would appreciate any input on this matter, even if its a reminder of what I'm doing wrong or how would you approach this problem.

Thank you all and have a great weekend.


Solution

  • You could extract query param that you pass from Link using useParams() hook in Activities.js file and then use that id to filter out the activities that has that facility id associated with it and then map on those activities.