From 8778eda2cb9553cd458371b331132b1f36970984 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Thu, 18 Jun 2020 22:37:54 +0800 Subject: [PATCH 01/64] Create Sign Up page for merchants --- web/src/Routes.tsx | 2 + web/src/assets/gpay-logo.svg | 7 ++ web/src/components/common/FormRow.tsx | 61 +++++++++++++ .../common/GroupBuyMerchantHeader.tsx | 49 +++++++++++ .../merchant/sign-up/OnboardingCard.tsx | 86 +++++++++++++++++++ web/src/components/merchant/sign-up/index.tsx | 40 +++++++++ web/src/index.css | 5 ++ 7 files changed, 250 insertions(+) create mode 100644 web/src/assets/gpay-logo.svg create mode 100644 web/src/components/common/FormRow.tsx create mode 100644 web/src/components/common/GroupBuyMerchantHeader.tsx create mode 100644 web/src/components/merchant/sign-up/OnboardingCard.tsx create mode 100644 web/src/components/merchant/sign-up/index.tsx diff --git a/web/src/Routes.tsx b/web/src/Routes.tsx index 9a994fa1..eb6a7ff2 100644 --- a/web/src/Routes.tsx +++ b/web/src/Routes.tsx @@ -23,12 +23,14 @@ import {Switch, Route} from 'react-router-dom'; const CustomerExplorePage = lazy(() => import('components/customer/explore')); // Merchant Pages const MerchantLandingPage = lazy(() => import('components/merchant/landing')); +const MerchantSignUpPage = lazy(() => import('components/merchant/sign-up')); const Routes: React.FC = () => ( }> + ); diff --git a/web/src/assets/gpay-logo.svg b/web/src/assets/gpay-logo.svg new file mode 100644 index 00000000..96ff5181 --- /dev/null +++ b/web/src/assets/gpay-logo.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx new file mode 100644 index 00000000..734e5ca9 --- /dev/null +++ b/web/src/components/common/FormRow.tsx @@ -0,0 +1,61 @@ +/** + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import Row from 'muicss/lib/react/row'; +import styled from 'styled-components'; + +const StyledRow = styled(Row)` + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + + margin: 30px 0; +`; + +const Label = styled.label` + width: 130px; + font-size: 18px; +`; + +const Input = styled.input` + height: 40px; + font-size: 18px; + padding: 0 20px; + + border-radius: 20px; + border: none; + box-shadow: 4px 2px 4px rgba(0, 0, 0, 0.25); + + &:focus { + outline: none; + } +`; + +interface FormRowProps { + label: string; + inputType: string; +} + +const FormRow: React.FC = ({label, inputType}) => ( + + + + +); + +export default FormRow; diff --git a/web/src/components/common/GroupBuyMerchantHeader.tsx b/web/src/components/common/GroupBuyMerchantHeader.tsx new file mode 100644 index 00000000..358efc6f --- /dev/null +++ b/web/src/components/common/GroupBuyMerchantHeader.tsx @@ -0,0 +1,49 @@ +/** + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import styled from 'styled-components'; + +import GPayLogo from 'assets/gpay-logo.svg'; + +const HeaderContainer = styled.div` + display: flex; + flex-direction: column; + align-items: center; +`; + +const Logo = styled.img` + width: 124px; +`; + +const Header = styled.h1` + font-size: 48px; + font-weight: normal; + line-height: 72px; + margin: 0; +`; + +const GroupBuyMerchantHeader: React.FC = () => ( + + +
+ Group Buy
+ Merchant +
+
+); + +export default GroupBuyMerchantHeader; diff --git a/web/src/components/merchant/sign-up/OnboardingCard.tsx b/web/src/components/merchant/sign-up/OnboardingCard.tsx new file mode 100644 index 00000000..f5b7a276 --- /dev/null +++ b/web/src/components/merchant/sign-up/OnboardingCard.tsx @@ -0,0 +1,86 @@ +/** + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import Form from 'muicss/lib/react/form'; +import Row from 'muicss/lib/react/row'; +import styled from 'styled-components'; + +import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; +import FormRow from 'components/common/FormRow'; + +const CardContainer: React.FC = styled.div` + display: flex; + flex-direction: column; + align-items: center; + + background: var(--pale-gray); + border-radius: 30px; + max-width: 670px; + padding: 80px; + box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.25); +`; + +const StyledRow = styled(Row)` + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + + margin: 30px 0; +`; + +const SubmitButton = styled.input` + height: 60px; + width: 300px; + border-radius: 30px; + border: none; + + background: var(--dark-gray); + color: white; + font-size: 24px; + font-weight: bolder; + text-transform: uppercase; + + margin-top: 80px; + + &:hover { + cursor: pointer; + } + + &:focus { + outline: none; + } +`; + +const OnboardingCard: React.FC = () => ( + + +
+ + + + + + + + + +
Already have an account? Sign in now!
+
+); + +export default OnboardingCard; diff --git a/web/src/components/merchant/sign-up/index.tsx b/web/src/components/merchant/sign-up/index.tsx new file mode 100644 index 00000000..dd2b957f --- /dev/null +++ b/web/src/components/merchant/sign-up/index.tsx @@ -0,0 +1,40 @@ +/** + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import Container from 'muicss/lib/react/container'; +import styled from 'styled-components'; + +import OnboardingCard from 'components/merchant/sign-up/OnboardingCard'; + +const PageContainer = styled(Container)` + min-height: 100vh; + height: 100%; + width: 100%; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +`; + +const MerchantSignUpPage: React.FC = () => ( + + + +); + +export default MerchantSignUpPage; diff --git a/web/src/index.css b/web/src/index.css index c1b3a6de..e1885d8a 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -15,6 +15,7 @@ */ @import url('https://fonts.googleapis.com/css?family=Poppins&display=swap'); +@import url("//cdn.muicss.com/mui-0.10.1/css/mui.min.css"); :root { /* brand colors */ @@ -47,3 +48,7 @@ code { a { color: var(--green); } + +a:hover { + cursor: pointer; +} From 0c3ab9705f0c4eb485931e24c463dc737961adac Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Thu, 18 Jun 2020 22:50:48 +0800 Subject: [PATCH 02/64] Fix lint errors --- web/.eslintrc.json | 4 +++- web/src/components/common/FormRow.tsx | 3 ++- web/src/components/common/GroupBuyMerchantHeader.tsx | 6 ++++-- .../components/merchant/sign-up/OnboardingCard.tsx | 12 +++++++----- web/src/components/merchant/sign-up/index.tsx | 10 +++++----- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/web/.eslintrc.json b/web/.eslintrc.json index 1fa036fc..a5465834 100644 --- a/web/.eslintrc.json +++ b/web/.eslintrc.json @@ -38,7 +38,9 @@ "caseInsensitive": true } } - ] + ], + // TypeScript lints this for us + "react/prop-types": "off" }, "settings": { "react": { diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index 734e5ca9..a6b5b8db 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -15,6 +15,7 @@ */ import React from 'react'; + import Row from 'muicss/lib/react/row'; import styled from 'styled-components'; @@ -51,7 +52,7 @@ interface FormRowProps { inputType: string; } -const FormRow: React.FC = ({label, inputType}) => ( +const FormRow: React.FC = ({label, inputType}) => ( diff --git a/web/src/components/common/GroupBuyMerchantHeader.tsx b/web/src/components/common/GroupBuyMerchantHeader.tsx index 358efc6f..ac484722 100644 --- a/web/src/components/common/GroupBuyMerchantHeader.tsx +++ b/web/src/components/common/GroupBuyMerchantHeader.tsx @@ -15,6 +15,7 @@ */ import React from 'react'; + import styled from 'styled-components'; import GPayLogo from 'assets/gpay-logo.svg'; @@ -36,11 +37,12 @@ const Header = styled.h1` margin: 0; `; -const GroupBuyMerchantHeader: React.FC = () => ( +const GroupBuyMerchantHeader: React.FC = () => (
- Group Buy
+ Group Buy +
Merchant
diff --git a/web/src/components/merchant/sign-up/OnboardingCard.tsx b/web/src/components/merchant/sign-up/OnboardingCard.tsx index f5b7a276..e0e1283d 100644 --- a/web/src/components/merchant/sign-up/OnboardingCard.tsx +++ b/web/src/components/merchant/sign-up/OnboardingCard.tsx @@ -15,13 +15,13 @@ */ import React from 'react'; + +import FormRow from 'components/common/FormRow'; +import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; import Form from 'muicss/lib/react/form'; import Row from 'muicss/lib/react/row'; import styled from 'styled-components'; -import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; -import FormRow from 'components/common/FormRow'; - const CardContainer: React.FC = styled.div` display: flex; flex-direction: column; @@ -66,7 +66,7 @@ const SubmitButton = styled.input` } `; -const OnboardingCard: React.FC = () => ( +const OnboardingCard: React.FC = () => (
@@ -79,7 +79,9 @@ const OnboardingCard: React.FC = () => ( -
Already have an account? Sign in now!
+
+ Already have an account? Sign in now! +
); diff --git a/web/src/components/merchant/sign-up/index.tsx b/web/src/components/merchant/sign-up/index.tsx index dd2b957f..9e26a89d 100644 --- a/web/src/components/merchant/sign-up/index.tsx +++ b/web/src/components/merchant/sign-up/index.tsx @@ -15,10 +15,10 @@ */ import React from 'react'; -import Container from 'muicss/lib/react/container'; -import styled from 'styled-components'; import OnboardingCard from 'components/merchant/sign-up/OnboardingCard'; +import Container from 'muicss/lib/react/container'; +import styled from 'styled-components'; const PageContainer = styled(Container)` min-height: 100vh; @@ -32,9 +32,9 @@ const PageContainer = styled(Container)` `; const MerchantSignUpPage: React.FC = () => ( - - - + + + ); export default MerchantSignUpPage; From 695dd2d574668f56f4a80b29639610918efdcc32 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 00:15:35 +0800 Subject: [PATCH 03/64] Make Sign Up page resolutions smaller to fit laptops --- web/src/components/common/FormRow.tsx | 15 ++++++++------- .../components/common/GroupBuyMerchantHeader.tsx | 6 +++--- .../merchant/sign-up/OnboardingCard.tsx | 14 +++++++------- web/src/components/merchant/sign-up/index.tsx | 4 ++-- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index a6b5b8db..e5ae8696 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -25,20 +25,21 @@ const StyledRow = styled(Row)` align-items: center; justify-content: center; - margin: 30px 0; + margin: 20px 0; `; const Label = styled.label` - width: 130px; - font-size: 18px; + width: 100px; + font-size: 14px; + margin-right: 20px; `; const Input = styled.input` - height: 40px; - font-size: 18px; - padding: 0 20px; + height: 30px; + font-size: 14px; + padding: 0 15px; - border-radius: 20px; + border-radius: 15px; border: none; box-shadow: 4px 2px 4px rgba(0, 0, 0, 0.25); diff --git a/web/src/components/common/GroupBuyMerchantHeader.tsx b/web/src/components/common/GroupBuyMerchantHeader.tsx index ac484722..568ed8a0 100644 --- a/web/src/components/common/GroupBuyMerchantHeader.tsx +++ b/web/src/components/common/GroupBuyMerchantHeader.tsx @@ -27,13 +27,13 @@ const HeaderContainer = styled.div` `; const Logo = styled.img` - width: 124px; + width: 80px; `; const Header = styled.h1` - font-size: 48px; + font-size: 32px; font-weight: normal; - line-height: 72px; + line-height: 48px; margin: 0; `; diff --git a/web/src/components/merchant/sign-up/OnboardingCard.tsx b/web/src/components/merchant/sign-up/OnboardingCard.tsx index e0e1283d..1d68a09f 100644 --- a/web/src/components/merchant/sign-up/OnboardingCard.tsx +++ b/web/src/components/merchant/sign-up/OnboardingCard.tsx @@ -30,7 +30,7 @@ const CardContainer: React.FC = styled.div` background: var(--pale-gray); border-radius: 30px; max-width: 670px; - padding: 80px; + padding: 40px; box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.25); `; @@ -40,22 +40,22 @@ const StyledRow = styled(Row)` align-items: center; justify-content: center; - margin: 30px 0; + margin: 15px 0; `; const SubmitButton = styled.input` - height: 60px; - width: 300px; - border-radius: 30px; + height: 40px; + width: 200px; + border-radius: 20px; border: none; background: var(--dark-gray); color: white; - font-size: 24px; + font-size: 18px; font-weight: bolder; text-transform: uppercase; - margin-top: 80px; + margin-top: 30px; &:hover { cursor: pointer; diff --git a/web/src/components/merchant/sign-up/index.tsx b/web/src/components/merchant/sign-up/index.tsx index 9e26a89d..7cdbee6e 100644 --- a/web/src/components/merchant/sign-up/index.tsx +++ b/web/src/components/merchant/sign-up/index.tsx @@ -21,8 +21,8 @@ import Container from 'muicss/lib/react/container'; import styled from 'styled-components'; const PageContainer = styled(Container)` - min-height: 100vh; - height: 100%; + max-height: 800px; + height: 100vh; width: 100%; display: flex; From 78d36cd0b41cd375e9cb0431089d0d083d85f82b Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 12:04:09 +0800 Subject: [PATCH 04/64] Add JSDoc comments for exported components --- web/src/components/common/FormRow.tsx | 7 +++++++ web/src/components/common/GroupBuyMerchantHeader.tsx | 4 ++++ web/src/components/merchant/sign-up/OnboardingCard.tsx | 4 ++++ 3 files changed, 15 insertions(+) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index e5ae8696..c4e73d0c 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -53,6 +53,13 @@ interface FormRowProps { inputType: string; } +/** + * This is a row in a form, consisting of a label and an input field shown + * side by side. + * + * @param {string} label - The word or phrase you want shown in the label. + * @param {string} inputType - The type attribute of the HTML input element. + */ const FormRow: React.FC = ({label, inputType}) => ( diff --git a/web/src/components/common/GroupBuyMerchantHeader.tsx b/web/src/components/common/GroupBuyMerchantHeader.tsx index 568ed8a0..ca02318d 100644 --- a/web/src/components/common/GroupBuyMerchantHeader.tsx +++ b/web/src/components/common/GroupBuyMerchantHeader.tsx @@ -37,6 +37,10 @@ const Header = styled.h1` margin: 0; `; +/** + * This is a header for the Merchant app. It consists of the GPay logo, followed + * by the words 'Group Buy Merchant'. + */ const GroupBuyMerchantHeader: React.FC = () => ( diff --git a/web/src/components/merchant/sign-up/OnboardingCard.tsx b/web/src/components/merchant/sign-up/OnboardingCard.tsx index 1d68a09f..6e4ca041 100644 --- a/web/src/components/merchant/sign-up/OnboardingCard.tsx +++ b/web/src/components/merchant/sign-up/OnboardingCard.tsx @@ -66,6 +66,10 @@ const SubmitButton = styled.input` } `; +/** + * This is the card containing the sign up form for the Merchant app. + * It is displayed in the Sign Up page. + */ const OnboardingCard: React.FC = () => ( From 520bb0aa934cb93e7b42ea54737c2c03704f51e8 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 12:27:48 +0800 Subject: [PATCH 05/64] rename OnboardingCard to SignUpCard to standardise --- .../merchant/sign-up/{OnboardingCard.tsx => SignUpCard.tsx} | 4 ++-- web/src/components/merchant/sign-up/index.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename web/src/components/merchant/sign-up/{OnboardingCard.tsx => SignUpCard.tsx} (96%) diff --git a/web/src/components/merchant/sign-up/OnboardingCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx similarity index 96% rename from web/src/components/merchant/sign-up/OnboardingCard.tsx rename to web/src/components/merchant/sign-up/SignUpCard.tsx index 6e4ca041..fc7f00d4 100644 --- a/web/src/components/merchant/sign-up/OnboardingCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -70,7 +70,7 @@ const SubmitButton = styled.input` * This is the card containing the sign up form for the Merchant app. * It is displayed in the Sign Up page. */ -const OnboardingCard: React.FC = () => ( +const SignUpCard: React.FC = () => (
@@ -89,4 +89,4 @@ const OnboardingCard: React.FC = () => ( ); -export default OnboardingCard; +export default SignUpCard; diff --git a/web/src/components/merchant/sign-up/index.tsx b/web/src/components/merchant/sign-up/index.tsx index 7cdbee6e..9d7a3e0b 100644 --- a/web/src/components/merchant/sign-up/index.tsx +++ b/web/src/components/merchant/sign-up/index.tsx @@ -16,7 +16,7 @@ import React from 'react'; -import OnboardingCard from 'components/merchant/sign-up/OnboardingCard'; +import SignUpCard from 'components/merchant/sign-up/SignUpCard'; import Container from 'muicss/lib/react/container'; import styled from 'styled-components'; @@ -33,7 +33,7 @@ const PageContainer = styled(Container)` const MerchantSignUpPage: React.FC = () => ( - + ); From 2f9d890651b26ecad0b691c494548d8383302624 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 12:31:22 +0800 Subject: [PATCH 06/64] Remove params in JSDoc comment of components --- web/src/components/common/FormRow.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index c4e73d0c..85124210 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -56,9 +56,6 @@ interface FormRowProps { /** * This is a row in a form, consisting of a label and an input field shown * side by side. - * - * @param {string} label - The word or phrase you want shown in the label. - * @param {string} inputType - The type attribute of the HTML input element. */ const FormRow: React.FC = ({label, inputType}) => ( From 2ef64c7b9bcec271622f52d64a12a6533111cccb Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 12:40:56 +0800 Subject: [PATCH 07/64] Rename MerchantLandingPage to LandingPage and MerchantSignUpPage to SignUpPage --- web/src/components/merchant/landing/index.tsx | 4 ++-- web/src/components/merchant/sign-up/index.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/src/components/merchant/landing/index.tsx b/web/src/components/merchant/landing/index.tsx index 2c92207d..6d1af639 100644 --- a/web/src/components/merchant/landing/index.tsx +++ b/web/src/components/merchant/landing/index.tsx @@ -16,6 +16,6 @@ import React from 'react'; -const MerchantLandingPage: React.FC = () =>
Merchant Landing Page
; +const LandingPage: React.FC = () =>
Merchant Landing Page
; -export default MerchantLandingPage; +export default LandingPage; diff --git a/web/src/components/merchant/sign-up/index.tsx b/web/src/components/merchant/sign-up/index.tsx index 9d7a3e0b..b5e1c395 100644 --- a/web/src/components/merchant/sign-up/index.tsx +++ b/web/src/components/merchant/sign-up/index.tsx @@ -31,10 +31,10 @@ const PageContainer = styled(Container)` align-items: center; `; -const MerchantSignUpPage: React.FC = () => ( +const SignUpPage: React.FC = () => ( ); -export default MerchantSignUpPage; +export default SignUpPage; From ec119badd457da2257795ff25e30bf75f278f205 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 12:55:37 +0800 Subject: [PATCH 08/64] Correct the Sign in link in Sign Up page --- web/src/components/merchant/sign-up/SignUpCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index fc7f00d4..fceaaa67 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -84,7 +84,7 @@ const SignUpCard: React.FC = () => (
- Already have an account? Sign in now! + Already have an account? Sign in now!
); From 3ba1f0c2b7f441e3673d455394b84e9d3fb70d0d Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 15:03:55 +0800 Subject: [PATCH 09/64] Update web/src/components/merchant/sign-up/SignUpCard.tsx Co-authored-by: Caryn Heng --- web/src/components/merchant/sign-up/SignUpCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index fceaaa67..6818a096 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -84,7 +84,7 @@ const SignUpCard: React.FC = () => (
- Already have an account? Sign in now! + Already have an account? Sign in now!
); From c8e706bfcccc8c508b13ce5d69cfcab6b49d98a2 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 15:27:30 +0800 Subject: [PATCH 10/64] Add missing import {Link} statement in SignUpCard --- web/src/components/merchant/sign-up/SignUpCard.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 6818a096..ed6aab7e 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -20,6 +20,7 @@ import FormRow from 'components/common/FormRow'; import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; import Form from 'muicss/lib/react/form'; import Row from 'muicss/lib/react/row'; +import {Link} from 'react-router-dom'; import styled from 'styled-components'; const CardContainer: React.FC = styled.div` From 2cdbd6bd3e16874d965133be1394b0f70d307492 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 15:43:26 +0800 Subject: [PATCH 11/64] Import gpay-logo.svg directly as React Component --- web/src/components/common/GroupBuyMerchantHeader.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/components/common/GroupBuyMerchantHeader.tsx b/web/src/components/common/GroupBuyMerchantHeader.tsx index ca02318d..2d8872de 100644 --- a/web/src/components/common/GroupBuyMerchantHeader.tsx +++ b/web/src/components/common/GroupBuyMerchantHeader.tsx @@ -18,7 +18,7 @@ import React from 'react'; import styled from 'styled-components'; -import GPayLogo from 'assets/gpay-logo.svg'; +import { ReactComponent as GPayLogo } from 'assets/gpay-logo.svg'; const HeaderContainer = styled.div` display: flex; @@ -26,7 +26,7 @@ const HeaderContainer = styled.div` align-items: center; `; -const Logo = styled.img` +const Logo = styled(GPayLogo)` width: 80px; `; @@ -43,7 +43,7 @@ const Header = styled.h1` */ const GroupBuyMerchantHeader: React.FC = () => ( - +
Group Buy
From 9407acb421a48553adf80baa15c3cf490eac4eff Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 15:47:04 +0800 Subject: [PATCH 12/64] Strip input tag style in index.css file instead of FormRox.tsx --- web/src/components/common/FormRow.tsx | 4 ---- web/src/index.css | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index 85124210..3f17b80e 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -42,10 +42,6 @@ const Input = styled.input` border-radius: 15px; border: none; box-shadow: 4px 2px 4px rgba(0, 0, 0, 0.25); - - &:focus { - outline: none; - } `; interface FormRowProps { diff --git a/web/src/index.css b/web/src/index.css index e1885d8a..09aa946a 100644 --- a/web/src/index.css +++ b/web/src/index.css @@ -52,3 +52,7 @@ a { a:hover { cursor: pointer; } + +input:focus { + outline: none; +} From 17515edde67b324426eeda1aa2f686f71e0a4cc3 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 15:47:24 +0800 Subject: [PATCH 13/64] Fix lint error --- web/src/components/common/GroupBuyMerchantHeader.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/common/GroupBuyMerchantHeader.tsx b/web/src/components/common/GroupBuyMerchantHeader.tsx index 2d8872de..b5c84355 100644 --- a/web/src/components/common/GroupBuyMerchantHeader.tsx +++ b/web/src/components/common/GroupBuyMerchantHeader.tsx @@ -18,7 +18,7 @@ import React from 'react'; import styled from 'styled-components'; -import { ReactComponent as GPayLogo } from 'assets/gpay-logo.svg'; +import {ReactComponent as GPayLogo} from 'assets/gpay-logo.svg'; const HeaderContainer = styled.div` display: flex; From 8470e94f5ceccf419089828639943ca8f7c5b878 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 15:55:01 +0800 Subject: [PATCH 14/64] Change Sign Up button from input element to MUI Button element --- web/src/components/merchant/sign-up/SignUpCard.tsx | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index ed6aab7e..5434adfe 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -18,6 +18,7 @@ import React from 'react'; import FormRow from 'components/common/FormRow'; import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; +import Button from 'muicss/lib/react/button'; import Form from 'muicss/lib/react/form'; import Row from 'muicss/lib/react/row'; import {Link} from 'react-router-dom'; @@ -44,7 +45,7 @@ const StyledRow = styled(Row)` margin: 15px 0; `; -const SubmitButton = styled.input` +const StyledButton = styled(Button)` height: 40px; width: 200px; border-radius: 20px; @@ -57,14 +58,6 @@ const SubmitButton = styled.input` text-transform: uppercase; margin-top: 30px; - - &:hover { - cursor: pointer; - } - - &:focus { - outline: none; - } `; /** @@ -81,7 +74,7 @@ const SignUpCard: React.FC = () => ( - + Sign Up
From 7b0eb428a1992143d4a714f71e158f19e9490763 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 16:04:36 +0800 Subject: [PATCH 15/64] Vertically centralise SignUpCard in SignUpPage --- web/src/components/merchant/sign-up/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/components/merchant/sign-up/index.tsx b/web/src/components/merchant/sign-up/index.tsx index b5e1c395..8af1e44a 100644 --- a/web/src/components/merchant/sign-up/index.tsx +++ b/web/src/components/merchant/sign-up/index.tsx @@ -21,8 +21,8 @@ import Container from 'muicss/lib/react/container'; import styled from 'styled-components'; const PageContainer = styled(Container)` - max-height: 800px; - height: 100vh; + min-height: 100vh; + height: 100%; width: 100%; display: flex; From dee7e44c354f28a30e7203a7626ba7e5bf316ca8 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 16:52:13 +0800 Subject: [PATCH 16/64] Add input name in FormRow --- web/src/components/common/FormRow.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index 3f17b80e..78a5e6ce 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -56,7 +56,14 @@ interface FormRowProps { const FormRow: React.FC = ({label, inputType}) => ( - + a.toUpperCase()) + .replace(/\s/g, '') + .replace(/^(.)/, a => a.toLowerCase())} + /> ); From 61aa094a0ce9067b40a23f31f2deb29932c23cf1 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 19:01:11 +0800 Subject: [PATCH 17/64] Add handlers for merchants' sign up form --- web/src/components/common/FormRow.tsx | 4 +- .../merchant/sign-up/SignUpCard.tsx | 119 ++++++++++++++---- 2 files changed, 97 insertions(+), 26 deletions(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index 78a5e6ce..8aec9e8f 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -47,13 +47,14 @@ const Input = styled.input` interface FormRowProps { label: string; inputType: string; + onChange: React.EventHandler>; } /** * This is a row in a form, consisting of a label and an input field shown * side by side. */ -const FormRow: React.FC = ({label, inputType}) => ( +const FormRow: React.FC = ({label, inputType, onChange}) => ( = ({label, inputType}) => ( .replace(/\s(.)/g, a => a.toUpperCase()) .replace(/\s/g, '') .replace(/^(.)/, a => a.toLowerCase())} + onChange={onChange} /> ); diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 5434adfe..de0d8dba 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -36,13 +36,18 @@ const CardContainer: React.FC = styled.div` box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.25); `; +const StyledForm = styled(Form)` + margin: 15px 0; +`; + const StyledRow = styled(Row)` - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; + height: 40px; + display: block; + line-height: 40px; +`; - margin: 15px 0; +const ErrorContainer = styled.div` + color: var(--bright-red); `; const StyledButton = styled(Button)` @@ -56,31 +61,95 @@ const StyledButton = styled(Button)` font-size: 18px; font-weight: bolder; text-transform: uppercase; - - margin-top: 30px; + margin: 0; `; +interface SignUpState { + name?: string; + email?: string; + password?: string; + confirmPassword?: string; + vpa?: string; + errorMessage?: string; +} + /** * This is the card containing the sign up form for the Merchant app. * It is displayed in the Sign Up page. */ -const SignUpCard: React.FC = () => ( - - -
- - - - - - - Sign Up - - -
- Already have an account? Sign in now! -
-
-); +class SignUpCard extends React.Component<{}, SignUpState> { + constructor(props: Readonly<{}>) { + super(props); + this.state = { + name: '', + email: '', + password: '', + confirmPassword: '', + vpa: '', + errorMessage: '', + }; + this.handleInputChange = this.handleInputChange.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + } + + handleInputChange(event: React.ChangeEvent) { + const name: string = event.target.name; + const value: string = event.target.value; + + this.setState({ + [name]: value, + errorMessage: '' + }); + } + + handleSubmit() { + const name: string | undefined = this.state.name; + const email: string | undefined = this.state.email; + const password: string | undefined = this.state.password; + const confirmPassword: string | undefined = this.state.confirmPassword; + const vpa: string | undefined = this.state.vpa; + + if (!(name && email && password && confirmPassword && vpa)) { + this.setState({ + errorMessage: 'Please fill in all of the fields.' + }); + console.log(this.state); + return; + } + + if (password !== confirmPassword) { + this.setState({ + errorMessage: 'Passwords do not match.' + }); + console.log(this.state); + return; + } + } + + render() { + return ( + + + + + + + + + + + {this.state.errorMessage} + + + Sign Up + + + Already have an account? Sign in{' '} + now! + + + ); + } +} export default SignUpCard; From ecec1e23b57c76ec2510ab34334d8f4da2fa4e15 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 19:55:18 +0800 Subject: [PATCH 18/64] Remove logging statements for debugging --- web/src/components/merchant/sign-up/SignUpCard.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index de0d8dba..91772b34 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -113,7 +113,6 @@ class SignUpCard extends React.Component<{}, SignUpState> { this.setState({ errorMessage: 'Please fill in all of the fields.' }); - console.log(this.state); return; } @@ -121,7 +120,6 @@ class SignUpCard extends React.Component<{}, SignUpState> { this.setState({ errorMessage: 'Passwords do not match.' }); - console.log(this.state); return; } } From 35e0082c1efc58f5137a9ea6fd9c9beeb3089014 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 19 Jun 2020 22:31:04 +0800 Subject: [PATCH 19/64] Add a new user account to Firebase for signed up merchant --- web/package.json | 2 + .../merchant/sign-up/SignUpCard.tsx | 71 ++- web/tsconfig.json | 3 +- web/yarn.lock | 406 +++++++++++++++++- 4 files changed, 463 insertions(+), 19 deletions(-) diff --git a/web/package.json b/web/package.json index d02f4783..8b4ac2da 100644 --- a/web/package.json +++ b/web/package.json @@ -16,6 +16,8 @@ "@types/react-dom": "^16.9.0", "@types/react-router-dom": "^5.1.5", "@types/styled-components": "^5.1.0", + "autobind-decorator": "^2.4.0", + "firebase": "^7.15.2", "muicss": "^0.10.2", "rc-progress": "^3.0.0", "react": "^16.13.1", diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 91772b34..be7c12bf 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -16,8 +16,10 @@ import React from 'react'; +import autobind from 'autobind-decorator'; import FormRow from 'components/common/FormRow'; import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; +import firebase from 'firebase'; import Button from 'muicss/lib/react/button'; import Form from 'muicss/lib/react/form'; import Row from 'muicss/lib/react/row'; @@ -77,6 +79,7 @@ interface SignUpState { * This is the card containing the sign up form for the Merchant app. * It is displayed in the Sign Up page. */ +@autobind class SignUpCard extends React.Component<{}, SignUpState> { constructor(props: Readonly<{}>) { super(props); @@ -88,8 +91,6 @@ class SignUpCard extends React.Component<{}, SignUpState> { vpa: '', errorMessage: '', }; - this.handleInputChange = this.handleInputChange.bind(this); - this.handleSubmit = this.handleSubmit.bind(this); } handleInputChange(event: React.ChangeEvent) { @@ -98,7 +99,7 @@ class SignUpCard extends React.Component<{}, SignUpState> { this.setState({ [name]: value, - errorMessage: '' + errorMessage: '', }); } @@ -111,17 +112,47 @@ class SignUpCard extends React.Component<{}, SignUpState> { if (!(name && email && password && confirmPassword && vpa)) { this.setState({ - errorMessage: 'Please fill in all of the fields.' + errorMessage: 'Please fill in all of the fields.', }); return; } if (password !== confirmPassword) { this.setState({ - errorMessage: 'Passwords do not match.' + errorMessage: 'Passwords do not match.', }); return; } + + // Add a new user account to Firebase. + if (!firebase.apps.length) { + firebase.initializeApp({ + apiKey: process.env.API_KEY, + authDomain: process.env.AUTH_DOMAIN, + }); + } + + const setState = this.setState.bind(this); + firebase + .auth() + .createUserWithEmailAndPassword(email, password) + .catch(error => { + const errorCode = error.code; + let errorMessage = error.message; + if (errorCode === 'auth/invalid-email') { + errorMessage = 'Please input a valid email address.'; + } else if (errorCode === 'auth/weak-password') { + errorMessage = 'Password should be at least 6 characters.'; + } else if (errorCode === 'auth/email-already-in-use') { + errorMessage = + 'The email address is already in use by another account.'; + } else if (errorCode === 'auth/operation-not-allowed') { + errorMessage = 'Oops, something is wrong. Please try again later!'; + } + setState({ + errorMessage, + }); + }); } render() { @@ -129,11 +160,31 @@ class SignUpCard extends React.Component<{}, SignUpState> { - - - - - + + + + + {this.state.errorMessage} diff --git a/web/tsconfig.json b/web/tsconfig.json index 761fa66d..08f8d960 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -19,7 +19,8 @@ "isolatedModules": true, "noEmit": true, "jsx": "react", - "baseUrl": "./src/" + "baseUrl": "./src/", + "experimentalDecorators": true }, "include": [ "src" diff --git a/web/yarn.lock b/web/yarn.lock index a701a0cf..7003030c 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -1184,6 +1184,244 @@ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== +"@firebase/analytics-types@0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@firebase/analytics-types/-/analytics-types-0.3.1.tgz#3c5f5d71129c88295e17e914e34b391ffda1723c" + integrity sha512-63vVJ5NIBh/JF8l9LuPrQYSzFimk7zYHySQB4Dk9rVdJ8kV/vGQoVTvRu1UW05sEc2Ug5PqtEChtTHU+9hvPcA== + +"@firebase/analytics@0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@firebase/analytics/-/analytics-0.3.7.tgz#472977bbffa9d67631cf66585ec7ea809a4a806e" + integrity sha512-xIxbrnnyMcbmMVFhbbAeBrRcPv3c0/gEjPR0okvqUp0A1KsUvKetyq4ajYW7UAzyFPQIJ9v5M+y47TAB9oRefQ== + dependencies: + "@firebase/analytics-types" "0.3.1" + "@firebase/component" "0.1.14" + "@firebase/installations" "0.4.12" + "@firebase/logger" "0.2.5" + "@firebase/util" "0.2.49" + tslib "^1.11.1" + +"@firebase/app-types@0.6.1": + version "0.6.1" + resolved "https://registry.yarnpkg.com/@firebase/app-types/-/app-types-0.6.1.tgz#dcbd23030a71c0c74fc95d4a3f75ba81653850e9" + integrity sha512-L/ZnJRAq7F++utfuoTKX4CLBG5YR7tFO3PLzG1/oXXKEezJ0kRL3CMRoueBEmTCzVb/6SIs2Qlaw++uDgi5Xyg== + +"@firebase/app@0.6.6": + version "0.6.6" + resolved "https://registry.yarnpkg.com/@firebase/app/-/app-0.6.6.tgz#94dfe36f3089d97d7963c1b36fdf125cc249350b" + integrity sha512-9NNhFedXHhUWDsbJL/A7vgiq9EDeqktFbkPYRfqN/GONIfVHfgAXOwQkEgz1trYV+XBP/n0Wyz8+lzXxu0+m8g== + dependencies: + "@firebase/app-types" "0.6.1" + "@firebase/component" "0.1.14" + "@firebase/logger" "0.2.5" + "@firebase/util" "0.2.49" + dom-storage "2.1.0" + tslib "^1.11.1" + xmlhttprequest "1.8.0" + +"@firebase/auth-interop-types@0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@firebase/auth-interop-types/-/auth-interop-types-0.1.5.tgz#9fc9bd7c879f16b8d1bb08373a0f48c3a8b74557" + integrity sha512-88h74TMQ6wXChPA6h9Q3E1Jg6TkTHep2+k63OWg3s0ozyGVMeY+TTOti7PFPzq5RhszQPQOoCi59es4MaRvgCw== + +"@firebase/auth-types@0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@firebase/auth-types/-/auth-types-0.10.1.tgz#7815e71c9c6f072034415524b29ca8f1d1770660" + integrity sha512-/+gBHb1O9x/YlG7inXfxff/6X3BPZt4zgBv4kql6HEmdzNQCodIRlEYnI+/da+lN+dha7PjaFH7C7ewMmfV7rw== + +"@firebase/auth@0.14.7": + version "0.14.7" + resolved "https://registry.yarnpkg.com/@firebase/auth/-/auth-0.14.7.tgz#9a46dd68efff7af7ec8c420b35f26d118c773cff" + integrity sha512-NTQY9luV70XUA6zGYOWloDSaOT+l0/R4u3W7ptqVCfZNc4DAt7euUkTbj7SDD14902sHF54j+tk5kmpEmMd0jA== + dependencies: + "@firebase/auth-types" "0.10.1" + +"@firebase/component@0.1.14": + version "0.1.14" + resolved "https://registry.yarnpkg.com/@firebase/component/-/component-0.1.14.tgz#2f0d09bbe672dad7afc14bde6f5feeb389740650" + integrity sha512-jbcTAne5mn5T508TY5BFrDOT1v/hXiX/22eMXweCXFbD+9JbsMztwQhNwqjwB8ihNAYG2FKw64UfI9NM04lD/g== + dependencies: + "@firebase/util" "0.2.49" + tslib "^1.11.1" + +"@firebase/database-types@0.5.1": + version "0.5.1" + resolved "https://registry.yarnpkg.com/@firebase/database-types/-/database-types-0.5.1.tgz#fab2f3fb48eec374a9f435ed21e138635cb9b71c" + integrity sha512-onQxom1ZBYBJ648w/VNRzUewovEDAH7lvnrrpCd69ukkyrMk6rGEO/PQ9BcNEbhlNtukpsqRS0oNOFlHs0FaSA== + dependencies: + "@firebase/app-types" "0.6.1" + +"@firebase/database@0.6.5": + version "0.6.5" + resolved "https://registry.yarnpkg.com/@firebase/database/-/database-0.6.5.tgz#e3b0a23166ca1d2d6308d1dbef82e5fba020ffb8" + integrity sha512-4AnsLUscnCZ48nRGe0YKmHq/cQ4pcM3pRV9O4Uh6mPQpTSixPDLMveuAHYJFUI9tgj5I+FNqjxezUFLS7+9XOw== + dependencies: + "@firebase/auth-interop-types" "0.1.5" + "@firebase/component" "0.1.14" + "@firebase/database-types" "0.5.1" + "@firebase/logger" "0.2.5" + "@firebase/util" "0.2.49" + faye-websocket "0.11.3" + tslib "^1.11.1" + +"@firebase/firestore-types@1.11.0": + version "1.11.0" + resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-1.11.0.tgz#ccb734fd424b8b6c3aff3ad1921a89ee31be229b" + integrity sha512-hD7+cmMUvT5OJeWVrcRkE87PPuj/0/Wic6bntCopJE1WIX/Dm117AUkHgKd3S7Ici6DLp4bdlx1MjjwWL5942w== + +"@firebase/firestore@1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-1.15.2.tgz#c0686a19a3ba60a608245ee108d5ed661bd7c8e4" + integrity sha512-JIXmrQjTFWRK91gY+6IK8wLNdAt59jBlxM9aa+rxwxZfK2tu19Gy2WBbMVrXv4DXHdlYVGODwE9Qan55B3nu3Q== + dependencies: + "@firebase/component" "0.1.14" + "@firebase/firestore-types" "1.11.0" + "@firebase/logger" "0.2.5" + "@firebase/util" "0.2.49" + "@firebase/webchannel-wrapper" "0.2.41" + "@grpc/grpc-js" "^1.0.0" + "@grpc/proto-loader" "^0.5.0" + tslib "^1.11.1" + +"@firebase/functions-types@0.3.17": + version "0.3.17" + resolved "https://registry.yarnpkg.com/@firebase/functions-types/-/functions-types-0.3.17.tgz#348bf5528b238eeeeeae1d52e8ca547b21d33a94" + integrity sha512-DGR4i3VI55KnYk4IxrIw7+VG7Q3gA65azHnZxo98Il8IvYLr2UTBlSh72dTLlDf25NW51HqvJgYJDKvSaAeyHQ== + +"@firebase/functions@0.4.46": + version "0.4.46" + resolved "https://registry.yarnpkg.com/@firebase/functions/-/functions-0.4.46.tgz#5e1895e31e02c2bf3ebaff318439b191daf19ec7" + integrity sha512-Vr7CmlIRcocDPG7XTuepU9gTEZ58ZUjLwaaFNPlF6fo/9fGlnGDwrZa6Y1HPqXmkNIcHQWl2UteSXKnDuPKczg== + dependencies: + "@firebase/component" "0.1.14" + "@firebase/functions-types" "0.3.17" + "@firebase/messaging-types" "0.4.5" + isomorphic-fetch "2.2.1" + tslib "^1.11.1" + +"@firebase/installations-types@0.3.4": + version "0.3.4" + resolved "https://registry.yarnpkg.com/@firebase/installations-types/-/installations-types-0.3.4.tgz#589a941d713f4f64bf9f4feb7f463505bab1afa2" + integrity sha512-RfePJFovmdIXb6rYwtngyxuEcWnOrzdZd9m7xAW0gRxDIjBT20n3BOhjpmgRWXo/DAxRmS7bRjWAyTHY9cqN7Q== + +"@firebase/installations@0.4.12": + version "0.4.12" + resolved "https://registry.yarnpkg.com/@firebase/installations/-/installations-0.4.12.tgz#c4856c07c59c0ce383502a39f381a6700b3d359f" + integrity sha512-DFN+lfrh+Yl2VoEuCZ4JpZQ2+F1C44gbOvmfVDoYEW4qDYgul7kP2jH+38xxdPubOpaNKZKmGKid4EkgtMnX0A== + dependencies: + "@firebase/component" "0.1.14" + "@firebase/installations-types" "0.3.4" + "@firebase/util" "0.2.49" + idb "3.0.2" + tslib "^1.11.1" + +"@firebase/logger@0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@firebase/logger/-/logger-0.2.5.tgz#bac27bfef32b36e3ecc4b9a5018e9441cb4765e6" + integrity sha512-qqw3m0tWs/qrg7axTZG/QZq24DIMdSY6dGoWuBn08ddq7+GLF5HiqkRj71XznYeUUbfRq5W9C/PSFnN4JxX+WA== + +"@firebase/messaging-types@0.4.5": + version "0.4.5" + resolved "https://registry.yarnpkg.com/@firebase/messaging-types/-/messaging-types-0.4.5.tgz#452572d3c5b7fa83659fdb1884450477229f5dc4" + integrity sha512-sux4fgqr/0KyIxqzHlatI04Ajs5rc3WM+WmtCpxrKP1E5Bke8xu/0M+2oy4lK/sQ7nov9z15n3iltAHCgTRU3Q== + +"@firebase/messaging@0.6.18": + version "0.6.18" + resolved "https://registry.yarnpkg.com/@firebase/messaging/-/messaging-0.6.18.tgz#613241fafc56c9548a4105bcd93f18c80a1f0fac" + integrity sha512-pu2K+kXuPO4i+9oeQ6nbh0Xxnb1XaQmAiuRRXUmr9sGmo6Sw2ZpYNEhHIHVxvFDn3OUg+QvGgM/ft16kG3DHRQ== + dependencies: + "@firebase/component" "0.1.14" + "@firebase/installations" "0.4.12" + "@firebase/messaging-types" "0.4.5" + "@firebase/util" "0.2.49" + idb "3.0.2" + tslib "^1.11.1" + +"@firebase/performance-types@0.0.13": + version "0.0.13" + resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.0.13.tgz#58ce5453f57e34b18186f74ef11550dfc558ede6" + integrity sha512-6fZfIGjQpwo9S5OzMpPyqgYAUZcFzZxHFqOyNtorDIgNXq33nlldTL/vtaUZA8iT9TT5cJlCrF/jthKU7X21EA== + +"@firebase/performance@0.3.7": + version "0.3.7" + resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.3.7.tgz#1eb2e48a0729bc537b9987f3df7bab464ada725c" + integrity sha512-H4yts/IZ6/8zy5rdsLH0ZbW7Qg5Yj13lCLlvNFxqtDlKI8UbgxvuBkDmXLApA+Ze2Ah2vRSSJ4J3LdxxRnC62Q== + dependencies: + "@firebase/component" "0.1.14" + "@firebase/installations" "0.4.12" + "@firebase/logger" "0.2.5" + "@firebase/performance-types" "0.0.13" + "@firebase/util" "0.2.49" + tslib "^1.11.1" + +"@firebase/polyfill@0.3.36": + version "0.3.36" + resolved "https://registry.yarnpkg.com/@firebase/polyfill/-/polyfill-0.3.36.tgz#c057cce6748170f36966b555749472b25efdb145" + integrity sha512-zMM9oSJgY6cT2jx3Ce9LYqb0eIpDE52meIzd/oe/y70F+v9u1LDqk5kUF5mf16zovGBWMNFmgzlsh6Wj0OsFtg== + dependencies: + core-js "3.6.5" + promise-polyfill "8.1.3" + whatwg-fetch "2.0.4" + +"@firebase/remote-config-types@0.1.9": + version "0.1.9" + resolved "https://registry.yarnpkg.com/@firebase/remote-config-types/-/remote-config-types-0.1.9.tgz#fe6bbe4d08f3b6e92fce30e4b7a9f4d6a96d6965" + integrity sha512-G96qnF3RYGbZsTRut7NBX0sxyczxt1uyCgXQuH/eAfUCngxjEGcZQnBdy6mvSdqdJh5mC31rWPO4v9/s7HwtzA== + +"@firebase/remote-config@0.1.23": + version "0.1.23" + resolved "https://registry.yarnpkg.com/@firebase/remote-config/-/remote-config-0.1.23.tgz#9b5f1b18fa71b7df96c5ed4fee95b53244726590" + integrity sha512-psirtTiu9tfVxSVHo82iIdaD0IXP+DgpAPdtxahDlq/b7Ln26fqdJ8KTM1AKI20ZV2h6d4U/HqeouObl+LyrJg== + dependencies: + "@firebase/component" "0.1.14" + "@firebase/installations" "0.4.12" + "@firebase/logger" "0.2.5" + "@firebase/remote-config-types" "0.1.9" + "@firebase/util" "0.2.49" + tslib "^1.11.1" + +"@firebase/storage-types@0.3.12": + version "0.3.12" + resolved "https://registry.yarnpkg.com/@firebase/storage-types/-/storage-types-0.3.12.tgz#79540761fb3ad8d674c98712633284d81b268e0f" + integrity sha512-DDV6Fs6aYoGw3w/zZZTkqiipxihnsvHf6znbeZYjIIHit3tr1uLJdGPDPiCTfZcTGPpg2ux6ZmvNDvVgJdHALw== + +"@firebase/storage@0.3.36": + version "0.3.36" + resolved "https://registry.yarnpkg.com/@firebase/storage/-/storage-0.3.36.tgz#2337fa19aa96652597e61388cd361619ab0204e2" + integrity sha512-DcxULwmoyZnpulW6e/G2y6gKXCMwnKWy8snw+7f4yvb6RI7WFMYB8nIb2CSArWmrnT7YD7e+G9BA1a6nZ0eycQ== + dependencies: + "@firebase/component" "0.1.14" + "@firebase/storage-types" "0.3.12" + "@firebase/util" "0.2.49" + tslib "^1.11.1" + +"@firebase/util@0.2.49": + version "0.2.49" + resolved "https://registry.yarnpkg.com/@firebase/util/-/util-0.2.49.tgz#01b7e08c2a542e54d9b24b2a93bc5d4de2c5d243" + integrity sha512-SjUoxSqIfcSvDBiMiFEF5SmUOcWNbMH2asJ0VZ1T3vPBlCIRp6tk+T3LMvUWAI8OCnTpbGtpX1fTKiUDLP4xkQ== + dependencies: + tslib "^1.11.1" + +"@firebase/webchannel-wrapper@0.2.41": + version "0.2.41" + resolved "https://registry.yarnpkg.com/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.2.41.tgz#4e470c25a99fa0b1f629f1c5ef180a318d399fd0" + integrity sha512-XcdMT5PSZHiuf7LJIhzKIe+RyYa25S3LHRRvLnZc6iFjwXkrSDJ8J/HWO6VT8d2ZTbawp3VcLEjRF/VN8glCrA== + +"@grpc/grpc-js@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.1.0.tgz#154fdc927ade3ae8e85e518533f7039cc600438d" + integrity sha512-IKNGIOuK7kXmitfmZ9JSB8Nz7RmfDchANzxgOLcMoJCZDKqoNzSLssaYTnvc0GD3FG3sBqW4Jisqt63W2KQ3Cw== + dependencies: + semver "^6.2.0" + +"@grpc/proto-loader@^0.5.0": + version "0.5.4" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.5.4.tgz#038a3820540f621eeb1b05d81fbedfb045e14de0" + integrity sha512-HTM4QpI9B2XFkPz7pjwMyMgZchJ93TVkL3kWPW8GDMDKYxsMnmf4w2TNMJK7+KNiYHS5cJrCEAFlF+AwtXWVPA== + dependencies: + lodash.camelcase "^4.3.0" + protobufjs "^6.8.6" + "@hapi/address@2.x.x": version "2.1.4" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" @@ -1408,6 +1646,59 @@ "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78= + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A= + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU= + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E= + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik= + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0= + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q= + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= + "@sheerun/mutationobserver-shim@^0.3.2": version "0.3.3" resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#5405ee8e444ed212db44e79351f0c70a582aae25" @@ -1687,6 +1978,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== +"@types/long@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" + integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -1714,6 +2010,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.47.tgz#5007b8866a2f9150de82335ca7e24dd1d59bdfb5" integrity sha512-yzBInQFhdY8kaZmqoL2+3U5dSTMrKaYcb561VU+lDzAYvqt+2lojvBEy+hmpSNuXnPTx7m9+04CzWYOUqWME2A== +"@types/node@^13.7.0": + version "13.13.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.12.tgz#9c72e865380a7dc99999ea0ef20fc9635b503d20" + integrity sha512-zWz/8NEPxoXNT9YyF2osqyA9WjssZukYpgI4UYZpOjcyqwIUqWGkcCionaEb9Ki+FULyPyvNFpg/329Kd2/pbw== + "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -2460,6 +2761,11 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== +autobind-decorator@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/autobind-decorator/-/autobind-decorator-2.4.0.tgz#ea9e1c98708cf3b5b356f7cf9f10f265ff18239c" + integrity sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw== + autoprefixer@^9.6.1: version "9.7.4" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.4.tgz#f8bf3e06707d047f0641d87aee8cfb174b2a5378" @@ -3607,6 +3913,11 @@ core-js-pure@^3.0.0: resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.4.tgz#4bf1ba866e25814f149d4e9aaa08c36173506e3a" integrity sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw== +core-js@3.6.5: + version "3.6.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" + integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -4251,6 +4562,11 @@ dom-serializer@0: domelementtype "^2.0.1" entities "^2.0.0" +dom-storage@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/dom-storage/-/dom-storage-2.1.0.tgz#00fb868bc9201357ea243c7bcfd3304c1e34ea39" + integrity sha512-g6RpyWXzl0RR6OTElHKBl7nwnK87GUyZMYC7JWsB/IA73vpqK2K6LT39x4VepLxlSsWBFrPVLnsSR5Jyty0+2Q== + domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" @@ -5044,6 +5360,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +faye-websocket@0.11.3, faye-websocket@~0.11.1: + version "0.11.3" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" + integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA== + dependencies: + websocket-driver ">=0.5.1" + faye-websocket@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" @@ -5051,13 +5374,6 @@ faye-websocket@^0.10.0: dependencies: websocket-driver ">=0.5.1" -faye-websocket@~0.11.1: - version "0.11.3" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e" - integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA== - dependencies: - websocket-driver ">=0.5.1" - fb-watchman@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" @@ -5209,6 +5525,26 @@ find-versions@^3.2.0: dependencies: semver-regex "^2.0.0" +firebase@^7.15.2: + version "7.15.2" + resolved "https://registry.yarnpkg.com/firebase/-/firebase-7.15.2.tgz#6d51d05fe1124253b2b466a8a61f303f82cbef47" + integrity sha512-JZ5GzIIQdh3BUmYr6A8ZYlYnhorFhKim5rDnz3F4ttakoYHFlD3gRVvxwJkEmemnbK2Cy+MZKImabObEuKrdrA== + dependencies: + "@firebase/analytics" "0.3.7" + "@firebase/app" "0.6.6" + "@firebase/app-types" "0.6.1" + "@firebase/auth" "0.14.7" + "@firebase/database" "0.6.5" + "@firebase/firestore" "1.15.2" + "@firebase/functions" "0.4.46" + "@firebase/installations" "0.4.12" + "@firebase/messaging" "0.6.18" + "@firebase/performance" "0.3.7" + "@firebase/polyfill" "0.3.36" + "@firebase/remote-config" "0.1.23" + "@firebase/storage" "0.3.36" + "@firebase/util" "0.2.49" + flat-cache@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" @@ -5970,6 +6306,11 @@ icss-utils@^4.0.0, icss-utils@^4.1.1: dependencies: postcss "^7.0.14" +idb@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/idb/-/idb-3.0.2.tgz#c8e9122d5ddd40f13b60ae665e4862f8b13fa384" + integrity sha512-+FLa/0sTXqyux0o6C+i2lOR0VoS60LU/jzUo5xjfY6+7sEEgy4Gz1O7yFBXvjd7N0NyIGWIRg8DcQSLEG+VSPw== + identity-obj-proxy@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz#94d2bda96084453ef36fbc5aaec37e0f79f1fc14" @@ -6599,7 +6940,7 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -isomorphic-fetch@^2.1.1: +isomorphic-fetch@2.2.1, isomorphic-fetch@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" integrity sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk= @@ -7421,6 +7762,11 @@ lodash._reinterpolate@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -7475,6 +7821,11 @@ loglevel@^1.6.6: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.7.tgz#b3e034233188c68b889f5b862415306f565e2c56" integrity sha512-cY2eLFrQSAfVPhCgH1s7JI73tMbg9YC3v3+ZHVW67sBS7UxWzNEk/ZBbSfLykBWHp33dqqtOv82gjhKEi81T/A== +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + longest-streak@^2.0.1: version "2.0.4" resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" @@ -9629,6 +9980,11 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +promise-polyfill@8.1.3: + version "8.1.3" + resolved "https://registry.yarnpkg.com/promise-polyfill/-/promise-polyfill-8.1.3.tgz#8c99b3cf53f3a91c68226ffde7bde81d7f904116" + integrity sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g== + promise@^7.1.1: version "7.3.1" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" @@ -9660,6 +10016,25 @@ prop-types@^15.6.2, prop-types@^15.7.2: object-assign "^4.1.1" react-is "^16.8.1" +protobufjs@^6.8.6: + version "6.9.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.9.0.tgz#c08b2bf636682598e6fabbf0edb0b1256ff090bd" + integrity sha512-LlGVfEWDXoI/STstRDdZZKb/qusoAWUnmLg9R8OLSO473mBLWHowx8clbX5/+mKDEI+v7GzjoK9tRPZMMcoTrg== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.1" + "@types/node" "^13.7.0" + long "^4.0.0" + proxy-addr@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" @@ -11738,6 +12113,11 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== +tslib@^1.11.1: + version "1.13.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" + integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== + tsutils@^3.17.1: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" @@ -12350,6 +12730,11 @@ whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5: dependencies: iconv-lite "0.4.24" +whatwg-fetch@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" + integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== + whatwg-fetch@>=0.10.0, whatwg-fetch@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" @@ -12640,6 +13025,11 @@ xmlchars@^2.1.1: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== +xmlhttprequest@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" + integrity sha1-Z/4HXFwk/vOfnWX197f+dRcZaPw= + xregexp@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50" From d7afbff1cf5f22d7334ae4675729ea49eaee57ce Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 12:14:53 +0800 Subject: [PATCH 20/64] fix lint errors --- .../merchant/sign-up/SignUpCard.tsx | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 91772b34..82704139 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -98,7 +98,7 @@ class SignUpCard extends React.Component<{}, SignUpState> { this.setState({ [name]: value, - errorMessage: '' + errorMessage: '', }); } @@ -111,14 +111,14 @@ class SignUpCard extends React.Component<{}, SignUpState> { if (!(name && email && password && confirmPassword && vpa)) { this.setState({ - errorMessage: 'Please fill in all of the fields.' + errorMessage: 'Please fill in all of the fields.', }); return; } if (password !== confirmPassword) { this.setState({ - errorMessage: 'Passwords do not match.' + errorMessage: 'Passwords do not match.', }); return; } @@ -129,11 +129,31 @@ class SignUpCard extends React.Component<{}, SignUpState> { - - - - - + + + + + {this.state.errorMessage} From 25f36e6166adef936b868da6358064ff8762dd16 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 15:10:40 +0800 Subject: [PATCH 21/64] Use react hooks --- .../merchant/sign-up/SignUpCard.tsx | 200 ++++++++++-------- 1 file changed, 107 insertions(+), 93 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 82704139..57d93f40 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React from 'react'; +import React, {useState} from 'react'; import FormRow from 'components/common/FormRow'; import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; @@ -77,97 +77,111 @@ interface SignUpState { * This is the card containing the sign up form for the Merchant app. * It is displayed in the Sign Up page. */ -class SignUpCard extends React.Component<{}, SignUpState> { - constructor(props: Readonly<{}>) { - super(props); - this.state = { - name: '', - email: '', - password: '', - confirmPassword: '', - vpa: '', - errorMessage: '', - }; - this.handleInputChange = this.handleInputChange.bind(this); - this.handleSubmit = this.handleSubmit.bind(this); - } - - handleInputChange(event: React.ChangeEvent) { - const name: string = event.target.name; - const value: string = event.target.value; - - this.setState({ - [name]: value, - errorMessage: '', - }); - } - - handleSubmit() { - const name: string | undefined = this.state.name; - const email: string | undefined = this.state.email; - const password: string | undefined = this.state.password; - const confirmPassword: string | undefined = this.state.confirmPassword; - const vpa: string | undefined = this.state.vpa; - - if (!(name && email && password && confirmPassword && vpa)) { - this.setState({ - errorMessage: 'Please fill in all of the fields.', - }); - return; - } - - if (password !== confirmPassword) { - this.setState({ - errorMessage: 'Passwords do not match.', - }); - return; - } - } - - render() { - return ( - - - - - - - - - - - {this.state.errorMessage} - - - Sign Up - - - Already have an account? Sign in{' '} - now! - - - ); - } -} +const SignUpCard: React.FC = () => { + const [name, setName] = useState(''); + const [nameError, setNameError] = useState(''); + + const [email, setEmail] = useState(''); + const [emailError, setEmailError] = useState(''); + + const [password, setPassword] = useState(''); + const [passwordError, setPasswordError] = useState(''); + + const [confirmPassword, setConfirmPassword] = useState(''); + const [confirmPasswordError, setConfirmPasswordError] = useState(''); + + const [vpa, setVpa] = useState(''); + const [vpaError, setVpaError] = useState(''); + + const [errorMessage, setErrorMessage] = useState(''); + + const handleNameChange = (event: React.ChangeEvent) => { + event.target.value + ? setNameError('') + : setNameError('Name cannot be empty.'); + setName(event.target.value); + }; + + const handleEmailChange = (event: React.ChangeEvent) => { + event.target.value + ? setEmailError('') + : setEmailError('Email cannot be empty.'); + setEmail(event.target.value); + }; + + const handlePasswordChange = (event: React.ChangeEvent) => { + event.target.value + ? setPasswordError('') + : setPasswordError('Password cannot be empty.'); + (!confirmPassword || event.target.value === confirmPassword) + ? setConfirmPasswordError('') + : setConfirmPasswordError('Passwords do no match.'); + setPassword(event.target.value); + }; + + const handleConfirmPasswordChange = ( + event: React.ChangeEvent + ) => { + event.target.value === password + ? setConfirmPasswordError('') + : setConfirmPasswordError('Passwords do no match.'); + setConfirmPassword(event.target.value); + }; + + const handleVpaChange = (event: React.ChangeEvent) => { + event.target.value ? setVpaError('') : setVpaError('VPA cannot be empty.'); + setVpa(event.target.value); + }; + + const handleSubmit = () => {}; + + return ( + + + + + + + + + + + {errorMessage} + + + Sign Up + + + Already have an account? Sign in{' '} + now! + + + ); +}; export default SignUpCard; From ac264e8401d84a7d29798e0a279cf50e2bbc8790 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 15:11:20 +0800 Subject: [PATCH 22/64] Make Group Buy Merchant header smaller --- web/src/components/common/GroupBuyMerchantHeader.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/components/common/GroupBuyMerchantHeader.tsx b/web/src/components/common/GroupBuyMerchantHeader.tsx index a8d7b8a1..19110cb9 100644 --- a/web/src/components/common/GroupBuyMerchantHeader.tsx +++ b/web/src/components/common/GroupBuyMerchantHeader.tsx @@ -27,13 +27,13 @@ const HeaderContainer = styled.div` `; const Logo = styled(GPayLogo)` - width: 80px; + width: 70px; `; const Header = styled.h1` - font-size: 32px; + font-size: 28px; font-weight: normal; - line-height: 48px; + line-height: 42px; margin: 0; text-align: center; `; From 3d4fb50dae533a5d74cb89464980702aab55a7d6 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 15:11:43 +0800 Subject: [PATCH 23/64] Show individual error for each form field --- web/src/components/common/FormRow.tsx | 60 ++++++++++++++++++++------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index 8aec9e8f..a1900177 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -16,22 +16,32 @@ import React from 'react'; +import Col from 'muicss/lib/react/col'; import Row from 'muicss/lib/react/row'; import styled from 'styled-components'; const StyledRow = styled(Row)` display: flex; flex-direction: row; - align-items: center; + align-items: top; justify-content: center; - margin: 20px 0; + margin: 10px 0; +`; + +const StyledCol = styled(Col)` + display: flex; + flex-direction: column; + align-items: left; `; const Label = styled.label` width: 100px; - font-size: 14px; + height: 30px; margin-right: 20px; + + font-size: 14px; + vertical-align: middle; `; const Input = styled.input` @@ -44,28 +54,50 @@ const Input = styled.input` box-shadow: 4px 2px 4px rgba(0, 0, 0, 0.25); `; +const ErrorContainer = styled.div` + height: 10px; + margin-left: 15px; + margin-top: 5px; + + + font-size: 10px; + line-height: 10px; + color: var(--bright-red); +`; + interface FormRowProps { label: string; inputType: string; onChange: React.EventHandler>; + error: string; } /** * This is a row in a form, consisting of a label and an input field shown * side by side. */ -const FormRow: React.FC = ({label, inputType, onChange}) => ( +const FormRow: React.FC = ({ + label, + inputType, + onChange, + error, +}) => ( - - a.toUpperCase()) - .replace(/\s/g, '') - .replace(/^(.)/, a => a.toLowerCase())} - onChange={onChange} - /> + + + + + a.toUpperCase()) + .replace(/\s/g, '') + .replace(/^(.)/, a => a.toLowerCase())} + onChange={onChange} + /> + {error} + ); From 0252c864a6b36d9cd7cb181ddfb30ea85c154b98 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 15:20:37 +0800 Subject: [PATCH 24/64] Refactor constants into a separate file --- .../merchant/sign-up/SignUpCard.tsx | 26 +++++++++++-------- web/src/constants/sign-up-errors.ts | 21 +++++++++++++++ 2 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 web/src/constants/sign-up-errors.ts diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 57d93f40..c95baca2 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -14,6 +14,14 @@ * limitations under the License. */ +import { + NAME_EMPTY, + EMAIL_EMPTY, + PASSWORD_EMPTY, + PASSWORDS_DO_NOT_MATCH, + VPA_EMPTY, +} from 'constants/sign-up-errors'; + import React, {useState} from 'react'; import FormRow from 'components/common/FormRow'; @@ -96,26 +104,22 @@ const SignUpCard: React.FC = () => { const [errorMessage, setErrorMessage] = useState(''); const handleNameChange = (event: React.ChangeEvent) => { - event.target.value - ? setNameError('') - : setNameError('Name cannot be empty.'); + event.target.value ? setNameError('') : setNameError(NAME_EMPTY); setName(event.target.value); }; const handleEmailChange = (event: React.ChangeEvent) => { - event.target.value - ? setEmailError('') - : setEmailError('Email cannot be empty.'); + event.target.value ? setEmailError('') : setEmailError(EMAIL_EMPTY); setEmail(event.target.value); }; const handlePasswordChange = (event: React.ChangeEvent) => { event.target.value ? setPasswordError('') - : setPasswordError('Password cannot be empty.'); - (!confirmPassword || event.target.value === confirmPassword) + : setPasswordError(PASSWORD_EMPTY); + !confirmPassword || event.target.value === confirmPassword ? setConfirmPasswordError('') - : setConfirmPasswordError('Passwords do no match.'); + : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); setPassword(event.target.value); }; @@ -124,12 +128,12 @@ const SignUpCard: React.FC = () => { ) => { event.target.value === password ? setConfirmPasswordError('') - : setConfirmPasswordError('Passwords do no match.'); + : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); setConfirmPassword(event.target.value); }; const handleVpaChange = (event: React.ChangeEvent) => { - event.target.value ? setVpaError('') : setVpaError('VPA cannot be empty.'); + event.target.value ? setVpaError('') : setVpaError(VPA_EMPTY); setVpa(event.target.value); }; diff --git a/web/src/constants/sign-up-errors.ts b/web/src/constants/sign-up-errors.ts new file mode 100644 index 00000000..53092b41 --- /dev/null +++ b/web/src/constants/sign-up-errors.ts @@ -0,0 +1,21 @@ +/** + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export const NAME_EMPTY = 'Name cannot be empty.'; +export const EMAIL_EMPTY = 'Email cannot be empty.'; +export const PASSWORD_EMPTY = 'Password cannot be empty.'; +export const PASSWORDS_DO_NOT_MATCH = 'Passwords do no match.'; +export const VPA_EMPTY = 'VPA cannot be empty.'; From 309f11c84409e0b84fa5ed95cacb2aa478ab7616 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 15:20:50 +0800 Subject: [PATCH 25/64] Fix lint error --- web/src/components/common/FormRow.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index a1900177..abb7fa33 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -59,7 +59,6 @@ const ErrorContainer = styled.div` margin-left: 15px; margin-top: 5px; - font-size: 10px; line-height: 10px; color: var(--bright-red); From 5bb59280ba1af194d4d7384d5650fcb80cde1854 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 15:27:06 +0800 Subject: [PATCH 26/64] Check form fields in handleSubmit --- web/src/components/merchant/sign-up/SignUpCard.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index c95baca2..b68a4eb9 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -137,7 +137,14 @@ const SignUpCard: React.FC = () => { setVpa(event.target.value); }; - const handleSubmit = () => {}; + const handleSubmit = () => { + if (!name) setNameError(NAME_EMPTY); + if (!email) setEmailError(EMAIL_EMPTY); + if (!password) setPasswordError(PASSWORD_EMPTY); + if (password !== confirmPassword) + setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); + if (!vpa) setVpaError(VPA_EMPTY); + }; return ( From 52f2bc1cf7554916522abb98fb9504a2f136a961 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 15:57:35 +0800 Subject: [PATCH 27/64] Remove unused interface --- web/src/components/merchant/sign-up/SignUpCard.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index b68a4eb9..466b6234 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -72,15 +72,6 @@ const StyledButton = styled(Button)` margin: 0; `; -interface SignUpState { - name?: string; - email?: string; - password?: string; - confirmPassword?: string; - vpa?: string; - errorMessage?: string; -} - /** * This is the card containing the sign up form for the Merchant app. * It is displayed in the Sign Up page. From 7e9ed2644a97e3079b5156051de6f4ed19ba8c1a Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 16:27:04 +0800 Subject: [PATCH 28/64] Enlarge error message font size --- web/src/components/common/FormRow.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index abb7fa33..01d713d5 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -55,11 +55,11 @@ const Input = styled.input` `; const ErrorContainer = styled.div` - height: 10px; + height: 12px; margin-left: 15px; margin-top: 5px; - font-size: 10px; + font-size: 12px; line-height: 10px; color: var(--bright-red); `; From b0856f41272b0f9744ac8541ac3e4da72cc7cdf7 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 16:42:15 +0800 Subject: [PATCH 29/64] Align Sign Up Form labels with inputs --- web/src/components/common/FormRow.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index 01d713d5..b445817d 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -42,6 +42,10 @@ const Label = styled.label` font-size: 14px; vertical-align: middle; + + display: flex; + flex-direction: column; + justify-content: center; `; const Input = styled.input` From 3681d50fda29adfa34c979a7c75feb3eb966c6d4 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 16:49:35 +0800 Subject: [PATCH 30/64] Remove unused const --- web/src/components/merchant/sign-up/SignUpCard.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 466b6234..39be4e39 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -92,8 +92,6 @@ const SignUpCard: React.FC = () => { const [vpa, setVpa] = useState(''); const [vpaError, setVpaError] = useState(''); - const [errorMessage, setErrorMessage] = useState(''); - const handleNameChange = (event: React.ChangeEvent) => { event.target.value ? setNameError('') : setNameError(NAME_EMPTY); setName(event.target.value); @@ -172,9 +170,6 @@ const SignUpCard: React.FC = () => { error={vpaError} /> - - {errorMessage} - Sign Up From 0d3203bb2b12acc682099bed44cb7c950a9fea0e Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 16:59:02 +0800 Subject: [PATCH 31/64] Remove unused const --- web/src/components/merchant/sign-up/SignUpCard.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 39be4e39..a126dc9d 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -54,10 +54,6 @@ const StyledRow = styled(Row)` line-height: 40px; `; -const ErrorContainer = styled.div` - color: var(--bright-red); -`; - const StyledButton = styled(Button)` height: 40px; width: 200px; From 1ea484296123678549c941ea07b6bede9a16c315 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 17:18:04 +0800 Subject: [PATCH 32/64] Refactor function to format phrase into camelCase --- web/src/components/common/FormRow.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index b445817d..3f7635ad 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -75,6 +75,13 @@ interface FormRowProps { error: string; } +const toCamelCase = (phrase: string) => + phrase + .toLowerCase() + .replace(/\s(.)/g, a => a.toUpperCase()) + .replace(/\s/g, '') + .replace(/^(.)/, a => a.toLowerCase()); + /** * This is a row in a form, consisting of a label and an input field shown * side by side. @@ -90,15 +97,7 @@ const FormRow: React.FC = ({ - a.toUpperCase()) - .replace(/\s/g, '') - .replace(/^(.)/, a => a.toLowerCase())} - onChange={onChange} - /> + {error} From b39a28b3a63649fd79742a07a36f75e6fc5d055d Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 17:21:03 +0800 Subject: [PATCH 33/64] Update JSDoc comment for FormRow --- web/src/components/common/FormRow.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index 3f7635ad..e430bbca 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -84,7 +84,8 @@ const toCamelCase = (phrase: string) => /** * This is a row in a form, consisting of a label and an input field shown - * side by side. + * side by side. This also contains a container for error message which is + * displayed below the input field where applicable. */ const FormRow: React.FC = ({ label, From 42f701880d61ecf3b06201dad756c20b2ec9dfbf Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 17:53:09 +0800 Subject: [PATCH 34/64] Add comments to explain Sign Up form checks --- web/src/components/merchant/sign-up/SignUpCard.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index a126dc9d..dcfd0464 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -102,6 +102,8 @@ const SignUpCard: React.FC = () => { event.target.value ? setPasswordError('') : setPasswordError(PASSWORD_EMPTY); + // We don't check that passwords match if user hasn't filled in + // 'Confirm Password' yet. !confirmPassword || event.target.value === confirmPassword ? setConfirmPasswordError('') : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); @@ -111,6 +113,9 @@ const SignUpCard: React.FC = () => { const handleConfirmPasswordChange = ( event: React.ChangeEvent ) => { + // We don't have to check if 'Confirm Password' is empty. If 'Password' is + // is not empty and 'Confirm Password' is empty, we show PASSWORDS_DO_NOT_MATCH. + // If both passwords are empty we show PASSWORD_EMPTY. event.target.value === password ? setConfirmPasswordError('') : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); @@ -123,6 +128,8 @@ const SignUpCard: React.FC = () => { }; const handleSubmit = () => { + // These checks are needed because empty error in the handleChange is shown + // only if user already fills in the field and then deletes it. if (!name) setNameError(NAME_EMPTY); if (!email) setEmailError(EMAIL_EMPTY); if (!password) setPasswordError(PASSWORD_EMPTY); From ed7983c1bdf44b7a7e5b12f814135b89d604b502 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 18:58:13 +0800 Subject: [PATCH 35/64] Use hooks in firebase code --- web/src/components/merchant/sign-up/SignUpCard.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index f7096582..30530eba 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -90,6 +90,8 @@ const SignUpCard: React.FC = () => { const [vpa, setVpa] = useState(''); const [vpaError, setVpaError] = useState(''); + const [errorMessage, setErrorMessage] = useState(''); + const handleNameChange = (event: React.ChangeEvent) => { event.target.value ? setNameError('') : setNameError(NAME_EMPTY); setName(event.target.value); @@ -147,7 +149,6 @@ const SignUpCard: React.FC = () => { }); } - const setState = this.setState.bind(this); firebase .auth() .createUserWithEmailAndPassword(email, password) @@ -164,9 +165,7 @@ const SignUpCard: React.FC = () => { } else if (errorCode === 'auth/operation-not-allowed') { errorMessage = 'Oops, something is wrong. Please try again later!'; } - setState({ - errorMessage, - }); + setErrorMessage(errorMessage); }); }; From 1626701b9c6145f807ad429bc084e40812713c69 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 19:10:54 +0800 Subject: [PATCH 36/64] Append REACT_APP_ in front of env var names --- web/src/components/merchant/sign-up/SignUpCard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 30530eba..1af14270 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -144,8 +144,8 @@ const SignUpCard: React.FC = () => { // Add a new user account to Firebase. if (!firebase.apps.length) { firebase.initializeApp({ - apiKey: process.env.API_KEY, - authDomain: process.env.AUTH_DOMAIN, + apiKey: process.env.REACT_APP_API_KEY, + authDomain: process.env.REACT_APP_AUTH_DOMAIN, }); } From 9d96fefec35cd245917dace4931b94c14aff5ee8 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 19:47:39 +0800 Subject: [PATCH 37/64] Readd logic that was removed due to merging --- web/src/components/merchant/sign-up/SignUpCard.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 1af14270..dd750176 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -141,6 +141,10 @@ const SignUpCard: React.FC = () => { setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); if (!vpa) setVpaError(VPA_EMPTY); + if (!name || !email || !password || password !== confirmPassword || !vpa) { + return; + } + // Add a new user account to Firebase. if (!firebase.apps.length) { firebase.initializeApp({ From 2e3b9c9a559c7b149906b6d9f7ecda5a80358f5f Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 19:53:36 +0800 Subject: [PATCH 38/64] Readd components that were deleted due to merging --- web/src/components/merchant/sign-up/SignUpCard.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index dd750176..6ac0c640 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -55,6 +55,9 @@ const StyledRow = styled(Row)` display: block; line-height: 40px; `; +const ErrorContainer = styled.div` + color: var(--bright-red); +`; const StyledButton = styled(Button)` height: 40px; @@ -208,6 +211,9 @@ const SignUpCard: React.FC = () => { error={vpaError} /> + + {errorMessage} + Sign Up From af6e9278c1c93dbfc5828d29bb76fc00588188bd Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 19:58:00 +0800 Subject: [PATCH 39/64] Remove unused autobind-decorator --- web/package.json | 1 - web/src/components/merchant/sign-up/SignUpCard.tsx | 1 - web/tsconfig.json | 3 +-- web/yarn.lock | 5 ----- 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/web/package.json b/web/package.json index 8b4ac2da..a7fe8b2a 100644 --- a/web/package.json +++ b/web/package.json @@ -16,7 +16,6 @@ "@types/react-dom": "^16.9.0", "@types/react-router-dom": "^5.1.5", "@types/styled-components": "^5.1.0", - "autobind-decorator": "^2.4.0", "firebase": "^7.15.2", "muicss": "^0.10.2", "rc-progress": "^3.0.0", diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 6ac0c640..bdbc2ff3 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -24,7 +24,6 @@ import { import React, {useState} from 'react'; -import autobind from 'autobind-decorator'; import FormRow from 'components/common/FormRow'; import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; import firebase from 'firebase'; diff --git a/web/tsconfig.json b/web/tsconfig.json index 08f8d960..761fa66d 100644 --- a/web/tsconfig.json +++ b/web/tsconfig.json @@ -19,8 +19,7 @@ "isolatedModules": true, "noEmit": true, "jsx": "react", - "baseUrl": "./src/", - "experimentalDecorators": true + "baseUrl": "./src/" }, "include": [ "src" diff --git a/web/yarn.lock b/web/yarn.lock index 7003030c..059a908f 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -2761,11 +2761,6 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autobind-decorator@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/autobind-decorator/-/autobind-decorator-2.4.0.tgz#ea9e1c98708cf3b5b356f7cf9f10f265ff18239c" - integrity sha512-OGYhWUO72V6DafbF8PM8rm3EPbfuyMZcJhtm5/n26IDwO18pohE4eNazLoCGhPiXOCD0gEGmrbU3849QvM8bbw== - autoprefixer@^9.6.1: version "9.7.4" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.4.tgz#f8bf3e06707d047f0641d87aee8cfb174b2a5378" From 2f1b38df7a3993c6eb523b4b94badb447d99ecd2 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 21:01:26 +0800 Subject: [PATCH 40/64] Refactor firebase auth initialisation into src/firebase-auth.ts --- .../merchant/sign-up/SignUpCard.tsx | 35 +++++++------------ web/src/firebase-auth.ts | 29 +++++++++++++++ 2 files changed, 41 insertions(+), 23 deletions(-) create mode 100644 web/src/firebase-auth.ts diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index bdbc2ff3..3b0fb790 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -26,7 +26,7 @@ import React, {useState} from 'react'; import FormRow from 'components/common/FormRow'; import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; -import firebase from 'firebase'; +import firebaseAuth from 'firebase-auth'; import Button from 'muicss/lib/react/button'; import Form from 'muicss/lib/react/form'; import Row from 'muicss/lib/react/row'; @@ -147,31 +147,20 @@ const SignUpCard: React.FC = () => { return; } - // Add a new user account to Firebase. - if (!firebase.apps.length) { - firebase.initializeApp({ - apiKey: process.env.REACT_APP_API_KEY, - authDomain: process.env.REACT_APP_AUTH_DOMAIN, - }); - } - - firebase - .auth() + firebaseAuth .createUserWithEmailAndPassword(email, password) .catch(error => { - const errorCode = error.code; - let errorMessage = error.message; - if (errorCode === 'auth/invalid-email') { - errorMessage = 'Please input a valid email address.'; - } else if (errorCode === 'auth/weak-password') { - errorMessage = 'Password should be at least 6 characters.'; - } else if (errorCode === 'auth/email-already-in-use') { - errorMessage = - 'The email address is already in use by another account.'; - } else if (errorCode === 'auth/operation-not-allowed') { - errorMessage = 'Oops, something is wrong. Please try again later!'; + if (error.code === 'auth/invalid-email') { + setErrorMessage('Please input a valid email address.'); + } else if (error.code === 'auth/weak-password') { + setErrorMessage('Password should be at least 6 characters.'); + } else if (error.code === 'auth/email-already-in-use') { + setErrorMessage( + 'The email address is already in use by another account.' + ); + } else { + setErrorMessage('Oops, something is wrong. Please try again later!'); } - setErrorMessage(errorMessage); }); }; diff --git a/web/src/firebase-auth.ts b/web/src/firebase-auth.ts new file mode 100644 index 00000000..5b46424e --- /dev/null +++ b/web/src/firebase-auth.ts @@ -0,0 +1,29 @@ +/** + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import firebase from 'firebase'; + +// Add a new user account to Firebase. +if (!firebase.apps.length) { + firebase.initializeApp({ + apiKey: process.env.REACT_APP_API_KEY, + authDomain: process.env.REACT_APP_AUTH_DOMAIN, + }); +} + +const firebaseAuth = firebase.auth(); + +export default firebaseAuth; From 90c2e231f457d5af3ba674b65637f6864458f911 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 21:10:59 +0800 Subject: [PATCH 41/64] Refactor firebase error messages into sign-up-errors.ts --- .../merchant/sign-up/SignUpCard.tsx | 41 ++++++++----------- web/src/constants/sign-up-errors.ts | 29 ++++++++++--- 2 files changed, 40 insertions(+), 30 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 3b0fb790..fd9fa2c2 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -14,18 +14,11 @@ * limitations under the License. */ -import { - NAME_EMPTY, - EMAIL_EMPTY, - PASSWORD_EMPTY, - PASSWORDS_DO_NOT_MATCH, - VPA_EMPTY, -} from 'constants/sign-up-errors'; - import React, {useState} from 'react'; import FormRow from 'components/common/FormRow'; import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; +import Errors from 'constants/sign-up-errors'; import firebaseAuth from 'firebase-auth'; import Button from 'muicss/lib/react/button'; import Form from 'muicss/lib/react/form'; @@ -95,24 +88,24 @@ const SignUpCard: React.FC = () => { const [errorMessage, setErrorMessage] = useState(''); const handleNameChange = (event: React.ChangeEvent) => { - event.target.value ? setNameError('') : setNameError(NAME_EMPTY); + event.target.value ? setNameError('') : setNameError(Errors.NAME_EMPTY); setName(event.target.value); }; const handleEmailChange = (event: React.ChangeEvent) => { - event.target.value ? setEmailError('') : setEmailError(EMAIL_EMPTY); + event.target.value ? setEmailError('') : setEmailError(Errors.EMAIL_EMPTY); setEmail(event.target.value); }; const handlePasswordChange = (event: React.ChangeEvent) => { event.target.value ? setPasswordError('') - : setPasswordError(PASSWORD_EMPTY); + : setPasswordError(Errors.PASSWORD_EMPTY); // We don't check that passwords match if user hasn't filled in // 'Confirm Password' yet. !confirmPassword || event.target.value === confirmPassword ? setConfirmPasswordError('') - : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); + : setConfirmPasswordError(Errors.PASSWORDS_DO_NOT_MATCH); setPassword(event.target.value); }; @@ -124,24 +117,24 @@ const SignUpCard: React.FC = () => { // If both passwords are empty we show PASSWORD_EMPTY. event.target.value === password ? setConfirmPasswordError('') - : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); + : setConfirmPasswordError(Errors.PASSWORDS_DO_NOT_MATCH); setConfirmPassword(event.target.value); }; const handleVpaChange = (event: React.ChangeEvent) => { - event.target.value ? setVpaError('') : setVpaError(VPA_EMPTY); + event.target.value ? setVpaError('') : setVpaError(Errors.VPA_EMPTY); setVpa(event.target.value); }; const handleSubmit = () => { // These checks are needed because empty error in the handleChange is shown // only if user already fills in the field and then deletes it. - if (!name) setNameError(NAME_EMPTY); - if (!email) setEmailError(EMAIL_EMPTY); - if (!password) setPasswordError(PASSWORD_EMPTY); + if (!name) setNameError(Errors.NAME_EMPTY); + if (!email) setEmailError(Errors.EMAIL_EMPTY); + if (!password) setPasswordError(Errors.PASSWORD_EMPTY); if (password !== confirmPassword) - setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); - if (!vpa) setVpaError(VPA_EMPTY); + setConfirmPasswordError(Errors.PASSWORDS_DO_NOT_MATCH); + if (!vpa) setVpaError(Errors.VPA_EMPTY); if (!name || !email || !password || password !== confirmPassword || !vpa) { return; @@ -151,15 +144,13 @@ const SignUpCard: React.FC = () => { .createUserWithEmailAndPassword(email, password) .catch(error => { if (error.code === 'auth/invalid-email') { - setErrorMessage('Please input a valid email address.'); + setErrorMessage(Errors.INVALID_EMAIL); } else if (error.code === 'auth/weak-password') { - setErrorMessage('Password should be at least 6 characters.'); + setErrorMessage(Errors.WEAK_PASSWORD); } else if (error.code === 'auth/email-already-in-use') { - setErrorMessage( - 'The email address is already in use by another account.' - ); + setErrorMessage(Errors.EMAIL_ALREADY_IN_USE); } else { - setErrorMessage('Oops, something is wrong. Please try again later!'); + setErrorMessage(Errors.SERVER_ERROR); } }); }; diff --git a/web/src/constants/sign-up-errors.ts b/web/src/constants/sign-up-errors.ts index 53092b41..ad475026 100644 --- a/web/src/constants/sign-up-errors.ts +++ b/web/src/constants/sign-up-errors.ts @@ -14,8 +14,27 @@ * limitations under the License. */ -export const NAME_EMPTY = 'Name cannot be empty.'; -export const EMAIL_EMPTY = 'Email cannot be empty.'; -export const PASSWORD_EMPTY = 'Password cannot be empty.'; -export const PASSWORDS_DO_NOT_MATCH = 'Passwords do no match.'; -export const VPA_EMPTY = 'VPA cannot be empty.'; +const NAME_EMPTY = 'Name cannot be empty.'; +const EMAIL_EMPTY = 'Email cannot be empty.'; +const PASSWORD_EMPTY = 'Password cannot be empty.'; +const VPA_EMPTY = 'VPA cannot be empty.'; + +const PASSWORDS_DO_NOT_MATCH = 'Passwords do no match.'; + +const INVALID_EMAIL = 'Please input a valid email address.'; +const WEAK_PASSWORD = 'Password should be at least 6 characters.'; +const EMAIL_ALREADY_IN_USE = 'The email address is already in use by another account.'; + +const SERVER_ERROR = 'Oops, something is wrong. Please try again later!'; + +export default { + NAME_EMPTY, + EMAIL_EMPTY, + PASSWORD_EMPTY, + VPA_EMPTY, + PASSWORDS_DO_NOT_MATCH, + INVALID_EMAIL, + WEAK_PASSWORD, + EMAIL_ALREADY_IN_USE, + SERVER_ERROR +}; From 8bf6aaad19caa1864b4f6128724ca4e79547036f Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 21:12:16 +0800 Subject: [PATCH 42/64] Fix lint errors --- web/src/components/merchant/sign-up/SignUpCard.tsx | 3 ++- web/src/constants/sign-up-errors.ts | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index fd9fa2c2..8372b1d9 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -14,11 +14,12 @@ * limitations under the License. */ +import Errors from 'constants/sign-up-errors'; + import React, {useState} from 'react'; import FormRow from 'components/common/FormRow'; import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; -import Errors from 'constants/sign-up-errors'; import firebaseAuth from 'firebase-auth'; import Button from 'muicss/lib/react/button'; import Form from 'muicss/lib/react/form'; diff --git a/web/src/constants/sign-up-errors.ts b/web/src/constants/sign-up-errors.ts index ad475026..538c1121 100644 --- a/web/src/constants/sign-up-errors.ts +++ b/web/src/constants/sign-up-errors.ts @@ -23,7 +23,8 @@ const PASSWORDS_DO_NOT_MATCH = 'Passwords do no match.'; const INVALID_EMAIL = 'Please input a valid email address.'; const WEAK_PASSWORD = 'Password should be at least 6 characters.'; -const EMAIL_ALREADY_IN_USE = 'The email address is already in use by another account.'; +const EMAIL_ALREADY_IN_USE = + 'The email address is already in use by another account.'; const SERVER_ERROR = 'Oops, something is wrong. Please try again later!'; @@ -36,5 +37,5 @@ export default { INVALID_EMAIL, WEAK_PASSWORD, EMAIL_ALREADY_IN_USE, - SERVER_ERROR + SERVER_ERROR, }; From d450e4b8654323e804a618189f50c50dc8859ef8 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 21:46:14 +0800 Subject: [PATCH 43/64] Add comment about Firebase auth --- web/src/components/merchant/sign-up/SignUpCard.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 8372b1d9..7b1937b1 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -141,6 +141,8 @@ const SignUpCard: React.FC = () => { return; } + // Add a new user account to Firebase so that user can be signed in with + // Firebase Authentication in the future. firebaseAuth .createUserWithEmailAndPassword(email, password) .catch(error => { From e1599a3e1c5ecca36eef636b6ff4935338a2f4b1 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 21:46:40 +0800 Subject: [PATCH 44/64] Refactor Firebase config JS object out --- web/src/firebase-auth.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/web/src/firebase-auth.ts b/web/src/firebase-auth.ts index 5b46424e..dd0b346a 100644 --- a/web/src/firebase-auth.ts +++ b/web/src/firebase-auth.ts @@ -16,12 +16,13 @@ import firebase from 'firebase'; -// Add a new user account to Firebase. +const config = { + apiKey: process.env.REACT_APP_API_KEY, + authDomain: process.env.REACT_APP_AUTH_DOMAIN, +}; + if (!firebase.apps.length) { - firebase.initializeApp({ - apiKey: process.env.REACT_APP_API_KEY, - authDomain: process.env.REACT_APP_AUTH_DOMAIN, - }); + firebase.initializeApp(config); } const firebaseAuth = firebase.auth(); From fd91670cd42d3f85befc4d68092e6d6cc1805a6b Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 22 Jun 2020 22:06:07 +0800 Subject: [PATCH 45/64] Show Firebase error below relevant field --- web/src/components/common/FormRow.tsx | 1 + web/src/components/merchant/sign-up/SignUpCard.tsx | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index e430bbca..b0c35875 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -50,6 +50,7 @@ const Label = styled.label` const Input = styled.input` height: 30px; + width: 350px; font-size: 14px; padding: 0 15px; diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 7b1937b1..bf85f886 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -147,11 +147,11 @@ const SignUpCard: React.FC = () => { .createUserWithEmailAndPassword(email, password) .catch(error => { if (error.code === 'auth/invalid-email') { - setErrorMessage(Errors.INVALID_EMAIL); + setEmailError(Errors.INVALID_EMAIL); } else if (error.code === 'auth/weak-password') { - setErrorMessage(Errors.WEAK_PASSWORD); + setPasswordError(Errors.WEAK_PASSWORD); } else if (error.code === 'auth/email-already-in-use') { - setErrorMessage(Errors.EMAIL_ALREADY_IN_USE); + setEmailError(Errors.EMAIL_ALREADY_IN_USE); } else { setErrorMessage(Errors.SERVER_ERROR); } From d1bc70f77a37146b8f0fe74c156d5740f1034c9e Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Tue, 23 Jun 2020 11:55:26 +0800 Subject: [PATCH 46/64] Add environment variables to web/app.yaml --- web/app.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/web/app.yaml b/web/app.yaml index e9082b4a..1bd10fff 100644 --- a/web/app.yaml +++ b/web/app.yaml @@ -11,4 +11,8 @@ handlers: - url: /.* static_files: build/index.html - upload: build/index.html + upload: build/index.html\ + +env_variables: + REACT_APP_API_KEY: '' + REACT_APP_AUTH_DOMAIN: '' From 5a151268136fa60ab42ac042886194221503d09d Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Tue, 23 Jun 2020 11:56:42 +0800 Subject: [PATCH 47/64] Add comment to web/app.yaml --- web/app.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/web/app.yaml b/web/app.yaml index 1bd10fff..2c7da43a 100644 --- a/web/app.yaml +++ b/web/app.yaml @@ -14,5 +14,6 @@ handlers: upload: build/index.html\ env_variables: + # Replace with API key and authentication domain before deployment REACT_APP_API_KEY: '' REACT_APP_AUTH_DOMAIN: '' From bbc572241e68f6d56a5cc5e26ef45913bb8b7a2c Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Tue, 23 Jun 2020 12:26:26 +0800 Subject: [PATCH 48/64] Refactor handleFirebaseSignUp into a separate function --- web/src/components/merchant/sign-up/SignUpCard.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index bf85f886..1c89ecd2 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -141,6 +141,10 @@ const SignUpCard: React.FC = () => { return; } + handleFirebaseSignUp(); + }; + + const handleFirebaseSignUp = () => { // Add a new user account to Firebase so that user can be signed in with // Firebase Authentication in the future. firebaseAuth From 5d2e85266afb2a8a2c90c4ffa33bc98002048506 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Tue, 23 Jun 2020 12:27:28 +0800 Subject: [PATCH 49/64] Use async/await instead of promises --- .../merchant/sign-up/SignUpCard.tsx | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 1c89ecd2..c5c8ab9f 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -144,22 +144,22 @@ const SignUpCard: React.FC = () => { handleFirebaseSignUp(); }; - const handleFirebaseSignUp = () => { + const handleFirebaseSignUp = async () => { // Add a new user account to Firebase so that user can be signed in with // Firebase Authentication in the future. - firebaseAuth - .createUserWithEmailAndPassword(email, password) - .catch(error => { - if (error.code === 'auth/invalid-email') { - setEmailError(Errors.INVALID_EMAIL); - } else if (error.code === 'auth/weak-password') { - setPasswordError(Errors.WEAK_PASSWORD); - } else if (error.code === 'auth/email-already-in-use') { - setEmailError(Errors.EMAIL_ALREADY_IN_USE); - } else { - setErrorMessage(Errors.SERVER_ERROR); - } - }); + try { + await firebaseAuth.createUserWithEmailAndPassword(email, password); + } catch (error) { + if (error.code === 'auth/invalid-email') { + setEmailError(Errors.INVALID_EMAIL); + } else if (error.code === 'auth/weak-password') { + setPasswordError(Errors.WEAK_PASSWORD); + } else if (error.code === 'auth/email-already-in-use') { + setEmailError(Errors.EMAIL_ALREADY_IN_USE); + } else { + setErrorMessage(Errors.SERVER_ERROR); + } + } }; return ( From 3cefe111cabf3087de465b7067556746106199d5 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Tue, 23 Jun 2020 12:55:29 +0800 Subject: [PATCH 50/64] Fix typos in constants/sign-up-errors.ts --- web/src/constants/sign-up-errors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/constants/sign-up-errors.ts b/web/src/constants/sign-up-errors.ts index 53092b41..8bf4354f 100644 --- a/web/src/constants/sign-up-errors.ts +++ b/web/src/constants/sign-up-errors.ts @@ -17,5 +17,5 @@ export const NAME_EMPTY = 'Name cannot be empty.'; export const EMAIL_EMPTY = 'Email cannot be empty.'; export const PASSWORD_EMPTY = 'Password cannot be empty.'; -export const PASSWORDS_DO_NOT_MATCH = 'Passwords do no match.'; +export const PASSWORDS_DO_NOT_MATCH = 'Passwords do not match.'; export const VPA_EMPTY = 'VPA cannot be empty.'; From 9bbe4130c2d64ce2df376cee21c0bd577dc9d40c Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Tue, 23 Jun 2020 13:05:05 +0800 Subject: [PATCH 51/64] Add comment to toCamelCase function --- web/src/components/common/FormRow.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index e430bbca..c595fd66 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -75,6 +75,10 @@ interface FormRowProps { error: string; } +/** + * This converts a space-separated string to camelCase e.g. 'Confirm Password' + * to 'confirmPassword' and 'VPA' to 'vpa'. + */ const toCamelCase = (phrase: string) => phrase .toLowerCase() From ce3106459fde40a4812ecf4c2df7aa6b68ad440d Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Tue, 23 Jun 2020 13:24:55 +0800 Subject: [PATCH 52/64] Move handleFirebaseSignUp comment to JSDoc comment --- web/src/components/merchant/sign-up/SignUpCard.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index c5c8ab9f..ecc42503 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -144,9 +144,11 @@ const SignUpCard: React.FC = () => { handleFirebaseSignUp(); }; + /** + * This adds a new user account to Firebase so that user can be signed in with + * Firebase Authentication in the future. + */ const handleFirebaseSignUp = async () => { - // Add a new user account to Firebase so that user can be signed in with - // Firebase Authentication in the future. try { await firebaseAuth.createUserWithEmailAndPassword(email, password); } catch (error) { From ef8de813752d5bcca8afe600b931736cff062d78 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Tue, 23 Jun 2020 14:01:36 +0800 Subject: [PATCH 53/64] Remove typo in web/app.yaml --- web/app.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app.yaml b/web/app.yaml index 2c7da43a..c684e8c6 100644 --- a/web/app.yaml +++ b/web/app.yaml @@ -11,7 +11,7 @@ handlers: - url: /.* static_files: build/index.html - upload: build/index.html\ + upload: build/index.html env_variables: # Replace with API key and authentication domain before deployment From b004e3ffd332b165563089f559d84cd6d938c1ca Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Thu, 25 Jun 2020 18:17:22 +0800 Subject: [PATCH 54/64] Use hook to separate logic from UI in SignUpCard --- .../merchant/sign-up/SignUpCard.tsx | 88 +++----------- web/src/hooks/merchant/sign-up.ts | 108 ++++++++++++++++++ 2 files changed, 123 insertions(+), 73 deletions(-) create mode 100644 web/src/hooks/merchant/sign-up.ts diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index dcfd0464..8a26f720 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -14,18 +14,11 @@ * limitations under the License. */ -import { - NAME_EMPTY, - EMAIL_EMPTY, - PASSWORD_EMPTY, - PASSWORDS_DO_NOT_MATCH, - VPA_EMPTY, -} from 'constants/sign-up-errors'; - -import React, {useState} from 'react'; +import React from 'react'; import FormRow from 'components/common/FormRow'; import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; +import useMerchantSignUpForm from 'hooks/merchant/sign-up'; import Button from 'muicss/lib/react/button'; import Form from 'muicss/lib/react/form'; import Row from 'muicss/lib/react/row'; @@ -73,70 +66,19 @@ const StyledButton = styled(Button)` * It is displayed in the Sign Up page. */ const SignUpCard: React.FC = () => { - const [name, setName] = useState(''); - const [nameError, setNameError] = useState(''); - - const [email, setEmail] = useState(''); - const [emailError, setEmailError] = useState(''); - - const [password, setPassword] = useState(''); - const [passwordError, setPasswordError] = useState(''); - - const [confirmPassword, setConfirmPassword] = useState(''); - const [confirmPasswordError, setConfirmPasswordError] = useState(''); - - const [vpa, setVpa] = useState(''); - const [vpaError, setVpaError] = useState(''); - - const handleNameChange = (event: React.ChangeEvent) => { - event.target.value ? setNameError('') : setNameError(NAME_EMPTY); - setName(event.target.value); - }; - - const handleEmailChange = (event: React.ChangeEvent) => { - event.target.value ? setEmailError('') : setEmailError(EMAIL_EMPTY); - setEmail(event.target.value); - }; - - const handlePasswordChange = (event: React.ChangeEvent) => { - event.target.value - ? setPasswordError('') - : setPasswordError(PASSWORD_EMPTY); - // We don't check that passwords match if user hasn't filled in - // 'Confirm Password' yet. - !confirmPassword || event.target.value === confirmPassword - ? setConfirmPasswordError('') - : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); - setPassword(event.target.value); - }; - - const handleConfirmPasswordChange = ( - event: React.ChangeEvent - ) => { - // We don't have to check if 'Confirm Password' is empty. If 'Password' is - // is not empty and 'Confirm Password' is empty, we show PASSWORDS_DO_NOT_MATCH. - // If both passwords are empty we show PASSWORD_EMPTY. - event.target.value === password - ? setConfirmPasswordError('') - : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); - setConfirmPassword(event.target.value); - }; - - const handleVpaChange = (event: React.ChangeEvent) => { - event.target.value ? setVpaError('') : setVpaError(VPA_EMPTY); - setVpa(event.target.value); - }; - - const handleSubmit = () => { - // These checks are needed because empty error in the handleChange is shown - // only if user already fills in the field and then deletes it. - if (!name) setNameError(NAME_EMPTY); - if (!email) setEmailError(EMAIL_EMPTY); - if (!password) setPasswordError(PASSWORD_EMPTY); - if (password !== confirmPassword) - setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); - if (!vpa) setVpaError(VPA_EMPTY); - }; + const { + handleNameChange, + nameError, + handleEmailChange, + emailError, + handlePasswordChange, + passwordError, + handleConfirmPasswordChange, + confirmPasswordError, + handleVpaChange, + vpaError, + handleSubmit, + } = useMerchantSignUpForm(); return ( diff --git a/web/src/hooks/merchant/sign-up.ts b/web/src/hooks/merchant/sign-up.ts new file mode 100644 index 00000000..695874a0 --- /dev/null +++ b/web/src/hooks/merchant/sign-up.ts @@ -0,0 +1,108 @@ +/** + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + NAME_EMPTY, + EMAIL_EMPTY, + PASSWORD_EMPTY, + PASSWORDS_DO_NOT_MATCH, + VPA_EMPTY, +} from 'constants/sign-up-errors'; + +import React, {useState} from 'react'; + +const useMerchantSignUpForm = () => { + const [name, setName] = useState(''); + const [nameError, setNameError] = useState(''); + + const [email, setEmail] = useState(''); + const [emailError, setEmailError] = useState(''); + + const [password, setPassword] = useState(''); + const [passwordError, setPasswordError] = useState(''); + + const [confirmPassword, setConfirmPassword] = useState(''); + const [confirmPasswordError, setConfirmPasswordError] = useState(''); + + const [vpa, setVpa] = useState(''); + const [vpaError, setVpaError] = useState(''); + + const handleNameChange = (event: React.ChangeEvent) => { + event.target.value ? setNameError('') : setNameError(NAME_EMPTY); + setName(event.target.value); + }; + + const handleEmailChange = (event: React.ChangeEvent) => { + event.target.value ? setEmailError('') : setEmailError(EMAIL_EMPTY); + setEmail(event.target.value); + }; + + const handlePasswordChange = (event: React.ChangeEvent) => { + event.target.value + ? setPasswordError('') + : setPasswordError(PASSWORD_EMPTY); + // We don't check that passwords match if user hasn't filled in + // 'Confirm Password' yet. + !confirmPassword || event.target.value === confirmPassword + ? setConfirmPasswordError('') + : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); + setPassword(event.target.value); + }; + + const handleConfirmPasswordChange = ( + event: React.ChangeEvent + ) => { + // We don't have to check if 'Confirm Password' is empty. If 'Password' is + // is not empty and 'Confirm Password' is empty, we show PASSWORDS_DO_NOT_MATCH. + // If both passwords are empty we show PASSWORD_EMPTY. + event.target.value === password + ? setConfirmPasswordError('') + : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); + setConfirmPassword(event.target.value); + }; + + const handleVpaChange = (event: React.ChangeEvent) => { + event.target.value ? setVpaError('') : setVpaError(VPA_EMPTY); + setVpa(event.target.value); + }; + + const handleSubmit = () => { + // These checks are needed because empty error in the handleChange is shown + // only if user already fills in the field and then deletes it. + if (!name) setNameError(NAME_EMPTY); + if (!email) setEmailError(EMAIL_EMPTY); + if (!password) setPasswordError(PASSWORD_EMPTY); + if (password !== confirmPassword) + setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); + if (!vpa) setVpaError(VPA_EMPTY); + }; + + return { + handleNameChange, + nameError, + handleEmailChange, + emailError, + handlePasswordChange, + passwordError, + handleConfirmPasswordChange, + confirmPasswordError, + handleVpaChange, + vpaError, + handleSubmit, + }; +}; + +export default useMerchantSignUpForm; From 2a6b7bac2f667673364a9a94bc4fb4c6a796c7b8 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 26 Jun 2020 03:07:33 +0800 Subject: [PATCH 55/64] Use react-hook-form library for Merchant SignUpForm --- web/package.json | 1 + web/src/components/common/FormRow.tsx | 26 +++- .../merchant/sign-up/SignUpCard.tsx | 73 +--------- .../merchant/sign-up/SignUpForm.tsx | 130 ++++++++++++++++++ web/src/constants/sign-up-errors.ts | 3 + web/src/hooks/merchant/sign-up.ts | 108 --------------- web/yarn.lock | 5 + 7 files changed, 162 insertions(+), 184 deletions(-) create mode 100644 web/src/components/merchant/sign-up/SignUpForm.tsx delete mode 100644 web/src/hooks/merchant/sign-up.ts diff --git a/web/package.json b/web/package.json index d02f4783..ade6fd40 100644 --- a/web/package.json +++ b/web/package.json @@ -21,6 +21,7 @@ "react": "^16.13.1", "react-dom": "^16.13.1", "react-feather": "^2.0.8", + "react-hook-form": "^5.7.2", "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", "styled-components": "^5.1.1", diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index c595fd66..03406a81 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -14,6 +14,7 @@ * limitations under the License. */ +import {Component, ReactElement} from 'react'; import React from 'react'; import Col from 'muicss/lib/react/col'; @@ -26,7 +27,7 @@ const StyledRow = styled(Row)` align-items: top; justify-content: center; - margin: 10px 0; + margin: 5px 0; `; const StyledCol = styled(Col)` @@ -68,11 +69,26 @@ const ErrorContainer = styled.div` color: var(--bright-red); `; +type ReactHookFormErrorMessage = + | string + | React.ReactElement< + any, + | string + | (( + props: any + ) => React.ReactElement< + any, + string | any | (new (props: any) => React.Component) + > | null) + | (new (props: any) => React.Component) + > + | undefined; + interface FormRowProps { label: string; inputType: string; - onChange: React.EventHandler>; - error: string; + forwardedRef: (ref: HTMLInputElement) => void; + error: ReactHookFormErrorMessage; } /** @@ -94,7 +110,7 @@ const toCamelCase = (phrase: string) => const FormRow: React.FC = ({ label, inputType, - onChange, + forwardedRef, error, }) => ( @@ -102,7 +118,7 @@ const FormRow: React.FC = ({ - + {error} diff --git a/web/src/components/merchant/sign-up/SignUpCard.tsx b/web/src/components/merchant/sign-up/SignUpCard.tsx index 8a26f720..187353e7 100644 --- a/web/src/components/merchant/sign-up/SignUpCard.tsx +++ b/web/src/components/merchant/sign-up/SignUpCard.tsx @@ -16,11 +16,8 @@ import React from 'react'; -import FormRow from 'components/common/FormRow'; import GroupBuyMerchantHeader from 'components/common/GroupBuyMerchantHeader'; -import useMerchantSignUpForm from 'hooks/merchant/sign-up'; -import Button from 'muicss/lib/react/button'; -import Form from 'muicss/lib/react/form'; +import SignUpForm from 'components/merchant/sign-up/SignUpForm'; import Row from 'muicss/lib/react/row'; import {Link} from 'react-router-dom'; import styled from 'styled-components'; @@ -37,87 +34,21 @@ const CardContainer: React.FC = styled.div` box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.25); `; -const StyledForm = styled(Form)` - margin: 15px 0; -`; - const StyledRow = styled(Row)` height: 40px; display: block; line-height: 40px; `; -const StyledButton = styled(Button)` - height: 40px; - width: 200px; - border-radius: 20px; - border: none; - - background: var(--dark-gray); - color: white; - font-size: 18px; - font-weight: bolder; - text-transform: uppercase; - margin: 0; -`; - /** * This is the card containing the sign up form for the Merchant app. * It is displayed in the Sign Up page. */ const SignUpCard: React.FC = () => { - const { - handleNameChange, - nameError, - handleEmailChange, - emailError, - handlePasswordChange, - passwordError, - handleConfirmPasswordChange, - confirmPasswordError, - handleVpaChange, - vpaError, - handleSubmit, - } = useMerchantSignUpForm(); - return ( - - - - - - - - - Sign Up - + Already have an account? Sign in{' '} now! diff --git a/web/src/components/merchant/sign-up/SignUpForm.tsx b/web/src/components/merchant/sign-up/SignUpForm.tsx new file mode 100644 index 00000000..740b3a36 --- /dev/null +++ b/web/src/components/merchant/sign-up/SignUpForm.tsx @@ -0,0 +1,130 @@ +/** + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + NAME_EMPTY, + EMAIL_EMPTY, + EMAIL_INVALID, + PASSWORD_EMPTY, + PASSWORD_WEAK, + PASSWORDS_DO_NOT_MATCH, + VPA_EMPTY, + VPA_INVALID, +} from 'constants/sign-up-errors'; + +import React from 'react'; + +import FormRow from 'components/common/FormRow'; +import Button from 'muicss/lib/react/button'; +import Form from 'muicss/lib/react/form'; +import {useForm} from 'react-hook-form'; +import styled from 'styled-components'; + +const StyledForm = styled(Form)` + display: flex; + flex-direction: column; + align-items: center; +`; + +const StyledButton = styled(Button)` + height: 40px; + width: 200px; + border-radius: 20px; + border: none; + + background: var(--dark-gray); + color: white; + font-size: 18px; + font-weight: bolder; + text-transform: uppercase; + margin-top: 20px; +`; + +type SignUpData = { + name: string; + email: string; + password: string; + confirmPassword: string; + vpa: string; +}; + +const SignUpForm = () => { + const {handleSubmit, register, watch, errors} = useForm({ + mode: 'onChange', + }); + const onSubmit = (values: SignUpData) => console.log(values); + + return ( + + + + + + value === watch('password') || PASSWORDS_DO_NOT_MATCH, + })} + error={errors?.confirmPassword?.message} + /> + + Sign Up + + ); +}; + +export default SignUpForm; diff --git a/web/src/constants/sign-up-errors.ts b/web/src/constants/sign-up-errors.ts index 8bf4354f..1d5f9a4d 100644 --- a/web/src/constants/sign-up-errors.ts +++ b/web/src/constants/sign-up-errors.ts @@ -16,6 +16,9 @@ export const NAME_EMPTY = 'Name cannot be empty.'; export const EMAIL_EMPTY = 'Email cannot be empty.'; +export const EMAIL_INVALID = 'Please input a valid email address.'; export const PASSWORD_EMPTY = 'Password cannot be empty.'; +export const PASSWORD_WEAK = 'Password must have at least 8 characters.'; export const PASSWORDS_DO_NOT_MATCH = 'Passwords do not match.'; export const VPA_EMPTY = 'VPA cannot be empty.'; +export const VPA_INVALID = 'Please input a valid VPA.'; diff --git a/web/src/hooks/merchant/sign-up.ts b/web/src/hooks/merchant/sign-up.ts deleted file mode 100644 index 695874a0..00000000 --- a/web/src/hooks/merchant/sign-up.ts +++ /dev/null @@ -1,108 +0,0 @@ -/** - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - NAME_EMPTY, - EMAIL_EMPTY, - PASSWORD_EMPTY, - PASSWORDS_DO_NOT_MATCH, - VPA_EMPTY, -} from 'constants/sign-up-errors'; - -import React, {useState} from 'react'; - -const useMerchantSignUpForm = () => { - const [name, setName] = useState(''); - const [nameError, setNameError] = useState(''); - - const [email, setEmail] = useState(''); - const [emailError, setEmailError] = useState(''); - - const [password, setPassword] = useState(''); - const [passwordError, setPasswordError] = useState(''); - - const [confirmPassword, setConfirmPassword] = useState(''); - const [confirmPasswordError, setConfirmPasswordError] = useState(''); - - const [vpa, setVpa] = useState(''); - const [vpaError, setVpaError] = useState(''); - - const handleNameChange = (event: React.ChangeEvent) => { - event.target.value ? setNameError('') : setNameError(NAME_EMPTY); - setName(event.target.value); - }; - - const handleEmailChange = (event: React.ChangeEvent) => { - event.target.value ? setEmailError('') : setEmailError(EMAIL_EMPTY); - setEmail(event.target.value); - }; - - const handlePasswordChange = (event: React.ChangeEvent) => { - event.target.value - ? setPasswordError('') - : setPasswordError(PASSWORD_EMPTY); - // We don't check that passwords match if user hasn't filled in - // 'Confirm Password' yet. - !confirmPassword || event.target.value === confirmPassword - ? setConfirmPasswordError('') - : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); - setPassword(event.target.value); - }; - - const handleConfirmPasswordChange = ( - event: React.ChangeEvent - ) => { - // We don't have to check if 'Confirm Password' is empty. If 'Password' is - // is not empty and 'Confirm Password' is empty, we show PASSWORDS_DO_NOT_MATCH. - // If both passwords are empty we show PASSWORD_EMPTY. - event.target.value === password - ? setConfirmPasswordError('') - : setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); - setConfirmPassword(event.target.value); - }; - - const handleVpaChange = (event: React.ChangeEvent) => { - event.target.value ? setVpaError('') : setVpaError(VPA_EMPTY); - setVpa(event.target.value); - }; - - const handleSubmit = () => { - // These checks are needed because empty error in the handleChange is shown - // only if user already fills in the field and then deletes it. - if (!name) setNameError(NAME_EMPTY); - if (!email) setEmailError(EMAIL_EMPTY); - if (!password) setPasswordError(PASSWORD_EMPTY); - if (password !== confirmPassword) - setConfirmPasswordError(PASSWORDS_DO_NOT_MATCH); - if (!vpa) setVpaError(VPA_EMPTY); - }; - - return { - handleNameChange, - nameError, - handleEmailChange, - emailError, - handlePasswordChange, - passwordError, - handleConfirmPasswordChange, - confirmPasswordError, - handleVpaChange, - vpaError, - handleSubmit, - }; -}; - -export default useMerchantSignUpForm; diff --git a/web/yarn.lock b/web/yarn.lock index a701a0cf..5d32c4f6 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -9906,6 +9906,11 @@ react-feather@^2.0.8: dependencies: prop-types "^15.7.2" +react-hook-form@^5.7.2: + version "5.7.2" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-5.7.2.tgz#a84e259e5d37dd30949af4f79c4dac31101b79ac" + integrity sha512-bJvY348vayIvEUmSK7Fvea/NgqbT2racA2IbnJz/aPlQ3GBtaTeDITH6rtCa6y++obZzG6E3Q8VuoXPir7QYUg== + react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" From aaee3778f693db732a5f4291e86ca9e1fb9c0512 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 26 Jun 2020 03:14:16 +0800 Subject: [PATCH 56/64] Use to-camel-case library instead of custom function --- web/package.json | 2 ++ web/src/components/common/FormRow.tsx | 12 +----------- web/yarn.lock | 24 ++++++++++++++++++++++++ 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/web/package.json b/web/package.json index ade6fd40..d744b83b 100644 --- a/web/package.json +++ b/web/package.json @@ -16,6 +16,7 @@ "@types/react-dom": "^16.9.0", "@types/react-router-dom": "^5.1.5", "@types/styled-components": "^5.1.0", + "@types/to-camel-case": "^1.0.0", "muicss": "^0.10.2", "rc-progress": "^3.0.0", "react": "^16.13.1", @@ -25,6 +26,7 @@ "react-router-dom": "^5.2.0", "react-scripts": "3.4.1", "styled-components": "^5.1.1", + "to-camel-case": "^1.0.0", "typescript": "~3.7.2" }, "scripts": { diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index 03406a81..e9ee580e 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -20,6 +20,7 @@ import React from 'react'; import Col from 'muicss/lib/react/col'; import Row from 'muicss/lib/react/row'; import styled from 'styled-components'; +import toCamelCase from 'to-camel-case'; const StyledRow = styled(Row)` display: flex; @@ -91,17 +92,6 @@ interface FormRowProps { error: ReactHookFormErrorMessage; } -/** - * This converts a space-separated string to camelCase e.g. 'Confirm Password' - * to 'confirmPassword' and 'VPA' to 'vpa'. - */ -const toCamelCase = (phrase: string) => - phrase - .toLowerCase() - .replace(/\s(.)/g, a => a.toUpperCase()) - .replace(/\s/g, '') - .replace(/^(.)/, a => a.toLowerCase()); - /** * This is a row in a form, consisting of a label and an input field shown * side by side. This also contains a container for error message which is diff --git a/web/yarn.lock b/web/yarn.lock index 5d32c4f6..50dc09e0 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -1819,6 +1819,11 @@ "@types/testing-library__dom" "*" pretty-format "^25.1.0" +"@types/to-camel-case@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/to-camel-case/-/to-camel-case-1.0.0.tgz#927ef0a7294d90b1835466c29b64b8ad2a32d8b5" + integrity sha512-LXJOP0xvOUB4dKu+t7EVhSsM2NauLSZSOGkBS7Wqz3lWHIseCJnMDG+HrZHLFZQ39Fq3jr4RErJyQzfsoOlXSA== + "@types/unist@^2.0.0", "@types/unist@^2.0.2": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" @@ -11651,11 +11656,23 @@ to-arraybuffer@^1.0.0: resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= +to-camel-case@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-camel-case/-/to-camel-case-1.0.0.tgz#1a56054b2f9d696298ce66a60897322b6f423e46" + integrity sha1-GlYFSy+daWKYzmamCJcyK29CPkY= + dependencies: + to-space-case "^1.0.0" + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= +to-no-case@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a" + integrity sha1-xyKQcWTvaxeBMsjmmTAhLRtKoWo= + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -11693,6 +11710,13 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +to-space-case@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17" + integrity sha1-sFLar7Gysp3HcM6gFj5ewOvJ/Bc= + dependencies: + to-no-case "^1.0.0" + toidentifier@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" From 147d81de16391fb55a945b65cb813f64fd81b1c8 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 26 Jun 2020 03:25:25 +0800 Subject: [PATCH 57/64] Disable Sign Up button until form is valid --- web/src/components/merchant/sign-up/SignUpForm.tsx | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/web/src/components/merchant/sign-up/SignUpForm.tsx b/web/src/components/merchant/sign-up/SignUpForm.tsx index 740b3a36..0e3d90b2 100644 --- a/web/src/components/merchant/sign-up/SignUpForm.tsx +++ b/web/src/components/merchant/sign-up/SignUpForm.tsx @@ -62,7 +62,9 @@ type SignUpData = { }; const SignUpForm = () => { - const {handleSubmit, register, watch, errors} = useForm({ + const {handleSubmit, register, watch, errors, formState} = useForm< + SignUpData + >({ mode: 'onChange', }); const onSubmit = (values: SignUpData) => console.log(values); @@ -122,7 +124,12 @@ const SignUpForm = () => { })} error={errors?.vpa?.message} /> - Sign Up + + Sign Up + ); }; From 28c137a322fa03d2b9c0073c62b6a07f0a7c42ec Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 26 Jun 2020 12:58:33 +0800 Subject: [PATCH 58/64] Create useSignUpForm hook to separate logic from UI --- .../merchant/sign-up/SignUpForm.tsx | 67 ++------------- .../merchant/sign-up/hooks/useSignUpForm.tsx | 85 +++++++++++++++++++ 2 files changed, 93 insertions(+), 59 deletions(-) create mode 100644 web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx diff --git a/web/src/components/merchant/sign-up/SignUpForm.tsx b/web/src/components/merchant/sign-up/SignUpForm.tsx index 0e3d90b2..f066265e 100644 --- a/web/src/components/merchant/sign-up/SignUpForm.tsx +++ b/web/src/components/merchant/sign-up/SignUpForm.tsx @@ -14,23 +14,12 @@ * limitations under the License. */ -import { - NAME_EMPTY, - EMAIL_EMPTY, - EMAIL_INVALID, - PASSWORD_EMPTY, - PASSWORD_WEAK, - PASSWORDS_DO_NOT_MATCH, - VPA_EMPTY, - VPA_INVALID, -} from 'constants/sign-up-errors'; - import React from 'react'; import FormRow from 'components/common/FormRow'; +import useSignUpForm from 'components/merchant/sign-up/hooks/useSignUpForm'; import Button from 'muicss/lib/react/button'; import Form from 'muicss/lib/react/form'; -import {useForm} from 'react-hook-form'; import styled from 'styled-components'; const StyledForm = styled(Form)` @@ -53,81 +42,41 @@ const StyledButton = styled(Button)` margin-top: 20px; `; -type SignUpData = { - name: string; - email: string; - password: string; - confirmPassword: string; - vpa: string; -}; - const SignUpForm = () => { - const {handleSubmit, register, watch, errors, formState} = useForm< - SignUpData - >({ - mode: 'onChange', - }); - const onSubmit = (values: SignUpData) => console.log(values); - + const {disabled, errors, onSubmit, validations} = useSignUpForm(); return ( - value === watch('password') || PASSWORDS_DO_NOT_MATCH, - })} + forwardedRef={validations.confirmPassword} error={errors?.confirmPassword?.message} /> - + Sign Up diff --git a/web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx b/web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx new file mode 100644 index 00000000..d19d63ce --- /dev/null +++ b/web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx @@ -0,0 +1,85 @@ +/** + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + NAME_EMPTY, + EMAIL_EMPTY, + EMAIL_INVALID, + PASSWORD_EMPTY, + PASSWORD_WEAK, + PASSWORDS_DO_NOT_MATCH, + VPA_EMPTY, + VPA_INVALID, +} from 'constants/sign-up-errors'; + +import {useForm} from 'react-hook-form'; + +type SignUpData = { + name: string; + email: string; + password: string; + confirmPassword: string; + vpa: string; +}; + +const useSignUpForm = () => { + const {errors, formState, handleSubmit, register, watch} = useForm< + SignUpData + >({ + mode: 'onChange', + }); + + const validations = { + name: register({ + required: NAME_EMPTY, + }), + email: register({ + required: EMAIL_EMPTY, + pattern: { + value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i, + message: EMAIL_INVALID, + }, + }), + password: register({ + required: PASSWORD_EMPTY, + minLength: { + value: 8, + message: PASSWORD_WEAK, + }, + }), + confirmPassword: register({ + validate: value => value === watch('password') || PASSWORDS_DO_NOT_MATCH, + }), + vpa: register({ + required: VPA_EMPTY, + pattern: { + value: /^[A-Z0-9]+@[A-Z0-9]+/i, + message: VPA_INVALID, + }, + }), + }; + const disabled = !formState.isValid; + const onSubmit = handleSubmit((values: SignUpData) => console.log(values)); + + return { + disabled, + errors, + onSubmit, + validations, + }; +}; + +export default useSignUpForm; From 7e402daaf3b8c4ab7d77917863ee0f086e7dddc7 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 26 Jun 2020 15:16:56 +0800 Subject: [PATCH 59/64] Update web/src/firebase-auth.ts --- web/src/firebase-auth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/firebase-auth.ts b/web/src/firebase-auth.ts index dd0b346a..d4480330 100644 --- a/web/src/firebase-auth.ts +++ b/web/src/firebase-auth.ts @@ -21,7 +21,7 @@ const config = { authDomain: process.env.REACT_APP_AUTH_DOMAIN, }; -if (!firebase.apps.length) { +if (firebase.apps.length > 0) { firebase.initializeApp(config); } From ec694181ec5c3ce428b5cd2941b5af2f25c7b0e9 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 26 Jun 2020 15:22:27 +0800 Subject: [PATCH 60/64] Use switch-case instead of if-else when handling firebase error --- .../merchant/sign-up/hooks/useSignUpForm.tsx | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx b/web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx index 51c878e4..3e3cab6d 100644 --- a/web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx +++ b/web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx @@ -37,14 +37,18 @@ const handleFirebaseSignUp = async (email: string, password: string, setError: ( try { await firebaseAuth.createUserWithEmailAndPassword(email, password); } catch (error) { - if (error.code === 'auth/invalid-email') { - setError("email", "pattern", Errors.EMAIL_INVALID); - } else if (error.code === 'auth/weak-password') { - setError("password", "minLength", Errors.PASSWORD_WEAK); - } else if (error.code === 'auth/email-already-in-use') { - setError("email", "unique", Errors.EMAIL_ALREADY_IN_USE); - } else { - throw error; + switch (error.code) { + case 'auth/invalid-email': + setError("email", "pattern", Errors.EMAIL_INVALID); + break; + case 'auth/weak-password': + setError("password", "minLength", Errors.PASSWORD_WEAK); + break; + case 'auth/email-already-in-use': + setError("email", "unique", Errors.EMAIL_ALREADY_IN_USE); + break; + default: + throw error; } } }; From 4ddd8684e3a07e60ce3d0270675c8806e029c801 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 26 Jun 2020 15:24:49 +0800 Subject: [PATCH 61/64] Fix lint errors --- .../merchant/sign-up/hooks/useSignUpForm.tsx | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx b/web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx index 3e3cab6d..3aa222f4 100644 --- a/web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx +++ b/web/src/components/merchant/sign-up/hooks/useSignUpForm.tsx @@ -33,19 +33,29 @@ type FormValues = FieldValues; * This adds a new user account to Firebase so that user can be signed in with * Firebase Authentication in the future. */ -const handleFirebaseSignUp = async (email: string, password: string, setError: (name: IsFlatObject extends true ? Extract : "email" | "password" | "name" | "confirmPassword" | "vpa", type: string, message?: Message) => void ): Promise => { +const handleFirebaseSignUp = async ( + email: string, + password: string, + setError: ( + name: IsFlatObject extends true + ? Extract + : 'email' | 'password' | 'name' | 'confirmPassword' | 'vpa', + type: string, + message?: Message + ) => void +): Promise => { try { await firebaseAuth.createUserWithEmailAndPassword(email, password); } catch (error) { - switch (error.code) { + switch (error.code) { case 'auth/invalid-email': - setError("email", "pattern", Errors.EMAIL_INVALID); + setError('email', 'pattern', Errors.EMAIL_INVALID); break; case 'auth/weak-password': - setError("password", "minLength", Errors.PASSWORD_WEAK); + setError('password', 'minLength', Errors.PASSWORD_WEAK); break; case 'auth/email-already-in-use': - setError("email", "unique", Errors.EMAIL_ALREADY_IN_USE); + setError('email', 'unique', Errors.EMAIL_ALREADY_IN_USE); break; default: throw error; @@ -79,7 +89,8 @@ const useSignUpForm = () => { }, }), confirmPassword: register({ - validate: value => value === watch('password') || Errors.PASSWORDS_DO_NOT_MATCH, + validate: value => + value === watch('password') || Errors.PASSWORDS_DO_NOT_MATCH, }), vpa: register({ required: Errors.VPA_EMPTY, @@ -92,7 +103,7 @@ const useSignUpForm = () => { const disabled = !formState.isValid; const onSubmit = handleSubmit((values: SignUpData) => { const {email, password} = values; - handleFirebaseSignUp(email, password, setError) + handleFirebaseSignUp(email, password, setError); }); return { From 2e9f2c02008a66729d24b1ede90e51c991a1a9ab Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Fri, 26 Jun 2020 16:02:28 +0800 Subject: [PATCH 62/64] Fix bug in firebase-auth --- web/src/firebase-auth.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/firebase-auth.ts b/web/src/firebase-auth.ts index d4480330..f0d21822 100644 --- a/web/src/firebase-auth.ts +++ b/web/src/firebase-auth.ts @@ -21,7 +21,7 @@ const config = { authDomain: process.env.REACT_APP_AUTH_DOMAIN, }; -if (firebase.apps.length > 0) { +if (firebase.apps.length === 0) { firebase.initializeApp(config); } From 893bde078e73dd6f54f98e18ac7cbeb91271a32b Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 29 Jun 2020 12:08:30 +0800 Subject: [PATCH 63/64] Remove unused import not removed during merge --- web/src/components/common/FormRow.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/web/src/components/common/FormRow.tsx b/web/src/components/common/FormRow.tsx index d242c746..be89c031 100644 --- a/web/src/components/common/FormRow.tsx +++ b/web/src/components/common/FormRow.tsx @@ -14,7 +14,6 @@ * limitations under the License. */ -import {Component, ReactElement} from 'react'; import React from 'react'; import Col from 'muicss/lib/react/col'; From 0f98cfa02e4def1efbb5a1d2143459e8b7431887 Mon Sep 17 00:00:00 2001 From: Karen Frilya Celine Date: Mon, 29 Jun 2020 12:08:57 +0800 Subject: [PATCH 64/64] Rephrase sign up error message --- web/src/constants/sign-up-errors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/constants/sign-up-errors.ts b/web/src/constants/sign-up-errors.ts index aac71cb3..5f79c5c1 100644 --- a/web/src/constants/sign-up-errors.ts +++ b/web/src/constants/sign-up-errors.ts @@ -17,7 +17,7 @@ export const NAME_EMPTY = 'Name cannot be empty.'; export const EMAIL_ALREADY_IN_USE = - 'The email address is already in use by another account.'; + 'This email address is already in use by another account.'; export const EMAIL_EMPTY = 'Email cannot be empty.'; export const EMAIL_INVALID = 'Please input a valid email address.';