Commit c70504d5 authored by Le Dinh Trung's avatar Le Dinh Trung

Merge branch 'feature/hompage-categories' into 'dev'

Feature/hompage categories

See merge request !25
parents b2df785d fc3f5ce4
...@@ -18,36 +18,17 @@ ...@@ -18,36 +18,17 @@
<script> <script>
export default { export default {
name: 'BreadCrumb', name: 'BreadCrumb',
props: {
status: {
type: Boolean,
default: true
}
},
data: () => ({
email: '',
password: '',
items: [
{
text: 'Home',
disabled: false,
href: '/home'
},
{
text: 'Element',
disabled: false,
href: '/'
},
{
text: 'Post',
disabled: false,
href: '/posts'
}
]
}),
computed: { computed: {
dialog () { items () {
return this.status const items = [{ text: 'Home', disabled: false, href: '/' }]
this.$route.matched.forEach((route) => {
if (route.name) {
items.push({ text: route.name, disabled: false, href: route.path })
}
})
return items
} }
} }
} }
......
<!-- eslint-disable vue/no-template-shadow -->
<template>
<v-row
justify="center"
>
<v-dialog
v-model="dialogDetail"
width="900px"
min-height="550px"
>
<v-row class="flex-row justify-center">
<v-col>
<v-carousel hide-delimiters :show-arrows="hover" :width="400">
<v-carousel-item
v-for="(item, i) in images"
:key="i"
:width="400"
:heigh="400"
:src="item"
cover
/>
</v-carousel>
</v-col>
<v-col>
<v-card-title v-model="item.name" class="modal-title" style="margin-left:-30px">
{{ name }}
</v-card-title>
<v-row class="flex-row align-center">
<h3 class="mr-4">
Price:
</h3>
<v-card-title v-model="item.price">
{{ price + "$" }}
</v-card-title>
</v-row>
<v-card-text v-model="item.description" class="descrip">
{{ description }}
</v-card-text>
<v-row class="flex-row justify-center align-center">
<h3 class="mr-4">
Color
</h3>
<v-row
cols="12"
>
<v-radio-group
v-model="color_modal"
row
mandatory
class="square-radio"
>
<v-radio
label="red"
color="red"
value="red"
class="square-radio"
/>
<v-radio
label="blue"
color="primary"
value="red darken-3"
class="square-radio"
/>
<v-radio
label="yellow"
color="yellow"
value="yellow"
class="square-radio"
/>
</v-radio-group>
</v-row>
</v-row>
<v-row class="flex-row justify-start align-center">
<h3 class="mr-4">
Size
</h3>
<v-btn-toggle
v-model="size_modal"
color="primary"
mandatory
>
<v-btn value="S">
S
</v-btn>
<v-btn value="M">
M
</v-btn>
<v-btn value="L">
L
</v-btn>
</v-btn-toggle>
</v-row>
<v-row class="mt-7">
<v-divider :thickness="2" />
</v-row>
<v-row cols="12" md="2" class="flex-row align-center">
<h3 class="mr-4">
Quantity
</h3>
<v-col md="2">
<v-text-field
v-model="quantity_modal"
type="number"
/>
</v-col>
<v-btn color="primary" dense @click="addProductToCard()">
Add to card (+)
</v-btn>
<v-btn
plain
>
<v-icon large>
mdi-heart-outline
</v-icon>
</v-btn>
</v-row>
<v-row class="mb-1">
<v-divider :thickness="2" />
</v-row>
<v-row>
<v-icon class="mx-2">
mdi-twitter
</v-icon>
<v-icon class="mx-2">
mdi-facebook
</v-icon>
<v-icon class="mx-2">
mdi-instagram
</v-icon>
</v-row>
</v-col>
</v-row>
</v-dialog>
</v-row>
</template>
<script>
import { eventBus } from '~/plugins/eventBus.js'
export default {
name: 'DetailModal',
props: {
status: {
type: Boolean,
default: false
},
name: {
type: String,
required: true
},
price: {
type: String,
required: true
},
description: {
type: String,
required: true
},
images: {
type: Array,
required: true
},
product_id: {
type: String,
required: true
}
},
data: () => ({
selected: '',
item: {
name: '',
price: '',
description: ''
},
size_modal: undefined,
color_modal: undefined,
quantity_modal: ''
}),
computed: {
dialogDetail () {
return this.status
}
},
methods: {
closeDialog () {
this.$props.status = false
},
addProductToCard () {
const fd = new FormData()
fd.append('product_id', this.product_id)
fd.append('color', this.color_modal)
fd.append('size', this.size_modal)
fd.append('quantity', this.quantity_modal)
this.$axios
.post('/carts/add-to-cart', fd, {
headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}`
}
})
.then((response) => {
this.$toast.success('Add product successfully!', {
duration: 3000
})
this.$props.status = false
eventBus.$emit('add-to-cart', response)
})
.catch((errors) => {
this.$toast.error('something went wrong while trying create!', {
duration: 3000
})
})
}
}
}
</script>
<style scoped>
::v-deep .v-dialog{
background-color: white;
}
.square-radio .v-input--selection-controls__input {
border-radius: 0 !important;
width: 24px !important;
height: 24px !important;
}
.square-radio .v-input--selection-controls__ripple {
border-radius: 50% !important;
}
.square-radio .v-input--selection-controls__input:checked:before {
border-radius: 50% !important;
}
.modal-title {
font-size: 30px;
font-weight: bold;
margin-left:-30px;
margin-top:10px;
}
.hex-variant {
/* margin-top:0px; */
}
.descrip {
margin-left:-30px;
}
.v-dialog {
overflow: hidden;
}
</style>
<!-- eslint-disable vue/multi-word-component-names -->
<template> <template>
<div> <div>
<!-- header top --> <!-- header top -->
...@@ -121,7 +120,7 @@ ...@@ -121,7 +120,7 @@
<b>$:0.00</b> <b>$:0.00</b>
</span> </span>
<v-badge <v-badge
:content="1" :content="products.length || 0"
floating floating
bordered bordered
overlap overlap
...@@ -132,19 +131,21 @@ ...@@ -132,19 +131,21 @@
</v-badge> </v-badge>
<v-menu activator="#menu-activator" style="width: 300px"> <v-menu activator="#menu-activator" style="width: 300px">
<v-list dense three-line> <v-list dense three-line>
<v-list-item v-for="item in items" :key="item.title" link> <v-list-item
v-for="item in products"
:key="item.id"
link
>
<v-list-item-avatar> <v-list-item-avatar>
<v-img :src="item.prependAvatar" /> <v-img :src="item.product.images[0]" />
</v-list-item-avatar> </v-list-item-avatar>
<v-list-item-content> <v-list-item-content>
<v-list-item-title>{{ item.title }}</v-list-item-title> <v-list-item-title>{{ item.product.name }}</v-list-item-title>
<v-list-item-subtitle> <v-list-item-subtitle>{{ item.quantity +"x"+ item.product.price }}</v-list-item-subtitle>
{{ item.subtitle }}
</v-list-item-subtitle>
</v-list-item-content> </v-list-item-content>
<v-list-item-action> <v-list-item-action>
<v-btn icon @click="remove(index)"> <v-btn icon @click="removeCart(item,index)">
<v-icon color="grey lighten-1"> <v-icon color="grey lighten-1">
mdi-close-circle-outline mdi-close-circle-outline
</v-icon> </v-icon>
...@@ -155,7 +156,7 @@ ...@@ -155,7 +156,7 @@
<v-divider /> <v-divider />
<div class="d-flex justify-space-between align-center ma-4"> <div class="d-flex justify-space-between align-center ma-4">
<span>Subtotal: </span> <span>Subtotal: </span>
<span>139$ </span> <span> {{ total + "$" }} </span>
</div> </div>
<v-divider /> <v-divider />
<v-btn <v-btn
...@@ -199,17 +200,17 @@ ...@@ -199,17 +200,17 @@
<v-divider /> <v-divider />
<v-list dense three-line> <v-list dense three-line>
<v-list-item v-for="item in items" :key="item.title" link> <v-list-item v-for="item in wishlist" :key="item.name" link>
<v-list-item-avatar> <v-list-item-avatar>
<v-img :src="item.prependAvatar" /> <v-img :src="item.product.images[0]" />
</v-list-item-avatar> </v-list-item-avatar>
<v-list-item-content> <v-list-item-content>
<v-list-item-title>{{ item.title }}</v-list-item-title> <v-list-item-title>{{ item.product.name }}</v-list-item-title>
<v-list-item-subtitle>{{ item.subtitle }}</v-list-item-subtitle> <v-list-item-subtitle>{{ item.product.price }}</v-list-item-subtitle>
</v-list-item-content> </v-list-item-content>
<v-list-item-action> <v-list-item-action>
<v-btn icon @click="remove(index)"> <v-btn icon @click="removeWishlist(item, index)">
<v-icon color="grey lighten-1"> <v-icon color="grey lighten-1">
mdi-close-circle-outline mdi-close-circle-outline
</v-icon> </v-icon>
...@@ -225,6 +226,7 @@ ...@@ -225,6 +226,7 @@
import LoginModal from '~/components/LoginModal.vue' import LoginModal from '~/components/LoginModal.vue'
import SignupModal from '~/components/RegisterModal.vue' import SignupModal from '~/components/RegisterModal.vue'
import NavBar from '~/components/user/NavBar' import NavBar from '~/components/user/NavBar'
import { eventBus } from '~/plugins/eventBus.js'
export default { export default {
name: 'UserHeader', name: 'UserHeader',
...@@ -233,8 +235,11 @@ export default { ...@@ -233,8 +235,11 @@ export default {
SignupModal, SignupModal,
NavBar NavBar
}, },
data: () => { data: () => {
return { return {
products: [],
wishlist: [],
activeLogin: false, activeLogin: false,
activeRegister: false, activeRegister: false,
drawer: false, drawer: false,
...@@ -245,41 +250,24 @@ export default { ...@@ -245,41 +250,24 @@ export default {
languages: [ languages: [
{ text: 'ENG', icon: 'mdi-clock' }, { text: 'ENG', icon: 'mdi-clock' },
{ text: 'FRH', icon: 'mdi-account' } { text: 'FRH', icon: 'mdi-account' }
],
items: [
{
prependAvatar: 'https://cdn.vuetifyjs.com/images/lists/1.jpg',
title: 'Brunch this weekend?',
subtitle:
'<span class="text-primary">Ali Connors</span> &mdash; I\'ll be in your neighborhood doing errands this weekend. Do you want to hang out?'
},
{
prependAvatar: 'https://cdn.vuetifyjs.com/images/lists/2.jpg',
title: 'Summer BBQ',
subtitle:
'<span class="text-primary">to Alex, Scott, Jennifer</span> &mdash; Wish I could come, but I\'m out of town this weekend.'
},
{
prependAvatar: 'https://cdn.vuetifyjs.com/images/lists/3.jpg',
title: 'Oui oui',
subtitle:
'<span class="text-primary">Sandra Adams</span> &mdash; Do you have Paris recommendations? Have you ever been?'
},
{
prependAvatar: 'https://cdn.vuetifyjs.com/images/lists/4.jpg',
title: 'Birthday gift',
subtitle:
'<span class="text-primary">Trevor Hansen</span> &mdash; Have any ideas about what we should get Heidi for her birthday?'
},
{
prependAvatar: 'https://cdn.vuetifyjs.com/images/lists/5.jpg',
title: 'Recipe to try',
subtitle:
'<span class="text-primary">Britta Holt</span> &mdash; We should eat this: Grate, Squash, Corn, and tomatillo Tacos.'
}
] ]
} }
}, },
computed: {
total () {
const arr = []
this.products.map((value) => {
return arr?.push(value.price)
})
return arr.reduce((acc, cur) => acc + cur, 0)
}
},
mounted () {
this.getCardProducts()
this.getWishlish()
this.updateWishlist()
this.updateCart()
},
methods: { methods: {
closeDialog () { closeDialog () {
this.activeLogin = false this.activeLogin = false
...@@ -293,9 +281,96 @@ export default { ...@@ -293,9 +281,96 @@ export default {
this.activeRegister = false this.activeRegister = false
this.activeRegister = true this.activeRegister = true
}, },
remove (index) { removeCart (item, index) {
this.items.splice(index, 1) try {
console.log(this.items) this.$axios
.delete(`/carts/delete-cart-item/${item.id}`, {
headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal(
'token'
)}`
}
})
.then((response) => {
this.products.splice(index, 1)
this.$toast.success('Remove product successfully!', {
duration: 1500
})
})
} catch (error) {
console.log(error)
this.$toast.error('ERR!', {
duration: 1500
})
}
},
async getCardProducts () {
await this.$axios
.get(`/carts/user-cart/${this.$auth.$storage.getUniversal('ID')}`, {
headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal(
'token'
)}`
}
})
.then((response) => {
this.products = response.data.data
console.log(this.products)
})
.catch(function (error) {
console.log(error)
})
},
async getWishlish () {
await this.$axios
.get(`/wish-list/user-wish-list/${this.$auth.$storage.getUniversal('ID')}`, {
headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal(
'token'
)}`
}
})
.then((response) => {
this.wishlist = response.data.data
console.log(this.wishlist)
})
.catch(function (error) {
console.log(error)
})
},
removeWishlist (item, index) {
try {
this.$axios
.delete(`/wish-list/delete-from-wish-list/${item.id}`, {
headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal(
'token'
)}`
}
})
.then((response) => {
this.wishlist.splice(index, 1)
this.$toast.success('Remove product successfully!', {
duration: 1500
})
})
} catch (error) {
console.log(error)
this.$toast.error('ERR!', {
duration: 1500
})
}
},
updateWishlist () {
eventBus.$on('add-to-wish-list', (response) => {
this.getWishlish()
})
},
updateCart () {
eventBus.$on('add-to-cart', (response) => {
console.log('abc')
this.getCardProducts()
})
} }
} }
} }
...@@ -450,7 +525,8 @@ b { ...@@ -450,7 +525,8 @@ b {
} }
.v-menu__content { .v-menu__content {
width: 300px; width: 300px;
top: 153px !important; top: 110px !important;
padding: 25px; padding: 25px;
background-color: #ffffff;
} }
</style> </style>
<template> <template>
<v-container> <v-container>
<div class="navbar d-flex justify-space-between "> <div class="navbar d-flex justify-space-between ">
<div class ="d-flex justify-space-between col-md-7"> <div class="d-flex justify-space-between col-md-7">
<div> <div>
<span> <span>
Home Home
...@@ -20,7 +20,14 @@ ...@@ -20,7 +20,14 @@
hoverable hoverable
activatable activatable
:items="categories" :items="categories"
/> @update:active="setCategory(item)"
>
<template #label="{ item }">
<nuxt-link :to="`/home-page/categories/${item.id}`" tag="div">
{{ item.name }}
</nuxt-link>
</template>
</v-treeview>
</div> </div>
</div> </div>
<div> <div>
...@@ -49,11 +56,12 @@ ...@@ -49,11 +56,12 @@
</span> </span>
</div> </div>
</div> </div>
</v-container> </v-container>
</template> </template>
<script> <script>
import { mapActions, mapState } from 'vuex'
export default { export default {
name: 'NavBar', name: 'NavBar',
data: () => ({ data: () => ({
...@@ -63,11 +71,14 @@ export default { ...@@ -63,11 +71,14 @@ export default {
}), }),
computed: { computed: {
...mapState(['selectedCategory']),
...mapActions(['setSelectedCategory']),
selected () { selected () {
if (!this.active.length) { return undefined } if (!this.active.length) { return undefined }
const id = this.active[0] const id = this.active[0]
console.log(id) console.log(id)
return this.categories.find(category => category.id === id) // console.log(this.categories.find(category => category.id === id).name)
return this.categories.find(category => category.id === id) || ''
} }
}, },
...@@ -75,11 +86,10 @@ export default { ...@@ -75,11 +86,10 @@ export default {
selected () { selected () {
if (!this.active.length) { return undefined } if (!this.active.length) { return undefined }
const id = this.active[0] const id = this.active[0]
return id return id || ''
} }
}, },
beforeCreate () {
created () {
this.$axios this.$axios
.get('guest/categories/index') .get('guest/categories/index')
.then((response) => { .then((response) => {
...@@ -89,8 +99,13 @@ export default { ...@@ -89,8 +99,13 @@ export default {
console.log(error) console.log(error)
}) })
}, },
mounted () {
},
methods: { methods: {
setCategory () {
console.log(this.selected)
this.$store.commit('category/setCurrentCategory', this.selected.name || '')
}
} }
} }
</script> </script>
......
<template> <template>
<v-app> <v-app>
<UserHeader /> <UserHeader ref="child" />
<Nuxt /> <Nuxt />
<FooterBar /> <FooterBar />
</v-app> </v-app>
......
...@@ -29,7 +29,8 @@ export default { ...@@ -29,7 +29,8 @@ export default {
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [ plugins: [
'~/plugins/axios.js', '~/plugins/axios.js',
'~/plugins/formatTime.js' '~/plugins/formatTime.js',
'~/plugins/eventBus.js'
], ],
// Auto import components: https://go.nuxtjs.dev/config-components // Auto import components: https://go.nuxtjs.dev/config-components
......
<!-- eslint-disable vue/no-v-for-template-key -->
<!-- eslint-disable vue/html-end-tags -->
<!-- eslint-disable vue/no-unused-vars -->
<template>
<div>
<BreadCrumb :items="breadcrumbItems" />
<v-container class="pa-0">
<v-row class="d-flex align-center pl-2 mt-2">
<v-col>
<v-hover v-slot="{ hover }">
<v-btn outlined :style="{ 'background-color': hover ? '#1976d2' : '#f5f5f5','color':hover ? '#f5f5f5' : 'black' }">
FILTER
</v-btn>
</v-hover>
</v-col>
</v-row>
<v-row class="pt-5 pb-5">
<v-col
v-for="(item, i) in pagedCards"
:key="i"
cols="12"
md="3"
>
<v-hover
v-slot="{ hover }"
:elevation="hover ? 12 : 2"
:class="{ 'on-hover': hover }"
>
<v-card
:elevation="hover ? 16 : 2"
:class="{ 'on-hover': hover }"
class="mx-auto pa-2 ma-3"
max-width="280"
link
>
<div>
<v-img
:src="item.images[0]"
height="250px"
cover
/>
</div>
<v-card-title class="d-flex justify-center">
{{ item.name }}
</v-card-title>
<v-card-subtitle class="d-flex justify-center">
{{ item.price + "$" }}
</v-card-subtitle>
<v-card-actions class="d-flex justify-center">
<v-btn
:class="{ 'show-btns': hover }"
icon
@click="getDataItem"
>
<v-icon
:class="{ 'show-btns': hover }"
>
mdi-cart
</v-icon>
</v-btn>
<v-btn
:class="{ 'show-btns': hover }"
icon
@click="addToWishlish(item)"
>
<v-icon
:class="{ 'show-btns': hover }"
>
mdi-heart
</v-icon>
</v-btn>
<v-btn
:class="{ 'show-btns': hover }"
icon
@click="openDialogDetail(); getDataItem(item)"
>
<v-icon
:class="{ 'show-btns': hover }"
>
mdi-magnify
</v-icon>
</v-btn>
</v-card-actions>
</v-card>
</v-hover>
</v-col>
</v-row>
<v-divider />
<v-row class="d-flex align-center justify-space-between pl-2 mt-2">
<div class="text-center">
<v-pagination v-model="currentPage" :total-visible="totalVisiblePages" :length="totalPages" class="my-3" circle>
<template #prev="{ active, disabled }">
<v-btn small class="mr-2" :disabled="disabled" @click="prevPage">
<v-icon small>
mdi-chevron-left
</v-icon>
</v-btn>
</template>
<template #next="{ active, disabled }">
<v-btn small class="ml-2" :disabled="disabled" @click="nextPage">
<v-icon small>
mdi-chevron-right
</v-icon>
</v-btn>
</template>
</v-pagination>
</div>
</v-row>
</v-container>
<DetailModal
:status="activeDetail"
:name="productModal.name"
:price="productModal.price"
:description="productModal.description"
:images="productModal.images"
:product_id="productModal.id"
@close="activeDetail=false"
/>
</div>
</template>
<script>
import BreadCrumb from '@/components/BreadCrumb'
import DetailModal from '@/components/DetailModal'
import { eventBus } from '~/plugins/eventBus.js'
export default {
layout: 'user',
component: {
BreadCrumb,
DetailModal
},
data: () => {
return {
activeDetail: false,
breadcrumbItems: [
{
text: 'Home',
disabled: false,
href: '/home'
},
{
text: 'Element',
disabled: false,
href: '/'
},
{
text: 'Post',
disabled: false,
href: '/posts'
}
],
icons: ['mdi-cart', 'mdi-heart', 'mdi-magnify'],
products: [],
page: 1,
productModal: {
name: '',
price: '',
description: '',
images: []
},
profile: {
name: '',
price: '',
description: ''
},
itemsPerPage: 8,
currentPage: 1,
wishlish: []
}
},
computed: {
totalPages () {
return Math.ceil(this.products.length / this.itemsPerPage)
},
pagedCards () {
const startIndex = (this.currentPage - 1) * this.itemsPerPage
const endIndex = startIndex + this.itemsPerPage
return this.products.slice(startIndex, endIndex)
},
totalVisiblePages () {
return Math.min(this.totalPages, 7)
}
},
created () {
this.getProductByCategoryId()
},
methods: {
async getProductByCategoryId () {
const resp = await this.$axios.get(`/guest/categories/products-by-category-id/${this.$route.params.id}`, {
headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}`
}
})
.then(response => (this.products = response.data.data[0].products))
.catch(function (error) {
console.log(error)
})
console.log(resp[0].products)
console.log(this.products[0].images[0])
},
openDialogDetail () {
this.activeDetail = false
this.activeDetail = true
},
getDataItem (item) {
console.log(item)
this.productModal = item
console.log(this.productModal.name)
},
saveProfile (data) {
this.profile = this.productModal
},
nextPage () {
this.currentPage++
},
prevPage () {
this.currentPage--
},
addToWishlish (item) {
const fd = new FormData()
fd.append('product_id', item.id)
this.$axios
.post('/wish-list/add-to-wish-list',
fd,
{
headers: {
Authorization: `Bearer ${this.$auth.$storage.getUniversal('token')}`
}
})
.then((response) => {
console.log(response)
this.$toast.success('Add product successfully!', {
duration: 2000
})
eventBus.$emit('add-to-wish-list', response)
})
.catch((errors) => {
this.$toast.error('something went wrong!', {
duration: 2000
})
})
}
}
}
</script>
<style lang="scss" scoped>
.v-card {
transition: opacity .4s ease-in-out;
}
.v-card:not(.on-hover) {
opacity: 0.9;
}
.show-btns {
color: #1976d2 !important;
}
.mdi-fast-forward::before {
content: "\F0211";
}
.mdi:before, .mdi-set {
display: inline-block;
font: normal normal normal 24px/1 "Material Design Icons";
font-size: inherit;
text-rendering: auto;
line-height: inherit;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
::before, ::after {
text-decoration: inherit;
vertical-align: inherit;
}
*, ::before, ::after {
background-repeat: no-repeat;
box-sizing: inherit;
}
.v-btn--icon.v-size--default .v-icon, .v-btn--fab.v-size--default .v-icon {
height: 24px;
font-size: 24px;
width: 24px;
}
.v-btn > .v-btn__content .v-icon {
color: rgba(255, 255, 255, 1);
}
</style>
...@@ -120,6 +120,7 @@ export default { ...@@ -120,6 +120,7 @@ export default {
localStorage.setItem('token', resp.data.data.bearer_token) localStorage.setItem('token', resp.data.data.bearer_token)
this.$auth.$storage.setUniversal('token', resp.data.data.bearer_token) this.$auth.$storage.setUniversal('token', resp.data.data.bearer_token)
this.$auth.$storage.setUniversal('userName', resp.data.data.name) this.$auth.$storage.setUniversal('userName', resp.data.data.name)
this.$auth.$storage.setUniversal('ID', resp.data.data.id)
this.$auth.$storage.setUniversal('loggedIn', 'true') this.$auth.$storage.setUniversal('loggedIn', 'true')
if (resp.status === 200) { if (resp.status === 200) {
this.$toast.success('Successfully authenticated', { this.$toast.success('Successfully authenticated', {
......
import Vue from 'vue'
export const eventBus = new Vue()
export const state = () => ({
currentCategory: ''
})
export const mutations = {
setCurrentCategory (state, category) {
state.currentCategory = category
}
}
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
Vue.use(Vuex) Vue.use(Vuex)
export const store = new Vuex.Store({ export const state = () => ({
modules: { products: []
}
}) })
export const mutations = {
setProducts (state, products) {
state.products = products
},
addProduct (state, product) {
state.products.push(product)
}
}
export const actions = {
async fetchProducts ({ commit }) {
// Lấy dữ liệu sản phẩm từ API
const products = await fetch('https://example.com/products')
.then(response => response.json())
.then(data => data)
// Lưu dữ liệu sản phẩm vào store Vuex
commit('setProducts', products)
}
}
export const getters = {
getProductById: state => (id) => {
return state.products.find(product => product.id === id)
}
}
export const strict = false
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment