diff --git a/Spin_Wheel/.env b/Spin_Wheel/.env new file mode 100644 index 00000000..7d910f14 --- /dev/null +++ b/Spin_Wheel/.env @@ -0,0 +1 @@ +SKIP_PREFLIGHT_CHECK=true \ No newline at end of file diff --git a/Spin_Wheel/.gitignore b/Spin_Wheel/.gitignore new file mode 100644 index 00000000..7ed61135 --- /dev/null +++ b/Spin_Wheel/.gitignore @@ -0,0 +1,26 @@ +# See https://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +/node_modules + +# testing +/coverage + +# production +/build +/dist + +# IDE +/.vscode/ +/.idea/ + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/Spin_Wheel/gulpfile.js b/Spin_Wheel/gulpfile.js new file mode 100644 index 00000000..f331867a --- /dev/null +++ b/Spin_Wheel/gulpfile.js @@ -0,0 +1,14 @@ +const gulp = require('gulp') +const inlinesource = require('gulp-inline-source') +const replace = require('gulp-replace') + +gulp.task('default', () => { + return gulp.src('./build/*.html') + .pipe(replace('.js">', '.js" inline>')) + .pipe(replace('rel="stylesheet">', 'rel="stylesheet" inline>')) + .pipe(inlinesource({ + compress: false, + ignore: ['png'] + })) + .pipe(gulp.dest('./build')) +}); \ No newline at end of file diff --git a/Spin_Wheel/images.d.ts b/Spin_Wheel/images.d.ts new file mode 100644 index 00000000..c48fd3d2 --- /dev/null +++ b/Spin_Wheel/images.d.ts @@ -0,0 +1,6 @@ +declare module '*.svg' +declare module '*.png' +declare module '*.jpg' +declare module 'react-router-dom' +declare module 'react-dom' +declare module 'styled-components' diff --git a/Spin_Wheel/package.json b/Spin_Wheel/package.json new file mode 100644 index 00000000..66a7b2b7 --- /dev/null +++ b/Spin_Wheel/package.json @@ -0,0 +1,71 @@ +{ + "name": "Spin Wheel", + "version": "0.1.0", + "private": true, + "dependencies": { + "@fortawesome/fontawesome-svg-core": "^1.2.27", + "@fortawesome/free-solid-svg-icons": "^5.12.1", + "@fortawesome/react-fontawesome": "^0.1.8", + "@material-ui/core": "^4.9.10", + "@material-ui/lab": "^4.0.0-alpha.49", + "@material-ui/icons": "^4.11.2", + "@types/d3-ease": "^1.0.9", + "@types/jest": "^25.1.2", + "@types/react-router-dom": "^5.1.3", + "bootstrap": "^4.4.1", + "classnames": "^2.2.5", + "d3-ease": "^1.0.6", + "dotenv": "^8.2.0", + "html-loader": "^1.1.0", + "html-webpack-inline-source-plugin": "^1.0.0-beta.2", + "html-webpack-plugin": "^4.0.0-beta.4", + "i18next": "^19.8.3", + "i18next-http-backend": "^1.2.6", + "lodash": "^4.17.20", + "prop-types": "^15.7.2", + "react": "^16.8.0", + "react-bootstrap": "^1.0.0-beta.17", + "react-circular-progressbar": "^2.0.3", + "react-dom": "^16.12.0", + "react-i18next": "^11.7.3", + "react-router-dom": "^5.1.2", + "react-scripts-ts": "^4.0.8", + "rx": "^4.1.0", + "styled-components": "^5.0.1" + }, + "scripts": { + "start": "react-scripts-ts start", + "build": "npm run build:react && npm run build:bundle && npx gulp", + "build:react": "react-scripts-ts build", + "build:bundle": "webpack --config webpack.config.js", + "test": "react-scripts-ts test --env=jsdom", + "eject": "react-scripts-ts eject", + "predeploy": "gh-pages -d build", + "deploy": "gh-pages -d build" + }, + "devDependencies": { + "@svgr/webpack": "^2.4.1", + "@types/classnames": "^2.2.3", + "@types/lodash": "^4.14.109", + "@types/node": "^10.17.14", + "@types/prop-types": "^15.7.3", + "@types/react": "^16.9.19", + "@types/react-dom": "^16.9.5", + "@types/rx": "^4.1.1", + "gh-pages": "^1.1.0", + "gulp": "^4.0.2", + "gulp-inline-source": "^4.0.0", + "gulp-replace": "^1.0.0", + "react-hot-loader": "^4.12.21", + "react-scripts": "^3.4.3", + "typescript": "^3.7.5", + "webpack-cli": "^3.3.12" + }, + "homepage": "./", + "browserslist": [ + ">0.2%", + "not dead", + "not ie <= 11", + "not op_mini all" + ] +} diff --git a/Spin_Wheel/public/favicon.ico b/Spin_Wheel/public/favicon.ico new file mode 100644 index 00000000..a11777cc Binary files /dev/null and b/Spin_Wheel/public/favicon.ico differ diff --git a/Spin_Wheel/public/index.html b/Spin_Wheel/public/index.html new file mode 100644 index 00000000..277cab1f --- /dev/null +++ b/Spin_Wheel/public/index.html @@ -0,0 +1,41 @@ + + + + + + + + + + + + React App + + + +
+ + + diff --git a/Spin_Wheel/public/manifest.json b/Spin_Wheel/public/manifest.json new file mode 100644 index 00000000..ef19ec24 --- /dev/null +++ b/Spin_Wheel/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "React App", + "name": "Create React App Sample", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": "./index.html", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/Spin_Wheel/src/components/ImageComponents/blueButtonSVG.tsx b/Spin_Wheel/src/components/ImageComponents/blueButtonSVG.tsx new file mode 100644 index 00000000..8be0f2b7 --- /dev/null +++ b/Spin_Wheel/src/components/ImageComponents/blueButtonSVG.tsx @@ -0,0 +1,59 @@ +import { + Box + } from "@material-ui/core" + import React from 'react' + import "./bluebutton.css" + + +const BluebuttonSVG = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) + +} +export default BluebuttonSVG; \ No newline at end of file diff --git a/Spin_Wheel/src/components/ImageComponents/bluebutton.css b/Spin_Wheel/src/components/ImageComponents/bluebutton.css new file mode 100644 index 00000000..6fd1d707 --- /dev/null +++ b/Spin_Wheel/src/components/ImageComponents/bluebutton.css @@ -0,0 +1,11 @@ +.a4, +.g4, +.h4{fill:#fff;} +.b4{fill:url(#a4);} +.c4{fill:url(#e4);} +.d4{fill:#0b425e;} +.e4{fill:url(#f4);} +.f4{fill:#269ccf;} +.g4{opacity:0.52;} +.h4{opacity:0.44;} +.i4{filter:url(#b4);} \ No newline at end of file diff --git a/Spin_Wheel/src/components/ImageComponents/greenButtonSVG.tsx b/Spin_Wheel/src/components/ImageComponents/greenButtonSVG.tsx new file mode 100644 index 00000000..cb5f7f72 --- /dev/null +++ b/Spin_Wheel/src/components/ImageComponents/greenButtonSVG.tsx @@ -0,0 +1,60 @@ +import { + Box + } from "@material-ui/core" + import React from 'react' + import "./greenbutton.css" + + +const GreenButtonSVG = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) + +} +export default GreenButtonSVG; \ No newline at end of file diff --git a/Spin_Wheel/src/components/ImageComponents/greenbutton.css b/Spin_Wheel/src/components/ImageComponents/greenbutton.css new file mode 100644 index 00000000..7fd08086 --- /dev/null +++ b/Spin_Wheel/src/components/ImageComponents/greenbutton.css @@ -0,0 +1,11 @@ +.a3, +.g3, +.h3{fill:#fff;} +.b3{fill:url(#a3);} +.c3{fill:url(#e3);} +.d3{fill:#2f5123;} +.e3{fill:url(#f3);} +.f3{fill:#4ac51b;} +.g3{opacity:0.52;} +.h3{opacity:0.44;} +.i3{filter:url(#b3);} \ No newline at end of file diff --git a/Spin_Wheel/src/components/ImageComponents/redButtonSVG.tsx b/Spin_Wheel/src/components/ImageComponents/redButtonSVG.tsx new file mode 100644 index 00000000..f6cec3e9 --- /dev/null +++ b/Spin_Wheel/src/components/ImageComponents/redButtonSVG.tsx @@ -0,0 +1,59 @@ +import { + Box + } from "@material-ui/core" + import React from 'react' + import "./redbutton.css" + + +const RedButtonSVG = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) + +} +export default RedButtonSVG; \ No newline at end of file diff --git a/Spin_Wheel/src/components/ImageComponents/redbutton.css b/Spin_Wheel/src/components/ImageComponents/redbutton.css new file mode 100644 index 00000000..a4679ce5 --- /dev/null +++ b/Spin_Wheel/src/components/ImageComponents/redbutton.css @@ -0,0 +1,10 @@ +.a, +.g, +.h{fill:#fff;} +.b{fill:url(#a);} +.c{fill:url(#e);} +.d{fill:rgba(57,10,10,0.57);} +.e{fill:url(#f);}.f{fill:#d50202;} +.g{opacity:0.52;} +.h{opacity:0.44;} +.i{filter:url(#b);} \ No newline at end of file diff --git a/Spin_Wheel/src/components/ImageComponents/yellowButtonSVG.tsx b/Spin_Wheel/src/components/ImageComponents/yellowButtonSVG.tsx new file mode 100644 index 00000000..7fb9ec6c --- /dev/null +++ b/Spin_Wheel/src/components/ImageComponents/yellowButtonSVG.tsx @@ -0,0 +1,60 @@ +import { + Box + } from "@material-ui/core" + import React from 'react' + import "./yellowbutton.css" + + +const YellowButtonSVG = () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) + +} +export default YellowButtonSVG; \ No newline at end of file diff --git a/Spin_Wheel/src/components/ImageComponents/yellowbutton.css b/Spin_Wheel/src/components/ImageComponents/yellowbutton.css new file mode 100644 index 00000000..cd043193 --- /dev/null +++ b/Spin_Wheel/src/components/ImageComponents/yellowbutton.css @@ -0,0 +1,11 @@ +.a2, +.g2, +.h2{fill:#fff;} +.b2{fill:url(#a2);} +.c2{fill:url(#e2);} +.d2{fill:#4e3e07;} +.e2{fill:url(#f2);} +.f2{fill:#e6b409;} +.g2{opacity:0.52;} +.h2{opacity:0.44;} +.i2{filter:url(#b2);} \ No newline at end of file diff --git a/Spin_Wheel/src/components/WheelComponent.tsx b/Spin_Wheel/src/components/WheelComponent.tsx new file mode 100644 index 00000000..9bf999a6 --- /dev/null +++ b/Spin_Wheel/src/components/WheelComponent.tsx @@ -0,0 +1,228 @@ +import React, { useEffect, useState } from 'react' + +const WheelComponent = ({ + segments, + segColors, + winningSegment, + onFinished, + primaryColor, + contrastColor, + arrowColor, + buttonText = ' ', + isOnlyOnce = false, + size, + upDuration, + downDuration, + fontFamily = 'proxima-nova', + circleCenterX, + circleCenterY, + canvasId, + clicked = true, + setClicked, + setTimeTaken, +} : any) => { + let currentSegment = '' + let isStarted = false + const [isFinished, setFinished] = useState(false) + let timerHandle = 0 + const timerDelay = segments.length + let angleCurrent = 10.6 + let angleDelta = 0 + let canvasContext: any = null + let maxSpeed = Math.PI / segments.length + const upTime = segments.length * upDuration + const downTime = segments.length * downDuration + let spinStart = 0 + let frames = 0 + const centerX = circleCenterX + const centerY = circleCenterY + + useEffect(() => { + wheelInit() + if(clicked === true){spin()} + setTimeout(() => { + window.scrollTo(0, 1) + }, 0) + }, [clicked]) + + const wheelInit = () => { + initCanvas() + wheelDraw() + } + + const initCanvas = () => { + const canvas = document.getElementById(canvasId) as HTMLCanvasElement + if (navigator.userAgent.indexOf('MSIE') !== -1) { + document?.getElementById('wheel')?.appendChild(canvas) + } + canvasContext = canvas.getContext('2d') + } + + const spin = () => { + isStarted = true + if (timerHandle === 0) { + spinStart = new Date().getTime() + // maxSpeed = Math.PI / ((segments.length*2) + Math.random()) + maxSpeed = Math.PI / segments.length + frames = 0 + timerHandle = window.setInterval(onTimerTick, timerDelay) + } + setClicked(false) + } + + const onTimerTick = () => { + frames++ + draw() + const duration = new Date().getTime() - spinStart + let progress = 0 + let finished = false + if (duration < upTime) { + progress = duration / upTime + angleDelta = maxSpeed * Math.sin((progress * Math.PI) / 2) + } else { + if (winningSegment) { + if (currentSegment === winningSegment && frames > segments.length) { + progress = duration / upTime + angleDelta = + maxSpeed * Math.sin((progress * Math.PI) / 2 + Math.PI / 2) + progress = 1 + } else { + progress = duration / downTime + angleDelta = + maxSpeed * Math.sin((progress * Math.PI) / 2 + Math.PI / 2) + } + } else { + progress = duration / downTime + angleDelta = maxSpeed * Math.sin((progress * Math.PI) / 2 + Math.PI / 2) + } + if (progress >= 1) {finished = true} + } + angleCurrent += angleDelta + while (angleCurrent >= Math.PI * 2) {angleCurrent -= Math.PI * 1.5} + if (finished) { + setTimeTaken(duration) + setFinished(true) + onFinished(currentSegment) + clearInterval(timerHandle) + timerHandle = 0 + angleDelta = 0 + } + } + + const wheelDraw = () => { + clear() + drawWheel() + drawNeedle() + } + + const draw = () => { + clear() + drawWheel() + drawNeedle() + } + + const drawSegment = (key:any, lastAngle:any, angle:any) => { + const ctx = canvasContext + const value = segments[key] + ctx.save() + ctx.beginPath() + ctx.moveTo(centerX, centerY) + ctx.arc(centerX, centerY, size, lastAngle, angle, false) + ctx.lineTo(centerX, centerY) + ctx.closePath() + ctx.fillStyle = segColors[key] + ctx.fill() + ctx.stroke() + ctx.save() + ctx.translate(centerX, centerY) + ctx.rotate((lastAngle + angle) / 2) + ctx.fillStyle = contrastColor + ctx.font = 'bold 1em ' + fontFamily + ctx.fillText(value.substr(0, 21), size / 2 + 20, 0) + ctx.restore() + } + + const drawWheel = () => { + const ctx = canvasContext + let lastAngle = angleCurrent + const len = segments.length + const PI2 = Math.PI * 2 + ctx.lineWidth = 0.1 + ctx.strokeStyle = primaryColor + ctx.textBaseline = 'middle' + ctx.textAlign = 'center' + ctx.font = '1em ' + fontFamily + for (let i = 1; i <= len; i++) { + const angle = PI2 * (i / len) + angleCurrent + drawSegment(i - 1, lastAngle, angle) + lastAngle = angle + } + + // Draw a center circle + ctx.beginPath() + ctx.arc(centerX, centerY, 50, 0, PI2, false) + ctx.closePath() + ctx.fillStyle = primaryColor + ctx.lineWidth = 5 + ctx.strokeStyle = 'white' + ctx.fill() + ctx.font = 'bold 1em ' + fontFamily + ctx.fillStyle = contrastColor + ctx.textAlign = 'center' + ctx.fillText(buttonText, centerX, centerY + 3) + ctx.stroke() + + // Draw outer circle + ctx.beginPath() + ctx.arc(centerX, centerY, size, 0, PI2, false) + ctx.closePath() + + ctx.lineWidth = 10 + ctx.strokeStyle = primaryColor + ctx.stroke() + } + + const drawNeedle = () => { + const ctx = canvasContext + ctx.lineWidth = 1 + ctx.strokeStyle = arrowColor + ctx.fillStyle = arrowColor + ctx.beginPath() + ctx.moveTo(centerX + 20, centerY - 40) + ctx.lineTo(centerX - 20, centerY - 40) + ctx.lineTo(centerX, centerY - 70) + ctx.closePath() + ctx.fill() + const change = angleCurrent + Math.PI / 2 + let i = + segments.length - + Math.floor((change / (Math.PI * 2)) * segments.length) - + 1 + if (i < 0){ i = i + segments.length} + ctx.textAlign = 'center' + ctx.textBaseline = 'middle' + ctx.fillStyle = primaryColor + ctx.font = 'bold 1.5em ' + fontFamily + currentSegment = segments[i] + if(isStarted){ + ctx.fillText(currentSegment, centerX + 10, centerY + size + 50) + } + } + const clear = () => { + const ctx = canvasContext + ctx.clearRect(0, 0, 1000, 800) + } + return ( +
+ +
+ ) +} +export default WheelComponent \ No newline at end of file diff --git a/Spin_Wheel/src/components/spinwheel/SpinWheel.tsx b/Spin_Wheel/src/components/spinwheel/SpinWheel.tsx new file mode 100644 index 00000000..1e9fcd72 --- /dev/null +++ b/Spin_Wheel/src/components/spinwheel/SpinWheel.tsx @@ -0,0 +1,59 @@ +import React from 'react' +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// import WheelComponent from 'react-wheel-of-prizes' +import WheelComponent from '../WheelComponent' + +const SpinWheel = ({...props}: any) => { + const {centerX, centerY, canvasId, wheelId, selectedItem, clicked, setClicked, setShowResult, setTimeTaken} = props; + const segments = [ + '0', + '50', + '100', + '250', + '0', + '50', + '100', + '250' + ] + const segColors = [ + '#008000', + '#ffff00', + '#ff0000', + '#0000ff', + '#008000', + '#ffff00', + '#ff0000', + '#0000ff' + ] + const onFinished = (winner : any) => { + setShowResult(true) + } + + + return ( + onFinished(winner)} + primaryColor='white' + contrastColor='black' + arrowColor='white' + buttonText='' + isOnlyOnce={false} + size={200} + upDuration={100} + downDuration={1000} + circleCenterX={centerX} + circleCenterY={centerY} + canvasId= {canvasId} + wheelId={wheelId} + clicked={clicked} + setClicked={setClicked} + setTimeTaken={setTimeTaken} + /> + ) +} + +export default SpinWheel \ No newline at end of file diff --git a/Spin_Wheel/src/components/spinwheel/spinwheel.css b/Spin_Wheel/src/components/spinwheel/spinwheel.css new file mode 100644 index 00000000..e69de29b diff --git a/Spin_Wheel/src/containers/Layout.tsx b/Spin_Wheel/src/containers/Layout.tsx new file mode 100644 index 00000000..d44c2fa6 --- /dev/null +++ b/Spin_Wheel/src/containers/Layout.tsx @@ -0,0 +1,231 @@ + +import React, {useEffect, useState} from 'react'; +import {Col, Container, Row } from "react-bootstrap"; +import Button from "react-bootstrap/Button"; +import BluebuttonSVG from 'src/components/ImageComponents/blueButtonSVG'; +import GreenButtonSVG from "../components/ImageComponents/greenButtonSVG"; +import RedButtonSVG from "../components/ImageComponents/redButtonSVG"; +import YellowButtonSVG from "../components/ImageComponents/yellowButtonSVG"; +import SpinWheel from '../components/spinwheel/SpinWheel'; +import { convertObjtoArray } from '../helper/helper'; +import i18n from "../i18n"; +import { + makeStyles, + AppBar, + IconButton, + Toolbar, + Typography, +} from "@material-ui/core" +import ArrowBackIcon from '@material-ui/icons/ArrowBack' +import './layout.css'; + + +const useStyles = makeStyles((theme) => ({ + toolbardashboard: { + minHeight: 65, + padding: "0 15px", + "& h5": { + color: "rgb(255,255,255)", + textAlign: "center", + fontWeight: "600", + fontSize: 18, + width: "calc(100% - 96px)", + }, + }, +})) + +const Layout = ({...props}) => { + const classes = useStyles() + const [settingsData, setSettingsData] = useState(null) + const spins = props.data.activity?.settings?.spins_per_game + const [timeTaken, setTimeTaken] = useState(0) + const [totalSpins, setTotalSpins] = useState(spins) + const [spinIndex, setSpinIndex] = useState(0) + const [selectedItem1, setSelectedItem1] = useState(null) + const [selectedItem2, setSelectedItem2] = useState(null) + const [isGameOver, setIsGameOver] = useState(false) + const [clicked, setClicked] = useState(false) + const [total,setTotal] = useState(props.data.activity?.settings?.balance) + const [routes, setRoutes] = useState([]) + const time = new Date().getTime() + const [buttonIndex, setButtonIndex] = useState(0) + const [complete, setComplete] = useState(false) + const highRiskConditionsLoseWheel = convertObjtoArray(settingsData?.high_risk[0]?.loose, settingsData?.high_risk[0]?.zero?.probability) + const highRiskConditionsWinWheel = convertObjtoArray(settingsData?.high_risk[0]?.win, settingsData?.high_risk[0]?.zero?.probability) + const lowRiskConditionsLoseWheel = convertObjtoArray(settingsData?.low_risk[0]?.loose, settingsData?.low_risk[0]?.zero?.probability) + const lowRiskConditionsWinWheel = convertObjtoArray(settingsData?.low_risk[0]?.win, settingsData?.low_risk[0]?.zero?.probability) + + + const [showResult, setShowResult] = useState(false) + + + function getRandomWithProbability(array : any) { + const filled = array.flatMap(([value, prob] : any) => { + const length = prob.toFixed(2) * 100; + return Array.from({ length }).fill(value) + }); + + const random = Math.floor(Math.random() * filled.length); + return filled[random] + } + + useEffect(() => { + const configuration = props.data.configuration; + const settings = props.data.activity?.settings ?? (props.data.settings ?? null); + i18n.changeLanguage(!!configuration ? configuration.language : "en-US"); + setSettingsData(settings) + }, []) + + + const selectItem =(values1 : any, values2 : any) =>{ + if(totalSpins>0) { + const selectedItemTemp1 = getRandomWithProbability(values1) + setSelectedItem1(selectedItemTemp1) + const selectedItemTemp2 = getRandomWithProbability(values2) + setSelectedItem2(selectedItemTemp2) + setTotalSpins(totalSpins-1) + setSpinIndex(spinIndex+1) + setShowResult(false) + setClicked(true) + + } + } + useEffect(() => { + if(complete) { + parent.postMessage(JSON.stringify({ completed: true }), "*") + } + }, [complete]) + + useEffect(() => { + if(isGameOver) { + setTimeout(()=>{ + parent.postMessage(routes.length > 0 ? JSON.stringify({ + timestamp: new Date().getTime(), + duration: new Date().getTime() - time, + temporal_slices: JSON.parse(JSON.stringify(routes)), + static_data: {}, + }) : null, "*") + }, 5000) + + } + }, [isGameOver]) + + useEffect(()=>{ + if(showResult){ + setTotal(total+parseInt(selectedItem1, 10)-parseInt(selectedItem2, 10)) + const route = { + "duration": timeTaken/1000+"s", + "item": spinIndex, + "level": buttonIndex, + "type": total+parseInt(selectedItem1, 10)-parseInt(selectedItem2, 10), + "value": null + } + setRoutes([...routes,route]) + } + + },[showResult]) + + const displayTotal = () =>{ + if(Math.sign(total) === -1) { + return "-$"+Math.abs(total) + } + else{ + return "$"+ Math.abs(total) + } + } + + return ( +
+ + + setComplete(true)} color="default" aria-label="Menu"> + + + {i18n.t("GAME")} + + + + + +

