“This is the 21st day of my participation in the First Challenge 2022. For details: First Challenge 2022”

Project source: gitee.com/yang-yiming…

I haven’t done this series for a few days, because I want to do it bit by bit, and there are many possible changes. Excuse me, everybody.

This article implements tasks detailed in a drawer.Our implementation effect

Train of thought

  • When we click on the task, open the drawer and display the content of the task.
  • Write the drawer as a component<TaskDetail>In the task component<TaskItem>Referenced in the
  • in<TaskItem>To define a variable visible passed into the component<TaskDetail>In, control drawer switch
  • The same will be<TaskDetail>To show the required data, pass it to props.
  • Drawers contain headings, task details, and time displays and revisions.

Open dry

The new file

New Folder

file

TSX we performed a type constraint on props.

  • Data is the data of a task component, including five items
  • Visible is a variable that controls drawer opening and closing
  • HandleClose is a callback function used to close the drawer. When the drawer is closed, the child component passes a value to the parent component to change the visible value in the parent component.
  • TimeTag is the value of the timeTag that we store when we create the task, so we don’t have to do the processing in this component

import styles from './index.less';
import { Drawer, Input,Popover,Tag,DatePicker } from 'antd';
import { useEffect, useState } from 'react';
import { CloseOutlined, CalendarOutlined } from '@ant-design/icons';
import IconFont from '@/public/Icon/index';
import 'moment/locale/zh-cn';

interface TaskDetailProps {
  data: data;
  visible: boolean;
  handleClose: () = > void;
  timeTag:string;
}
interface data {
  title: string;
  desc: string;
  startTime: string;
  endTime: string;
  status: 'doing' | 'done';

}
export default function TaskDetail(props: TaskDetailProps) {
  return (
          <div>Task details</div>
  );
}
Copy the code

Add drawers and switch

Imported components

Some of these are for later use and are quoted here first.

import styles from './index.less';
import { Drawer, Input,Popover,Tag,DatePicker } from 'antd';
import { useEffect, useState } from 'react';
import { CloseOutlined, CalendarOutlined } from '@ant-design/icons';
import IconFont from '@/public/Icon/index';
Copy the code

The parameters are

  • Placement =” Right “Popbox on the right
  • OnClose ={handleClose} closes the drawer function
  • Visible ={visible} Show drawer
  • Keyboard ={true} Specifies whether to enable esc
  • Closable ={false} does it show the off button in the top left corner because it’s on the left, which is kind of obtrusive let’s get rid of it and write another icon for the off button

export default function TaskDetail(props: TaskDetailProps) {
  const { TextArea } = Input;
  // Decompose the props content
  const { data, visible, handleClose,timeTag } = props;
  // Submit the parameters to be used after modification
  const [submitData, setSubmitData] = useState({
    title: ' '.desc: ' '.startTime: ' '.endTime: ' '.status: ' '});return (
    <Drawer placement="right" onClose={handleClose} visible={visible} keyboard={true} closable={false}>
       <div className={styles.container}>
        <div className={styles.close}>
          <CloseOutlined onClick={handleClose} />
        </div>
        </div>
    </Drawer>
  );
}
Copy the code

Corresponding style

.container {
  width: 100%;

  .close {
    width: 100%;
    height: 30px;
    text-align: right; }}Copy the code

Task title input box

The normal I use here does not use antDesign components. We don’t want an input border here.

 <div className={styles.inputCon}>
          <input
            className={styles.input}
            value={submitData.title}
            onChange={e= >{ setSubmitData({ ... submitData, title: e.target.value }); }} / >
  </div>
Copy the code

The corresponding style

  .inputCon {
    width: 100%;
    .input {
      /** remove the border */
      border: 0;
      outline: none;
      border: none;
      width: 100%;

      /** Change the color */
      outline-color: "red";
      font-size: 20px; }}Copy the code

