学校の時刻表を構築し、バッキングAPIとしてGoogleカレンダーAPIを使用します.


課題は、私たちが学校で使用し、バッキングAPIとしてGoogleカレンダーAPIを使用する伝統的な学校のカレンダーをデジタル化することです.私の理解では、これはレッスンをGoogleカレンダーから取得し、Webアプリケーションに表示されることを意味します.
このため、2つのアプローチを取ることにしました.
  • アプローチ1.ゼロから全体の時刻表の構造を構築し、データを取得し、それを表示するいくつかの関数を記述します.
  • アプローチ2.Googleカレンダーデータをその構造化されていない性質で処理することができ、イベント/レッスンを表示するプリビルドされたパッケージコンポーネントを見つけます.
  • アプローチ1

    ワークフロー。


    Use styled-components to build a reusable TableColumn component that will take in props and inside it, use those props to fetch data dynamically from a json file.
    
    Srcフォルダでは、データと呼ばれるフォルダーを作成しました.JSONとこれは私のデータが住んでいる場所です.
    TableColumnsコンポーネントの場合、これはビルドです.私は、私が望んだように小道具を渡すことができたので、私が多くのコードを書く必要がないことを意味した要素の上で支配を必要としたので、スタイルの部品を選びました.
    import React from "react";
    import styled from "styled-components";
    const data = require("../data/subjectData.json");
    
    const MainDiv = styled.div`
      height: 30em;
      width: 11.6em;
      border-right: 1px solid black;
      border-bottom: 1px solid black;
    `;
    
    const ItemDiv = styled.div`
      height: ${(props) => (props.subject ? "5em" : "2.5em")};
      width: ${(props) => (props.half ? "50%" : "100%")};
      display: flex;
      align-items: center;
      justify-content: center;
      border-bottom: 1px solid black;
    `;
    
    const ClassTitleDiv = styled.div`
      display: flex;
      flex-flow: row nowrap;
    `;
    
    const MainClassColumnDiv = styled.div`
      display: flex;
      flex-flow: row nowrap;
      height: 25em;
      width: 100%;
    `;
    
    const ClassColumnDiv = styled.div`
      height: 100%;
      width: 50%;
      background-color: ${(props) => (props.col ? "#f1f3f8" : "#d6e0f0")};
      display: flex;
      flex-flow: column nowrap;
      align-items: center;
      justify-content: center;
    `;
    
    function TableColumn({ title, lesson }) {
      return (
        <MainDiv>
          <ItemDiv>{title}</ItemDiv>
          <ClassTitleDiv>
            <ItemDiv half>3N</ItemDiv>
            <ItemDiv half>3S</ItemDiv>
          </ClassTitleDiv>
          <MainClassColumnDiv>
            <ClassColumnDiv col>
              {data.subject[lesson]["3N"].map((sub) => {
                return (
                  <ItemDiv half subject>
                    {sub.subject}
                  </ItemDiv>
                );
              })}
            </ClassColumnDiv>
            <ClassColumnDiv>
              {data.subject[lesson]["3S"].map((sub) => {
                return (
                  <ItemDiv half subject>
                    {sub.subject}
                  </ItemDiv>
                );
              })}
            </ClassColumnDiv>
          </MainClassColumnDiv>
        </MainDiv>
      );
    }
    
    export default TableColumn;
    
    このtablecolumnコンポーネントは、クラス3 nとクラス3 sの両方のレッスンをマップします.各コンポーネントは、両方のクラスの単一のレッスンを表します.
    私が完全な時刻表を描いていたメインページのために、私は外の時刻表構造(日)をセットしました、そして、私はtableolumnを子要素として通過しました.
    import React from "react";
    import styled from "styled-components";
    import TableColumn from "../components/TableColumn";
    
    const MainDiv = styled.div`
      height: 100vh;
      display: flex;
      flex-flow: column;
      align-items: center;
    `;
    
    const Title = styled.h3`
      font-size: 2em;
      font-weight: 800;
      margin-top: 0.2em;
    `;
    
    const MainTableDiv = styled.div`
      height: auto;
      width: auto;
      display: flex;
      flex-flow: row nowrap;
    `;
    
    const DayOfWeekDiv = styled.div`
      height: 25em;
      width: 8em;
      padding-top: 5em;
      border-right: 1px solid black;
      border-bottom: 1px solid black;
    `;
    
    const Day = styled.div`
      height: 5em;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-weight: 500;
    `;
    
    function HomePage() {
      const days = ["Mon", "Tue", "Wed", "Thur", "Fri"];
      return (
        <MainDiv>
          <Title>
            <u>School TimeTable</u>
          </Title>
          <MainTableDiv>
            <DayOfWeekDiv>
              {days.map((day) => {
                return <Day>{day}</Day>;
              })}
            </DayOfWeekDiv>
            <TableColumn title={"8am - 9am"} lesson={"lesson1"} />
            <TableColumn title={"10am - 11am"} lesson={"lesson2"} />
            <TableColumn title={"11:30am - 12:45pm"} lesson={"lesson3"} />
            <TableColumn title={"1:30pm - 2:30pm"} lesson={"lesson4"} />
            <TableColumn title={"3pm - 4pm"} lesson={"lesson5"} />
          </MainTableDiv>
        </MainDiv>
      );
    }
    
    export default HomePage;
    
    JSONローダを使用するには、いくつかのWebPackの設定を設定します

    テスト


    For the tests, I did not have much to test but I had to ensure that the TableColumn component's structure remains intact and so I set up snapshot test.
    
    import React from "react";
    import renderer from "react-test-renderer";
    import TableColumn from "./components/TableColumn";
    
    test("renders correctly the table columns", () => {
      const title = "Titles";
      const tree = renderer
        .create(<TableColumn title={title} lesson={"lesson5"} />)
        .toJSON();
      expect(tree).toMatchSnapshot();
    });
    
    

    シー・シーディー


    この部分は毎回私を興奮させる.このwebappのために、私は物事をシンプルにしたかったので、私は両方の連続的な統合と展開のための構造を非常にシンプルにしました.
    私は.Githubフォルダとその中で、2つのファイルを含むワークフローフォルダを追加しました.ciを処理して展開するyml.CDを扱うYML.
    インテグレート.気象研
    name: React Continuous Integration
    
    on:
      pull_request:
        branches: [master]
    
    jobs:
      test_pull_request:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v2
          - run: yarn install
          - run: yarn test -u
          - run: yarn test
          - run: yarn build
    
    
    プルリクエストが作成されると、これはテストを実行します.
    展開.気象研
    name: Firebase Continuous Deployment
    
    on:
      push:
        branches: [master]
    
    jobs:
        deploy:
          runs-on: ubuntu-latest
          steps:
            - uses: actions/checkout@master
            - run: yarn install
            - run: yarn build
            - uses: w9jds/firebase-action@master
              with:
                args: deploy --only hosting
              env:
                FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
    
    変更が検出されると、これはマスターにチェックアウトします.最適化されたビルドを作成するために必要なコマンドをすべて実行します.その後、すべてのfirebaseコマンドを処理するFireBaseアクションと呼ばれるGithubアクションアプリケーションを利用します.Webアプリケーションが正常にFireBase上でホストされます.
    このアプローチはGoogleカレンダーAPIを利用しませんでした.主な理由は、私はカレンダーデータを実際に私のコンポーネント構造内で適切に使用することができるデータに構造を構築するためにいくつかの時間がかかると認識したことでした.私は、私が私自身の完全なカスタムスケジューラを構築する方法を見つけ出す前に、それが働くプロトタイプをそこに持っている方がずっと意味があると思いました.
    それは、以下の結果です.
    結果

    View Live
    The Github Repository
    アプローチ2

    ワークフロー。


    このアプローチでは、既にビルド済みのスケジューラコンポーネントを探すことにしました.長い間、私はDevExtreme Schedulerを見つけました.
    それは私がデータをすべてのデータを意味して、そのデータをスケジューラ構成要素に渡した事前に構築されたデータストアに渡すことができました.
    今、私はちょうどGoogleカレンダーから私のイベントデータを取得しなければならなかった.このために、私はGCPプロジェクトと私のカレンダーIDからGoogleプロダクトキーを必要としました
    これは、1つのコンポーネントが全体のWebアプリケーションを実行するのに十分であることを意味します.
    import React, { Component } from "react";
    // prebuilt table component
    import Scheduler from "devextreme-react/scheduler";
    // data handler
    import CustomStore from "devextreme/data/custom_store";
    import "whatwg-fetch";
    
    // function to fetch the events from the calendar
    function getLessons(_, requestOptions) {
      const PUBLIC_KEY = process.env.REACT_APP_GOOGLE_PUBLIC_KEY,
        CALENDAR_ID = process.env.REACT_APP_CALENDAR_ID;
      const lessonsUrl = [
        "https://www.googleapis.com/calendar/v3/calendars/",
        CALENDAR_ID,
        "/events?key=",
        PUBLIC_KEY,
      ].join("");
    
      return fetch(lessonsUrl, requestOptions)
        .then((response) => response.json())
        .then((data) => data.items);
    }
    
    // data handler
    const dataSource = new CustomStore({
      load: (options) => getLessons(options, { showDeleted: false }),
    });
    
    // scheduler preferences
    const currentDate = new Date(2020, 8, 21);
    const views = ["day", "workWeek"];
    
    class App extends Component {
      render() {
        return (
          <>
            <div className="title">
              <h3>
                <u>3N TimeTable</u>
              </h3>
            </div>
            <Scheduler
              dataSource={dataSource}
              views={views}
              defaultCurrentView="workWeek"
              defaultCurrentDate={currentDate}
              height={500}
              startDayHour={7}
              endDayHour={16}
              editing={false}
              showAllDayPanel={false}
              startDateExpr="start.dateTime"
              endDateExpr="end.dateTime"
              textExpr="summary"
              timeZone="Africa/Nairobi"
            />
          </>
        );
      }
    }
    
    export default App;
    
    スケジューラコンポーネントでは、編集がfalseに設定されていることに注意してください.管理ページを持っている場合は、同じスケジューラ構造を使用し、その編集プロパティをtrueに設定して、Webアプリケーションを介してイベント編集を可能にします.
    テストのために、私はこのアプローチのために何も持ちませんでした.その結果、200の結果コードを得ることができます.
    このアプローチのために、私はRuseが存在しない場合に現れる404ページを加えました.

    グーグルカレンダー シー・シーディー


    私はテストがなかったので、CIを設定しなかった.
    CDについては、第1のアプローチと同じ簡単な構造にしました.しかし、これについては、いくつかの秘密キー(GoogleキーとカレンダーID)を渡す必要がありました.
    name: Firebase Continuous Deployment.
    
    on:
      push:
        branches: [master]
    
    jobs:
      deploy:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@master
          - run: yarn install
          - run: yarn build
            env:
              REACT_APP_GOOGLE_PUBLIC_KEY: ${{ secrets.REACT_APP_GOOGLE_PUBLIC_KEY }}
              REACT_APP_CALENDAR_ID: ${{ secrets.REACT_APP_CALENDAR_ID}}
          - uses: w9jds/firebase-action@master
            with:
              args: deploy --only hosting
            env:
              FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
    
    
    これらの秘密は、設定の秘密の下でgithubレポで追加され、新しい秘密を作成します.
    結果


    View Live
    それです.そういうわけで、私は挑戦について行きました.
    ムシャスグラシアス!