responsive design done
This commit is contained in:
parent
007902bb6d
commit
bb9db81d69
|
|
@ -22,8 +22,10 @@ const LotteryAuthPage = () => {
|
|||
}, [logout]);
|
||||
|
||||
return (
|
||||
<div className="flex justify-center items-center min-h-[50vh] py-[200px]">
|
||||
<LotteryAuthForm />
|
||||
<div className="container">
|
||||
<div className="flex justify-center items-center min-h-[50vh] py-[200px]">
|
||||
<LotteryAuthForm />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,56 +1,61 @@
|
|||
'use client';
|
||||
"use client";
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useLotteryAuth } from '@/store/useLotteryAuth';
|
||||
import ProtectedRoute from '@/components/lottery/auth/ProtectedRoute';
|
||||
import LotteryHeader from '@/components/lottery/LotteryHeader';
|
||||
import { useState } from "react";
|
||||
import { useLotteryAuth } from "@/store/useLotteryAuth";
|
||||
import ProtectedRoute from "@/components/lottery/auth/ProtectedRoute";
|
||||
import LotteryHeader from "@/components/lottery/LotteryHeader";
|
||||
|
||||
import LotteryWinnersSection from '@/components/lottery/LotteryWinnersSection';
|
||||
import LotteryRulesSection from '@/components/lottery/rules/LotteryRulesSection';
|
||||
import LotteryCountDown from '@/components/lottery/countDown/LotteryCountDown';
|
||||
import LotteryCountDownAllert from '@/components/lottery/countDown/countDownAllert/LotteryCountDownAllert';
|
||||
import LotteryWinnersSection from "@/components/lottery/LotteryWinnersSection";
|
||||
import LotteryRulesSection from "@/components/lottery/rules/LotteryRulesSection";
|
||||
import LotteryCountDown from "@/components/lottery/countDown/LotteryCountDown";
|
||||
import LotteryCountDownAllert from "@/components/lottery/countDown/countDownAllert/LotteryCountDownAllert";
|
||||
|
||||
const LotteryPage = () => {
|
||||
const { lotteryData } = useLotteryAuth();
|
||||
const [status, setStatus] = useState<'not-started' | 'started' | 'ended'>('not-started');
|
||||
const [status, setStatus] = useState<"not-started" | "started" | "ended">(
|
||||
"not-started"
|
||||
);
|
||||
|
||||
console.log(status);
|
||||
|
||||
return (
|
||||
<ProtectedRoute>
|
||||
<div className="flex flex-col md:gap-[128px] gap-[80px] font-roboto md:pt-[64px] sm:pt-[48px] pt-[40px] pb-[128px] text-lightOnSurface">
|
||||
<div className="flex flex-col md:gap-[128px] gap-[80px] font-roboto md:pt-[64px] sm:pt-[48px] pt-[40px] ms:pb-[128px] pb-[80px] text-lightOnSurface">
|
||||
{lotteryData && (
|
||||
<LotteryHeader
|
||||
title={lotteryData.data.title}
|
||||
description={lotteryData.data.description}
|
||||
image={lotteryData.data.image}
|
||||
smsCode={lotteryData.data.sms_code}
|
||||
/>
|
||||
)}
|
||||
<div className="flex flex-col sm:gap-[64px] gap-[40px]">
|
||||
<LotteryHeader
|
||||
title={lotteryData.data.title}
|
||||
description={lotteryData.data.description}
|
||||
image={lotteryData.data.image}
|
||||
smsCode={lotteryData.data.sms_code}
|
||||
/>
|
||||
|
||||
{lotteryData ? (
|
||||
status === 'not-started' ? (
|
||||
<div className="container">
|
||||
<LotteryCountDown
|
||||
lotteryStatus={status}
|
||||
setLotteryStatus={setStatus}
|
||||
endDate={lotteryData?.data.end_time}
|
||||
startDate={lotteryData?.data.start_time}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="container">
|
||||
<LotteryCountDownAllert
|
||||
lotteryStatus={status}
|
||||
setLotteryStatus={setStatus}
|
||||
endDate={lotteryData?.data.end_time}
|
||||
startDate={lotteryData?.data.start_time}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
) : null}
|
||||
{status === "not-started" ? (
|
||||
<div className="container">
|
||||
<LotteryCountDown
|
||||
lotteryStatus={status}
|
||||
setLotteryStatus={setStatus}
|
||||
endDate={lotteryData.data.end_time}
|
||||
startDate={lotteryData.data.start_time}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<LotteryRulesSection />
|
||||
|
||||
{(status === 'ended' || status === 'started') && <LotteryWinnersSection />}
|
||||
{lotteryData && (status === "ended" || status === "started") && (
|
||||
<div className="flex flex-col sm:gap-[100px] gap-[40px]">
|
||||
<LotteryCountDownAllert
|
||||
lotteryStatus={status}
|
||||
setLotteryStatus={setStatus}
|
||||
endDate={lotteryData.data.end_time}
|
||||
startDate={lotteryData.data.start_time}
|
||||
/>
|
||||
<LotteryWinnersSection lotteryStatus={status} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ProtectedRoute>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -93,7 +93,8 @@ html {
|
|||
}
|
||||
|
||||
.text-stroke {
|
||||
text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 1px 1px 0 white;
|
||||
text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white,
|
||||
1px 1px 0 white;
|
||||
}
|
||||
|
||||
.big-swiper .swiper-pagination-bullet {
|
||||
|
|
@ -121,20 +122,20 @@ html {
|
|||
|
||||
.small-swiper .swiper-button-next:after {
|
||||
color: white;
|
||||
content: url('/arrow-right-small.svg');
|
||||
content: url("/arrow-right-small.svg");
|
||||
}
|
||||
.small-swiper .swiper-button-prev:after {
|
||||
color: white;
|
||||
content: url('/arrow-left-small.svg');
|
||||
content: url("/arrow-left-small.svg");
|
||||
}
|
||||
|
||||
.big-swiper .swiper-button-next:after {
|
||||
color: white;
|
||||
content: url('/arrow-right-big.svg');
|
||||
content: url("/arrow-right-big.svg");
|
||||
}
|
||||
.big-swiper .swiper-button-prev:after {
|
||||
color: white;
|
||||
content: url('/arrow-left-big.svg');
|
||||
content: url("/arrow-left-big.svg");
|
||||
}
|
||||
|
||||
video {
|
||||
|
|
@ -187,15 +188,15 @@ big {
|
|||
@apply bg-[#E6E6FA] rounded-xl py-3 px-4 placeholder:text-[#BCBCD6] outline-none;
|
||||
}
|
||||
|
||||
.calendar [aria-label='Go to next month'] {
|
||||
.calendar [aria-label="Go to next month"] {
|
||||
@apply shadow-sm transition-all;
|
||||
}
|
||||
|
||||
.calendar [aria-label='Go to previous month'] {
|
||||
.calendar [aria-label="Go to previous month"] {
|
||||
@apply shadow-sm transition-all;
|
||||
}
|
||||
|
||||
.day-styles [name='day'] {
|
||||
.day-styles [name="day"] {
|
||||
@apply p-4 text-textDarkt leading-[140%] bg-purple-600 rounded-full;
|
||||
}
|
||||
|
||||
|
|
@ -261,20 +262,12 @@ big {
|
|||
}
|
||||
|
||||
.wheel-circle {
|
||||
background: url('/wheel-circle.svg');
|
||||
background: url("/wheel-circle.svg");
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
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; */
|
||||
|
|
@ -303,11 +296,53 @@ big {
|
|||
} */
|
||||
|
||||
.slot-seperator {
|
||||
content: url('/dash.svg');
|
||||
content: url("/dash.svg");
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
margin: 0 20px;
|
||||
@apply md:mx-5;
|
||||
}
|
||||
|
||||
.rolling-number {
|
||||
@apply text-lightOnPrimary md:text-[80px] md:leading-[88px] -tracking-[1%] md:px-4;
|
||||
}
|
||||
|
||||
@media (max-width: 1025px) {
|
||||
.rolling-number {
|
||||
@apply text-[48px] px-2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.slot-seperator {
|
||||
content: url("/dash-md.svg");
|
||||
@apply mx-2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1025px) {
|
||||
.rolling-number {
|
||||
@apply text-[48px] px-2;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 426px) {
|
||||
.rolling-number {
|
||||
@apply text-[24px] px-1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 320px) {
|
||||
.rolling-number {
|
||||
@apply text-[16px] px-1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 426px) {
|
||||
.slot-seperator {
|
||||
content: url("/dash-sm.svg");
|
||||
@apply mx-2;
|
||||
}
|
||||
}
|
||||
|
||||
.confetti-piece {
|
||||
|
|
@ -324,7 +359,8 @@ big {
|
|||
transform: translateX(0) translateY(0) rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: translateX(calc(var(--end-x) / 2)) translateY(-30vh) rotate(180deg);
|
||||
transform: translateX(calc(var(--end-x) / 2)) translateY(-30vh)
|
||||
rotate(180deg);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
|
|
|
|||
|
|
@ -1,34 +1,43 @@
|
|||
'use client';
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { useLotteryAuth } from '@/store/useLotteryAuth';
|
||||
import { LotteryWinnerDataSimplified } from '@/typings/lottery/lottery.types';
|
||||
import LotteryWinnersList from './winners/LotteryWinnersList';
|
||||
import LotterySlotCounter from './slotCounter/LotterySlotCounter';
|
||||
import ReactConfetti from 'react-confetti';
|
||||
import { useWindowSize } from 'react-use';
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { useLotteryAuth } from "@/store/useLotteryAuth";
|
||||
import { LotteryWinnerDataSimplified } from "@/typings/lottery/lottery.types";
|
||||
import LotteryWinnersList from "./winners/LotteryWinnersList";
|
||||
import LotterySlotCounter from "./slotCounter/LotterySlotCounter";
|
||||
import ReactConfetti from "react-confetti";
|
||||
import { useWindowSize } from "react-use";
|
||||
import LotteryCountDownAllert from "./countDown/countDownAllert/LotteryCountDownAllert";
|
||||
|
||||
const WEBSOCKET_URL = 'wss://sms.turkmentv.gov.tm/ws/lottery?dst=0506';
|
||||
const WEBSOCKET_URL = "wss://sms.turkmentv.gov.tm/ws/lottery?dst=0506";
|
||||
const PING_INTERVAL = 25000;
|
||||
const SLOT_COUNTER_DURATION = 20000;
|
||||
|
||||
const LotteryWinnersSection = () => {
|
||||
const LotteryWinnersSection = ({
|
||||
lotteryStatus,
|
||||
}: {
|
||||
lotteryStatus: string;
|
||||
}) => {
|
||||
// UI States
|
||||
const [winners, setWinners] = useState<LotteryWinnerDataSimplified[]>([]);
|
||||
const [currentNumber, setCurrentNumber] = useState<string>('00-00-00-00-00');
|
||||
const [currentNumber, setCurrentNumber] = useState<string>("00-00-00-00-00");
|
||||
const [isConfettiActive, setIsConfettiActive] = useState(false);
|
||||
const [wsStatus, setWsStatus] = useState<'connecting' | 'connected' | 'error'>('connecting');
|
||||
|
||||
const [wsStatus, setWsStatus] = useState<
|
||||
"connecting" | "connected" | "error"
|
||||
>("connecting");
|
||||
const { width, height } = useWindowSize();
|
||||
const { lotteryData } = useLotteryAuth();
|
||||
const [isSlotCounterAnimating, setIsSlotCounterAnimating] = useState(false);
|
||||
const [pendingWinner, setPendingWinner] = useState<LotteryWinnerDataSimplified | null>(null);
|
||||
const [pendingWinner, setPendingWinner] =
|
||||
useState<LotteryWinnerDataSimplified | null>(null);
|
||||
|
||||
// Refs
|
||||
const wsRef = useRef<WebSocket | null>(null);
|
||||
const pingIntervalRef = useRef<NodeJS.Timeout>();
|
||||
const mountedRef = useRef(false);
|
||||
|
||||
console.log(isConfettiActive, 'isConfettiActive');
|
||||
console.log(isConfettiActive, "isConfettiActive");
|
||||
|
||||
// Initialize winners from lottery data
|
||||
useEffect(() => {
|
||||
|
|
@ -39,7 +48,9 @@ const LotteryWinnersSection = () => {
|
|||
ticket: winner.ticket,
|
||||
}));
|
||||
setWinners(simplifiedWinners);
|
||||
setCurrentNumber(lotteryData.data.winners.at(-1)?.ticket || '00-00-00-00-00');
|
||||
setCurrentNumber(
|
||||
lotteryData.data.winners.at(-1)?.ticket || "00-00-00-00-00"
|
||||
);
|
||||
}
|
||||
}, [lotteryData]);
|
||||
|
||||
|
|
@ -52,21 +63,21 @@ const LotteryWinnersSection = () => {
|
|||
const socket = new WebSocket(WEBSOCKET_URL);
|
||||
wsRef.current = socket;
|
||||
|
||||
socket.addEventListener('open', () => {
|
||||
socket.addEventListener("open", () => {
|
||||
if (!mountedRef.current) return;
|
||||
console.log('WebSocket Connected');
|
||||
setWsStatus('connected');
|
||||
console.log("WebSocket Connected");
|
||||
setWsStatus("connected");
|
||||
|
||||
pingIntervalRef.current = setInterval(() => {
|
||||
if (socket.readyState === WebSocket.OPEN) {
|
||||
socket.send(JSON.stringify({ type: 'ping' }));
|
||||
socket.send(JSON.stringify({ type: "ping" }));
|
||||
}
|
||||
}, PING_INTERVAL);
|
||||
});
|
||||
|
||||
socket.addEventListener('message', async (event) => {
|
||||
socket.addEventListener("message", async (event) => {
|
||||
if (!mountedRef.current) return;
|
||||
console.log('Message received:', event.data);
|
||||
console.log("Message received:", event.data);
|
||||
|
||||
try {
|
||||
const newWinner = JSON.parse(event.data);
|
||||
|
|
@ -82,7 +93,9 @@ const LotteryWinnersSection = () => {
|
|||
setCurrentNumber(winnerData.ticket);
|
||||
|
||||
// Wait for slot counter animation
|
||||
await new Promise((resolve) => setTimeout(resolve, SLOT_COUNTER_DURATION));
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, SLOT_COUNTER_DURATION)
|
||||
);
|
||||
|
||||
setIsConfettiActive(true);
|
||||
setWinners((prev) => [...prev, winnerData]);
|
||||
|
|
@ -111,30 +124,30 @@ const LotteryWinnersSection = () => {
|
|||
}, 5000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error processing message:', error);
|
||||
console.error("Error processing message:", error);
|
||||
setIsSlotCounterAnimating(false);
|
||||
setPendingWinner(null);
|
||||
}
|
||||
});
|
||||
|
||||
socket.addEventListener('error', (error) => {
|
||||
socket.addEventListener("error", (error) => {
|
||||
if (!mountedRef.current) return;
|
||||
console.error('WebSocket Error:', error);
|
||||
setWsStatus('error');
|
||||
console.error("WebSocket Error:", error);
|
||||
setWsStatus("error");
|
||||
});
|
||||
|
||||
socket.addEventListener('close', () => {
|
||||
socket.addEventListener("close", () => {
|
||||
if (!mountedRef.current) return;
|
||||
console.log('WebSocket Closed');
|
||||
setWsStatus('error');
|
||||
console.log("WebSocket Closed");
|
||||
setWsStatus("error");
|
||||
|
||||
if (pingIntervalRef.current) {
|
||||
clearInterval(pingIntervalRef.current);
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error creating WebSocket:', error);
|
||||
setWsStatus('error');
|
||||
console.error("Error creating WebSocket:", error);
|
||||
setWsStatus("error");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -154,7 +167,7 @@ const LotteryWinnersSection = () => {
|
|||
|
||||
return (
|
||||
<section>
|
||||
{wsStatus === 'error' && (
|
||||
{wsStatus === "error" && (
|
||||
<div className="text-red-500 text-center mb-2">
|
||||
Connection error. Please refresh the page.
|
||||
</div>
|
||||
|
|
@ -170,12 +183,12 @@ const LotteryWinnersSection = () => {
|
|||
tweenDuration={10000}
|
||||
run={true}
|
||||
colors={[
|
||||
'linear-gradient(45deg, #5D5D72, #8589DE)',
|
||||
'linear-gradient(45deg, #E1E0FF, #575992)',
|
||||
'#8589DE',
|
||||
'#575992',
|
||||
'#E1E0FF',
|
||||
'#BA1A1A',
|
||||
"linear-gradient(45deg, #5D5D72, #8589DE)",
|
||||
"linear-gradient(45deg, #E1E0FF, #575992)",
|
||||
"#8589DE",
|
||||
"#575992",
|
||||
"#E1E0FF",
|
||||
"#BA1A1A",
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -183,10 +196,13 @@ const LotteryWinnersSection = () => {
|
|||
|
||||
<div className="container">
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="-mb-[90px] z-10">
|
||||
<LotterySlotCounter numberString={currentNumber} isAnimating={isSlotCounterAnimating} />
|
||||
<div className="md:-mb-[90px] sm:-mb-[40px] -mb-[20px] z-10">
|
||||
<LotterySlotCounter
|
||||
numberString={currentNumber}
|
||||
isAnimating={isSlotCounterAnimating}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-6 bg-lightPrimaryContainer rounded-[12px] flex-1 w-full items-center justify-center pt-[122px] pb-[62px]">
|
||||
<div className="flex gap-6 bg-lightPrimaryContainer rounded-[12px] flex-1 w-full items-center justify-center md:pt-[122px] sm:pt-[90px] pt-[40px] sm:pb-[62px] pb-[32px] md:px-0 px-4">
|
||||
<LotteryWinnersList winners={winners} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
'use client';
|
||||
"use client";
|
||||
|
||||
import { Queries } from '@/api/queries';
|
||||
import { useState, FormEvent } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useLotteryAuth } from '@/store/useLotteryAuth';
|
||||
import { Queries } from "@/api/queries";
|
||||
import { useState, FormEvent } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useLotteryAuth } from "@/store/useLotteryAuth";
|
||||
|
||||
const LotteryAuthForm = () => {
|
||||
const [phone, setPhone] = useState('');
|
||||
const [code, setCode] = useState('');
|
||||
const [phone, setPhone] = useState("");
|
||||
const [code, setCode] = useState("");
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const router = useRouter();
|
||||
|
|
@ -28,12 +28,12 @@ const LotteryAuthForm = () => {
|
|||
setError(null);
|
||||
|
||||
if (!validatePhone(phone)) {
|
||||
setError('Telefon belgisi nädogry formatda');
|
||||
setError("Telefon belgisi nädogry formatda");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateCode(code)) {
|
||||
setError('Kod nädogry formatda');
|
||||
setError("Kod nädogry formatda");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -42,17 +42,17 @@ const LotteryAuthForm = () => {
|
|||
try {
|
||||
const response = await Queries.authenticateLottery(phone, code);
|
||||
setAuth(response, phone, code);
|
||||
router.replace('/lottery');
|
||||
router.replace("/lottery");
|
||||
} catch (err) {
|
||||
console.error('Authentication error:', err);
|
||||
setError('Telefon belgisi ýa-da kod nädogry');
|
||||
console.error("Authentication error:", err);
|
||||
setError("Telefon belgisi ýa-da kod nädogry");
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePhoneChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value.replace(/\D/g, ''); // Remove non-digits
|
||||
const value = e.target.value.replace(/\D/g, ""); // Remove non-digits
|
||||
if (value.length <= 11) {
|
||||
// Limit to 11 digits (99363 + 6 digits)
|
||||
setPhone(value);
|
||||
|
|
@ -70,8 +70,11 @@ const LotteryAuthForm = () => {
|
|||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className="bg-lightSurfaceContainer rounded-[24px] p-[40px] w-[530px] flex flex-col gap-[24px]">
|
||||
<h1 className="text-display3 font-[500] leading-display3">Lotereýa giriş</h1>
|
||||
className="bg-lightSurfaceContainer rounded-[24px] md:p-[40px] sm:p-[24px] p-[16px] w-[530px] flex flex-col gap-[24px]"
|
||||
>
|
||||
<h1 className="md:text-display3 sm:text-[32px] text-[24px] font-[500] md:leading-display3">
|
||||
Lotereýa giriş
|
||||
</h1>
|
||||
<div className="flex flex-col gap-[16px]">
|
||||
<div className="flex flex-col gap-[8px]">
|
||||
<input
|
||||
|
|
@ -89,17 +92,22 @@ const LotteryAuthForm = () => {
|
|||
value={code}
|
||||
onChange={handleCodeChange}
|
||||
className="px-[16px] py-[12px] bg-lightPrimaryContainer rounded-[12px] outline-none text-lightOnSurfaceVariant text-textSmall leading-textSmall"
|
||||
placeholder="5-0102030408"
|
||||
placeholder="5-0105639808"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
{error && <p className="text-lightError text-textSmall leading-textSmall">{error}</p>}
|
||||
{error && (
|
||||
<p className="text-lightError text-textSmall leading-textSmall">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading || !phone || !code}
|
||||
className="text-textLarge leading-textLarge py-[12px] w-full flex justify-center items-center rounded-[12px] bg-lightPrimary font-medium text-lightOnPrimary disabled:opacity-50">
|
||||
{isLoading ? 'Ýüklenilýär...' : 'Giriş'}
|
||||
className="sm:text-textLarge sm:leading-textLarge text-[16px] leading-[24px] sm:py-[12px] py-[8px] w-full flex justify-center items-center rounded-[12px] bg-lightPrimary font-medium text-lightOnPrimary disabled:opacity-50"
|
||||
>
|
||||
{isLoading ? "Ýüklenilýär..." : "Giriş"}
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ const LotteryCountDown: React.FC<LotteryCountDownProps> = ({
|
|||
seconds: 0,
|
||||
});
|
||||
|
||||
console.log(lotteryStatus);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
if (lotteryStatus === "not-started") {
|
||||
|
|
@ -57,8 +59,8 @@ const LotteryCountDown: React.FC<LotteryCountDownProps> = ({
|
|||
console.log(lotteryStatus);
|
||||
|
||||
return (
|
||||
<div className="bg-lightPrimaryContainer sm:p-6 p-2 flex flex-col w-full md:gap-2 rounded-[12px] text-lightOnPrimaryContainer">
|
||||
<h3 className="text-center md:font-heading-1-regular text-[32px] leading-[40px] text-lightOnSurface">
|
||||
<div className="bg-lightPrimaryContainer sm:p-6 py-3 flex flex-col w-full md:gap-2 rounded-[12px] sm:gap-3 gap-0 text-lightOnPrimaryContainer">
|
||||
<h3 className="text-center md:font-heading-1-regular sm:text-[32px] sm:leading-[40px] text-[20px] leading-[28px] text-lightOnSurface">
|
||||
{lotteryStatus === "started"
|
||||
? "Bije dowam edýär"
|
||||
: lotteryStatus === "ended"
|
||||
|
|
@ -68,7 +70,7 @@ const LotteryCountDown: React.FC<LotteryCountDownProps> = ({
|
|||
{/* LotteryCountDown */}
|
||||
{lotteryStatus === "not-started" && (
|
||||
<div className="flex items-center sm:gap-6 gap-2 justify-between">
|
||||
<div className="flex flex-col items-center justify-center flex-1 p-6">
|
||||
<div className="flex flex-col items-center justify-center flex-1 sm:p-6 p-4 sm:pb-3">
|
||||
<h3 className="md:text-[80px] sm:text-[56px] text-[28px] md:leading-[88px] sm:leading-[64px] leading-[36px] -tracking-[1%]">
|
||||
{timeLeft.hours}
|
||||
</h3>
|
||||
|
|
@ -77,12 +79,13 @@ const LotteryCountDown: React.FC<LotteryCountDownProps> = ({
|
|||
</h4>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="w-3 h-3 rounded-full bg-lightOnSurfaceVariant"></div>
|
||||
<div className="w-3 h-3 rounded-full bg-lightOnSurfaceVariant"></div>
|
||||
{/* Dots */}
|
||||
<div className="flex flex-col sm:gap-3 gap-2">
|
||||
<div className="sm:w-3 sm:h-3 w-1 h-1 rounded-full bg-lightOnSurfaceVariant"></div>
|
||||
<div className="sm:w-3 sm:h-3 w-1 h-1 rounded-full bg-lightOnSurfaceVariant"></div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center justify-center flex-1 sm:p-6 p-4 pb-3">
|
||||
<div className="flex flex-col items-center justify-center flex-1 sm:p-6 p-4 sm:pb-3">
|
||||
<h3 className="md:text-[80px] sm:text-[56px] text-[28px] md:leading-[88px] sm:leading-[64px] leading-[36px] -tracking-[1%]">
|
||||
{timeLeft.minutes}
|
||||
</h3>
|
||||
|
|
@ -91,12 +94,13 @@ const LotteryCountDown: React.FC<LotteryCountDownProps> = ({
|
|||
</h4>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="w-3 h-3 rounded-full bg-lightOnSurfaceVariant"></div>
|
||||
<div className="w-3 h-3 rounded-full bg-lightOnSurfaceVariant"></div>
|
||||
{/* Dots */}
|
||||
<div className="flex flex-col sm:gap-3 gap-2">
|
||||
<div className="sm:w-3 sm:h-3 w-1 h-1 rounded-full bg-lightOnSurfaceVariant"></div>
|
||||
<div className="sm:w-3 sm:h-3 w-1 h-1 rounded-full bg-lightOnSurfaceVariant"></div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center justify-center flex-1 p-6">
|
||||
<div className="flex flex-col items-center justify-center flex-1 sm:p-6 p-4 sm:pb-3">
|
||||
<h3 className="md:text-[80px] sm:text-[56px] text-[28px] md:leading-[88px] sm:leading-[64px] leading-[36px] -tracking-[1%]">
|
||||
{timeLeft.seconds}
|
||||
</h3>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useLotteryAuth } from '@/store/useLotteryAuth';
|
||||
import { useLotteryAuth } from "@/store/useLotteryAuth";
|
||||
|
||||
const LotteryRulesSection = () => {
|
||||
const { lotteryData } = useLotteryAuth();
|
||||
|
|
@ -7,17 +7,18 @@ const LotteryRulesSection = () => {
|
|||
<section>
|
||||
<div className="container">
|
||||
<div className="flex flex-col md:gap-8 gap-6">
|
||||
<h2 className="md:font-heading-1-regular text-[32px] leading-[40px]">
|
||||
<h2 className="md:font-heading-1-regular sm:text-[32px] text-[26px] sm:leading-[40px] leading-[34px]">
|
||||
Lotereýanyň duzgunleri:
|
||||
</h2>
|
||||
<div className="flex gap-6">
|
||||
<div className="flex flex-col md:gap-4 gap-2 bg-lightSurfaceContainer py-4 md:px-8 px-6 rounded-[12px] w-full">
|
||||
<h3 className="md:font-heading-5-regular text-[20px] leading-[24px]">
|
||||
|
||||
<div className="flex sm:flex-row flex-col gap-6">
|
||||
<div className="flex flex-col md:gap-4 sm:gap-2 gap-4 bg-lightSurfaceContainer sm:py-4 md:px-8 sm:px-6 py-3 px-4 rounded-[12px] w-full">
|
||||
<h3 className="md:font-heading-5-regular sm:text-[20px] text-[18px] sm:leading-[24px] leading-[28px]">
|
||||
Umumy düzgünler:
|
||||
</h3>
|
||||
<ul className="list-disc flex flex-col md:gap-4 gap-2 pl-[16px]">
|
||||
{Array(5)
|
||||
.fill(' ')
|
||||
.fill(" ")
|
||||
.map((item, i) => (
|
||||
<li className="font-small-regular" key={i}>
|
||||
Ilkinji we dogry jogap beren sanawda ilkinji ýeri eýelýär
|
||||
|
|
@ -26,8 +27,10 @@ const LotteryRulesSection = () => {
|
|||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col md:gap-4 gap-2 bg-lightSurfaceContainer py-4 md:px-8 px-6 rounded-[12px] w-full">
|
||||
<h3 className="md:font-heading-5-regular text-[20px] leading-[24px]">Üns beriň:</h3>
|
||||
<div className="flex flex-col md:gap-4 sm:gap-2 gap-4 bg-lightSurfaceContainer sm:py-4 md:px-8 sm:px-6 py-3 px-4 rounded-[12px] w-full">
|
||||
<h3 className="md:font-heading-5-regular sm:text-[20px] text-[18px] sm:leading-[24px] leading-[28px]">
|
||||
Üns beriň:
|
||||
</h3>
|
||||
<ul className="list-disc flex flex-col md:gap-4 gap-2 pl-[16px]">
|
||||
{lotteryData?.user_lottery_numbers.map((item, i) => (
|
||||
<li className="font-small-regular" key={i}>
|
||||
|
|
|
|||
|
|
@ -1,51 +1,82 @@
|
|||
'use client';
|
||||
import Image from 'next/image';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import SlotCounter from 'react-slot-counter';
|
||||
"use client";
|
||||
import Image from "next/image";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import SlotCounter from "react-slot-counter";
|
||||
import { useMediaQuery } from "usehooks-ts";
|
||||
|
||||
interface LotterySlotCounterProps {
|
||||
numberString: string;
|
||||
isAnimating: boolean;
|
||||
}
|
||||
|
||||
const LotterySlotCounter = ({ numberString, isAnimating }: LotterySlotCounterProps) => {
|
||||
const LotterySlotCounter = ({
|
||||
numberString,
|
||||
isAnimating,
|
||||
}: LotterySlotCounterProps) => {
|
||||
const [formattedNumber, setFormattedNumber] = useState(numberString);
|
||||
|
||||
useEffect(() => {
|
||||
const formatted = numberString.replace(/-/g, ',');
|
||||
const formatted = numberString.replace(/-/g, ",");
|
||||
setFormattedNumber(formatted);
|
||||
}, [numberString]);
|
||||
|
||||
const tablet = useMediaQuery("(max-width: 769px)");
|
||||
const mobile = useMediaQuery("(max-width: 426px)");
|
||||
|
||||
return (
|
||||
<div className="relative w-fit">
|
||||
<Image
|
||||
src="/roller-triangle.svg"
|
||||
alt="roller-triangle"
|
||||
width={48}
|
||||
height={48}
|
||||
className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-1/2 z-20"
|
||||
/>
|
||||
<Image
|
||||
src="/roller-triangle.svg"
|
||||
alt="roller-triangle"
|
||||
width={48}
|
||||
height={48}
|
||||
className="absolute right-0 top-1/2 -translate-y-1/2 translate-x-1/2 z-20 rotate-180"
|
||||
/>
|
||||
{mobile ? (
|
||||
<Image
|
||||
src="/roller-triangle-sm.svg"
|
||||
alt="roller-triangle"
|
||||
width={24}
|
||||
height={24}
|
||||
className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-1/2 z-20"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src="/roller-triangle.svg"
|
||||
alt="roller-triangle"
|
||||
width={48}
|
||||
height={48}
|
||||
className="absolute left-0 top-1/2 -translate-y-1/2 -translate-x-1/2 z-20"
|
||||
/>
|
||||
)}
|
||||
|
||||
{mobile ? (
|
||||
<Image
|
||||
src="/roller-triangle-sm.svg"
|
||||
alt="roller-triangle"
|
||||
width={24}
|
||||
height={24}
|
||||
className="absolute right-0 top-1/2 -translate-y-1/2 translate-x-1/2 z-20 rotate-180"
|
||||
/>
|
||||
) : (
|
||||
<Image
|
||||
src="/roller-triangle.svg"
|
||||
alt="roller-triangle"
|
||||
width={48}
|
||||
height={48}
|
||||
className="absolute right-0 top-1/2 -translate-y-1/2 translate-x-1/2 z-20 rotate-180"
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
className="flex w-full items-center h-[180px] max-w-[1132px] justify-center text-white py-4 px-6 rounded-full overflow-y-hidden overflow-x-visible relative border-4 border-lightPrimary"
|
||||
className="flex items-center md:h-[180px] sm:h-[100px] h-[50px] md:max-w-[1132px] sm:max-w-[640px] max-w-[324px] w-full justify-center text-white md:py-4 md:px-6 rounded-full overflow-y-hidden overflow-x-visible relative border-4 border-lightPrimary"
|
||||
style={{
|
||||
background:
|
||||
'linear-gradient(180deg, #454673 0%, #575992 10.5%, #575992 90%, #454673 100%)',
|
||||
boxShadow: '0px 4px 4px 0px #00000040',
|
||||
}}>
|
||||
"linear-gradient(180deg, #454673 0%, #575992 10.5%, #575992 90%, #454673 100%)",
|
||||
boxShadow: "0px 4px 4px 0px #00000040",
|
||||
}}
|
||||
>
|
||||
{/* Highlight */}
|
||||
<div
|
||||
className="absolute top-[50%] -translate-y-1/2 left-0 w-full h-full"
|
||||
style={{
|
||||
background:
|
||||
'linear-gradient(180deg, rgba(87, 89, 146, 0) 0%, #7274AB 50%, rgba(87, 89, 146, 0) 100%)',
|
||||
}}></div>
|
||||
"linear-gradient(180deg, rgba(87, 89, 146, 0) 0%, #7274AB 50%, rgba(87, 89, 146, 0) 100%)",
|
||||
}}
|
||||
></div>
|
||||
|
||||
<div className="z-10">
|
||||
<SlotCounter
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use client';
|
||||
"use client";
|
||||
|
||||
import { motion } from 'framer-motion';
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
interface IProps {
|
||||
phone: string;
|
||||
|
|
@ -17,14 +17,15 @@ const LotteryWinner = ({ phone, ticket, isNew, winnerNumber }: IProps) => {
|
|||
animate={{ opacity: 1, translateY: 0 }}
|
||||
exit={{ opacity: 0, translateY: -20 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="flex flex-col gap-2 md:pb-4 pb-3 border-b w-full border-[#CECCFF]">
|
||||
className="flex flex-col gap-2 md:pb-4 pb-3 border-b w-full border-[#CECCFF]"
|
||||
>
|
||||
<h4 className="md:font-heading-6-regular text-[20px] leading-[28px]">
|
||||
The winner of the {winnerNumber} stage:
|
||||
</h4>
|
||||
<div className="flex items-center gap-4">
|
||||
<p className="font-base-medium">{phone}</p>
|
||||
<p className="md:font-base-medium font-base-regular">{phone}</p>
|
||||
<div className="w-1 h-1 rounded-full bg-lightOnSurfaceVariant"></div>
|
||||
<p className="font-base-medium">{ticket}</p>
|
||||
<p className="md:font-base-medium font-base-regular">{ticket}</p>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,18 +1,28 @@
|
|||
import { LotteryWinnerData, LotteryWinnerDataSimplified } from '@/typings/lottery/lottery.types';
|
||||
import LotteryWinner from './LotteryWinner';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { v4 } from 'uuid';
|
||||
import {
|
||||
LotteryWinnerData,
|
||||
LotteryWinnerDataSimplified,
|
||||
} from "@/typings/lottery/lottery.types";
|
||||
import LotteryWinner from "./LotteryWinner";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { v4 } from "uuid";
|
||||
|
||||
const LotteryWinnersList = ({ winners }: { winners: LotteryWinnerDataSimplified[] }) => {
|
||||
const LotteryWinnersList = ({
|
||||
winners,
|
||||
}: {
|
||||
winners: LotteryWinnerDataSimplified[];
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-4 w-full max-w-[1028px]">
|
||||
<div className="flex flex-col gap-2 w-full md:pb-4 pb-3 border-b border-[#CECCFF]">
|
||||
<h4 className="font-heading-3-regular">Results</h4>
|
||||
<p className="font-base-medium">The results after each stage will be shown here.</p>
|
||||
<div className="flex flex-col gap-2 w-full pb-4 border-b border-[#CECCFF]">
|
||||
<h4 className="md:font-heading-3-regular text-[28px]">Results</h4>
|
||||
<p className="md:font-base-medium text-[16px]">
|
||||
The results after each stage will be shown here.
|
||||
</p>
|
||||
</div>
|
||||
<motion.div
|
||||
layout
|
||||
className="grid grid-cols-3 gap-x-2 gap-y-4 w-full h-[244px] overflow-y-auto lottery-scrollbar">
|
||||
className="grid md:grid-cols-3 sm:grid-cols-2 grid-cols-1 gap-x-2 gap-y-4 w-full h-[244px] overflow-y-auto lottery-scrollbar"
|
||||
>
|
||||
<AnimatePresence mode="popLayout">
|
||||
{winners.map((item, index) => (
|
||||
<LotteryWinner
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="25" height="4" viewBox="0 0 25 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="24" height="4" transform="translate(0.25)" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 172 B |
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="12" height="2" viewBox="0 0 12 2" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="12" height="2" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 144 B |
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="18" height="22" viewBox="0 0 18 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 2.33975L16 11L1 19.6603L1 2.33975Z" fill="#575992" stroke="#D8D6FF" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 202 B |
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="18" height="22" viewBox="0 0 18 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 2.33975L16 11L1 19.6603L1 2.33975Z" fill="#575992" stroke="#D8D6FF" stroke-width="2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 202 B |
Loading…
Reference in New Issue