主なプロジェクト技術の回顧


サイトを選択する理由


私たちのグループがクローンしたサイトはここにあります!👉 国家政治.
まずはサイトがとても綺麗😊
フロントを勉強する考えがたくさんありました.デザイン感もこのように学びました!
▼▼▼▼機能多様🤠
日付、位置、検索、フィルタリング、予約など様々な情報を展示しているので、バックグラウンドで学ぶべきこともたくさんあると思います.ユーザーによって異なるサイトを実装する予定でしたが、時間(ゲスト/ホスト分離)がないため、この部分はスキップ!

使用するテクノロジー


FRONT END 🖼


HTML | CSS (Module CSS) | React JS

BACK END 📚


Node.js | Express | Prisma | MySQL | Postman

Database Diagram



私の役は?


フロントエンド|Detail


🖼 レイアウト


STAYPOLIOの詳細ページで修正したい部分があるので、実装は少し違います.
スライドの寮名とHeartがよく見えない
⚄▼スライドの下で繰り返される寮名
🙋‍♀️ 一体になって、デザインを変えたらどうですか?


客室写真が展示されているスライドで、写真は左に少し見えます.
🙋‍♀️ 全部隠してたらどうなるの?

📍 地図API


Kakao MapAPIを使用して画面に地図を印刷
▼▼地図上で私が望む位置までマーク!(リフォーム時)

🧐 FAQコンポーネント



⚇DBは情報を導入せず,コンテンツをハードコーディングしている.
⚄FAQ要素は、ボタン要素とコンテンツ要素の2つの要素から構成される.
⚄▼この2つの要素はそれぞれ接続されており、ボタンはステータス値で管理され、コンテンツ要素は配列の形で含まれており、ステータス値はインデックスの形でアクセスして表示されます.このため、ボタンを押すと、そのボタンに関連するコンテンツ素子が画面に出力される.
▼▼▼ボタンを押すと、このボタンだけがハイライトになります.この機能は、ステータス値として管理することもできます.クリックすると、ステータス値がボタンのインデックス値に設定されます.ステータス値とボタンのインデックス値が一致すると、有効なcssは、適用されるクラス名を追加することによって実現されます.

バックエンド|検索とフィルタリング


検索


旅行先/住所にキーワードを入力すると住所名/都市/地域のデータからキーワードを含むデータを取得できます

フィルタリング



🧐 寮の種類は全部で4つあり、複数選択できます.ユーザがいくつを選択するか分からないので,どのように動的に管理するかを考えた.
👉 WHERE INメソッドでは4種類から選択でき、選択した値は宿泊類別名として使用でき、選択していない値は空の文字列として使用できます.

const getSearchedDormitories = async (
  keyword,
  isAll,
  first,
  second,
  third,
  fourth
) => {
  keyword = "%" + keyword + "%";
  return await prisma.$queryRaw`
  SELECT * FROM
  (SELECT 
  d.id AS id,
  c.name AS category, 
  d.name AS name, 
  ci.name AS city, 
  dis.name district, 
(SELECT 
  JSON_ARRAYAGG(y.price)
  FROM dormitories x 
  JOIN rooms y ON y.dormitory_id = x.id
  WHERE x.id = d.id
  GROUP BY x.id) AS price,
(SELECT
  JSON_ARRAYAGG(y.head_count)
  FROM dormitories x
  JOIN rooms y ON y.dormitory_id = x.id
  WHERE x.id = d.id
  GROUP BY x.id) AS headCount,
(SELECT 
  JSON_ARRAYAGG(y.image_url)
  FROM dormitories x
  JOIN dormitories_images y ON y.dormitory_id = x.id
  WHERE d.id = x.id
  GROUP BY x.id) AS imageUrl
FROM dormitories d
JOIN categories c ON d.category_id = c.id
JOIN rooms r ON d.id = r.dormitory_id
JOIN cities ci ON d.city_id = ci.id
JOIN districts dis ON d.district_id = dis.id
WHERE d.name LIKE ${keyword} OR ci.name LIKE ${keyword} OR dis.name LIKE ${keyword}
GROUP BY d.id
ORDER BY d.id) AS myTable
${
  !isAll
    ? Prisma.sql`WHERE category in (${first}, ${second}, ${third}, ${fourth})`
    : Prisma.empty
};`;
};

