Board logo

標題: [教學] 用 ChromeOS/Linux 開發 Google Apps Script WebApp 不用起 server 續篇 [打印本頁]

作者: javacomhk    時間: 2022-5-16 19:53     標題: 用 ChromeOS/Linux 開發 Google Apps Script WebApp 不用起 server 續篇

本帖最後由 javacomhk 於 2022-5-19 17:48 編輯

請首先參考這篇怎樣設定 React.js + Bootstrap 開發 Cloud 嘅 WebApp 教學,而現在呢一續篇是延續上一篇去講解 Google Apps Script WebApp 最精彩及重要的 backend 功能,就係可儲存及讀取在 Google Spreadsheet 嘅 data。與及在儲存 Spreadsheet data 後立即用 Gmail 服務去觸發 sendMail 功能。

(D) 第四部份,使用 React.js + Bootstrap 增加 Input Form 及 Validation Rules 另外修改網頁去顯示 Google Spreadsheet data。

(D1) 修改以下文件 ~/webappreact/src/App.js 內容為
  1. import { Routes, Route } from "react-router-dom"
  2. import Home from "./components/Home"
  3. import About from "./components/About"
  4. import Data from "./components/Data"
  5. import FormInput from "./components/FormInput"
  6. import Nav from "./components/Nav"

  7. function App() {
  8.   return <>
  9.       <Nav />
  10.       <Routes>
  11.         <Route path="/" element={<Home />} />
  12.         <Route path="/about" element={<About />} />
  13.         <Route path="/data" element={<Data />} />
  14.         <Route path="/form" element={<FormInput />} />
  15.         <Route path="*" element={<Home />} />
  16.       </Routes>
  17.     </>
  18. }
  19. export default App
複製代碼
(D2) 修改以下文件 ~/webappreact/src/components/Nav.js 內容為
  1. import { Link } from "react-router-dom"

  2. function Nav() {
  3.   return <>
  4.         <span className="css-nav"><Link to="/">Home</Link></span>
  5.         <span className="css-nav"><Link to="about">About</Link></span>
  6.         <span className="css-nav"><Link to="data">Data</Link></span>
  7.         <span className="css-nav"><Link to="form">Form</Link></span>
  8.   </>
  9. }

  10. export default Nav
複製代碼
(D3) 修改以下文件 ~/webappreact/src/components/Data.js 內容為
  1. import React, {useState, useEffect} from "react"
  2. import {Container, Table} from "react-bootstrap";

  3. function Data() {
  4.   const [jsonResults,setJsonResults] = useState(null)
  5.   const [data,setData] = useState(null)
  6.   const [loading, setLoading] = useState(false)
  7.   if (typeof google === 'object') {
  8.     useEffect(()=>{
  9.       setLoading(true)
  10.       google.script.run.withSuccessHandler(response => {
  11.         console.log(response)
  12.         const [...values] = JSON.parse(response);
  13.         const keys = ["firstname","lastname","country","email","date"];
  14.         const objects = values.map(array => array.reduce((a, v, i) => ({...a, [keys[i]]: v}), {}));
  15.         console.log(objects);
  16.         setData([...objects])
  17.         setLoading(false);
  18.       }).withFailureHandler(er => {
  19.         alert(er)
  20.       }).getSpreadData();
  21.     },[])
  22.   }
  23.   else {
  24.     return <>
  25.       <Container>
  26.       <div style={{"height": "30px"}}/>
  27.       <h1 className="h1">Test getData from localhost</h1>
  28.       <Table striped bordered hover>
  29.         <thead>
  30.           <tr>
  31.             <th>#</th>
  32.             <th>First Name</th>
  33.             <th>Last Name</th>
  34.             <th>Creation Date</th>
  35.           </tr>
  36.         </thead>
  37.         <tbody>
  38.           <tr>
  39.             <td>1</td>
  40.             <td>FirstName 1</td>
  41.             <td>LastName 1</td>
  42.             <td>20220516</td>
  43.           </tr>
  44.           <tr>
  45.             <td>2</td>
  46.             <td>FirstName 2</td>
  47.             <td>LastName 2</td>
  48.             <td>20220517</td>
  49.           </tr>
  50.         </tbody>
  51.       </Table>
  52.       </Container>
  53.     </>
  54.   }
  55.   if (loading) return <h1>loading...</h1>
  56.   if (!data) return null;
  57.   console.log(JSON.stringify(data))
  58.   return <>
  59.     <Container>
  60.     <div style={{"height": "30px"}}/>
  61.     <h1 className="h1">getData from Google SpreadSheet</h1>
  62.     <Table striped bordered hover>
  63.       <thead>
  64.         <tr>
  65.           <th>#</th>
  66.           <th>First Name</th>
  67.           <th>Last Name</th>
  68.           <th>Creation Date</th>
  69.         </tr>
  70.       </thead>
  71.       <tbody>
  72.         { data.map((row, index) => (
  73.           <tr key={index}>
  74.             <td>{index}</td>
  75.             <td>{row.firstname}</td>
  76.             <td>{row.lastname}</td>
  77.             <td>{row.date}</td>
  78.           </tr>
  79.           ))
  80.         }
  81.       </tbody>
  82.     </Table>
  83.     </Container>
  84.   </>
  85. }

  86. export default Data