Task description text box

 const { TextArea } = Input;
 
 <div className={styles.desc}>
          <TextArea/ / of the five elementsrows={5}// Whether to display the word countshowCount={true}
            value={submitData.desc}// Maximum number of wordsmaxLength={100}
            onChange={e= >{ setSubmitData({ ... submitData, desc: e.target.value }); }} / ></div>
Copy the code

The corresponding style

  .desc {
    margin-top: 20px;
  }
Copy the code

time

Display content switch

 // Toggle time labels and buttons
 const [isBtnShow,setIsBtnShow] = useState(false)
Copy the code

This part is all the processing time written before, the main logic is:

  • Click the Today, Tomorrow, Customize button to change the display state of the time picker to True. Click call today, call tomorrowchooseDefaultTimefunction
  • After clicking the custom time button, disable today and tomorrow buttons
  // The time used by the time selector and tag
  const [defaultTime, setDefaultTime] = useState<any>({
    time: ' '.tag: ' '});// Whether to display the time selector when you customize the time
  const [datePickShow, setDefinedDatePick] = useState(false);
Copy the code
   <div className={styles.calender}>
         // Calendar icon
          <div className={styles.iconCon}>
            <CalendarOutlined style={{ fontSize: '17px' }} />
          </div>
          <div className={styles.dateCon}>
             {
                 !isBtnShow ? (
                  <>
                    <div
                    className={` ${styles.time_btn} ${isBtnShow ? styles.disabled :"'} `}onClick={()= > {
                        setDefinedDatePick(true)
                      chooseDefaultTime('today');
                    }}
                  >
                    <IconFont type="iconjintian" className={styles.icon} />today</div>
                  <div
                    className={` ${styles.time_btn} ${isBtnShow ? styles.disabled :"'} `}onClick={()= > {
                        setDefinedDatePick(true)
                      chooseDefaultTime('tomorrow');
                    }}
                  >
                    <IconFont type="icona-rili2" className={styles.icon} />tomorrow</div>
                  <div
                    className={styles.time_btn}
                    onClick={()= > {
                        setDefinedDatePick(true)
                    }}
                  >
                    <IconFont type="icona-rili3" className={styles.icon} />The custom</div>
                  </>) : (<>
                  <Tag closable onClose={closeTag} className={styles.tag} color="gold" style={{ padding: '5px'}}onClick={()= >{setDefinedDatePick(true)}}>
                    {defaultTime.tag}
                  </Tag>
                     </>
                 )
             }
                              
          </div>
        </div>
      </div>
Copy the code

The same method is used to add tasks

 // Select today and tomorrow
  const chooseDefaultTime = (day: string) = > {
    if (day == 'today') {
      const time = moment(moment().format('YYYY-MM-DD 18:00'));
      const tag = `${moment().format('M month DD date ')}18:00 ` (today);
      setDefaultTime({ time, tag });
    } else if (day == 'tomorrow') {
      const time = moment(moment().add(1.'days').format('YYYY-MM-DD 18:00'));
      const tag = `${moment().add(1.'days').format('M month DD date ')}18:00 ` (tomorrow); setDefaultTime({ time, tag }); }};// Modify the date in the time picker
    const changeDate = (date:any) = > {
        const todayStart = moment(moment().format('YYYY-MM-DD 00:00'));
        const yestardayStart = moment(moment(todayStart).subtract(1.'days'));
        const todayEnd = moment(moment().format('YYYY-MM-DD 24:00'));
        const tomorrowEnd = moment(moment(todayEnd).add(1.'days'));
        console.log(tomorrowEnd, 'tomorrowEndtomorrowEnd');
        let today = ' ';
        if (todayStart < date && date < todayEnd) {
          today = '(today);
        } else if (todayEnd < date && date < tomorrowEnd) {
          today = '(tomorrow);
        } else if (yestardayStart < date && date < todayStart) {
          today = '(yesterday);
        } else {
          today = ` (week${moment(date).day() == 0 ? 'day' : moment(date).day()}) `;
        }
        setDefaultTime({ time: date, tag: moment(date).format(` on DD MM${today} HH:mm`)}); };/ / closing Tag
  const closeTag = () = > {
    setDefinedDatePick(false);
    setIsBtnShow(false)};Copy the code

Time selector

Remove the input field

When we create the task time picker, there is an input box, click to open the time picker.

We don’t want this input box here today

Direct use ofopen={datePickShow}A switch that controls the time selector.

But the input box is still there

There was nothing else I could do, so I covered the input field with a layer of divs. The following className is dateConwrap

   <DatePicker
                      showTime
                      open={datePickShow}
                      defaultValue={defaultTime.time}
                      locale={locale}
                      onOk={() = >{setDefinedDatePick(false); setIsBtnShow(true)}}
                      autoFocus
                      onChange={e= >{ changeDate(e); }} / ><div className={styles.dateConwrap}></div>       
Copy the code
    .dateConwrap{
      position:absolute;
      width:90%;
      height:40px;
      background-color: #fff;
    }
Copy the code

The complete code

index.tsx

import styles from './index.less';
import { Drawer, Input,Popover,Tag,DatePicker } from 'antd';
import { useEffect, useState } from 'react';
import { CloseOutlined, CalendarOutlined } from '@ant-design/icons';
import IconFont from '@/public/Icon/index';
import 'moment/locale/zh-cn';
// Time selector bottom English --> Chinese
import locale from 'antd/lib/date-picker/locale/zh_CN';
import moment from 'moment';
interface TaskDetailProps {
  data: data;
  visible: boolean;
  handleClose: () = > void;
  timeTag:string;
}
interface data {
  title: string;
  desc: string;
  startTime: string;
  endTime: string;
  status: 'doing' | 'done';

}
export default function TaskDetail(props: TaskDetailProps) {
  const { TextArea } = Input;
  const { data, visible, handleClose,timeTag } = props;
  const [submitData, setSubmitData] = useState({
    title: ' '.desc: ' '.startTime: ' '.endTime: ' '.status: ' '});// The time used by the time selector and tag
  const [defaultTime, setDefaultTime] = useState<any>({
    time: ' '.tag: ' '});const [isBtnShow,setIsBtnShow] = useState(false)
  // Whether to display the time selector when you customize the time
  const [datePickShow, setDefinedDatePick] = useState(false);
  // Select today and tomorrow
  const chooseDefaultTime = (day: string) = > {
    if (day == 'today') {
      const time = moment(moment().format('YYYY-MM-DD 18:00'));
      const tag = `${moment().format('M month DD date ')}18:00 ` (today);
      setDefaultTime({ time, tag });
    } else if (day == 'tomorrow') {
      const time = moment(moment().add(1.'days').format('YYYY-MM-DD 18:00'));
      const tag = `${moment().add(1.'days').format('M month DD date ')}18:00 ` (tomorrow); setDefaultTime({ time, tag }); }};// Modify the date in the time picker
    const changeDate = (date:any) = > {
        const todayStart = moment(moment().format('YYYY-MM-DD 00:00'));
        const yestardayStart = moment(moment(todayStart).subtract(1.'days'));
        const todayEnd = moment(moment().format('YYYY-MM-DD 24:00'));
        const tomorrowEnd = moment(moment(todayEnd).add(1.'days'));
        console.log(tomorrowEnd, 'tomorrowEndtomorrowEnd');
        let today = ' ';
        if (todayStart < date && date < todayEnd) {
          today = '(today);
        } else if (todayEnd < date && date < tomorrowEnd) {
          today = '(tomorrow);
        } else if (yestardayStart < date && date < todayStart) {
          today = '(yesterday);
        } else {
          today = ` (week${moment(date).day() == 0 ? 'day' : moment(date).day()}) `;
        }
        setDefaultTime({ time: date, tag: moment(date).format(` on DD MM${today} HH:mm`)}); };/ / closing Tag
  const closeTag = () = > {
    setDefinedDatePick(false);
    setIsBtnShow(false)}; useEffect(() = > {
    setSubmitData(data);
    setDefaultTime({
        // time:endTime,
        tag:timeTag,
    })
    console.log(timeTag,'timeTagtimeTagtimeTag') timeTag? setIsBtnShow(true):setIsBtnShow(false)
  }, [data]);
  console.log(submitData);

  return (
    <Drawer placement="right" onClose={handleClose} visible={visible} keyboard={true} closable={false}>
      <div className={styles.container}>
        <div className={styles.close}>
          <CloseOutlined onClick={handleClose} />
        </div>
        <div className={styles.inputCon}>
          <input
            className={styles.input}
            value={submitData.title}
            onChange={e= >{ setSubmitData({ ... submitData, title: e.target.value }); }} / ></div>
        <div className={styles.desc}>
          <TextArea
            rows={5}
            showCount={true}
            value={submitData.desc}
            maxLength={100}
            onChange={e= >{ setSubmitData({ ... submitData, desc: e.target.value }); }} / ></div>
        <div className={styles.calender}>
          <div className={styles.iconCon}>
            <CalendarOutlined style={{ fontSize: '17px' }} />
          </div>
          <div className={styles.dateCon}>
             {
                 !isBtnShow ? (
                  <>
                    <div
                    className={` ${styles.time_btn} ${isBtnShow ? styles.disabled :"'} `}onClick={()= > {
                        setDefinedDatePick(true)
                      chooseDefaultTime('today');
                    }}
                  >
                    <IconFont type="iconjintian" className={styles.icon} />today</div>
                  <div
                    className={` ${styles.time_btn} ${isBtnShow ? styles.disabled :"'} `}onClick={()= > {
                        setDefinedDatePick(true)
                      chooseDefaultTime('tomorrow');
                    }}
                  >
                    <IconFont type="icona-rili2" className={styles.icon} />tomorrow</div>
                  <div
                    className={styles.time_btn}
                    onClick={()= > {
                        setDefinedDatePick(true)
                    }}
                  >
                    <IconFont type="icona-rili3" className={styles.icon} />The custom</div>
                  </>) : (<>
                  <Tag closable onClose={closeTag} className={styles.tag} color="gold" style={{ padding: '5px'}}onClick={()= >{setDefinedDatePick(true)}}>
                    {defaultTime.tag}
                  </Tag>
                     </>)}<DatePicker
                      showTime
                      open={datePickShow}
                      defaultValue={defaultTime.time}
                      locale={locale}
                      onOk={()= >{setDefinedDatePick(false); setIsBtnShow(true)}} autoFocus onChange={e => { changeDate(e); }} / ><div className={styles.dateConwrap}></div>                

                  
          </div>
        </div>
      </div>
    </Drawer>
  );
}

