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