Search code examples
reactjslistnavigation-drawerantd

Passing value to drawer from a list in React antd


I have a function that shows a list of customers and their details. However, when I click on the name of the customer, I want a drawer to open. The data within that draw should be specific to the customer (which I originally fetched). Plus I have a tab within the drawer that will fetch additional data for the customer based on their userID. I need this userID passed on from the initial list to the Drawer. I am stuck here because I am unable to figure out how to make that connection between the list and the Drawer.

import React, { useState, useEffect } from "react";
import axios from "axios";
import { Button, Space, Descriptions, Tabs, List, Avatar, Drawer } from "antd";
import { BulbOutlined, MessageOutlined } from "@ant-design/icons";
import UserIdeas from "./UserIdeas";
import UserMessages from "./UserMessages";

const UserDrawer = () => {
  const [user_list, getData] = useState("");

  //get a list of users and their information. UserID is the key
  //Data looks like this
  // [  {title: 'Ahmed xxx', userId:1, email: 'ahmed@xx.com' , location: 'Canada'  },  {title: 'Ahmed2 xxx', userId:2, email: 'ahmed2@xx.com' , location: 'Canada'  },]

  const getAllData = () => {
    var user_access_token = localStorage.getItem("user_access_token");
    axios
      .get(process.env.REACT_APP_API_URL + "reports/product/1/users", {
        headers: {
          Authorization: "Bearer " + user_access_token,
        },
      })
      .then((response) => {
        const allData = response.data;
        getData(allData);
      })
      .catch((error) => console.error(error));
  };

  useEffect(() => {
    getAllData();
  }, []);

  const [open, setOpen] = useState(false);
  const [size, setSize] = useState();
  const showLargeDrawer = () => {
    setOpen(true);
  };
  const onClose = () => {
    setOpen(false);
  };

  //Menu of the Tabs. Need to pass the UserId for each customer to the component to display the data associated with the user
  const items = [
    {
      key: "1",
      label: (
        <span>
          <BulbOutlined /> Ideas
        </span>
      ),
      children: <UserIdeas user_id={item.userId} />,
    },
    {
      key: "2",
      label: (
        <span>
          <MessageOutlined /> Comments
        </span>
      ),
      children: <UserMessages user_id={item.userId} />,
    },
  ];

  return (
    <>
      <List
        itemLayout="vertical"
        dataSource={user_list}
        renderItem={(item) => (
          <List.Item>
            <List.Item.Meta
              title={
                <a onClick={showLargeDrawer} key={`a-${item.userId}`}>
                  {item.title}
                </a>
              }
            />
          </List.Item>
        )}
      />

      <Drawer
        title={item.title} //show the title of the user
        placement="right"
        size={size}
        onClose={onClose}
        open={open}
        // dataSource={user_list}
        extra={
          <Space>
            {" "}
            <Button type="primary" onClick={onClose}>
              close
            </Button>
          </Space>
        }
      >
        <Descriptions>
          <Descriptions.Item label="E-Mail Address"> {email}</Descriptions.Item>
          <Descriptions.Item label="Location">{location}</Descriptions.Item>
        </Descriptions>

        <Tabs
          tabPosition={"left"}
          defaultActiveKey="1"
          items={items}
          closable
        />
      </Drawer>
    </>
  );
};

export default UserDrawer;

Solution

  • You need a couple of things to show the correct data on the drawer. The first one is to add a state that stores the selected user index on your list.

    const [selectedUser, setSelectedUser] = useState(null);
    

    By default no user will be selected

    You also have to change the function showLargeDrawer to something like this, where you get the element where userId is the same that the one on the clicked item, store it on selectedUser and setOpen to true

    const showLargeDrawer = (userId) => {
      const chosenUser = user_list?.find(user=>user.userId===userId) ?? null;
      setSelectedUser(chosenUser);
      setOpen(true);
    };
    

    And on the onclick function on the List

    onClick={()=>showLargeDrawer(item.userId)}
    

    Finally on the Description you simply show the properties of the selectedUser

    <Descriptions>
          <Descriptions.Item label="E-Mail Address">
             {selectedUser?.email ?? 'No email found'}
          </Descriptions.Item>
          <Descriptions.Item label="Location">
             {selectedUser?.location ?? 'No location found'}
          </Descriptions.Item>
    </Descriptions>
    

    With this additions to your code it will work the way you want to.