refactoring: add hooks
This commit is contained in:
parent
d8492ae873
commit
4433c2bb55
150
src/App.vue
150
src/App.vue
@ -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,
|
||||
})
|
||||
|
||||
@ -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
56
src/hooks/useCart.js
Normal 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
14
src/hooks/useDrawer.js
Normal 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
101
src/hooks/useItems.js
Normal 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,
|
||||
}
|
||||
}
|
||||
@ -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';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user