react project : TODO-LIST 웹애플리케이션

haegnim·2023년 6월 30일

Project

목록 보기
4/5
post-thumbnail

TO-DO LIST

프로젝트 개요

react TO-DO-LIST 사용자가 할 일 목록을 관리할 수 있는 웹 애플리케이션입니다.

배포

📎TO-DO LIST
📎github


프로젝트 구조

페이지 구성

  • 메인페이지
  • 상세페이지
  • 수정페이지

구현 기능

  • TODO 추가 : TODO 제목과 상세내용을 입력하고 저장
  • TODO 수정 : TODO 상세페이지에서 TODO의 내용을 수정
  • TODO 삭제 : TODO를 삭제할 수 있습니다.
  • TODO 완료/미완료 표시 : 체크 아이콘을 클릭하여 완료/미완료 TODO를 구별
  • TODO 필터링 : 전체 TODO, 완료 TODO, 미완료 TODO를 필터링 하여 페이지에 보여줌
  • TODOLIST 레이아웃 전환 : 레이아웃 변환 토글 버튼을 통해 card, list 2가지 레이아웃 제공

내가 맡은 작업

TODO 메인페이지

구현기능

  • TODOLIST 구현
  • TODO 필터링 구현
  • TODO 완료/미완료 표시
  • TODO 레이아웃 전환 CSS

props

todos, workState, toggles는 리덕스로 받아온 값이다.

  • todos : todolist의 content를 받아온다.
  • workState : todo의 완료 미완료 필더값을 받아온다.
  • toggle : todo의 레이아웃값을 받아온다.

함수

  • getKeyByValue는 객체로 담겨있는 toggles의 값을 받아온다.
  • isdoneColor todo의 완료 미완료 상태(isdone)에 따라 스타일 컴포넌트로 넣어줄 컬러를 반환한다.
  • todoList는 workState의 값에 따라 완료/ 미완료/ 전체를 나눠 필터링해 배열을 반환한다.
function TodoListItem({ todos, workState, toggles }) {
    const dispatch = useDispatch();
    const getKeyByValue = () => {
        for (let key in toggles) {
            if (toggles[key] && key) {
                return key;
            }
        }
    };
    const isdoneColor = (isdone) => {
        return isdone === true ? '#31af7f' : '#b5b5b5';
    };
    console.log(getKeyByValue());
    const todoList = () => {
        if (workState === 'all') {
            return todos;
        } else {
            return todos.filter((item) => item.isDone === workState);
        }
    };

    return (
        <TodoItemBlock>
            {todoList().map((item, idx) => {
                return (
                    <TodoItem
                        key={item.id}
                        className={getKeyByValue()}
                        isdonecolor={item.isDone ? `#e1fff6` : '#fff'}
                    >
                        <IdBox className={getKeyByValue()}>{idx + 1}</IdBox>
                        <StyledContent item={item} getKeyByvalue={getKeyByValue()} />
                        <IconBox className={getKeyByValue()} isdonecolor={isdoneColor(item.isDone)}>
                            <Check
                                id="check-icon"
                                onClick={() => {
                                    dispatch(toggleItem(item.id));
                                }}
                            />
                            <Delete
                                id="delete-icon"
                                onClick={() => {
                                    dispatch(deleteItem(item.id));
                                }}
                            />
                        </IconBox>
                    </TodoItem>
                );
            })}
        </TodoItemBlock>
    );
}

필터바 컴포넌트

스타일 컴포넌트 (스타일링 부분은 제거)

const StyledfilterBlock = styled.div`
	.
	.
	.
    display: flex;
    position: relative;
    transition: all 0.3s ease-in-out;
    label {
		.
		.
		.
        z-index: 99;
        position: relative;
        display: flex;
        align-items: center;
        justify-content: space-around;
        cursor: pointer;
        &.active {
            color: #31be86;
            .countNum {
                background-color: #fff;
            }
        }
    }
`;
const Glider = styled.span`
	.
	.
	.
    position: absolute;
    z-index: 1;
    transition: 0.25s ease-out;
    transform: translateX(${(props) => props.translatevalue}%);
`;
const CountNum = styled.span`
    display: inline-block;
	.
	.
	.
`;

filter bar 컴포넌트
useState를 사용하지 않으면 리렌더링이 안되기 때문에 사용했다.

  • Span : 스타일 컴포넌트로 translate에 props 값을 전달
  • active : label의 active 클래스 추가 제거
  • onChangeHandler : workState로 값을 전달
const Styledfilter = ({ onChangeHandler, workNum, doneNum }) => {
    const [span, setSpan] = useState(0);
    const [active, setActive] = useState(1);
    const tabMove = (x, id, value) => {
        setSpan(x);
        setActive(id);
        onChangeHandler(value);
    };
    return (
        <StyledfilterBlock>
            <Glider translatevalue={span}></Glider>
            <label onClick={() => tabMove(0, 1, 'all')} className={active === 1 ? 'active' : ''}>
                All
            </label>
            <label
                onClick={() => tabMove(100, 2, 'working')}
                className={active === 2 ? 'active' : ''}

                🔥 Working..!
                <CountNum className="countNum">{workNum}</CountNum>
            </label>
            <label onClick={() => tabMove(200, 3, 'done')} className={active === 3 ? 'active' : ''}>
                🌈 Done...!
                <CountNum className="countNum">{doneNum}</CountNum>
            </label>
        </StyledfilterBlock>
    );
};

TODO 상세페이지 제작(view)

TODO 수정페이지 제작(view)

UI 컴포넌트 재사용

input, textarea, button 컴포넌트를 재사용했다.

  • 수정페이지 컴포넌트
const TodoUpdate = ({ todo }) => {
    return (
        <TodoUpdateBlock>
            <UpdatePage>
                <Link to="/">
                    <BackButton backgroundcolor={`#31be86`} hovercolor={`#c9f4e9`}></BackButton>
                </Link>
                <form>
                    <StyledInput value={'리액트 공부하기'} height={`40px`} radius={`14px`} />
                    <StyledTextArea value={'리액트 공부하기'} />
                    <StyledButton buttontext={'update'} />
                </form>
            </UpdatePage>
        </TodoUpdateBlock>
    );
};
  • BackButton 컴포넌트
const BackBtn = styled.button`
    width: 143px;
    height: 36px;
    border: none;
    background-color: ${(props) => props.backgroundcolor || `#c9f4e9`};
    color: ${(props) => props.hovercolor || `#31be86`};
    .
	.
	.

    &:hover {
        background-color: ${(props) => props.hovercolor || `#31be86`};
        color: ${(props) => props.backgroundcolor || `#fff`};
    }
`;
const BackButton = ({ backgroundcolor, hovercolor }) => {
    return (
        <BackBtn backgroundcolor={backgroundcolor} hovercolor={hovercolor}>
            <FontAwesomeIcon icon={faReply} id="icon-reply" />
            이전
        </BackBtn>
    );
};
export default BackButton;

0개의 댓글