igara/syonet_seven

View on GitHub
nodejs/www/pages/tools/scraping.tsx

Summary

Maintainability
D
1 day
Test Coverage
import { WrapperComponent } from "@www/components/wrapper";
import toolsScrapingStyle from "@www/styles/tools/scraping.module.css";
import { authActions } from "@www/actions/common/auth";
import { CHECK_AUTH, CheckAuth } from "@www/libs/apollo/gql/auth";
import { AppState, wrapper } from "@www/stores";
import Head from "next/head";
import { useState, useEffect, ChangeEvent } from "react";
import { useDispatch, useSelector } from "react-redux";
import { db } from "@www/models/dexie/db";
import { TextComponent } from "@www/components/common/input/text";
import { TextAreaComponent } from "@www/components/common/input/textarea";
import { ButtonComponent } from "@www/components/common/input/button";
import { LinkComponent } from "@www/components/common/link";
import { useMutation, useLazyQuery } from "@apollo/react-hooks";
import {
  EXEC_SCRAPING,
  ExecScraping,
  SAVE_SCRAPING_HTML,
  SaveScrapingHTML,
} from "@www/libs/apollo/gql/google/scraping";
// import { createOGPImage } from "@www/libs/ogp_image";
import { requestWebpush } from "@www/libs/apollo/gql/webpush";

const ogp = {
  title: "Web魚拓っぽい",
  path: "ogp/tools/scraping",
};

const ToolsScrapingPageComponent = () => {
  const state = useSelector((state: AppState) => state);
  const dispatch = useDispatch();

  const [url, setURL] = useState("");
  const changeURL = (event: ChangeEvent<HTMLInputElement>) => setURL(event.target.value);
  const [html, setHTML] = useState("");
  const [title, setTitle] = useState("");
  const [fileID, setFileID] = useState("");
  const [directoryID, setDirectoryID] = useState("");

  const [loadExecScraping, resultExecScraping] = useLazyQuery<ExecScraping>(EXEC_SCRAPING, {
    onCompleted: async data => {
      setHTML(data.execScraping.html);

      const t = data.execScraping.html.match(/<title>.*<\/title>/);
      if (t) setTitle(t[0].replace("<title>", "").replace("</title>", ""));
    },
  });

  const [loadSaveScrapingHTML, resultSaveScrapingHTML] = useMutation<SaveScrapingHTML>(SAVE_SCRAPING_HTML, {
    onCompleted: async data => {
      setFileID(data.saveScrapingHTML.fileID);
      setDirectoryID(data.saveScrapingHTML.directoryID);
    },
  });

  const [loadCheckAuth] = useLazyQuery<CheckAuth>(CHECK_AUTH, {
    onCompleted: async checkAuth => {
      if (!checkAuth.checkAuth) {
        await db.access_tokens.clear();
      } else {
        await dispatch(authActions.checkAuth(checkAuth.checkAuth));
      }
    },
  });

  useEffect(() => {
    if (process.browser) {
      (async () => {
        await requestWebpush();
        await loadCheckAuth();
      })();
    }
  }, []);

  const description = "指定したサイトのURLからCSS、JavaScript、画像含めてひとつのHTMLに生成します";

  return (
    <>
      <Head>
        <title>{ogp.title}</title>
        <meta content={description} name="description"></meta>
        <meta property="og:title" content={ogp.title} />
        <meta property="og:type" content="website" />
        <meta property="og:image" content={`${process.env.WWW_HOST}/${ogp.path}/${ogp.title}.png`} />
        <meta property="og:description" content={description} />
        <meta name="twitter:card" content="summary_large_image" />
      </Head>
      <WrapperComponent>
        <div className={toolsScrapingStyle.wrapper}>
          <h2>{ogp.title}</h2>
          <div>{description}</div>
          <hr />

          <table>
            <tbody>
              <tr>
                <td>
                  <TextComponent DefalutValue="" Placeholder="URL" OnChangeHandler={changeURL} />
                </td>
                <td className={toolsScrapingStyle.validation}>
                  {/^(https|http):\/\/\S*/.test(url) ? "" : "正しいURLを入力してください"}
                </td>
              </tr>
            </tbody>
          </table>
          <ButtonComponent
            OnClickHandler={() => {
              setHTML("");
              setTitle("");
              loadExecScraping({
                variables: {
                  url,
                },
              });
            }}
            Abled={!Boolean(url)}
          >
            生成
          </ButtonComponent>
          <br />
          <TextAreaComponent
            DefalutValue={html}
            Placeholder="HTML"
            ClassName={toolsScrapingStyle.htmlText}
            ReadOnly={true}
          />
          <div>
            タイトル: {title} {resultExecScraping.loading && "読み込み中..."}
          </div>

          <ButtonComponent
            OnClickHandler={() => {
              const blob = new Blob([html], { type: "text/plan" });
              const link = document.createElement("a");
              link.href = URL.createObjectURL(blob);
              link.download = "preview.html";
              link.click();
            }}
            Abled={!Boolean(html)}
          >
            プレビュー
          </ButtonComponent>

          <hr />
          <h3>ログイン中ユーザ</h3>
          <table>
            <tbody>
              <tr>
                <td>{(state.auth.username && state.auth.type === "AuthGoogle") || "???"}</td>
                <td className={toolsScrapingStyle.validation}>
                  {state.auth.username && state.auth.type === "AuthGoogle" ? (
                    state.auth.username
                  ) : (
                    <LinkComponent href="/login">Googleログインしていません。</LinkComponent>
                  )}
                </td>
              </tr>
              <tr>
                <td>
                  <ButtonComponent
                    OnClickHandler={() => {
                      setFileID("");
                      setDirectoryID("");
                      loadSaveScrapingHTML({
                        variables: {
                          html,
                          title,
                          url,
                        },
                      });
                    }}
                    Abled={!Boolean(html && state.auth.username && state.auth.type === "AuthGoogle")}
                  >
                    保存
                  </ButtonComponent>
                </td>
              </tr>
              <tr>
                <td>FileID: </td>
                <td>
                  {fileID && (
                    <a
                      href={`https://drive.google.com/file/d/${fileID}/view`}
                      target="_blank"
                      rel="noopener noreferrer"
                    >
                      {fileID}
                    </a>
                  )}
                  {resultSaveScrapingHTML.loading && "読み込み中..."}
                </td>
              </tr>
              <tr>
                <td>DirectoryID: </td>
                <td>
                  {directoryID && (
                    <a
                      href={`https://drive.google.com/drive/folders/${directoryID}`}
                      target="_blank"
                      rel="noopener noreferrer"
                    >
                      {directoryID}
                    </a>
                  )}
                  {resultSaveScrapingHTML.loading && "読み込み中..."}
                </td>
              </tr>
            </tbody>
          </table>
        </div>
      </WrapperComponent>
    </>
  );
};

export default ToolsScrapingPageComponent;

export const getServerSideProps = wrapper.getServerSideProps(async () => {
  // await createOGPImage({
  //   path: ogp.path,
  //   title: ogp.title,
  // });

  return {
    props: {},
  };
});