refactoring: add hooks

This commit is contained in:
Sergey Krylov 2025-01-28 07:20:26 +03:00
parent d8492ae873
commit 4433c2bb55
6 changed files with 198 additions and 130 deletions

View File

@ -1,139 +1,41 @@
<script setup>
import { computed, onMounted, provide, reactive, ref, watch } from 'vue'
import { onMounted, provide, watch } from 'vue'
import Header from '@/components/Header.vue'
import Drawer from '@/components/Drawer.vue'
import axios from 'axios'
import { toast } from 'vue3-toastify'
import 'vue3-toastify/dist/index.css';
const showDrawer = ref(false);
const items = ref([]);
const isLoading = ref(false);
const isFetching = ref(false);
const filters = reactive({
searchQuery: '',
sortBy: ''
});
const isCreatingOrder = ref(false);
import { useItems } from '@/hooks/useItems.js'
import { useCart } from '@/hooks/useCart.js'
import { useDrawer } from '@/hooks/useDrawer.js'
const fetchItems = async (filters = {}, {isFirstLoading}) => {
const params = {};
if (filters.searchQuery) {
params.title = '*' + filters.searchQuery + '*'
}
if (filters.sortBy) {
params.sortBy = filters.sortBy
}
const {
fetchItems,
filters,
isLoading,
items,
toggleToCart,
toggleToFavorite,
} = useItems();
try {
if (isFirstLoading) {
isLoading.value = true
}
isFetching.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
isFetching.value = false
}
}
const {
cart,
createOrder,
isCreatingOrder,
totalPrice,
} = useCart({items})
const {
showDrawer,
openDrawer,
closeDrawer,
} = useDrawer();
onMounted(() => fetchItems({}, {isFirstLoading: true}))
watch(filters, fetchItems)
const toggleToFavorite = async (item) => {
try {
item.isFavorite = !item.isFavorite;
await axios.patch(`${import.meta.env.VITE_API_URL}/items/${item.id}`, item);
if (item.isFavorite) {
toast("Добавлено в избранное", {
"type": "success",
"hideProgressBar": true,
"transition": "slide",
"dangerouslyHTMLString": true,
"position": "bottom-right",
})
}
} catch (e) {
console.log('Error', e)
toast("Ошибка при добавлении в избранное", {
"type": "error",
"hideProgressBar": true,
"transition": "slide",
"dangerouslyHTMLString": true,
"position": "bottom-right",
})
}
}
const toggleToCart = async (item) => {
try {
item.isAdded = !item.isAdded;
await axios.patch(`${import.meta.env.VITE_API_URL}/items/${item.id}`, item);
if (item.isAdded) {
toast("Добавлено в корзину", {
"type": "success",
"hideProgressBar": true,
"transition": "slide",
"dangerouslyHTMLString": true,
"position": "bottom-right",
})
}
} catch (e) {
console.log('Error', e)
}
}
const createOrder = async () => {
try {
isCreatingOrder.value = true;
const { data } = await axios.post(`${import.meta.env.VITE_API_URL}/orders`, {
items: cart.value,
totalPrice: totalPrice.value
});
items.value.forEach((item) => {
item.isAdded = false;
});
await axios.patch(`${import.meta.env.VITE_API_URL}/items`, items.value);
toast("Заказ успешно оформлен", {
"type": "success",
"hideProgressBar": true,
"transition": "slide",
"dangerouslyHTMLString": true,
"position": "bottom-right",
})
return data;
} catch (e) {
toast("Ошибка при создании заказа", {
"type": "error",
"hideProgressBar": true,
"transition": "slide",
"dangerouslyHTMLString": true,
"position": "bottom-right",
})
} finally {
isCreatingOrder.value = false;
}
}
const cart = computed(() => items.value.filter(i => i.isAdded));
const totalPrice = computed(() => cart.value.reduce((res, cur) => {
return res + cur.price
}, 0))
provide('cart', {
cart,
toggleToCart,
totalPrice,
openDrawer: () => showDrawer.value = true,
closeDrawer: () => showDrawer.value = false,
openDrawer,
closeDrawer,
createOrder,
isCreatingOrder,
})

View File

@ -35,12 +35,6 @@
<span>Закладки</span>
</li>
</router-link>
<li class="flex items-center gap-2 text-gray-500 hover:text-black cursor-pointer">
<img src="/profile.svg" alt="Profile" />
<span>Профиль</span>
</li>
</ul>
</header>
</template>

