diff --git a/app/(main)/lottery/page.tsx b/app/(main)/lottery/page.tsx index 04010d0..7f495fd 100644 --- a/app/(main)/lottery/page.tsx +++ b/app/(main)/lottery/page.tsx @@ -9,17 +9,17 @@ import LotteryCounter from '@/components/lottery/RollingCounter/RollingCounter'; import LotteryWinnersSection from '@/components/lottery/LotteryWinnersSection'; import LotteryRulesSection from '@/components/lottery/rules/LotteryRulesSection'; -import RollingCounter from '@/components/lottery/RollingCounter/RollingCounter'; +import LotteryCountDown from '@/components/lottery/countDown/LotteryCountDown'; +import { useState } from 'react'; +import LotteryCountDownAllert from '@/components/lottery/countDown/countDownAllert/LotteryCountDownAllert'; const LotteryPage = () => { const { lotteryData } = useLotteryAuth(); - const { status, currentNumber } = useLottery(LOTTERY_CONFIG.START_DATE, LOTTERY_CONFIG.END_DATE); + const [status, setStatus] = useState<'not-started' | 'started' | 'ended'>('not-started'); return (
- - {lotteryData && ( { /> )} + {lotteryData ? ( + status === 'not-started' ? ( +
+ +
+ ) : ( +
+ +
+ ) + ) : null} + {(status === 'ended' || status === 'started') && } diff --git a/app/globals.css b/app/globals.css index 4a60b39..8ca7435 100644 --- a/app/globals.css +++ b/app/globals.css @@ -232,6 +232,10 @@ big { @apply font-medium -tracking-[1%] text-[24px] leading-[32px]; } +.font-heading-6-regular { + @apply -tracking-[1%] text-[20px] leading-[28px]; +} + .font-base-regular { @apply font-normal -tracking-[1%] text-[16px] leading-[24px]; } @@ -263,6 +267,31 @@ big { background-repeat: no-repeat; } +.rolling-number { + font-size: 80px; + letter-spacing: -1%; + padding: 0px 16px; + + @apply text-lightOnPrimary; +} + +.index-module_slot__DpPgW { + overflow: visible !important; + /* height: auto !important; */ +} + +/* .index-module_num__j6XH3 { + height: fit-content !important; +} */ + +.slot-seperator { + content: url('/dash.svg'); + background-position: center; + background-size: cover; + background-repeat: no-repeat; + margin: 0 20px; +} + .confetti-piece { position: absolute; /* border-radius: 50%; */ diff --git a/components/lottery/LotteryHeader.tsx b/components/lottery/LotteryHeader.tsx index ec12705..5b1807d 100644 --- a/components/lottery/LotteryHeader.tsx +++ b/components/lottery/LotteryHeader.tsx @@ -1,4 +1,4 @@ -import Image from "next/image"; +import Image from 'next/image'; interface LotteryHeaderProps { title: string; @@ -7,12 +7,7 @@ interface LotteryHeaderProps { smsCode: string; } -const LotteryHeader = ({ - title, - description, - image, - smsCode, -}: LotteryHeaderProps) => { +const LotteryHeader = ({ title, description, image, smsCode }: LotteryHeaderProps) => { return (
@@ -20,11 +15,25 @@ const LotteryHeader = ({

{title}

-

- {description} -

-
- SMS-kod: {smsCode} +

{description}

+
+ + + + + + SMS-kod: {smsCode} +
{image && ( diff --git a/components/lottery/LotteryWinnersSection.tsx b/components/lottery/LotteryWinnersSection.tsx index e174194..79133c6 100644 --- a/components/lottery/LotteryWinnersSection.tsx +++ b/components/lottery/LotteryWinnersSection.tsx @@ -1,30 +1,61 @@ 'use client'; import LotteryWinnersList from './winners/LotteryWinnersList'; -import SpinWheel from './spinWheel/SpinWheel'; import { useState, useEffect } from 'react'; import { useLotteryAuth } from '@/store/useLotteryAuth'; import { LotteryWinnerData } from '@/typings/lottery/lottery.types'; -import RollingCounter from './RollingCounter/RollingCounter'; +import LotterySlotCounter from './slotCounter/LotterySlotCounter'; +import Confetti from 'react-confetti/dist/types/Confetti'; +import ReactConfetti from 'react-confetti'; +import { useWindowSize } from 'react-use'; const LotteryWinnersSection = () => { const [winners, setWinners] = useState([]); + const [currentNumber, setCurrentNumber] = useState('00-00-00-00-00'); + const [wsStatus, setWsStatus] = useState<'connecting' | 'connected' | 'error'>('connecting'); + + const [isConfettiActive, setIsConfettiActive] = useState(false); + + const { width, height } = useWindowSize(); const { lotteryData } = useLotteryAuth(); useEffect(() => { if (lotteryData?.data.winners) { setWinners(lotteryData.data.winners); + setCurrentNumber(lotteryData.data.winners.at(-1)?.ticket || '00-00-00-00-00'); } const wsUrl = 'https://sms.turkmentv.gov.tm/api/ws/lottery'; const ws = new WebSocket(wsUrl); + ws.onopen = () => { + console.log('WebSocket connected'); + setWsStatus('connected'); + }; + + ws.onclose = () => { + console.log('WebSocket disconnected'); + setWsStatus('error'); + }; + + ws.onerror = (error) => { + console.error('WebSocket error:', error); + setWsStatus('error'); + }; + ws.onmessage = (event) => { console.log('WebSocket message received:', event.data); const newWinner = JSON.parse(event.data); console.log('Parsed WebSocket data:', newWinner); setWinners((prev) => [...prev, newWinner]); + + setTimeout(() => { + setIsConfettiActive(true); + setTimeout(() => { + setIsConfettiActive(false); + }, 5000); + }, 10000); }; return () => { @@ -34,16 +65,41 @@ const LotteryWinnersSection = () => { return (
+ {wsStatus === 'error' && ( +
+ Connection error. Please refresh the page. +
+ )} + + {isConfettiActive && ( +
+ +
+ )} +
-
-
+
+
+ +
+
{/* Winners */} - - {/* Sping the wheel */} -
- {/* */} -
diff --git a/components/lottery/RollingCounter/RollingCounter.tsx b/components/lottery/RollingCounter/RollingCounter.tsx index 7bbf77d..39d19ed 100644 --- a/components/lottery/RollingCounter/RollingCounter.tsx +++ b/components/lottery/RollingCounter/RollingCounter.tsx @@ -171,7 +171,7 @@ const RollingCounter: React.FC = ({ numberString }) => { } return ( -
+
{currentNumbers.map((num, index) => ( { const { lotteryData } = useLotteryAuth(); @@ -17,7 +17,7 @@ const LotteryRulesSection = () => {
    {Array(5) - .fill(" ") + .fill(' ') .map((item, i) => (
  • Ilkinji we dogry jogap beren sanawda ilkinji ýeri eýelýär @@ -27,17 +27,13 @@ const LotteryRulesSection = () => {
-

- Üns beriň: -

+

Üns beriň:

    - {Array(1) - .fill(" ") - .map((item, i) => ( -
  • - SMS = 1 manat -
  • - ))} + {lotteryData?.user_lottery_numbers.map((item, i) => ( +
  • + {item} +
  • + ))}
diff --git a/components/lottery/slotCounter/LotterySlotCounter.tsx b/components/lottery/slotCounter/LotterySlotCounter.tsx new file mode 100644 index 0000000..2ace2b9 --- /dev/null +++ b/components/lottery/slotCounter/LotterySlotCounter.tsx @@ -0,0 +1,64 @@ +'use client'; +import Image from 'next/image'; +import React, { useEffect, useState } from 'react'; +import SlotCounter from 'react-slot-counter'; + +const LotterySlotCounter = ({ numberString }: { numberString: string }) => { + const [formattedNumber, setFormattedNumber] = useState(numberString); + + useEffect(() => { + const formatted = numberString.replace(/-/g, ','); + setFormattedNumber(formatted); + }, [numberString]); + + return ( +
+ roller-triangle + roller-triangle +
+ {/* Highlight */} +
+ +
+ +
+
+
+ ); +}; + +export default LotterySlotCounter; diff --git a/components/lottery/winners/LotteryWinner.tsx b/components/lottery/winners/LotteryWinner.tsx index 6c99bb8..3eacee3 100644 --- a/components/lottery/winners/LotteryWinner.tsx +++ b/components/lottery/winners/LotteryWinner.tsx @@ -4,10 +4,11 @@ import { motion } from 'framer-motion'; interface IProps { index: number; - number: string; + phone: string; + ticket: string; } -const LotteryWinner = ({ index, number }: IProps) => { +const LotteryWinner = ({ index, phone, ticket }: IProps) => { return ( { opacity: 1, translateY: 0, }} - className="flex flex-col gap-2 md:pb-4 pb-3 last:border-none border-b border-lightOutlineVariant"> -

+ className="flex flex-col gap-2 md:pb-4 pb-3 border-b w-full border-[#CECCFF]"> +

The winner of the {index + 1} stage:

-

8 XX XX-XX-XX

+
+

{phone}

+
+

{ticket}

+
); }; diff --git a/components/lottery/winners/LotteryWinnersList.tsx b/components/lottery/winners/LotteryWinnersList.tsx index 6427e50..73e51ff 100644 --- a/components/lottery/winners/LotteryWinnersList.tsx +++ b/components/lottery/winners/LotteryWinnersList.tsx @@ -1,22 +1,17 @@ -import { LotteryWinnerData } from "@/typings/lottery/lottery.types"; -import LotteryWinner from "./LotteryWinner"; +import { LotteryWinnerData } from '@/typings/lottery/lottery.types'; +import LotteryWinner from './LotteryWinner'; const LotteryWinnersList = ({ winners }: { winners: LotteryWinnerData[] }) => { return ( -
-
-
-

Results

-

- The results after each stage will be shown here. -

-
- -
- {winners.map((_, index) => ( - - ))} -
+
+
+

Results

+

The results after each stage will be shown here.

+
+
+ {winners.map((item, index) => ( + + ))}
); diff --git a/lib/hooks/useLottery.ts b/lib/hooks/useLottery.ts index 4ecf2a6..6cdea6a 100644 --- a/lib/hooks/useLottery.ts +++ b/lib/hooks/useLottery.ts @@ -1,9 +1,9 @@ -import { useState, useEffect } from "react"; -import { LotteryStatus } from "@/typings/lottery/lottery.types"; +import { useState, useEffect } from 'react'; +import { LotteryStatus } from '@/typings/lottery/lottery.types'; export const useLottery = (startDate: string, endDate: string) => { - const [status, setStatus] = useState("not-started"); - const [currentNumber, setCurrentNumber] = useState("22-22-22-22-22"); + const [status, setStatus] = useState('not-started'); + const [currentNumber, setCurrentNumber] = useState('22-22-22-22-22'); useEffect(() => { const calculateStatus = () => { @@ -11,9 +11,9 @@ export const useLottery = (startDate: string, endDate: string) => { const start = new Date(startDate); const end = new Date(endDate); - if (now < start) return "not-started"; - if (now > end) return "ended"; - return "started"; + if (now < start) return 'not-started'; + if (now > end) return 'ended'; + return 'started'; }; setStatus(calculateStatus()); @@ -25,9 +25,9 @@ export const useLottery = (startDate: string, endDate: string) => { }, [startDate, endDate]); useEffect(() => { - if (status === "started") { + if (status === 'started') { const timer = setTimeout(() => { - setCurrentNumber("81-34-52-35-61"); + setCurrentNumber('81-34-52-35-61'); }, 10000); return () => clearTimeout(timer); @@ -36,6 +36,7 @@ export const useLottery = (startDate: string, endDate: string) => { return { status, + setStatus, currentNumber, }; }; diff --git a/package-lock.json b/package-lock.json index 04d55ce..f5e946e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ "react-hook-form": "^7.43.9", "react-icons": "^4.8.0", "react-player": "^2.12.0", + "react-slot-counter": "^3.0.4", "react-use": "^17.5.1", "swiper": "^9.2.4", "tailwind-merge": "^2.4.0", @@ -5504,6 +5505,18 @@ } } }, + "node_modules/react-slot-counter": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-slot-counter/-/react-slot-counter-3.0.4.tgz", + "integrity": "sha512-38eJP7NFr6eU7YiqgJ9UOhvZOIMNISjg1FmyIbcdoirKCeEabnP3JHwtY2QhoMj4+XtBHm7/QldsytMv+b2Zgw==", + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", @@ -10541,6 +10554,12 @@ "tslib": "^2.0.0" } }, + "react-slot-counter": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-slot-counter/-/react-slot-counter-3.0.4.tgz", + "integrity": "sha512-38eJP7NFr6eU7YiqgJ9UOhvZOIMNISjg1FmyIbcdoirKCeEabnP3JHwtY2QhoMj4+XtBHm7/QldsytMv+b2Zgw==", + "requires": {} + }, "react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", diff --git a/package.json b/package.json index 2a06cf9..8e45abf 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "react-hook-form": "^7.43.9", "react-icons": "^4.8.0", "react-player": "^2.12.0", + "react-slot-counter": "^3.0.4", "react-use": "^17.5.1", "swiper": "^9.2.4", "tailwind-merge": "^2.4.0", @@ -58,4 +59,3 @@ "eslint-config-next": "^14.1.0" } } - diff --git a/public/dash.svg b/public/dash.svg new file mode 100644 index 0000000..0926e23 --- /dev/null +++ b/public/dash.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/roller-triangle.svg b/public/roller-triangle.svg new file mode 100644 index 0000000..155da0d --- /dev/null +++ b/public/roller-triangle.svg @@ -0,0 +1,3 @@ + + + diff --git a/tailwind.config.js b/tailwind.config.js index 10bdaaa..d0ef3ba 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -89,6 +89,10 @@ export const theme = { lightOnWarningAllertContainer: '#F57C00', lightWarningAllertContainer: '#FFF8E1', lightWarningAllertContainerOutline: '#F9EDC8', + + // RollerCounter + rollerCounterGradient: + 'linear-gradient(180deg, #454673 0%, #575992 10.5%, #575992 90%, #454673 100%)', }, fontSize: { // Display