Copy the code

index.less

.container {
  width: 100%;

  .close {
    width: 100%;
    height: 30px;
    text-align: right;
  }

  .inputCon {
    width: 100%;

    .input {
      border: 0;
      outline: none;
      border: none;
      width: 100%;

      /** Change the color */
      outline-color: "red";
      font-size: 20px; }}.desc {
    margin-top: 20px;
  }

  .calender {
    width: 100%;
    margin-top: 40px;
    display: flex;
    // height:40px;
    .iconCon {
      width: 30px;
      display: flex;
      align-items: center;
      vertical-align: middle;
    }
    .tag{
      z-index:10;
    }
    .dateConwrap{
      position:absolute;
      width:90%;
      height:40px;
      background-color: #fff;
    }
    .dateCon {
      flex:1;
      display: flex;
     
      .time_btn {
        margin-top: 4px;
        padding: 5px;
        font-size: 12px; 
        background-color: #f5f1f1;
        z-index: 10;
        border-radius: 5px;        
        &:hover {
          background-color: #cfcbcb ; 
        }
  
        .icon {
          font-size: 15px;
          margin-right: 3px; }}.time_btn:nth-child(n+2) {
        margin-left: 5px; }}} :global{
  .ant-picker-input{
    // display: none;
  }
  .ant-picker{
    width:30px; }}}Copy the code