Start implementing MySQL data fetching.
gitea/icedream/vizon-countdown-website/develop There was a failure building this commit
Details
gitea/icedream/vizon-countdown-website/develop There was a failure building this commit
Details
- Create Drawing component to display drawing information. - Add SQL file to create view to filter for amount of correctly matched numbers. - Use pooled connections for MySQL connections. - Implement API endpoint "status", not done yet, needs to query from above mentioned view. - Add more npm scripts that interact with docker/docker-compose. - Allow web container to write back to source folder.develop
parent
9bea67e1b1
commit
202c35b517
|
@ -28,7 +28,7 @@ services:
|
||||||
build: docker/node
|
build: docker/node
|
||||||
command: sh ./docker/web.sh
|
command: sh ./docker/web.sh
|
||||||
volumes:
|
volumes:
|
||||||
- ".:/src:ro"
|
- ".:/src"
|
||||||
- "web_npm_cache:/var/cache/npm"
|
- "web_npm_cache:/var/cache/npm"
|
||||||
- "/src/node_modules"
|
- "/src/node_modules"
|
||||||
ports:
|
ports:
|
||||||
|
|
94
index.js
94
index.js
|
@ -1,8 +1,32 @@
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const mysql = require('mysql');
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
const moment = require('moment-timezone');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
|
|
||||||
|
/* Database setup */
|
||||||
|
|
||||||
|
const dbPool = mysql.createPool({
|
||||||
|
host: process.env.MYSQL_HOST || 'localhost',
|
||||||
|
user: process.env.MYSQL_USER || 'root',
|
||||||
|
password: process.env.MYSQL_PASSWORD || undefined,
|
||||||
|
database: process.env.MYSQL_DATABASE || 'vizon',
|
||||||
|
socketPath: process.env.MYSQL_SOCKET_PATH || undefined,
|
||||||
|
timezone: process.env.TZ || 'local',
|
||||||
|
|
||||||
|
debug: process.env.NODE_ENV === 'development',
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const tableNames = {
|
||||||
|
drawings: process.env.MYSQL_TABLE_DRAWINGS || 'vizon_drawings',
|
||||||
|
users: process.env.MYSQL_TABLE_USERS || 'vizon_users',
|
||||||
|
rankings: 'vizon_web_rankings',
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Frontend server setup */
|
||||||
|
|
||||||
const frontendDir = path.resolve(__dirname, 'dist');
|
const frontendDir = path.resolve(__dirname, 'dist');
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
@ -29,6 +53,76 @@ fs.stat(frontendDir, (err) => {
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
|
||||||
|
// Additional middleware which will set headers that we need on each request.
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
// Disable caching so we'll always get the latest comments.
|
||||||
|
res.setHeader('Cache-Control', 'no-cache');
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
function calculateRankings(id: Number) {
|
||||||
|
db.query('SELECT * FROM `vizon_web_rankings` WHERE `vizon_drawings_id`=?', [id], (err, results, fields) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Failed to query rankings from database:', err);
|
||||||
|
res.status(500).json({
|
||||||
|
error: 'Database query failed',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get('/api/status', (req, res) => {
|
||||||
|
dbPool.getConnection((err, db) => {
|
||||||
|
if (err) {
|
||||||
|
console.error('Failed to connect to database:', err);
|
||||||
|
res.status(500).json({
|
||||||
|
error: 'Database connection failed',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
db.query('SELECT * FROM ?? ORDER BY ?? DESC LIMIT 0, 1', [
|
||||||
|
tableNames.drawings,
|
||||||
|
'id',
|
||||||
|
], (qerr, results, fields) => {
|
||||||
|
if (qerr) {
|
||||||
|
console.error('Failed to request drawings:', err);
|
||||||
|
res.status(500).json({
|
||||||
|
error: 'Database query failed',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = results[0];
|
||||||
|
|
||||||
|
const id = row.id;
|
||||||
|
|
||||||
|
const date = moment(row.drawing_date);
|
||||||
|
|
||||||
|
const numbers = [
|
||||||
|
row.first,
|
||||||
|
row.second,
|
||||||
|
row.third,
|
||||||
|
row.fourth,
|
||||||
|
row.fifth,
|
||||||
|
row.sixth,
|
||||||
|
].map(i => parseInt(i, 10));
|
||||||
|
|
||||||
|
const ranking = [
|
||||||
|
// @TODO - calculate ranking from mysql tables {drawings} and {bets}
|
||||||
|
];
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
lastDrawing: {
|
||||||
|
id,
|
||||||
|
date,
|
||||||
|
numbers,
|
||||||
|
ranking,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.listen(app.get('port'), () => {
|
app.listen(app.get('port'), () => {
|
||||||
console.log(`Server started: http://localhost:${app.get('port')}/`);
|
console.log(`Server started: http://localhost:${app.get('port')}/`);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1643,6 +1643,11 @@
|
||||||
"integrity": "sha1-TK2iGTZS6zyp7I5VyQFWacmAaXg=",
|
"integrity": "sha1-TK2iGTZS6zyp7I5VyQFWacmAaXg=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"bignumber.js": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.0.2.tgz",
|
||||||
|
"integrity": "sha1-LR3DfuWWiGfs6pC22k0W5oYI0h0="
|
||||||
|
},
|
||||||
"binary-extensions": {
|
"binary-extensions": {
|
||||||
"version": "1.10.0",
|
"version": "1.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz",
|
||||||
|
@ -2474,8 +2479,7 @@
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"cosmiconfig": {
|
"cosmiconfig": {
|
||||||
"version": "2.2.2",
|
"version": "2.2.2",
|
||||||
|
@ -5518,8 +5522,7 @@
|
||||||
"isarray": {
|
"isarray": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"isbinaryfile": {
|
"isbinaryfile": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
|
@ -6691,14 +6694,12 @@
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.18.1",
|
"version": "2.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.18.1.tgz",
|
||||||
"integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8=",
|
"integrity": "sha1-w2GT3Tzhwu7SrbfIAtu8d6gbHA8="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"moment-timezone": {
|
"moment-timezone": {
|
||||||
"version": "0.5.13",
|
"version": "0.5.13",
|
||||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.13.tgz",
|
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.13.tgz",
|
||||||
"integrity": "sha1-mc5cfYJyYusPH3AgRBd/YHRde5A=",
|
"integrity": "sha1-mc5cfYJyYusPH3AgRBd/YHRde5A=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"moment": "2.18.1"
|
"moment": "2.18.1"
|
||||||
}
|
}
|
||||||
|
@ -6730,6 +6731,17 @@
|
||||||
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
|
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"mysql": {
|
||||||
|
"version": "2.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mysql/-/mysql-2.14.1.tgz",
|
||||||
|
"integrity": "sha512-ZPXqQeYH7L1QPDyC77Rcp32cNCQnNjz8Y4BbF17tOjm5yhSfjFa3xS4PvuxWJtEEmwVc4ccI7sSntj4eyYRq0A==",
|
||||||
|
"requires": {
|
||||||
|
"bignumber.js": "4.0.2",
|
||||||
|
"readable-stream": "2.3.3",
|
||||||
|
"safe-buffer": "5.1.1",
|
||||||
|
"sqlstring": "2.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nan": {
|
"nan": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz",
|
||||||
|
@ -8940,8 +8952,7 @@
|
||||||
"process-nextick-args": {
|
"process-nextick-args": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
|
||||||
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
|
"integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"progress": {
|
"progress": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
@ -9291,7 +9302,6 @@
|
||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
|
||||||
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
|
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-util-is": "1.0.2",
|
"core-util-is": "1.0.2",
|
||||||
"inherits": "2.0.3",
|
"inherits": "2.0.3",
|
||||||
|
@ -9774,8 +9784,7 @@
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
|
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"sass-graph": {
|
"sass-graph": {
|
||||||
"version": "2.2.4",
|
"version": "2.2.4",
|
||||||
|
@ -10471,6 +10480,11 @@
|
||||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
|
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"sqlstring": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.2.0.tgz",
|
||||||
|
"integrity": "sha1-wxNcTqirzX5+50GklmqJHYak8ZE="
|
||||||
|
},
|
||||||
"sshpk": {
|
"sshpk": {
|
||||||
"version": "1.13.1",
|
"version": "1.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
|
||||||
|
@ -10554,7 +10568,6 @@
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "5.1.1"
|
"safe-buffer": "5.1.1"
|
||||||
}
|
}
|
||||||
|
@ -11128,8 +11141,7 @@
|
||||||
"util-deprecate": {
|
"util-deprecate": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"utila": {
|
"utila": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
"docker-compose": "docker-compose -f docker-compose.local.yml",
|
"docker-compose": "docker-compose -f docker-compose.local.yml",
|
||||||
"docker:down:clean": "npm run -s docker:down -- --rmi all -v",
|
"docker:down:clean": "npm run -s docker:down -- --rmi all -v",
|
||||||
"docker:down": "npm run -s docker-compose -- down",
|
"docker:down": "npm run -s docker-compose -- down",
|
||||||
|
"docker:logs": "npm run -s docker-compose -- logs",
|
||||||
|
"docker:logs:follow": "npm run -s docker:logs -- -f",
|
||||||
|
"docker:restart": "npm run -s docker-compose -- restart",
|
||||||
"docker:up:daemon": "npm run -s docker:up -- -d",
|
"docker:up:daemon": "npm run -s docker:up -- -d",
|
||||||
"docker:up": "npm run -s docker-compose -- up --build",
|
"docker:up": "npm run -s docker-compose -- up --build",
|
||||||
"docker": "npm run -s docker:up",
|
"docker": "npm run -s docker:up",
|
||||||
|
@ -51,7 +54,6 @@
|
||||||
"eslint-plugin-react": "^7.2.1",
|
"eslint-plugin-react": "^7.2.1",
|
||||||
"eslint": "^4.5.0",
|
"eslint": "^4.5.0",
|
||||||
"file-loader": "^0.11.2",
|
"file-loader": "^0.11.2",
|
||||||
"moment-timezone": "^0.5.13",
|
|
||||||
"normalize-scss": "^7.0.0",
|
"normalize-scss": "^7.0.0",
|
||||||
"nwb-sass": "^0.8.1",
|
"nwb-sass": "^0.8.1",
|
||||||
"nwb": "^0.18.10",
|
"nwb": "^0.18.10",
|
||||||
|
@ -68,6 +70,8 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "^1.17.2",
|
"body-parser": "^1.17.2",
|
||||||
"express": "^4.15.4"
|
"express": "^4.15.4",
|
||||||
|
"moment-timezone": "^0.5.13",
|
||||||
|
"mysql": "^2.14.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
CREATE OR REPLACE VIEW `vizon_web_rankings` AS
|
||||||
|
SELECT
|
||||||
|
bets.id,
|
||||||
|
vizon_drawings_id,
|
||||||
|
COUNT(*) AS richtige
|
||||||
|
FROM
|
||||||
|
(
|
||||||
|
SELECT
|
||||||
|
vizon_users_id AS id,
|
||||||
|
vizon_drawings_id,
|
||||||
|
FIRST AS NUMBER
|
||||||
|
FROM
|
||||||
|
vizon_bets
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
vizon_users_id,
|
||||||
|
vizon_drawings_id,
|
||||||
|
SECOND
|
||||||
|
FROM
|
||||||
|
vizon_bets
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
vizon_users_id,
|
||||||
|
vizon_drawings_id,
|
||||||
|
third
|
||||||
|
FROM
|
||||||
|
vizon_bets
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
vizon_users_id,
|
||||||
|
vizon_drawings_id,
|
||||||
|
fourth
|
||||||
|
FROM
|
||||||
|
vizon_bets
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
vizon_users_id,
|
||||||
|
vizon_drawings_id,
|
||||||
|
fifth
|
||||||
|
FROM
|
||||||
|
vizon_bets
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
vizon_users_id,
|
||||||
|
vizon_drawings_id,
|
||||||
|
sixth
|
||||||
|
FROM
|
||||||
|
vizon_bets
|
||||||
|
) bets,
|
||||||
|
(
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
FIRST AS NUMBER
|
||||||
|
FROM
|
||||||
|
vizon_drawings
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
SECOND
|
||||||
|
FROM
|
||||||
|
vizon_drawings
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
third
|
||||||
|
FROM
|
||||||
|
vizon_drawings
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
fourth
|
||||||
|
FROM
|
||||||
|
vizon_drawings
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
fifth
|
||||||
|
FROM
|
||||||
|
vizon_drawings
|
||||||
|
UNION ALL
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
sixth
|
||||||
|
FROM
|
||||||
|
vizon_drawings
|
||||||
|
) drawings
|
||||||
|
WHERE
|
||||||
|
bets.vizon_drawings_id = drawings.id AND bets.number = drawings.number
|
||||||
|
GROUP BY
|
||||||
|
bets.id,
|
||||||
|
vizon_drawings_id
|
14
src/App.jsx
14
src/App.jsx
|
@ -4,6 +4,7 @@ import moment from 'moment-timezone';
|
||||||
import 'react-fontawesome';
|
import 'react-fontawesome';
|
||||||
import WebFont from 'webfontloader';
|
import WebFont from 'webfontloader';
|
||||||
import Countdown from './Countdown';
|
import Countdown from './Countdown';
|
||||||
|
import Drawing from './Drawing';
|
||||||
import Header from './Header';
|
import Header from './Header';
|
||||||
import Footer from './Footer';
|
import Footer from './Footer';
|
||||||
import getUpcomingDate from './getUpcomingDate';
|
import getUpcomingDate from './getUpcomingDate';
|
||||||
|
@ -79,6 +80,19 @@ class App extends React.Component {
|
||||||
The next VIzon draw is on {nextUpcomingDate.format('dddd')}, {nextUpcomingDate.format('L LT z')}.
|
The next VIzon draw is on {nextUpcomingDate.format('dddd')}, {nextUpcomingDate.format('L LT z')}.
|
||||||
</p>
|
</p>
|
||||||
<Countdown date={nextUpcomingDate} />
|
<Countdown date={nextUpcomingDate} />
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Last Drawing:
|
||||||
|
</p>
|
||||||
|
<Drawing
|
||||||
|
numbers={[1, 2, 3, 4, 5, 6]}
|
||||||
|
ranking={[
|
||||||
|
{ rank: '1st', winners: 0 },
|
||||||
|
{ rank: '2nd', winners: 0 },
|
||||||
|
{ rank: '3rd', winners: 0 },
|
||||||
|
{ rank: 'Consolation', winners: 4 },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Footer>
|
<Footer>
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import style from './Drawing.sass';
|
||||||
|
|
||||||
|
const Numbers = ({ numbers }) => (
|
||||||
|
<div className={style.numbers}>
|
||||||
|
{
|
||||||
|
numbers.map((number, index) => (
|
||||||
|
<div key={index} className={style.number}>
|
||||||
|
{number}
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
Numbers.propTypes = {
|
||||||
|
numbers: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class Drawing extends React.Component {
|
||||||
|
static propTypes = {
|
||||||
|
ranking: PropTypes.arrayOf(PropTypes.shape({
|
||||||
|
rank: PropTypes.string,
|
||||||
|
winners: PropTypes.int,
|
||||||
|
})).isRequired,
|
||||||
|
numbers: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { ranking, numbers } = this.props;
|
||||||
|
return (
|
||||||
|
<div className={style.drawing}>
|
||||||
|
<Numbers numbers={numbers} />
|
||||||
|
<div className={style.ranking}>
|
||||||
|
{
|
||||||
|
ranking.map(({ rank, winners }) => (
|
||||||
|
<div key={rank} className={style.rank}>
|
||||||
|
<div className={style.rankName}>{rank}</div>
|
||||||
|
<div className={style.winners}>{winners > 0 ? winners : 'No'} winners</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
.drawing
|
||||||
|
|
||||||
|
.numbers
|
||||||
|
display: flex
|
||||||
|
flex-direction: row
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
.number
|
||||||
|
flex: 1 0 auto
|
||||||
|
text-align: center
|
||||||
|
font-size: 2.5em
|
||||||
|
font-weight: bold
|
||||||
|
|
||||||
|
.ranking
|
||||||
|
display: table
|
||||||
|
width: 100%
|
||||||
|
|
||||||
|
.rank
|
||||||
|
display: table-row
|
||||||
|
|
||||||
|
.rankName, .winners
|
||||||
|
display: table-cell
|
||||||
|
|
||||||
|
.rankName
|
||||||
|
text-align: right
|
||||||
|
width: 50%
|
||||||
|
padding-right: .25em
|
||||||
|
|
||||||
|
.winners
|
||||||
|
text-align: left
|
||||||
|
width: 50%
|
||||||
|
padding-left: .25em
|
Loading…
Reference in New Issue