{i18n.t("TOTAL_BALANCE")} : {displayTotal()}

+ +
+ + + + {spinIndex > 0 ? (

{i18n.t("YOU_WON")} : {showResult && selectedItem2 !=null ? `${selectedItem1}` : ""}

) :

} + + + + + {spinIndex > 0 ?

{i18n.t("YOU_LOSE")} : {showResult && selectedItem2 !=null ? `${selectedItem2}` : ""}

:

} + + + + + + + + + + + + +

{i18n.t("TOTAL_SPINS")} : {totalSpins}

+ +
+ {isGameOver && + +

{i18n.t("GAME_OVER")}

+ +
} +
+
+ ); + +} + +export default Layout diff --git a/Spin_Wheel/src/containers/layout.css b/Spin_Wheel/src/containers/layout.css new file mode 100644 index 00000000..d55115f1 --- /dev/null +++ b/Spin_Wheel/src/containers/layout.css @@ -0,0 +1,85 @@ + +.layout{ + width : 100%; +} +.wheel{ + width: 100%; + max-width: 500px; + margin:0 auto; +} +.wheel canvas{ + width: 450px !important; + height: 450px !important; +} +h1,h3 { + text-align: center; +} +p { + text-align: center; + font-size: 17px; + font-weight: 650; +} + .button-group { + text-align: center; + margin-top: -28px; +} +.button-class { + background: white !important; + border: none !important; + width: 65px; + height: 60px; + pointer-events: none; +} +.button-class svg{ + width: 50px; + pointer-events: stroke; +} + +.btn:focus { + box-shadow: none !important; +} +.btn:hover { + box-shadow: none !important; +} +h3.wheel-score{ + font-size: 1.5rem; + margin-top: 10px; +} +.responsive-canvas{ + width: 500px; + height: 500px; + object-fit: contain ; +} +.error-class{ + color: red; + font-size: 20px; +} + +h1.wheel-score{ + font-size: 2rem; + margin-top: 10px; +} +@media only screen and (max-width: 500px) { + .wheel canvas{ + width: 350px !important; + height: 350px !important; + } + .button-class{ + width: 70px; + } + .button-class svg{ + width: 40px; + } + h1.wheel-score, h3.wheel-score{ + font-size: 1.5rem; + + } +} +.MuiSvgIcon-root { + color: white; +} + + + + + \ No newline at end of file diff --git a/Spin_Wheel/src/functions.ts b/Spin_Wheel/src/functions.ts new file mode 100644 index 00000000..839e8265 --- /dev/null +++ b/Spin_Wheel/src/functions.ts @@ -0,0 +1,14 @@ +// Get random numbers +export function getRandomNumbers(dcount: number, min: number, max: number) { + const randomArray: Array = []; + for (let i = min; i <= dcount; i++) { + randomArray[i - 1] = randomNumber(max, 0, randomArray) + } + return randomArray; +} +// recursive random number generation without any duplicate +function randomNumber(max: number, min: number, randomArray: Array): number { + const num = Math.floor(Math.random() * (max - min + 1)) + min; + return randomArray.indexOf(num) >= 0 || num === 0 ? randomNumber(max, min, randomArray) : num; +} + diff --git a/Spin_Wheel/src/helper/helper.ts b/Spin_Wheel/src/helper/helper.ts new file mode 100644 index 00000000..9146a543 --- /dev/null +++ b/Spin_Wheel/src/helper/helper.ts @@ -0,0 +1,54 @@ +export function getParts(n: number) { + const parts = []; + + for (let i = 100; i < n; i++) { + parts.push(i) + } + return parts; +} + +export function getRandom(array: any) { + return array[Math.floor(Math.random() * array.length)]; +} + +export function getRandomN() { + return Math.floor(Math.random() * 1000) + 100; + + +} + +export function convertObjtoArray(data: any, zeroProbability : any) { + let dataArray = ["0","50", "100", "250"] + const subArray = []; + const zeroArray = []; + const resultArray = []; + if((data !== null && data !== undefined) && data?.probability !== 0) { + subArray?.push(data?.sum.toString()) + subArray?.push(data?.probability/100) + resultArray.push(subArray) + } + else if(data?.probability === 0){ + if(zeroProbability === 0){ + dataArray = dataArray.filter((element : any) => element !== "0") + } + dataArray.forEach((dataElement : any) =>{ + const tempArray: any = []; + if(dataElement !== data?.sum.toString()){ + tempArray?.push(dataElement) + tempArray?.push(50/100) + resultArray.push(tempArray) + } + }) + } + + if((zeroProbability !== null && zeroProbability !== undefined) && zeroProbability !== 0) { + zeroArray?.push("0") + zeroArray?.push(zeroProbability/100) + resultArray?.push(zeroArray) + } + + return resultArray; +} + + + diff --git a/Spin_Wheel/src/i18n.js b/Spin_Wheel/src/i18n.js new file mode 100644 index 00000000..11757b99 --- /dev/null +++ b/Spin_Wheel/src/i18n.js @@ -0,0 +1,132 @@ +import i18n from "i18next"; +import { initReactI18next } from "react-i18next"; + +const resources = { + "da-DK":{ + translation: { + CONGRATS: "Tillykke", + GAME: "Lotteri", + GAME_OVER: "Spillet Overstået", + TIME_OUT: "Tiden er gået", + TOTAL_BALANCE: "Samlet saldo", + TOTAL_SPINS: "Samlede spins", + YOU_LOSE: "Du taber", + YOU_WON: "Du vandt", + } + }, + "de-DE":{ + translation: { + CONGRATS: "Herzlichen Glückwunsch", + GAME: "Lotterie", + GAME_OVER: "Spiel ist aus", + TIME_OUT: "Auszeit", + TOTAL_BALANCE: "Gesamtsaldo", + TOTAL_SPINS: "Spins insgesamt", + YOU_LOSE: "Du verlierst", + YOU_WON: "Du hast gewonnen", + } + }, + "en-US": { + translation: { + CONGRATS: "Congrats", + GAME: "Lottery", + GAME_OVER: "Game Over", + TIME_OUT: "Time Out", + TOTAL_BALANCE: "Total Balance", + TOTAL_SPINS: "Total Spins", + YOU_LOSE: "You Lose", + YOU_WON: "You Won", + + }, + }, + "es-ES": { + translation: { + CONGRATS: "Felicidades", + GAME: "La Lotería", + GAME_OVER: "Juego Terminado", + TIME_OUT: "Se acabó el tiempo", + TOTAL_BALANCE: "Saldo total", + TOTAL_SPINS: "Giros totales", + YOU_LOSE: "Tú pierdes", + YOU_WON: "Ganaste", + + }, + }, + "fr-FR":{ + translation: { + CONGRATS: "Félicitations", + GAME: "Loterie", + GAME_OVER: "Jeu terminé", + TIME_OUT: "Temps libre", + TOTAL_BALANCE: "Solde total", + TOTAL_SPINS: "Total des tours", + YOU_LOSE: "Tu as perdu", + YOU_WON: "Tu as gagné", + } + }, + "hi-IN": { + translation: { + CONGRATS: "बधाई हो ", + GAME: "लॉटरी", + GAME_OVER: "खेल खत्म", + TIME_OUT: "समय समाप्त", + TOTAL_BALANCE: "कुल शेष", + TOTAL_SPINS: "कुल घुमाव", + YOU_LOSE: "आप खोया", + YOU_WON: "आप जीता", + + }, + }, + "it-IT":{ + translation: { + CONGRATS: "Congratulazioni", + GAME: "Lotteria", + GAME_OVER: "Fin de partie", + TIME_OUT: "Tempo scaduto", + TOTAL_BALANCE: "Saldo totale", + TOTAL_SPINS: "Giri totali", + YOU_LOSE: "Hai perso", + YOU_WON: "Hai vinto", + + }, + }, + "ko-KR":{ + translation: { + CONGRATS: "\ucd95\ud558\ud574\uc694", + GAME: "\uc6b4", + GAME_OVER: "\uac8c\uc784\u0020\ub05d", + TIME_OUT: "\uc2dc\uac04\u0020\ucd08\uacfc", + TOTAL_BALANCE: "\uc804\uccb4\u0020\uade0\ud615", + TOTAL_SPINS: "\ucd1d\u0020\uc2a4\ud540", + YOU_LOSE: "\ub2f9\uc2e0\uc740\u0020\ud328\ubc30", + YOU_WON: "\ub2f9\uc2e0\uc774\u0020\uc774\uacbc\ub2e4", + + }, + }, + "zh-CN":{ + translation: { + CONGRATS: "\u606d\u559c", + GAME: "\u5f69\u7968", + GAME_OVER: "\u6e38\u620f\u7ed3\u675f", + TIME_OUT: "\u6682\u505c", + TOTAL_BALANCE: "\u603b\u4f59\u989d", + TOTAL_SPINS: "\u603b\u65cb\u8f6c", + YOU_LOSE: "\u4f60\u8f93\u4e86", + YOU_WON: "\u4f60\u8d62\u4e86", + + }, + } + +}; + +i18n + .use(initReactI18next) // passes i18n down to react-i18next + .init({ + interpolation: { + escapeValue: false, + }, + keySeparator: false, + resources, + }); + +export default i18n; diff --git a/Spin_Wheel/src/index.css b/Spin_Wheel/src/index.css new file mode 100644 index 00000000..d508d7b1 --- /dev/null +++ b/Spin_Wheel/src/index.css @@ -0,0 +1,17 @@ +body { + margin: 0; + padding: 0; + font-family: sans-serif; + background: rgb(236, 238, 240); +} + +.countdown-timer__text{ + text-align: center; + width: 100%; + color: #fff; + font-size: 14px; + min-height: 25px; +} +.modal-header{border-bottom: 0;} +.modal-footer{border-top: 0;} +.modal-body{padding: 0 1rem; font-size: 15px;} diff --git a/Spin_Wheel/src/index.tsx b/Spin_Wheel/src/index.tsx new file mode 100644 index 00000000..481e1859 --- /dev/null +++ b/Spin_Wheel/src/index.tsx @@ -0,0 +1,76 @@ +/** + * @file index.tsx + * @brief Intial component for the react app + * @date Feb , 2020 + * @author ZCO Engineer + * @copyright (c) 2020, ZCO + */ +import "bootstrap/dist/css/bootstrap.min.css" +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; +import { AppContainer } from "react-hot-loader"; +import Layout from './containers/Layout'; + +const settingsDataInitial = { + + "activity" : { + "settings" : { + "high_risk": [ + { + "loose": { + "probability": 50, + "sum": 250, + + }, + "win": { + "probability": 50, + "sum": 100, + + }, + "zero": { + "probability": 50, + "sum": 0, + } + } + ], + "low_risk": [ + { + "loose": { + "probability": 50, + "sum": 50 + + }, + "win": { + "probability": 50, + "sum": 50, + }, + "zero": { + "probability": 50, + "sum": 0, + } + } + ], + "spins_per_game": 20, + "balance" : 500 + }}, + "configuration" : { + "language" : "es-ES" + } +} + +const eventMethod = !!window.addEventListener ? "addEventListener" : "attachEvent" +const eventer = window[eventMethod] +const messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message" +eventer( + messageEvent, (e : any) => { + ReactDOM.render( + + + , + document.getElementById("root") + ); + }, + false +) + diff --git a/Spin_Wheel/src/react-app-env.d.ts b/Spin_Wheel/src/react-app-env.d.ts new file mode 100644 index 00000000..6431bc5f --- /dev/null +++ b/Spin_Wheel/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/Spin_Wheel/tsconfig.json b/Spin_Wheel/tsconfig.json new file mode 100644 index 00000000..c0238d0d --- /dev/null +++ b/Spin_Wheel/tsconfig.json @@ -0,0 +1,43 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "strictNullChecks": true, + "suppressImplicitAnyIndexErrors": true, + "noUnusedLocals": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "esModuleInterop": true, + "strict": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts" + ], + "include": [ + "src" + ] +} diff --git a/Spin_Wheel/tsconfig.prod.json b/Spin_Wheel/tsconfig.prod.json new file mode 100644 index 00000000..c0238d0d --- /dev/null +++ b/Spin_Wheel/tsconfig.prod.json @@ -0,0 +1,43 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "outDir": "build/dist", + "module": "esnext", + "target": "es5", + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "jsx": "react", + "moduleResolution": "node", + "rootDir": "src", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": true, + "strictNullChecks": true, + "suppressImplicitAnyIndexErrors": true, + "noUnusedLocals": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "esModuleInterop": true, + "strict": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true + }, + "exclude": [ + "node_modules", + "build", + "scripts", + "acceptance-tests", + "webpack", + "jest", + "src/setupTests.ts" + ], + "include": [ + "src" + ] +} diff --git a/Spin_Wheel/tslint.json b/Spin_Wheel/tslint.json new file mode 100644 index 00000000..82ed32bd --- /dev/null +++ b/Spin_Wheel/tslint.json @@ -0,0 +1,19 @@ +{ + "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], + "linterOptions": { + "exclude": [ + "config/**/*.js", + "node_modules/**/*.ts" + ] + }, + "rules": { + "array-type": [true, "generic"], + "interface-name": [true, "never-prefix"], + "member-access": false, + "member-ordering": false, + "object-literal-sort-keys":false, + "ordered-imports": false, + "no-console": false, + "jsx-no-lambda": false + } +} diff --git a/Spin_Wheel/webpack.config.js b/Spin_Wheel/webpack.config.js new file mode 100644 index 00000000..1b02e91d --- /dev/null +++ b/Spin_Wheel/webpack.config.js @@ -0,0 +1,25 @@ +const path = require("path") +const UglifyJsPlugin = require("uglifyjs-webpack-plugin") +const glob = require("glob") + +module.exports = { + entry: { + "bundle.js": glob.sync("build/static/?(js|css)/main.*.?(js|css)").map(f => path.resolve(__dirname, f)), + }, + module: { + rules: [ + { + test: /\.css$/, + use: ["style-loader", "css-loader"], + }, + { + loader: "file-loader", + test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, + }, + ], + }, + output: { + filename: "build/static/js/bundle.min.js", + }, + plugins: [new UglifyJsPlugin()], +} \ No newline at end of file