Commit 11234aa8 authored by Alessandro Caridi's avatar Alessandro Caridi Committed by Michele Azzolari

inizio react + estrazione dati

parent 8ff1f2bf
.dockerignore
.editorconfig
.eslintrc.json
.git
.gitignore
.gitlab-ci.yml
.idea
Dockerfile
README.md
node_modules
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
{
"extends": [
"react-app"
],
"plugins": [
"prettier"
],
"rules": {
"no-undef": "off",
"no-use-before-define": "off",
"react/jsx-filename-extension": "off",
"react/no-array-index-key": "off",
"no-console": "off",
"camelcase": "off",
"prettier/prettier": [
"error",
{
"printWidth": 120,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"parser": "flow",
"semi": true
}
]
}
}
data/
.idea/
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
.idea
public/data
npm-debug.log*
yarn-debug.log*
yarn-error.log*
image: docker:stable
variables:
GIT_STRATEGY: clone
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2
CONTAINER_TEST_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
CONTAINER_RELEASE_IMAGE: $CI_REGISTRY_IMAGE:latest
services:
- docker:dind
before_script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN docker-registry.fluidware.it
stages:
- test
- build
- release
test:
stage: test
script:
- docker build --target builder -t console-tester .
- docker run --rm console-tester sh -c 'CI=true npm run test'
build:
stage: build
script:
- docker build --pull -t $CONTAINER_TEST_IMAGE .
- docker push $CONTAINER_TEST_IMAGE
only:
- tags
release-image:
stage: release
script:
- docker pull $CONTAINER_TEST_IMAGE
- docker tag $CONTAINER_TEST_IMAGE $CONTAINER_RELEASE_IMAGE
- docker push $CONTAINER_RELEASE_IMAGE
only:
- tags
tag-version-prefix=""
# builder image
FROM node:10-alpine AS builder
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install --no-optional
COPY . .
RUN npm run build
# production image
FROM node:10-alpine
EXPOSE 5000
ENV NODE_ENV=production
WORKDIR /app
RUN npm i -g serve
COPY --from=builder /usr/src/app/build .
CMD [ "serve", "-s", "-l", "5000" ]
This diff is collapsed.
{
"name": "react-boilerplate",
"version": "0.1.0",
"description": "Fluidware react boilerplate",
"private": true,
"dependencies": {
"connected-react-router": "^6.3.0",
"node-sass": "^4.12.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-lazy-load-image-component": "^1.3.2",
"react-redux": "^6.0.0",
"react-router-dom": "^4.3.1",
"react-scripts": "3.0.1",
"react-transition-group": "^4.1.0",
"redux": "^4.0.1",
"redux-thunk": "^2.3.0"
},
"proxy": "http://localhost:9100",
"optionalDependencies": {
"eslint-plugin-prettier": "^3.0.1",
"prettier": "^1.15.3"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="stylesheets/style.css" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
html {
font-size: 16px;
}
@media (max-width: 991px) {
html{font-size: 14px;}
}
@media (max-width: 767px) {
html{font-size: 12px;}
}
import React, { PureComponent } from 'react';
import { Provider } from 'react-redux';
import store, { history } from '../../store';
import { ConnectedRouter } from 'connected-react-router';
import { BrowserRouter as Router } from 'react-router-dom';
import WrapApp from './WrapApp';
import ErrorBoundary from './ErrorBoundary';
class BaseApp extends PureComponent {
render() {
return (
<Provider store={store}>
<ConnectedRouter history={history}>
<Router>
<div className="app-wrapper">
<ErrorBoundary>
<WrapApp />
</ErrorBoundary>
</div>
</Router>
</ConnectedRouter>
</Provider>
);
}
}
export default BaseApp;
import React from 'react';
import ReactDOM from 'react-dom';
import BaseApp from './BaseApp';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<BaseApp />, div);
ReactDOM.unmountComponentAtNode(div);
});
import React, { Component } from 'react';
//import { postData } from '../../lib/utils/httputils';
const logErrorToMyService = function(error, info) {
//postData('/api/v1/error', { error, info }).finally();
};
class ErrorBoundary extends Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
componentDidCatch(error, info) {
// You can also log the error to an error reporting service
logErrorToMyService(error, info);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return (
<div>
<h1>Something went wrong :-(</h1>
<p>We've beeing notified and we're working on it.. Please try again later..</p>
<a href="/">Home</a>
</div>
);
}
return this.props.children;
}
}
export default ErrorBoundary;
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Route, withRouter } from 'react-router-dom';
import { doGetData } from '../../models/data';
import { doGetTranslations } from '../../models/i18n';
import Navbar from '../Navbar';
import Home from '../Home';
import Footer from '../Footer';
class WrapApp extends PureComponent {
static propTypes = {
lang: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
render() {
if (!this.props.lang.loaded) {
return <div>Loading...</div>;
}
return (
<div className="app-inner">
<div className="app-inner">
<Navbar lang={this.props.lang} location={this.props.location} dispatch={this.props.dispatch} />
<Route path="/" exact component={Home} />
<Footer />
</div>
</div>
);
}
componentDidMount() {
const lang = localStorage.getItem('lang') || 'it';
this.props.dispatch(doGetTranslations(lang));
this.props.dispatch(doGetData());
}
}
function mapStateToProps(state) {
const { lang } = state;
return {
lang
};
}
export default withRouter(connect(mapStateToProps)(WrapApp));
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { CSSTransition } from 'react-transition-group';
import './Carousel.scss';
import CarouselItemVideo from './CarouselItemVideo';
class Carousel extends PureComponent {
static propTypes = {
slides: PropTypes.array.isRequired,
interval: PropTypes.number,
lang: PropTypes.object.isRequired
};
static defaultProps = {
interval: 5000
};
state = {
currentSlide: 0
};
carouselLocked = false;
render() {
return (
<div
className="carousel-wrapper"
onMouseEnter={e => this.stopCarousel()}
onMouseLeave={e => this.startCarousel()}
>
<div className="carousel slide" data-ride="carousel">
<ol className="carousel-indicators">
{this.props.slides.map((slide, i) => {
return this.getCarouselIndicator(slide, i);
})}
</ol>
<div className="carousel-inner">
{this.props.slides.map((slide, i) => {
return this.getCarouselItem(slide, i);
})}
</div>
<a onClick={this.goToPrev} className="carousel-control-prev" href="#myCarousel" role="button">
<span className="carousel-control-prev-icon" aria-hidden="true" />
<span className="sr-only">Previous</span>
</a>
<a onClick={this.goToNext} className="carousel-control-next" href="#myCarousel" role="button">
<span className="carousel-control-next-icon" aria-hidden="true" />
<span className="sr-only">Next</span>
</a>
</div>
</div>
);
}
componentDidMount() {
this.startCarousel();
}
startCarousel() {
if (this.carouselLocked === true) {
return;
}
this.stopCarousel();
this.carouselInterval = setInterval(() => {
this.goToNext();
}, this.props.interval);
}
stopCarousel() {
if (this.carouselInterval) {
clearInterval(this.carouselInterval);
}
}
getCarouselIndicator(slide, i) {
return <li key={i} className={i === this.state.currentSlide ? 'active' : ''} onClick={e => this.goToSlide(e, i)} />;
}
goToPrev = e => {
const prevSlide = this.state.currentSlide - 1;
this.goToSlide(e, prevSlide >= 0 ? prevSlide : this.props.slides.length - 1);
};
goToNext = e => {
const nextSlide = this.state.currentSlide + 1;
this.goToSlide(e, nextSlide > this.props.slides.length - 1 ? 0 : nextSlide);
};
goToSlide(e, i) {
e && e.preventDefault();
this.carouselLocked = false;
this.setState({
currentSlide: i
});
}
lockCarousel() {
this.carouselLocked = true;
}
getCarouselItem(slide, i) {
const urlContentCarousel = slide.content;
return (
<CSSTransition key={i} in={i === this.state.currentSlide} timeout={1000} classNames="my-node">
<div className={'carousel-item' + (i === this.state.currentSlide ? ' active' : '')}>
{slide.type === 'img' && (
<div className="img-carousel" style={{ backgroundImage: `url(` + urlContentCarousel + `)` }} />
)}
{slide.type === 'video' && (
<CarouselItemVideo
coverImg={slide.cover}
urlVideo={slide.content}
active={i === this.state.currentSlide}
onStart={() => this.lockCarousel()}
/>
)}
<div className="container">
<div className="carousel-caption text-left">
<h1>{slide.caption}</h1>
</div>
</div>
</div>
</CSSTransition>
);
}
}
export default Carousel;
@import '../shared';
.carousel {
margin-top: 56px;
.carousel-item {
.img-carousel {
background-position: center;
background-repeat: no-repeat;
background-size: cover;
min-height: 400px;
}
.carousel-caption {
color: red;
}
}
}
.my-node-enter {
opacity: 0;
}
.my-node-enter-active {
opacity: 1;
transition: opacity 1000ms;
}
.my-node-exit {
opacity: 1;
}
.my-node-exit-active {
opacity: 0;
transition: opacity 1000ms;
}
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import './CarouselItemVideo.scss';
class CarouselItemVideo extends PureComponent {
state = {
shown: false
};
static propTypes = {
coverImg: PropTypes.string.isRequired,
urlVideo: PropTypes.string.isRequired,
onStart: PropTypes.func.isRequired,
active: PropTypes.bool.isRequired
};
render() {
const { coverImg, urlVideo } = this.props;
const { shown } = this.state;
return (
<div className="text-center video-wrapper" style={{ backgroundImage: `url(` + coverImg + `)` }}>
{!shown && (
<img className="icona-video" src="/assets/play-video.png" alt="icona start" onClick={e => this.setShown(e)} />
)}
{shown && (
<div id={'yt'} className="yt-video">
<iframe
className="iframe"
title="youtube video"
src={'https://www.youtube.com/embed/' + urlVideo + '?autoplay=1&rel=0&controls=0'}
frameBorder="0"
allowFullScreen
/>
</div>
)}
</div>
);
}
componentDidUpdate(prevProps) {
const { active } = this.props;
const { shown } = this.state;
if (active === false && active !== prevProps.active && shown) {
this.setState({
shown: false
});
}
}
setShown(e) {