Skip to content

Commit

Permalink
feat: add Recommendation, Banner logic
Browse files Browse the repository at this point in the history
  • Loading branch information
uniquemo committed May 3, 2020
1 parent a5b9210 commit 5c01f03
Show file tree
Hide file tree
Showing 9 changed files with 237 additions and 15 deletions.
18 changes: 16 additions & 2 deletions src/apis/personalized.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import axios from 'helpers/axios'
import { IGetPersonalizedSongListRequest, ISongList, IMusic, IMV } from './types/personalized'
import { IGetPersonalizedSongListRequest, ISongList, IMusic, IMV, IBanner } from './types/personalized'

type GetPersonalizedSongListFn = (params: IGetPersonalizedSongListRequest) => Promise<ISongList[]>
type GetPersonalizedNewMusicFn = () => Promise<IMusic[]>
type GetPersonalizedMVFn = () => Promise<IMV[]>
type GetBannerFn = () => Promise<IBanner[]>

const getPersonalizedSongList: GetPersonalizedSongListFn = async ({ limit }) => {
const response = await axios({
Expand Down Expand Up @@ -35,8 +36,21 @@ const getPersonalizedMV: GetPersonalizedMVFn = async () => {
return response.result
}

const getBanner: GetBannerFn = async () => {
const response = await axios({
method: 'get',
url: '/banner',
params: {
type: 0
}
})

return response.banners
}

export default {
getPersonalizedSongList,
getPersonalizedNewMusic,
getPersonalizedMV
getPersonalizedMV,
getBanner
}
10 changes: 10 additions & 0 deletions src/apis/types/personalized.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,13 @@ export interface IMV {
subed: boolean,
type: number
}

export interface IBanner {
exclusive: boolean,
imageUrl: string,
targetId: number,
targetType: number,
titleColor: string,
typeTitle: string,
url: string
}
20 changes: 20 additions & 0 deletions src/hooks/useInterval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useEffect, useRef } from 'react'

const useInterval = (callback: Function, delay?: number | null) => {
const savedCallback = useRef<Function>(() => {})

useEffect(() => {
savedCallback.current = callback
})

useEffect(() => {
if (delay !== null) {
const interval = setInterval(() => savedCallback.current(), delay || 0)
return () => clearInterval(interval)
}

return undefined
}, [delay])
}

export default useInterval
23 changes: 23 additions & 0 deletions src/pages/Discovery/Recommendation/Banner/BannerItem/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react'
import cn from 'classnames'

import styles from './style.module.css'

interface IProps {
typeTitle: string,
imageUrl: string,
className?: string
}

const BannerItem: React.FC<IProps> = ({ typeTitle, imageUrl, className }) => {
return (
<div className={cn(styles.root, className)}>
<img src={imageUrl} />
<div className={styles.type}>
{typeTitle}
</div>
</div>
)
}

export default BannerItem
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
@value colors: "~styles/colors.module.css";
@value red from colors;

.root {
width: 50%;
padding-top: 18.52%;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 5px;
position: absolute;
cursor: pointer;
top: 0;
left: 50%;
transform: translate(-50%, 0);
transition: transform 1s ease;

img {
width: 100%;
height: 100%;
border-radius: 5px;
position: absolute;
top: 0;
left: 0;
}

.type {
padding: 3px 10px;
position: absolute;
bottom: 0;
right: 0;
background-color: red;
color: #fff;
font-size: 0.9em;
border-top-left-radius: 5px;
border-bottom-right-radius: 5px;
}
}
77 changes: 77 additions & 0 deletions src/pages/Discovery/Recommendation/Banner/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import React from 'react'
import { Spinner } from '@blueprintjs/core'
import cn from 'classnames'

import BannerItem from './BannerItem'

import useAsyncFn from 'hooks/useAsyncFn'
import useInterval from 'hooks/useInterval'
import personalizedApis from 'apis/personalized'

import styles from './style.module.css'

const { useEffect, useState, useMemo } = React

const Banner = () => {
const [currentMid, setCurrentMid] = useState(0)
const [state, getBannerFn] = useAsyncFn(personalizedApis.getBanner)
const { value: banners = [], loading: isGettingBanner } = state

useEffect(() => {
getBannerFn()
}, [])

useInterval(() => {
if (!banners.length) {
return
}
setCurrentMid((currentMid + 1) % banners.length)
}, 3000)

const bannersClassName = useMemo(() => {
const len = banners.length
const left = (currentMid - 1 + len) % len
const right = (currentMid + 1) % len
return {
[currentMid]: styles.middle,
[left]: styles.left,
[right]: styles.right
}
}, [currentMid, banners])

const handleMidChange = (index: number) => {
setCurrentMid(index)
}

return (isGettingBanner
? <Spinner />
: <div className={styles.root}>
<div className={styles.banners}>
{banners.map(({ imageUrl, typeTitle }, index) => {
const className = bannersClassName[index] || styles.hidden
return (
<BannerItem
key={imageUrl}
typeTitle={typeTitle}
imageUrl={imageUrl}
className={className}
/>
)
})}
</div>
<div className={styles.dots}>
{banners.map(({ imageUrl }, index) => {
return (
<div
key={imageUrl}
className={cn(styles.dot, index === currentMid ? styles.active : '')}
onMouseOver={() => handleMidChange(index)}
/>
)
})}
</div>
</div>
)
}

export default Banner
53 changes: 53 additions & 0 deletions src/pages/Discovery/Recommendation/Banner/style.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
@value colors: "~styles/colors.module.css";
@value tipsColor, red from colors;

.root {
position: relative;
padding-top: 22%;
margin-bottom: 20px;
}

.banners {
width: 100%;
position: absolute;
top: 0;
left: 0;
}

.middle {
transform: translate(-50%, 0) scale(1);
z-index: 2;
}

.left {
transform: translate(-110%, 0) scale(0.8);
}

.right {
transform: translate(10%, 0) scale(0.8);
}

.hidden {
transform: translate(-50%, 0) scale(1);
visibility: hidden;
}

.dots {
display: flex;
position: absolute;
bottom: 10px;
left: 50%;
transform: translate(-50%, 0);

.dot {
width: 7px;
height: 7px;
margin-right: 10px;
border-radius: 50%;
background-color: tipsColor;
}

.active {
background-color: red;
}
}
9 changes: 0 additions & 9 deletions src/pages/Discovery/Recommendation/Slider/index.tsx

This file was deleted.

6 changes: 2 additions & 4 deletions src/pages/Discovery/Recommendation/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react'
import Slider from './Slider'
import Banner from './Banner'
import SongList from './SongList'
import LatestMusic from './LatestMusic'
import MV from './MV'
Expand All @@ -9,9 +9,7 @@ import styles from './style.module.css'
const Recommendation = () => {
return (
<div className={styles.root}>
<div className={styles.block}>
<Slider />
</div>
<Banner />

<div className={styles.block}>
<SongList />
Expand Down

0 comments on commit 5c01f03

Please sign in to comment.