Coder Social home page Coder Social logo

elicepa's Introduction

ElicePA

프로젝트 소개

이 PA 는 엘리스 기능중 하나인 과목 검색의 간소화된 버전을 구현하는 것입니다. 실제 페이지는 https://academy.elice.io/courses/all 에서 확인할 수 있습니다.

프로젝트 과정

  1. 프로젝트와 관련해 학습을 진행했습니다.

  2. 프로젝트 구상 계획을 세웠습니다.

    1. repo 생성 image

    2. issues 작성 image

    3. issues에 맞춰 branch 생성 image

    4. code 작업 image

    5. git push 후 git pull request image

    6. git merge (코드 리뷰와 approve는 개인 프로젝트였기 때문에 생략) image

    7. 프로젝트 배포 image

  3. 프로젝트 구현 과정을 기간 내 한 곳까지 README.MD를 작성했습니다.

문제 해결

url query

  • sessionStorage를 이용했습니다. 각 chip별로 unique한 값인 name을 부여한 뒤 toggle switch처럼 checked할 경우(click해서 checked가 true일 경우) 배열에 name을 넣었습니다.(chip.tsx 참고)
  • 배열을 토대로 해당 query 값을 정의한 뒤 배열값인 name을 key로 사용해 query 값을 가져왔습니다.(filterQuery.ts 참고)
  • 오름차순으로 정렬한 뒤 join 함수를 사용해 &로 string 화 시켜 Router.push 했습니다.
  • 이때 next의 next dynamic route를 이용했으며, query 값이 없을 경우도 고려해 [[...query]]를 사용했습니다.(Optional Catch-all Segments)

못한 부분

  • pagination

    • 시간 안에 구현을 못해 제가 한 이전 프로젝트 중 작업한 pagination 코드 부분을 첨부합니다.
    • 마감일이 끝난 이후에도 작업을 계속해 완성할 수 있도록 하겠습니다.
    • 졸업 프로젝트로 작년 1학기 때 진행했으며, 기본적으로 1~10 까지의 페이지가 있으며, 1일때 왼쪽 화살표를 클릭할 경우 페이지가 이동되지 않도록 설정했습니다.(오른쪽도 마찬가지)
    • react와 js, styled-components를 사용했습니다.
    • 프로젝트 pagination 코드 링크
    • 졸업 프로젝트 피그마 링크
image
// pagination 로직 부분

const changePage = (count) => {
  if (page % 10 == 0) {
    pageClick[9] = false;
  } else {
    pageClick[(page % 10) - 1] = false;
  }
  if (count % 10 == 0) {
    pageClick[9] = true;
  } else {
    pageClick[(count % 10) - 1] = true;
  }
  console.log("count = ", count);
  page[0] = count;
  setPage([...page]);
  setPageClick([...pageClick]);
  console.log("page = ", page);
  searchTag();
};

