サブプロジェクトレビュー(Megabox)


サブプロジェクトの短縮(?)回顧録を書きます.ますます多くの回忆录を书くことができることを望みます!!これでやっと就職できる.🤣
メガボックス ... 🥴 私たちMEGAFOXもよくできました!(制作の時に精神が崩れてしまいました…)
👉 崩壊の始まりメガフォックスハーブ

🎬 チームの概要


👩🏻‍💻 プロジェクト期間
  • 2021.10.18 ~ 2021.10.28
  • 🔎   チーム名
  • Megafox
    何してるの...?真剣に考えた後にドビンの考えで誕生しました^^7
  • 🐥   チームメンバーの概要と実装機能FrontEnd

  • 申恵利(Me!)🙇‍♀️)
    共通タブ構成部品の実装
    完全な映画ページ実装
    ムービー詳細ページの実装
    映画全体のネーミングを実現
    映画画像全体のサスペンション時にAPI受信を実現するストーリーコンテンツ
    ダイナミックルーティングによる映画詳細ページへのアクセス
    表示レベルに応じてアイコンを非画像スタイルに設定

  • 教壇
    Headerゾーンナビゲーションの実装
    サイトマップの実装
    ムービー名にマウスサスペンション機能を使用すると、対応するムービーポスターを印刷できます.
    ログイン/終了状態に基づいてユーザ情報出力を実現
    ホームページ:apiを使用して映画観客数top 4を出力
    ムービーポスター上のマウスのサスペンションにより、対応するムービー情報出力機能を実現

  • 鄭燦栄
    共通スタイル変数、fontの追加
    ソーシャルログインの実施(KACA)
    映画館全体のページを実現
    スクロールイベントの実装(上へ移動ボタン)
    前売りページ実装
    実施日スライド
    上映時間と上映時間に合わせてチーク処理を実施しております
    複数選択ボタンを実装し、選択したターゲットに基づいてAPI呼び出しを実現
  • BackEnd

  • 李多彬
    ココアソーシャルログインAPIを使用したログインAPI(GET)
    ユーザ情報呼び出しAPI(GET)
    ログインレコーダを実装してユーザー権限を検証
    コメントAPIの作成、削除、変更(POST、GET、DELETE、PATCH)
    クイック前売り、販売履歴API(POST、GET)

  • 金道勲.
    映画リスト/詳細ページAPI(GET)
    シアターリストAPI(GET)
    映画、映画館、コメント良い/API削除(POST)
    クイック前売り、販売履歴API(POST、GET)
  • 🛠   応用技術

  • FrontEnd :React, React Hooks, React Route ,Styled-Components

  • BackEnd :[email protected], [email protected], [email protected]

  • 配置:AWS(EC 2、RDS、LB)
  • これは私が真剣に書いたコードです。私を見てください。👼


    機能実装とコード共有


    🎹 Tab Component(共通)


    映画全体のページや詳細ページにはtabが同じ色で加わっているため、共通の構成部分となっている.😊

    コード共有

    import React from 'react';
    import styled from 'styled-components/macro';
    import { flexAround } from 'styles/mixin';
    
    //다른곳에서 쓰이는 컴포넌트이기 때문에 props로 내려받아야 할 속성들을 지정한다.
    function Tab({ tabList, selectedTab, toggleTab }) {
      return (
        <TabMenuContainer>
          <TabMenu>
        	//받아온 data를 map으로 구현합니다.
            {tabList.map(tab => {
              return (
                <TabMenuList
                //선택된 tab의 id가 selectedTab과 일치하면 TabMenuList 컴포넌트로 인해 border의 컬러가 바뀌게된다.
                  isSelected={selectedTab === tab.id}
                  key={tab.id}
                  onClick={() => {
                    toggleTab(tab.id);
                  }}
                >
                  {tab.menu}
                </TabMenuList>
              );
            })}
          </TabMenu>
        </TabMenuContainer>
      );
    }
    
    
    //styled-components
    const TabMenuContainer = styled.div`
      max-width: 1100px;
      margin: 0 auto;
      padding-top: 40px;
    `;
    
    const TabMenu = styled.ul`
      ${flexAround}
    `;
    
    const TabMenuList = styled.li`
      width: 20%;
      padding: 10px;
      text-align: center;
      color: ${({ isSelected, theme }) => (isSelected ? theme.purple : '#222')};
      border: 1px solid
        ${({ isSelected, theme }) => (isSelected ? theme.purple : '#ebebeb')};
      border-bottom: 1px solid
        ${({ isSelected, theme }) => (isSelected ? 'transparent' : theme.purple)};
    
      cursor: pointer;
    `;
    
    export default Tab;
    

    🎫 映画全体のページ


    全体の映画のページの上で体現する内容はとても多くて、私は更に体現する機能を説明して、そして評論で詳しく説明します.😁
  • を実現し、映画画像全体のサスペンション時にAPIが受信したストーリーコンテンツを表示する
  • 動的ルーティングにより、各映画詳細ページの
  • が実現される.
  • の視聴レベルに応じて、アイコン
  • が非画像スタイルで表示する.

    コード共有

    import React, { useEffect, useState } from 'react';
    import { Link } from 'react-router-dom';
    import Tab from 'components/Tab/Tab.js';
    import styled from 'styled-components/macro';
    import { flexCenter } from 'styles/mixin';
    
    //LIMIT은 상수 데이터이므로 function 밖에서 선언해주었다.
    const LIMIT = 4;
    
    function Movies() {
      const [moviePosterList, setMoviePosterList] = useState([]);
    
      // offset을 제외한 tab, tabCurrent, toggleTab은 tab 컴포넌트에서 내려 받는것들!
      const [tab, setTab] = useState([]);
      const [tabCurrent, setTabCurrent] = useState(1);
    
      const [offset, setOffset] = useState(0);
    
      const toggleTab = idx => {
        setTabCurrent(idx);
      };
    
      // custom hook으로 빼주려다가 시간이 촉박해서 주소를 넣었다 😅 리팩토링 할 예정...
      useEffect(() => {
        fetch(
          `배포용주소/movie?limit=${LIMIT}&offset=${offset * LIMIT}`
        )
          .then(res => res.json())
        
          //...(Spread Operator)를 사용하지 않으면 값 공유가 되어 페이지네이션이 많이 아파한다...
          .then(res => setMoviePosterList(prev => [...prev, ...res]));
      }, [offset]);
    
      useEffect(() => {
        fetch('data/TabData.json')
          .then(res => res.json())
          .then(res => setTab(res));
      }, []);
    
      const findMovie = () => {
        setOffset(offset + 1);
      };
    
      //조건에 따라 색이 바뀌게 구현됨(리팩토링 필요한 코드!)
      const ageLimit = age => {
        if (age === '12세이상관람가') {
          return '#188ef7';
        }
        if (age === '15세이상관람가') {
          return '#eba010';
        }
        if (age === '전체관람가') {
          return '#3fa701';
        }
        if (age === '청소년관람불가') {
          return '#e81002';
        }
      };
    
      return (
        <MoviesContainer>
          <MoviesLayout>
            <MoviesTitle>전체영화</MoviesTitle>
        
        	//공통 컴포넌트에 필요한 props를 받아왔다.
            <Tab tabList={tab} selectedTab={tabCurrent} toggleTab={toggleTab} />
            <MoviesSearchContents>
              <MoviesSearchNewRelease>
                <NewReleaseBtn>
                  <span />
                </NewReleaseBtn>
                <p>개봉작만</p>
                <p>10개의 영화가 검색되었습니다.</p>
              </MoviesSearchNewRelease>
    
              <MoviesSearch>
                <input placeholder="영화명 검색" />
                <button>
                  <i className="fas fa-search" />
                </button>
              </MoviesSearch>
            </MoviesSearchContents>
            <MoviesListContainer>
               //map 함수를 이용해 movie list를 구현
              {moviePosterList?.map(info => {
                return (
                  <MoviesList key={info.movie_id}>
                    <MoviesSummaryContainer>
                      <Link to={`/movie-info/${info.movie_id}`}>
                        <MoviesPoster
                          src={info.image[0].main_image_url}
                          alt={info.ko_name}
                        />
                        <MoviesSummary>
                          <p>{info.description}</p>
                        </MoviesSummary>
                      </Link>
                    </MoviesSummaryContainer>
    
                    <MoviesListTitle>
    
                      <MoviesAge age={ageLimit(info.age_rate)}>
    		  //12, 15는 숫자만 나오게하고 그외는 정해진 글자로 나오도록 설정(리팩토링이 필요한것같다.)
                        {(() => {
                          if (parseInt(info.age_rate, 10)) {
                            return parseInt(info.age_rate, 10);
                          } else {
                            if (info.age_rate === '청소년관람불가') {
                              return '청불';
                            }
                            if (info.age_rate === '전체관람가') {
                              return '전체';
                            }
                          }
                        })()}
                      </MoviesAge>
                      <h3>{info.ko_name}</h3>
                    </MoviesListTitle>
                    <MoviesInfo>
                      <p>예매율 13.6%</p>
                      <span />
                      <p>{info.release_date}</p>
                    </MoviesInfo>
                    <MoviesBtn>
                      <LikeBtn>
                        <i className="far fa-heart" />
                        <p>{info.like}</p>
                      </LikeBtn>
    
                      <BookingLink to="/booking">
                        <BookingBtn>
                          <p>예매</p>
                        </BookingBtn>
                      </BookingLink>
                    </MoviesBtn>
                  </MoviesList>
                );
              })}
            </MoviesListContainer>
    
    	//클릭시 movie list들이 4개씩 나온다.
            <SeeMore onClick={findMovie}>
              더보기
              <i className="fas fa-chevron-down" />
            </SeeMore>
          </MoviesLayout>
        </MoviesContainer>
      );
    }
    
    //styled-components
    const MoviesContainer = styled.div`
      padding-top: 40px;
    `;
    
    const MoviesLayout = styled.div`
      max-width: 1100px;
      margin: 0 auto;
    `;
    
    const MoviesTitle = styled.h2`
      padding: 0 0 26px 0;
      font-size: 28px;
      color: ${props => props.theme.gray};
    `;
    
    const MoviesSearchContents = styled.div`
      display: flex;
      justify-content: space-between;
      margin-top: 40px;
      margin-bottom: 15px;
    `;
    
    const MoviesSearchNewRelease = styled.div`
      display: flex;
      align-items: center;
    
      p {
        margin-left: 10px;
        font-size: 15px;
        color: #ccc;
    
        &:last-child {
          margin-left: 20px;
          font-size: 16px;
          color: #222;
        }
      }
    `;
    
    const NewReleaseBtn = styled.button`
      position: relative;
      width: 26px;
      height: 14px;
      border-radius: 32%;
      border: transparent;
      background: #ccc;
    
      span {
        position: absolute;
        display: inline-block;
        width: 11px;
        height: 11px;
        top: 1.46px;
        left: 2px;
        border-radius: 50%;
        background: white;
      }
    `;
    
    const MoviesSearch = styled.div`
      position: relative;
      display: flex;
      border: 1px solid #d8d9db;
    
      input {
        width: 80%;
        height: 34px;
        padding-left: 10px;
        border: transparent;
    
        &:focus {
          outline: none;
        }
      }
    
      button {
        width: 20%;
        border: transparent;
        background: transparent;
    
        i {
          position: absolute;
          top: 8px;
          right: 9px;
          font-size: 16px;
          color: #929292;
        }
    
        &:focus {
          outline: none;
        }
      }
    `;
    
    const MoviesListContainer = styled.div`
      display: flex;
      flex-wrap: wrap;
    `;
    
    const MoviesList = styled.div`
      display: flex;
      flex-direction: column;
      min-width: 20%;
      max-width: 22%;
      margin-right: 30px;
      margin-bottom: 60px;
    `;
    
    const MoviesPoster = styled.img`
      width: 100%;
    `;
    
    const MoviesSummaryContainer = styled.div`
      position: relative;
      width: 100%;
      height: 100%;
    `;
    
    const MoviesSummary = styled.div`
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      width: 100%;
      height: 99%;
      padding: 20px;
      color: white;
      line-height: 1.4;
      background: rgba(0, 0, 0, 0.5);
      opacity: 0;
    
      p {
        height: 150px;
        font-size: 15px;
        overflow: hidden;
      }
    
      &:hover {
        opacity: 1;
      }
    `;
    
    const MoviesListTitle = styled.div`
      display: flex;
      align-items: center;
      margin-top: 15px;
    
      h3 {
        width: 70%;
        margin-left: 5px;
        font-size: 20px;
        font-weight: 400;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    `;
    
    const MoviesAge = styled.span`
      display: inline-block;
      width: 23px;
      height: 23px;
      line-height: 2.2;
      border-radius: 50%;
      text-align: center;
      font-size: 11px;
      color: white;
      background: ${({ age }) => age};
    `;
    
    const MoviesInfo = styled.div`
      display: flex;
      margin-top: 10px;
      font-size: 16px;
    
      span {
        margin: 0 5px;
        border-left: 1px solid #d8d9db;
      }
    `;
    
    const MoviesBtn = styled.div`
      display: flex;
      margin-top: 10px;
    `;
    
    const LikeBtn = styled.button`
      ${flexCenter}
      width: 25%;
      padding: 5px;
      margin-right: 5px;
      border: 1px solid #ebebeb;
      border-radius: 3px;
      color: #aaa;
      background: transparent;
    
      i {
        font-size: 17px;
        margin-right: 2px;
      }
    
      p {
        margin-left: 3px;
        color: ${props => props.theme.purple};
      }
    
      &:hover {
        background: #f2f4f8;
      }
    `;
    
    const BookingLink = styled.a`
      width: 77%;
      text-decoration: none;
    `;
    
    const BookingBtn = styled.button`
      width: 100%;
      padding: 5px;
      color: white;
      border: transparent;
      border-radius: 3px;
      background: ${props => props.theme.purple};
    
      &:hover {
        background: #351f67;
      }
    `;
    
    const SeeMore = styled.button`
      ${flexCenter};
      width: 100%;
      padding: 10px 15px;
      margin-top: 40px;
      border: 1px solid #eaeaea;
      color: #666;
      background: transparent;
    
      i {
        margin-left: 6px;
      }
    
      &:hover {
        border: 1px solid #666;
      }
    `;
    
    export default Movies;
    

    🍿 詳細ページ


    詳細ページ?映画情報ページ?どう歌えばいいか悩んで、詳細ページにしました...いずれにしても,ここではid値で判別し,動的ルーティングを適用した.そこでmovie-info/:idでルータ:Dを作成しました

    👇 routes.ぶぶん

    コード共有

    import React, { useEffect, useState } from 'react';
    import { Link } from 'react-router-dom';
    import styled from 'styled-components';
    import { flexBetween, flexCenter } from 'styles/mixin';
    
    //match는 구조분해할당으로 넣어주었다!
    function MoviesInfo({ match }) {
      const [movie, setMovie] = useState({});
    
      useEffect(() => {
      // id값을 매칭해서 결괏값을 동적 라우팅을 통해 나타내준다.
        fetch(`http://3.36.66.16:8000/movie/${match.params.id}`)
          .then(res => res.json())
          .then(res => {
            setMovie(res[0]);
          });
      }, [match.params.id, setMovie]);
    
      return (
        <>
          <MoviesInfoContainer>
            <MoviesPosterInfo>
              <MoviesBackground img={movie.images?.[0].main_image_url} />
              <MoviesInfoHeader>
                <MoviesInfoHeaderContainer>
                  <MoviesHashtag>#돌비시네마 #빵원티켓+ #굿즈패키지</MoviesHashtag>
                  <h3>{movie.ko_name}</h3>
                  <h4>{movie.eng_name}</h4>
    
                  <HeaderBtn>
                    <HeaderLike>
                      <i className="far fa-heart" />
                      <p>{movie.like}</p>
                    </HeaderLike>
    
                    <HeaderSharedBtn>
                      <i className="fas fa-share-alt" />
                      <p>공유하기</p>
                    </HeaderSharedBtn>
                  </HeaderBtn>
                </MoviesInfoHeaderContainer>
    
                <MoviesContentInfo>
                  <MoviesImg
                    src={movie.images?.[0].main_image_url}
                    alt={movie.ko_name}
                  />
                  <Link to="/booking">
                    <button>예매</button>
                  </Link>
                </MoviesContentInfo>
              </MoviesInfoHeader>
    
              <MoviesInfoContents>
                <MoviesScore>
                  <p>실관람 평점</p>
                  <MoviesCount>
                    <i className="fas fa-trophy" />
                    <p>8.7</p>
                  </MoviesCount>
                </MoviesScore>
    
                <MoviesScore>
                  <p>누적관객수</p>
                  <MoviesCount>
                    <i className="fas fa-users" />
                    <p>66,038</p>
                  </MoviesCount>
                </MoviesScore>
              </MoviesInfoContents>
            </MoviesPosterInfo>
          </MoviesInfoContainer>
          <MoviesReview>
            <p>
              {movie.ko_name}에 대한 <span>1,543</span>개의 이야기가 있어요!
            </p>
            <ReviewContents>
              <MyReview>
                <span>F</span>
                <p>MEGAFOX</p>
              </MyReview>
              <MyStory>
                <p>
                  <span>{movie.ko_name}</span> 재미있게 보셨나요? 영화의 어떤 점이
                  좋았는지 이야기해주세요.
                </p>
    
                <MyStoryWrite>
                  <i className="far fa-edit" />
                  <p>관람평쓰기</p>
                </MyStoryWrite>
              </MyStory>
            </ReviewContents>
    
            <AnotherUser>
              <AnotherUserId>
                <i className="fas fa-user" />
                <p>Jet**</p>
              </AnotherUserId>
    
              <AnotherUserComment>
                <p>관람평</p>
                <span>10</span>
                <p>연출</p>
    
                <AnotherUserLine />
    
                <AnotherUserWrite>
                  <p>웅장한 스케일과 스토리에 잼나게 봤어요</p>
                  <AnotherUserMenu>
                    <AnotherUserLike>
                      <i className="far fa-thumbs-up" />
                      <p>0</p>
                    </AnotherUserLike>
                    <i className="fas fa-ellipsis-v" />
                  </AnotherUserMenu>
                </AnotherUserWrite>
              </AnotherUserComment>
            </AnotherUser>
          </MoviesReview>
        </>
      );
    }
    
    //styled-components
    const MoviesInfoContainer = styled.div`
      background: black;
    `;
    
    const MoviesPosterInfo = styled.div`
      position: relative;
      max-width: 1100px;
      height: 520px;
      margin: 0 auto;
    `;
    
    const MoviesBackground = styled.div`
      position: absolute;
      width: 100%;
      height: 100%;
      margin: 0 auto;
      background: url(${({ img }) => img}) no-repeat;
      background-position: top center;
      background-size: 80% auto;
      filter: blur(5px);
      opacity: 0.4;
    `;
    
    const MoviesInfoHeaderContainer = styled.div`
      display: flex;
      flex-direction: column;
    `;
    
    const MoviesInfoHeader = styled.div`
      position: relative;
      display: flex;
      justify-content: space-between;
      padding: 55px 45px 0 45px;
      color: white;
    
      h3 {
        margin: 15px 0 10px 0;
        font-size: 46px;
      }
    `;
    
    const MoviesHashtag = styled.span`
      color: #ccc;
      font-size: 15px;
    `;
    
    const HeaderBtn = styled.div`
      display: flex;
      margin-top: 15px;
    `;
    
    const HeaderLike = styled.button`
      display: flex;
      align-items: center;
      padding: 6px 15px;
      margin-right: 6px;
      border: 1px solid #706f72;
      border-radius: 4px;
      color: white;
      background: transparent;
    
      i {
        margin-right: 4px;
      }
    `;
    
    const HeaderSharedBtn = styled.button`
      display: flex;
      align-items: center;
      border: 1px solid #706f72;
      border-radius: 4px;
      color: white;
      background: transparent;
    
      i {
        margin-right: 4px;
      }
    `;
    
    const MoviesInfoContents = styled.div`
      display: flex;
      padding: 0 45px;
    `;
    
    const MoviesScore = styled.div`
      position: relative;
      display: flex;
      flex-direction: column;
      margin-left: 35px;
    
      p {
        color: #ccc;
        font-size: 14px;
        padding-bottom: 15px;
      }
    
      &:first-child {
        margin-left: 0;
      }
    
      i {
        color: white;
      }
    `;
    
    const MoviesCount = styled.div`
      display: flex;
      i {
        margin-right: 6px;
        font-size: 20px;
      }
    
      p {
        font-size: 32px;
        color: white;
      }
    `;
    
    const MoviesContentInfo = styled.div`
      display: flex;
      flex-direction: column;
      width: 260px;
      height: 374px;
    
      button {
        width: 100%;
        margin-top: 8px;
        padding: 10px;
        font-size: 18px;
        border-radius: 5px;
        border: transparent;
        color: white;
        font-weight: bold;
        background: #329eb1;
      }
    `;
    
    const MoviesImg = styled.img`
      border-radius: 10px;
    `;
    
    const MoviesReview = styled.div`
      max-width: 1100px;
      margin: 0 auto;
      padding-top: 30px;
    
      p {
        font-size: 22px;
        color: ${props => props.theme.purple};
    
        span {
          color: #01738b;
        }
      }
    `;
    
    const ReviewContents = styled.div`
      display: flex;
      margin-top: 15px;
    `;
    
    const MyReview = styled.div`
      display: flex;
      flex-direction: column;
      width: 6%;
    
      span {
        ${flexCenter}
        width: 50px;
        height: 50px;
        margin: 0 auto 10px auto;
        line-height: 3;
        border-radius: 50%;
        text-align: center;
        font-weight: bold;
        color: white;
        background: rgb(107, 74, 190);
        background: linear-gradient(
          127deg,
          rgba(107, 74, 190, 1) 0%,
          rgba(80, 51, 150, 1) 100%
        );
      }
    
      p {
        font-size: 14px;
        color: #444;
      }
    `;
    
    const MyStory = styled.div`
      ${flexBetween}
      width: 93%;
      padding: 25px;
      margin-left: 25px;
      border: 1px solid #eaeaea;
      border-radius: 0 10px 10px 10px;
    
      p {
        color: #666;
        font-size: 15px;
      }
    `;
    
    const MyStoryWrite = styled.div`
      display: flex;
      color: #666;
    
      i {
        margin-right: 5px;
        color: #acabb0;
      }
    `;
    
    const AnotherUser = styled.div`
      display: flex;
      margin-top: 20px;
    `;
    
    const AnotherUserId = styled.div`
      display: flex;
      justify-content: center;
      flex-direction: column;
      width: 6%;
    
      i {
        margin-bottom: 5px;
        font-size: 30px;
        text-align: center;
        color: #b1b1b1;
      }
    
      p {
        font-size: 14px;
        color: #444;
        text-align: center;
      }
    `;
    
    const AnotherUserComment = styled.div`
      ${flexBetween};
      width: 95%;
      margin-left: 23px;
      padding: 25px;
      background: #f8f8fa;
    
      p {
        font-size: 15px;
      }
    
      span {
        font-size: 36px;
        color: ${props => props.theme.purple};
      }
    `;
    
    const AnotherUserLine = styled.span`
      width: 1px;
      height: 50px;
      border-left: 1px solid #d3d3d3;
    `;
    
    const AnotherUserWrite = styled.div`
      ${flexBetween};
      width: 80%;
    
      p {
        color: #666;
      }
    `;
    
    const AnotherUserMenu = styled.div`
      display: flex;
      align-items: center;
      color: #444;
    `;
    
    const AnotherUserLike = styled.div`
      display: flex;
      flex-direction: column;
      align-items: center;
      margin-right: 25px;
      color: #aeaeae;
    
      i {
        font-size: 18px;
        margin-bottom: 5px;
      }
      p {
        color: #666;
      }
    `;
    
    export default MoviesInfo;
    

    残念な点


    1つ目は、初めてと同じように、トレロを使います.うーん、なんといっても、時間が迫っているから、だんだんトレロの言い訳を利用できなくなってきたのではなく、弁解や機能実現に努力しているから...🙄
    第二に、残念なことに、作成したAPI、😥

    メリット


    やっぱり俺たちのメンバーだ!!坊ちゃんよかった.😍 お互い知らない人は手伝って!ヘルプ...チャンヨンとダンが一方的に助けてくれたけど.😅ほほほ)2週間の種目ではなく、1ヶ月だったら、最後まで助け合って和やかに終わる感じだったので、メンバーはみんな元気でした:)

    最後に。

  • 熱心な授業のYeon~旭!改めてありがとうございます.ほほほ(私は馬鹿のように名の授業が分からないのも残念な点と言える.😢)
  • 問題を解決する方法を教えてくれてありがとう.🥳
  • cssが好きではないと言って一緒に解決して教えてくれた勝賢は本当に感謝しています.😊
  • イライラをテーマにした100%笑顔の私たちチームメンバー本当にありがとうございました疲れているはずなので...どうもありがとう😭
  • 2つ目のプロジェクトでは、やったことのない機能を追加したのではないかと聞かれる方が多く、初めて使用したfunction componentとstyled-conntsで崩れてしまいましたが、やはり面白くてプロジェクトが終わったのが残念でした.これでいい人で構成されたプロジェクトをもう1つ作れるのでしょうか.不安感もありますが、いろいろな経験を通して、違う視野を持つことができるので、また勉強していくべきだと思います.私は自分がよくできると信じて、この时間も大変なことを言うと決心しました.😌