From d78c9d3b214a517a723aa4b9020683cb582f7e26 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Sun, 29 Jul 2018 11:06:30 +0900 Subject: [PATCH 01/64] add mobx --- frontend/package.json | 2 ++ frontend/yarn.lock | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/frontend/package.json b/frontend/package.json index 1d48be445..868e9fb02 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -28,6 +28,8 @@ "@types/react-slick": "^0.23.1", "babel-polyfill": "^6.26.0", "file-loader": "^1.1.11", + "mobx": "^5.0.3", + "mobx-react": "^5.2.3", "normalize.css": "^8.0.0", "react": "^16.4.0", "react-dom": "^16.4.0", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index d4618f7c3..1ffbc8514 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -3392,6 +3392,17 @@ mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: dependencies: minimist "0.0.8" +mobx-react@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-5.2.3.tgz#cdf6141c2fe63377c5813cbd254e8ce0d4676631" + dependencies: + hoist-non-react-statics "^2.5.0" + react-lifecycles-compat "^3.0.2" + +mobx@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-5.0.3.tgz#53b97f2a0f9b0dd7774c96249f81bf2d513d8e1c" + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -4281,6 +4292,10 @@ react-is@^16.3.1: version "16.4.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.4.0.tgz#cc9fdc855ac34d2e7d9d2eb7059bbc240d35ffcf" +react-lifecycles-compat@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + react-router-dom@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6" From bbb84c69c6de4eb9564b86e04bf746b28559b4a6 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Sun, 29 Jul 2018 15:56:35 +0900 Subject: [PATCH 02/64] Add RestClient --- frontend/package.json | 1 + frontend/src/api/RestClient.ts | 83 ++++++++++++++++++++++++++++++++++ frontend/yarn.lock | 13 ++++++ 3 files changed, 97 insertions(+) create mode 100644 frontend/src/api/RestClient.ts diff --git a/frontend/package.json b/frontend/package.json index 868e9fb02..1c64ce80b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -26,6 +26,7 @@ "@types/react-dom": "^16.0.5", "@types/react-router-dom": "^4.2.7", "@types/react-slick": "^0.23.1", + "axios": "^0.18.0", "babel-polyfill": "^6.26.0", "file-loader": "^1.1.11", "mobx": "^5.0.3", diff --git a/frontend/src/api/RestClient.ts b/frontend/src/api/RestClient.ts new file mode 100644 index 000000000..135cd9b3d --- /dev/null +++ b/frontend/src/api/RestClient.ts @@ -0,0 +1,83 @@ +export default class RestClient { + axios: any; + + constructor(baseUrl: string) { + const axiosBase = require("axios"); + const csrfToken = (document.querySelector("meta[name=csrf-token]")).content; + + this.axios = axiosBase.create({ + baseURL: baseUrl, + timeout: 1000, + headers: { + "Content-Type": "application/json", + "X-CSRF-TOKEN": csrfToken, + }, + }); + } + + get( + path: string, + params: object, + successed: (res: object) => void, + errored: (res: object) => void, + always = () => {} + ) { + return this.axios + .get(path, { params: params }) + .then((result: object) => { + console.log(`GET ${this.axios.baseURL}/${path}`); + console.log(`result: ${result}`); + successed(result); + }) + .catch((error: object) => { + console.log(`ERROR! GET ${this.axios.baseURL}/${path}`); + console.log(`error: ${error}`); + errored(error); + }) + .then(always()); + } + + post( + path: string, + params: object, + successed: (res: object) => void, + errored: (res: object) => void, + always = () => {} + ) { + return this.axios + .post(path, params) + .then((result: object) => { + console.log(`POST ${this.axios.baseURL}/${path}`); + console.log(`result: ${result}`); + successed(result); + }) + .catch((error: object) => { + console.log(`ERROR! POST ${this.axios.baseURL}/${path}`); + console.log(`error: ${error}`); + errored(error); + }) + .then(always()); + } + + delete( + path: string, + params: object, + successed: (res: object) => void, + errored: (res: object) => void, + always = () => {} + ) { + return this.axios + .delete(path, { data: { params } }) + .then((result: object) => { + console.log(`DELETE ${this.axios.baseURL}/${path}`); + console.log(`result: ${result}`); + successed(result); + }) + .catch((error: object) => { + console.log(`ERROR! DELETE ${this.axios.baseURL}/${path}`); + console.log(`error: ${error}`); + errored(error); + }) + .then(always()); + } +} diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 1ffbc8514..1676f3d3d 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -397,6 +397,13 @@ awesome-typescript-loader@^5.0.0: mkdirp "^0.5.1" source-map-support "^0.5.3" +axios@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102" + dependencies: + follow-redirects "^1.3.0" + is-buffer "^1.1.5" + babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -2200,6 +2207,12 @@ flush-write-stream@^1.0.0: inherits "^2.0.1" readable-stream "^2.0.4" +follow-redirects@^1.3.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291" + dependencies: + debug "^3.1.0" + for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" From 35319fd622f108eece12c566676f84cf454e14ed Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Mon, 6 Aug 2018 11:03:24 +0900 Subject: [PATCH 03/64] =?UTF-8?q?=E8=AB=B8=E3=80=85=E5=AE=9F=E8=A3=85?= =?UTF-8?q?=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controllers/api/v1/contacts_controller.rb | 11 +- frontend/src/api/ContactApi.ts | 13 ++ frontend/src/api/RestClient.ts | 4 +- frontend/src/entries/Contact.tsx | 207 ++++++++++++++---- frontend/src/index.tsx | 10 +- frontend/src/layouts/Main.tsx | 2 +- frontend/src/stores/ContactStore.ts | 14 ++ frontend/src/stores/RootStore.ts | 14 ++ frontend/tsconfig.json | 1 + 9 files changed, 218 insertions(+), 58 deletions(-) create mode 100644 frontend/src/api/ContactApi.ts create mode 100644 frontend/src/stores/ContactStore.ts create mode 100644 frontend/src/stores/RootStore.ts diff --git a/app/controllers/api/v1/contacts_controller.rb b/app/controllers/api/v1/contacts_controller.rb index 9b6050af6..312c642b3 100644 --- a/app/controllers/api/v1/contacts_controller.rb +++ b/app/controllers/api/v1/contacts_controller.rb @@ -8,20 +8,15 @@ def enum end def create - @contact = Contact.new(contact_params) - - if @contact.save - head :created - else - render :new - end + Contact.create!(contact_params) + head :created end private # Never trust parameters from the scary internet, only allow the white list through. def contact_params - params.require(:contact).permit( + params.permit( :corner, :message, :nickname, diff --git a/frontend/src/api/ContactApi.ts b/frontend/src/api/ContactApi.ts new file mode 100644 index 000000000..0105fb520 --- /dev/null +++ b/frontend/src/api/ContactApi.ts @@ -0,0 +1,13 @@ +import RestClient from "./RestClient"; + +export default class ContactApi { + restClient: RestClient; + + constructor(restClient: RestClient) { + this.restClient = restClient; + } + + saveContact(json: object, succussed: (res: object) => void, errored: (err: object) => void, always = () => {}) { + return this.restClient.post("/api/v1/contacts", json, succussed, errored, always); + } +} diff --git a/frontend/src/api/RestClient.ts b/frontend/src/api/RestClient.ts index 135cd9b3d..d9a75a112 100644 --- a/frontend/src/api/RestClient.ts +++ b/frontend/src/api/RestClient.ts @@ -1,12 +1,12 @@ export default class RestClient { axios: any; - constructor(baseUrl: string) { + constructor() { const axiosBase = require("axios"); const csrfToken = (document.querySelector("meta[name=csrf-token]")).content; this.axios = axiosBase.create({ - baseURL: baseUrl, + baseURL: "http://localhost:3000", // TODO(euglena1215): productionとの切り替え方法を考える timeout: 1000, headers: { "Content-Type": "application/json", diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index 6ac1ea85b..a416cd4f4 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -1,6 +1,9 @@ import * as React from "react"; import styled from "styled-components"; +import RestClient from "./../api/RestClient"; +import ContactApi from "./../api/ContactApi"; + import { media } from "./../commons/style"; import { ChkButtonBase } from "./../commons/ChkButtonBase"; import { chkColors } from "./../commons/color"; @@ -8,46 +11,166 @@ import { chkColors } from "./../commons/color"; import { HeroArea } from "./../components/HeroArea"; import { ContactHeroContent } from "./../components/ContactHeroContent"; -export const Contact = () => ( -
- } /> - - - お問い合わせフォーム -
- - - - - - - - - - - - - - - - - - - - 送信 -
-
-
-
-); +type Prop = {}; +type State = { + name: string; + corner: number; + department: number; + grade: number; + email: string; + nickname: string; + content: string; + readable: boolean; +}; + +export default class Contact extends React.Component { + constructor(props: Prop) { + super(props); + this.state = { + name: "", + corner: 0, + department: 0, + grade: 0, + email: "", + nickname: "", + content: "", + readable: false, + }; + + this.createContact = this.createContact.bind(this); + this.onChangeName = this.onChangeName.bind(this); + this.onChangeCorner = this.onChangeCorner.bind(this); + this.onChangeDepartment = this.onChangeDepartment.bind(this); + this.onChangeGrade = this.onChangeGrade.bind(this); + this.onChangeEmail = this.onChangeEmail.bind(this); + this.onChangeNickname = this.onChangeNickname.bind(this); + this.onChangeContent = this.onChangeContent.bind(this); + } + + render() { + return ( +
+ } /> + + + お問い合わせフォーム +
+ + + + + + + + + + + + + + + + + + + + 送信 +
+
+
+
+ ); + } + + createContact(e: any) { + e.preventDefault(); + + const contactApi = new ContactApi(new RestClient()); + + contactApi.saveContact( + { + corner: this.state.corner, + message: this.state.content, + nickname: this.state.nickname, + name: this.state.name, + department: this.state.department, + grade: this.state.grade, + readable: this.state.readable, + }, + (res: object) => console.log(res), + (err: object) => console.log(err) + ); + } + + onChangeName(e: any) { + this.setState({ name: e.target.value }); + } + + onChangeCorner(e: any) { + this.setState({ corner: e.target.value }); + } + + onChangeDepartment(e: any) { + this.setState({ department: e.target.value }); + } + + onChangeGrade(e: any) { + this.setState({ grade: e.target.value }); + } + + onChangeEmail(e: any) { + this.setState({ email: e.target.value }); + } + + onChangeNickname(e: any) { + this.setState({ nickname: e.target.value }); + } + + onChangeContent(e: any) { + this.setState({ content: e.target.value }); + } +} const ContactFormWrapper = styled.div` width: 100%; @@ -98,10 +221,6 @@ const ContactFormInput = styled.input` } `; -const ContactFormInputHalf = ContactFormInput.extend` - width: 50%; -`; - const ContactFormButton = ChkButtonBase.extend` background-color: ${chkColors.orange}; width: 30%; diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 9590182b1..8111bba1d 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -4,12 +4,16 @@ require("./commons/font"); import * as React from "react"; import * as ReactDOM from "react-dom"; import { BrowserRouter } from "react-router-dom"; +import { Provider } from "mobx-react"; import { App } from "./App"; +import RootStore from "./stores/RootStore"; ReactDOM.render( - - - , + + + + + , document.getElementById("app") ); diff --git a/frontend/src/layouts/Main.tsx b/frontend/src/layouts/Main.tsx index 388a22d3e..1b6fc4d05 100644 --- a/frontend/src/layouts/Main.tsx +++ b/frontend/src/layouts/Main.tsx @@ -3,7 +3,7 @@ import { Switch, Route } from "react-router-dom"; import { Index } from "./../entries/Index"; import { RadioHistory } from "./../entries/RadioHistory"; -import { Contact } from "./../entries/Contact"; +import Contact from "./../entries/Contact"; export const Main = () => (
diff --git a/frontend/src/stores/ContactStore.ts b/frontend/src/stores/ContactStore.ts new file mode 100644 index 000000000..7abe81325 --- /dev/null +++ b/frontend/src/stores/ContactStore.ts @@ -0,0 +1,14 @@ +import ContactApi from "../api/ContactApi"; +import Contact from "../models/Contact"; + +export default class ContactStore { + transportLayer: ContactApi; + + constructor(transportLayer: ContactApi) { + this.transportLayer = transportLayer; + } + + createContact(json: object) { + return new Contact(this, json); + } +} diff --git a/frontend/src/stores/RootStore.ts b/frontend/src/stores/RootStore.ts new file mode 100644 index 000000000..934a4e796 --- /dev/null +++ b/frontend/src/stores/RootStore.ts @@ -0,0 +1,14 @@ +import ContactStore from "./ContactStore"; +import ContactApi from "../api/ContactApi"; +import RestClient from "../api/RestClient"; + +export default class RootStore { + contactStore: ContactStore; + + constructor() { + const restClient = new RestClient(); + + const contactApi = new ContactApi(restClient); + this.contactStore = new ContactStore(contactApi); + } +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 49c9ac807..0e143098b 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -12,6 +12,7 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "forceConsistentCasingInFileNames": true, + "experimentalDecorators": true, "newLine": "LF" }, "include": ["src/**/*"], From 23a7e1ef434bf68035cd3c556377e3bda854d2f6 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Tue, 14 Aug 2018 11:07:57 +0900 Subject: [PATCH 04/64] =?UTF-8?q?store=E3=82=92=E7=B5=8C=E7=94=B1=E3=81=97?= =?UTF-8?q?=E3=81=A6POST=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= =?UTF-8?q?=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/entries/Contact.tsx | 55 ++++++++++++----------------- frontend/src/models/ContactModel.ts | 55 +++++++++++++++++++++++++++++ frontend/src/stores/ContactStore.ts | 4 +-- 3 files changed, 80 insertions(+), 34 deletions(-) create mode 100644 frontend/src/models/ContactModel.ts diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index a416cd4f4..d119415bc 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -1,17 +1,18 @@ import * as React from "react"; import styled from "styled-components"; -import RestClient from "./../api/RestClient"; -import ContactApi from "./../api/ContactApi"; +import { media } from "../commons/style"; +import { ChkButtonBase } from "../commons/ChkButtonBase"; +import { chkColors } from "../commons/color"; -import { media } from "./../commons/style"; -import { ChkButtonBase } from "./../commons/ChkButtonBase"; -import { chkColors } from "./../commons/color"; +import { HeroArea } from "../components/HeroArea"; +import { ContactHeroContent } from "../components/ContactHeroContent"; +import { inject } from "../../node_modules/mobx-react"; +import RootStore from "../stores/RootStore"; -import { HeroArea } from "./../components/HeroArea"; -import { ContactHeroContent } from "./../components/ContactHeroContent"; - -type Prop = {}; +type Prop = { + rootStore?: RootStore; +}; type State = { name: string; corner: number; @@ -19,10 +20,11 @@ type State = { grade: number; email: string; nickname: string; - content: string; + message: string; readable: boolean; }; +@inject("rootStore") export default class Contact extends React.Component { constructor(props: Prop) { super(props); @@ -33,7 +35,7 @@ export default class Contact extends React.Component { grade: 0, email: "", nickname: "", - content: "", + message: "", readable: false, }; @@ -44,7 +46,7 @@ export default class Contact extends React.Component { this.onChangeGrade = this.onChangeGrade.bind(this); this.onChangeEmail = this.onChangeEmail.bind(this); this.onChangeNickname = this.onChangeNickname.bind(this); - this.onChangeContent = this.onChangeContent.bind(this); + this.onChangeMessage = this.onChangeMessage.bind(this); } render() { @@ -108,11 +110,11 @@ export default class Contact extends React.Component { 送信 @@ -126,21 +128,10 @@ export default class Contact extends React.Component { createContact(e: any) { e.preventDefault(); - const contactApi = new ContactApi(new RestClient()); - - contactApi.saveContact( - { - corner: this.state.corner, - message: this.state.content, - nickname: this.state.nickname, - name: this.state.name, - department: this.state.department, - grade: this.state.grade, - readable: this.state.readable, - }, - (res: object) => console.log(res), - (err: object) => console.log(err) - ); + const root = this.props.rootStore!; + const contact = root.contactStore.createContact(this.state); + + contact.save(); } onChangeName(e: any) { @@ -167,8 +158,8 @@ export default class Contact extends React.Component { this.setState({ nickname: e.target.value }); } - onChangeContent(e: any) { - this.setState({ content: e.target.value }); + onChangeMessage(e: any) { + this.setState({ message: e.target.value }); } } diff --git a/frontend/src/models/ContactModel.ts b/frontend/src/models/ContactModel.ts new file mode 100644 index 000000000..ce2434b1b --- /dev/null +++ b/frontend/src/models/ContactModel.ts @@ -0,0 +1,55 @@ +import { computed } from "mobx"; +import ContactStore from "../stores/ContactStore"; + +export default class ContactModel { + store: ContactStore; + + id: number; + readable: boolean; + corner: number; + message: string; + nickname?: string; + name?: string; + email: string; + department: number; + grade: number; + + constructor(store: ContactStore, json: any) { + this.store = store; + + const { id, readable, corner, message, nickname, name, email, department, grade } = json; + this.id = id; + this.readable = readable; + this.corner = corner; + this.message = message; + this.nickname = nickname; + this.name = name; + this.email = email; + this.department = department; + this.grade = grade; + } + + save() { + console.log(this.toJson); + return this.store.transportLayer.saveContact( + this.toJson, + (res: object) => console.log(res), + (err: object) => console.log(err) + ); + } + + @computed + get toJson() { + return { + id: this.id, + readable: this.readable, + corner: this.corner, + message: this.message, + nickname: this.nickname, + name: this.name, + email: this.email, + department: this.department, + grade: this.grade, + }; + } +} diff --git a/frontend/src/stores/ContactStore.ts b/frontend/src/stores/ContactStore.ts index 7abe81325..1ad536d00 100644 --- a/frontend/src/stores/ContactStore.ts +++ b/frontend/src/stores/ContactStore.ts @@ -1,5 +1,5 @@ import ContactApi from "../api/ContactApi"; -import Contact from "../models/Contact"; +import ContactModel from "../models/ContactModel"; export default class ContactStore { transportLayer: ContactApi; @@ -9,6 +9,6 @@ export default class ContactStore { } createContact(json: object) { - return new Contact(this, json); + return new ContactModel(this, json); } } From ec407be2e1ac09dd1436cb281e52ac74c17c7523 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Tue, 14 Aug 2018 12:21:58 +0900 Subject: [PATCH 05/64] =?UTF-8?q?validation=E3=81=97=E5=BF=98=E3=82=8C?= =?UTF-8?q?=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/models/contact.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/contact.rb b/app/models/contact.rb index 8ea5b9452..08ad6336f 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -18,6 +18,7 @@ class Contact < ApplicationRecord validates :corner, presence: true validates :message, presence: true validates :department, presence: true + validates :grade, presence: true bind_inum :corner, ContactCorners bind_inum :department, ContactDepartments From c0bafd9234269f90ca4869f315bae342567c0031 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Tue, 14 Aug 2018 12:22:07 +0900 Subject: [PATCH 06/64] =?UTF-8?q?=E3=82=B9=E3=82=BF=E3=82=A4=E3=83=AB?= =?UTF-8?q?=E8=AA=BF=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/entries/Contact.tsx | 92 ++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 23 deletions(-) diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index d119415bc..754730401 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -15,9 +15,9 @@ type Prop = { }; type State = { name: string; - corner: number; - department: number; - grade: number; + corner?: number; + department?: number; + grade?: number; email: string; nickname: string; message: string; @@ -30,9 +30,9 @@ export default class Contact extends React.Component { super(props); this.state = { name: "", - corner: 0, - department: 0, - grade: 0, + corner: undefined, + department: undefined, + grade: undefined, email: "", nickname: "", message: "", @@ -50,6 +50,7 @@ export default class Contact extends React.Component { } render() { + // TODO(euglena1215): requiredの*をべた書きで書かなくてもいいようにする return (
} /> @@ -67,33 +68,38 @@ export default class Contact extends React.Component { /> - + + + + + + + - - + { /> - 送信 @@ -212,6 +219,45 @@ const ContactFormInput = styled.input` } `; +const ContactFormSelect = styled.select` + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + width: 100%; + line-height: 1.5rem; + padding: 5px; + padding-left: 30px; + border: 2px solid #00afec; + border-radius: 1.5rem; + background: none transparent; + vertical-align: middle; + color: #00afec; +`; + +const ContactFormSelectHalf = ContactFormSelect.extend` + width: 50%; +`; + +const ContactFormTextarea = styled.textarea` + margin: 5px; + margin-left: 0; + margin-right: 0; + padding: 5px; + padding-left: 30px; + line-height: 1.5rem; + width: 100%; + border: 2px solid #00afec; + border-radius: 1.5rem; + + ::placeholder { + color: #00afec; + opacity: 1; + } + ::-ms-input-placeholder { + color: #00afec; + } +`; + const ContactFormButton = ChkButtonBase.extend` background-color: ${chkColors.orange}; width: 30%; From 6d89374d503ad97fefe1d6e3f28d20b0213eb5ee Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Tue, 14 Aug 2018 14:26:13 +0900 Subject: [PATCH 07/64] =?UTF-8?q?=E3=82=A2=E3=83=A9=E3=83=BC=E3=83=88?= =?UTF-8?q?=E3=82=92=E8=A1=A8=E7=A4=BA=E3=81=95=E3=81=9B=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/entries/Contact.tsx | 30 ++++++++++++++++++++++++++++- frontend/src/models/ContactModel.ts | 8 ++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index 754730401..5e45a26d6 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -22,6 +22,10 @@ type State = { nickname: string; message: string; readable: boolean; + alert: { + message: string; + status?: string; + }; }; @inject("rootStore") @@ -37,6 +41,10 @@ export default class Contact extends React.Component { nickname: "", message: "", readable: false, + alert: { + message: "", + status: undefined, + }, }; this.createContact = this.createContact.bind(this); @@ -59,6 +67,7 @@ export default class Contact extends React.Component { お問い合わせフォーム
+ {this.state.alert.status === void 0 ? null : {this.state.alert.message}} { const root = this.props.rootStore!; const contact = root.contactStore.createContact(this.state); - contact.save(); + contact.save( + (_: object) => { + this.setState({ alert: { status: "successed", message: "おたよりを送信しました。" } }); + }, + (_: object) => { + this.setState({ alert: { status: "failed", message: "おたよりの送信に失敗しました。" } }); + } + ); } onChangeName(e: any) { @@ -266,3 +282,15 @@ const ContactFormButton = ChkButtonBase.extend` margin-right: auto; border-radius: 20px; `; + +const AlertMessage = styled.div` + width: 100%; + margin-left: auto; + margin-right: auto; + margin-bottom: 10px; + padding: 15px; + border-radius: 8px; + background-color: #ffe18e; + color: #c59406; + z-index: 100; +`; diff --git a/frontend/src/models/ContactModel.ts b/frontend/src/models/ContactModel.ts index ce2434b1b..098273c48 100644 --- a/frontend/src/models/ContactModel.ts +++ b/frontend/src/models/ContactModel.ts @@ -29,13 +29,9 @@ export default class ContactModel { this.grade = grade; } - save() { + save(successed: (res: object) => void, failed: (res: object) => void) { console.log(this.toJson); - return this.store.transportLayer.saveContact( - this.toJson, - (res: object) => console.log(res), - (err: object) => console.log(err) - ); + return this.store.transportLayer.saveContact(this.toJson, successed, failed); } @computed From 52cd35469e37620f76c2ea45b7dce9b96d6643d8 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Tue, 14 Aug 2018 14:33:51 +0900 Subject: [PATCH 08/64] =?UTF-8?q?selectbox=E3=81=AE=E9=81=B8=E6=8A=9E?= =?UTF-8?q?=E8=82=A2=E3=81=8C=E8=B6=B3=E3=82=8A=E3=81=AA=E3=81=8B=E3=81=A3?= =?UTF-8?q?=E3=81=9F=E3=81=AE=E3=81=A7=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/entries/Contact.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index 5e45a26d6..d3051d635 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -103,6 +103,12 @@ export default class Contact extends React.Component { + + + + + + From c844115faf9168da67b5875a95b0eeb7d3fddf16 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Tue, 14 Aug 2018 15:48:43 +0900 Subject: [PATCH 09/64] =?UTF-8?q?baseURL=E3=82=92=E5=BC=95=E6=95=B0?= =?UTF-8?q?=E3=81=A7=E6=B8=A1=E3=81=99=E3=82=88=E3=81=86=E3=81=AB=E3=81=97?= =?UTF-8?q?=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/api/RestClient.ts | 4 ++-- frontend/src/index.tsx | 3 ++- frontend/src/stores/RootStore.ts | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/frontend/src/api/RestClient.ts b/frontend/src/api/RestClient.ts index d9a75a112..135cd9b3d 100644 --- a/frontend/src/api/RestClient.ts +++ b/frontend/src/api/RestClient.ts @@ -1,12 +1,12 @@ export default class RestClient { axios: any; - constructor() { + constructor(baseUrl: string) { const axiosBase = require("axios"); const csrfToken = (document.querySelector("meta[name=csrf-token]")).content; this.axios = axiosBase.create({ - baseURL: "http://localhost:3000", // TODO(euglena1215): productionとの切り替え方法を考える + baseURL: baseUrl, timeout: 1000, headers: { "Content-Type": "application/json", diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 8111bba1d..d17cd30b4 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -9,8 +9,9 @@ import { Provider } from "mobx-react"; import { App } from "./App"; import RootStore from "./stores/RootStore"; +// TODO(euglena1215): URLのproductionとの切り替え方法を考える ReactDOM.render( - + diff --git a/frontend/src/stores/RootStore.ts b/frontend/src/stores/RootStore.ts index 934a4e796..25812464c 100644 --- a/frontend/src/stores/RootStore.ts +++ b/frontend/src/stores/RootStore.ts @@ -5,8 +5,8 @@ import RestClient from "../api/RestClient"; export default class RootStore { contactStore: ContactStore; - constructor() { - const restClient = new RestClient(); + constructor(baseUrl: string) { + const restClient = new RestClient(baseUrl); const contactApi = new ContactApi(restClient); this.contactStore = new ContactStore(contactApi); From 44c8226bbf56faf85cc9424d4b59616064ffa4e8 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Tue, 14 Aug 2018 15:53:52 +0900 Subject: [PATCH 10/64] onSubmit -> onClick --- frontend/src/entries/Contact.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index d3051d635..116eb2efb 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -65,7 +65,7 @@ export default class Contact extends React.Component { お問い合わせフォーム - + {this.state.alert.status === void 0 ? null : {this.state.alert.message}} { required /> - 送信 + 送信 From 5037d8f9d6e3726e988a719a9af62e4107d01a38 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Tue, 14 Aug 2018 16:14:06 +0900 Subject: [PATCH 11/64] =?UTF-8?q?setState=E3=82=92inline=E3=81=A7=E5=91=BC?= =?UTF-8?q?=E3=81=B6=E3=82=88=E3=81=86=E3=81=AB=E3=81=97=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/api/RestClient.ts | 4 +-- frontend/src/entries/Contact.tsx | 59 +++++++++----------------------- 2 files changed, 19 insertions(+), 44 deletions(-) diff --git a/frontend/src/api/RestClient.ts b/frontend/src/api/RestClient.ts index 135cd9b3d..bdd3bac48 100644 --- a/frontend/src/api/RestClient.ts +++ b/frontend/src/api/RestClient.ts @@ -26,12 +26,12 @@ export default class RestClient { .get(path, { params: params }) .then((result: object) => { console.log(`GET ${this.axios.baseURL}/${path}`); - console.log(`result: ${result}`); + console.log(`result: ${JSON.stringify(result)}`); successed(result); }) .catch((error: object) => { console.log(`ERROR! GET ${this.axios.baseURL}/${path}`); - console.log(`error: ${error}`); + console.log(`error: ${JSON.stringify(error)}`); errored(error); }) .then(always()); diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index 116eb2efb..4ef6db5ab 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -48,13 +48,6 @@ export default class Contact extends React.Component { }; this.createContact = this.createContact.bind(this); - this.onChangeName = this.onChangeName.bind(this); - this.onChangeCorner = this.onChangeCorner.bind(this); - this.onChangeDepartment = this.onChangeDepartment.bind(this); - this.onChangeGrade = this.onChangeGrade.bind(this); - this.onChangeEmail = this.onChangeEmail.bind(this); - this.onChangeNickname = this.onChangeNickname.bind(this); - this.onChangeMessage = this.onChangeMessage.bind(this); } render() { @@ -73,11 +66,16 @@ export default class Contact extends React.Component { type="text" placeholder="名前" value={this.state.name} - onChange={this.onChangeName} + onChange={(e: any) => this.setState({ name: e.target.value })} />
- + this.setState({ corner: e.target.value })} + required + > @@ -89,7 +87,7 @@ export default class Contact extends React.Component { this.setState({ department: e.target.value })} required > @@ -100,7 +98,12 @@ export default class Contact extends React.Component { - + this.setState({ grade: e.target.value })} + required + > @@ -117,7 +120,7 @@ export default class Contact extends React.Component { type="email" placeholder="メールアドレス" value={this.state.email} - onChange={this.onChangeEmail} + onChange={(e: any) => this.setState({ email: e.target.value })} /> @@ -126,7 +129,7 @@ export default class Contact extends React.Component { type="text" placeholder="ラジオネーム" value={this.state.nickname} - onChange={this.onChangeNickname} + onChange={(e: any) => this.setState({ nickname: e.target.value })} /> @@ -135,7 +138,7 @@ export default class Contact extends React.Component { placeholder="内容*" rows={4} value={this.state.message} - onChange={this.onChangeMessage} + onChange={(e: any) => this.setState({ message: e.target.value })} required /> @@ -162,34 +165,6 @@ export default class Contact extends React.Component { } ); } - - onChangeName(e: any) { - this.setState({ name: e.target.value }); - } - - onChangeCorner(e: any) { - this.setState({ corner: e.target.value }); - } - - onChangeDepartment(e: any) { - this.setState({ department: e.target.value }); - } - - onChangeGrade(e: any) { - this.setState({ grade: e.target.value }); - } - - onChangeEmail(e: any) { - this.setState({ email: e.target.value }); - } - - onChangeNickname(e: any) { - this.setState({ nickname: e.target.value }); - } - - onChangeMessage(e: any) { - this.setState({ message: e.target.value }); - } } const ContactFormWrapper = styled.div` From 2e775264c56fe38232bdf7d9be4ea790701be4ea Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Tue, 14 Aug 2018 17:22:01 +0900 Subject: [PATCH 12/64] =?UTF-8?q?readable=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/entries/Contact.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index 4ef6db5ab..3ff85d3fe 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -142,6 +142,19 @@ export default class Contact extends React.Component { required /> + + + 送信 @@ -255,6 +268,11 @@ const ContactFormTextarea = styled.textarea` } `; +const ContactFormCheckbox = styled.input` + margin-left: 20px; + margin-right: 10px; +`; + const ContactFormButton = ChkButtonBase.extend` background-color: ${chkColors.orange}; width: 30%; From c4e8e38b8d2f14bac513dc2fd58ad8a1ca33af51 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Tue, 14 Aug 2018 17:52:47 +0900 Subject: [PATCH 13/64] rename --- frontend/src/entries/Contact.tsx | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index 3ff85d3fe..b41cf2c00 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -56,8 +56,9 @@ export default class Contact extends React.Component {
} /> - +
お問い合わせフォーム +
{this.state.alert.status === void 0 ? null : {this.state.alert.message}} @@ -157,7 +158,7 @@ export default class Contact extends React.Component { 送信
- +
); @@ -185,6 +186,15 @@ const ContactFormWrapper = styled.div` display: flex; justify-content: center; align-items: center; + + > div { + width: 50%; + margin-bottom: 100px; + + @media ${media.mobile} { + width: 90%; + } + } `; const ContactFormTitle = styled.div` @@ -196,15 +206,6 @@ const ContactFormTitle = styled.div` color: #00afec; `; -const ContactForm = styled.div` - width: 50%; - margin-bottom: 100px; - - @media ${media.mobile} { - width: 90%; - } -`; - const ContactFormInputWrapper = styled.div` margin: 20px; `; From 3649d1309775c64cbecea1a83576cda318fb4fb2 Mon Sep 17 00:00:00 2001 From: Shintani Teppei Date: Tue, 14 Aug 2018 23:16:56 +0900 Subject: [PATCH 14/64] =?UTF-8?q?ContactForm=E3=81=ABcomponent=E3=81=AB?= =?UTF-8?q?=E5=88=87=E3=82=8A=E5=88=86=E3=81=91=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/components/ContactForm.tsx | 229 +++++++++++++++++++++++ frontend/src/entries/Contact.tsx | 235 ++---------------------- 2 files changed, 244 insertions(+), 220 deletions(-) create mode 100644 frontend/src/components/ContactForm.tsx diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx new file mode 100644 index 000000000..29f0d94ad --- /dev/null +++ b/frontend/src/components/ContactForm.tsx @@ -0,0 +1,229 @@ +import * as React from "react"; +import styled from "styled-components"; +import { ChkButtonBase } from "../commons/ChkButtonBase"; +import { chkColors } from "../commons/color"; +import ContactStore from "../stores/ContactStore"; + +type Prop = { + contactStore: ContactStore; + successed: (res: object) => void; + failed: (res: object) => void; +}; + +type State = { + name: string; + corner?: number; + department?: number; + grade?: number; + email: string; + nickname: string; + message: string; + readable: boolean; +}; + +export default class ContactForm extends React.Component { + constructor(props: Prop) { + super(props); + this.state = { + name: "", + corner: undefined, + department: undefined, + grade: undefined, + email: "", + nickname: "", + message: "", + readable: false, + }; + + this.createContact = this.createContact.bind(this); + } + + render() { + return ( +
+ + this.setState({ name: e.target.value })} + /> + + + this.setState({ corner: e.target.value })} + required + > + + + + + + + + + this.setState({ department: e.target.value })} + required + > + + + + + + + + + this.setState({ grade: e.target.value })} + required + > + + + + + + + + + + + + this.setState({ email: e.target.value })} + /> + + + this.setState({ nickname: e.target.value })} + /> + + + this.setState({ message: e.target.value })} + required + /> + + + + + 送信 +
+ ); + } + + createContact(e: any) { + e.preventDefault(); + + const { contactStore } = this.props; + const contact = contactStore.createContact(this.state); + + contact.save(this.props.successed, this.props.failed); + } +} + +const ContactFormInputWrapper = styled.div` + margin: 20px; +`; + +const ContactFormInput = styled.input` + margin: 5px; + margin-left: 0; + margin-right: 0; + padding: 5px; + padding-left: 30px; + line-height: 1.5rem; + width: 100%; + border: 2px solid #00afec; + border-radius: 1.5rem; + + ::placeholder { + color: #00afec; + opacity: 1; + } + ::-ms-input-placeholder { + color: #00afec; + } +`; + +const ContactFormSelect = styled.select` + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + width: 100%; + line-height: 1.5rem; + padding: 5px; + padding-left: 30px; + border: 2px solid #00afec; + border-radius: 1.5rem; + background: none transparent; + vertical-align: middle; + color: #00afec; +`; + +const ContactFormSelectHalf = ContactFormSelect.extend` + width: 50%; +`; + +const ContactFormTextarea = styled.textarea` + margin: 5px; + margin-left: 0; + margin-right: 0; + padding: 5px; + padding-left: 30px; + line-height: 1.5rem; + width: 100%; + border: 2px solid #00afec; + border-radius: 1.5rem; + + ::placeholder { + color: #00afec; + opacity: 1; + } + ::-ms-input-placeholder { + color: #00afec; + } +`; + +const ContactFormCheckbox = styled.input` + margin-left: 20px; + margin-right: 10px; +`; + +const ContactFormButton = ChkButtonBase.extend` + background-color: ${chkColors.orange}; + width: 30%; + margin-top: 40px; + margin-left: auto; + margin-right: auto; + border-radius: 20px; +`; diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index b41cf2c00..e54c11cac 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -2,26 +2,17 @@ import * as React from "react"; import styled from "styled-components"; import { media } from "../commons/style"; -import { ChkButtonBase } from "../commons/ChkButtonBase"; -import { chkColors } from "../commons/color"; import { HeroArea } from "../components/HeroArea"; import { ContactHeroContent } from "../components/ContactHeroContent"; import { inject } from "../../node_modules/mobx-react"; import RootStore from "../stores/RootStore"; +import ContactForm from "../components/ContactForm"; type Prop = { rootStore?: RootStore; }; type State = { - name: string; - corner?: number; - department?: number; - grade?: number; - email: string; - nickname: string; - message: string; - readable: boolean; alert: { message: string; status?: string; @@ -33,24 +24,19 @@ export default class Contact extends React.Component { constructor(props: Prop) { super(props); this.state = { - name: "", - corner: undefined, - department: undefined, - grade: undefined, - email: "", - nickname: "", - message: "", - readable: false, alert: { message: "", status: undefined, }, }; - this.createContact = this.createContact.bind(this); + this.successSendContact = this.successSendContact.bind(this); + this.failSendContact = this.failSendContact.bind(this); } render() { + const rootStore = this.props.rootStore!; + // TODO(euglena1215): requiredの*をべた書きで書かなくてもいいようにする return (
@@ -59,125 +45,23 @@ export default class Contact extends React.Component {
お問い合わせフォーム -
- - {this.state.alert.status === void 0 ? null : {this.state.alert.message}} - this.setState({ name: e.target.value })} - /> - - - this.setState({ corner: e.target.value })} - required - > - - - - - - - - - this.setState({ department: e.target.value })} - required - > - - - - - - - - - this.setState({ grade: e.target.value })} - required - > - - - - - - - - - - - - this.setState({ email: e.target.value })} - /> - - - this.setState({ nickname: e.target.value })} - /> - - - this.setState({ message: e.target.value })} - required - /> - - - - - 送信 -
+
); } - createContact(e: any) { - e.preventDefault(); - - const root = this.props.rootStore!; - const contact = root.contactStore.createContact(this.state); + successSendContact(_: object) { + this.setState({ alert: { status: "successed", message: "おたよりを送信しました。" } }); + } - contact.save( - (_: object) => { - this.setState({ alert: { status: "successed", message: "おたよりを送信しました。" } }); - }, - (_: object) => { - this.setState({ alert: { status: "failed", message: "おたよりの送信に失敗しました。" } }); - } - ); + failSendContact(_: object) { + this.setState({ alert: { status: "failed", message: "おたよりの送信に失敗しました。" } }); } } @@ -205,92 +89,3 @@ const ContactFormTitle = styled.div` text-align: center; color: #00afec; `; - -const ContactFormInputWrapper = styled.div` - margin: 20px; -`; - -const ContactFormInput = styled.input` - margin: 5px; - margin-left: 0; - margin-right: 0; - padding: 5px; - padding-left: 30px; - line-height: 1.5rem; - width: 100%; - border: 2px solid #00afec; - border-radius: 1.5rem; - - ::placeholder { - color: #00afec; - opacity: 1; - } - ::-ms-input-placeholder { - color: #00afec; - } -`; - -const ContactFormSelect = styled.select` - -moz-appearance: none; - -webkit-appearance: none; - appearance: none; - width: 100%; - line-height: 1.5rem; - padding: 5px; - padding-left: 30px; - border: 2px solid #00afec; - border-radius: 1.5rem; - background: none transparent; - vertical-align: middle; - color: #00afec; -`; - -const ContactFormSelectHalf = ContactFormSelect.extend` - width: 50%; -`; - -const ContactFormTextarea = styled.textarea` - margin: 5px; - margin-left: 0; - margin-right: 0; - padding: 5px; - padding-left: 30px; - line-height: 1.5rem; - width: 100%; - border: 2px solid #00afec; - border-radius: 1.5rem; - - ::placeholder { - color: #00afec; - opacity: 1; - } - ::-ms-input-placeholder { - color: #00afec; - } -`; - -const ContactFormCheckbox = styled.input` - margin-left: 20px; - margin-right: 10px; -`; - -const ContactFormButton = ChkButtonBase.extend` - background-color: ${chkColors.orange}; - width: 30%; - margin-top: 40px; - margin-left: auto; - margin-right: auto; - border-radius: 20px; -`; - -const AlertMessage = styled.div` - width: 100%; - margin-left: auto; - margin-right: auto; - margin-bottom: 10px; - padding: 15px; - border-radius: 8px; - background-color: #ffe18e; - color: #c59406; - z-index: 100; -`; From 4b1af5788d549985825b989154fc5e7dca163b32 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 12 May 2019 00:26:55 +0900 Subject: [PATCH 15/64] no-console, no-empty is false --- frontend/tslint.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/tslint.json b/frontend/tslint.json index 9920293e2..62d49eb49 100644 --- a/frontend/tslint.json +++ b/frontend/tslint.json @@ -12,6 +12,8 @@ true, "ignore-same-line" ], + "no-console": false, + "no-empty": false, "no-unused-expression": [ true, "allow-fast-null-checks" From 22b60722a74eddb402e8875411b9473c47d4b374 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 12 May 2019 09:04:40 +0900 Subject: [PATCH 16/64] refactor: replace es6 --- frontend/src/api/RestClient.ts | 57 +++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/frontend/src/api/RestClient.ts b/frontend/src/api/RestClient.ts index bdd3bac48..54834dd74 100644 --- a/frontend/src/api/RestClient.ts +++ b/frontend/src/api/RestClient.ts @@ -1,80 +1,87 @@ +import axios, { AxiosInstance, AxiosResponse, AxiosError } from "axios"; + export default class RestClient { - axios: any; + public axios: AxiosInstance; constructor(baseUrl: string) { - const axiosBase = require("axios"); - const csrfToken = (document.querySelector("meta[name=csrf-token]")).content; + const csrfToken = (document.querySelector("meta[name=csrf-token]") as HTMLMetaElement).content; - this.axios = axiosBase.create({ + this.axios = axios.create({ baseURL: baseUrl, timeout: 1000, headers: { "Content-Type": "application/json", - "X-CSRF-TOKEN": csrfToken, - }, + "X-CSRF-TOKEN": csrfToken + } }); } - get( + public get( path: string, params: object, successed: (res: object) => void, errored: (res: object) => void, - always = () => {} + always: () => any = () => {} ) { return this.axios - .get(path, { params: params }) - .then((result: object) => { - console.log(`GET ${this.axios.baseURL}/${path}`); + .get(path, { params }) + .then((result: AxiosResponse) => { + console.log(`GET ${result.config.url}`); + if (params) console.log(`Params: ${JSON.stringify(params)}`); console.log(`result: ${JSON.stringify(result)}`); successed(result); }) - .catch((error: object) => { - console.log(`ERROR! GET ${this.axios.baseURL}/${path}`); + .catch((error: AxiosError) => { + console.log(`ERROR! GET ${error.config.url}`); + if (params) console.log(`ERROR! Params: ${JSON.stringify(params)}`); console.log(`error: ${JSON.stringify(error)}`); errored(error); }) .then(always()); } - post( + public post( path: string, params: object, successed: (res: object) => void, errored: (res: object) => void, - always = () => {} + always: () => any = () => {} ) { return this.axios .post(path, params) - .then((result: object) => { - console.log(`POST ${this.axios.baseURL}/${path}`); + .then((result: AxiosResponse) => { + console.log(`POST ${result.config.url}`); + if (params) console.log(`Params: ${JSON.stringify(params)}`); console.log(`result: ${result}`); successed(result); }) - .catch((error: object) => { - console.log(`ERROR! POST ${this.axios.baseURL}/${path}`); + .catch((error: AxiosError) => { + console.log(`ERROR! POST ${error.config.url}`); + if (params) console.log(`ERROR! Params: ${JSON.stringify(params)}`); console.log(`error: ${error}`); errored(error); }) .then(always()); } - delete( + public delete( path: string, params: object, successed: (res: object) => void, errored: (res: object) => void, - always = () => {} + always: () => any = () => {} ) { return this.axios .delete(path, { data: { params } }) - .then((result: object) => { - console.log(`DELETE ${this.axios.baseURL}/${path}`); + .then((result: AxiosResponse) => { + console.log(`DELETE ${result.config.url}`); + if (params) console.log(`Params: ${JSON.stringify(params)}`); console.log(`result: ${result}`); successed(result); }) - .catch((error: object) => { - console.log(`ERROR! DELETE ${this.axios.baseURL}/${path}`); + .catch((error: AxiosError) => { + console.log(`ERROR! DELETE ${error.config.url}`); + if (params) console.log(`ERROR! Params: ${JSON.stringify(params)}`); console.log(`error: ${error}`); errored(error); }) From 35698a218cbcc5bb4e4fbff9c0a602c5db9e0f20 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 12 May 2019 09:13:48 +0900 Subject: [PATCH 17/64] set class property as public --- frontend/src/api/ContactApi.ts | 9 +++++-- frontend/src/models/ContactModel.ts | 41 +++++++++++++++-------------- frontend/src/stores/ContactStore.ts | 4 +-- frontend/src/stores/RootStore.ts | 2 +- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/frontend/src/api/ContactApi.ts b/frontend/src/api/ContactApi.ts index 0105fb520..73e410379 100644 --- a/frontend/src/api/ContactApi.ts +++ b/frontend/src/api/ContactApi.ts @@ -1,13 +1,18 @@ import RestClient from "./RestClient"; export default class ContactApi { - restClient: RestClient; + public restClient: RestClient; constructor(restClient: RestClient) { this.restClient = restClient; } - saveContact(json: object, succussed: (res: object) => void, errored: (err: object) => void, always = () => {}) { + public saveContact( + json: object, + succussed: (res: object) => void, + errored: (err: object) => void, + always = () => {} + ) { return this.restClient.post("/api/v1/contacts", json, succussed, errored, always); } } diff --git a/frontend/src/models/ContactModel.ts b/frontend/src/models/ContactModel.ts index 098273c48..12987dd36 100644 --- a/frontend/src/models/ContactModel.ts +++ b/frontend/src/models/ContactModel.ts @@ -2,17 +2,17 @@ import { computed } from "mobx"; import ContactStore from "../stores/ContactStore"; export default class ContactModel { - store: ContactStore; + public store: ContactStore; - id: number; - readable: boolean; - corner: number; - message: string; - nickname?: string; - name?: string; - email: string; - department: number; - grade: number; + public id: number; + public readable: boolean; + public corner: number; + public message: string; + public nickname?: string; + public name?: string; + public email: string; + public department: number; + public grade: number; constructor(store: ContactStore, json: any) { this.store = store; @@ -29,23 +29,24 @@ export default class ContactModel { this.grade = grade; } - save(successed: (res: object) => void, failed: (res: object) => void) { + public save(successed: (res: object) => void, failed: (res: object) => void) { console.log(this.toJson); return this.store.transportLayer.saveContact(this.toJson, successed, failed); } @computed get toJson() { + const { id, readable, corner, message, nickname, name, email, department, grade } = this; return { - id: this.id, - readable: this.readable, - corner: this.corner, - message: this.message, - nickname: this.nickname, - name: this.name, - email: this.email, - department: this.department, - grade: this.grade, + id, + readable, + corner, + message, + nickname, + name, + email, + department, + grade }; } } diff --git a/frontend/src/stores/ContactStore.ts b/frontend/src/stores/ContactStore.ts index 1ad536d00..0648be0c7 100644 --- a/frontend/src/stores/ContactStore.ts +++ b/frontend/src/stores/ContactStore.ts @@ -2,13 +2,13 @@ import ContactApi from "../api/ContactApi"; import ContactModel from "../models/ContactModel"; export default class ContactStore { - transportLayer: ContactApi; + public transportLayer: ContactApi; constructor(transportLayer: ContactApi) { this.transportLayer = transportLayer; } - createContact(json: object) { + public createContact(json: object) { return new ContactModel(this, json); } } diff --git a/frontend/src/stores/RootStore.ts b/frontend/src/stores/RootStore.ts index 25812464c..a610cbbbc 100644 --- a/frontend/src/stores/RootStore.ts +++ b/frontend/src/stores/RootStore.ts @@ -3,7 +3,7 @@ import ContactApi from "../api/ContactApi"; import RestClient from "../api/RestClient"; export default class RootStore { - contactStore: ContactStore; + public contactStore: ContactStore; constructor(baseUrl: string) { const restClient = new RestClient(baseUrl); From 4df6b2a8098fa316fa673e81872a6d3e4a019640 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 12 May 2019 09:26:25 +0900 Subject: [PATCH 18/64] add props: onClick --- frontend/src/commons/ChkButtonBase.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/commons/ChkButtonBase.tsx b/frontend/src/commons/ChkButtonBase.tsx index 20c37f5f4..aed913edf 100644 --- a/frontend/src/commons/ChkButtonBase.tsx +++ b/frontend/src/commons/ChkButtonBase.tsx @@ -14,29 +14,29 @@ interface IPropsChkButtonBase extends IPropsCss { to?: string; text: string | React.ReactNode; name?: string; + onClick?: (e: any) => any; } const ChkButtonBase = (props: IPropsChkButtonBase) => { - const { to, text, name } = props; - const { color, bgcolor, border } = props; + const { to, text, name, color, bgcolor, border, onClick, ...otherProps } = props; if (to) { if (to.startsWith("http")) { return ( - + {text} ); } else { return ( - + {text} ); } } else { return ( - + {text} ); From b93317046b739e98216efca12d93736d226e81aa Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 12 May 2019 09:29:43 +0900 Subject: [PATCH 19/64] refactoring --- frontend/src/components/ContactForm.tsx | 48 ++++++++++++------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index 29f0d94ad..d47e39c18 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -1,16 +1,15 @@ import * as React from "react"; import styled from "styled-components"; -import { ChkButtonBase } from "../commons/ChkButtonBase"; -import { chkColors } from "../commons/color"; import ContactStore from "../stores/ContactStore"; +import ChkButtonBase from "../commons/ChkButtonBase"; -type Prop = { +interface IProp { contactStore: ContactStore; successed: (res: object) => void; failed: (res: object) => void; -}; +} -type State = { +interface IState { name: string; corner?: number; department?: number; @@ -19,10 +18,10 @@ type State = { nickname: string; message: string; readable: boolean; -}; +} -export default class ContactForm extends React.Component { - constructor(props: Prop) { +export default class ContactForm extends React.Component { + constructor(props: IProp) { super(props); this.state = { name: "", @@ -32,15 +31,15 @@ export default class ContactForm extends React.Component { email: "", nickname: "", message: "", - readable: false, + readable: false }; this.createContact = this.createContact.bind(this); } - render() { + public render() { return ( -
+ { this.setState({ corner: e.target.value })} + onChange={(e: any) => + this.setState({ + corner: e.target.value + }) + } required > @@ -82,7 +85,11 @@ export default class ContactForm extends React.Component { this.setState({ grade: e.target.value })} + onChange={(e: any) => + this.setState({ + grade: e.target.value + }) + } required > @@ -136,12 +143,12 @@ export default class ContactForm extends React.Component { ラジオ内でメッセージを読み上げてもいい場合はチェックをつけてください - 送信 + ); } - createContact(e: any) { + public createContact(e: any) { e.preventDefault(); const { contactStore } = this.props; @@ -190,7 +197,7 @@ const ContactFormSelect = styled.select` color: #00afec; `; -const ContactFormSelectHalf = ContactFormSelect.extend` +const ContactFormSelectHalf = styled(ContactFormSelect)` width: 50%; `; @@ -219,11 +226,4 @@ const ContactFormCheckbox = styled.input` margin-right: 10px; `; -const ContactFormButton = ChkButtonBase.extend` - background-color: ${chkColors.orange}; - width: 30%; - margin-top: 40px; - margin-left: auto; - margin-right: auto; - border-radius: 20px; -`; +const ContactFormButton = styled(ChkButtonBase)``; From 869c389af418bc9961b5497c4c5972602d9e8469 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Fri, 17 May 2019 20:27:03 +0900 Subject: [PATCH 20/64] upgrade --- frontend/yarn.lock | 78 ++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 143df6b3b..abca3c141 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -66,26 +66,26 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" "@types/prop-types@*": - version "15.5.8" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.8.tgz#8ae4e0ea205fe95c3901a5a1df7f66495e3a56ce" + version "15.7.1" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6" "@types/react-dom@^16.0.5": - version "16.0.11" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.0.11.tgz#bd10ccb0d9260343f4b9a49d4f7a8330a5c1f081" + version "16.8.4" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.4.tgz#7fb7ba368857c7aa0f4e4511c4710ca2c5a12a88" dependencies: "@types/react" "*" "@types/react-router-dom@^4.2.7": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-4.3.1.tgz#71fe2918f8f60474a891520def40a63997dafe04" + version "4.3.3" + resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-4.3.3.tgz#7837e3e9fefbc84a8f6c8a51dca004f4e83e94e3" dependencies: "@types/history" "*" "@types/react" "*" "@types/react-router" "*" "@types/react-router@*": - version "4.4.3" - resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-4.4.3.tgz#ea68b4021cb576866f83365b2201411537423d50" + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.0.0.tgz#22ae8f55d8af770ea1f755218936f01bfe1bfe27" dependencies: "@types/history" "*" "@types/react" "*" @@ -97,8 +97,8 @@ "@types/react" "*" "@types/react@*", "@types/react@^16.3.16": - version "16.7.20" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.20.tgz#13ae752c012710d0fa800985ca809814b51d3b58" + version "16.8.17" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.17.tgz#f287b76a5badb93bc9aa3f54521a3eb53d6c2374" dependencies: "@types/prop-types" "*" csstype "^2.2.0" @@ -1943,8 +1943,8 @@ csso@~2.3.1: source-map "^0.5.3" csstype@^2.2.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.1.tgz#4cfbf637a577497036ebcd7e32647ef19a0b8076" + version "2.6.4" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.4.tgz#d585a6062096e324e7187f80e04f92bd0f00e37f" cyclist@~0.2.2: version "0.2.2" @@ -3015,8 +3015,14 @@ hmac-drbg@^1.0.0: minimalistic-crypto-utils "^1.0.1" hoist-non-react-statics@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz#d2ca2dfc19c5a91c5a6615ce8e564ef0347e2a40" + version "2.5.5" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" + +hoist-non-react-statics@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" + dependencies: + react-is "^16.7.0" home-or-tmp@^2.0.0: version "2.0.0" @@ -3848,7 +3854,7 @@ long@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" dependencies: @@ -4122,15 +4128,15 @@ mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: minimist "0.0.8" mobx-react@^5.2.3: - version "5.2.3" - resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-5.2.3.tgz#cdf6141c2fe63377c5813cbd254e8ce0d4676631" + version "5.4.4" + resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-5.4.4.tgz#b3de9c6eabcd0ed8a40036888cb0221ab9568b80" dependencies: - hoist-non-react-statics "^2.5.0" + hoist-non-react-statics "^3.0.0" react-lifecycles-compat "^3.0.2" mobx@^5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/mobx/-/mobx-5.0.3.tgz#53b97f2a0f9b0dd7774c96249f81bf2d513d8e1c" + version "5.9.4" + resolved "https://registry.yarnpkg.com/mobx/-/mobx-5.9.4.tgz#1dee92aba33f67b7baeeb679e3bd376a12e55812" move-concurrently@^1.0.1: version "1.0.1" @@ -5014,7 +5020,7 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -prop-types@^15.3.0, prop-types@^15.6.2: +prop-types@^15.3.0: version "15.6.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" dependencies: @@ -5029,6 +5035,14 @@ prop-types@^15.5.4, prop-types@^15.6.1: loose-envify "^1.3.1" object-assign "^4.1.1" +prop-types@^15.6.2: + version "15.7.2" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.8.1" + proxy-addr@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.4.tgz#ecfc733bf22ff8c6f407fa275327b9ab67e48b93" @@ -5160,18 +5174,22 @@ rc@^1.1.7: strip-json-comments "~2.0.1" react-dom@^16.4.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.7.0.tgz#a17b2a7ca89ee7390bc1ed5eb81783c7461748b8" + version "16.8.6" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f" dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.2" - scheduler "^0.12.0" + scheduler "^0.13.6" react-is@^16.6.0: version "16.7.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.7.0.tgz#c1bd21c64f1f1364c6f70695ec02d69392f41bfa" +react-is@^16.7.0, react-is@^16.8.1: + version "16.8.6" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16" + react-lifecycles-compat@^3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -5219,13 +5237,13 @@ react-twitter-widgets@^1.7.1: scriptjs "^2.5.8" react@^16.4.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.7.0.tgz#b674ec396b0a5715873b350446f7ea0802ab6381" + version "16.8.6" + resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe" dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" prop-types "^15.6.2" - scheduler "^0.12.0" + scheduler "^0.13.6" read-chunk@^2.1.0: version "2.1.0" @@ -5530,9 +5548,9 @@ sax@^1.2.4, sax@~1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -scheduler@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.12.0.tgz#8ab17699939c0aedc5a196a657743c496538647b" +scheduler@^0.13.6: + version "0.13.6" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.6.tgz#466a4ec332467b31a91b9bf74e5347072e4cd889" dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" From 0d60e53596a0e4123f7ac45452222783abe6528d Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 19 May 2019 16:12:15 +0900 Subject: [PATCH 21/64] upgrade --- frontend/package.json | 44 ++++++++-------- frontend/yarn.lock | 114 ++++++++++++++++++++++++------------------ 2 files changed, 88 insertions(+), 70 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index e4c09a9c9..d5a490688 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,44 +12,44 @@ "lint": "npx tslint --fix -c ./tslint.json 'src/**/*{.ts,.tsx}'" }, "devDependencies": { + "@types/react": "^16.8.17", + "@types/react-dom": "^16.8.4", + "@types/react-router-dom": "^4.3.3", + "@types/react-slick": "^0.23.4", + "@types/styled-components": "^4.1.6", "awesome-typescript-loader": "^5.0.0", "babel-loader": "^7.1.4", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", + "clean-webpack-plugin": "^1.0.0", "css-loader": "^0.28.11", + "file-loader": "^1.1.11", + "prettier": "^1.15.3", "source-map-loader": "^0.2.3", "style-loader": "^0.21.0", + "tslint": "^5.11.0", + "tslint-config-prettier": "^1.17.0", + "tslint-plugin-prettier": "^2.0.1", "typescript": "^3.4.5", + "url-loader": "^1.0.1", "webpack": "^4.10.2", - "webpack-cli": "^2.1.4" + "webpack-cli": "^2.1.4", + "webpack-dev-server": "^3.1.10", + "webpack-manifest-plugin": "^2.0.4", + "webpack-merge": "^4.1.4" }, "dependencies": { - "@types/react": "^16.3.16", - "@types/react-dom": "^16.0.5", - "@types/react-router-dom": "^4.2.7", - "@types/react-slick": "^0.23.4", - "@types/styled-components": "^4.1.6", "axios": "^0.18.0", "babel-polyfill": "^6.26.0", - "clean-webpack-plugin": "^1.0.0", - "file-loader": "^1.1.11", - "mobx": "^5.0.3", - "mobx-react": "^5.2.3", + "mobx": "^5.9.4", + "mobx-react": "^5.4.4", "normalize.css": "^8.0.0", - "prettier": "^1.15.3", - "react": "^16.4.0", - "react-dom": "^16.4.0", - "react-router-dom": "^4.3.1", + "react": "^16.8.6", + "react-dom": "^16.8.6", + "react-router-dom": "^5.0.0", "react-slick": "^0.24.0", "react-twitter-widgets": "^1.7.1", "slick-carousel": "^1.8.1", - "styled-components": "^4.1.3", - "tslint": "^5.11.0", - "tslint-config-prettier": "^1.17.0", - "tslint-plugin-prettier": "^2.0.1", - "url-loader": "^1.0.1", - "webpack-dev-server": "^3.1.10", - "webpack-manifest-plugin": "^2.0.4", - "webpack-merge": "^4.1.4" + "styled-components": "^4.1.3" } } diff --git a/frontend/yarn.lock b/frontend/yarn.lock index abca3c141..7082fd349 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -14,6 +14,12 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/runtime@^7.1.2": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.4.4.tgz#dc2e34982eb236803aa27a07fea6857af1b9171d" + dependencies: + regenerator-runtime "^0.13.2" + "@babel/types@^7.0.0": version "7.3.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.0.tgz#61dc0b336a93badc02bf5f69c4cd8e1353f2ffc0" @@ -69,13 +75,13 @@ version "15.7.1" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6" -"@types/react-dom@^16.0.5": +"@types/react-dom@^16.8.4": version "16.8.4" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.4.tgz#7fb7ba368857c7aa0f4e4511c4710ca2c5a12a88" dependencies: "@types/react" "*" -"@types/react-router-dom@^4.2.7": +"@types/react-router-dom@^4.3.3": version "4.3.3" resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-4.3.3.tgz#7837e3e9fefbc84a8f6c8a51dca004f4e83e94e3" dependencies: @@ -96,7 +102,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^16.3.16": +"@types/react@*", "@types/react@^16.8.17": version "16.8.17" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.8.17.tgz#f287b76a5badb93bc9aa3f54521a3eb53d6c2374" dependencies: @@ -1817,6 +1823,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" +create-react-context@^0.2.2: + version "0.2.3" + resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.3.tgz#9ec140a6914a22ef04b8b09b7771de89567cb6f3" + dependencies: + fbjs "^0.8.0" + gud "^1.0.0" + cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -2518,7 +2531,7 @@ faye-websocket@~0.11.1: dependencies: websocket-driver ">=0.5.1" -fbjs@^0.8.16: +fbjs@^0.8.0, fbjs@^0.8.16: version "0.8.17" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" dependencies: @@ -2909,6 +2922,10 @@ grouped-queue@^0.3.3: dependencies: lodash "^4.17.2" +gud@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" + handle-thing@^1.2.5: version "1.2.5" resolved "http://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" @@ -2996,15 +3013,16 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.0" -history@^4.7.2: - version "4.7.2" - resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b" +history@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/history/-/history-4.9.0.tgz#84587c2068039ead8af769e9d6a6860a14fa1bca" dependencies: - invariant "^2.2.1" + "@babel/runtime" "^7.1.2" loose-envify "^1.2.0" resolve-pathname "^2.2.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" value-equal "^0.4.0" - warning "^3.0.0" hmac-drbg@^1.0.0: version "1.0.1" @@ -3014,11 +3032,7 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^2.5.0: - version "2.5.5" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" - -hoist-non-react-statics@^3.0.0: +hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0: version "3.3.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" dependencies: @@ -3231,7 +3245,7 @@ into-stream@^3.1.0: from2 "^2.1.1" p-is-promise "^1.1.0" -invariant@^2.2.1, invariant@^2.2.2, invariant@^2.2.4: +invariant@^2.2.2: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" dependencies: @@ -4127,14 +4141,14 @@ mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: dependencies: minimist "0.0.8" -mobx-react@^5.2.3: +mobx-react@^5.4.4: version "5.4.4" resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-5.4.4.tgz#b3de9c6eabcd0ed8a40036888cb0221ab9568b80" dependencies: hoist-non-react-statics "^3.0.0" react-lifecycles-compat "^3.0.2" -mobx@^5.0.3: +mobx@^5.9.4: version "5.9.4" resolved "https://registry.yarnpkg.com/mobx/-/mobx-5.9.4.tgz#1dee92aba33f67b7baeeb679e3bd376a12e55812" @@ -5027,7 +5041,7 @@ prop-types@^15.3.0: loose-envify "^1.3.1" object-assign "^4.1.1" -prop-types@^15.5.4, prop-types@^15.6.1: +prop-types@^15.5.4: version "15.6.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" dependencies: @@ -5173,7 +5187,7 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-dom@^16.4.0: +react-dom@^16.8.6: version "16.8.6" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.8.6.tgz#71d6303f631e8b0097f56165ef608f051ff6e10f" dependencies: @@ -5194,28 +5208,32 @@ react-lifecycles-compat@^3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" -react-router-dom@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6" +react-router-dom@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.0.0.tgz#542a9b86af269a37f0b87218c4c25ea8dcf0c073" dependencies: - history "^4.7.2" - invariant "^2.2.4" + "@babel/runtime" "^7.1.2" + history "^4.9.0" loose-envify "^1.3.1" - prop-types "^15.6.1" - react-router "^4.3.1" - warning "^4.0.1" + prop-types "^15.6.2" + react-router "5.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" -react-router@^4.3.1: - version "4.3.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-4.3.1.tgz#aada4aef14c809cb2e686b05cee4742234506c4e" +react-router@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.0.0.tgz#349863f769ffc2fa10ee7331a4296e86bc12879d" dependencies: - history "^4.7.2" - hoist-non-react-statics "^2.5.0" - invariant "^2.2.4" + "@babel/runtime" "^7.1.2" + create-react-context "^0.2.2" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" loose-envify "^1.3.1" path-to-regexp "^1.7.0" - prop-types "^15.6.1" - warning "^4.0.1" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" react-slick@^0.24.0: version "0.24.0" @@ -5236,7 +5254,7 @@ react-twitter-widgets@^1.7.1: prop-types "^15.3.0" scriptjs "^2.5.8" -react@^16.4.0: +react@^16.8.6: version "16.8.6" resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe" dependencies: @@ -5339,6 +5357,10 @@ regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" +regenerator-runtime@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447" + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" @@ -6129,6 +6151,14 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +tiny-invariant@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.4.tgz#346b5415fd93cb696b0c4e8a96697ff590f92463" + +tiny-warning@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.2.tgz#1dfae771ee1a04396bdfde27a3adcebc6b648b28" + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -6444,18 +6474,6 @@ vm-browserify@0.0.4: dependencies: indexof "0.0.1" -warning@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" - dependencies: - loose-envify "^1.0.0" - -warning@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.1.tgz#66ce376b7fbfe8a887c22bdf0e7349d73d397745" - dependencies: - loose-envify "^1.0.0" - watchpack@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" From f301d59f1dbbab7ba3da6ea3143c6a2772ab16fa Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 19 May 2019 18:48:27 +0900 Subject: [PATCH 22/64] print params by table --- frontend/src/api/RestClient.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/src/api/RestClient.ts b/frontend/src/api/RestClient.ts index 54834dd74..2d26f41cd 100644 --- a/frontend/src/api/RestClient.ts +++ b/frontend/src/api/RestClient.ts @@ -27,13 +27,13 @@ export default class RestClient { .get(path, { params }) .then((result: AxiosResponse) => { console.log(`GET ${result.config.url}`); - if (params) console.log(`Params: ${JSON.stringify(params)}`); - console.log(`result: ${JSON.stringify(result)}`); + if (params) console.table(params); + console.log(`status: ${result.status}, statusText: ${result.statusText}`); successed(result); }) .catch((error: AxiosError) => { console.log(`ERROR! GET ${error.config.url}`); - if (params) console.log(`ERROR! Params: ${JSON.stringify(params)}`); + if (params) console.table(params); console.log(`error: ${JSON.stringify(error)}`); errored(error); }) @@ -51,13 +51,13 @@ export default class RestClient { .post(path, params) .then((result: AxiosResponse) => { console.log(`POST ${result.config.url}`); - if (params) console.log(`Params: ${JSON.stringify(params)}`); - console.log(`result: ${result}`); + if (params) console.table(params); + console.log(`status: ${result.status}, statusText: ${result.statusText}`); successed(result); }) .catch((error: AxiosError) => { console.log(`ERROR! POST ${error.config.url}`); - if (params) console.log(`ERROR! Params: ${JSON.stringify(params)}`); + if (params) console.table(params); console.log(`error: ${error}`); errored(error); }) @@ -75,13 +75,13 @@ export default class RestClient { .delete(path, { data: { params } }) .then((result: AxiosResponse) => { console.log(`DELETE ${result.config.url}`); - if (params) console.log(`Params: ${JSON.stringify(params)}`); - console.log(`result: ${result}`); + if (params) console.table(params); + console.log(`status: ${result.status}, statusText: ${result.statusText}`); successed(result); }) .catch((error: AxiosError) => { console.log(`ERROR! DELETE ${error.config.url}`); - if (params) console.log(`ERROR! Params: ${JSON.stringify(params)}`); + if (params) console.table(params); console.log(`error: ${error}`); errored(error); }) From 9c68a74560ddc3380ced23412f266688c4c70732 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 19 May 2019 18:48:52 +0900 Subject: [PATCH 23/64] add TextInput --- frontend/src/components/Forms/TextInput.tsx | 89 +++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 frontend/src/components/Forms/TextInput.tsx diff --git a/frontend/src/components/Forms/TextInput.tsx b/frontend/src/components/Forms/TextInput.tsx new file mode 100644 index 000000000..f21703f55 --- /dev/null +++ b/frontend/src/components/Forms/TextInput.tsx @@ -0,0 +1,89 @@ +import * as React from "react"; +import styled, { css } from "styled-components"; + +type TextInputType = "text" | "password" | "email"; + +export interface ITextInputProps { + value?: string; + name?: string; + placeholder?: string; + type?: TextInputType; + multiLine?: boolean; + onChange?(value: string): void; +} + +export default ({ value, name, placeholder, multiLine, onChange, type = "text" }: ITextInputProps) => { + const [currentInputValue, setCurrentInputValue] = React.useState(""); + const [inFocus, setInFocus] = React.useState(false); + + const handleChange = React.useCallback((e: React.ChangeEvent) => { + const data = e.target.value; + setCurrentInputValue(data); + console.log(data); + + if (onChange) { + onChange(data); + } + }, []); + + const handleFocus = React.useCallback(() => { + setInFocus(true); + }, []); + + // call: did handleFoucus + const handleBlur = React.useCallback(() => { + console.log(inFocus); + setInFocus(false); + }, []); + + React.useEffect( + () => { + if (value != null) { + setCurrentInputValue(value); + } + }, + [value] + ); + + const props = { + type, + placeholder, + onFocus: handleFocus, + onBlur: handleBlur, + id: name, + value: currentInputValue, + onChange: handleChange, + styledFocus: inFocus ? true : false + }; + + return multiLine ? : ; +}; + +// TODO: focus時とそうでない時で背景かアウトラインのデザインを変える +const style = css` + margin: 5px; + margin-left: 0; + margin-right: 0; + padding: 5px; + padding-left: 30px; + line-height: 1.5rem; + width: 100%; + border: 2px solid #00afec; + border-radius: 1.5rem; + + ::placeholder { + color: #00afec; + opacity: 1; + } + ::-ms-input-placeholder { + color: #00afec; + } +`; + +const StyledInput = styled.input` + ${style}; +`; + +const StyledTextarea = styled.textarea` + ${style} +`; From bc69f2ee379c1da1a148f0d532691fae01a82fdb Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 19 May 2019 19:06:27 +0900 Subject: [PATCH 24/64] remove console.log --- frontend/src/components/Forms/TextInput.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/Forms/TextInput.tsx b/frontend/src/components/Forms/TextInput.tsx index f21703f55..2af1ffecf 100644 --- a/frontend/src/components/Forms/TextInput.tsx +++ b/frontend/src/components/Forms/TextInput.tsx @@ -32,7 +32,6 @@ export default ({ value, name, placeholder, multiLine, onChange, type = "text" } // call: did handleFoucus const handleBlur = React.useCallback(() => { - console.log(inFocus); setInFocus(false); }, []); From c3d22ec8b3a5594cdb220afd88d2b5050cf79efb Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 19 May 2019 19:29:22 +0900 Subject: [PATCH 25/64] upgrade styled-components --- frontend/package.json | 4 ++-- frontend/yarn.lock | 33 ++++++++++++++++++--------------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index d5a490688..49f14dc29 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,7 +16,7 @@ "@types/react-dom": "^16.8.4", "@types/react-router-dom": "^4.3.3", "@types/react-slick": "^0.23.4", - "@types/styled-components": "^4.1.6", + "@types/styled-components": "^4.1.15", "awesome-typescript-loader": "^5.0.0", "babel-loader": "^7.1.4", "babel-preset-es2015": "^6.24.1", @@ -50,6 +50,6 @@ "react-slick": "^0.24.0", "react-twitter-widgets": "^1.7.1", "slick-carousel": "^1.8.1", - "styled-components": "^4.1.3" + "styled-components": "^4.2.0" } } diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 7082fd349..eac4b0815 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -67,10 +67,6 @@ version "4.7.2" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.2.tgz#0e670ea254d559241b6eeb3894f8754991e73220" -"@types/node@*": - version "10.12.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" - "@types/prop-types@*": version "15.7.1" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6" @@ -81,6 +77,13 @@ dependencies: "@types/react" "*" +"@types/react-native@*": + version "0.57.57" + resolved "https://registry.yarnpkg.com/@types/react-native/-/react-native-0.57.57.tgz#4b59068acf6e542ac8e1e02e8a639b47e3e02c02" + dependencies: + "@types/prop-types" "*" + "@types/react" "*" + "@types/react-router-dom@^4.3.3": version "4.3.3" resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-4.3.3.tgz#7837e3e9fefbc84a8f6c8a51dca004f4e83e94e3" @@ -109,12 +112,12 @@ "@types/prop-types" "*" csstype "^2.2.0" -"@types/styled-components@^4.1.6": - version "4.1.6" - resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-4.1.6.tgz#9aa1d47dbc6bae540083869bcc6c639c6e9af0fe" +"@types/styled-components@^4.1.15": + version "4.1.15" + resolved "https://registry.yarnpkg.com/@types/styled-components/-/styled-components-4.1.15.tgz#532b6738ec633b2911e0470522c23e3c658952f2" dependencies: - "@types/node" "*" "@types/react" "*" + "@types/react-native" "*" csstype "^2.2.0" "@webassemblyjs/ast@1.5.9": @@ -3978,9 +3981,9 @@ mem@^4.0.0: mimic-fn "^1.0.0" p-is-promise "^1.1.0" -memoize-one@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-4.1.0.tgz#a2387c58c03fff27ca390c31b764a79addf3f906" +memoize-one@^5.0.0: + version "5.0.4" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.4.tgz#005928aced5c43d890a4dfab18ca908b0ec92cbc" memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" @@ -6029,16 +6032,16 @@ style-loader@^0.21.0: loader-utils "^1.1.0" schema-utils "^0.4.5" -styled-components@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.1.3.tgz#4472447208e618b57e84deaaeb6acd34a5e0fe9b" +styled-components@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.2.0.tgz#811fbbec4d64c7189f6c7482b9eb6fefa7fefef7" dependencies: "@babel/helper-module-imports" "^7.0.0" "@emotion/is-prop-valid" "^0.7.3" "@emotion/unitless" "^0.7.0" babel-plugin-styled-components ">= 1" css-to-react-native "^2.2.2" - memoize-one "^4.0.0" + memoize-one "^5.0.0" prop-types "^15.5.4" react-is "^16.6.0" stylis "^3.5.0" From 08db1afce129a9a6e2ef9a361a6adef3a8897c8f Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 19 May 2019 19:40:56 +0900 Subject: [PATCH 26/64] add Select --- frontend/src/components/Forms/Select.tsx | 71 ++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 frontend/src/components/Forms/Select.tsx diff --git a/frontend/src/components/Forms/Select.tsx b/frontend/src/components/Forms/Select.tsx new file mode 100644 index 000000000..e10451287 --- /dev/null +++ b/frontend/src/components/Forms/Select.tsx @@ -0,0 +1,71 @@ +import * as React from "react"; +import styled from "styled-components"; + +// TODO: childrenの型が分からない +export interface ITextInputProps { + children: any; + value?: string; + name?: string; + onChange?(value: string): void; +} + +export default ({ value, name, onChange, children }: ITextInputProps) => { + console.log(typeof children); + const [currentValue, setCurrentValue] = React.useState(value); + const [inFocus, setInFocus] = React.useState(false); + + const handleChange = React.useCallback((e: React.ChangeEvent) => { + const data = e.target.value; + setCurrentValue(data); + console.log(data); + + if (onChange) { + onChange(data); + } + }, []); + + const handleFocus = React.useCallback(() => { + setInFocus(true); + }, []); + + // call: did handleFoucus + const handleBlur = React.useCallback(() => { + setInFocus(false); + }, []); + + React.useEffect( + () => { + if (value != null) { + setCurrentValue(value); + } + }, + [value] + ); + + const props = { + onFocus: handleFocus, + onBlur: handleBlur, + id: name, + value: currentValue, + onChange: handleChange, + styledFocus: inFocus ? true : false + }; + + return {children}; +}; + +// TODO: focus時とそうでない時で背景かアウトラインのデザインを変える +const StyledSelect = styled.select` + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + width: 100%; + line-height: 1.5rem; + padding: 5px; + padding-left: 30px; + border: 2px solid #00afec; + border-radius: 1.5rem; + background: none transparent; + vertical-align: middle; + color: #00afec; +`; From 942ff62b6833ee324dc20fba840ec522036d688f Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 01:05:59 +0900 Subject: [PATCH 27/64] add rows to textarea --- frontend/src/components/ContactForm2.tsx | 117 ++++++++++++++++++++ frontend/src/components/Forms/CheckBox.tsx | 70 ++++++++++++ frontend/src/components/Forms/TextInput.tsx | 2 +- 3 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 frontend/src/components/ContactForm2.tsx create mode 100644 frontend/src/components/Forms/CheckBox.tsx diff --git a/frontend/src/components/ContactForm2.tsx b/frontend/src/components/ContactForm2.tsx new file mode 100644 index 000000000..8af7ccb34 --- /dev/null +++ b/frontend/src/components/ContactForm2.tsx @@ -0,0 +1,117 @@ +import * as React from "react"; +import styled from "styled-components"; + +// import ContactStore from "../stores/ContactStore"; + +// import ChkButtonBase from "../commons/ChkButtonBase"; + +import TextInput from "./Forms/TextInput"; +import Select from "./Forms/Select"; + +// interface IProp { +// contactStore: ContactStore; +// successed: (res: object) => void; +// failed: (res: object) => void; +// } + +// message: string; +// readable: boolean; + +// props: IProp + +export default () => { + // this.createContact = this.createContact.bind(this); + const [name, setName] = React.useState(""); + const [corner, setCorner] = React.useState(""); + const [department, setDepartment] = React.useState(""); + const [grade, setGrade] = React.useState(""); + const [email, setEmail] = React.useState(""); + const [nickname, setNickname] = React.useState(""); + + const [message, setMessage] = React.useState(""); + // const [nickname, setNickname] = React.useState(""); + + return ( +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* */} + + ); +}; + +// public createContact(e: any) { +// e.preventDefault(); + +// const { contactStore } = this.props; +// const contact = contactStore.createContact(this.state); + +// contact.save(this.props.successed, this.props.failed); +// } +// } + +// const ContactFormCheckbox = styled.input` +// margin-left: 20px; +// margin-right: 10px; +// `; + +// const ContactFormButton = styled(ChkButtonBase)``; + +const InlineWrapper = styled.div` + margin: 20px; +`; + +const InlineHalfWrapper = styled.div` + width: 50%; + display: inline-block; +`; diff --git a/frontend/src/components/Forms/CheckBox.tsx b/frontend/src/components/Forms/CheckBox.tsx new file mode 100644 index 000000000..a60b528cd --- /dev/null +++ b/frontend/src/components/Forms/CheckBox.tsx @@ -0,0 +1,70 @@ +import * as React from "react"; +import styled from "styled-components"; + +// TODO: childrenの型が分からない +export interface ITextInputProps { + children: any; + value?: string; + name?: string; + onChange?(value: string): void; +} + +export default ({ value, name, onChange, children }: ITextInputProps) => { + const [currentValue, setCurrentValue] = React.useState(value); + const [inFocus, setInFocus] = React.useState(false); + + const handleChange = React.useCallback((e: React.ChangeEvent) => { + const data = e.target.value; + setCurrentValue(data); + console.log(data); + + if (onChange) { + onChange(data); + } + }, []); + + const handleFocus = React.useCallback(() => { + setInFocus(true); + }, []); + + // call: did handleFoucus + const handleBlur = React.useCallback(() => { + setInFocus(false); + }, []); + + React.useEffect( + () => { + if (value != null) { + setCurrentValue(value); + } + }, + [value] + ); + + const props = { + onFocus: handleFocus, + onBlur: handleBlur, + id: name, + value: currentValue, + onChange: handleChange, + styledFocus: inFocus ? true : false + }; + + return {children}; +}; + +// TODO: focus時とそうでない時で背景かアウトラインのデザインを変える +const StyledSelect = styled.select` + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + width: 100%; + line-height: 1.5rem; + padding: 5px; + padding-left: 30px; + border: 2px solid #00afec; + border-radius: 1.5rem; + background: none transparent; + vertical-align: middle; + color: #00afec; +`; diff --git a/frontend/src/components/Forms/TextInput.tsx b/frontend/src/components/Forms/TextInput.tsx index 2af1ffecf..060c6705c 100644 --- a/frontend/src/components/Forms/TextInput.tsx +++ b/frontend/src/components/Forms/TextInput.tsx @@ -55,7 +55,7 @@ export default ({ value, name, placeholder, multiLine, onChange, type = "text" } styledFocus: inFocus ? true : false }; - return multiLine ? : ; + return multiLine ? : ; }; // TODO: focus時とそうでない時で背景かアウトラインのデザインを変える From 4bc302159df17c152bf9870ed7d0a85b45332476 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 01:22:05 +0900 Subject: [PATCH 28/64] remove console.log --- frontend/src/components/Forms/Select.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/src/components/Forms/Select.tsx b/frontend/src/components/Forms/Select.tsx index e10451287..432735f5d 100644 --- a/frontend/src/components/Forms/Select.tsx +++ b/frontend/src/components/Forms/Select.tsx @@ -10,14 +10,12 @@ export interface ITextInputProps { } export default ({ value, name, onChange, children }: ITextInputProps) => { - console.log(typeof children); const [currentValue, setCurrentValue] = React.useState(value); const [inFocus, setInFocus] = React.useState(false); const handleChange = React.useCallback((e: React.ChangeEvent) => { const data = e.target.value; setCurrentValue(data); - console.log(data); if (onChange) { onChange(data); From 383c812c7f8f305ec5378b2e736b5b8a9e083a2b Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 01:22:25 +0900 Subject: [PATCH 29/64] fix --- frontend/src/components/Forms/CheckBox.tsx | 49 ++++++++++------------ 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/frontend/src/components/Forms/CheckBox.tsx b/frontend/src/components/Forms/CheckBox.tsx index a60b528cd..2fffa8155 100644 --- a/frontend/src/components/Forms/CheckBox.tsx +++ b/frontend/src/components/Forms/CheckBox.tsx @@ -1,22 +1,20 @@ import * as React from "react"; import styled from "styled-components"; -// TODO: childrenの型が分からない export interface ITextInputProps { - children: any; - value?: string; + children: string; + checked: boolean; name?: string; - onChange?(value: string): void; + onChange?(value: boolean): void; } -export default ({ value, name, onChange, children }: ITextInputProps) => { - const [currentValue, setCurrentValue] = React.useState(value); +export default ({ checked, name, onChange, children }: ITextInputProps) => { + const [currentChecked, setCurrentChecked] = React.useState(checked); const [inFocus, setInFocus] = React.useState(false); - const handleChange = React.useCallback((e: React.ChangeEvent) => { - const data = e.target.value; - setCurrentValue(data); - console.log(data); + const handleChange = React.useCallback((e: React.ChangeEvent) => { + const data = e.target.checked; + setCurrentChecked(data); if (onChange) { onChange(data); @@ -34,37 +32,32 @@ export default ({ value, name, onChange, children }: ITextInputProps) => { React.useEffect( () => { - if (value != null) { - setCurrentValue(value); + if (checked !== null) { + setCurrentChecked(checked); } }, - [value] + [checked] ); const props = { onFocus: handleFocus, onBlur: handleBlur, id: name, - value: currentValue, + checked: currentChecked, onChange: handleChange, styledFocus: inFocus ? true : false }; - return {children}; + return ( + + ); }; // TODO: focus時とそうでない時で背景かアウトラインのデザインを変える -const StyledSelect = styled.select` - -moz-appearance: none; - -webkit-appearance: none; - appearance: none; - width: 100%; - line-height: 1.5rem; - padding: 5px; - padding-left: 30px; - border: 2px solid #00afec; - border-radius: 1.5rem; - background: none transparent; - vertical-align: middle; - color: #00afec; +const StyledCheckBox = styled.input` + margin-left: 20px; + margin-right: 10px; `; From 6edda7d5f366ef9ded4b42a381fd6845b5c38aa0 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 01:23:28 +0900 Subject: [PATCH 30/64] fix rule --- frontend/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 82d18fc02..ce9d4f5d6 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -12,6 +12,7 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, "experimentalDecorators": true, "newLine": "LF" }, From c529ffa36f24d8e95ee1c6af710621a4be487b52 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 01:31:33 +0900 Subject: [PATCH 31/64] remove console.log --- frontend/src/components/Forms/TextInput.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/Forms/TextInput.tsx b/frontend/src/components/Forms/TextInput.tsx index 060c6705c..1f3ce85ef 100644 --- a/frontend/src/components/Forms/TextInput.tsx +++ b/frontend/src/components/Forms/TextInput.tsx @@ -19,7 +19,6 @@ export default ({ value, name, placeholder, multiLine, onChange, type = "text" } const handleChange = React.useCallback((e: React.ChangeEvent) => { const data = e.target.value; setCurrentInputValue(data); - console.log(data); if (onChange) { onChange(data); From d99c618654c70b0284a21226b5c58ade825a284a Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 01:31:45 +0900 Subject: [PATCH 32/64] remove id --- frontend/src/models/ContactModel.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/frontend/src/models/ContactModel.ts b/frontend/src/models/ContactModel.ts index 12987dd36..8834be5c8 100644 --- a/frontend/src/models/ContactModel.ts +++ b/frontend/src/models/ContactModel.ts @@ -4,7 +4,6 @@ import ContactStore from "../stores/ContactStore"; export default class ContactModel { public store: ContactStore; - public id: number; public readable: boolean; public corner: number; public message: string; @@ -17,8 +16,7 @@ export default class ContactModel { constructor(store: ContactStore, json: any) { this.store = store; - const { id, readable, corner, message, nickname, name, email, department, grade } = json; - this.id = id; + const { readable, corner, message, nickname, name, email, department, grade } = json; this.readable = readable; this.corner = corner; this.message = message; @@ -36,9 +34,8 @@ export default class ContactModel { @computed get toJson() { - const { id, readable, corner, message, nickname, name, email, department, grade } = this; + const { readable, corner, message, nickname, name, email, department, grade } = this; return { - id, readable, corner, message, From a7b484141267ed1b510706067b1b9c689d4a6d66 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 01:33:02 +0900 Subject: [PATCH 33/64] fix --- frontend/src/components/ContactForm.tsx | 282 +++++++---------------- frontend/src/components/ContactForm2.tsx | 117 ---------- frontend/src/entries/Contact.tsx | 19 +- 3 files changed, 99 insertions(+), 319 deletions(-) delete mode 100644 frontend/src/components/ContactForm2.tsx diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index d47e39c18..da318b19f 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -1,79 +1,68 @@ import * as React from "react"; import styled from "styled-components"; + import ContactStore from "../stores/ContactStore"; + import ChkButtonBase from "../commons/ChkButtonBase"; +import TextInput from "./Forms/TextInput"; +import Select from "./Forms/Select"; +import CheckBox from "./Forms/CheckBox"; + interface IProp { contactStore: ContactStore; successed: (res: object) => void; failed: (res: object) => void; } -interface IState { - name: string; - corner?: number; - department?: number; - grade?: number; - email: string; - nickname: string; - message: string; - readable: boolean; -} +export default (props: IProp) => { + const [name, setName] = React.useState(""); + const [corner, setCorner] = React.useState(""); + const [department, setDepartment] = React.useState(""); + const [grade, setGrade] = React.useState(""); + const [email, setEmail] = React.useState(""); + const [nickname, setNickname] = React.useState(""); + + const [message, setMessage] = React.useState(""); + const [readable, setReadable] = React.useState(false); -export default class ContactForm extends React.Component { - constructor(props: IProp) { - super(props); - this.state = { - name: "", - corner: undefined, - department: undefined, - grade: undefined, - email: "", - nickname: "", - message: "", - readable: false - }; - - this.createContact = this.createContact.bind(this); - } - - public render() { - return ( -
- - this.setState({ name: e.target.value })} - /> - - - - this.setState({ - corner: e.target.value - }) - } - required - > - - - - - - - - - this.setState({ department: e.target.value })} - required - > + const createContact = (e: any) => { + e.preventDefault(); + + const { contactStore } = props; + const contact = contactStore.createContact({ + name, + corner, + department, + grade, + email, + nickname, + message, + readable + }); + + contact.save(props.successed, props.failed); + }; + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ラジオ内でメッセージを読み上げてもいい場合はチェックをつけてください + + + + + + ); +}; + +const InlineWrapper = styled.div` margin: 20px; `; -const ContactFormInput = styled.input` - margin: 5px; - margin-left: 0; - margin-right: 0; - padding: 5px; - padding-left: 30px; - line-height: 1.5rem; - width: 100%; - border: 2px solid #00afec; - border-radius: 1.5rem; - - ::placeholder { - color: #00afec; - opacity: 1; - } - ::-ms-input-placeholder { - color: #00afec; - } -`; - -const ContactFormSelect = styled.select` - -moz-appearance: none; - -webkit-appearance: none; - appearance: none; - width: 100%; - line-height: 1.5rem; - padding: 5px; - padding-left: 30px; - border: 2px solid #00afec; - border-radius: 1.5rem; - background: none transparent; - vertical-align: middle; - color: #00afec; -`; - -const ContactFormSelectHalf = styled(ContactFormSelect)` +const InlineHalfWrapper = styled.div` width: 50%; -`; - -const ContactFormTextarea = styled.textarea` - margin: 5px; - margin-left: 0; - margin-right: 0; - padding: 5px; - padding-left: 30px; - line-height: 1.5rem; - width: 100%; - border: 2px solid #00afec; - border-radius: 1.5rem; - - ::placeholder { - color: #00afec; - opacity: 1; - } - ::-ms-input-placeholder { - color: #00afec; - } -`; - -const ContactFormCheckbox = styled.input` - margin-left: 20px; - margin-right: 10px; + display: inline-block; `; const ContactFormButton = styled(ChkButtonBase)``; diff --git a/frontend/src/components/ContactForm2.tsx b/frontend/src/components/ContactForm2.tsx deleted file mode 100644 index 8af7ccb34..000000000 --- a/frontend/src/components/ContactForm2.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import * as React from "react"; -import styled from "styled-components"; - -// import ContactStore from "../stores/ContactStore"; - -// import ChkButtonBase from "../commons/ChkButtonBase"; - -import TextInput from "./Forms/TextInput"; -import Select from "./Forms/Select"; - -// interface IProp { -// contactStore: ContactStore; -// successed: (res: object) => void; -// failed: (res: object) => void; -// } - -// message: string; -// readable: boolean; - -// props: IProp - -export default () => { - // this.createContact = this.createContact.bind(this); - const [name, setName] = React.useState(""); - const [corner, setCorner] = React.useState(""); - const [department, setDepartment] = React.useState(""); - const [grade, setGrade] = React.useState(""); - const [email, setEmail] = React.useState(""); - const [nickname, setNickname] = React.useState(""); - - const [message, setMessage] = React.useState(""); - // const [nickname, setNickname] = React.useState(""); - - return ( -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {/* */} - - ); -}; - -// public createContact(e: any) { -// e.preventDefault(); - -// const { contactStore } = this.props; -// const contact = contactStore.createContact(this.state); - -// contact.save(this.props.successed, this.props.failed); -// } -// } - -// const ContactFormCheckbox = styled.input` -// margin-left: 20px; -// margin-right: 10px; -// `; - -// const ContactFormButton = styled(ChkButtonBase)``; - -const InlineWrapper = styled.div` - margin: 20px; -`; - -const InlineHalfWrapper = styled.div` - width: 50%; - display: inline-block; -`; diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index d17b58aeb..3afecce80 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -7,12 +7,13 @@ import { HeroArea } from "../components/HeroArea"; import { ContactHeroContent } from "../components/ContactHeroContent"; import { inject } from "../../node_modules/mobx-react"; import RootStore from "../stores/RootStore"; -import ContactForm from "../components/ContactForm"; +import ContactForm from "../components/ContactForm2"; -interface Prop { +interface IProp { rootStore?: RootStore; } -interface State { + +interface IState { alert: { message: string; status?: string; @@ -20,8 +21,8 @@ interface State { } @inject("rootStore") -export default class Contact extends React.Component { - constructor(props: Prop) { +export default class Contact extends React.Component { + constructor(props: any) { super(props); this.state = { alert: { @@ -57,11 +58,15 @@ export default class Contact extends React.Component { } public successSendContact(_: object) { - this.setState({ alert: { status: "successed", message: "おたよりを送信しました。" } }); + this.setState({ + alert: { status: "successed", message: "おたよりを送信しました。" } + }); } public failSendContact(_: object) { - this.setState({ alert: { status: "failed", message: "おたよりの送信に失敗しました。" } }); + this.setState({ + alert: { status: "failed", message: "おたよりの送信に失敗しました。" } + }); } } From 5917d9ab9120fee329edf6417cfbbb6d2ce3b31d Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 01:34:09 +0900 Subject: [PATCH 34/64] fix --- frontend/src/components/ContactForm.tsx | 1 + frontend/src/entries/Contact.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index da318b19f..bc2b4078a 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -44,6 +44,7 @@ export default (props: IProp) => { contact.save(props.successed, props.failed); }; + // TODO(euglena1215): requiredの*をべた書きで書かなくてもいいようにする return (
diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index 3afecce80..fa74cd172 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -1,13 +1,14 @@ import * as React from "react"; import styled from "styled-components"; +import { inject } from "mobx-react"; + +import RootStore from "../stores/RootStore"; import { media } from "../commons/style"; import { HeroArea } from "../components/HeroArea"; import { ContactHeroContent } from "../components/ContactHeroContent"; -import { inject } from "../../node_modules/mobx-react"; -import RootStore from "../stores/RootStore"; -import ContactForm from "../components/ContactForm2"; +import ContactForm from "../components/ContactForm"; interface IProp { rootStore?: RootStore; @@ -38,7 +39,6 @@ export default class Contact extends React.Component { public render() { const rootStore = this.props.rootStore!; - // TODO(euglena1215): requiredの*をべた書きで書かなくてもいいようにする return (
} /> From 5c21bdd7cc7a26917950330be37d8fb584662c07 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 02:15:34 +0900 Subject: [PATCH 35/64] add message --- frontend/src/components/ContactForm.tsx | 155 +++++++++++++++--------- frontend/src/entries/Contact.tsx | 9 +- 2 files changed, 102 insertions(+), 62 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index bc2b4078a..427312e2a 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -13,6 +13,10 @@ interface IProp { contactStore: ContactStore; successed: (res: object) => void; failed: (res: object) => void; + alert: { + message: string; + status?: string; + }; } export default (props: IProp) => { @@ -46,67 +50,80 @@ export default (props: IProp) => { // TODO(euglena1215): requiredの*をべた書きで書かなくてもいいようにする return ( - - - - - - - - - - - - - - - + + + + + - - - - - - - - - - - - - - - - - - ラジオ内でメッセージを読み上げてもいい場合はチェックをつけてください - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + ラジオ内でメッセージを読み上げてもいい場合はチェックをつけてください + + + + + + ); }; @@ -120,3 +137,21 @@ const InlineHalfWrapper = styled.div` `; const ContactFormButton = styled(ChkButtonBase)``; + +const AlertBar = styled.div` + width: 80%; + margin: 10px auto; + line-height: 1.5rem; + padding: 5px; + border-radius: 1.5rem; + vertical-align: middle; + text-align: center; +`; + +const SuccessedAlertBar = styled(AlertBar)` + background-color: #c9ecd4; +`; + +const FailedAlertBar = styled(AlertBar)` + background-color: #ff9494; +`; diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index fa74cd172..e6bc4d23a 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -1,5 +1,6 @@ import * as React from "react"; import styled from "styled-components"; +import { withRouter, RouteComponentProps } from "react-router-dom"; import { inject } from "mobx-react"; import RootStore from "../stores/RootStore"; @@ -22,7 +23,7 @@ interface IState { } @inject("rootStore") -export default class Contact extends React.Component { +class Contact extends React.Component { constructor(props: any) { super(props); this.state = { @@ -50,6 +51,7 @@ export default class Contact extends React.Component { contactStore={rootStore.contactStore} successed={this.successSendContact} failed={this.failSendContact} + alert={this.state.alert} />
@@ -59,8 +61,9 @@ export default class Contact extends React.Component { public successSendContact(_: object) { this.setState({ - alert: { status: "successed", message: "おたよりを送信しました。" } + alert: { status: "successed", message: "おたよりを送信しました。 5秒後に自動でトップページに戻ります。" } }); + setTimeout(() => console.log(this.props.history.push("/")), 5000); } public failSendContact(_: object) { @@ -94,3 +97,5 @@ const ContactFormTitle = styled.div` text-align: center; color: #00afec; `; + +export default withRouter(Contact); From 00a26a5a037b8123f9ab2ea2b48740bae52b6a0f Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 18:11:18 +0900 Subject: [PATCH 36/64] fix successed & failed design --- frontend/src/components/ContactForm.tsx | 18 ++++++++++++------ frontend/src/entries/Contact.tsx | 5 ++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index 427312e2a..e63861795 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -136,22 +136,28 @@ const InlineHalfWrapper = styled.div` display: inline-block; `; -const ContactFormButton = styled(ChkButtonBase)``; +const ContactFormButton = styled(ChkButtonBase)` + width: 40%; + margin: 0 auto; +`; const AlertBar = styled.div` - width: 80%; + width: 100%; margin: 10px auto; - line-height: 1.5rem; + line-height: 1rem; padding: 5px; - border-radius: 1.5rem; vertical-align: middle; + border: 3px solid #000; + color: #000; text-align: center; `; const SuccessedAlertBar = styled(AlertBar)` - background-color: #c9ecd4; + border: 3px solid #3ed986; + color: #000; `; const FailedAlertBar = styled(AlertBar)` - background-color: #ff9494; + border: 3px solid #d95f3f; + color: #d95f3f; `; diff --git a/frontend/src/entries/Contact.tsx b/frontend/src/entries/Contact.tsx index e6bc4d23a..189c77d06 100644 --- a/frontend/src/entries/Contact.tsx +++ b/frontend/src/entries/Contact.tsx @@ -68,7 +68,10 @@ class Contact extends React.Component { public failSendContact(_: object) { this.setState({ - alert: { status: "failed", message: "おたよりの送信に失敗しました。" } + alert: { + status: "failed", + message: "おたよりの送信に失敗しました。 * がついている項目は全て記入して再送信してください。" + } }); } } From ce242056d70b2ab26b2e11d04d15d0e7473b1fd5 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 18:28:15 +0900 Subject: [PATCH 37/64] fix props no always needed --- frontend/src/api/RestClient.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/api/RestClient.ts b/frontend/src/api/RestClient.ts index 2d26f41cd..eb11bf5fc 100644 --- a/frontend/src/api/RestClient.ts +++ b/frontend/src/api/RestClient.ts @@ -18,9 +18,9 @@ export default class RestClient { public get( path: string, - params: object, - successed: (res: object) => void, - errored: (res: object) => void, + params?: object, + successed?: (res: object) => void, + errored?: (res: object) => void, always: () => any = () => {} ) { return this.axios @@ -29,13 +29,13 @@ export default class RestClient { console.log(`GET ${result.config.url}`); if (params) console.table(params); console.log(`status: ${result.status}, statusText: ${result.statusText}`); - successed(result); + if (successed) successed(result); }) .catch((error: AxiosError) => { console.log(`ERROR! GET ${error.config.url}`); if (params) console.table(params); console.log(`error: ${JSON.stringify(error)}`); - errored(error); + if (errored) errored(error); }) .then(always()); } From 821969ece6ac9013de49ac1c11a2c84992a56d80 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Mon, 20 May 2019 18:28:32 +0900 Subject: [PATCH 38/64] add fetchContactEnum --- frontend/src/api/ContactApi.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/api/ContactApi.ts b/frontend/src/api/ContactApi.ts index 73e410379..bdcb697d0 100644 --- a/frontend/src/api/ContactApi.ts +++ b/frontend/src/api/ContactApi.ts @@ -15,4 +15,8 @@ export default class ContactApi { ) { return this.restClient.post("/api/v1/contacts", json, succussed, errored, always); } + + public fetchContactEnum() { + return this.restClient.get("/api/v1/contacts/enum"); + } } From 5e4173cc54031957cc4bd8eb0c0f1810171931a7 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Tue, 21 May 2019 03:07:09 +0900 Subject: [PATCH 39/64] use axios.interceptors.response --- frontend/src/api/RestClient.ts | 47 +++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/frontend/src/api/RestClient.ts b/frontend/src/api/RestClient.ts index eb11bf5fc..c9809c248 100644 --- a/frontend/src/api/RestClient.ts +++ b/frontend/src/api/RestClient.ts @@ -14,9 +14,27 @@ export default class RestClient { "X-CSRF-TOKEN": csrfToken } }); + + this.axios.interceptors.response.use( + response => { + const { config, data, status } = response; + const { method, params, url } = config; + + console.group(`${method ? method.toUpperCase() : "undefined method"}:${status} - ${url}`); + if (params) console.table(params); + console.log(data); + console.groupEnd(); + + return response; + }, + error => { + console.log(error); + return Promise.reject(error); + } + ); } - public get( + public get( path: string, params?: object, successed?: (res: object) => void, @@ -25,19 +43,18 @@ export default class RestClient { ) { return this.axios .get(path, { params }) - .then((result: AxiosResponse) => { - console.log(`GET ${result.config.url}`); - if (params) console.table(params); - console.log(`status: ${result.status}, statusText: ${result.statusText}`); + .then((result: AxiosResponse) => { if (successed) successed(result); + return result; }) .catch((error: AxiosError) => { - console.log(`ERROR! GET ${error.config.url}`); - if (params) console.table(params); - console.log(`error: ${JSON.stringify(error)}`); if (errored) errored(error); }) - .then(always()); + .then(result => { + always(); + if (result) return result.data; + return result; + }); } public post( @@ -50,15 +67,9 @@ export default class RestClient { return this.axios .post(path, params) .then((result: AxiosResponse) => { - console.log(`POST ${result.config.url}`); - if (params) console.table(params); - console.log(`status: ${result.status}, statusText: ${result.statusText}`); successed(result); }) .catch((error: AxiosError) => { - console.log(`ERROR! POST ${error.config.url}`); - if (params) console.table(params); - console.log(`error: ${error}`); errored(error); }) .then(always()); @@ -74,15 +85,9 @@ export default class RestClient { return this.axios .delete(path, { data: { params } }) .then((result: AxiosResponse) => { - console.log(`DELETE ${result.config.url}`); - if (params) console.table(params); - console.log(`status: ${result.status}, statusText: ${result.statusText}`); successed(result); }) .catch((error: AxiosError) => { - console.log(`ERROR! DELETE ${error.config.url}`); - if (params) console.table(params); - console.log(`error: ${error}`); errored(error); }) .then(always()); From a44a6e567fe82bfc19b043d45d1d0370426123e7 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Tue, 21 May 2019 03:07:33 +0900 Subject: [PATCH 40/64] add type --- frontend/src/api/ContactApi.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/src/api/ContactApi.ts b/frontend/src/api/ContactApi.ts index bdcb697d0..5bdd9338b 100644 --- a/frontend/src/api/ContactApi.ts +++ b/frontend/src/api/ContactApi.ts @@ -1,5 +1,11 @@ import RestClient from "./RestClient"; +export interface IContactEnum { + corners: { [key: string]: number }; + departments: { [key: string]: number }; + grades: { [key: string]: number }; +} + export default class ContactApi { public restClient: RestClient; @@ -17,6 +23,6 @@ export default class ContactApi { } public fetchContactEnum() { - return this.restClient.get("/api/v1/contacts/enum"); + return this.restClient.get("/api/v1/contacts/enum"); } } From c6cdd39760de62aa9bb3645fcdfca6913535bd8e Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 23 May 2019 15:40:47 +0900 Subject: [PATCH 41/64] add mobx-react-lite --- frontend/package.json | 1 + frontend/yarn.lock | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/frontend/package.json b/frontend/package.json index 49f14dc29..edcfb9018 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -43,6 +43,7 @@ "babel-polyfill": "^6.26.0", "mobx": "^5.9.4", "mobx-react": "^5.4.4", + "mobx-react-lite": "^1.3.2", "normalize.css": "^8.0.0", "react": "^16.8.6", "react-dom": "^16.8.6", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index eac4b0815..3905a8a84 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -4144,6 +4144,10 @@ mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: dependencies: minimist "0.0.8" +mobx-react-lite@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-1.3.2.tgz#4366048b5d283d12a82053367638b5d79281951f" + mobx-react@^5.4.4: version "5.4.4" resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-5.4.4.tgz#b3de9c6eabcd0ed8a40036888cb0221ab9568b80" From 6f1a8d239fee11c9464e166f816cca951db1e9a3 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 23 May 2019 23:28:02 +0900 Subject: [PATCH 42/64] add CircleSpinner --- .../src/components/Spinners/CircleSpinner.tsx | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 frontend/src/components/Spinners/CircleSpinner.tsx diff --git a/frontend/src/components/Spinners/CircleSpinner.tsx b/frontend/src/components/Spinners/CircleSpinner.tsx new file mode 100644 index 000000000..4e3d92cff --- /dev/null +++ b/frontend/src/components/Spinners/CircleSpinner.tsx @@ -0,0 +1,46 @@ +import * as React from "react"; +import styled, { keyframes } from "styled-components"; + +import { chkColors } from "../../commons/color"; + +interface IProps { + size?: number; + color?: string; + isLoading?: boolean; +} + +export default ({ size = 35, color = chkColors.blue, isLoading = true }: IProps) => { + console.log(size); + console.log(color); + + return isLoading ? ( + + + + ) : null; +}; + +const Wrapper = styled.div` + display: flex; + justify-content: center; + align-items: center; +`; + +const clip = keyframes` + 0% {transform: rotate(0deg) scale(1)} + 50% {transform: rotate(180deg) scale(0.8)} + 100% {transform: rotate(360deg) scale(1)} +`; + +const StyledSpinner = styled.div` + background: transparent !important; + width: ${(props: IProps) => `${props.size}px`}; + height: ${(props: IProps) => `${props.size}px`}; + border-radius: 100%; + border: 2px solid; + border-color: ${(props: IProps) => props.color}; + border-bottom-color: transparent; + display: inline-block; + animation: ${clip} 1.3s 0s infinite linear; + animation-fill-mode: both; +`; From fd558584ba2a1c2397831e1d34aa6abe0d8ca516 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 23 May 2019 23:35:57 +0900 Subject: [PATCH 43/64] remove commnet --- frontend/src/components/Spinners/CircleSpinner.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/frontend/src/components/Spinners/CircleSpinner.tsx b/frontend/src/components/Spinners/CircleSpinner.tsx index 4e3d92cff..1cf3a064d 100644 --- a/frontend/src/components/Spinners/CircleSpinner.tsx +++ b/frontend/src/components/Spinners/CircleSpinner.tsx @@ -10,9 +10,6 @@ interface IProps { } export default ({ size = 35, color = chkColors.blue, isLoading = true }: IProps) => { - console.log(size); - console.log(color); - return isLoading ? ( From 01405c49fa6da656de417ae783ddb5f31587d1f8 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 23 May 2019 23:37:44 +0900 Subject: [PATCH 44/64] add optionsElements --- frontend/src/components/Forms/Select.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/Forms/Select.tsx b/frontend/src/components/Forms/Select.tsx index 432735f5d..5e77e3b64 100644 --- a/frontend/src/components/Forms/Select.tsx +++ b/frontend/src/components/Forms/Select.tsx @@ -3,13 +3,14 @@ import styled from "styled-components"; // TODO: childrenの型が分からない export interface ITextInputProps { - children: any; + children?: any; value?: string; name?: string; + optionElements?: { [key: string]: string | number }; onChange?(value: string): void; } -export default ({ value, name, onChange, children }: ITextInputProps) => { +export default ({ value, name, optionElements, onChange, children }: ITextInputProps) => { const [currentValue, setCurrentValue] = React.useState(value); const [inFocus, setInFocus] = React.useState(false); @@ -49,7 +50,12 @@ export default ({ value, name, onChange, children }: ITextInputProps) => { styledFocus: inFocus ? true : false }; - return {children}; + return ( + + {children && children} + {optionElements && Object.keys(optionElements).map(v => )} + + ); }; // TODO: focus時とそうでない時で背景かアウトラインのデザインを変える From a128a17ea49e467ee5413bdbfbcd9c422d555a2a Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 23 May 2019 23:51:31 +0900 Subject: [PATCH 45/64] set key for map --- frontend/src/components/Forms/Select.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/Forms/Select.tsx b/frontend/src/components/Forms/Select.tsx index 5e77e3b64..b69abe94b 100644 --- a/frontend/src/components/Forms/Select.tsx +++ b/frontend/src/components/Forms/Select.tsx @@ -53,7 +53,12 @@ export default ({ value, name, optionElements, onChange, children }: ITextInputP return ( {children && children} - {optionElements && Object.keys(optionElements).map(v => )} + {optionElements && + Object.keys(optionElements).map(v => ( + + ))} ); }; From 050dba4d7c09c414e4eea991c3f805b17ad227c4 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 23 May 2019 23:52:25 +0900 Subject: [PATCH 46/64] rewrite by react hooks --- frontend/src/components/ContactForm.tsx | 55 ++++++++++++++----------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index e63861795..c668570f1 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -1,5 +1,6 @@ import * as React from "react"; import styled from "styled-components"; +import { observer } from "mobx-react-lite"; import ContactStore from "../stores/ContactStore"; @@ -9,6 +10,8 @@ import TextInput from "./Forms/TextInput"; import Select from "./Forms/Select"; import CheckBox from "./Forms/CheckBox"; +import CircleSpinner from "./Spinners/CircleSpinner"; + interface IProp { contactStore: ContactStore; successed: (res: object) => void; @@ -19,7 +22,14 @@ interface IProp { }; } -export default (props: IProp) => { +export default observer((props: IProp) => { + const { contactStore } = props; + const { contactEnum } = contactStore; + + React.useEffect(() => { + contactStore.fetchContactEnum(); + }, []); + const [name, setName] = React.useState(""); const [corner, setCorner] = React.useState(""); const [department, setDepartment] = React.useState(""); @@ -33,7 +43,6 @@ export default (props: IProp) => { const createContact = (e: any) => { e.preventDefault(); - const { contactStore } = props; const contact = contactStore.createContact({ name, corner, @@ -49,7 +58,7 @@ export default (props: IProp) => { }; // TODO(euglena1215): requiredの*をべた書きで書かなくてもいいようにする - return ( + return contactEnum ? ( <> {props.alert.status === "successed" && ( @@ -68,37 +77,25 @@ export default (props: IProp) => {
- - - - - - - - - - - - - - - - - - - - @@ -112,7 +109,13 @@ export default (props: IProp) => { - + @@ -124,8 +127,10 @@ export default (props: IProp) => { + ) : ( + ); -}; +}); const InlineWrapper = styled.div` margin: 20px; From da05e1644df146e18fae999437afe98266d23eb4 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Fri, 24 May 2019 00:07:08 +0900 Subject: [PATCH 47/64] fix --- frontend/package.json | 2 +- frontend/src/api/RestClient.ts | 83 +++++++++++++++++----------------- frontend/yarn.lock | 24 ++++++---- 3 files changed, 56 insertions(+), 53 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index edcfb9018..e237458d8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -39,7 +39,7 @@ "webpack-merge": "^4.1.4" }, "dependencies": { - "axios": "^0.18.0", + "axios": "0.19.0-beta.1", "babel-polyfill": "^6.26.0", "mobx": "^5.9.4", "mobx-react": "^5.4.4", diff --git a/frontend/src/api/RestClient.ts b/frontend/src/api/RestClient.ts index c9809c248..0092f26a4 100644 --- a/frontend/src/api/RestClient.ts +++ b/frontend/src/api/RestClient.ts @@ -1,4 +1,4 @@ -import axios, { AxiosInstance, AxiosResponse, AxiosError } from "axios"; +import axios, { AxiosInstance } from "axios"; export default class RestClient { public axios: AxiosInstance; @@ -15,6 +15,7 @@ export default class RestClient { } }); + // TODO: Productionではログを流さないようにする this.axios.interceptors.response.use( response => { const { config, data, status } = response; @@ -34,62 +35,60 @@ export default class RestClient { ); } - public get( + public async get( path: string, params?: object, successed?: (res: object) => void, errored?: (res: object) => void, always: () => any = () => {} ) { - return this.axios - .get(path, { params }) - .then((result: AxiosResponse) => { - if (successed) successed(result); - return result; - }) - .catch((error: AxiosError) => { - if (errored) errored(error); - }) - .then(result => { - always(); - if (result) return result.data; - return result; - }); + try { + const response = await this.axios.get(path, { params }); + if (successed) successed(response); + return response; + } catch (error) { + if (errored) errored(error); + throw error; + } finally { + always(); + } } - public post( + public async post( path: string, - params: object, - successed: (res: object) => void, - errored: (res: object) => void, + params?: object, + successed?: (res: object) => void, + errored?: (res: object) => void, always: () => any = () => {} ) { - return this.axios - .post(path, params) - .then((result: AxiosResponse) => { - successed(result); - }) - .catch((error: AxiosError) => { - errored(error); - }) - .then(always()); + try { + const response = await this.axios.post(path, params); + if (successed) successed(response); + return response; + } catch (error) { + if (errored) errored(error); + throw error; + } finally { + always(); + } } - public delete( + public async delete( path: string, - params: object, - successed: (res: object) => void, - errored: (res: object) => void, + params?: object, + successed?: (res: object) => void, + errored?: (res: object) => void, always: () => any = () => {} ) { - return this.axios - .delete(path, { data: { params } }) - .then((result: AxiosResponse) => { - successed(result); - }) - .catch((error: AxiosError) => { - errored(error); - }) - .then(always()); + try { + const response = await this.axios.delete(path, { data: { params } }); + if (successed) successed(response); + return response; + } catch (error) { + if (errored) errored(error); + throw error; + } finally { + always(); + } } } diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 3905a8a84..b9ccf8e4a 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -480,12 +480,12 @@ awesome-typescript-loader@^5.0.0: source-map-support "^0.5.3" webpack-log "^1.2.0" -axios@^0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102" +axios@0.19.0-beta.1: + version "0.19.0-beta.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0-beta.1.tgz#3d6a9ee75885d1fd39e108df9a4fb2e48e1af1e8" dependencies: - follow-redirects "^1.3.0" - is-buffer "^1.1.5" + follow-redirects "^1.4.1" + is-buffer "^2.0.2" babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" @@ -2000,7 +2000,7 @@ debug@=3.1.0, debug@^3.1.0: dependencies: ms "2.0.0" -debug@^3.2.5: +debug@^3.2.5, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" dependencies: @@ -2660,11 +2660,11 @@ follow-redirects@^1.0.0: dependencies: debug "=3.1.0" -follow-redirects@^1.3.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.1.tgz#67a8f14f5a1f67f962c2c46469c79eaec0a90291" +follow-redirects@^1.4.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" dependencies: - debug "^3.1.0" + debug "^3.2.6" for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" @@ -3308,6 +3308,10 @@ is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" +is-buffer@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" + is-builtin-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" From 92cae4132ec5c54b38ba0d03b6cfb0bfdf1b2669 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Fri, 24 May 2019 00:08:40 +0900 Subject: [PATCH 48/64] add ContactEnum --- frontend/src/stores/ContactStore.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/frontend/src/stores/ContactStore.ts b/frontend/src/stores/ContactStore.ts index 0648be0c7..3f9ebaf55 100644 --- a/frontend/src/stores/ContactStore.ts +++ b/frontend/src/stores/ContactStore.ts @@ -1,7 +1,11 @@ -import ContactApi from "../api/ContactApi"; +import { action, observable } from "mobx"; + +import ContactApi, { IContactEnum } from "../api/ContactApi"; import ContactModel from "../models/ContactModel"; export default class ContactStore { + @observable public contactEnum?: IContactEnum; + public transportLayer: ContactApi; constructor(transportLayer: ContactApi) { @@ -11,4 +15,13 @@ export default class ContactStore { public createContact(json: object) { return new ContactModel(this, json); } + + public async fetchContactEnum() { + const enums = await this.transportLayer.fetchContactEnum(); + this.setContactEnum(enums.data); + } + + @action public setContactEnum(enums: any) { + this.contactEnum = enums; + } } From 081ca80c9af835c331f435ab2454522bccb72c1c Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Fri, 24 May 2019 00:09:18 +0900 Subject: [PATCH 49/64] fix comment --- frontend/src/components/ContactForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index c668570f1..295b05b76 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -57,7 +57,7 @@ export default observer((props: IProp) => { contact.save(props.successed, props.failed); }; - // TODO(euglena1215): requiredの*をべた書きで書かなくてもいいようにする + // TODO(euglena1215): validationをつける return contactEnum ? ( <> {props.alert.status === "successed" && ( From b9909b37c596c5278c87dc4bd941beccd97e120f Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 30 May 2019 21:58:22 +0900 Subject: [PATCH 50/64] create validation methods --- frontend/src/utils/validation.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 frontend/src/utils/validation.ts diff --git a/frontend/src/utils/validation.ts b/frontend/src/utils/validation.ts new file mode 100644 index 000000000..c2157457e --- /dev/null +++ b/frontend/src/utils/validation.ts @@ -0,0 +1,30 @@ +const EMAIL_REGEXP = /^([\w])+([\w\._-])*@([\w_-])+\.([\w\._-]+)+$/; + +export interface IValidationResult { + validity: boolean; + errorMessage?: string; +} + +export const notValidate = (_?: any) => { + return { + validity: true + }; +}; + +export const validateEmail = (email: string): IValidationResult => { + if (!email) { + return { + validity: false, + errorMessage: "メールアドレスを入力してください。" + }; + } + if (!EMAIL_REGEXP.test(email)) { + return { + validity: false, + errorMessage: "有効なメールアドレスではありません。" + }; + } + return { validity: true }; +}; + +export type ValidationMethods = typeof validateEmail | typeof notValidate; From 74aa2916f38d2a14f61d44b22a66298c81c271e4 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 30 May 2019 22:02:11 +0900 Subject: [PATCH 51/64] add error color --- frontend/src/commons/color.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/commons/color.ts b/frontend/src/commons/color.ts index 7e3e19c6c..54a09b53b 100644 --- a/frontend/src/commons/color.ts +++ b/frontend/src/commons/color.ts @@ -12,5 +12,6 @@ export const chkColors: IColor = { white: "#ffffff", placeholder: "#b0bec5", aqua: "#b3dfe2", - darkenAqua: "#50AAB7" + darkenAqua: "#50AAB7", + error: "#ff4b42" }; From aef420723629d9306c34f0340ffef3b1a6552f11 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 30 May 2019 22:03:10 +0900 Subject: [PATCH 52/64] add validation: email --- frontend/src/components/ContactForm.tsx | 10 ++++- frontend/src/components/Forms/TextInput.tsx | 50 +++++++++++++++++++-- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index 295b05b76..6990bacf3 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -6,6 +6,8 @@ import ContactStore from "../stores/ContactStore"; import ChkButtonBase from "../commons/ChkButtonBase"; +import { validateEmail } from "../utils/validation"; + import TextInput from "./Forms/TextInput"; import Select from "./Forms/Select"; import CheckBox from "./Forms/CheckBox"; @@ -101,7 +103,13 @@ export default observer((props: IProp) => { - + diff --git a/frontend/src/components/Forms/TextInput.tsx b/frontend/src/components/Forms/TextInput.tsx index 1f3ce85ef..a524ac967 100644 --- a/frontend/src/components/Forms/TextInput.tsx +++ b/frontend/src/components/Forms/TextInput.tsx @@ -1,6 +1,9 @@ import * as React from "react"; import styled, { css } from "styled-components"; +import { chkColors } from "../../commons/color"; +import { IValidationResult, ValidationMethods, notValidate } from "../../utils/validation"; + type TextInputType = "text" | "password" | "email"; export interface ITextInputProps { @@ -9,11 +12,21 @@ export interface ITextInputProps { placeholder?: string; type?: TextInputType; multiLine?: boolean; + validation?: ValidationMethods; onChange?(value: string): void; } -export default ({ value, name, placeholder, multiLine, onChange, type = "text" }: ITextInputProps) => { +export default ({ + value, + name, + placeholder, + multiLine, + onChange, + validation = notValidate, + type = "text" +}: ITextInputProps) => { const [currentInputValue, setCurrentInputValue] = React.useState(""); + const [validationResult, setValidationResult] = React.useState({ validity: true } as IValidationResult); const [inFocus, setInFocus] = React.useState(false); const handleChange = React.useCallback((e: React.ChangeEvent) => { @@ -25,6 +38,16 @@ export default ({ value, name, placeholder, multiLine, onChange, type = "text" } } }, []); + React.useEffect( + () => { + if (validation) { + if (!currentInputValue) return; + setValidationResult(validation(currentInputValue)); + } + }, + [currentInputValue] + ); + const handleFocus = React.useCallback(() => { setInFocus(true); }, []); @@ -51,10 +74,25 @@ export default ({ value, name, placeholder, multiLine, onChange, type = "text" } id: name, value: currentInputValue, onChange: handleChange, - styledFocus: inFocus ? true : false + styledFocus: inFocus ? true : false, + validationResult: validationResult.validity }; - return multiLine ? : ; + return ( +
+ {multiLine ? ( + <> + + {validationResult && validationResult.validity ? null : {validationResult.errorMessage}} + + ) : ( + <> + + {validationResult && validationResult.validity ? null : {validationResult.errorMessage}} + + )} +
+ ); }; // TODO: focus時とそうでない時で背景かアウトラインのデザインを変える @@ -66,7 +104,7 @@ const style = css` padding-left: 30px; line-height: 1.5rem; width: 100%; - border: 2px solid #00afec; + border: 2px solid ${(props: any) => (props.validationResult ? "#00afec" : chkColors.error)}; border-radius: 1.5rem; ::placeholder { @@ -76,6 +114,10 @@ const style = css` ::-ms-input-placeholder { color: #00afec; } + + &:-webkit-autofill { + box-shadow: 0 0 0 1000px #fff inset; + } `; const StyledInput = styled.input` From 182d42472eed278b6e73b022d523b0e75f6895e9 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 30 May 2019 22:07:10 +0900 Subject: [PATCH 53/64] cannot select placefolder options --- frontend/src/components/ContactForm.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index 6990bacf3..0ddd44ae9 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -80,7 +80,9 @@ export default observer((props: IProp) => { @@ -92,12 +94,16 @@ export default observer((props: IProp) => { value={department} optionElements={contactEnum.departments} > - +
From b7cd0f25632b685e41ab8cc631992f262e8aa6bb Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 30 May 2019 22:49:47 +0900 Subject: [PATCH 54/64] fix --- frontend/src/components/Forms/TextInput.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Forms/TextInput.tsx b/frontend/src/components/Forms/TextInput.tsx index a524ac967..dc78d8e3f 100644 --- a/frontend/src/components/Forms/TextInput.tsx +++ b/frontend/src/components/Forms/TextInput.tsx @@ -45,7 +45,7 @@ export default ({ setValidationResult(validation(currentInputValue)); } }, - [currentInputValue] + [currentInputValue, inFocus] ); const handleFocus = React.useCallback(() => { From 84417e1e825bf390dcfc9dd3add051f5c8167732 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 30 May 2019 23:12:13 +0900 Subject: [PATCH 55/64] solve error & add require --- frontend/src/components/ContactForm.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index 0ddd44ae9..419ab7940 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -45,6 +45,8 @@ export default observer((props: IProp) => { const createContact = (e: any) => { e.preventDefault(); + if (!(corner && department && grade && validateEmail(email).validity)) return; + const contact = contactStore.createContact({ name, corner, @@ -80,7 +82,7 @@ export default observer((props: IProp) => { @@ -94,14 +96,14 @@ export default observer((props: IProp) => { value={department} optionElements={contactEnum.departments} > - From 73ee59350b047bc4d0c34ca4e25d687c65094165 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Thu, 30 May 2019 23:35:49 +0900 Subject: [PATCH 56/64] change send button color --- frontend/src/commons/color.ts | 3 ++- frontend/src/components/ContactForm.tsx | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/frontend/src/commons/color.ts b/frontend/src/commons/color.ts index 54a09b53b..bbf43caac 100644 --- a/frontend/src/commons/color.ts +++ b/frontend/src/commons/color.ts @@ -13,5 +13,6 @@ export const chkColors: IColor = { placeholder: "#b0bec5", aqua: "#b3dfe2", darkenAqua: "#50AAB7", - error: "#ff4b42" + error: "#ff4b42", + disabled: "#cccccc" }; diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index 419ab7940..64ead8ea7 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -42,10 +42,23 @@ export default observer((props: IProp) => { const [message, setMessage] = React.useState(""); const [readable, setReadable] = React.useState(false); + const [sendable, setSendable] = React.useState(false); + + React.useEffect( + () => { + if (corner && department && grade && validateEmail(email).validity) { + setSendable(true); + } else { + setSendable(false); + } + }, + [corner, department, grade, email] + ); + const createContact = (e: any) => { e.preventDefault(); - if (!(corner && department && grade && validateEmail(email).validity)) return; + if (!sendable) return; const contact = contactStore.createContact({ name, @@ -140,7 +153,12 @@ export default observer((props: IProp) => { - + ) : ( @@ -160,6 +178,7 @@ const InlineHalfWrapper = styled.div` const ContactFormButton = styled(ChkButtonBase)` width: 40%; margin: 0 auto; + cursor: ${(props: { sendable: boolean }) => (props.sendable ? "pointer" : "default")}; `; const AlertBar = styled.div` From f08d4e82252c78736c82d9638beda04680f590e0 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Fri, 31 May 2019 09:49:42 +0900 Subject: [PATCH 57/64] validity to isValid --- frontend/src/components/ContactForm.tsx | 2 +- frontend/src/components/Forms/TextInput.tsx | 8 ++++---- frontend/src/utils/validation.ts | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index 64ead8ea7..955d33164 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -46,7 +46,7 @@ export default observer((props: IProp) => { React.useEffect( () => { - if (corner && department && grade && validateEmail(email).validity) { + if (corner && department && grade && validateEmail(email).isValid) { setSendable(true); } else { setSendable(false); diff --git a/frontend/src/components/Forms/TextInput.tsx b/frontend/src/components/Forms/TextInput.tsx index dc78d8e3f..305afe846 100644 --- a/frontend/src/components/Forms/TextInput.tsx +++ b/frontend/src/components/Forms/TextInput.tsx @@ -26,7 +26,7 @@ export default ({ type = "text" }: ITextInputProps) => { const [currentInputValue, setCurrentInputValue] = React.useState(""); - const [validationResult, setValidationResult] = React.useState({ validity: true } as IValidationResult); + const [validationResult, setValidationResult] = React.useState({ isValid: true } as IValidationResult); const [inFocus, setInFocus] = React.useState(false); const handleChange = React.useCallback((e: React.ChangeEvent) => { @@ -75,7 +75,7 @@ export default ({ value: currentInputValue, onChange: handleChange, styledFocus: inFocus ? true : false, - validationResult: validationResult.validity + validationResult: validationResult.isValid }; return ( @@ -83,12 +83,12 @@ export default ({ {multiLine ? ( <> - {validationResult && validationResult.validity ? null : {validationResult.errorMessage}} + {validationResult && validationResult.isValid ? null : {validationResult.errorMessage}} ) : ( <> - {validationResult && validationResult.validity ? null : {validationResult.errorMessage}} + {validationResult && validationResult.isValid ? null : {validationResult.errorMessage}} )}
diff --git a/frontend/src/utils/validation.ts b/frontend/src/utils/validation.ts index c2157457e..3d5af54cb 100644 --- a/frontend/src/utils/validation.ts +++ b/frontend/src/utils/validation.ts @@ -1,30 +1,30 @@ const EMAIL_REGEXP = /^([\w])+([\w\._-])*@([\w_-])+\.([\w\._-]+)+$/; export interface IValidationResult { - validity: boolean; + isValid: boolean; errorMessage?: string; } export const notValidate = (_?: any) => { return { - validity: true + isValid: true }; }; export const validateEmail = (email: string): IValidationResult => { if (!email) { return { - validity: false, + isValid: false, errorMessage: "メールアドレスを入力してください。" }; } if (!EMAIL_REGEXP.test(email)) { return { - validity: false, + isValid: false, errorMessage: "有効なメールアドレスではありません。" }; } - return { validity: true }; + return { isValid: true }; }; export type ValidationMethods = typeof validateEmail | typeof notValidate; From 6ee245ae8c6c768fa95cd302a346b465b3e0d16a Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Fri, 31 May 2019 10:01:55 +0900 Subject: [PATCH 58/64] fix: show error message when exist --- frontend/src/components/Forms/TextInput.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/Forms/TextInput.tsx b/frontend/src/components/Forms/TextInput.tsx index 305afe846..afffa40a3 100644 --- a/frontend/src/components/Forms/TextInput.tsx +++ b/frontend/src/components/Forms/TextInput.tsx @@ -26,7 +26,7 @@ export default ({ type = "text" }: ITextInputProps) => { const [currentInputValue, setCurrentInputValue] = React.useState(""); - const [validationResult, setValidationResult] = React.useState({ isValid: true } as IValidationResult); + const [validationResult, setValidationResult] = React.useState({} as IValidationResult); const [inFocus, setInFocus] = React.useState(false); const handleChange = React.useCallback((e: React.ChangeEvent) => { @@ -75,7 +75,7 @@ export default ({ value: currentInputValue, onChange: handleChange, styledFocus: inFocus ? true : false, - validationResult: validationResult.isValid + validationResult: validationResult.isValid || !validationResult.errorMessage }; return ( @@ -83,12 +83,12 @@ export default ({ {multiLine ? ( <> - {validationResult && validationResult.isValid ? null : {validationResult.errorMessage}} + {validationResult && !validationResult.errorMessage ? null : {validationResult.errorMessage}} ) : ( <> - {validationResult && validationResult.isValid ? null : {validationResult.errorMessage}} + {validationResult && !validationResult.errorMessage ? null : {validationResult.errorMessage}} )} From 1be4d552a907e4df6f43f2c9fa59005f6e316ce2 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Fri, 31 May 2019 10:10:23 +0900 Subject: [PATCH 59/64] fix --- frontend/src/utils/validation.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/utils/validation.ts b/frontend/src/utils/validation.ts index 3d5af54cb..686562e7c 100644 --- a/frontend/src/utils/validation.ts +++ b/frontend/src/utils/validation.ts @@ -5,7 +5,7 @@ export interface IValidationResult { errorMessage?: string; } -export const notValidate = (_?: any) => { +export const notValidate = (_: any) => { return { isValid: true }; From d827a41aa7d6e28c57bc808368bf58c4fd4ae799 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sat, 1 Jun 2019 09:05:13 +0900 Subject: [PATCH 60/64] remove property: isValid --- frontend/src/components/ContactForm.tsx | 2 +- frontend/src/components/Forms/TextInput.tsx | 2 +- frontend/src/utils/validation.ts | 11 ++++------- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index 955d33164..af6eda463 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -46,7 +46,7 @@ export default observer((props: IProp) => { React.useEffect( () => { - if (corner && department && grade && validateEmail(email).isValid) { + if (corner && department && grade && validateEmail(email).errorMessage) { setSendable(true); } else { setSendable(false); diff --git a/frontend/src/components/Forms/TextInput.tsx b/frontend/src/components/Forms/TextInput.tsx index afffa40a3..84f872fb3 100644 --- a/frontend/src/components/Forms/TextInput.tsx +++ b/frontend/src/components/Forms/TextInput.tsx @@ -75,7 +75,7 @@ export default ({ value: currentInputValue, onChange: handleChange, styledFocus: inFocus ? true : false, - validationResult: validationResult.isValid || !validationResult.errorMessage + validationResult: !validationResult.errorMessage }; return ( diff --git a/frontend/src/utils/validation.ts b/frontend/src/utils/validation.ts index 686562e7c..81237065a 100644 --- a/frontend/src/utils/validation.ts +++ b/frontend/src/utils/validation.ts @@ -1,30 +1,27 @@ const EMAIL_REGEXP = /^([\w])+([\w\._-])*@([\w_-])+\.([\w\._-]+)+$/; export interface IValidationResult { - isValid: boolean; - errorMessage?: string; + errorMessage: string; } -export const notValidate = (_: any) => { +export const notValidate = (_: any): IValidationResult => { return { - isValid: true + errorMessage: "" }; }; export const validateEmail = (email: string): IValidationResult => { if (!email) { return { - isValid: false, errorMessage: "メールアドレスを入力してください。" }; } if (!EMAIL_REGEXP.test(email)) { return { - isValid: false, errorMessage: "有効なメールアドレスではありません。" }; } - return { isValid: true }; + return { errorMessage: "" }; }; export type ValidationMethods = typeof validateEmail | typeof notValidate; From 06b35fa9c4a85311981e070cf46c6eb02153c32e Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sat, 1 Jun 2019 09:17:05 +0900 Subject: [PATCH 61/64] rename validationResult to validationError --- frontend/src/components/ContactForm.tsx | 2 +- frontend/src/components/Forms/TextInput.tsx | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index af6eda463..55509a7a7 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -46,7 +46,7 @@ export default observer((props: IProp) => { React.useEffect( () => { - if (corner && department && grade && validateEmail(email).errorMessage) { + if (corner && department && grade && !validateEmail(email).errorMessage) { setSendable(true); } else { setSendable(false); diff --git a/frontend/src/components/Forms/TextInput.tsx b/frontend/src/components/Forms/TextInput.tsx index 84f872fb3..ed9b3ac34 100644 --- a/frontend/src/components/Forms/TextInput.tsx +++ b/frontend/src/components/Forms/TextInput.tsx @@ -26,7 +26,7 @@ export default ({ type = "text" }: ITextInputProps) => { const [currentInputValue, setCurrentInputValue] = React.useState(""); - const [validationResult, setValidationResult] = React.useState({} as IValidationResult); + const [validationError, setValidationError] = React.useState({} as IValidationResult); const [inFocus, setInFocus] = React.useState(false); const handleChange = React.useCallback((e: React.ChangeEvent) => { @@ -42,7 +42,7 @@ export default ({ () => { if (validation) { if (!currentInputValue) return; - setValidationResult(validation(currentInputValue)); + setValidationError(validation(currentInputValue)); } }, [currentInputValue, inFocus] @@ -75,7 +75,7 @@ export default ({ value: currentInputValue, onChange: handleChange, styledFocus: inFocus ? true : false, - validationResult: !validationResult.errorMessage + validationError: !validationError.errorMessage }; return ( @@ -83,12 +83,12 @@ export default ({ {multiLine ? ( <> - {validationResult && !validationResult.errorMessage ? null : {validationResult.errorMessage}} + {validationError && !validationError.errorMessage ? null : {validationError.errorMessage}} ) : ( <> - {validationResult && !validationResult.errorMessage ? null : {validationResult.errorMessage}} + {validationError && !validationError.errorMessage ? null : {validationError.errorMessage}} )} @@ -104,7 +104,7 @@ const style = css` padding-left: 30px; line-height: 1.5rem; width: 100%; - border: 2px solid ${(props: any) => (props.validationResult ? "#00afec" : chkColors.error)}; + border: 2px solid ${(props: any) => (props.validationError ? "#00afec" : chkColors.error)}; border-radius: 1.5rem; ::placeholder { From b8b7e8191aef375a74c33b26c7d3fad4cba06113 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sat, 1 Jun 2019 09:19:17 +0900 Subject: [PATCH 62/64] fix --- frontend/src/components/ContactForm.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index 55509a7a7..802180f8e 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -46,13 +46,13 @@ export default observer((props: IProp) => { React.useEffect( () => { - if (corner && department && grade && !validateEmail(email).errorMessage) { + if (corner && department && grade && !validateEmail(email).errorMessage && message) { setSendable(true); } else { setSendable(false); } }, - [corner, department, grade, email] + [corner, department, grade, email, message] ); const createContact = (e: any) => { @@ -96,7 +96,7 @@ export default observer((props: IProp) => { @@ -110,14 +110,14 @@ export default observer((props: IProp) => { optionElements={contactEnum.departments} > @@ -126,7 +126,7 @@ export default observer((props: IProp) => { { Date: Sat, 1 Jun 2019 19:10:30 +0900 Subject: [PATCH 63/64] be able to some validations --- frontend/src/components/ContactForm.tsx | 3 +- frontend/src/components/Forms/TextInput.tsx | 34 +++++++++------------ frontend/src/utils/validation.ts | 2 +- 3 files changed, 17 insertions(+), 22 deletions(-) diff --git a/frontend/src/components/ContactForm.tsx b/frontend/src/components/ContactForm.tsx index 802180f8e..0af3ef823 100644 --- a/frontend/src/components/ContactForm.tsx +++ b/frontend/src/components/ContactForm.tsx @@ -74,7 +74,6 @@ export default observer((props: IProp) => { contact.save(props.successed, props.failed); }; - // TODO(euglena1215): validationをつける return contactEnum ? ( <> {props.alert.status === "successed" && ( @@ -129,7 +128,7 @@ export default observer((props: IProp) => { placeholder="メールアドレス(必須)" onChange={setEmail} value={email} - validation={validateEmail} + validations={[validateEmail]} /> diff --git a/frontend/src/components/Forms/TextInput.tsx b/frontend/src/components/Forms/TextInput.tsx index ed9b3ac34..85c547d0a 100644 --- a/frontend/src/components/Forms/TextInput.tsx +++ b/frontend/src/components/Forms/TextInput.tsx @@ -2,7 +2,7 @@ import * as React from "react"; import styled, { css } from "styled-components"; import { chkColors } from "../../commons/color"; -import { IValidationResult, ValidationMethods, notValidate } from "../../utils/validation"; +import { IValidationResult, ValidationMethod } from "../../utils/validation"; type TextInputType = "text" | "password" | "email"; @@ -12,21 +12,13 @@ export interface ITextInputProps { placeholder?: string; type?: TextInputType; multiLine?: boolean; - validation?: ValidationMethods; + validations?: ValidationMethod[]; onChange?(value: string): void; } -export default ({ - value, - name, - placeholder, - multiLine, - onChange, - validation = notValidate, - type = "text" -}: ITextInputProps) => { +export default ({ value, name, placeholder, multiLine, onChange, validations, type = "text" }: ITextInputProps) => { const [currentInputValue, setCurrentInputValue] = React.useState(""); - const [validationError, setValidationError] = React.useState({} as IValidationResult); + const [validationErrors, setValidationErrors] = React.useState([] as IValidationResult[]); const [inFocus, setInFocus] = React.useState(false); const handleChange = React.useCallback((e: React.ChangeEvent) => { @@ -40,9 +32,14 @@ export default ({ React.useEffect( () => { - if (validation) { + if (validations) { if (!currentInputValue) return; - setValidationError(validation(currentInputValue)); + + const newErrors: IValidationResult[] = []; + validations.forEach(validation => { + newErrors.push(validation(currentInputValue)); + }); + setValidationErrors(newErrors); } }, [currentInputValue, inFocus] @@ -75,7 +72,7 @@ export default ({ value: currentInputValue, onChange: handleChange, styledFocus: inFocus ? true : false, - validationError: !validationError.errorMessage + validationError: validationErrors.filter(v => v.errorMessage).length > 0 ? true : false }; return ( @@ -83,19 +80,18 @@ export default ({ {multiLine ? ( <> - {validationError && !validationError.errorMessage ? null : {validationError.errorMessage}} + {validationErrors.length > 0 ? validationErrors.map((v, i) => {v.errorMessage}) : null} ) : ( <> - {validationError && !validationError.errorMessage ? null : {validationError.errorMessage}} + {validationErrors.length > 0 ? validationErrors.map((v, i) => {v.errorMessage}) : null} )} ); }; -// TODO: focus時とそうでない時で背景かアウトラインのデザインを変える const style = css` margin: 5px; margin-left: 0; @@ -104,7 +100,7 @@ const style = css` padding-left: 30px; line-height: 1.5rem; width: 100%; - border: 2px solid ${(props: any) => (props.validationError ? "#00afec" : chkColors.error)}; + border: 2px solid ${(props: any) => (props.validationError ? chkColors.error : "#00afec")}; border-radius: 1.5rem; ::placeholder { diff --git a/frontend/src/utils/validation.ts b/frontend/src/utils/validation.ts index 81237065a..a1f7ad756 100644 --- a/frontend/src/utils/validation.ts +++ b/frontend/src/utils/validation.ts @@ -24,4 +24,4 @@ export const validateEmail = (email: string): IValidationResult => { return { errorMessage: "" }; }; -export type ValidationMethods = typeof validateEmail | typeof notValidate; +export type ValidationMethod = typeof validateEmail | typeof notValidate; From 5741f2384fedb56ac281b1a605dc4fdde2632c64 Mon Sep 17 00:00:00 2001 From: kobakakzu0429 Date: Sun, 2 Jun 2019 10:44:20 +0900 Subject: [PATCH 64/64] remove notValidate --- frontend/src/utils/validation.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/frontend/src/utils/validation.ts b/frontend/src/utils/validation.ts index a1f7ad756..f5665e754 100644 --- a/frontend/src/utils/validation.ts +++ b/frontend/src/utils/validation.ts @@ -4,12 +4,6 @@ export interface IValidationResult { errorMessage: string; } -export const notValidate = (_: any): IValidationResult => { - return { - errorMessage: "" - }; -}; - export const validateEmail = (email: string): IValidationResult => { if (!email) { return { @@ -24,4 +18,4 @@ export const validateEmail = (email: string): IValidationResult => { return { errorMessage: "" }; }; -export type ValidationMethod = typeof validateEmail | typeof notValidate; +export type ValidationMethod = typeof validateEmail;