56
src/hooks/useCart.js Normal file
View File

@ -0,0 +1,56 @@
import axios from 'axios'
import { toast } from 'vue3-toastify'
import { computed, ref } from 'vue'
export function useCart(props) {
const { items } = props;
const isCreatingOrder = ref(false);
const createOrder = async () => {
try {
isCreatingOrder.value = true;
const { data } = await axios.post(`${import.meta.env.VITE_API_URL}/orders`, {
items: cart.value,
totalPrice: totalPrice.value
});
items.value.forEach((item) => {
item.isAdded = false;
});
await axios.patch(`${import.meta.env.VITE_API_URL}/items`, items.value);
toast("Заказ успешно оформлен", {
"type": "success",
"hideProgressBar": true,
"transition": "slide",
"dangerouslyHTMLString": true,
"position": "bottom-right",
})
return data;
} catch (e) {
toast("Ошибка при создании заказа", {
"type": "error",
"hideProgressBar": true,
"transition": "slide",
"dangerouslyHTMLString": true,
"position": "bottom-right",
})
} finally {
isCreatingOrder.value = false;
}
}
const cart = computed(() => items.value.filter(i => i.isAdded));
const totalPrice = computed(() => cart.value.reduce((res, cur) => {
return res + cur.price
}, 0))
return {
cart,
createOrder,
isCreatingOrder,
totalPrice,
}
}

14
src/hooks/useDrawer.js Normal file
View File

@ -0,0 +1,14 @@
import { ref } from 'vue'
export function useDrawer() {
const showDrawer = ref(false);
const openDrawer = () => showDrawer.value = true;
const closeDrawer = () => showDrawer.value = false;
return {
showDrawer,
openDrawer,
closeDrawer,
}
}

101
src/hooks/useItems.js Normal file
View File

@ -0,0 +1,101 @@
import axios from 'axios'
import { reactive, ref, watch } from 'vue'
import { toast } from 'vue3-toastify'
export function useItems() {
const items = ref([]);
const isLoading = ref(false);
const isFetching = ref(false);
const filters = reactive({
searchQuery: '',
sortBy: ''
});
const fetchItems = async (filters = {}, {isFirstLoading}) => {
const params = {};
if (filters.searchQuery) {
params.title = '*' + filters.searchQuery + '*'
}
if (filters.sortBy) {
params.sortBy = filters.sortBy
}
try {
if (isFirstLoading) {
isLoading.value = true
}
isFetching.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
isFetching.value = false
}
}
const toggleToFavorite = async (item) => {
try {
item.isFavorite = !item.isFavorite;
await axios.patch(`${import.meta.env.VITE_API_URL}/items/${item.id}`, item);
if (item.isFavorite) {
toast("Добавлено в избранное", {
"type": "success",
"hideProgressBar": true,
"transition": "slide",
"dangerouslyHTMLString": true,
"position": "bottom-right",
})
}
} catch (e) {
console.log('Error', e)
toast("Ошибка при добавлении в избранное", {
"type": "error",
"hideProgressBar": true,
"transition": "slide",
"dangerouslyHTMLString": true,
"position": "bottom-right",
})
}
}
const toggleToCart = async (item) => {
try {
item.isAdded = !item.isAdded;
await axios.patch(`${import.meta.env.VITE_API_URL}/items/${item.id}`, item);
if (item.isAdded) {
toast("Добавлено в корзину", {
"type": "success",
"hideProgressBar": true,
"transition": "slide",
"dangerouslyHTMLString": true,
"position": "bottom-right",
})
}
} catch (e) {
console.log('Error', e)
toast("Ошибка при добавлении в корзину", {
"type": "error",
"hideProgressBar": true,
"transition": "slide",
"dangerouslyHTMLString": true,
"position": "bottom-right",
})
}
}
watch(filters, fetchItems)
return {
items,
filters,
isLoading,
isFetching,
fetchItems,
toggleToFavorite,
toggleToCart,
}
}

View File

@ -1,4 +1,5 @@
import { createApp } from 'vue'
import 'vue3-toastify/dist/index.css';
import './assets/main.css'
import App from './App.vue'
import Vue3Toastify from 'vue3-toastify';