adding waypoints in the react-google-maps - google-maps-api-3

editable samplecode how to use waypoints in the following code does the waypoints helps to plot the way which I updated in the database wheather the ponits will be based on the points I have updated
const DirectionsService = new google.maps.DirectionsService();
const DirectionsDisplay = new google.maps.DirectionsRenderer({suppressMarkers: true},{strokeColor:"#4a4a4a"});
DirectionsService.route({
origin: new google.maps.LatLng(this.state.orgin.latitude ,this.state.orgin.longitude),
destination: new google.maps.LatLng(this.state.destination.latitude ,this.state.destination.longitude),
travelMode: google.maps.TravelMode.DRIVING,
},
(result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
this.setState({
directions: result,
});
} else {
console.error(`error fetching directions ${result}`);
}
});
}).catch(function (err) {
});
}
})
)(props =>
<GoogleMap
defaultZoom={50}>
<DirectionsRenderer directions={props.directions} />
< Marker
position={{ lat:props.delivery!=undefined?props.delivery.latitude:null, lng: props.delivery!=undefined?props.delivery.longitude:null }} />
</GoogleMap>
);
return (
<MapWithADirectionsRenderer />
)
}

You can add waypoints by adding waypoints[] array of DirectionsWaypoint in your Directions Request.
You can check this documentation to learn more: https://developers.google.com/maps/documentation/javascript/directions#DirectionsRequests
Here's a sample waypoints array:
waypoints: [
{
location: new google.maps.LatLng(14.546748, 121.05455)
},
{
location: new google.maps.LatLng(14.552444,121.044488)
}
]
Here's a sample Direction Request with waypoints:
DirectionsService.route({
origin: new google.maps.LatLng(14.533593, 121.053128),
destination: new google.maps.LatLng(14.550895, 121.025079),
travelMode: google.maps.TravelMode.DRIVING,
waypoints: [
{
location: new google.maps.LatLng(14.546748, 121.05455)
},
{
location: new google.maps.LatLng(14.552444,121.044488)
}
]
}, (result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
this.setState({
directions: result,
});
} else {
console.error(`error fetching directions ${result}`);
}
});

A very simple way to implement wayPoints in React
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { withScriptjs } from "react-google-maps";
import Map from './components/Map';
function App() {
const MapLoader = withScriptjs(Map);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
</header>
<MapLoader
googleMapURL="https://maps.googleapis.com/maps/api/js?key=Key"
loadingElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
export default App;
And in your Map.js file
/*global google*/
import React, { Component } from "react";
import {
withGoogleMap,
withScriptjs,
GoogleMap,
DirectionsRenderer
} from "react-google-maps";
class Map extends Component {
state = {
directions: null,
};
componentDidMount() {
const directionsService = new google.maps.DirectionsService();
const origin = { lat: 6.5244, lng: 3.3792 };
const destination = { lat: 6.4667, lng: 3.4500};
directionsService.route(
{
origin: origin,
destination: destination,
travelMode: google.maps.TravelMode.DRIVING,
waypoints: [
{
location: new google.maps.LatLng(6.4698, 3.5852)
},
{
location: new google.maps.LatLng(6.6018,3.3515)
}
]
},
(result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
console.log(result)
this.setState({
directions: result
});
} else {
console.error(`error fetching directions ${result}`);
}
}
);
}
render() {
const GoogleMapExample = withGoogleMap(props => (
<GoogleMap
defaultCenter={{ lat: 6.5244, lng: 3.3792 }}
defaultZoom={13}
>
<DirectionsRenderer
directions={this.state.directions}
/>
</GoogleMap>
));
return (
<div>
<GoogleMapExample
containerElement={<div style={{ height: `500px`, width: "500px" }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default Map;
I believe this is okay

Related

Vue3- Vuetify - Infinite scroll like instagram/facebook

I'm developing a website that I want to add a infinite scroll feature.
This site is currently using vue3 and vuetify next.
The following code is a component with a default slot.(It's working, but not as I wanted)
Component
<template>
<section>
<slot />
<VRow v-if="data?.loadMoreSection?.showLoadMoreSection" class="mt-10" no-gutters>
<VContainer fluid>
<VRow
v-if="data?.loadMoreSection?.showScrollDownOrLoadMoreText && !data.delayScroll"
>
<VSpacer />
<VCol cols="auto">
<span v-if="data?.loadMoreSection?.loadMoreType">
{{
getText({
...(data?.loadMoreSection?.scrollDownOrLoadMoreText ?? {}),
params: { type: getText(data?.loadMoreSection?.loadMoreType) },
})
}}
</span>
<span v-else>
{{ getText(data?.loadMoreSection?.scrollDownOrLoadMoreText) }}
</span>
</VCol>
<VSpacer />
</VRow>
<VRow v-if="data?.loadMoreSection?.showLoadMoreButton">
<VSpacer />
<VCol cols="auto">
<VBtn #click.stop="onLoadMore">
<span v-if="data?.loadMoreSection?.loadMoreType">
{{
getText({
...(data?.loadMoreSection?.loadMoreButtonText ?? {}),
params: { type: getText(data?.loadMoreSection?.loadMoreType) },
})
}}
</span>
<span v-else>
{{ getText(data?.loadMoreSection?.loadMoreButtonText) }}
</span>
</VBtn>
</VCol>
<VSpacer />
</VRow>
</VContainer>
</VRow>
</section>
</template>
<script setup lang="ts">
import { Events } from "#enums";
import { ILocaleText } from "#models/localeText";
export interface IInfiniteScrollLoaderEvents {
(e: Events.onScroll): void;
(e: Events.onLoadMore): void;
(e: Events.onScrollDelayed): void;
}
export interface IInfiniteScrollLoadMoreSectionProperties {
showLoadMoreSection?: boolean;
showLoadMoreButton?: boolean;
showScrollDownOrLoadMoreText?: boolean;
scrollDownText?: ILocaleText;
loadMoreButtonText?: ILocaleText;
loadMoreType?: ILocaleText;
scrollDownOrLoadMoreText?: ILocaleText;
}
export interface IInfiniteScrollLoaderProperties {
padding?: number;
scrollTimeoutMs?: number;
disableScroll?: boolean;
loadMoreSection?: IInfiniteScrollLoadMoreSectionProperties;
}
interface IInfiniteScrollLoaderData {
delayScroll: boolean;
loadMoreSection?: IInfiniteScrollLoadMoreSectionProperties;
}
const properties = withDefaults(defineProps<IInfiniteScrollLoaderProperties>(), {
padding: 50,
disableScroll: false,
scrollTimeoutMs: 1000,
});
const data = reactive<IInfiniteScrollLoaderData>({
delayScroll: false,
loadMoreSection: {
showLoadMoreSection: true,
showLoadMoreButton: true,
showScrollDownOrLoadMoreText: true,
loadMoreButtonText: {
key: "templates.loadMoreTypeEllipsis",
},
scrollDownOrLoadMoreText: {
key: "templates.scrollDownOrClickToLoadMoreTypeEllipsis",
},
},
});
onMounted(async () => {
await mergeLoadMoreSectionPropertiesWithData();
});
async function mergeLoadMoreSectionPropertiesWithData() {
const merged = {};
Object.assign(merged, data.loadMoreSection, properties.loadMoreSection);
data.loadMoreSection = merged;
}
const emits = defineEmits<IInfiniteScrollLoaderEvents>();
const isValidScroll = computed(
() =>
window.scrollY + window.innerHeight >= document.body.scrollHeight - properties.padding
);
function delayScroll() {
data.delayScroll = true;
setTimeout(() => {
data.delayScroll = false;
emits(Events.onScrollDelayed);
}, properties.scrollTimeoutMs ?? 1000);
}
function isScrollingDown(event: any) {
if (!event) return false;
return !(event.deltaY && event.deltaY < 0);
}
function onLoadMore(event: any) {
emits(Events.onLoadMore);
}
function onScroll(event: any) {
if (properties.disableScroll) return;
if (!isScrollingDown(event)) return;
if (!isValidScroll) return;
if (data.delayScroll) return;
emits(Events.onScroll);
delayScroll();
}
onMounted(async () => {
if (!properties.disableScroll) window.addEventListener("wheel", onScroll);
});
onUnmounted(async () => {
if (!properties.disableScroll) window.removeEventListener("wheel", onScroll);
});
</script>
Usage Example
<template>
<InfiniteScrollLoader
#on-scroll="fetchData"
#on-load-more="fetchData"
:scroll-timeout-ms="5000"
:disable-scroll="data.loading"
:loadMoreSection="props.loadMoreSection"
>
<div>content</div>
</InfiniteScrollLoader>
</template>
<script setup lang="ts">
async function fetchData(){
await setTimeout(()=>console.log('fetched'),5000)
}
</script>
I just want to make this component more smooth. But I'm terrible working with css/animations and etc, I don't have any idea how to implement it.

Next.js: Can't deploy production build; Works in dev; Am I using the async functions correctly?

I am trying to create a production build for a next.js project. However I am getting the following error.
Error occurred prerendering page "/products". Read more: https://nextjs.org/docs/messages/prerender-error
TypeError: Cannot destructure property 'productList' of 'data' as it is undefined.
at ProductTile (/Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/jcrew-take-home-assignment/.next/server/chunks/619.js:39:5)
at d (/Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/jcrew-take-home-assignment/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:33:498)
at bb (/Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/jcrew-take-home-assignment/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:36:16)
at a.b.render (/Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/jcrew-take-home-assignment/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:42:43)
at a.b.read (/Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/jcrew-take-home-assignment/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:41:83)
at exports.renderToString (/Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/jcrew-take-home-assignment/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:52:138)
at Object.renderPage (/Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/jcrew-take-home-assignment/node_modules/next/dist/next-server/server/render.js:53:854)
at Function.getInitialProps (/Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/jcrew-take-home-assignment/.next/server/pages/_document.js:599:19)
at loadGetInitialProps (/Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/jcrew-take-home-assignment/node_modules/next/dist/next-server/lib/utils.js:5:101)
at renderToHTML (/Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/jcrew-take-home-assignment/node_modules/next/dist/next-server/server/render.js:53:1145)
errors FetchError: request to http://localhost:8000/category-server/ failed, reason: connect ECONNREFUSED 127.0.0.1:8000
at ClientRequest.<anonymous> (/Users/antonio-pavicevac-ortiz/Dropbox/developer_folder/jcrew-take-home-assignment/node_modules/node-fetch/lib/index.js:1461:11)
at ClientRequest.emit (node:events:327:20)
at Socket.socketErrorListener (node:_http_client:478:9)
at Socket.emit (node:events:327:20)
at emitErrorNT (node:internal/streams/destroy:194:8)
at emitErrorCloseNT (node:internal/streams/destroy:159:3)
at processTicksAndRejections (node:internal/process/task_queues:80:21) {
type: 'system',
errno: 'ECONNREFUSED',
code: 'ECONNREFUSED'
}
I believe the crux of it is:
Error occurred prerendering page "/products". Read more: https://nextjs.org/docs/messages/prerender-error
But I can't figure it out—here are the asnyc files in questions:
[product].js
import React, { useEffect, useState } from 'react'
import Image from 'next/image'
import Link from 'next/link'
import Swatches from '../../components/Swatches.js'
function Product({ query }) {
let { defaultColorCode, description, colors, product, price } = query;
colors = JSON.parse(colors)
let [productImage, setProductImage] = useState(`/${product}_${defaultColorCode}`);
const handleProductChange = (productCode, defaultColorCode) => {
setProductImage(`/${productCode}_${defaultColorCode}`)
}
const myLoader = ({ src }) => {
return `https://www.jcrew.com/s7-img-facade/${src}`
}
return (
<div className="p-10 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-1 lg:grid-cols-2 xl:grid-cols-2 gap-5">
<div className="product-link p-2 rounded overflow-hidden shadow-lg">
<Image className="product-image" loader={myLoader}
src={productImage} alt={description} layout="fill" />
<p className="font-medium text-sm mb-2">{description}</p>
<p className="text-sm text-gray-700">
{
price
}
</p>
</div>
<span className="p-3 font-medium text-sm mb-2">
<Swatches handleProductChange={handleProductChange} defaultColorCode={defaultColorCode} productImage={productImage} productCode={product} colors={colors} />
</span>
</div>
)
}
export const getServerSideProps = ({ query }) => {
return {
props: {
query
}
}
}
export default Product
The home page:
import Head from 'next/head'
import ProductPage from './products.js'
export const getStaticProps = async () => {
try {
const res = await fetch('http://localhost:8000/category-server/')
const data = await res.json()
return {
props: {
data: data
},
}
} catch (error) {
console.log('errors', error)
}
}
export default function Home({ data }) {
return (
<>
<Head>
<title>Category Page 🤔</title>
<meta charSet="utf-8" />
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
<ProductPage data={data} />
</>
)
}
Update:
I wound up updating the /server/category-server.js file:
const express = require('express')
const next = require('next')
const PORT = parseInt(process.env.PORT, 10) || 8000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express();
server.get('https://jcrew-take-home-assignment.herokuapp.com/category-server', function (req, res) {
res.json(require('./category'))
})
server.all('*', (req, res) => {
return handle(req, res)
})
if (process.env.NODE_ENV === 'production') {
server.use(express.static('.next/'));
server.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, '.next/', 'index.html'));
});
server.listen(PORT, err => {
if (err) throw err;
console.log(
`> Ready and listening on PORT:${PORT} in the ${process.env.NODE_ENV} environment`
);
});
} else {
server.listen(PORT, err => {
if (err) throw err;
console.log(`> Ready and listening on http://localhost:${PORT}`);
});
}
My pages/index.js
import Head from 'next/head'
import absoluteUrl from 'next-absolute-url'
import dynamic from 'next/dynamic'
const ProductPage = dynamic(
() => import('./products.js'),
{ ssr: false }
)
const fetchRelative = (req, path) => {
const { origin } = absoluteUrl(req)
return fetch(`${origin}${path}`);
}
export const getStaticProps = async ({ req, res }) => {
if (typeof (window) !== 'undefined') {
var res = await fetchRelative(req, '/category-server/')
var data = await res.json()
}
return {
props: {
data: data || {}
},
}
}
export default function Home({ data }) {
return (
<>
<Head>
<title>Category Page 🤔</title>
<meta charSet="utf-8" />
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
<ProductPage data={data} />
</>
)
}
And my ProductTile.js
import React from 'react'
import Image from 'next/image'
import Link from 'next/link'
const ProductTile = ({ data = {} }) => {
let { productList } = data
var [products] = productList || []
var { products } = products || {};
React.useEffect(() => {
function remove_style(all) {
var i = all.length;
var j, is_hidden;
// Presentational attributes.
var attr = [
'align',
'background',
'bgcolor',
'border',
'cellpadding',
'cellspacing',
'color',
'face',
'height',
'hspace',
'marginheight',
'marginwidth',
'noshade',
'nowrap',
'valign',
'vspace',
'width',
'vlink',
'alink',
'text',
'link',
'frame',
'frameborder',
'clear',
'scrolling',
'style'
];
var attr_len = attr.length;
while (i--) {
is_hidden = (all[i].style.display === 'none');
j = attr_len;
while (j--) {
all[i].removeAttribute(attr[j]);
}
if (is_hidden) {
all[i].style.display = 'none';
is_hidden = false;
}
}
}
var all = window.document.getElementsByTagName('*');
remove_style(all);
}, [])
const myLoader = ({ src }) => {
return `https://www.jcrew.com/s7-img-facade/${src}`
}
const getColorSwatches = (products, index) => {
if (products[index] != undefined) {
return JSON.stringify(products[index].colors)
}
}
return (
<div>
<div className="p-10 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-3 lg:grid-cols-3 xl:grid-cols-3 gap-5">
{
products != undefined && products.reduce((products, product) => products.find(x => x.productId === product.productId) ? products : [...products, product], []).map(({ colorCode, defaultColorCode, now, productId, productCode,
productDescription, }, index) => {
let path = `https://www.jcrew.com/s7-img-facade/${productCode}_${defaultColorCode}`
let swatches = getColorSwatches(products, index)
return (
<Link key={`${productId}${index}`}
href={{
pathname: '/s7-img-facade/[slug]',
query: {
defaultColorCode: defaultColorCode,
slug: productCode,
description: productDescription, image: path, price: now !== undefined
? now.formatted
: 'Not-available',
colors: swatches
},
}}
passHref>
<div className="product-link p-2 rounded overflow-hidden shadow-lg">
<Image className="product-image" loader={myLoader}
src={`/${productCode}_${defaultColorCode}`} alt={productDescription} layout="fill" />
<p className="font-medium text-sm mb-2">{productDescription}</p>
<p className="text-sm text-gray-700">
{
now !== undefined
? now.formatted
: 'Not-available'
}
</p>
</div>
</Link>
)
})}
</div>
</div>
)
}
export default ProductTile

How to add custom markers using google maps directions api in react js

Tech Stack - Google Map Directions Api, React JS, etc.
Problem Statement - Using google maps direction Api's i am drawing 3 pins i.e. origin, waypoints and destination. I am able to plot all these of these but unable to add custom markers to each of these. Any help/suggestion shall be really appreciated: -
Code Snippet: -
import React, { Component } from "react";
import {
withGoogleMap,
withScriptjs,
GoogleMap,
DirectionsRenderer
} from "react-google-maps";
class Map extends Component {
state = {
directions: null
};
componentDidMount() {
const directionsService = new google.maps.DirectionsService();
const origin = { lat: 40.756795, lng: -73.954298, icon: 'https://toppng.com/uploads/preview/map-marker-icon-600x-map-marker-11562939743ayfahlvygl.png' };
const destination = { lat: 41.756795, lng: -78.954298, icon: 'https://toppng.com/uploads/preview/map-marker-icon-600x-map-marker-11562939743ayfahlvygl.png' };
directionsService.route({
origin: origin,
destination: destination,
waypoints: [{
location: new google.maps.LatLng(42.756795, -78.954298, 'https://toppng.com/uploads/preview/map-marker-icon-600x-map-marker-11562939743ayfahlvygl.png'),
stopover: false
}],
travelMode: google.maps.TravelMode.DRIVING
},
(result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
this.setState({
directions: result
});
} else {
console.error(`error fetching directions ${result}`);
}
}
);
}
render() {
const GoogleMapExample = withGoogleMap(props => (
<GoogleMap
defaultCenter={{ lat: 40.756795, lng: -73.954298 }}
defaultZoom={13}
>
<DirectionsRenderer
directions={this.state.directions}
/>
</GoogleMap>
));
return (
<div>
<GoogleMapExample
containerElement={<div style={{ height: `500px`, width: "500px" }} />}
mapElement={<div style={{ height: `100%` }} />}
/>
</div>
);
}
}
export default Map;
Thanks
react-google-maps has a Marker component that you can use.
<GoogleMap
defaultCenter={{ lat: 40.756795, lng: -73.954298 }}
defaultZoom={13}
>
<DirectionsRenderer
directions={this.state.directions}
/>
<Marker location={{ lat: x, lng: y }} />
</GoogleMap>

How To Edit Date and Time Picker Vuejs Vuetify From Firebase Using Latest Version

Hello i am new in vuejs and vuetify, today and a couple weeks ago i am learning how to create project using vuejs, vuetify and firebase as storage data. my project refer to this links : https://www.youtube.com/watch?v=FXY1UyQfSFw&list=PL55RiY5tL51qxUbODJG9cgrsVd7ZHbPrt and still working on progress now i am stuck with my project below are the entire of my all code:
components folder components/Meetup/EditMeetupDateDioalog.vue
<template>
<v-flex xs12 sm6 md4>
<v-dialog
v-model="editDialog"
persistent
lazy
full-width
width="290px"
>
<v-btn slot="activator" flat outline small color="primary">Edit date</v-btn>
<v-date-picker v-model="editableDate" scrollable>
<v-spacer></v-spacer>
<v-btn flat color="primary" #click="editDialog = false">Cancel</v-btn>
<v-btn flat color="primary" #click.native="onSaveChanges">Save</v-btn>
</v-date-picker>
</v-dialog>
</v-flex>
</template>
<script>
export default {
props: ['meetup'],
data () {
return {
editDialog: false,
editableDate: null
}
},
methods: {
onSaveChanges () {
const newDate = new Date(this.meetup.date)
const newDay = new Date(this.editableDate).getUTCDate()
const newMonth = new Date(this.editableDate).getUTCMonth()
const newYear = new Date(this.editableDate).getUTCFullYear()
newDate.setUTCDate(newDay)
newDate.setUTCMonth(newMonth)
newDate.setUTCFullYear(newYear)
this.$store.dispatch('updateMeetupData', {
id: this.meetup.id,
date: newDate
})
}
},
created () {
this.editableDate = new Date(this.meetup.date)
}
}
</script>
main.js
import Vue from 'vue'
import App from './App'
import * as firebase from 'firebase'
import router from './router'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.min.css'
import { store } from './store'
import DateFilter from './filters/date'
import AlertCmp from './components/Shared/Alert.vue'
import EditMeetupDetailsDialog from './components/Meetup/Edit/EditMeetupDetailsDialog.vue'
import EditMeetupDateDialog from './components/Meetup/Edit/EditMeetupDateDialog.vue'
// import GMapAutocomplete from './components/Meetup/GMapAutocomplete.vue'
Vue.use(Vuetify, { theme: {
primary: '#03a9f4',
secondary: '#424242',
accent: '#82B1FF',
error: '#FF5252',
info: '#2196F3',
success: '#4CAF50',
warning: '#FFC107'
}})
Vue.config.productionTip = false
Vue.filter('date', DateFilter)
Vue.component('app-alert', AlertCmp)
Vue.component('app-edit-meetup-details-dialog', EditMeetupDetailsDialog)
Vue.component('app-edit-meetup-date-dialog', EditMeetupDateDialog)
// Vue.component('app-gmap-autocomplete', GMapAutocomplete)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
render: h => h(App),
created () {
firebase.initializeApp({
apiKey: 'AIzaSyCd_0uXFwdV5s6NTqJyC*******',
authDomain: 'kopdar-dev.firebaseapp.com',
databaseURL: 'https://kopdar-dev.firebaseio.com',
projectId: 'kopdar-dev',
storageBucket: 'kopdar-dev.appspot.com'
})
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.$store.dispatch('autoSignIn', user)
}
})
this.$store.dispatch('loadedMeetups')
}
})
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import * as firebase from 'firebase'
Vue.use(Vuex)
export const store = new Vuex.Store({
state: {
loadedMeetups: [
{
imageUrl: 'http://www.all-free-photos.com/images/paris/IM2392-hr.jpg',
id: 'kdgkyrjwlklnfhaifh25u92wrl',
title: 'Meetup in Paris',
date: new Date(),
location: 'Paris - French',
description: 'This meetup talk about modern web application'
},
{
imageUrl: 'http://www.all-free-photos.com/images/berlin/PI88764-hr.jpg',
id: 'sjgs8wjw0sklsgj90836skfnk',
title: 'Meetup in Berlin',
date: new Date(),
location: 'Berlin - German',
description: 'Talk about I/O modern web application'
}
],
user: null,
loading: false,
error: null
},
mutations: {
setLoadedMeetups (state, payload) {
state.loadedMeetups = payload
},
createMeetup (state, payload) {
state.loadedMeetups.push(payload)
},
updateMeetup (state, payload) {
const meetup = state.loadedMeetups.find(meetup => {
return meetup.id === payload.id
})
if (payload.title) {
meetup.title = payload.title
}
if (payload.description) {
meetup.description = payload.description
}
if (payload.location) {
meetup.location = payload.location
}
if (payload.date) {
meetup.date = payload.date.toISOString
}
},
setUser (state, payload) {
state.user = payload
},
setLoading (state, payload) {
state.loading = payload
},
setError (state, payload) {
state.error = payload
},
clearError (state) {
state.error = null
}
},
actions: {
loadedMeetups ({commit}) {
commit('setLoading', true)
firebase.database().ref('kopdar').once('value')
.then(
(data) => {
const kopdar = []
const obj = data.val()
for (let key in obj) {
kopdar.push({
id: key,
title: obj[key].title,
location: obj[key].location,
description: obj[key].description,
imageUrl: obj[key].imageUrl,
date: obj[key].date,
creatorId: obj[key].creatorId
})
}
commit('setLoadedMeetups', kopdar)
commit('setLoading', false)
}
)
.catch(
(error) => {
console.log(error)
commit('setLoading', true)
}
)
},
createMeetup ({commit, getters}, payload) {
const meetup = {
title: payload.title,
location: payload.location,
description: payload.description,
date: payload.date.toISOString(),
creatorId: getters.user.id
}
let imageUrl
let key
firebase.database().ref('kopdar').push(meetup)
.then((data) => {
key = data.key
return key
})
.then(key => {
const filename = payload.image.name
const ext = filename.slice(filename.lastIndexOf('.'))
return firebase.storage().ref('kopdar/' + key + '.' + ext).put(payload.image)
})
.then(fileData => {
// imageUrl = fileData.metadata.downloadURLs[0]
// imageUrl = 'http://www.all-free-photos.com/images/paris/IM2392-hr.jpg'
imageUrl = firebase.storage().ref(fileData.metadata.fullPath).getDownloadURL()
.then((url) => {
return firebase.database().ref('kopdar').child(key).update({imageUrl: url})
})
// return firebase.database().ref('kopdar').child(key).update({imageUrl: imageUrl})
})
.then(() => {
commit('createMeetup', {
...meetup,
imageUrl: imageUrl,
id: key
})
})
.catch((error) => {
console.log(error)
})
// Reach out to firebase and store it
},
updateMeetupData ({commit}, payload) {
commit('setLoading', true)
const updateObj = {}
if (payload.title) {
updateObj.title = payload.title
}
if (payload.description) {
updateObj.description = payload.description
}
if (payload.location) {
updateObj.location = payload.location
}
if (payload.date) {
updateObj.date = payload.date.toISOString()
}
firebase.database().ref('kopdar').child(payload.id).update(updateObj)
.then(() => {
commit('setLoading', false)
commit('updateMeetup', payload)
})
.catch(error => {
console.log(error)
commit('setloading', false)
})
},
signUserUp ({commit}, payload) {
commit('setLoading', true)
commit('clearError')
firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
.then(
user => {
commit('setLoading', false)
const newUser = {
id: user.uid,
registeredMeetups: []
}
commit('setUser', newUser)
}
)
.catch(
error => {
commit('setLoading', false)
commit('setError', error)
console.log(error)
}
)
},
signUserIn ({commit}, payload) {
commit('setLoading', true)
commit('clearError')
firebase.auth().signInWithEmailAndPassword(payload.email, payload.password)
.then(
user => {
commit('setLoading', false)
const newUser = {
id: user.uid,
registeredMeetups: []
}
commit('setUser', newUser)
}
)
.catch(
error => {
commit('setLoading', false)
commit('setError', error)
console.log(error)
}
)
},
autoSignIn ({commit}, payload) {
commit('setUser', {id: payload.uid, registeredMeetups: []})
},
logout ({commit}) {
firebase.auth().signOut()
commit('setUser', null)
},
clearError ({commit}) {
commit('clearError')
}
},
getters: {
loadedMeetups (state) {
return state.loadedMeetups.sort((meetupA, meetupB) => {
return meetupA.date > meetupB.date
})
},
featuredMeetups (state, getters) {
return getters.loadedMeetups.slice(0, 5)
},
loadedMeetup (state) {
return (meetupId) => {
return state.loadedMeetups.find((meetup) => {
return meetup.id === meetupId
})
}
},
user (state) {
return state.user
},
loading (state) {
return state.loading
},
error (state) {
return state.error
}
}
})
My Meetup.vue
<template>
<v-container>
<v-layout row wrap>
<v-flex xs12 sm6 offset-sm3>
<!-- <v-progress-circular
:size="70"
:width="7"
color="primary"
indeterminate
v-if="loading"
></v-progress-circular> -->
<!-- <div class="text-xs-center">
<v-progress-circular
:rotate="-90"
:size="100"
:width="15"
:value="value"
color="primary"
v-if="loading">
{{ value }}
</v-progress-circular>
</div>-->
<v-progress-linear background-color="blue-grey"
color="lime" :indeterminate="true" v-if="loading"></v-progress-linear>
</v-flex>
</v-layout>
<v-layout row wrap>
<v-flex xs12 sm8 offset-sm2 v-if="!loading">
<v-card>
<v-img
:src="meetup.imageUrl"
height="300px"></v-img>
<v-card-title>
<h3 class="primary--text"><strong>{{ meetup.title }}</strong></h3>
<template v-if="userIsCreator">
<v-spacer></v-spacer>
<app-edit-meetup-details-dialog :meetup="meetup"></app-edit-meetup-details-dialog>
</template>
</v-card-title>
<v-card-text>
<div>
<app-edit-meetup-date-dialog
:meetup="meetup"
v-if="userIsCreator"></app-edit-meetup-date-dialog>
</div>
<div class="info--text">{{ meetup.date | date }} | {{ meetup.location }}</div>
<div>{{ meetup.description }}</div>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn round outline class="primary">Register</v-btn>
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-container>
</template>
<script>
export default {
data () {
return {
interval: {},
value: 0
}
},
beforeDestroy () {
clearInterval(this.interval)
},
mounted () {
this.interval = setInterval(() => {
if (this.value === 10) {
return (this.value = 0)
}
this.value += 1
}, 1000)
},
props: ['id'],
computed: {
meetup () {
return this.$store.getters.loadedMeetup(this.id)
},
loading () {
return this.$store.getters.loading
},
userIsAuthenticated () {
return this.$store.getters.user !== null && this.$store.getters.user !== undefined
},
userIsCreator () {
if (!this.userIsAuthenticated) {
return false
}
return this.$store.getters.user.id === this.meetup.creatorId
}
}
}
</script>
<style scopedSlots>
.v-progress-circular{
margin: 1rem
}
</style>
This is the entire errors that I got
This is my error picture link : https://imgur.com/a/nnDbhpA
This is my EditMeetupTimeDialog.vue
<template>
<v-flex xs12 sm6 md4>
<v-dialog
v-model="editDialog"
persistent
lazy
full-width
width="290px"
>
<v-btn slot="activator" flat outline small color="primary">Edit time</v-btn>
<v-time-picker v-model="editableTime" format="24hr">
<v-spacer></v-spacer>
<v-btn flat color="primary" #click="editDialog = false">Cancel</v-btn>
<v-btn flat color="primary" #click.native="onSaveChanges">Save</v-btn>
</v-time-picker>
</v-dialog>
</v-flex>
</template>
<script>
export default {
props: ['meetup'],
data () {
return {
editDialog: false,
editableTime: null
}
},
methods: {
onSaveChanges () {
const newDate = new Date(this.meetup.date)
const hours = this.editableTime.match(/^(\d+)/)[1]
const minutes = this.editableTime.match(/:(\d+)/)[1]
newDate.setHours(hours)
newDate.setMinutes(minutes)
this.$store.dispatch('updateMeetupData', {
id: this.meetup.id,
date: newDate.getTime()
})
}
},
created () {
this.editableTime = new Date(this.meetup.date).getTime()
}
}
</script>
and i still get errors using getTime() and toISOString()
Hope this question makes sense.
Note: I am using the latest version software to dealing with my practice project
In Vuetify document, the value which is passed to v-date-picker need to be an array or string. You can convert:
methods: {
onSaveChanges () {
const newDate = new Date(this.meetup.date)
const newDay = new Date(this.editableDate).getUTCDate()
const newMonth = new Date(this.editableDate).getUTCMonth()
const newYear = new Date(this.editableDate).getUTCFullYear()
newDate.setUTCDate(newDay)
newDate.setUTCMonth(newMonth)
newDate.setUTCFullYear(newYear)
this.$store.dispatch('updateMeetupData', {
id: this.meetup.id,
date: newDate.toISOString().substr(0, 10)
})
}
},
created () {
this.editableDate = new Date(this.meetup.date).toISOString().substr(0, 10)
}

Vuex state change is not reactive

I am working with Vuex and Firebase Auth system.
I just want to store with Vuex the user object that i get from:
firebase.auth().getCurrentUser
so that every time it changes, it updates the views.
But i ve troubles with this.
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
user: {
loggedIn: false,
data: null
}
},
getters: {
user(state){
return state.user
}
},
mutations: {
SET_LOGGED_IN(state, value) {
state.user.loggedIn = value;
},
SET_USER(state, data) {
state.user.data = data;
}
},
actions: {
fetchUser({ commit }, user) {
commit("SET_LOGGED_IN", user !== null);
if (user) {
commit("SET_USER", user);
} else {
commit("SET_USER", null);
}
}
}
});
Account.vue
<template>
<ion-item>
<ion-label #click="openModal()" position="stacked">Your name</ion-label>
{{user.data.displayName}}
</ion-item>
</template>
computed: {
// map `this.user` to `this.$store.getters.user`
...mapGetters({
user: "user"
})
},
methods: {
openModal() {
let us = this.$store.getters.user;
return this.$ionic.modalController
.create({
component: Modal,
componentProps: {
data: {
content: 'New Content',
},
propsData: {
pro: us.data.displayName
},
},
})
.then(m => m.present())
},
.
.
.
</script>
Modal.vue
<template>
<ion-app>
<h1>MODAL</h1>
<ion-input :value="prop" #input="prop = $event.target.value"></ion-input>
<ion-button #click="clos()">Save</ion-button>
</ion-app>
</template>
<script>
import firebase from "firebase";
export default {
props:['pro'],
data(){
return{
prop: this.pro
}
},
methods:{
clos(){
let vm = this;
let user = firebase.auth().currentUser;
window.console.log("updating",vm.prop)
user.updateProfile({
displayName: vm.prop
}).then(function(){
user = firebase.auth().currentUser;
vm.$store.dispatch("fetchUser",user);
}).catch(function(err){
window.console.log("err",err);
})
this.$ionic.modalController.dismiss();
}
}
}
</script>
I can see using Vue Dev Tools that when I dispatch the new user in Modal.vue
vm.$store.dispatch("fetchUser",user);
that the Vuex state is correctly updated, but the view in Account.vue is not.
But if I press the button 'commit this mutation' in the dev tools the view updates!
How can I fix this behavior?
try this solution:
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
user: {
loggedIn: false,
data: null
}
},
getters: {
user(state){
return state.user;
},
userData(state){
return state.user.data;
}
},
mutations: {
SET_LOGGED_IN(state, value) {
state.user.loggedIn = value;
},
SET_USER(state, data) {
state.user.data = data;
}
},
actions: {
fetchUser({ commit }, user) {
commit("SET_LOGGED_IN", user !== null);
if (user) {
commit("SET_USER", user);
} else {
commit("SET_USER", null);
}
}
}
});
Account.vue
<template>
<ion-item>
<ion-label #click="openModal()" position="stacked">Your name</ion-label>
{{user.displayName}}
</ion-item>
</template>
computed: {
// map `this.user` to `this.$store.getters.user`
...mapGetters({
user: "userData"
})
},
methods: {
openModal() {
let us = this.$store.getters.userData;
return this.$ionic.modalController
.create({
component: Modal,
componentProps: {
data: {
content: 'New Content',
},
propsData: {
pro: us.displayName
},
},
})
.then(m => m.present())
},
.
.
.
</script>
You can try this:
SET_USER(state, data) {
Vue.$set(state.user, 'data', data)
}

Resources