複製代碼
(D4) 修改以下文件 ~/webappreact/src/apps-script/main.js 內容為
  1. function doGet() {
  2.   return HtmlService.createTemplateFromFile("index")
  3.   .evaluate()
  4.   .addMetaTag("viewport","width=device-width, initial-scale=1.0")
  5. }

  6. function getData() {
  7.   console.log("getData()")
  8.   return (
  9.     [{
  10.       "key": "apple",
  11.       "value": "green"
  12.      },
  13.      {   
  14.      "key": "banana",
  15.      "value": "yellow"
  16.      }]
  17.   );
  18. }

  19. function getSpreadData() {
  20.   const data = SpreadsheetApp
  21.       .getActiveSpreadsheet()
  22.       .getActiveSheet()
  23.       .getDataRange()
  24.       .getValues();
  25.   console.log("getSpreadData() "+ JSON.stringify(data))

  26.   return JSON.stringify(data)
  27. }

  28. function AddRecord(firstname, lastname, country, email) {
  29.   console.log("AddRecord() "+ email)
  30.   var webAppSheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  31.   const datestr = (new Date().toLocaleString('sv',{timeZone: 'Asia/Hong_Kong'})).slice(0, 19).replace(/-/g, "").replace(/:/g, "").replace("T", " ");
  32.   webAppSheet.appendRow([firstname, lastname, country, email, datestr]);
  33.   // sendEmailfromdoc(firstname, lastname, email);
  34. }

  35. function sendEmailfromdoc(firstname, lastname, email){
  36.   // fill in google doc ID here
  37.   var id = 'FILL-IN-GOOGLE-DOC-ID-HERE' ;
  38.   var forDriveScope = DriveApp.getStorageUsed(); //needed to get Drive Scope requested
  39.   var url = "https://docs.google.com/feeds/download/documents/export/Export?id="+id+"&exportFormat=html";
  40.   var param = {
  41.     method      : "get",
  42.     headers     : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
  43.     muteHttpExceptions:true,
  44.   };
  45.   var html = UrlFetchApp.fetch(url,param).getContentText();
  46. // email send out with replaced fields
  47.   var htmlout1 = html.replace("{{title_1}}","Welcome to join our Newsletter subscription");
  48.   htmlout1 = htmlout1.replace("{{heading_1}}","Dear "+ firstname +" "+lastname);
  49.   htmlout1 = htmlout1.replace("{{heading_2}}","You have subscribed our Newsletter successfully.");
  50. //  Logger.log(htmlout1);
  51.   MailApp.sendEmail({
  52.     to: email,
  53.     subject: "Newsletter Registration",
  54.     htmlBody: htmlout1
  55.     });
  56.   console.log('email sent to '+ email + ' !!')
  57. }
複製代碼
(D5) 新增以下文件 ~/webappreact/src/components/FormInput.js 內容為
  1. 上傳在 … https://pastebin.com/nFWTgrdz
複製代碼
(D6)新增及修改完 Code 後可根據上一篇的(B8)的方法執行 npm run build 及 npm run start 後在 localhost 測試

(D7) 新增及修改完 Code 後可根據上一篇的(B9) 的方法執行 npm run build 及 npm run gpush 後預備在 Google WebApp 測試,接著便可用 Browser 打入Test Development 的Web URL 去測試 Input Form,今次主要測試Form 內的 Registration Form Input,成功後如下截圖。
[attach]2320492[/attach][attach]2320493[/attach]



(E) 第五部份,製作 email template 及修改 Google Apps Script Code 去測試 Gmail 服務

(E1) 用 Chrome Browser在 drive.google.com 新增一個 Google doc 作為 email template ,內容如下圖,具備有 {{title_1}}  {{heading_1}}   {{heading_2}}  等字串及或附加任何圖片或文字格式。


(E2) 在 Browser 網址欄中取得當時這個 Google doc 的 ID 字串(如下圖)。

(E3) 將這個 ID 貼在 ~/webappreact/src/apps-script/main.js 檔的相應位置(如下圖)及同時 uncomment (即去除最開頭嘅 // 字符) 這句 sendEmailfromdoc 代碼讓 input form save data 後隨即執行 sendMail 功能。

[attach]2320497[/attach]

[attach]2320496[/attach]


(E4) 修改完 Code 後可根據上一篇的(B9) 方法執行 npm run build 及 npm run gpush 後預備在 Google WebApp 測試。

(E5) Browser 在 drive.google.com 打開 React Test Project ,進入 Apps Script Editor 透過執行任何 function 例如 getData() ,便會激發要求去授權取得 Authorisation token 讀取 Google doc 及可以去 send mail 。

(E6) 接著便可使用 Test Development 的 Web URL 去測試 Input Form 內輸入你自己的電郵地址去登記,看看是否可以收到郵件如下截圖。
[attach]2320491[/attach]
作者: javacomhk    時間: 2022-5-16 20:22

本帖最後由 javacomhk 於 2022-5-19 17:35 編輯

留位
作者: javacomhk    時間: 2022-5-17 03:07

本帖最後由 javacomhk 於 2022-5-19 17:36 編輯

留位





歡迎光臨 電腦領域 HKEPC Hardware (https://www.hkepc.com/forum/) Powered by Discuz! 7.2