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>
|
<script setup>
|
||||||
import { computed, onMounted, provide, reactive, ref, watch } from 'vue'
|
import { onMounted, provide, watch } from 'vue'
|
||||||
import Header from '@/components/Header.vue'
|
import Header from '@/components/Header.vue'
|
||||||
import Drawer from '@/components/Drawer.vue'
|
import Drawer from '@/components/Drawer.vue'
|
||||||
import axios from 'axios'
|
import { useItems } from '@/hooks/useItems.js'
|
||||||
import { toast } from 'vue3-toastify'
|
import { useCart } from '@/hooks/useCart.js'
|
||||||
import 'vue3-toastify/dist/index.css';
|
import { useDrawer } from '@/hooks/useDrawer.js'
|
||||||
const showDrawer = ref(false);
|
|
||||||
const items = ref([]);
|
|
||||||
const isLoading = ref(false);
|
|
||||||
const isFetching = ref(false);
|
|
||||||
const filters = reactive({
|
|
||||||
searchQuery: '',
|
|
||||||
sortBy: ''
|
|
||||||
});
|
|
||||||
const isCreatingOrder = ref(false);
|
|
||||||
|
|
||||||
const fetchItems = async (filters = {}, {isFirstLoading}) => {
|
const {
|
||||||
const params = {};
|
fetchItems,
|
||||||
if (filters.searchQuery) {
|
filters,
|
||||||
params.title = '*' + filters.searchQuery + '*'
|
isLoading,
|
||||||
}
|
items,
|
||||||
if (filters.sortBy) {
|
toggleToCart,
|
||||||
params.sortBy = filters.sortBy
|
toggleToFavorite,
|
||||||
}
|
} = useItems();
|
||||||
|
|
||||||
try {
|
const {
|
||||||
if (isFirstLoading) {
|
cart,
|
||||||
isLoading.value = true
|
createOrder,
|
||||||
}
|
isCreatingOrder,
|
||||||
isFetching.value = true
|
totalPrice,
|
||||||
const { data } = await axios.get(`${import.meta.env.VITE_API_URL}/items`, { params });
|
} = useCart({items})
|
||||||
items.value = data
|
|
||||||
} catch (e) {
|
const {
|
||||||
console.error('Some error', e)
|
showDrawer,
|
||||||
} finally {
|
openDrawer,
|
||||||
isLoading.value = false
|
closeDrawer,
|
||||||
isFetching.value = false
|
} = useDrawer();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => fetchItems({}, {isFirstLoading: true}))
|
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', {
|
provide('cart', {
|
||||||
cart,
|
cart,
|
||||||
toggleToCart,
|
toggleToCart,
|
||||||
totalPrice,
|
totalPrice,
|
||||||
openDrawer: () => showDrawer.value = true,
|
openDrawer,
|
||||||
closeDrawer: () => showDrawer.value = false,
|
closeDrawer,
|
||||||
createOrder,
|
createOrder,
|
||||||
isCreatingOrder,
|
isCreatingOrder,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -35,12 +35,6 @@
|
|||||||
<span>Закладки</span>
|
<span>Закладки</span>
|
||||||
</li>
|
</li>
|
||||||
</router-link>
|
</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>
|
</ul>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</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 { createApp } from 'vue'
|
||||||
|
import 'vue3-toastify/dist/index.css';
|
||||||
import './assets/main.css'
|
import './assets/main.css'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import Vue3Toastify from 'vue3-toastify';
|
import Vue3Toastify from 'vue3-toastify';
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user