mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
4.14k stars 1.29k forks source link

[pickers] DatePicker date selection part jump else where #14971

Open neo-lu15 opened 1 day ago

neo-lu15 commented 1 day ago

Steps to reproduce

Link to live example: (required)

螢幕擷取畫面 2024-10-15 170051

Steps:

import dayjs from 'dayjs';

import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'

body() { const { showChecklist, checklistData, startDate, endDate, showDateFilter } = this.state;

return (
  <LocalizationProvider dateAdapter={AdapterDayjs}>
  <div>
    {!showChecklist ? (
      <>
        <div>
          <Input
            placeholder="Calendar Name"
            value={this.state.inputText}
            onChange={(e) => this.handleInputChange(e)}
          />
          <Button
            icon={<ArrowRight16Filled />}
            onClick={() => this.handleSearchClick()}
          >
            Search
          </Button>
        </div>
      </>
    ) : (
      <div className="list-body">
        <div>
          <Input
            placeholder="Calendar Name"
            value={this.state.inputText}
            onChange={(e) => this.handleInputChange(e)}
          />
          <Button
            icon={<ArrowRight16Filled />}
            onClick={() => this.handleSearchClick()}
          >
            Search
          </Button>
        </div>

        <div >
          {checklistData.map((item) => {
            return(
            <div key={item.id} >
              <div className="divider" />

              <Checkbox
                className="checkbox"
                label=""
                onChange={(e, checked) => this.handleCheckboxChange(item.id, checked)}
              />
              <div className="meeting-info">
                <Link className="title" href={item.webLink} target="_blank">
                  {item.subject}
                </Link>
                <Text className="content">
                  {item.organizer.emailAddress.name}
                </Text>
                <DatePicker
                  label="Start Date"
                  defaultValue={dayjs(item.recurrence.range.startDate)}
                  value={startDate}
                  slotProps={{
                    // The actions will be the same between desktop and mobile
                    actionBar: {
                      actions: ['clear'],
                    },
                    // The actions will be different between desktop and mobile
                    actionBar: ({ wrapperVariant }) => ({
                      actions: wrapperVariant === 'desktop' ? [] : ['clear'],
                    }),
                  }}
                  onSelectDate={(date) => this.handleDateChange("startDate", date)}
                />
                <DatePicker
                  label="End Date"
                  defaultValue={dayjs(item.recurrence.range.endtDate)}
                  value={endDate}
                  slotProps={{ popper: { placement: 'bottom-end' }}}
                  onSelectDate={(date) => this.handleDateChange("endDate", date)}
                />
              </div>
            </div>);
          })}
        </div>

        {showDateFilter && (
          <div className="date-filter">

            <Button onClick={() => this.filterEventsByDate()}>
              Apply Date Filter
            </Button>
          </div>
        )}

      </div>
    )}
  </div>
  </LocalizationProvider>
);

}

Current behavior

where i use calender to choose date it popped to the up page

Expected behavior

it has to be under the datpicker

Context

can you help me with this what's wrong?

Your environment

npx @mui/envinfo body() { const { showChecklist, checklistData, startDate, endDate, showDateFilter } = this.state; return (
{!showChecklist ? ( <>
this.handleInputChange(e)} />
) : (
this.handleInputChange(e)} />
{checklistData.map((item) => { return(
this.handleCheckboxChange(item.id, checked)} />
{item.subject} {item.organizer.emailAddress.name} this.handleDateChange("startDate", date)} /> this.handleDateChange("endDate", date)} />
); })}
)}
); } ``` Don't forget to mention which browser you used. Output from `npx @mui/envinfo` goes here. ```
螢幕擷取畫面 2024-10-15 170051

Search keywords: datepicker

arthurbalduini commented 1 day ago

Hello @neo-lu15,

I didn't manage to reproduce your issue with the provided information. It could be very helpful if you can share a live example using tools like stackblitz, for instance.

Do not hesitate to get ping us once you update the issue ! 🙂

neo-lu15 commented 1 day ago

Hi @arthurbalduini I'm using developing the outlook addin and using the datapicker i'm not sure will it influence or not my modules are "dependencies": { "@azure/msal-browser": "^3.18.0", "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", "@fluentui/react-charting": "^5.14.10", "@fluentui/react-components": "^9.18.0", "@fluentui/react-icons": "^2.0.186", "@microsoft/microsoft-graph-client": "^3.0.7", "@microsoft/microsoft-graph-types": "^2.40.0", "@microsoft/teams-js": "^2.19.0", "@microsoft/teamsfx": "^2.2.0", "@microsoft/teamsfx-react": "^3.0.0", "@mui/material": "^6.1.3", "@mui/x-date-pickers": "^7.20.0", "d3": "^7.9.0", "d3-brush": "^3.0.0", "d3-selection": "^3.0.0", "dayjs": "^1.11.13", "react": "^18.2.0", "react-d3-tree": "^3.6.2", "react-dom": "^18.2.0", "react-helmet-async": "^2.0.5", "react-router-dom": "^6.8.0", "react-scripts": "^5.0.1" },

my codes are import "../styles/DownloadCalendarAttachmentWidget.css"; import dayjs from 'dayjs';

import { DatePicker } from '@mui/x-date-pickers/DatePicker'; import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs' import { Text, Button, Input, Spinner, Checkbox, Link } from "@fluentui/react-components"; import { ArrowRight16Filled, MoreHorizontal32Regular, ArrowDownload24Regular } from "@fluentui/react-icons"; import { BaseWidget } from "@microsoft/teamsfx-react"; import { SearchEvent, downloadAttachment } from "../services/services";

