mirror of
https://github.com/bs-community/blessing-skin-server.git
synced 2025-02-23 14:59:07 +08:00
refactor pagination
This commit is contained in:
parent
d603f48bad
commit
4c52f82393
@ -43,42 +43,23 @@ class ClosetController extends Controller
|
||||
public function getClosetData(Request $request)
|
||||
{
|
||||
$category = $request->input('category', 'skin');
|
||||
$page = abs($request->input('page', 1));
|
||||
$perPage = (int) $request->input('perPage', 6);
|
||||
$q = $request->input('q', null);
|
||||
$search = $request->input('q');
|
||||
|
||||
$perPage = $perPage > 0 ? $perPage : 6;
|
||||
|
||||
$user = auth()->user();
|
||||
$closet = $user->closet();
|
||||
$query = auth()->user()->closet();
|
||||
|
||||
if ($category == 'cape') {
|
||||
$closet = $closet->where('type', 'cape');
|
||||
$query = $query->where('type', 'cape');
|
||||
} else {
|
||||
$closet = $closet->where(function ($query) {
|
||||
$query = $query->where(function ($query) {
|
||||
return $query->where('type', 'steve')->orWhere('type', 'alex');
|
||||
});
|
||||
}
|
||||
|
||||
if ($q) {
|
||||
$closet = $closet->where('item_name', 'like', "%$q%");
|
||||
if ($search) {
|
||||
$query = $query->where('item_name', 'like', "%$search%");
|
||||
}
|
||||
|
||||
$total = $closet->count();
|
||||
$closet->offset(($page - 1) * $perPage)->limit($perPage);
|
||||
|
||||
$totalPages = ceil($total / $perPage);
|
||||
$items = $closet->get()->map(function ($t) {
|
||||
$t->name = $t->pivot->item_name;
|
||||
|
||||
return $t;
|
||||
});
|
||||
|
||||
return json('', 0, [
|
||||
'category' => $category,
|
||||
'items' => $items,
|
||||
'total_pages' => $totalPages,
|
||||
]);
|
||||
return $query->paginate(6);
|
||||
}
|
||||
|
||||
public function add(Request $request)
|
||||
|
@ -174,6 +174,7 @@ return [
|
||||
Illuminate\Hashing\HashServiceProvider::class,
|
||||
Illuminate\Mail\MailServiceProvider::class,
|
||||
Illuminate\Notifications\NotificationServiceProvider::class,
|
||||
Illuminate\Pagination\PaginationServiceProvider::class,
|
||||
Illuminate\Queue\QueueServiceProvider::class,
|
||||
Illuminate\Redis\RedisServiceProvider::class,
|
||||
Illuminate\Session\SessionServiceProvider::class,
|
||||
|
@ -22,3 +22,12 @@ export type TextureType = 'steve' | 'alex' | 'cape'
|
||||
export type ClosetItem = Texture & {
|
||||
pivot: { user_uid: number; texture_tid: number; item_name: string }
|
||||
}
|
||||
|
||||
export type Paginator<T> = {
|
||||
data: T[]
|
||||
current_page: number
|
||||
last_page: number
|
||||
from: number
|
||||
to: number
|
||||
total: number
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import debounce from 'lodash.debounce'
|
||||
import { t } from '@/scripts/i18n'
|
||||
import * as fetch from '@/scripts/net'
|
||||
import { showModal, toast } from '@/scripts/notify'
|
||||
import { ClosetItem as Item, Texture } from '@/scripts/types'
|
||||
import { ClosetItem as Item, Texture, Paginator } from '@/scripts/types'
|
||||
import Loading from '@/components/Loading'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import ClosetItem from './ClosetItem'
|
||||
@ -37,23 +37,13 @@ const Closet: React.FC = () => {
|
||||
useEffect(() => {
|
||||
const getItems = async () => {
|
||||
setIsLoading(true)
|
||||
const {
|
||||
data: { items, category: c, total_pages: totalPages },
|
||||
} = await fetch.get<
|
||||
fetch.ResponseBody<{
|
||||
items: Item[]
|
||||
category: Category
|
||||
total_pages: number
|
||||
}>
|
||||
>('/user/closet/list', {
|
||||
category,
|
||||
q: query,
|
||||
page,
|
||||
})
|
||||
const { data, last_page } = await fetch.get<Paginator<Item>>(
|
||||
'/user/closet/list',
|
||||
{ category, q: query, page },
|
||||
)
|
||||
|
||||
setItems(items)
|
||||
setCategory(c)
|
||||
setTotalPages(totalPages)
|
||||
setItems(data)
|
||||
setTotalPages(last_page)
|
||||
setIsLoading(false)
|
||||
}
|
||||
getItems()
|
||||
|
@ -3,7 +3,7 @@ import { render, fireEvent, wait } from '@testing-library/react'
|
||||
import $ from 'jquery'
|
||||
import { t } from '@/scripts/i18n'
|
||||
import * as fetch from '@/scripts/net'
|
||||
import { ClosetItem, Player } from '@/scripts/types'
|
||||
import { ClosetItem, Player, Paginator } from '@/scripts/types'
|
||||
import Closet from '@/views/user/Closet'
|
||||
|
||||
jest.mock('@/scripts/net')
|
||||
@ -49,6 +49,17 @@ const fixturePlayer: Readonly<Player> = Object.freeze<Player>({
|
||||
tid_cape: 2,
|
||||
})
|
||||
|
||||
function createPaginator(data: ClosetItem[]): Paginator<ClosetItem> {
|
||||
return {
|
||||
data,
|
||||
total: data.length,
|
||||
from: 1,
|
||||
to: data.length,
|
||||
current_page: 1,
|
||||
last_page: 1,
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
const container = document.createElement('div')
|
||||
container.id = 'previewer'
|
||||
@ -60,17 +71,13 @@ afterEach(() => {
|
||||
})
|
||||
|
||||
test('loading indicator', () => {
|
||||
fetch.get.mockResolvedValue({
|
||||
data: { items: [], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
fetch.get.mockResolvedValue(createPaginator([]))
|
||||
const { queryByTitle } = render(<Closet />)
|
||||
expect(queryByTitle('Loading...')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
test('empty closet', async () => {
|
||||
fetch.get.mockResolvedValue({
|
||||
data: { items: [], category: 'skin', total_pages: 0 },
|
||||
})
|
||||
fetch.get.mockResolvedValue(createPaginator([]))
|
||||
|
||||
const { queryByText } = render(<Closet />)
|
||||
await wait()
|
||||
@ -79,15 +86,9 @@ test('empty closet', async () => {
|
||||
|
||||
test('categories', async () => {
|
||||
fetch.get
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [fixtureCape], category: 'cape', total_pages: 1 },
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
.mockResolvedValueOnce(createPaginator([fixtureSkin]))
|
||||
.mockResolvedValueOnce(createPaginator([fixtureCape]))
|
||||
.mockResolvedValueOnce(createPaginator([fixtureSkin]))
|
||||
|
||||
const { getByText, queryByText } = render(<Closet />)
|
||||
await wait()
|
||||
@ -107,12 +108,8 @@ test('categories', async () => {
|
||||
|
||||
test('search textures', async () => {
|
||||
fetch.get
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [], category: 'skin', total_pages: 0 },
|
||||
})
|
||||
.mockResolvedValueOnce(createPaginator([fixtureSkin]))
|
||||
.mockResolvedValueOnce(createPaginator([]))
|
||||
|
||||
const { getByPlaceholderText, queryByText } = render(<Closet />)
|
||||
await wait()
|
||||
@ -127,12 +124,8 @@ test('search textures', async () => {
|
||||
|
||||
test('switch page', async () => {
|
||||
fetch.get
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [], category: 'skin', total_pages: 2 },
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 2 },
|
||||
})
|
||||
.mockResolvedValueOnce({ ...createPaginator([]), last_page: 2 })
|
||||
.mockResolvedValueOnce({ ...createPaginator([fixtureSkin]), last_page: 2 })
|
||||
|
||||
const { getByText, queryByText } = render(<Closet />)
|
||||
await wait()
|
||||
@ -144,9 +137,7 @@ test('switch page', async () => {
|
||||
|
||||
describe('rename item', () => {
|
||||
beforeEach(() => {
|
||||
fetch.get.mockResolvedValue({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
fetch.get.mockResolvedValue(createPaginator([fixtureSkin]))
|
||||
})
|
||||
|
||||
it('succeeded', async () => {
|
||||
@ -234,9 +225,7 @@ describe('rename item', () => {
|
||||
|
||||
describe('remove item', () => {
|
||||
beforeEach(() => {
|
||||
fetch.get.mockResolvedValue({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
fetch.get.mockResolvedValue(createPaginator([fixtureSkin]))
|
||||
})
|
||||
|
||||
it('succeeded', async () => {
|
||||
@ -287,12 +276,8 @@ describe('remove item', () => {
|
||||
describe('select textures', () => {
|
||||
beforeEach(() => {
|
||||
fetch.get
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [fixtureCape], category: 'cape', total_pages: 1 },
|
||||
})
|
||||
.mockResolvedValueOnce(createPaginator([fixtureSkin]))
|
||||
.mockResolvedValueOnce(createPaginator([fixtureCape]))
|
||||
})
|
||||
|
||||
it('select skin', async () => {
|
||||
@ -336,9 +321,7 @@ describe('select textures', () => {
|
||||
|
||||
describe('set avatar', () => {
|
||||
beforeEach(() => {
|
||||
fetch.get.mockResolvedValue({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
fetch.get.mockResolvedValue(createPaginator([fixtureSkin]))
|
||||
|
||||
const img = document.createElement('img')
|
||||
img.alt = 'User Image'
|
||||
@ -398,9 +381,7 @@ describe('set avatar', () => {
|
||||
|
||||
describe('apply textures to player', () => {
|
||||
it('selected nothing', async () => {
|
||||
fetch.get.mockResolvedValue({
|
||||
data: { items: [], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
fetch.get.mockResolvedValue(createPaginator([]))
|
||||
|
||||
const { getByText, getByRole, queryByText } = render(<Closet />)
|
||||
await wait()
|
||||
@ -413,9 +394,7 @@ describe('apply textures to player', () => {
|
||||
|
||||
it('search players', async () => {
|
||||
fetch.get
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
.mockResolvedValueOnce(createPaginator([fixtureSkin]))
|
||||
.mockResolvedValueOnce({ data: [fixturePlayer] })
|
||||
|
||||
const {
|
||||
@ -440,9 +419,7 @@ describe('apply textures to player', () => {
|
||||
|
||||
it('succeeded', async () => {
|
||||
fetch.get
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
.mockResolvedValueOnce(createPaginator([fixtureSkin]))
|
||||
.mockResolvedValueOnce({ data: [fixturePlayer] })
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'success' })
|
||||
|
||||
@ -470,9 +447,7 @@ describe('apply textures to player', () => {
|
||||
|
||||
it('failed', async () => {
|
||||
fetch.get
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
.mockResolvedValueOnce(createPaginator([fixtureSkin]))
|
||||
.mockResolvedValueOnce({ data: [fixturePlayer] })
|
||||
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
|
||||
|
||||
@ -500,9 +475,7 @@ describe('apply textures to player', () => {
|
||||
|
||||
it('close dialog', async () => {
|
||||
fetch.get
|
||||
.mockResolvedValueOnce({
|
||||
data: { items: [fixtureSkin], category: 'skin', total_pages: 1 },
|
||||
})
|
||||
.mockResolvedValueOnce(createPaginator([fixtureSkin]))
|
||||
.mockResolvedValueOnce({ data: [fixturePlayer] })
|
||||
|
||||
const { getByText, getByAltText } = render(<Closet />)
|
||||
|
@ -40,46 +40,28 @@ class ClosetControllerTest extends TestCase
|
||||
// Use default query parameters
|
||||
$this->getJson('/user/closet/list')
|
||||
->assertJsonStructure([
|
||||
'data' => [
|
||||
'category',
|
||||
'total_pages',
|
||||
'items' => [['tid', 'name', 'type']],
|
||||
],
|
||||
'data' => [['tid', 'name', 'type']],
|
||||
]);
|
||||
|
||||
// Responsive
|
||||
$result = $this->json('get', '/user/closet/list?perPage=0')->json()['data'];
|
||||
$this->assertCount(6, $result['items']);
|
||||
$result = $this->json('get', '/user/closet/list?perPage=8')->json()['data'];
|
||||
$this->assertCount(8, $result['items']);
|
||||
$result = $this->json('get', '/user/closet/list?perPage=8&page=2')->json()['data'];
|
||||
$this->assertCount(2, $result['items']);
|
||||
|
||||
// Get capes
|
||||
$cape = factory(Texture::class)->states('cape')->create();
|
||||
$this->user->closet()->attach($cape->tid, ['item_name' => 'custom_name']);
|
||||
$this->getJson('/user/closet/list?category=cape')
|
||||
->assertJson(['data' => [
|
||||
'category' => 'cape',
|
||||
'total_pages' => 1,
|
||||
'items' => [[
|
||||
->assertJson(['data' => [[
|
||||
'tid' => $cape->tid,
|
||||
'name' => 'custom_name',
|
||||
'type' => 'cape',
|
||||
]],
|
||||
'pivot' => ['item_name' => 'custom_name'],
|
||||
],
|
||||
]]);
|
||||
|
||||
// Search by keyword
|
||||
$random = $textures->random();
|
||||
$this->getJson('/user/closet/list?q='.$random->name)
|
||||
->assertJson(['data' => [
|
||||
'category' => 'skin',
|
||||
'total_pages' => 1,
|
||||
'items' => [[
|
||||
->assertJson(['data' => [[
|
||||
'tid' => $random->tid,
|
||||
'name' => $random->name,
|
||||
'type' => $random->type,
|
||||
]],
|
||||
],
|
||||
]]);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user