Это полное фиаско

This commit is contained in:
Аришина) 2024-09-20 17:04:13 +04:00
parent 19a608b934
commit 73954d9d5a
23 changed files with 412 additions and 110 deletions

1
.env
View File

@ -1 +1,2 @@
REACT_APP_DATABASE='http://localhost:3000/'
REACT_APP_RECAPTCHA_SITE_KEY='6LcZ-kkqAAAAAFdmy2tD1gKFdjxb0D71w5VMaisr'

View File

@ -1,2 +1,18 @@
# PromoCursed
ВАЖНАЯ ИНФОРМАЦИЯ!!!
По какой-то причине при передаче объекта песни в CurrentTrack и получение свойств объекта в этом компонента
появляются ошибки. Их не было до какого-то момента, но я не успел к сроку выявить причины (я долго дебажил),
но результата это не принесло. До сих пор причины для меня остаются, к сожалению, загадкой...
Что было добавлено/исправлено после очной демонстрации:
1. Компоненты были раскиданы по папкам
2. Переименовал некоторые папки (например, API),
3. Добавил новые компоненты
4. Роутинг и страницы
5. Валидация форм
Должен был добавить плеер с воспроизведением песен, но из-за ошибок, про которые я написал выше, не удалось.
Пришлось жестко передать объект песни прямо в коде компонента.

View File