export default class DownloadCalendarAttachmentWidget extends BaseWidget { constructor(props) { super(props); this.state = { inputText: "", loading: false, showChecklist: false, checklistData: [], selectedEventIds: [], // Track selected events' IDs showDateFilter: false, // Control visibility of the date filter startDate: null, endDate: null }; }

async getData() { // If you need to fetch any initial data, do it here return {}; }

header() { return (

Download Calendar Attachment
);

}

body() { const { showChecklist, checklistData, startDate, endDate, showDateFilter } = this.state;

return (
  <LocalizationProvider dateAdapter={AdapterDayjs}>
  <div>
    {!showChecklist ? (
      <>
        <div>
          <Input
            placeholder="Calendar Name"
            value={this.state.inputText}
            onChange={(e) => this.handleInputChange(e)}
          />
          <Button
            icon={<ArrowRight16Filled />}
            onClick={() => this.handleSearchClick()}
          >
            Search
          </Button>
        </div>
      </>
    ) : (
      <div className="list-body">
        <div>
          <Input
            placeholder="Calendar Name"
            value={this.state.inputText}
            onChange={(e) => this.handleInputChange(e)}
          />
          <Button
            icon={<ArrowRight16Filled />}
            onClick={() => this.handleSearchClick()}
          >
            Search
          </Button>
        </div>

        <div >
          {checklistData.map((item) => {
            return(
            <div key={item.id} >
              <div className="divider" />

              <Checkbox
                className="checkbox"
                label=""
                onChange={(e, checked) => this.handleCheckboxChange(item.id, checked)}
              />
              <div className="meeting-info">
                <Link className="title" href={item.webLink} target="_blank">
                  {item.subject}
                </Link>
                <Text className="content">
                  {item.organizer.emailAddress.name}
                </Text>
                <DatePicker
                  label="Start Date"
                  defaultValue={dayjs(item.recurrence.range.startDate)}
                  value={startDate}
                  slotProps={{
                    // The actions will be the same between desktop and mobile
                    actionBar: {
                      actions: ['clear'],
                    },
                    // The actions will be different between desktop and mobile
                    actionBar: ({ wrapperVariant }) => ({
                      actions: wrapperVariant === 'desktop' ? [] : ['clear'],
                    }),
                  }}
                  onSelectDate={(date) => this.handleDateChange("startDate", date)}
                />
                <DatePicker
                  label="End Date"
                  defaultValue={dayjs(item.recurrence.range.endtDate)}
                  value={endDate}
                  slotProps={{ popper: { placement: 'bottom-end' }}}
                  onSelectDate={(date) => this.handleDateChange("endDate", date)}
                />
              </div>
            </div>);
          })}
        </div>

        {showDateFilter && (
          <div className="date-filter">

            <Button onClick={() => this.filterEventsByDate()}>
              Apply Date Filter
            </Button>
          </div>
        )}

      </div>
    )}
  </div>
  </LocalizationProvider>
);

}

loading() { return Loading...; }

footer() { return ( <><Button id="download-footer" appearance="transparent" icon={} iconPosition="after" size="small" onClick={() => this.handleDownloadClick()} // Trigger download on button click

Download </> ); }

handleInputChange(e) { this.setState({ inputText: e.target.value }); }

async handleSearchClick() { console.log("Search button clicked"); console.log(this.state.inputText); this.setState({ loading: true });

try {
  const events = await SearchEvent(this.state.inputText);
  this.setState({
    checklistData: events, // Assuming events is an array of event objects
    filteredData: events,
    showChecklist: true,
    loading: false,
  });
} catch (error) {
  console.error("Error downloading attachment:", error);
  this.setState({ loading: false });
}

}

handleCheckboxChange(id) { console.log(handleCheckboxChange called with id: ${id});

this.setState(prevState => {
  const isCurrentlySelected = prevState.selectedEventIds.includes(id);
  console.log(`ID ${id} is currently ${isCurrentlySelected ? 'selected' : 'not selected'}`);

  let newSelectedEventIds;

  if (isCurrentlySelected) {
    // Remove the ID if it's currently selected
    newSelectedEventIds = prevState.selectedEventIds.filter(eventId => eventId !== id);
    console.log(`Removed ${id} from selected IDs`);
  } else {
    // Add the ID if it's not currently selected
    newSelectedEventIds = [...prevState.selectedEventIds, id];
    console.log(`Added ${id} to selected IDs`);
  }

  const showDateFilter = newSelectedEventIds.length > 0;

  console.log("New selected event IDs:", newSelectedEventIds);
  console.log("Show date filter:", showDateFilter);

  return {
    selectedEventIds: newSelectedEventIds,
    showDateFilter: showDateFilter
  };
});

}

handleDateChange(field, date) { this.setState({ [field]: date }); }

filterEventsByDate() { const { checklistData, startDate, endDate } = this.state;

const filteredData = checklistData.filter((event) => {
  const eventDate = new Date(event.start.dateTime);
  return (!startDate || eventDate >= startDate) && (!endDate || eventDate <= endDate);
});

this.setState({ filteredData });

}

async handleDownloadClick() { const { selectedEventIds } = this.state;

if (selectedEventIds.length === 0) {
  alert("No events selected for download.");
  return;
}

// Loop through each selected event ID and download its attachments
for (let eventId of selectedEventIds) {
  try {
    await downloadAttachment(eventId);
  } catch (error) {
    console.error("Error downloading attachment for event:", eventId, error);
  }
}

} }