### API
```
export type LAYOUT_TYPE = 'user' | 'class' | 'category' | 'music' | 'hashtag';
export interface Classes {
id: number;
classCoverImage: string;
classTitle: string;
totalLearners: string;
rating: number;
}
export interface User {
id: number;
name: string;
username: string;
coverUrl: string;
}
export interface Categories {
id: number;
categoryCover: string;
name: string;
}
export interface Hashtag {
id: number;
coverUrl: string;
name: string;
}
export interface Music {
id: number;
coverUrl: string;
title: string;
artist: string;
file: {
fileDuration: number;
fileUrl: string;
};
}
export interface ListResponse<T> {
data: T[];
pagination?: {
page: number;
pageCount: number;
total: number;
};
}
export interface SectionItem<T> {
type: LAYOUT_TYPE;
title: string;
itemChild: ListResponse<T>;
}
export type ExploreRequestType = {
keywords?: string;
type: LAYOUT_TYPE;
page?: number;
per_page?: number;
title?:string;
};
```
### Reducer
```
import {ProfileItemType} from '../userProfile/reducer';
import {RootState} from '../../index';
import {createSlice, createAction, PayloadAction} from '@reduxjs/toolkit';
import {
Classes,
ListResponse,
Item,
Categories,
SectionItem,
Music,
Hashtag,
ExploreRequestType,
LAYOUT_TYPE,
User,
} from './api';
export interface SliceState {
section: {
[key in string]: SectionItem<Classes|User | Categories | Music | Hashtag>;
};
}
const initialState = {
section: {},
} as SliceState;
export const Slice = createSlice({
name: 'Section',
initialState,
reducers: {
updateDataSection(
state: SliceState,
action: PayloadAction<
SectionItem<Classes | Categories | User | Music | Hashtag>
>,
) {
let SectionId = action.payload.type;
if (action.payload.itemChild.data) {
if (action.payload.itemChild.pagination.page === 1) {
state.section[SectionId] = action.payload;
} else {
// TODO: loadmore with pagination > 1
}
} else {
state.section[SectionId] = action.payload;
}
},
},
});
export const getDataSection = createAction('section/getDataHomePage');
export const getDataUsersAction = createAction<ExploreRequestType>(
'section/getDataUsers',
);
export const getDataMusicsAction = createAction<ExploreRequestType>(
'section/getDataMusics',
);
export const getDataHashtagsAction = createAction<ExploreRequestType>(
'section/getDataHashtags',
);
export const getDataClassesAction = createAction('section/getDataClasses');
export const getDataCategoriesAction = createAction(
'explore/getDataCategories',
);
export const {updateDataSection} = Slice.actions;
export const selectDataSection = (
state: RootState,
type: LAYOUT_TYPE,
title?: string,
keyWord?: string //update later
) => {
// case 1 if this is load more list => update item of filter data
let SectionId = type;
// choose specially filteredData
let list: SectionItem<Classes | User | Categories | Music | Hashtag> = {
type,
title: title ?? '',
itemChild: {
data: [],
},
};
// if have a data in state, list equal data
if (state.Section.section[SectionId]) {
list = state.Section.section[SectionId];
}
return list;
};
export default Slice.reducer;
```
### Saga
```
import {put, call, debounce, takeLatest} from 'redux-saga/effects';
import {setLoading} from '../application/reducer';
import {handleError} from '@utils/apiProxy';
import {
getDataHashtagsAction,
getDataMusicsAction,
getDataUsersAction,
updateDataSection,
} from './reducer';
import {getRandom} from '@utils/common';
export function* musicHandler(action) {
try {
yield put(setLoading(true));
if (getDataMusicsAction.match(action)) {
let fakeData: any = [];
const randomUTitle = [
'Eleanor Rigby',
'Darling Nikki',
'Fernando',
'Gloria',
'Jack and Diane',
'Daniel',
'Buddy Holly',
'The Wind Cries Mary',
];
const tenItems = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
fakeData = tenItems.map(id => ({
id,
coverUrl:
'https://thumbs.dreamstime.com/b/music-notes-random-pattern-background-wallpapers-use-content-creation-design-layouts-189454693.jpg',
title: getRandom(randomUTitle),
artist: 'new',
file: {
fileDuration: 20,
fileUrl: '',
},
}));
console.log('fake data in redueraaaaaaaa',fakeData);
yield put(
updateDataSection({
type: action.payload.type,
title: action.payload.title ?? '',
itemChild: {
data: fakeData,
pagination: {
page: 1,
pageCount: 20,
total: 30
},
},
}),
);
}
} catch (error) {
yield call(handleError, error, '');
} finally {
yield put(setLoading(false));
}
}
export function* hashtagHandler(action) {
try {
yield put(setLoading(true));
if (getDataHashtagsAction.match(action)) {
let fakeData: any = [];
const randomUTitle = [
'Eleanor Rigby',
'Darling Nikki',
'Fernando',
'Gloria',
'Jack and Diane',
'Daniel',
'Buddy Holly',
'The Wind Cries Mary',
];
const tenItems = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
fakeData = tenItems.map(id => ({
id,
coverUrl:
'https://media.istockphoto.com/photos/two-young-people-guy-and-girl-in-casual-clothes-dancing-contemporary-picture-id1334841020?k=20&m=1334841020&s=612x612&w=0&h=LsTymAEfSU6aBES-7IqaeXMnvmOqkcu7bcIggPCJBYM=',
name: 'hashtags',
}));
console.log('hashtags reducer',fakeData)
yield put(
updateDataSection({
type: action.payload.type,
title: action.payload.title ?? '',
itemChild: {
data: fakeData,
pagination: {
page: 1,
pageCount: 20,
total: 30,
},
},
}),
);
}
} catch (error) {
yield call(handleError, error, '');
} finally {
yield put(setLoading(false));
}
}
export function* usersHandler(action) {
try {
yield put(setLoading(true));
if (getDataUsersAction.match(action)) {
let fakeData: any = [];
const randomUTitle = [
'Eleanor Rigby',
'Darling Nikki',
'Fernando',
'Gloria',
'Jack and Diane',
'Daniel',
'Buddy Holly',
'The Wind Cries Mary',
];
const tenItems = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
fakeData = tenItems.map(id => ({
id,
name: getRandom(randomUTitle),
username: '',
coverUrl:
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRLe5PABjXc17cjIMOibECLM7ppDwMmiDg6Dw&usqp=CAU',
}));
yield put(
updateDataSection({
type: action.payload.type,
title: action.payload.title ?? '',
itemChild: {
data: fakeData,
pagination: {
page: 1,
pageCount: 20,
total: 30,
},
},
}),
);
}
} catch (error) {
yield call(handleError, error, '');
} finally {
yield put(setLoading(false));
}
}
export default function* () {
yield takeLatest(getDataMusicsAction.type, musicHandler);
yield takeLatest(getDataHashtagsAction.type, hashtagHandler);
yield takeLatest(getDataUsersAction.type, usersHandler);
}
```