в боковой панели отображается информация о песнях

This commit is contained in:
Аришина) 2024-11-18 21:20:14 +04:00
parent 2fa22ec4c4
commit a74b994b07
12 changed files with 219 additions and 18 deletions

View File

@ -128,7 +128,7 @@
"id": "9",
"song_name": "Downstairs to Heaven",
"band_id": "3",
"band_name": "Эйси Диси",
"band_name": "AC/DC",
"albumid": "3",
"album_name": "Album 3",
"source": "http://localhost:3001/songs_sources/acdc.mp3",

View File

@ -41,4 +41,24 @@ export async function getAds() {
return await axios.get<IAdvertisement[]>(`${localhost}advertisements`);
}
export async function getAlbum(id: string) {
return await axios.get(`${localhost}albums/` + id);
}
export async function getAlbums() {
return await axios.get(`${localhost}albums/`);
}
export async function getBand(id: string) {
return await axios.get(`${localhost}bands/` + id);
}
export async function getBands() {
return await axios.get(`${localhost}bands/`);
}

View File

@ -207,4 +207,11 @@
.bg-gradient {
background-image: linear-gradient(-45deg, red 0%, orange 25%, orange 51%, #ad0000 100%);
}
.title-side-block {
font-size: 22px;
border-bottom: 2px solid #505050;
align-self: flex-start;
color: #505050;
}

View File

@ -10,6 +10,9 @@ import { Layout } from './components/layoutComponents/Layout';
import { CurrentSongProvider } from './contexts/SongContexts/SongContextProvider';
import { PlayingProvider } from './contexts/SongContexts/PlayingProvider';
import { VolumeProvider } from './contexts/VolumeContexts/VolumeProvider';
import { SideBlockProvider } from './contexts/SideBlockContexts/SideBlockProvider';
import { useState } from 'react';
import { IAdvertisement } from './models/IModels';
function App() {
@ -19,6 +22,7 @@ function App() {
<CurrentSongProvider songId=''>
<PlayingProvider isPlaying={false}>
<VolumeProvider volumeValue={30}>
<SideBlockProvider>
<Routes>
<Route path='/' element={<Layout />}>
<Route index element={<Homepage />} />
@ -27,6 +31,7 @@ function App() {
</Route>
</Routes>
</SideBlockProvider>
</VolumeProvider>
</PlayingProvider>
</CurrentSongProvider>

View File

@ -1,13 +1,19 @@
import React, { useEffect } from "react";
import { IAdvertisement } from "../../models/IModels";
import React, { ReactElement, useEffect } from "react";
import { IAdvertisement, IAlbum, IBand, ISong } from "../../models/IModels";
import { AdCard } from "../cardComponents/AdCard";
import { getAds } from "../../API/api";
import { useSideBlockContext } from '../../contexts/SideBlockContexts/SideBlockProvider';
import { InformationTemplate } from "../menuComponents/Templates/informationTemplate";
export function AdBlock({ads}: {ads: IAdvertisement[]}) {
export function AdBlock({ advertisements, object }: {object?: IAdvertisement | ISong | IBand | IAlbum | undefined, advertisements?: IAdvertisement[]}) {
const { contentObject } = useSideBlockContext();
return (
<div className="AdBlock border-solid border-2 border-slate-100" style={{height: 'auto', minHeight: '100%', width: '35%'}}>
{ads.map(ad => <AdCard key={ad.id} ad={ad} />)}
{object && <InformationTemplate obj={object}></InformationTemplate>}
</div>
);
}

View File

@ -8,6 +8,8 @@ import { getSongs } from '../../API/api';
import Title from 'antd/es/typography/Title';
import { GetColumns } from './Templates/songsTemplate';
import { GetColumnsWithNumber } from './Templates/numeredSongsTemplate';
import { usePlayingContext } from '../../contexts/SongContexts/PlayingProvider';
import { useCurrentSongContext } from '../../contexts/SongContexts/SongContextProvider';
// Функция для генерации номеров строк
const generateRowNumbers = (rows: any[]) =>
@ -17,6 +19,9 @@ export function ChartSongsBlock() {
const [songs, setSongs] = useState<ISong[]>([]);
const [numberedSongs, setNumberedSongs] = useState<ISong[]>([]);
const currentSongId = useCurrentSongContext();
const isPlaying = usePlayingContext();
const fetchData = async () => {
const response = await getSongs();
setSongs(response.data);
@ -37,7 +42,7 @@ export function ChartSongsBlock() {
columns={GetColumnsWithNumber(numberedSongs)}
showHeader={false}
pagination={false}
rowClassName={() => 'song-table-row chart-row'}
rowClassName={(record) => isPlaying ? (record.id === currentSongId.songId ? 'song-table-row-active' : 'song-table-row') : 'song-table-row'}
rowKey={(record) => record.id}
scroll={{ x: true }}
/>

View File

@ -1,26 +1,35 @@
import React, { useEffect, useState } from 'react';
import React, { useContext, useEffect, useState } from 'react';
import { render } from '@testing-library/react';
import {ISong} from '../../models/IModels';
import {IAlbum, IBand, ISong} from '../../models/IModels';
import axios from 'axios';
import { Table, Button, Empty } from 'antd';
import { Loading3QuartersOutlined, PlayCircleFilled, PlayCircleOutlined } from '@ant-design/icons';
import { getSongs } from '../../API/api';
import { getSongs, getBands, getAlbums } from '../../API/api';
import Title from 'antd/es/typography/Title';
import { GetColumns } from './Templates/songsTemplate';
import { Spin } from "antd";
import { useCurrentSongContext } from '../../contexts/SongContexts/SongContextProvider';
import { usePlayingContext } from '../../contexts/SongContexts/PlayingProvider';
import { useSideBlockContext } from '../../contexts/SideBlockContexts/SideBlockProvider';
export function NewSongsBlock() {
const [songs, setSongs] = useState<ISong[]>([]);
const [bands, setBands] = useState<IBand[]>([]);
const [albums, setAlbums] = useState<IAlbum[]>([]);
const currentSongId = useCurrentSongContext();
const isPlaying = usePlayingContext();
const { setContentObject } = useSideBlockContext();
const fetchData = async () => {
const response = getSongs();
setSongs((await response).data);
const responseSongs = getSongs();
const responseBands = getBands();
const responseAlbums = getAlbums();
setSongs((await responseSongs).data);
setBands((await responseBands).data);
setAlbums((await responseAlbums).data);
};
useEffect(() => {
@ -42,6 +51,26 @@ export function NewSongsBlock() {
rowClassName={(record) => isPlaying ? (record.id === currentSongId.songId ? 'song-table-row-active' : 'song-table-row') : 'song-table-row'}
rowKey={(s: ISong) => s.id}
rowHoverable={false}
onRow={(record) => ({
onClick: (event) => {
if (event.target instanceof HTMLTableCellElement && event.target.tagName === 'TD') {
let song = songs.find((s: ISong) => s.id === record.id)
switch (event.target.cellIndex) {
case 1:
setContentObject(song);
break;
case 2:
setContentObject(bands.find((b: IBand) => b.id === song?.band_id));
break;
case 3:
setContentObject(albums.find((a: IAlbum) => a.id === song?.albumid));
break;
}
}
},
})}
/>
</Spin>
</div>

View File

@ -0,0 +1,84 @@
import react from "react";
import { IAlbum, IBand, ISong, IAdvertisement } from "../../../models/IModels";
import { getSong, getAlbum, getBand } from "../../../API/api";
import Text from 'antd/es/typography/Text';
import { useSideBlockContext } from '../../../contexts/SideBlockContexts/SideBlockProvider';
import { AdCard } from "../../cardComponents/AdCard";
import { Loading3QuartersOutlined } from "@ant-design/icons";
import { Spin } from "antd";
export function InformationTemplate ({obj}: {obj: ISong | IBand | IAlbum | IAdvertisement | undefined}) {
function isAd(obj: any): obj is IAdvertisement {
return Array.isArray(obj) && obj.every(item =>
typeof item === 'object' &&
item !== null &&
'id' in item &&
'photo' in item
);
}
function isSong(obj: any): obj is ISong {
return typeof obj === 'object' &&
obj !== null &&
'id' in obj &&
'song_name' in obj;
}
function isAlbum(obj: any): obj is IAlbum {
return typeof obj === 'object' &&
obj !== null &&
'id' in obj &&
'name' in obj &&
'cover' in obj &&
'year' in obj;
}
function isBand(obj: any): obj is IBand {
return typeof obj === 'object' &&
obj !== null &&
'id' in obj &&
'name' in obj &&
'city' in obj;
}
const { contentObject } = useSideBlockContext();
switch (typeof obj) {
case 'object':
return (
<div className="flex container" style={{ display: 'flex'}}>
{isAd(obj) && Array.isArray(obj) ? obj.map((ad) => <AdCard ad={ad} key={ad.id} />) : null}
{isSong(obj) ?
<div>
<Text className="title-side-block">ТРЕК</Text>
<img
src={obj.cover} alt={obj.song_name} className="rounded m-auto" style={{ width: '50%'}}>
</img>
<Text>{obj.song_name}</Text>
</div>
: null}
{isBand(obj) ? <Text>{obj.name}</Text> : null}
{isAlbum(obj) ? <Text>{obj.name}</Text> : null}
</div>
)
case 'undefined':
return (
<div className="flex container" style={{flexDirection: 'column'}}>
<Spin indicator={<Loading3QuartersOutlined spin style={{color: '#9d0000', fontSize: 30}} />}/>
</div>
)
}
}

View File

@ -0,0 +1,11 @@
import React from "react";
export interface ISongTemplateInterface {
key: number;
title: string;
artist: string;
album: string;
image: string;
duration: string;
}

View File

@ -1,7 +1,7 @@
import { Button } from "antd";
import { ISong } from "../../../models/IModels";
import { useState } from "react";
import { height } from "@mui/system";
import { height, style } from "@mui/system";
import { useCurrentSongContext } from "../../../contexts/SongContexts/SongContextProvider";
import { usePlayingContext } from "../../../contexts/SongContexts/PlayingProvider";
@ -43,7 +43,8 @@ const useColumns = (songs: ISong[])=> {
title: '',
dataIndex: 'song_name',
key: 'song_name',
width: 400
width: 400,
render: (text: string, song: ISong) => <span style={{cursor: 'default'}}>{text}</span>
},
{
title: '',
@ -63,4 +64,4 @@ const useColumns = (songs: ISong[])=> {
export function GetColumns(songs: ISong[]) {
return useColumns(songs);
}
}

View File

@ -0,0 +1,32 @@
import React, { createContext, useContext, ReactNode, useState, ReactElement } from "react";
interface SideBlockProviderProps {
children: ReactElement;
contentObject ?: any;
}
interface SideBlockContextValue {
contentObject ?: any;
setContentObject: (contentObject: any) => void;
}
const SideBlockContext = createContext<SideBlockContextValue | undefined>(undefined);
export function SideBlockProvider({ children, contentObject }: SideBlockProviderProps) {
const [content, setContent] = useState(contentObject);
console.log(content);
return (
<SideBlockContext.Provider value={{ contentObject: content, setContentObject: setContent }}>
{children}
</SideBlockContext.Provider>
);
}
export const useSideBlockContext = function(): SideBlockContextValue {
const context = useContext(SideBlockContext);
if (context === undefined) {
throw new Error("useSideBlockContext must be used within a SideBlockProvider");
}
return context;
};

View File

@ -5,6 +5,7 @@ import { MenuBlock } from "../components/layoutComponents/MenuBlock";
import { CurrentTrack } from "../components/songComponents/CurrentTrack";
import { IPlaylist, ISong, IAlbum, IGenre, IAdvertisement, IBand } from "../models/IModels";
import { useCurrentSongContext } from "../contexts/SongContexts/SongContextProvider";
import { useSideBlockContext } from "../contexts/SideBlockContexts/SideBlockProvider";
export function Homepage() {
@ -12,12 +13,13 @@ export function Homepage() {
const [albums, setAlbums] = useState<IAlbum[]>([]);
const [songs, setSongs] = useState<ISong[]>([]);
const [ads, setAds] = useState<IAdvertisement[]>([]);
const [playlists, setPlaylist] = React.useState<IPlaylist[]>([]);
const [genres, setGenres] = React.useState<IGenre[]>([]);
const currentSongId = useCurrentSongContext();
const { contentObject, setContentObject } = useSideBlockContext();
const fetchData = async () => {
const [responseSongs, responseAds, responsePlaylists, responseGenres] = await Promise.all([
@ -35,15 +37,14 @@ export function Homepage() {
useEffect(() => {
fetchData();
setContentObject(ads);
}, []);
const currentSong = songs.find(song => song.id === currentSongId.songId);
console.log('Айди песни:');
return (
<>
<MenuBlock playlists={[]} songs={songs} albums={albums} genres={[]}/><AdBlock ads={ads}/>
<MenuBlock playlists={[]} songs={songs} albums={albums} genres={[]}/><AdBlock object={contentObject}/>
{currentSong && <CurrentTrack song={currentSong} songs={songs}/>}
</>