const nextPage = (direction) => {
  if (direction == "right") {
    for (let i = 0; i < 10; i++) {
      pageNumbers[i] += 10;
    }
    setPageNumbers([...pageNumbers]);
  } else {
    if (pageNumbers[0] - 10 <= 0) {
      setPageNumbers([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
    } else {
      for (let i = 0; i < 10; i++) {
        pageNumbers[i] -= 10;
      }
      setPageNumbers([...pageNumbers]);
    }
  }
  page[0] = pageNumbers[0];
  setPage([...page]);
  searchTag();
};
// pagination css 부분

const Style = {
PageList: styled.div`
 width: 100%;
 display: flex;
 align-items: center;
 justify-content: center;
 padding: 3vh 0;
`,
PageNum: styled.div`
 display: flex;
 flex-direction: row;
`,
Num: styled.div`
 padding: 0 1vw;
`,
NextBtn: styled.button`
 border: none;
 background-color: transparent;
 &:hover{
   color: #81E768;
 }
 ${({isselected}) =>
   isselected ?`
     color: #81E768;
     font-weight: bold;
   `
   :`
     color: #000000;
   `
 }
`
};,

<Style.PageList>
     <Style.NextBtn onClick={() => nextPage("left")}><FontAwesomeIcon icon={faChevronLeft} color="#94E0AC" size="2x" /></Style.NextBtn>
       <Style.PageNum>
         {pageNumbers.map(number => {
           return (
             <Style.NextBtn key={number} isselected={number == page? 1: 0} onClick={() => changePage(number)}><Style.Num>{number}</Style.Num></Style.NextBtn>
           )})
         }
       </Style.PageNum>
       <Style.NextBtn onClick={() => nextPage("right")}><FontAwesomeIcon icon={faChevronRight} color="#94E0AC" size="2x" /></Style.NextBtn>
     </Style.PageList>
  • api 연결

    • 시간 안에 구현을 못해 제가 한 이전 프로젝트 중 작업한 api 연결 작업 코드 부분을 첨부합니다.
    • 마감일이 끝난 이후에도 작업을 계속해 완성할 수 있도록 하겠습니다.
    • 부트캠프 중 진행한 프로젝트로 작년 하반기 때 진행했습니다.
    • next 환경에서 scss를 사용했습니다.
    • 프로젝트 링크
    • 프로젝트 api 연결 작업 코드 링크
// 검색어를 통해 filtering 된 게시물을 가져오는 작업 코드

import { apiClient } from "@/lib/axios";

export const getSearchData = async (keyword: string) => {
  try {
    const { data } = await apiClient.get(`/api/search/all/${keyword}`);
    return data;
  } catch (e) {
    if (e instanceof Error) throw new Error(e.message);
  }
};

배포 링크

https://elice-pa-ten.vercel.app/

elicepa's People

Contributors

lim-jiseon avatar

Watchers

 avatar

elicepa's Issues

api 연결

api를 연결합니다.

interface OrgCourseListResponses {
  courseCount: number;
  courses: {
    courseType: number;
    tags: string[];
    title: string;
    shortDescription: string;
    classType: number;
    logoFileUrl: null | string;
    enrolledRolePeriod: null | string;
    enrolledRoleBeginDatetime: number | null;
    enrolledRoleEndDatetime: number | null;
    beginDatetime: number;
    endDatetime: null | number;
    isDiscounted: boolean;
    discountedPrice: string;
    discountedPriceUsd: string;
    discountRate: null | any;
    price: string;
    priceUsd: string;
    enrollType: number;
    isFree: boolean;
  }[];
}

요구사항

  • State Management
    • Component의 local state를 사용하셔도 되고, 혹은 선택적으로 Redux/Rx/Flux/… 등의 global state를 이용하셔도 됩니다.
  • Ajax request
    • API를 부르기 위해서 사용하는 ajax 라이브러리는 자유롭게 선택하시면 됩니다.
  • request, response type 정의
  • CORS 해결
  • course list에 대한 reponse는 아래 interface를 참고하여 구현하면 됩니다. (코스페이지를 만들기위한 필요한 data만 골라서 client로 보냅니다.)
  • https://academy.elice.io/ 에서 production에서 사용하고 있는 request, response를 참고하면 됩니다.

검색바 컴포넌트 구현

해당 사진의 검색바 컴포넌트를 구현합니다.

image

요구사항

  • Textbox 의 border는 rgb(201, 202, 204) 의 색과 1px의 두께, 그리고 4px 의 radius 를 가집니다.
  • Placeholder text의 색은 CSS gray로 설정합니다.
  • 상하 12px 의 margin을 가집니다.
  • Textbox 왼쪽에는 search icon 이 있습니다. Font-awesome 등을 사용하시거나 자유롭게 아이콘을 제작하셔서 사용하셔도 됩니다.
  • 아이콘은 양옆 16px의 margin을 가집니다.
  • Textbox 에서 문자열을 입력 시 문자열을 입력할 때마다 300ms debounced search를 수행합니다.

chip 컴포넌트 구현

해당 사진의 chip 컴포넌트를 구현합니다.

image

요구사항

  • 임의의 라이브러리 사용 혹은 직접 구현을 통해, Chip 을 구현합니다.
  • 디자인은 자유롭게 구현합니다.
  • [무료], [유료] 를 모두 선택하거나 하나만 선택, 그리고 아예 선택하지 않을 수 있습니다.
  • 필터는 filter_conditions 파라미터를 이용합니다.(JSON type)

유료/무료과목필터 방법 예

// 유료과목필터 방법 예
filter_conditions: JSON.stringify({
 $and: [
     { title: '%c언어%' },
     { $or: [{ enroll_type: 0, is_free: false }] },
 ],
}),
// 무료, 유료과목필터 방법 예
filter_conditions: JSON.stringify({
 $and: [
     { title: '%c언어%' },
     {
         $or: [
             { enroll_type: 0, is_free: true },
             { enroll_type: 0, is_free: false },
         ],
     },
 ],
})```

Pagination 구현

해당 사진의 Pagination 구현합니다.

image

요구사항

  • Pagination 숫자는 w: 24px, h : 24px 의 크기를 가진 box 내에 표시합니다.
  • 현재 페이지의 Box는 #524fa1 의 색을, 이 때 숫자의 색은 white 입니다.
  • 그 외 숫자의 색은 #999 입니다.
  • 현재 페이지 기준 앞쪽으로 최대 4개, 뒷쪽으로 최대 4개의 페이지를 더 표시합니다.
    • 예) 현재 페이지가 13인 경우: 9 10 11 12 [13] 14 15 16 17
  • Arrow
    • 현재 페이지가 1이거나 마지막 페이지인 경우 왼쪽/오른쪽 arrow 색은 #ccc
    • 그렇지 않으면 #222 의 색을 가집니다.

chip table 구현

해당 사진의 chip table을 구현합니다.

image

요구사항

  • 임의의 라이브러리 사용 혹은 직접 구현을 통해, Chip 을 구현합니다.
  • 디자인은 자유롭게 구현합니다.
  • [무료], [유료] 를 모두 선택하거나 하나만 선택, 그리고 아예 선택하지 않을 수 있습니다.
  • 필터는 filter_conditions 파라미터를 이용합니다.(JSON type)

유료/무료과목필터 방법 예

// 유료과목필터 방법 예
filter_conditions: JSON.stringify({
 $and: [
     { title: '%c언어%' },
     { $or: [{ enroll_type: 0, is_free: false }] },
 ],
}),
// 무료, 유료과목필터 방법 예
filter_conditions: JSON.stringify({
 $and: [
     { title: '%c언어%' },
     {
         $or: [
             { enroll_type: 0, is_free: true },
             { enroll_type: 0, is_free: false },
         ],
     },
 ],
})```

card area 구현

해당 사진의 카드 레이아웃을 구현합니다.

image

요구사항

  • 232px 기준, 코스 카드 4개가 들어갈 수 있습니다.
  • 코스 카드 간 gutter size는 x: 16px, y: 16px 입니다.
  • Pagination을 수행합니다.
  • 한 페이지당 최대 20개의 코스 카드를 표시할 수 있도록 합니다.

search area 구현

해당 사진의 search area를 구현합니다.

image

요구사항

  • 스크린과 컨테이너 사이에 24px 의 padding이 있어야 합니다.
  • 스크린의 크기가 1280px 일 경우부터는 레이아웃의 크기가 1280px로 중앙정렬되게 고정되어야 합니다.
  • 스크린의 크기가 1280px 미만일 때는 레이아웃이 스크린 전체의 width 를 차지하도록 합니다.

카드 컴포넌트 구현

해당 사진의 카드 컴포넌트를 구현합니다.

image

요구사항

  • Course Card
    • w: 296px, h: 338px 입니다.
    • 8px 의 border radius를 가지며, border 는 없습니다.
  • Body
    • 상하 28px, 좌우 24px 의 padding을 가집니다.
  • Label
    • 12px 의 size, bold, #524fa1 의 색상을 가진 레이블을 표시합니다.
    • course.enroll_type 및 course.is_free 값에 따라 다음 값을 표시합니다.
  • Title
    • 폰트 크기는 18px, bold, #222, line height 는 1.6 으로 설정합니다.
    • course.title 값을 표시합니다.
    • Title 이 길 경우 최대 라인수는 2로 표시하며 끝에 … 를 표시합니다.
  • Description
    • 폰트 크기는 14px, #5e5f61, line height 는 1.6 으로 설정합니다.
    • course.short_description 값을 표시합니다.
    • 텍스트가 길 경우 최대 라인수는 2로 표시하며 끝에 … 를 표시합니다.
  • IconText
    • 아이콘은 24px의 크기의 임의의 아이콘을 사용합니다.
    • 텍스트는 12px, #7d7e80 의 색상을 가집니다.
    • 아이콘과 텍스트 사이에는 8px 의 space 가 있습니다.
    • 아이콘과 텍스트의 vertical align 은 중앙정렬 되어야 합니다.
    • 다음 내용을 표시합니다.
[임의 아이콘] 난이도 : 미설정
[임의 아이콘] 수업 : 온라인
[임의 아이콘] 기간 : 무제한
  • Logo
    • Body 오른쪽 끝 위치에 align 하여 수업 로고를 표시합니다.
    • 수업 로고의 위치는 첫 번째 IconText 의 상단과 일치합니다.
    • course.logo_file_url 을 표시합니다.
    • w: 52px, h: 52px 크기를 유지하며 로고의 proportion 이 정사각형이 아닌 경우 정사각형 내에 이미지의 proportion 을 유지하면서 모든 부분이 보이도록 해야 합니다.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.