コラボレーション方式


約束を守る


私たちのチームには大体2つのデートがあります.
必ず
  • 午前と夜の会議を守らなければなりません!
    午前中の会議では、昨日までの進捗状況と今日やるべきことを共有し、一日の作業コードを整理し、アップロードしたPRを審査し、統合しました.
  • 午前の会議で一度に滞在
    merge後、develop branchが更新された後、機能別にブランチを再作成し、再実行します.このように約束が衝突することもなくgitによってトラブルが発生することもないので,容易に連携が可能である.問題があったとしても、午前中に会議を開いて解決し、負担を軽減したので、Gitも怖くない.
  • すべてのアクションを記録


    チームプロジェクトでは、本当に良い部分は、すべての細部を動作に記録する習慣です.会議の記録からそれぞれのやるべきこと、パターン、APIフォーマット、発表準備まで、活動に記録して、お互いの状況や情報を共有して、会議の内容だけでなく、会議の中で過ぎたばかりの内容も記録できて、これからためらうことなく、よかったです.

    🥺 私のコードは絶対に忘れられない


    FAQコンポーネント


    FAQ Component
    // FAQ 컴포넌트 
    
    import React, { useState } from 'react';
    import style from './FAQ.module.css';
    import classNames from 'classnames/bind';
    import FAQButton from './faqButtons/FAQButton';
    import ETC from './faqContents/ETC';
    import InfoForUsing from './faqContents/InfoForUsing';
    import Capacity from './faqContents/Capacity';
    import InfoBooking from './faqContents/InfoBooking';
    import InfoAmenity from './faqContents/InfoAmenity';
    
    const FAQ = () => {
      const cx = classNames.bind(style);
      // //infoButton 값 관리
      const [clicked, setClicked] = useState(0);
    
      // //infoButton 관리하는 함수
      const click = num => {
        setClicked(num);
      };
      // components in array
      const [compArray, setCompArray] = useState([
        <Capacity key={0} index={clicked} name="인원 및 금액" />,
        <InfoBooking key={1} index={clicked} name="예약 및 결제" />,
        <InfoForUsing key={2} index={clicked} name="이용 안내" />,
        <InfoAmenity key={3} index={clicked} name="부대시설 안내" />,
        <ETC key={4} index={clicked} name="기타 안내" />,
      ]);
    
      return (
        <div className={cx('container')}>
          <div className={cx('buttons')}>
            <p className={cx('title')}>FAQ</p>
            <FAQButton
              click={click}
              name="인원 및 금액"
              clicked={clicked}
              index={0}
            />
            <FAQButton
              click={click}
              name="예약 및 결제"
              clicked={clicked}
              index={1}
            />
            <FAQButton click={click} name="이용 안내" clicked={clicked} index={2} />
            <FAQButton
              click={click}
              name="부대시설 안내"
              clicked={clicked}
              index={3}
            />
            <FAQButton click={click} name="기타 안내" clicked={clicked} index={4} />
          </div>
          <div className={cx('contents')}>
            <p>FAQ를 통하여 예약에 관련된 더 자세한 내용들을 찾아보세요.</p>
            {compArray[clicked]}
          </div>
        </div>
      );
    };
    
    export default FAQ;
    
    FAQButton Component
    // FAQButton 컴포넌트
    import React from 'react';
    import style from './FAQButton.module.css';
    import classNames from 'classnames/bind';
    
    const FAQButton = ({ name, clicked, click, index }) => {
      const cx = classNames.bind(style);
    
      const clickButton = () => {
        click(index);
      };
    
      return (
        <p
          className={cx('infoBtn', clicked === index ? 'infoActive' : '')}
          onClick={clickButton}
        >
          {name}
        </p>
      );
    };
    
    export default FAQButton;
    

    なぜ印象に残っているのでしょうか?🎤


    😎 初めていろいろ考えた覚えがある
    画面を切り替えずに構成部品を変更するだけで、CSS処理も必要です.
    2つの素子を接続するのは思ったほど簡単ではないからです.
    また、何を言ったらいいのか分かりませんが、最初はぼんやり見つめていました.
    どうやって実現するのか分からないので、最初からそういう論理を持って、同期たちと対面して考えるコードが印象的でした.
    そして不思議に3日間ハミングして、週末の夜1時間後に
    突然ロジックが実现したことを思い出して本当にドラマチックです...それは瞬間です.
    本当に刺激的な経験でした

    どのように悩み、実現したのか。🎤


    私は2つの提案を得た.
    ⚄▼配列で構成部品を管理する
    ⚇成分を使い分ける
    学生たちからこの二つのアドバイスをもらって、どうしたらいいか悩んでいます.
    「二つのことを一度にしなければならない」というプレッシャーは、どのように表現すればいいのか分からない.
    そして「一人ずつゆっくり!そこで,まずボタン素子を実現した.
    その後、ボタン素子が使用するstate値は、コンテンツ素子を実現することもできる.

    この過程で何を得ましたか。🎤


    🙋‍♀️ 反応が本当に面白かった!
    今回のプロジェクトを通して、stateとpropsの楽しみと効率を知りました.
    私はよく使うだけで、効率的にコードを書くことができます.
    アイデアがあり、素子を再利用するのも魅力的です.
    後で他のプロジェクトをするときに反応する魅力に陥りたい
    🙋‍♀️ シャベルで掘れ!聞き終わったら!何か作ろう!
    今回本当に感じたのは「何でも残りがある」という思いです.
    この機能を実装する前に、表面的には簡単に見えましたが、私にとってはかなり複雑でした.
    どうしたらいいか分からないので、茫然としています.
    あの頃グーグルゲームをしていたらどこにも見つからなかったもの
    その時知った知識は他の機能を実装する際に非常に有用である.
    他の同級生が止められたとき、私は手伝うことができます.
    そして人々はいろいろな考えを持っています.
    私とは違う目で問題に近づくことができます.
    だから私は思いがけない考えを出すことができます.
    これが導火線となり、問題は順調に解決した.
    私を一人でくよくよさせないで、私たちも他の人と問題を分かち合ってみましょう.
    最後に、まず試して、いろいろなエラーメッセージマップを見てみましょう.
    反応を実現するのに一番面白いのは私が試したものです
    目の前に見えるものが面白い.
    まるでゲームをしているかのようだ.
    私のコードにフィードバックしてくれたアシスタントと楽しい旅?^
    とにかく、何でもやってみるのではなく、私が身につけている知識を
    過去を指摘して、勝手にコードを打ってもいいですよ.

    useEffect

    
    const [detail, setDetail] = useState({
       id: 1,
       dormitoryName: '제주조랑말',
       comment: '감귤과수원의 풍경을 끌어들인 특별한 공간에서의 휴식',
       main_description:
         '제주조랑말은 감귤과수원 안에 있는 비정형적인 외관으로 프라이빗한 휴식 그리고 충실한 편안함과 동시에 특별한 제주에서의 휴식을 제공하고 싶습니다.',
       sub_description:
         '제주조랑말에서 아침에 눈을 뜨면 누운채로도 푸릇푸릇 반짝이는 귤밭을 시야에 채울 수 있으며 방문을 열면 귤 밭 사이사이에서 조잘거리는 새소리가 들립니다. 천연덕스럽게 야외복도를 넘어 자라고 있는 로즈마리의 향도 차분하게 온몸으로 스며듭니다. 느지막히 일어나서 바로 내린 커피향과 갓구운 빵냄새가 가득한 카페에서 감귤밭에 둘러쌓여 조식을 즐겨 보세요. 제주토끼는 앞만보고 달리기를 강요받는 도시사람들에게 잠시 달리기를 멈추고 몸과 마음이 쉴 수 있는 휴식을 선물하고 싶습니다.',
       city: '제주',
       district: '서귀포시',
       dormitoryImageUrl: [
         'https://images.unsplash.com/photo-1584132869994-873f9363a562?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80',
         'https://images.unsplash.com/photo-1551882547-ff40c63fe5fa?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80',
         'https://images.unsplash.com/photo-1498503182468-3b51cbb6cb24?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=2070&q=80',
       ],
       roomSpecialTitle: ['귤밭', '조식', '건축'],
       roomSpecialDes: [
         '제주조랑말은 귤밭에 둘러싸여 있어 4계절 내내 초록초록함을 느낄 수 있습니다. 특히 5월에는 숙소에 계시는동안 은은한 귤꽃향을 즐기실 수 있으며, 여름에는 풋귤을, 가을에는 주렁주렁 달려있는 감귤을, 겨울에는 밭에서 바로 딴 감귤을 맛보실 수 있습니다.',
         '제주조랑말은 화려하진 않지만 기본에 충실한 조식을 제공합니다. 로즈마리의 향과 귀를 간지럽히는 새소리를 들으며 카페에 오시면 귤밭에 둘러 쌓인 공간에서 신선한 제철 샐러드, 갓구운 빵, 직접 내리는 핸드드립 커피를 즐기실 수 있습니다.',
         '비정형적인 외관과 주변의 감귤과수원을 내부로 충분히 끌어들인 공간은 최-페레이라 건축의 설계로 탄생되었습니다. 레벨을 달리하여 더욱 프라이빗하게, 벽돌을 이용한 영롱쌓기로 제주의 바람과 빛을 더욱 변화무쌍하게 느끼실 수 있습니다.',
       ],
       recommendPlacesName: ['ICC제주국제컨벤션센터', '큰돈가', '중문색달해변'],
       recommendPlacesType: ['shop', 'food', 'nature'],
       recommendPlacesDes: [
         '국제회의전문시설이자 강연회·연회·이벤트·전시회·공연 등을 열 수 있는 복합공간',
         ' 직접 구워주는 제주 흑돼지 맛집',
         '서핑과 노을을 즐길 수 있는 해변',
       ],
     });
    
     useEffect(() => {
       fetch('http://localhost:8000/dormitories/2', {
         method: 'GET',
         headers: {
           'Content-Type': 'application/json',
         },
       })
         .then(res => res.json())
         .then(result => {
           setDetail(result.data[0]);
         });
     }, []);
    
    

    なぜ印象に残っているのでしょうか?🎤


    😎 フロントからバックエンドapiへの接続が完了し、データの受信が良好です.
    リフレッシュすると白い画面しか見えません.
    これはどういうことですか.😣
    午前6時からびくびくと悩んでいた.
    隊員の助けで解決した後、私は絶対に忘れられない.
    間もなく発表されるプレッシャーの下で、99%に達したが、1%未満の場合!
    そこから「反応ライフサイクル」の大切さを実感した.

    どのように悩み、実現したのか。🎤


    本当に不思議なことに、1つの異なるapiや情報しか持ってこないものは、再レンダリングしても良いので、あまりにも多くの情報を持ってきて、精錬せずに直接道具に移行して、レンダリングに問題があるかどうかを考えています.
    したがって、親コンポーネントからデータを選択してpropsに渡すか、いっそサブコンポーネントからもう一度ロードします(この方法はあまりにも非効率なので、すぐに心が落ち着きました!)
    様々なタックルが行われていましたが、最終的に他の選手が教えてくれたのは「初期値形態と導入したデータ形態」でした.
    2つのシェイプが同じ場合にのみ、再レンダリング時に遠慮なくインポートできます.
    私はそれさえ知らない.😞 私は厳しいところで問題を探している.
    しかし、だから私は絶対に忘れません.

    この過程で何を得ましたか。🎤


    ライフサイクルに反応する大切さを痛感!
    2番目のプロジェクトの前にライフサイクルを学習
    次のプロジェクトでは、レンダリングをよりよく処理してみましょう.😎