-
Notifications
You must be signed in to change notification settings - Fork 10
challenge attempts #1
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: master
Are you sure you want to change the base?
Changes from all commits
f7b58ff
4af35fe
2969765
aaf54da
8aa6334
1e84703
a885794
aeedbf7
3042d72
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,10 +1,22 @@ | ||
| .cards { | ||
| width: 600px; | ||
| margin: 0 auto; | ||
| margin-bottom: 80px; | ||
| } | ||
|
|
||
| .card { | ||
| height: 300px; | ||
| background-size: cover; | ||
| background-repeat: no-repeat; | ||
| } | ||
|
|
||
| .carousel { | ||
| height: 300px; | ||
| } | ||
|
|
||
| .carousel img { | ||
| width: 100%; | ||
| height: 100%; | ||
| object-fit: cover; | ||
| overflow: hidden; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,47 @@ | ||
| import * as React from 'react'; | ||
| import Carousel from "./Carousel" | ||
|
|
||
| export default function Cards() { | ||
| const nasaApiKey = '6H6EdNLLrDu8SC1LZMJkbJzoGIghjvrjzgQpF72W'; | ||
| const baseUri = 'https://api.nasa.gov/planetary/apod'; | ||
| const nasaApiKey = '6H6EdNLLrDu8SC1LZMJkbJzoGIghjvrjzgQpF72W'; | ||
| const baseUri = 'https://api.nasa.gov/planetary/apod'; | ||
| // not the most elegant date randomiser, I know, but works (sort of) | ||
| var myDate = "2019-0"+Math.floor(Math.random()*12).toString() +"-" + Math.floor(Math.random()*29).toString(); | ||
|
|
||
|
|
||
| function getImage(date: string) { | ||
| return fetch(`${baseUri}?api_key=${nasaApiKey}&date=${myDate}`) | ||
| .then(response => { | ||
| return response.json(); | ||
| }) | ||
| .then(jsonResponse => { | ||
| return jsonResponse.hdurl; | ||
| }); | ||
| } | ||
|
|
||
| const images = [ | ||
| { src: "https://apod.nasa.gov/apod/image/2002/freeflyer_nasa_960.jpg" }, | ||
| { src: "https://apod.nasa.gov/apod/image/2002/SolarOrbiterLaunch_Demeter_960.jpg" }, | ||
| { src: "https://apod.nasa.gov/apod/image/2002/EclipseCamel_Cripps_960.jpg" }, | ||
| { src: "https://apod.nasa.gov/apod/image/2001/C2017T2_2020-01-24-26-28_posta1024.jpg" } | ||
|
|
||
| ]; | ||
|
|
||
| // const [activeImage, setActiveImage] = React.useState(0); | ||
| // | ||
| // const randomImages = e => { | ||
| // const len = images.length; | ||
| // setActiveImage(Math.floor(Math.random() * len)) | ||
| // | ||
| // }; | ||
|
|
||
|
|
||
| export default function Card({ date }) { | ||
|
|
||
| const [imageUrl, setImageUrl] = React.useState(''); | ||
| const [image, setImage] = React.useState(''); | ||
|
|
||
| React.useEffect(() => { | ||
| getImage(date).then(response => setImage(response)); | ||
| }, []); | ||
|
|
||
| const [image1Url, setImage1Url] = React.useState<string>(''); | ||
| const [image2Url, setImage2Url] = React.useState<string>(''); | ||
|
|
@@ -16,16 +55,6 @@ export default function Cards() { | |
| getImage('2020-02-01').then(response => setImage4Url(response)); | ||
| }, []); | ||
|
|
||
| function getImage(date: string) { | ||
| return fetch(`${baseUri}?api_key=${nasaApiKey}&date=${date}`) | ||
| .then(response => { | ||
| return response.json(); | ||
| }) | ||
| .then(jsonResponse => { | ||
| return jsonResponse.hdurl; | ||
| }); | ||
| } | ||
|
|
||
| const buttonStyles: React.CSSProperties = { | ||
| padding: '10px 20px', | ||
| background: 'grey', | ||
|
|
@@ -37,28 +66,27 @@ export default function Cards() { | |
| <div style={{ textAlign: 'center' }}> | ||
| <h1>🥇 Challenge 3</h1> | ||
| <a href="/thanks">Click here when you're finished</a> | ||
| {/* NASA API docs here: https://api.nasa.gov/ */} | ||
| <h3>Slider</h3> | ||
| <h3>1. Refactor this code to remove duplication and make it more 'Reacty'.</h3> | ||
| <h3>2. Convert the images into a slider using the pagination buttons.</h3> | ||
|
|
||
| <div className="cards"> | ||
| <div className="card" style={{ backgroundImage: `url(${image1Url})` }} /> | ||
| <div className="card" style={{ backgroundImage: `url(${image2Url})` }} /> | ||
| <div className="card" style={{ backgroundImage: `url(${image3Url})` }} /> | ||
| <div className="card" style={{ backgroundImage: `url(${image4Url})` }} /> | ||
| </div> | ||
| <div style={{ display: 'flex', justifyContent: 'center' }}> | ||
| <button style={buttonStyles}>Previous</button> | ||
| <button style={buttonStyles}>Next</button> | ||
| <div className="wrapper"> | ||
| <Carousel className="carousel" initialStep={1} images={images} /> | ||
| </div> | ||
| </div> | ||
|
|
||
| <h3>Randomised Image</h3> | ||
| <h3>1. Randomise the image when you click the button.</h3> | ||
| //frustrating part here is I've generated the random aspect, just can't work out | ||
| // how to deal with the onClick | ||
|
|
||
| <div className="cards"> | ||
| <div className="card" style={{ backgroundImage: `url(${image1Url})` }} /> | ||
| </div> | ||
| <div style={{ display: 'flex', justifyContent: 'center' }}> | ||
| <button style={buttonStyles}>Randomise</button> | ||
| <div className="card" style={{ backgroundImage: `${baseUri}?api_key=${nasaApiKey}&date=${myDate}` }} /></div> | ||
| <div style={{ display: 'flex', justifyContent: 'center' }}> | ||
| <button style={buttonStyles} >Randomise</button> | ||
|
Contributor
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. So for the onClick add an onclick handler to the button;
Then we also need to do something with the onClick so: Then we need some new state And finally change the background image for the card: |
||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| ); | ||
| } | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import React from 'react'; | ||
| import { useStep } from 'react-hooks-helper'; | ||
|
|
||
| import Navigation from './Navigation'; | ||
| import Progress from './Progress'; | ||
|
|
||
| const Carousel = ({ initialStep, images }) => { | ||
| const { step, navigation, index, isPaused, autoAdvanceDuration } = useStep({ | ||
| initialStep, | ||
| steps: images, | ||
| }); | ||
| const { description = '', src, alt = '' } = step; | ||
|
|
||
| return ( | ||
| <div className="cards"> | ||
| <div className="card"> | ||
| <div className="carousel"> | ||
| <img alt={alt} src={src} /> | ||
| <Navigation | ||
| isPaused={isPaused} | ||
| index={index} | ||
| count={images.length} | ||
| {...navigation} | ||
| /> | ||
| {!isPaused && <Progress step={index} duration={autoAdvanceDuration} />} | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default Carousel; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import React from 'react'; | ||
|
|
||
| const Dots = ({ index, count, go }) => ( | ||
| <div className="dots"> | ||
| {Array.from(Array(count), (_, i) => i).map(i => ( | ||
| <button key={i} disabled={i === index} onClick={() => go(i)} /> | ||
| ))} | ||
| </div> | ||
| ); | ||
|
|
||
| export default Dots; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,28 @@ | ||
| import * as React from 'react'; | ||
| import { useState } from 'react'; | ||
|
|
||
|
|
||
|
|
||
| export default function Login() { | ||
| const [email, setEmail] = React.useState<string>(''); | ||
|
|
||
| const [email, setEmail] = useState(""); | ||
| const [emailValidationError, setEmailValidationError] = useState(""); | ||
| const [showPassword, setShowPassword] = useState<boolean>(true); | ||
|
|
||
|
|
||
| function handleEmailChange(event) { | ||
| setEmail(event.target.value); | ||
| }; | ||
|
|
||
| function validateEmail(value) { | ||
| let error; | ||
| if (!value) { | ||
| error = 'Required'; | ||
| } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value)) { | ||
| error = 'Invalid email address'; | ||
| } | ||
| return error; | ||
| }; | ||
|
Comment on lines
+17
to
+25
Contributor
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. Pretty much there with this one. Add an onblur handler to the email input and add the email validation error into the error box: Then change your validation function slightly: |
||
|
|
||
LiamBorner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| React.useEffect(() => { | ||
| console.log( | ||
|
|
@@ -17,6 +38,7 @@ export default function Login() { | |
| color: 'white', | ||
| }; | ||
|
|
||
|
|
||
| const authToken = document.querySelector('head meta[name="csrf-token"]' as any).content; | ||
|
|
||
| return ( | ||
|
|
@@ -26,20 +48,22 @@ export default function Login() { | |
| <h3>2. Validate the email is in the correct format (client side) on input blur.</h3> | ||
| <h3>3. Implement the functionality to show the password.</h3> | ||
| <h3>4. Login successfully using the correct password.</h3> | ||
| <form method="POST" action="/login"> | ||
|
|
||
| <form method="POST" action="/login"> | ||
| <input type="hidden" name="authenticity_token" value={authToken} /> | ||
| <label htmlFor="">Email</label> | ||
| <input name="email" type="text" value={email} /> | ||
| <div style={{ color: 'red', margin: '10px 0' }}>{/* Email validation errors go here */}</div> | ||
| <input name="email" type="email" value={email} onChange={handleEmailChange} /> | ||
| <div style={{ color: 'red', margin: '10px 0' }}></div> | ||
| <label htmlFor="">Password</label> | ||
| <div style={{ display: 'flex', marginBottom: '20px' }}> | ||
| <input name="password" type="password" /> | ||
| <button type="button">Show Password</button> | ||
| <input name="password" type={showPassword ? "text" : "password"} /> | ||
| </div> | ||
| <button type="button" onClick={() => setShowPassword(!showPassword)}>{showPassword ? 'Hide' : 'Show'} Password</button> | ||
| <button style={buttonStyles} disabled={!email}> | ||
| Login | ||
| </button> | ||
| </form> | ||
| </div> | ||
| ); | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import React from "react"; | ||
|
|
||
| import Dots from "./Dots"; | ||
|
|
||
| const Navigation = ({ | ||
| isPaused, | ||
| index, | ||
| count, | ||
| next, | ||
| previous, | ||
| go, | ||
| play, | ||
| pause | ||
| }) => { | ||
| return ( | ||
| <div className="navigation"> | ||
| <Dots index={index} count={count} go={go} /> | ||
| <div className="play-pause"> | ||
| <button onClick={previous}><</button> | ||
| {isPaused ? ( | ||
| <button onClick={play}>►</button> | ||
| ) : ( | ||
| <button onClick={pause}>❙❙</button> | ||
| )} | ||
| <button onClick={next}>></button> | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default Navigation; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| import React from "react"; | ||
|
|
||
| const Progress = ({ step, duration }) => ( | ||
| <div | ||
| key={step} | ||
| className="step-precentage" | ||
| style={{ animationDuration: `${duration}ms` }} | ||
| /> | ||
| ); | ||
|
|
||
| export default Progress; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,2 @@ | ||
| <%# This is the link to the first challenge -> challenge_1_path %> | ||
| <%= react_component 'staticPages/Home', linkPath: nil %> | ||
| <%= react_component 'staticPages/Home', linkPath: challenge_1_path %> | ||
LiamBorner marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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.
You don't need to use myDate here since we are passing the date into the method.
Just needs to be
return fetch('${baseUri}?api_key=${nasaApiKey}&date=${date}')