-
Notifications
You must be signed in to change notification settings - Fork 3
status icons for mailing list form including loading icon #125
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,15 @@ | ||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | ||
import React, { useState } from "react"; | ||
import styled from "styled-components"; | ||
import { StaticP } from "utility/ContentStyles.js"; | ||
|
||
const EmailForm = styled.form` | ||
text-align: center; | ||
margin: auto; | ||
padding-bottom: 24px; | ||
display: flex; | ||
align-items: flex-start; | ||
justify-content: center; | ||
`; | ||
|
||
const EmailInputBox = styled.input` | ||
min-width: 250px; | ||
border: 2px solid #555; | ||
|
@@ -16,7 +19,8 @@ const EmailInputBox = styled.input` | |
border-bottom-left-radius: 10px; | ||
padding: 0 16px; | ||
`; | ||
const EmailSubmitButton = styled.input` | ||
|
||
const EmailSubmitButton = styled.button` | ||
color: white; | ||
border: 2px solid #555; | ||
border-left: 0; | ||
|
@@ -30,51 +34,106 @@ const EmailSubmitButton = styled.input` | |
border-top-right-radius: 10px; | ||
border-bottom-right-radius: 10px; | ||
&:hover { | ||
background: rgb(222, 103, 63); | ||
background: rgb(222, 103, 63); | ||
} | ||
&:disabled { | ||
background: #aaa; | ||
} | ||
&:disabled:hover { | ||
cursor: not-allowed; | ||
} | ||
`; | ||
|
||
export default function MailingList() { | ||
const [address, setAddress] = useState(""); | ||
const [result, setResult] = useState(null); | ||
const LoadingAnimation = styled.span` | ||
${(props) => (props.active ? "animation: spin 2s linear infinite;" : "")} | ||
@keyframes spin { | ||
0% { | ||
transform: rotate(0deg); | ||
} | ||
100% { | ||
transform: rotate(360deg); | ||
} | ||
} | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
`; | ||
|
||
async function addEmailToList(e) { | ||
e.preventDefault(); | ||
setResult(null); | ||
const READY_STATUS = "ready"; | ||
const LOADING_STATUS = "loading"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's more idiomatic to use an object mapping to strings for enums. const Status = {
READY: "READY"
...
} |
||
const SUCCESS_STATUS = "success"; | ||
const FAILURE_STATUS = "failure"; | ||
|
||
// make email post request | ||
const response = await fetch('https://api.michhackers.com/email/add', { | ||
method: 'POST', | ||
headers: { | ||
"Content-Type": "application/json" | ||
}, | ||
body: JSON.stringify({ | ||
email: address | ||
}) | ||
}); | ||
const statusToTitle = {}; | ||
statusToTitle[READY_STATUS] = "Send"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this part would be better if it was an object like {title: "Send", icon: "paper-plane"} to avoid that nasty nested ternary. Alternatively, move the setting of the icon to a variable and use |
||
statusToTitle[LOADING_STATUS] = "Sending..."; | ||
statusToTitle[SUCCESS_STATUS] = "Sent!"; | ||
statusToTitle[FAILURE_STATUS] = "Failed to send"; | ||
|
||
// handle error | ||
if (response.status !== 200) { | ||
setResult(`An error occured: ${response.status} ${response.statusText}`); | ||
return; | ||
} | ||
export default function MailingList() { | ||
const [address, setAddress] = useState(""); | ||
const [status, setStatus] = useState(READY_STATUS); | ||
const [disabled, setDisabled] = useState(false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Disabled state is redundant since it's only ever There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can just be like |
||
|
||
// handle successful response | ||
setAddress(""); | ||
setResult("Successfully added!"); | ||
} | ||
async function addEmailToList(e) { | ||
e.preventDefault(); | ||
setStatus(LOADING_STATUS); | ||
setDisabled(true); | ||
//make email post request | ||
const response = await fetch("https://api.michhackers.com/email/add", { | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json" | ||
}, | ||
body: JSON.stringify({ | ||
email: address, | ||
}), | ||
}); | ||
|
||
// handle error | ||
if (response.status !== 200) { | ||
setStatus(FAILURE_STATUS); | ||
setDisabled(false); | ||
console.error( | ||
`An error occured: ${response.status} ${response.statusText}` | ||
); | ||
return; | ||
} | ||
setStatus(SUCCESS_STATUS); | ||
setAddress(""); | ||
setDisabled(false); | ||
} | ||
|
||
return ( | ||
<EmailForm onSubmit={addEmailToList}> | ||
{result && <StaticP>{result}</StaticP>} | ||
<EmailInputBox | ||
type="email" | ||
value={address} | ||
onChange={e => setAddress(e.target.value)} | ||
placeholder="[email protected]" | ||
required | ||
/> | ||
<EmailSubmitButton type="submit" value="Join" /> | ||
</EmailForm> | ||
); | ||
return ( | ||
<EmailForm onSubmit={addEmailToList}> | ||
<EmailInputBox | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It could use a Toast message to indicate completeness or to spit out the error message from the server. |
||
type="email" | ||
value={address} | ||
onChange={(e) => { | ||
setAddress(e.target.value); | ||
setStatus(READY_STATUS); | ||
setDisabled(false); | ||
}} | ||
placeholder="[email protected]" | ||
required | ||
/> | ||
<EmailSubmitButton | ||
type="submit" | ||
disabled={disabled} | ||
title={statusToTitle[status]} | ||
> | ||
<LoadingAnimation active={status === LOADING_STATUS}> | ||
{status === LOADING_STATUS ? ( | ||
<FontAwesomeIcon icon={["fas", "spinner"]} /> | ||
) : status === READY_STATUS ? ( | ||
<FontAwesomeIcon icon={["fas", "paper-plane"]} /> | ||
) : status === SUCCESS_STATUS ? ( | ||
<FontAwesomeIcon icon={["fas", "check"]} /> | ||
) : ( | ||
<FontAwesomeIcon icon={["fas", "times"]} /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think a restart icon would be more effective in telling the user to try resubmitting. |
||
)} | ||
</LoadingAnimation> | ||
</EmailSubmitButton> | ||
</EmailForm> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Linter says semicolon is missing here. Can't see the github thing for suggesting a specific change.