Initial commit: Tapalka monorepo (bot, front, strapi)
This commit is contained in:
137
CMyTapper/robucks-front/components/home/Home.module.css
Normal file
137
CMyTapper/robucks-front/components/home/Home.module.css
Normal file
@@ -0,0 +1,137 @@
|
||||
.home {
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-image: url("../../public/images/background-img.jpg");
|
||||
}
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
padding-bottom: 3rem;
|
||||
height: 100%;
|
||||
gap: 25px;
|
||||
}
|
||||
|
||||
.greeting {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
line-height: 34.4px;
|
||||
}
|
||||
|
||||
.greeting span {
|
||||
background: linear-gradient(45deg, #42BB47, #33A137, #42BB47);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.balance {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.balanceAmount {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
.totalBalance {
|
||||
font-size: 42px;
|
||||
font-weight: 600;
|
||||
line-height: 51px;
|
||||
background: linear-gradient(45deg, #42BB47, #33A137, #42BB47);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.miningButton {
|
||||
margin-bottom: 75px;
|
||||
width: 187px;
|
||||
height: 60px;
|
||||
padding: 20px 30px;
|
||||
background: #42BB47;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
line-height: 19.6px;
|
||||
box-shadow: 0 0 42px 0 #42BB47B2;
|
||||
border-radius: 30px;
|
||||
border: 0.5px solid;
|
||||
cursor: pointer;
|
||||
border-image-source: linear-gradient(180deg, #42BB47 4.41%, #308A34 61.59%, #42BB47 101.32%);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.farmingButton {
|
||||
margin-bottom: 75px;
|
||||
width: 300px;
|
||||
height: 60px;
|
||||
padding: 20px 30px;
|
||||
background: black;
|
||||
box-shadow: 0px 0px 42px 0px #42BB4780;
|
||||
text-decoration: none;
|
||||
cursor: not-allowed;
|
||||
border-radius: 30px;
|
||||
border: 1px solid #42BB4780;
|
||||
color: #42BB4780;
|
||||
font-weight: 600;
|
||||
line-height: 19.6px;
|
||||
}
|
||||
|
||||
.claimReward {
|
||||
box-shadow: 0px 0px 42px 0px #42BB4780;
|
||||
width: 257px;
|
||||
height: 60px;
|
||||
padding: 20px 30px;
|
||||
cursor: pointer;
|
||||
margin-bottom: 75px;
|
||||
border-radius: 30px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
line-height: 19.6px;
|
||||
background: #10101080;
|
||||
border: 1px solid #42BB47;
|
||||
color: #42BB4780;
|
||||
}
|
||||
|
||||
.claimAmount {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.claimAmount span {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #42BB47;
|
||||
}
|
||||
|
||||
.reward {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
gap: 10px;
|
||||
color: #42BB47;
|
||||
}
|
||||
|
||||
.reward span {
|
||||
color: #42BB47;
|
||||
}
|
||||
|
||||
.disabledButton {
|
||||
background: #10101080;
|
||||
color: #42BB47;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.miningButton,
|
||||
.farmingButton,
|
||||
.claimReward {
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
62
CMyTapper/robucks-front/components/home/Home.tsx
Normal file
62
CMyTapper/robucks-front/components/home/Home.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
'use client';
|
||||
import React, { FC } from 'react';
|
||||
import styles from './Home.module.css';
|
||||
import Image from 'next/image';
|
||||
import { IConfig } from '@/api/config.api';
|
||||
import ButtonMining from '@/components/ui/button-mining/ButtonMining';
|
||||
import { usePlayerStore } from '@/store/player.state';
|
||||
import { toFixed } from '@/utils/FormatNumber';
|
||||
|
||||
interface IHome {
|
||||
remainingTime: string | null;
|
||||
config: IConfig | null;
|
||||
isLoading: boolean;
|
||||
typeButton: 'pending' | 'farming' | 'claim_reward';
|
||||
handleStartFarming: () => void;
|
||||
handleClaimRewards: () => void;
|
||||
}
|
||||
|
||||
const Home: FC<IHome> = ({
|
||||
remainingTime,
|
||||
config,
|
||||
isLoading,
|
||||
typeButton,
|
||||
handleStartFarming,
|
||||
handleClaimRewards,
|
||||
}) => {
|
||||
const { player } = usePlayerStore();
|
||||
return (
|
||||
<div className={styles.home}>
|
||||
<div className={styles.main}>
|
||||
<div className={styles.greeting}>
|
||||
<p>Привет, </p>
|
||||
<span>{player ? player.attributes.telegram_nick : '-'}!</span>
|
||||
</div>
|
||||
<div className={styles.balance}>
|
||||
<span>Ваш баланс</span>
|
||||
<div className={styles.balanceAmount}>
|
||||
<Image
|
||||
src={'/icons/robucks-icon.svg'}
|
||||
alt={'robucks icon'}
|
||||
width={32}
|
||||
height={32}
|
||||
/>
|
||||
<span className={styles.totalBalance}>
|
||||
{player ? toFixed(player.attributes.balance) : '0'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<ButtonMining
|
||||
isLoading={isLoading}
|
||||
typeButton={typeButton}
|
||||
remainingTime={remainingTime}
|
||||
farm_amount={config?.attributes.farm_amount}
|
||||
handleStartFarming={handleStartFarming}
|
||||
handleClaimRewards={handleClaimRewards}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
93
CMyTapper/robucks-front/components/home/HomeContainer.tsx
Normal file
93
CMyTapper/robucks-front/components/home/HomeContainer.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import Home from '@/components/home/Home';
|
||||
import { FormatTime } from '@/utils/FormatTime';
|
||||
import { useButtonStore } from '@/store/button.state';
|
||||
import { PlayerApi } from '@/api/player.api';
|
||||
import { usePlayerStore } from '@/store/player.state';
|
||||
import { useConfigStore } from '@/store/config.state';
|
||||
import { useTokenStore } from '@/store/token.state';
|
||||
import { toFixed } from '@/utils/FormatNumber';
|
||||
|
||||
const HomeContainer = () => {
|
||||
const { typeButton, setTypeButton } = useButtonStore();
|
||||
|
||||
const { player: playerStore, setPlayer } = usePlayerStore();
|
||||
const { config: configStore } = useConfigStore();
|
||||
const { token } = useTokenStore();
|
||||
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [remainingTime, setRemainingTime] = useState<number | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoading) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [isLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (playerStore && playerStore.attributes.start_farm && configStore) {
|
||||
const farmingTime = configStore.attributes.farming_time * 1000;
|
||||
const endTime = new Date(playerStore.attributes.start_farm).getTime() + farmingTime;
|
||||
|
||||
const updateRemainingTime = () => {
|
||||
const now = new Date().getTime();
|
||||
const timeLeft = endTime - now;
|
||||
setRemainingTime(timeLeft > 0 ? timeLeft : 0);
|
||||
};
|
||||
|
||||
updateRemainingTime();
|
||||
const interval = setInterval(updateRemainingTime, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
} else {
|
||||
setRemainingTime(null);
|
||||
}
|
||||
}, [playerStore, configStore]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!remainingTime && !playerStore?.attributes.start_farm) {
|
||||
setTypeButton('pending');
|
||||
} else if (remainingTime && playerStore?.attributes.start_farm) {
|
||||
setTypeButton('farming');
|
||||
} else if (!remainingTime && playerStore?.attributes.start_farm) {
|
||||
setTypeButton('claim_reward');
|
||||
}
|
||||
}, [remainingTime, playerStore]);
|
||||
|
||||
const handleStartFarming = useCallback(async () => {
|
||||
if (!token || !playerStore) {
|
||||
return;
|
||||
}
|
||||
const api = PlayerApi.getInstance(token);
|
||||
const updatedPlayer = await api.startFarm(new Date(), playerStore.id);
|
||||
setPlayer(updatedPlayer);
|
||||
}, [playerStore]);
|
||||
|
||||
const handleClaimRewards = useCallback(async () => {
|
||||
if (!token || !playerStore || !configStore) {
|
||||
return;
|
||||
}
|
||||
const api = PlayerApi.getInstance(token);
|
||||
// TODO: улучшить безопасность в методе claimRewards
|
||||
const updatedPlayer = await api.claimRewards(
|
||||
playerStore.id,
|
||||
toFixed(playerStore?.attributes.balance) + configStore?.attributes.farm_amount,
|
||||
);
|
||||
setPlayer(updatedPlayer);
|
||||
}, [playerStore, configStore]);
|
||||
|
||||
return (
|
||||
<Home
|
||||
config={configStore}
|
||||
isLoading={isLoading}
|
||||
typeButton={typeButton}
|
||||
remainingTime={FormatTime(remainingTime)}
|
||||
handleStartFarming={handleStartFarming}
|
||||
handleClaimRewards={handleClaimRewards}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default HomeContainer;
|
||||
Reference in New Issue
Block a user