From 9dbfae44746b82441d1c1ed7b21fbeb5e5770f2a Mon Sep 17 00:00:00 2001 From: akuleshov7 Date: Mon, 9 Sep 2024 12:51:41 +0300 Subject: [PATCH] Adding randomizer machine --- .../backend/controller/RandomController.kt | 17 +++++ .../backend/repository/UserRepository.kt | 6 +- .../posidata/backend/service/UserService.kt | 8 +- frontend/build.gradle.kts | 1 + frontend/src/jsMain/kotlin/ru/posidata/App.kt | 6 ++ .../ru/posidata/views/main/LuckyDraw.kt | 74 +++++++++++++++++++ .../kotlin/ru/posidata/views/main/MainView.kt | 1 - .../kotlin/ru/posidata/views/main/Welcome.kt | 2 +- .../utils/externals/slotmachine/LuckyDraw.kt | 37 ++++++++++ .../externals/telegram/ReactTelegramAuth.kt | 1 - .../externals/telegram/TLoginButtonProps.kt | 1 - kotlin-js-store/yarn.lock | 5 ++ 12 files changed, 151 insertions(+), 8 deletions(-) create mode 100644 backend/src/main/kotlin/ru/posidata/backend/controller/RandomController.kt create mode 100644 frontend/src/jsMain/kotlin/ru/posidata/views/main/LuckyDraw.kt create mode 100644 frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/slotmachine/LuckyDraw.kt diff --git a/backend/src/main/kotlin/ru/posidata/backend/controller/RandomController.kt b/backend/src/main/kotlin/ru/posidata/backend/controller/RandomController.kt new file mode 100644 index 0000000..b927623 --- /dev/null +++ b/backend/src/main/kotlin/ru/posidata/backend/controller/RandomController.kt @@ -0,0 +1,17 @@ +package ru.posidata.backend.controller + +import org.springframework.http.ResponseEntity +import org.springframework.web.bind.annotation.* +import ru.posidata.backend.service.UserService + +@RestController +@RequestMapping("api") +class RandomController( + private val userService: UserService +) { + @GetMapping("/random") + fun random(): ResponseEntity { + val randomUser = userService.getRandomUser() + return ResponseEntity.ok(randomUser.toDTO()) + } +} diff --git a/backend/src/main/kotlin/ru/posidata/backend/repository/UserRepository.kt b/backend/src/main/kotlin/ru/posidata/backend/repository/UserRepository.kt index 815be7e..0f7dbaa 100644 --- a/backend/src/main/kotlin/ru/posidata/backend/repository/UserRepository.kt +++ b/backend/src/main/kotlin/ru/posidata/backend/repository/UserRepository.kt @@ -1,10 +1,10 @@ package ru.posidata.backend.repository -import org.springframework.data.repository.CrudRepository +import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository import ru.posidata.backend.entity.OurUserEntityFromDb @Repository -interface UserRepository : CrudRepository { +interface UserRepository : JpaRepository { fun findByUsername(username: String): OurUserEntityFromDb? -} \ No newline at end of file +} diff --git a/backend/src/main/kotlin/ru/posidata/backend/service/UserService.kt b/backend/src/main/kotlin/ru/posidata/backend/service/UserService.kt index 6b68c72..1ec8196 100644 --- a/backend/src/main/kotlin/ru/posidata/backend/service/UserService.kt +++ b/backend/src/main/kotlin/ru/posidata/backend/service/UserService.kt @@ -25,7 +25,7 @@ class UserService(private val userRepository: UserRepository) { val value = userRepository.findByUsername(username) if (value != null) { value.updateResultIn(value.currentGameNumber(), isNextRound) - return userRepository.save(value) + return userRepository.saveAndFlush(value) } else { println("Not able to find $username in DB") return null @@ -35,4 +35,10 @@ class UserService(private val userRepository: UserRepository) { return null } } + + fun getRandomUser(): OurUserEntityFromDb { + val userCount = userRepository.count().toInt() + val users = userRepository.findAll().random() + return users + } } diff --git a/frontend/build.gradle.kts b/frontend/build.gradle.kts index d92e523..e9292f1 100644 --- a/frontend/build.gradle.kts +++ b/frontend/build.gradle.kts @@ -63,6 +63,7 @@ kotlin { implementation(npm("react-dom", "^18.0.0")) implementation(npm("react-modal", "^3.0.0")) implementation(npm("@popperjs/core", "2.11.8")) + implementation(npm("react-slot-counter", "3.0.1")) // ====== font awesome ====== implementation(npm("@fortawesome/fontawesome-svg-core", "6.5.2")) implementation(npm("@fortawesome/free-solid-svg-icons", "6.5.2")) diff --git a/frontend/src/jsMain/kotlin/ru/posidata/App.kt b/frontend/src/jsMain/kotlin/ru/posidata/App.kt index c9a3d3d..ba979c8 100644 --- a/frontend/src/jsMain/kotlin/ru/posidata/App.kt +++ b/frontend/src/jsMain/kotlin/ru/posidata/App.kt @@ -16,6 +16,7 @@ import kotlinx.browser.window import react.router.dom.RouterProvider import react.router.dom.createBrowserRouter import ru.posidata.views.components.errorBoundary +import ru.posidata.views.main.luckyDrawCard import ru.posidata.views.main.mainView @@ -32,6 +33,11 @@ val App: FC = FC { path = "/" element = mainView.create() errorElement = errorBoundary.create() + }, + jso { + path = "/luckydraw" + element = luckyDrawCard.create() + errorElement = errorBoundary.create() } ) ) diff --git a/frontend/src/jsMain/kotlin/ru/posidata/views/main/LuckyDraw.kt b/frontend/src/jsMain/kotlin/ru/posidata/views/main/LuckyDraw.kt new file mode 100644 index 0000000..4f05fde --- /dev/null +++ b/frontend/src/jsMain/kotlin/ru/posidata/views/main/LuckyDraw.kt @@ -0,0 +1,74 @@ +package ru.posidata.views.main + +import js.objects.jso +import kotlinx.browser.window +import react.* +import react.dom.html.ReactHTML +import react.dom.html.ReactHTML.button +import react.dom.html.ReactHTML.div +import react.dom.html.ReactHTML.h1 +import ru.posidata.common.UserForSerializationDTO +import ru.posidata.views.utils.externals.particles.Particles +import ru.posidata.views.utils.externals.slotmachine.Slot +import ru.posidata.views.utils.internals.* +import web.cssom.* + +val luckyDrawCard = FC { _ -> + val (luckyUserName, setLuckyUserName) = useState(null) + + val getUser = useDeferredRequest { + val response = get( + url = "${window.location.origin}/api/random", + params = jso {}, + headers = jsonHeaders, + loadingHandler = ::noopLoadingHandler, + responseHandler = ::noopResponseHandler, + ) + setLuckyUserName(response.decodeFromJsonString().username) + } + Particles::class.react { + id = "tsparticles" + url = "${window.location.origin}/particles.json" + } + + ReactHTML.div { + className = ClassName("full-width-container") + id = "back" + ReactHTML.div { + className = ClassName("row justify-content-center align-items-center text-center") + style = jso { + minHeight = "100vh".unsafeCast() + } + + h1 { + className = ClassName(" justify-content-center align-items-center text-center") + style = jso { + fontFamily = "'Inter', sans-serif".unsafeCast() + fontSize = 200.unsafeCast() + color = "white".unsafeCast() + } + if (luckyUserName != null) { + Slot { + startValue = "posidata" + value = luckyUserName + speed = 3.0 + duration = 7.0 + } + } + } + + div { + className = ClassName("col-5 zIndex1000") + button { + +"Погнали, разыграем кусок ДСП!" + className = ClassName("btn btn-outline-info zIndex1000") + onClick = { + getUser() + } + } + } + } + } +} + +external interface LuckyDrawProps : Props diff --git a/frontend/src/jsMain/kotlin/ru/posidata/views/main/MainView.kt b/frontend/src/jsMain/kotlin/ru/posidata/views/main/MainView.kt index d5b018b..2dbcfdb 100644 --- a/frontend/src/jsMain/kotlin/ru/posidata/views/main/MainView.kt +++ b/frontend/src/jsMain/kotlin/ru/posidata/views/main/MainView.kt @@ -15,7 +15,6 @@ import ru.posidata.common.UserForSerializationDTO import web.cssom.* val mainView = FC { - Particles::class.react { id = "tsparticles" url = "${kotlinx.browser.window.location.origin}/particles.json" diff --git a/frontend/src/jsMain/kotlin/ru/posidata/views/main/Welcome.kt b/frontend/src/jsMain/kotlin/ru/posidata/views/main/Welcome.kt index a67224a..467b14c 100644 --- a/frontend/src/jsMain/kotlin/ru/posidata/views/main/Welcome.kt +++ b/frontend/src/jsMain/kotlin/ru/posidata/views/main/Welcome.kt @@ -4,7 +4,6 @@ import js.objects.jso import kotlinx.browser.window import react.* import react.dom.html.ReactHTML.a -import react.dom.html.ReactHTML.button import react.dom.html.ReactHTML.div import react.dom.html.ReactHTML.h1 import react.dom.html.ReactHTML.h6 @@ -138,6 +137,7 @@ val welcomeCard = FC { props -> +". ${if (props.tgUser == null) "Чтобы участвовать в розыгрыше и рейтинге - залогинься:" else ""}" } + if (props.tgUser == null) { TLoginButton { botName = "PosiDataBot" diff --git a/frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/slotmachine/LuckyDraw.kt b/frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/slotmachine/LuckyDraw.kt new file mode 100644 index 0000000..0c35c9a --- /dev/null +++ b/frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/slotmachine/LuckyDraw.kt @@ -0,0 +1,37 @@ +@file:JsModule("react-slot-counter") +@file:JsNonModule + +package ru.posidata.views.utils.externals.slotmachine + +import react.* + +@JsName("default") // Ensures you're importing the default export +external val Slot: FC // Declare the component + +// External Props definition that maps to your TypeScript interface +external interface SlotProps : Props { + var index: Int + var isNew: Boolean? + var charClassName: String? + var numbersRef: RefObject + var active: Boolean + var isChanged: Boolean + var effectiveDuration: Double + var delay: Double + var value: dynamic + var startValue: dynamic? + var disableStartValue: Boolean? + var dummyList: Array + var hasSequentialDummyList: Boolean? + var hasInfiniteList: Boolean? + var valueClassName: String? + var numberSlotClassName: String? + var numberClassName: String? + var reverse: Boolean? + var sequentialAnimationMode: Boolean + var useMonospaceWidth: Boolean + var maxNumberWidth: Int? + var onFontHeightChange: ((Int) -> Unit)? + var speed: Double + var duration: Double +} diff --git a/frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/telegram/ReactTelegramAuth.kt b/frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/telegram/ReactTelegramAuth.kt index de0f7c1..5c1b181 100644 --- a/frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/telegram/ReactTelegramAuth.kt +++ b/frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/telegram/ReactTelegramAuth.kt @@ -1,5 +1,4 @@ @file:JsModule("react-telegram-auth") -@file:JsNonModule package ru.posidata.views.utils.externals.telegram diff --git a/frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/telegram/TLoginButtonProps.kt b/frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/telegram/TLoginButtonProps.kt index 4f421a8..07f512a 100644 --- a/frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/telegram/TLoginButtonProps.kt +++ b/frontend/src/jsMain/kotlin/ru/posidata/views/utils/externals/telegram/TLoginButtonProps.kt @@ -1,5 +1,4 @@ @file:JsModule("react-telegram-auth") -@file:JsNonModule package ru.posidata.views.utils.externals.telegram diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock index cd36f26..7736320 100644 --- a/kotlin-js-store/yarn.lock +++ b/kotlin-js-store/yarn.lock @@ -2877,6 +2877,11 @@ react-router@6.23.1, react-router@^6.23.1: dependencies: "@remix-run/router" "1.16.1" +react-slot-counter@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/react-slot-counter/-/react-slot-counter-3.0.1.tgz#7b2becdbea1f8c83eb754371d1bd65b287ef3648" + integrity sha512-+NwzRrZ+zWErP/8nz+0Y/imtOcMDr1A2Gv8CfzXNRW/zXaxNPMpZQdWeJAX/HiSqaeGc+jxKqKscoMN101NYDg== + react-telegram-auth@1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/react-telegram-auth/-/react-telegram-auth-1.0.4.tgz#76443a3930497de7ab03a24d791e03aeeac47a5c"