96 lines
2.7 KiB
Vue
96 lines
2.7 KiB
Vue
<script setup>
|
||
import { onMounted, provide, reactive, ref, watch } from 'vue'
|
||
import Header from '@/components/Header.vue'
|
||
import CardList from '@/components/CardList.vue'
|
||
import Drawer from '@/components/Drawer.vue'
|
||
import axios from 'axios'
|
||
import Spinner from '@/components/Spinner.vue'
|
||
|
||
const showDrawer = ref(false);
|
||
const items = ref([]);
|
||
const isLoading = ref(false);
|
||
const filters = reactive({
|
||
searchQuery: '',
|
||
sortBy: ''
|
||
});
|
||
|
||
const fetchItems = async (filters = {}) => {
|
||
const params = {};
|
||
if (filters.searchQuery) {
|
||
params.title = '*' + filters.searchQuery + '*'
|
||
}
|
||
if (filters.sortBy) {
|
||
params.sortBy = filters.sortBy
|
||
}
|
||
|
||
try {
|
||
isLoading.value = true
|
||
const { data } = await axios.get(`${import.meta.env.VITE_API_URL}/items`, { params });
|
||
items.value = data
|
||
} catch (e) {
|
||
console.error('Some error', e)
|
||
} finally {
|
||
isLoading.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(fetchItems)
|
||
watch(filters, fetchItems)
|
||
|
||
const addItemToFavorite = async (item) => {
|
||
try {
|
||
item.isFavorite = !item.isFavorite;
|
||
await axios.patch(`${import.meta.env.VITE_API_URL}/items/${item.id}`, item);
|
||
} catch (e) {
|
||
console.log('Error', e)
|
||
}
|
||
}
|
||
|
||
provide('openDrawer', () => showDrawer.value = true)
|
||
provide('closeDrawer', () => showDrawer.value = false)
|
||
</script>
|
||
<template>
|
||
<Drawer v-if="showDrawer" />
|
||
|
||
<div
|
||
class="mt-14 w-4/5 mx-auto bg-white rounded-xl shadow-xl"
|
||
>
|
||
<Header/>
|
||
|
||
<div class="p-10">
|
||
<div class="flex justify-between items-center mb-8">
|
||
<h2 class="text-3xl font-bold">Все кроссовки</h2>
|
||
|
||
<div class="flex gap-4 flex-wrap">
|
||
<select class="py-2 px-3 border rounded-md outline-none" v-model="filters.sortBy">
|
||
<option value="" disabled>Сортировка по:</option>
|
||
<option value="title">По названию</option>
|
||
<option value="price">По цене (сначала дешевые)</option>
|
||
<option value="-price">По цене (сначала дорогие)</option>
|
||
</select>
|
||
|
||
<div class="relative">
|
||
<img class="absolute top-3 left-4" src="/search.svg" alt="Search">
|
||
<input v-model="filters.searchQuery" class="border rounded-md py-2 pl-11 pr-4 outline-none focus:border-gray-400" type="text" placeholder="Поиск">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div v-if="isLoading" class="flex justify-center align-center">
|
||
<Spinner/>
|
||
</div>
|
||
|
||
<div v-else>
|
||
<CardList
|
||
v-if="items.length > 0"
|
||
:items="items"
|
||
@addToFavorite="addItemToFavorite"
|
||
/>
|
||
<h2 v-else>Пусто</h2>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</template>
|