added tailwind

parent fac8d15e
......@@ -3,6 +3,7 @@ import HomePage from './containers/HomePage';
import {BrowserRouter, Routes, Route} from 'react-router-dom';
import Layout from './components/Layout/Layout';
import Albums from './containers/Albums';
import Tracks from './containers/Tracks';
const App = () => {
return (
......@@ -11,6 +12,7 @@ const App = () => {
<Route path="/" element={<Layout />}>
<Route index element={<HomePage />} />
<Route path="albums" element={<Albums />} />
<Route path="tracks" element={<Tracks />} />
</Route>
</Routes>
</BrowserRouter>
......
......@@ -2,7 +2,11 @@ import React from 'react';
import {Outlet} from 'react-router-dom';
const Layout = () => {
return <Outlet />;
return (
<div className="container mx-auto px-96">
<Outlet />
</div>
);
};
export default Layout;
......@@ -2,13 +2,15 @@ import React, {useEffect} from 'react';
import {getAlbumsByQueryParams} from '../features/album/albumSlice';
import {useAppDispatch, useAppSelector} from '../store/hooks';
import {useLocation} from 'react-router-dom';
import {useNavigate} from 'react-router-dom';
const Albums = () => {
const Albums: React.FunctionComponent = (): React.ReactElement => {
const {albums} = useAppSelector((state) => state.album);
const dispatch = useAppDispatch();
const params = new URLSearchParams(window.location.search);
const artist = params.get('artist');
const {state} = useLocation();
const navigate = useNavigate();
useEffect(() => {
dispatch(getAlbumsByQueryParams(artist!));
......@@ -16,20 +18,33 @@ const Albums = () => {
return (
<div>
<h2 className="mt-0 mb-2 text-4xl font-medium leading-tight ">Albums</h2>
<h2>{state.artist}</h2>
{albums.map((album) => {
return (
<div key={album._id}>
<img
className="w-48 h-48 object-cover "
src={`${import.meta.env.VITE_MY_URL}/${album.image}`}
alt={album.name}
/>
<p>{album.name}</p>
<p>{album.year}</p>
</div>
);
})}
<div className="flex flex-wrap gap-10 justify-between ">
{albums.length ? (
albums.map((album) => {
return (
<div key={album._id}>
<img
onClick={() =>
navigate(
{pathname: '/tracks', search: `?album=${album._id}`},
{state: {album: album.name, artist: state.artist}}
)
}
className="w-48 h-48 object-cover "
src={`${import.meta.env.VITE_MY_URL}/${album.image}`}
alt={album.name}
/>
<p>{album.name}</p>
<p>{album.year}</p>
</div>
);
})
) : (
<p>No albums yet</p>
)}
</div>
</div>
);
};
......
......@@ -9,29 +9,38 @@ const HomePage = () => {
const navigate = useNavigate();
useEffect(() => {
dispatch(getArtists());
setInterval(() => {
dispatch(getArtists());
}, 1000);
}, [dispatch]);
return (
<div>
{artists.map((artist) => {
return (
<div key={artist._id}>
<img
onClick={() =>
navigate(
{pathname: '/albums', search: `?artist=${artist._id}`},
{state: {artist: artist.name}}
)
}
className="w-48 h-48 object-cover "
src={`${import.meta.env.VITE_MY_URL}/${artist.photo}`}
alt={artist.name}
/>
<span>{artist.name}</span>
</div>
);
})}
<h2 className="mt-0 mb-2 text-4xl font-medium leading-tight ">Artists</h2>
<div className="flex flex-wrap gap-10 justify-between ">
{artists.length ? (
artists.map((artist) => {
return (
<div key={artist._id}>
<img
onClick={() =>
navigate(
{pathname: '/albums', search: `?artist=${artist._id}`},
{state: {artist: artist.name}}
)
}
className="w-56 h-56 object-cover "
src={`${import.meta.env.VITE_MY_URL}/${artist.photo}`}
alt={artist.name}
/>
<span>{artist.name}</span>
</div>
);
})
) : (
<p>No Artist yet</p>
)}
</div>
</div>
);
};
......
import React, {useEffect} from 'react';
import {useLocation} from 'react-router-dom';
import {getTracksByQuery} from '../features/track/trackSlice';
import {useAppDispatch, useAppSelector} from '../store/hooks';
const Tracks = () => {
const {state} = useLocation();
const {tracks} = useAppSelector((state) => state.track);
const dispatch = useAppDispatch();
const params = new URLSearchParams(window.location.search);
const album = params.get('album');
useEffect(() => {
dispatch(getTracksByQuery(album!));
}, [dispatch]);
return (
<div>
<h2 className="mt-0 mb-2 text-4xl font-medium leading-tight ">Tracks</h2>
<h2>{state.artist}</h2>
<h2>{state.album}</h2>
<div className="flex flex-col gap-6 pt-4">
{tracks.length ? (
tracks.map((track) => {
return (
<div
className="border border-solid color border-black p-4"
key={track._id}
>
<p>Track number: {track.seq.toString()}</p>
<p>Track name: {track.name}</p>
<p>Track duration: {track.duration}</p>
</div>
);
})
) : (
<p>No Tracks Yet</p>
)}
</div>
</div>
);
};
export default Tracks;
import {createAsyncThunk, createSlice} from '@reduxjs/toolkit';
import type {PayloadAction} from '@reduxjs/toolkit';
import {RootState} from '../../store/store';
import axios from 'axios';
import ITrack from '../../interfaces/ITrack';
interface TrackState {
tracks: ITrack[];
loading: boolean;
}
const initialState: TrackState = {
tracks: [],
loading: false,
};
export const getTracksByQuery = createAsyncThunk(
'getTracksByQuery',
async (albumId: string) => {
const res = await axios.get(`${import.meta.env.VITE_MY_URL}/tracks`, {
params: {
album: albumId,
},
});
return res.data;
}
);
export const trackSlice = createSlice({
name: 'track',
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(getTracksByQuery.pending, (state, action) => {
state.loading = true;
})
.addCase(getTracksByQuery.rejected, (state, action) => {
state.loading = false;
})
.addCase(
getTracksByQuery.fulfilled,
(state, {payload}: PayloadAction<ITrack[]>) => {
console.log(payload);
state.tracks = payload;
}
);
},
});
export const {} = trackSlice.actions;
export const selectAlbums = (state: RootState) => state.track.tracks;
export default trackSlice.reducer;
export default interface ITrack {
name: string;
album: string;
duration: string;
seq: Number;
_id: string;
}
import {configureStore} from '@reduxjs/toolkit';
import albumSlice from '../features/album/albumSlice';
import artistSlice from '../features/artist/artistSlice';
import trackSlice from '../features/track/trackSlice';
export const store = configureStore({
reducer: {
artist: artistSlice,
album: albumSlice,
track: trackSlice,
},
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment