Commit 496651de authored by catea792's avatar catea792
parents ffcb4ea2 c70504d5
<template>
<div class=" page-header dark-section">
<h3 class="page-subtitle">
categories
</h3>
<h2 class="page-title">
BREADCRUMB
</h2>
<ul class="breadcrumb">
<v-breadcrumbs :items="items">
<template #divider>
<v-icon>mdi-chevron-right</v-icon>
</template>
</v-breadcrumbs>
</ul>
</div>
</template>
<script>
export default {
name: 'BreadCrumb',
computed: {
items () {
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
}
}
}
</script>
<style scope>
.page-header {
background-image: url(https://d-themes.com/html/riode/images/shop/page-header-back.jpg);
background-color: #3C63A4;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 250px;
padding: 3em 1em;
background-color: #C8C3BF;
background-position: center;
background-size: cover;
text-align: center;
color: #222;
width: 100vw;
margin-top: 10px;
}
.breadcrumb {
display: flex;
flex-wrap: wrap;
align-items: center;
color: #666;
font-family: Poppins,sans-serif;
font-size: 1.4rem;
}
.v-application a {
color: #fff !important;
}
.page-title {
margin-bottom: 0;
text-transform: uppercase;
font-size: 4rem;
line-height: 1.125;
color: #222;
color: #fff;
}
.page-subtitle {
margin-bottom: 0.5rem;
text-transform: uppercase;
font-size: 2rem;
line-height: 1.2;
color: #fff;
}
</style>
<!-- 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/no-parsing-error -->
<template>
<v-footer dark padless>
<v-card flat tile class="indigo lighten-1 white--text text-center">
<v-card-text>
<v-btn v-for="icon in icons" :key="icon" class="mx-4 white--text" icon>
<v-icon size="24px">
{{ icon }}
</v-icon>
</v-btn>
</v-card-text>
<v-card-text class="white--text pt-0">
Phasellus feugiat arcu sapien, et iaculis ipsum elementum sit amet.
Mauris cursus commodo interdum. Praesent ut risus eget metus luctus
accumsan id ultrices nunc. Sed at orci sed massa consectetur dignissim a
sit amet dui. Duis commodo vitae velit et faucibus. Morbi vehicula
lacinia malesuada. Nulla placerat augue vel ipsum ultrices, cursus
iaculis dui sollicitudin. Vestibulum eu ipsum vel diam elementum tempor
vel ut orci. Orci varius natoque penatibus et magnis dis parturient
montes, nascetur ridiculus mus.
</v-card-text>
<v-divider />
<div class="footer-bottom">
<div class="footer-bottom-left">
<figure class="payment">
<img
src="~/assets/images/payment.png"
alt="payment"
width="159"
height="29"
>
</figure>
</div>
<p class="copyright">
Riode eCommerce © 2022. All Rights Reserved
</p>
<div class="footer-bottom-right">
<div class="social-link">
<v-btn
v-for="icon in icons"
:key="icon"
class="mx-4 white--text"
icon
>
<v-icon size="24px">
{{ icon }}
</v-icon>
</v-btn>
</div>
</div>
<v-footer class="mt-12 flex-wrap" min-height="350px" dark padless>
<v-row class="d-flex justify-space-between align-center">
<v-col
cols="12"
md="3"
>
<v-img
width="153px"
src="https://d-themes.com/html/riode/images/logo-footer.png"
/>
</v-col>
<div class="flex-column">
<h3>Subscribe to our Newsletter</h3>
<h4>Get all the latest information, Sales and Offers.</h4>
</div>
</v-card>
<v-col
cols="12"
md="4"
>
<v-text-field label="email address here ..."></v-text-field>
</v-col>
<v-btn color="primary">SUBSCRIBE</v-btn>
</v-row>
<v-divider></v-divider>
</v-footer>
</template>
<script>
export default {
name: 'FooterBar',
data: () => ({
icons: ['mdi-facebook', 'mdi-twitter', 'mdi-linkedin', 'mdi-instagram']
icons: ['mdi-facebook', 'mdi-twitter', 'mdi-linkedin', 'mdi-instagram'],
img: 'https://d-themes.com/html/riode/images/logo-footer.png'
})
}
</script>
<style>
.footer-bottom-left {
position: absolute;
left: 0;
}
.footer-bottom-right {
position: absolute;
right: 0;
}
.copyright {
position: absolute;
left: 0;
right: 0;
margin-left: auto;
margin-right: auto;
}
</style>
<style></style>
<template>
<v-row
justify="center"
>
<v-dialog
v-model="dialog"
width="450px"
@click:outside="closeDialog"
>
<v-card-title class="justify-center">
<p class="font-weight-black" style="font-size: 35px">
LOGIN
</p>
</v-card-title>
<v-form ref="form" justify="center" class="formlogin">
<v-col cols="12" sm="6" md="12">
<v-text-field
v-model="email"
variant="underlined"
label="Email"
required
/>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field
v-model="password"
variant="underlined"
label="Password"
required
/>
</v-col>
<v-col cols="12" sm="6" md="12" justify-content: space-between>
<v-checkbox
label="Remember me"
/>
</v-col>
<div class="d-flex flex-column">
<v-btn
color="primary"
class="mt-4"
block
@click="login"
>
Login
</v-btn>
<v-btn
color="primary"
class="mt-4"
block
@click="$emit('close')"
>
Close
</v-btn>
</div>
</v-form>
<v-col cols="12" style="display:flex">
<v-divider sm="6" /> login with <v-divider sm="6" />
</v-col>
<v-col cols="12" style="text-align: center;">
<v-icon>
mdi-twitter
</v-icon>
<v-icon>
mdi-facebook
</v-icon>
<v-icon>
mdi-instagram
</v-icon>
</v-col>
</v-dialog>
</v-row>
</template>
<script>
export default {
name: 'LoginModal',
props: {
status: {
type: Boolean,
default: true
}
},
data: () => ({
email: '',
password: ''
}),
computed: {
dialog () {
return this.status
}
},
methods: {
async login () {
try {
const resp = await this.$axios.post('/login',
{
email: this.email,
password: this.password
})
localStorage.setItem('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('loggedIn', 'true')
if (resp.status === 200) {
this.$toast.success('Successfully authenticated', {
duration: 2000
})
this.$router.push('home')
}
} catch (e) {
this.$toast.error('Username or Password not valid', {
duration: 2000
})
this.$router.push('/login')
}
},
closeDialog () {
this.$props.status = false
}
}
}
</script>
<style scoped>
.formlogin {
padding: 30px;
}
::v-deep .v-dialog{
background-color: #5ae2dc;
}
</style>
<template>
<v-carousel
cycle
height="550"
hide-delimiter-background
show-arrows-on-hover
>
<v-carousel-item
v-for="(slide, i) in slides"
:key="i"
:src="img[i]"
>
<v-row
class="fill-height"
align="center"
justify="center"
>
<div class="text-h2">
{{ slide }} Slide
</div>
</v-row>
</v-carousel-item>
</v-carousel>
</template>
<script>
export default {
name: 'PageCarousels',
data () {
return {
img: [
'https://d-themes.com/html/riode/images/demos/demo1/slides/slide1.jpg',
'https://d-themes.com/html/riode/images/demos/demo1/slides/slide2.jpg'
],
slides: [
'First',
'Second'
]
}
}
}
</script>
<style>
.v-window__container {
margin-top: 20px;
}
</style>
<template>
<v-row justify="center">
<v-dialog
v-model="dialog"
width="450px"
@click:outside="closeDialog"
>
<v-card-title class="justify-center">
<p class="font-weight-black" style="font-size: 35px">
REGISTER
</p>
</v-card-title>
<v-form ref="form" justify="center" class="formlogin">
<v-col cols="12" sm="6" md="12">
<v-text-field
v-model="name"
variant="underlined"
label="Name"
:rules="requiredRules"
required
/>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field
v-model="email"
variant="underlined"
label="Email"
:rules="emailRules"
required
/>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field
v-model="password"
variant="underlined"
label="Password"
type="password"
:rules="passwordRules"
required
/>
</v-col>
<v-col cols="12" sm="6" md="12">
<v-text-field
v-model="password_confirmation"
variant="underlined"
label="Confirm your password"
type="password"
:rules="[passwordRules, passwordConfirmationRule]"
required
/>
</v-col>
<v-col cols="12" sm="6" md="12" justify-content: space-between>
<v-checkbox
v-model="checkbox"
label="I agree to the privacy policy"
/>
</v-col>
<div class="d-flex flex-column">
<v-btn
color="primary"
class="mt-4"
block
@click="signup"
>
Sign Up
</v-btn>
<v-btn
color="primary"
class="mt-4"
block
@click="$emit('close')"
>
Close
</v-btn>
</div>
</v-form>
<v-col cols="12" style="display:flex">
<v-divider sm="6" /> login with <v-divider sm="6" />
</v-col>
<v-col cols="12" style="text-align: center;">
<v-icon>
mdi-twitter
</v-icon>
<v-icon>
mdi-facebook
</v-icon>
<v-icon>
mdi-instagram
</v-icon>
</v-col>
</v-dialog>
</v-row>
</template>
<script>
export default {
name: 'SignupModal',
props: {
status: {
type: Boolean,
default: false
}
},
data: () => ({
name: '',
email: '',
password: '',
password_confirmation: '',
checkbox: '',
requiredRules: [
v => !!v || 'This field is required'
],
emailRules: [
v => !!v || 'E-mail is required',
v => /.+@.+\..+/.test(v) || 'E-mail must be valid'
],
passwordRules: [
v => !!v || 'Password is required',
v => (v && v.length >= 6) || 'Password must be more than 6 characters',
v => (v && v.length <= 255) || 'Password must be less than 255 characters'
]
}),
computed: {
dialog () {
return this.status
},
passwordConfirmationRule () {
return () => (this.password === this.password_confirmation) || 'Password must match'
}
},
methods: {
async signup () {
try {
await this.$axios.post('/register', {
name: this.name,
email: this.email,
password: this.password,
password_confirmation: this.password_confirmation
}
).then((resp) => {
if (resp.data.status === 'success') {
this.$toast.success('Register successfully', {
duration: 2000
})
this.$router.push('login')
}
})
} catch (error) {
this.$toast.error(error.response.data.message, {
duration: 2000
})
}
},
closeDialog () {
this.$props.status = false
}
}
}
</script>
<style scoped>
.formlogin {
padding: 30px;
}
::v-deep .v-dialog{
background-color: #5ae2dc;
}
</style>
<template>
<div>
<!-- header top -->
<div class="header-top">
<v-container class="pa-0">
<v-row no-gutters>
<v-col cols="12" sm="8" class="header-top-left">
<span>Hello message</span>
</v-col>
<v-col cols="12" sm="4" class="header-top-right">
<div class="dropdown">
<span> USD </span>
<v-icon small>
mdi-chevron-down
</v-icon>
<div class="dropdown-content">
<div
v-for="(item, i) in currency"
:key="i"
class="dropdown-item"
>
<span>
{{ item.text }}
</span>
</div>
</div>
</div>
<div class="dropdown">
<span> ENG </span>
<v-icon small>
mdi-chevron-down
</v-icon>
<div class="dropdown-content">
<div
v-for="(item, i) in languages"
:key="i"
class="dropdown-item"
>
<span>
{{ item.text }}
</span>
</div>
</div>
</div>
<v-divider vertical />
<div class="header-info">
<v-icon small>
mdi-map-marker-outline
</v-icon>
<span>Contact</span>
</div>
<div class="header-info">
<v-icon small>
mdi-alert-circle-outline
</v-icon>
<span>Need help</span>
</div>
<div class="authentication">
<div class="header-info" @click="openDialogLogin">
<v-icon small>
mdi-account-outline
</v-icon>
<span>Login</span>
</div>
<v-icon small>
mdi-slash-forward
</v-icon>
<div class="header-info" @click="openDialogSignUp">
<span>Signup</span>
</div>
</div>
</v-col>
</v-row>
</v-container>
</div>
<!-- end header top -->
<!-- header middle -->
<div class="header-middle d-flex">
<v-container class="header-middle-content" py-7>
<v-col cols="12" md="8" class="header-middle-left padding-0">
<div class="logo">
<v-img
width="153px"
src="https://d-themes.com/html/riode/images/logo.png"
/>
</div>
<v-form class="d-flex form-search">
<v-text-field
outlined
dense
hide-details="auto"
label="Search"
class="search-input"
/>
<span class="icon">
<v-icon> mdi-magnify </v-icon>
</span>
</v-form>
</v-col>
<v-col cols="12" md="4" class="header-middle-right padding-0">
<div class="hotline d-flex">
<v-icon large>
mdi-phone-outline
</v-icon>
<div class="contact">
<span>Call us now:</span>
<b>0(800) 123-456</b>
</div>
</div>
<v-divider vertical inset />
<div class="wish-list" v-bind="attrs" v-on="on" @click.stop="drawer = true">
<v-icon large>
mdi-heart-outline
</v-icon>
</div>
<v-divider vertical inset />
<div id="menu-activator" class="cart" plain v-bind="attrs" v-on="on">
<span>Shopping cart:
<b>$:0.00</b>
</span>
<v-badge
:content="products.length || 0"
floating
bordered
overlap
>
<v-icon large>
mdi-cart-outline
</v-icon>
</v-badge>
<v-menu activator="#menu-activator" style="width: 300px">
<v-list dense three-line>
<v-list-item
v-for="item in products"
:key="item.id"
link
>
<v-list-item-avatar>
<v-img :src="item.product.images[0]" />
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>{{ item.product.name }}</v-list-item-title>
<v-list-item-subtitle>{{ item.quantity +"x"+ item.product.price }}</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
<v-btn icon @click="removeCart(item,index)">
<v-icon color="grey lighten-1">
mdi-close-circle-outline
</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list>
<v-divider />
<div class="d-flex justify-space-between align-center ma-4">
<span>Subtotal: </span>
<span> {{ total + "$" }} </span>
</div>
<v-divider />
<v-btn
size="x-large"
color="primary"
class="d-flex mt-4 align-center mx-auto"
>
GO TO CHECKOUT
</v-btn>
</v-menu>
</div>
</v-col>
</v-container>
</div>
<!-- end header middle -->
<!-- header bottom -->
<div class="header-bottom">
<NavBar />
</div>
<!-- end header bottom -->
<!-- show modal -->
<LoginModal :status="activeLogin" @close="activeLogin = false" />
<SignupModal :status="activeRegister" @close="activeRegister = false" />
<!-- show drawer -->
<v-navigation-drawer
v-model="drawer"
absolute
right
width="350px"
temporary
>
<div class="d-flex justify-space-between drawer_header">
<b>WISHLIST</b>
<v-btn plain @click.stop="drawer = !drawer">
Close
<v-icon> mdi-arrow-right-thin </v-icon>
</v-btn>
</div>
<v-divider />
<v-list dense three-line>
<v-list-item v-for="item in wishlist" :key="item.name" link>
<v-list-item-avatar>
<v-img :src="item.product.images[0]" />
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title>{{ item.product.name }}</v-list-item-title>
<v-list-item-subtitle>{{ item.product.price }}</v-list-item-subtitle>
</v-list-item-content>
<v-list-item-action>
<v-btn icon @click="removeWishlist(item, index)">
<v-icon color="grey lighten-1">
mdi-close-circle-outline
</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list>
</v-navigation-drawer>
</div>
</template>
<script>
import LoginModal from '~/components/LoginModal.vue'
import SignupModal from '~/components/RegisterModal.vue'
import NavBar from '~/components/user/NavBar'
import { eventBus } from '~/plugins/eventBus.js'
export default {
name: 'UserHeader',
components: {
LoginModal,
SignupModal,
NavBar
},
data: () => {
return {
products: [],
wishlist: [],
activeLogin: false,
activeRegister: false,
drawer: false,
currency: [
{ text: 'USD', icon: 'mdi-clock' },
{ text: 'EUR', icon: 'mdi-account' }
],
languages: [
{ text: 'ENG', icon: 'mdi-clock' },
{ text: 'FRH', icon: 'mdi-account' }
]
}
},
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: {
closeDialog () {
this.activeLogin = false
this.activeLogin = true
},
openDialogLogin () {
this.activeLogin = false
this.activeLogin = true
},
openDialogSignUp () {
this.activeRegister = false
this.activeRegister = true
},
removeCart (item, index) {
try {
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()
})
}
}
}
</script>
<style scoped>
.header-top {
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
font-size: 12px;
color: rgba(0, 0, 0, 0.8);
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
.header-top-left {
display: flex;
align-items: center;
}
.header-top-right {
display: flex;
align-items: center;
justify-content: space-between;
z-index: 10;
}
.dropdown {
display: flex;
cursor: pointer;
position: relative;
}
.dropdown > span {
line-height: 2rem;
}
.dropdown-content {
display: none;
position: absolute;
top: 30px;
background: white;
box-shadow: 2px 2px 15px 3px rgba(1, 1, 1, 0.3);
}
.dropdown-item {
margin: 5px 7px;
}
.v-divider--vertical {
min-height: 70%;
max-height: 70%;
margin: 5px -1px;
}
.header-info {
cursor: pointer;
}
span:hover {
color: #2266cc;
cursor: pointer;
}
.dropdown:hover .dropdown-content {
display: block;
}
.header-info {
display: flex;
align-items: center;
}
.header-info:hover .span.v-icon{
color: #2266cc;
}
.authentication {
display: flex;
}
.v-icon.v-icon {
margin: 0 3px;
}
.header-middle-content {
display: flex;
padding-left: 0;
padding-right: 0;
font-size: 12px;
color: #000000;
}
.header-middle-left {
display: flex;
align-items: center;
padding-right: 0;
padding-left: 0;
justify-content: space-between;
}
.padding-0 {
padding: 0 !important;
}
.logo {
display: flex;
align-items: center;
}
.form-search {
width: 100%;
position: relative;
margin: 0 auto;
margin: 0 5vw;
}
.search-input {
width: inherit;
position: absolute;
}
span.icon {
position: absolute;
right: 5px;
cursor: pointer;
}
span.icon:hover .v-icon.v-icon{
color: #2266cc;
}
.header-middle-right {
display: flex;
justify-content: space-between;
}
b {
display: block;
font-size: 14px;
}
.hotline {
cursor: pointer;
}
.hotline:hover {
color: #2266cc;
}
.wish-list {
cursor: pointer;
}
.wish-list:hover .v-icon.v-icon {
color: #2266cc;
}
.cart {
display: flex;
}
.v-application .d-flex {
align-items: center;
}
.favorite-modal {
position: fixed;
}
.favorite-modal .modal_header {
padding: 20px 0px 20px 30px;
}
.modal_header > b {
font-weight: 700;
font-size: 16px;
}
.modal_header > button {
font-size: 12px;
}
.modal_header > i {
scale: 0.8;
}
.drawer_header {
padding: 20px 0 20px 30px;
}
.v-menu__content {
width: 300px;
top: 110px !important;
padding: 25px;
background-color: #ffffff;
}
</style>
<template>
<v-container>
<div class="navbar d-flex justify-space-between ">
<div class="d-flex justify-space-between col-md-7">
<div>
<span>
Home
</span>
</div>
<div class="dropdown">
<span>
Products
</span>
<v-icon>mdi-chevron-down</v-icon>
<div class="dropdown-content elevation-10" :elevation="2">
<v-treeview
:active.sync="active"
rounded
dense
hoverable
activatable
: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>
<span>
Pages
</span>
</div>
<div>
<span>
Blogs
</span>
</div>
<div>
<span>
About
</span>
</div>
</div>
<div class="d-flex align-center ">
<v-icon>mdi-tag</v-icon>
<span class="mx-2">
Special offer!
</span>
<span class="mx-2">
Buy riode
</span>
</div>
</div>
</v-container>
</template>
<script>
import { mapActions, mapState } from 'vuex'
export default {
name: 'NavBar',
data: () => ({
active: [],
open: [],
categories: []
}),
computed: {
...mapState(['selectedCategory']),
...mapActions(['setSelectedCategory']),
selected () {
if (!this.active.length) { return undefined }
const id = this.active[0]
console.log(id)
// console.log(this.categories.find(category => category.id === id).name)
return this.categories.find(category => category.id === id) || ''
}
},
watch: {
selected () {
if (!this.active.length) { return undefined }
const id = this.active[0]
return id || ''
}
},
beforeCreate () {
this.$axios
.get('guest/categories/index')
.then((response) => {
this.categories = response.data.data
})
.catch(function (error) {
console.log(error)
})
},
mounted () {
},
methods: {
setCategory () {
console.log(this.selected)
this.$store.commit('category/setCurrentCategory', this.selected.name || '')
}
}
}
</script>
<style scoped>
.navbar span {
font-weight: bold;
cursor: pointer;
transition: 0.3s;
}
.navbar span:hover {
color: #26c;
}
.dropdown {
position: relative;
}
.dropdown:hover .dropdown-content {
display: block;
}
.dropdown-content {
display: none;
position: absolute;
z-index: 1;
background-color: #ffffff;
min-width: 350px;
/* margin-top: 20px; */
}
</style>
<style>
div .v-treeview-node__label {
cursor: pointer;
}
</style>
<template>
<Nuxt />
<Nuxt />
</template>
<script>
......
<template>
<nuxt />
</template>
\ No newline at end of file
<template>
<v-app>
<UserHeader ref="child" />
<Nuxt />
<FooterBar />
</v-app>
</template>
<script>
import Header from '@/components/user/Header'
import FooterBar from '@/components/FooterBar'
export default {
component: {
Header,
FooterBar
},
components: { FooterBar },
created () {
this.changeColor()
},
methods: {
changeColor () {
this.$vuetify.theme.dark = !this.$vuetify.theme.dark
return true
}
}
}
</script>
<style>
body{
font-family: monospace;
}
</style>
......@@ -29,7 +29,8 @@ export default {
// Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
plugins: [
'~/plugins/axios.js',
'~/plugins/formatTime.js'
'~/plugins/formatTime.js',
'~/plugins/eventBus.js'
],
// Auto import components: https://go.nuxtjs.dev/config-components
......
<template>
<div>
<div>
<h1 style="text-align: center">ABOUT</h1>
</div>
<div>
<h1 style="text-align: center">
ABOUT
</h1>
</div>
</div>
</template>
\ No newline at end of file
</template>
<!-- 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>
<!-- eslint-disable vue/no-v-for-template-key -->
<!-- eslint-disable vue/html-end-tags -->
<!-- eslint-disable vue/no-unused-vars -->
<template>
<div>
<BreadCrumb />
<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 items"
: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"
height="250px"
cover
/>
<!-- <v-card-actions v-if="hover" class="d-flex align-center justify-center" style="position: absolute">
<v-btn
v-for="(icon, index) in icons"
:key="index"
:class="{ 'show-btns': hover }"
icon
>
<v-icon
:class="{ 'show-btns': hover }"
>
{{ icon }}
</v-icon>
</v-btn>
</v-card-actions> -->
</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
>
<v-icon
:class="{ 'show-btns': hover }"
>
mdi-cart
</v-icon>
</v-btn>
<v-btn
:class="{ 'show-btns': hover }"
icon
>
<v-icon
:class="{ 'show-btns': hover }"
>
mdi-heart
</v-icon>
</v-btn>
<v-btn
:class="{ 'show-btns': hover }"
icon
>
<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="page"
:length="4"
prev-icon="mdi-menu-left"
next-icon="mdi-menu-right"
/>
</div>
</v-row>
</v-container>
</div>
</template>
<script>
import BreadCrumb from '@/components/BreadCrumb'
export default {
components: { BreadCrumb },
layout: 'user',
component: {
BreadCrumb
},
data: () => {
return {
items: [
{
images: 'https://cdn.vuetifyjs.com/images/cards/sunshine.jpg',
name: 'Brunch this weekend?',
price: '50$'
},
{
images: 'https://cdn.vuetifyjs.com/images/cards/sunshine.jpg',
name: 'Brunch this weekend?',
price: '50$'
},
{
images: 'https://cdn.vuetifyjs.com/images/cards/sunshine.jpg',
name: 'Brunch this weekend?',
price: '50$'
},
{
images: 'https://cdn.vuetifyjs.com/images/cards/sunshine.jpg',
name: 'Brunch this weekend?',
price: '50$'
},
{
images: 'https://cdn.vuetifyjs.com/images/cards/sunshine.jpg',
name: 'Brunch this weekend?',
price: '50$'
},
{
images: 'https://cdn.vuetifyjs.com/images/cards/sunshine.jpg',
name: 'Brunch this weekend?',
price: '50$'
},
{
images: 'https://cdn.vuetifyjs.com/images/cards/sunshine.jpg',
name: 'Brunch this weekend?',
price: '50$'
},
{
images: 'https://cdn.vuetifyjs.com/images/cards/sunshine.jpg',
name: 'Brunch this weekend?',
price: '50$'
}
],
icons: ['mdi-cart', 'mdi-heart', 'mdi-magnify'],
products: [],
page: 1
}
},
created () {
this.getProductByCategoryId()
},
methods: {
async getProductByCategoryId () {
const resp = await this.$axios.get('/guest/categories/products-by-category-id/1', {
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])
}
}
}
</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>
<template>
<div>
<!-- Banners -->
<PageCarousels />
</div>
</template>
<script>
import PageCarousels from '@/components/PageCarousels'
export default {
layout: 'user',
component: {
PageCarousels
}
}
</script>
<style>
</style>
......@@ -120,6 +120,7 @@ export default {
localStorage.setItem('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('ID', resp.data.data.id)
this.$auth.$storage.setUniversal('loggedIn', 'true')
if (resp.status === 200) {
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 Vuex from 'vuex'
Vue.use(Vuex)
export const store = new Vuex.Store({
modules: {
}
export const state = () => ({
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