@ -7,7 +7,7 @@
"band_name": "Nevroz",
"albumid": "1",
"album_name": "Album 1",
"source": "source_path",
"source": "/src/songs/Nirvana_-_Smells_Like_Teen_Spirit_75941061.mp3",
"cover": "https://cdn1.ozone.ru/s3/multimedia-t/6893834213.jpg",
"playlists": [
"1",
@ -23,7 +23,7 @@
"band_name": "Nevroz",
"albumid": "1",
"album_name": "Album 1",
"source": "source_path",
"source": "/src/songs/Blur_-_Song_2_47967381.mp3",
"cover": "https://cdn1.ozone.ru/s3/multimedia-t/6893834213.jpg",
"playlists": [
"2"
@ -38,7 +38,7 @@
"band_name": "noizemchik",
"albumid": "2",
"album_name": "Ругань из-за Стёпы",
"source": "source_path",
"source": "/src/songs/Noice_MC_-_Rugan_iz-za_steny_63872179.mp3",
"cover": "https://sun9-11.userapi.com/impg/yfCwuWXI6NkFVC2HvMlegM2qWLlenkeiiRyvNQ/jpH8m1wlLqs.jpg?size=604x604&quality=95&sign=60a1d1877b49631fb6078db88715fc88&c_uniq_tag=UKrig2vg02reyBH_ML0OKeqt5gm_2jpwEXD7NJBUXoQ&type=album"
,
"playlists": [
@ -54,7 +54,7 @@
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "/src/songs/DSPD_-_Crazy_Frog_75801748.mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"2", "3"
@ -69,7 +69,7 @@
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"3"
@ -84,7 +84,7 @@
"band_name": "Nevroz",
"albumid": "1",
"album_name": "Album 1",
"source": "source_path",
"source": "/src/songs/Nirvana_-_Smells_Like_Teen_Spirit_75941061.mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"1", "2"
@ -99,7 +99,7 @@
"band_name": "Nevroz",
"albumid": "1",
"album_name": "Album 1",
"source": "source_path",
"source": "/src/songs/Blur_-_Song_2_47967381.mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"2"
@ -114,7 +114,7 @@
"band_name": "noizemchik",
"albumid": "2",
"album_name": "Ругань из-за Стёпы",
"source": "source_path",
"source": "/src/songs/Noice_MC_-_Rugan_iz-za_steny_63872179.mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh"
,
"playlists": [
@ -130,7 +130,7 @@
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "/src/songs/DSPD_-_Crazy_Frog_75801748.mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"2", "3"
@ -145,7 +145,7 @@
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"3"
@ -160,7 +160,7 @@
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"3"
@ -175,7 +175,7 @@
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"3"
@ -190,7 +190,7 @@
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"3"
@ -205,7 +205,7 @@
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"3"
@ -220,7 +220,7 @@
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"3"
@ -235,7 +235,7 @@
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"3"
@ -250,7 +250,7 @@
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "/src/songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
"cover": "https://avatars.yandex.net/get-music-content/10129881/f3cf1afc.a.30561322-1/m1000x1000?webp=falseh",
"playlists": [
"3"

38
package-lock.json generated
View File

@ -26,6 +26,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-dotenv": "^0.1.3",
"react-google-recaptcha": "^3.1.0",
"react-router-dom": "^6.26.2",
"react-scripts": "5.0.1",
"styled-components": "^6.1.12",
@ -46,6 +47,7 @@
"@storybook/react-webpack5": "^8.2.9",
"@storybook/test": "^8.2.9",
"@types/node-fetch": "^2.6.11",
"@types/react-google-recaptcha": "^2.1.9",
"eslint-plugin-storybook": "^0.8.0",
"prop-types": "^15.8.1",
"storybook": "^8.2.9",
@ -9518,6 +9520,16 @@
"@types/react": "*"
}
},
"node_modules/@types/react-google-recaptcha": {
"version": "2.1.9",
"resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.9.tgz",
"integrity": "sha512-nT31LrBDuoSZJN4QuwtQSF3O89FVHC4jLhM+NtKEmVF5R1e8OY0Jo4//x2Yapn2aNHguwgX5doAq8Zo+Ehd0ug==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-transition-group": {
"version": "4.4.11",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz",
@ -24607,6 +24619,19 @@
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
"license": "MIT"
},
"node_modules/react-async-script": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz",
"integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==",
"license": "MIT",
"dependencies": {
"hoist-non-react-statics": "^3.3.0",
"prop-types": "^15.5.0"
},
"peerDependencies": {
"react": ">=16.4.1"
}
},
"node_modules/react-colorful": {
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz",
@ -24948,6 +24973,19 @@
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==",
"license": "MIT"
},
"node_modules/react-google-recaptcha": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz",
"integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==",
"license": "MIT",
"dependencies": {
"prop-types": "^15.5.0",
"react-async-script": "^1.2.0"
},
"peerDependencies": {
"react": ">=16.4.1"
}
},
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",

View File

@ -21,6 +21,7 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-dotenv": "^0.1.3",
"react-google-recaptcha": "^3.1.0",
"react-router-dom": "^6.26.2",
"react-scripts": "5.0.1",
"styled-components": "^6.1.12",
@ -74,6 +75,7 @@
"@storybook/react-webpack5": "^8.2.9",
"@storybook/test": "^8.2.9",
"@types/node-fetch": "^2.6.11",
"@types/react-google-recaptcha": "^2.1.9",
"eslint-plugin-storybook": "^0.8.0",
"prop-types": "^15.8.1",
"storybook": "^8.2.9",

View File

@ -20,6 +20,10 @@
href="https://fonts.googleapis.com/css2?family=Permanent+Marker&display=swap"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&amp;display=swap"
rel="stylesheet"
/>
<title>React App</title>
<script id="react-dotenv" src="./env.js"></script>

View File

@ -85,21 +85,17 @@
}
.AdBlock {
border-top: none !important;
border-bottom: none !important;
}
.song-table-row {
border: #61dafb !important;
border-style: solid !important;
border-width: 1px !important;
border-radius: 5px !important;
}
.song-table-row:hover {
border: #61dafb !important;
border-style: solid !important;
border-width: 1px !important;
border-radius: 5px !important;
outline: #9b9b9b solid 1px !important;
outline-offset: -1px !important;
}
@ -159,3 +155,30 @@
font-weight: 400;
font-size: 42px;
}
.login {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 20px;
height: 100%;
width: 40%;
font-size: 24px;
background-color: #fff;
margin: 200px;
}
.login-button {
font-family: 'Roboto', sans-serif;
}
.login-button:hover {
background-color: transparent !important;
border-color: #ad0000 !important;
color: #ad0000 !important;
}
.bg-gradient {
background-image: linear-gradient(-45deg, red 0%, yellow 25%, yellow 51%, #ad0000 100%);
}

View File

@ -24,46 +24,14 @@ import { Profilepage } from './pages/Profilepage';
import { Layout } from './components/layoutComponents/Layout';
function App() {
const [songs, setSongs] = React.useState<ISong[]>([]);
const [albums, setAlbums] = React.useState<IAlbum[]>([]);
const [genres, setGenres] = React.useState<IGenre[]>([]);
const [bands, setBands] = React.useState<IBand[]>([]);
const [playlists, setPlaylist] = React.useState<IPlaylist[]>([]);
const [ads, setAds] = React.useState<IAdvertisement[]>([]);
async function fetchData() {
const responseSongs = getSongs();
// const responseAlbums = await axios.get<IAlbum[]>('http://localhost:3000/albums');
const responseGenres = getGenres();
// const responseBands = await axios.get<IBand[]>('http://localhost:3000/bands');
const responsePlaylists = getPlaylists();
const responseAds = getAds();
setSongs((await responseSongs).data);
// setAlbums(responseAlbums.data);
setGenres((await responseGenres).data);
// setBands(responseBands.data);
setPlaylist((await responsePlaylists).data);
setAds((await responseAds).data);
}
useEffect(
() => {
fetchData();
},
[]
)
const song = songs[1];
return (
<div className="App bg-slate-100">
<div id="app" className='bg-white'>
<div id="app" className='bg-gradient'>
<Routes>
<Route path='/' element={<Layout />}>
<Route index element={<Homepage playlists={playlists} songs={songs} genres={genres} albums={albums} ads={ads} />} />
<Route index element={<Homepage />} />
<Route path='login' element={<Loginpage />} />
<Route path='register' element={<Registerpage />} />
<Route path='profile' element={<Profilepage />} />

View File

@ -1,7 +1,10 @@
import React, { useEffect } from "react";
import { IAdvertisement } from "../../models/IModels";
import { AdCard } from "../cardComponents/AdCard";
import { getAds } from "../../API/api";
export function AdBlock({ads}: {ads: IAdvertisement[]}) {
export function AdBlock({ads}: {ads: any[]}) {
return (
<div className="AdBlock border-solid border-2 border-slate-100" style={{height: 'auto', minHeight: '100%', width: '30%'}}>
{ads.map(ad => <AdCard key={ad.id} ad={ad} />)}

View File

@ -18,17 +18,17 @@ export function MenuBlock({playlists, songs, albums, genres}: MenuBlockProps) {
const chartTab = {
label: 'Чарт',
key: 'Chart',
children: songs? <SongsBlock songs={songs}/> : null
children: songs? <SongsBlock /> : null
};
const playlistsTab = {
label: 'Плейлисты',
key: 'Playlists',
children: playlists && genres ? <FullPlaylistBlock {...{playlists, genres}}/> : null
children: playlists && genres ? <FullPlaylistBlock playlists={playlists} genres={genres}/> : null
};
const newSongsTab = {
label: 'Новинки',
key: 'New',
children: songs? <SongsBlock songs={songs}/> : null
children: songs? <SongsBlock /> : null
};
const tabs = [chartTab, playlistsTab, newSongsTab];

View File

@ -1,8 +1,9 @@
import { IGenre, IPlaylist } from "../../models/IModels";
import { getPlaylistsByGenre } from "../../API/api";
import { getGenres, getPlaylists, getPlaylistsByGenre } from "../../API/api";
import { PlaylistsBlock } from "./PlaylistsBlock";
import React, { useEffect } from "react";
export function FullPlaylistBlock({playlists}: {playlists: IPlaylist[]}, {genres}: {genres: IGenre[]}) {
export function FullPlaylistBlock({playlists, genres}: {playlists: IPlaylist[], genres: IGenre[]}) {
let genres_list: string[] = [];

View File

@ -5,9 +5,21 @@ import { Track } from '../songComponents/Track';
import axios from 'axios';
import { Table, Button, Empty } from 'antd';
import { PlayCircleFilled, PlayCircleOutlined } from '@ant-design/icons';
import { getSongs } from '../../API/api';
export function SongsBlock({songs}: {songs: ISong[]}) {
export function SongsBlock() {
const [songs, setSongs] = useState<ISong[]>([]);
const fetchData = async () => {
const response = getSongs();
setSongs((await response).data);
};
useEffect(() => {
fetchData();
}, []);
const columns = [
{
@ -50,10 +62,10 @@ export function SongsBlock({songs}: {songs: ISong[]}) {
]
return (
<div className="song-block flex bg-white border-solid border-2 border-slate-100">
<div className="song-block flex border-slate-100">
<Table
style={{width: '100%' }}
style={{width: '100%', backgroundColor: 'transparent'}}
className="songs-table menu-block"
dataSource={songs.map((s: ISong) => ({...s, play: ''}))}
columns={columns}

View File

@ -1,8 +1,10 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { Button, Col, Grid, Row, Table } from 'antd';
import { BackwardFilled, FastForwardFilled, FastBackwardFilled, PlayCircleFilled, PlayCircleOutlined, StepBackwardFilled, StepForwardFilled, HeartOutlined, ShareAltOutlined } from '@ant-design/icons';
import { BackwardFilled, FastForwardFilled, FastBackwardFilled, PlayCircleFilled, PlayCircleOutlined, StepBackwardFilled, StepForwardFilled, HeartOutlined, ShareAltOutlined, PauseCircleFilled, PauseCircleOutlined } from '@ant-design/icons';
import { ISong, SongProps } from '../../models/IModels';
import styled from 'styled-components'
import useSound from 'use-sound';
import { getSongs } from '../../API/api';
const Song = styled.div`
align-items: center;
@ -10,16 +12,22 @@ const Song = styled.div`
bottom: 0;
width: 75%;`
export function CurrentTrack() {
type CurrentSongProps = {
song: ISong
isPlayingVariable: boolean
}
const song = {
export function CurrentTrack({song, isPlayingVariable}: CurrentSongProps) {
song = {
"id": "5",
"song_name": "Кем я стал",
"band_id": "3",
"band_name": "DSPD",
"albumid": "3",
"album_name": "Album 3",
"source": "source_path",
"source": "../../songs/DSPD feat. даня хренников - Кем я стал_(audio-lord.ru).mp3",
"cover": "https://avatars.yandex.net/get-music-content/6058982/7e431a83.a.23910092-1/m1000x1000?webp=false",
"playlists": [
"3",
@ -29,13 +37,27 @@ export function CurrentTrack() {
};
const [isPlaying, setIsPlaying] = useState(isPlayingVariable);
const [play, { pause, duration, sound }] = useSound(song.source, {volume: 0.5});
const playingButton = () => {
if (isPlaying) {
pause();
setIsPlaying(false);
} else {
play();
setIsPlaying(true);
}
};
return (
<Song >
<div className='current-track'>
<Row className='w-full h-full bg-white opacity-90 rounded' style={{display: 'flex', alignItems: 'center'}}>
<Col span={4} className='flex flex-direction-row justify-center'>
<Button type='link' icon={<FastBackwardFilled className='player-button' />}></Button>
<Button type="link" icon={<PlayCircleOutlined className='player-button' />}></Button>
<Button type="link" icon={isPlaying ? <PauseCircleOutlined className='player-button' onClick={playingButton}/> : <PlayCircleOutlined className='player-button' onClick={playingButton}/>}></Button>
<Button type="link" icon={<FastForwardFilled className='player-button' style={{fontSize: 30}} />}></Button>
</Col>
<Col style={{width: 80}}>

View File

@ -4,15 +4,9 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
font-family: 'Roboto', sans-serif !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-image: url('https://www.fonstola.ru/images/201301/fonstola.ru_86743.jpg');
background-repeat: no-repeat;
background-size: cover;
}
code {
@ -34,3 +28,75 @@ footer {
bottom: 0;
width: 100%;
}
.roboto-thin {
font-family: "Roboto", sans-serif;
font-weight: 100;
font-style: normal;
}
.roboto-light {
font-family: "Roboto", sans-serif;
font-weight: 300;
font-style: normal;
}
.roboto-regular {
font-family: "Roboto", sans-serif;
font-weight: 400;
font-style: normal;
}
.roboto-medium {
font-family: "Roboto", sans-serif;
font-weight: 500;
font-style: normal;
}
.roboto-bold {
font-family: "Roboto", sans-serif;
font-weight: 700;
font-style: normal;
}
.roboto-black {
font-family: "Roboto", sans-serif;
font-weight: 900;
font-style: normal;
}
.roboto-thin-italic {
font-family: "Roboto", sans-serif;
font-weight: 100;
font-style: italic;
}
.roboto-light-italic {
font-family: "Roboto", sans-serif;
font-weight: 300;
font-style: italic;
}
.roboto-regular-italic {
font-family: "Roboto", sans-serif;
font-weight: 400;
font-style: italic;
}
.roboto-medium-italic {
font-family: "Roboto", sans-serif;
font-weight: 500;
font-style: italic;
}
.roboto-bold-italic {
font-family: "Roboto", sans-serif;
font-weight: 700;
font-style: italic;
}
.roboto-black-italic {
font-family: "Roboto", sans-serif;
font-weight: 900;
font-style: italic;
}

View File

@ -24,15 +24,16 @@ export interface IGenre {
export interface ISong {
id: string
song_name: string;
band_name: string;
cover: string;
genreid: string;
albumid: string;
source: string;
band_id: string;
band_name: string;
albumid: string;
album_name: string;
genre_name: string;
source: string;
cover: string;
playlists: string[];
genreid: string;
genre_name: string;
}
export interface IPlaylist {

View File

@ -1,10 +1,45 @@
import React, { useEffect, useState } from "react";
import { getSongs, getGenres, getPlaylists, getAds } from "../API/api";
import { AdBlock } from "../components/layoutComponents/AdBlock";
import { MenuBlock } from "../components/layoutComponents/MenuBlock";
import { CurrentTrack } from "../components/songComponents/CurrentTrack";
import { IPlaylist, ISong, IAlbum, IGenre, IAdvertisement } from "../models/IModels";
import { IPlaylist, ISong, IAlbum, IGenre, IAdvertisement, IBand } from "../models/IModels";
export function Homepage() {
const [albums, setAlbums] = useState<IAlbum[]>([]);
const [bands, setBands] = useState<IBand[]>([]);
const [songs, setSongs] = useState<ISong[]>([]);
const [ads, setAds] = useState<IAdvertisement[]>([]);
const [playlists, setPlaylist] = React.useState<IPlaylist[]>([]);
const [genres, setGenres] = React.useState<IGenre[]>([]);
const fetchData = async () => {
const [responseSongs, responseAds, responsePlaylists, responseGenres] = await Promise.all([
getSongs(),
getAds(),
getPlaylists(),
getGenres(),
]);
setSongs(responseSongs.data);
setAds(responseAds.data);
setPlaylist(responsePlaylists.data);
setGenres(responseGenres.data);
};
useEffect(() => {
fetchData();
}, []);
export function Homepage({playlists, songs, genres, albums, ads}: {playlists: IPlaylist[], songs: ISong[], genres: IGenre[], albums: IAlbum[], ads: IAdvertisement[]}) {
return (
<><MenuBlock playlists={playlists} songs={songs} albums={albums} genres={genres} /><AdBlock ads={ads} /><CurrentTrack /></>
<>
<MenuBlock playlists={[]} songs={songs} albums={albums} genres={[]}/><AdBlock ads={ads}/>
<CurrentTrack song={songs[0]} isPlayingVariable={false} />
</>
);
}

View File

@ -1,32 +1,53 @@
import { Form } from 'antd'
import { LockOutlined, MailOutlined } from '@ant-design/icons';
import { Form, Input, Button, Checkbox } from 'antd'
import { Link } from 'react-router-dom';
export function Loginpage() {
return (
<div className="container mx-auto" style={{height: 'auto', width: '100%', display: 'flex', justifyContent: 'center', backgroundImage: "url('https://www.google.com/url?sa=i&url=https%3A%2F%2Fwallpapers.99px.ru%2Fwallpapers%2F32630%2F&psig=AOvVaw1t52LawgmuRVrJhHsKhhe8&ust=1726831156597000&source=images&cd=vfe&opi=89978449&ved=0CBQQjRxqFwoTCNC43L7xzogDFQAAAAAdAAAAABAE')"}}>
<div className='sb-login rounded bg-black'>
<div className="container mx-auto" style={{height: '200%', width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<div className='login' >
<Form>
<p>Вход</p>
<Form.Item style={{margin: '140px'}}>
<p className='text-3xl' style={{ fontFamily: 'Roboto', marginTop: '100px', marginBottom: '50px'}}>Вход</p>
<Form.Item style={{marginBottom: '50px'}}>
<Form.Item
name="username"
rules={[{ required: true, message: 'Please input your username!' }]}
style={{padding: '20px'}}
name="email"
rules={[{ required: true, message: 'Введите вашу почту!' }, { type: 'email', message: 'Некорректный формат' }]}
style={{ fontFamily: 'Roboto'}}
>
<input
<Input
prefix={<MailOutlined className="site-form-item-icon" />}
type="text"
placeholder="Username"
placeholder="Почта"
/>
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: 'Please input your password!' }]}
style={{padding: '20px'}}
rules={[{ required: true, message: 'Введите пароль!!' }, { min: 8, message: 'Пароль должен быть длиной минимум 8 символов' }]}
style={{ fontFamily: 'Roboto'}}
>
<input
<Input
prefix={<LockOutlined className="site-form-item-icon" />}
type="password"
placeholder="Password"
placeholder="Пароль"
/>
<Button type='link' href=''>Забыли пароль?</Button>
</Form.Item>
<Form.Item>
<Form.Item name="remember" valuePropName="checked" noStyle />
<Button type="primary" className='bg-red-800 login-button hover:bg-transparent' htmlType="submit" style={{marginRight:'10px'}}>
Войти
</Button>
<Checkbox style={{marginLeft:'10px'}}>Запомнить меня</Checkbox>
</Form.Item>
<Form.Item>
<Form.Item name="submit" noStyle>
</Form.Item>
</Form.Item>
<Form.Item>
<Form.Item name="noaccount" noStyle>
<Link to={'../register'}>Нет аккаунта?</Link>
</Form.Item>
</Form.Item>
</Form.Item>
</Form>

View File

@ -1,7 +1,96 @@
import { MailOutlined, LockOutlined } from "@ant-design/icons";
import { Form, Input, Button, Checkbox } from "antd";
import { Link } from "react-router-dom";
import ReCAPTCHA from "react-google-recaptcha";
import React, { useState } from "react";
import FormItem from "antd/es/form/FormItem";
export function Registerpage() {
const [verified, setVerified] = useState(false);
function onChange(value: any) {
console.log("Captcha value:", value);
setVerified(true);
}
return (
<div className="container mx-auto bg-slate-300" style={{height: 300, width: '75%'}}>
<p>Регистрация</p>
<div className="container mx-auto" style={{height: '200%', width: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center'}}>
<div className='login' >
<Form>
<p className='text-3xl' style={{ fontFamily: 'Roboto', marginTop: '100px', marginBottom: '50px'}}>Вход</p>
<Form.Item style={{marginBottom: '50px'}}>
<Form.Item
name="email"
rules={[{ required: true, message: 'Введите вашу почту!' }, { type: 'email', message: 'Некорректный формат' }]}
style={{ fontFamily: 'Roboto'}}
>
<Input
prefix={<MailOutlined className="site-form-item-icon" />}
type="text"
placeholder="Почта"
/>
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true, message: 'Введите пароль!!' }, { min: 8, message: 'Пароль должен быть длиной минимум 8 символов' }]}
style={{ fontFamily: 'Roboto'}}
>
<Input
prefix={<LockOutlined className="site-form-item-icon" />}
type="password"
placeholder="Пароль"
/>
</Form.Item>
<Form.Item
name="password2"
rules={[{ required: true, message: 'Заполните поле!' }, ({ getFieldValue }) => ({
validator(_, value) {
if (value === getFieldValue('password')) {
return Promise.resolve();
}
return Promise.reject('Пароли должны совпадать!');
},
})]}
style={{ fontFamily: 'Roboto'}}
>
<Input
prefix={<LockOutlined className="site-form-item-icon" />}
type="password"
placeholder="Повторите пароль"
/>
</Form.Item>
<Form.Item>
<ReCAPTCHA
sitekey={process.env.REACT_APP_RECAPTCHA_SITE_KEY as string}
onChange={onChange}
style={{marginTop: '10px'}}
/>
</Form.Item>
<Form.Item>
<Form.Item name="remember" valuePropName="checked" noStyle />
<Button type="primary" disabled={!verified} className='bg-red-800 login-button hover:bg-transparent' htmlType="submit" style={{marginRight:'10px'} }>
Регистрация
</Button>
<Checkbox style={{marginLeft:'10px'}}>Запомнить меня</Checkbox>
</Form.Item>
<Form.Item>
<Form.Item name="submit" noStyle>
</Form.Item>
</Form.Item>
<Form.Item>
<Form.Item name="noaccount" noStyle>
<Link to={'../login'}>Уже есть аккаунт?</Link>
</Form.Item>
</Form.Item>
</Form.Item>
</Form>
</div>
</div>
);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.