Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions app/assets/stylesheets/card.scss
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;
}
84 changes: 56 additions & 28 deletions app/javascript/components/challenges/Cards.tsx
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}`)
Copy link
Contributor

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}')

.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>('');
Expand All @@ -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',
Expand All @@ -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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So for the onClick add an onclick handler to the button;

<button style={buttonStyles} onClick={handleRandomise}>Randomise</button>

Then we also need to do something with the onClick so:

function handleRandomise() {
   const randomDate = "2019-0"+Math.floor(Math.random()*12).toString() +"-" +  
   Math.floor(Math.random()*29).toString();
     getImage(randomDate).then(response => setRandomImage(response))
   }

Then we need some new state const [randomImage, setRandomImage] = React.useState('')

And finally change the background image for the card:

<div className="card" style={{ backgroundImage: `url(${randomImage})` }} /></div>
  <div style={{ display: 'flex', justifyContent: 'center' }}>
    <button style={buttonStyles} onClick={handleRandomise}>Randomise</button>
  </div>

</div>
</div>
</div>

);
}
};
32 changes: 32 additions & 0 deletions app/javascript/components/challenges/Carousel.jsx
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;
10 changes: 7 additions & 3 deletions app/javascript/components/challenges/Counter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import * as React from 'react';

import NextButton from './NextButton';

export default function Counter() {
const [count, setCount] = React.useState<number>(0);
export default function Counter(initialCount = 1) {

const [count, setCount] = React.useState<number>(-10);
const resetCounter = () => setCount(0);

return (
<div>
Expand All @@ -16,8 +18,10 @@ export default function Counter() {
<input readOnly value={count} />
</div>
<div>
<button onClick={() => setCount(count ** 2)}>Decrease</button>
<button onClick={() => setCount(count - 1)}>Decrease</button>
<button onClick={() => setCount(count + 1)}>Increase</button>
<button onClick={resetCounter}>Reset</button>

</div>
{count === -10 && <NextButton />}
</div>
Expand Down
11 changes: 11 additions & 0 deletions app/javascript/components/challenges/Dots.jsx
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;
36 changes: 30 additions & 6 deletions app/javascript/components/challenges/Login.tsx
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
Copy link
Contributor

Choose a reason for hiding this comment

The 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:

<input name="email" type="email" value={email} onChange={handleEmailChange} onBlur={validateEmail} />
<div style={{ color: 'red', margin: '10px 0' }}>{emailValidationError}</div>

Then change your validation function slightly:

function validateEmail(event) {
    const value = event.target.value;
    let error;
    if (!value) {
      error = 'Required';
    } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}$/i.test(value)) {
      error = 'Invalid email address';
    }
    setEmailValidationError(error)
  };


React.useEffect(() => {
console.log(
Expand All @@ -17,6 +38,7 @@ export default function Login() {
color: 'white',
};


const authToken = document.querySelector('head meta[name="csrf-token"]' as any).content;

return (
Expand All @@ -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>
);

}
31 changes: 31 additions & 0 deletions app/javascript/components/challenges/Navigation.jsx
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}>&lt;</button>
{isPaused ? (
<button onClick={play}>►</button>
) : (
<button onClick={pause}>❙❙</button>
)}
<button onClick={next}>&gt;</button>
</div>
</div>
);
};

export default Navigation;
6 changes: 4 additions & 2 deletions app/javascript/components/challenges/NextButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ export default function NextButton() {
{ x: 400, y: -200 },
{ x: 50, y: 200 },
];
setLeft(positionArray[randomIndex].x);
setTop(positionArray[randomIndex].y);
//I stopped this from running away from me by commenting this out ...not sure if I was meant to

// setLeft(positionArray[randomIndex].x);
// setTop(positionArray[randomIndex].y);
}

const styles: React.CSSProperties = {
Expand Down
11 changes: 11 additions & 0 deletions app/javascript/components/challenges/Progress.jsx
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;
2 changes: 1 addition & 1 deletion app/views/static_pages/home.html.erb
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 %>
Empty file added cards.html.erb
Empty file.
Loading