I got the user profile from the Realtime database but when I have more than 1 account I get the second user profile too.
Here below you see the data from 2 users. But I want to get the user that is loggend in and that is the currentUser
The ID is the currentUser
This is the Realtime database:
This is my Profile.vue page:
<div class="container" v-for="profileData of profile" :key="profileData['.key']">
<div v-if="seen" class="row">
<div class="col">
<div class="card card-border" style="width: 30rem;">
<div class="card-body">
<h4 class="card-title text-center mb-4">Personal information</h4>
<p class="card-text">ID: {{profileData.CurrentUser}}</p>
<p class="card-text">First name: {{profileData.firstName}}</p>
<p class="card-text">Last name: {{profileData.lastName}}</p>
<p class="card-text">Phone number: {{profileData.phoneNumber}}</p>
<p class="card-text">Adress: {{profileData.adress}}</p>
<p class="card-text">Citizenship: {{profileData.citizenship}}</p>
<p class="card-text">Personal email: {{profileData.personalEmail}}</p>
</div>
</div>
</div>
<div class="col"></div>
<div class="col">
<div class="card card-border" style="width: 30rem;">
<div class="card-body">
<h4 class="card-title text-center mb-3">Business information</h4>
<p>Company name: {{profileData.companyName}}</p>
<p>Chamber Of Commerce Number: {{profileData.chamberOfCommerceNumber}}</p>
<p>Street: {{profileData.street}}</p>
<p>House number: {{profileData.houseNumber}}</p>
<p>ZIP code: {{profileData.zipCode}}</p>
<p>Location: {{profileData.location}}</p>
<p>Company email: {{profileData.companyEmail}}</p>
</div>
</div>
</div>
</div>
</div>
I added a if/else in the created() section below.
And this is the script:
<script>
import firebase from "firebase";
import { db } from '../../config/db';
export default {
data() {
return {
email: "",
password: "",
profileData: [],
isHidden: true,
seen: true,
isLoggedIn: false
}
},
firebase: {
profile: db.ref('profile')
},
methods: {
resetPassword() {
const auth = firebase.auth();
auth.sendPasswordResetEmail(auth.currentUser.email).then(() => {
console.log('Email send');
// Email sent.
}).catch((error) => {
// An error happened.
console.log(error);
});
}
},
created() {
if(firebase.auth().currentUser) {
this.isLoggedIn = true;
this.currentUser = firebase.auth().currentUser.email;
}
var user = firebase.auth().currentUser;
if (this.user == this.profileData.CurrentUser) {
this.seen = true;
} else {
this.seen = false;
}
}
};
</script>
In this Profile.vue page I have the add function:
AddProfile() {
console.log(JSON.stringify(this.profileData) + this.currentUser)
this.$firebaseRefs.profile.push({
firstName: this.profileData.firstName,
lastName: this.profileData.lastName,
phoneNumber: this.profileData.phoneNumber,
adress: this.profileData.adress,
citizenship: this.profileData.citizenship,
personalEmail: this.profileData.personalEmail,
companyName: this.profileData.companyName,
chamberOfCommerceNumber: this.profileData.chamberOfCommerceNumber,
street: this.profileData.street,
houseNumber: this.profileData.houseNumber,
zipCode: this.profileData.zipCode,
location: this.profileData.location,
companyEmail: this.profileData.companyEmail,
CurrentUser: this.currentUser
})
this.profileData.firstName = '';
this.profileData.lastName = '';
this.profileData.phoneNumber = '';
this.profileData.adress = '';
this.profileData.personalEmail = '';
this.profileData.companyName = '';
this.profileData.chamberOfCommerceNumber = '';
this.profileData.street = '';
this.profileData.houseNumber = '';
this.profileData.zipCode = '';
this.profileData.location = '';
this.profileData.companyEmail = '';
this.CurrentUser = '';
window.scrollTo(0,0, 0,0);
console.log('Added to database');
/* Waiting for 2 seconds here */
this.$router.push('/internship')
},
Apparently you are using Vuefire.
As you will see in the Vuefire documentation, by doing
firebase: {
profile: db.ref('profile')
},
you are using a declarative biding on the profile Realtime Database node and therefore it is normal that you get all the children of this node.
If you just want to display the node corresponding to the current user, you could use the programmatic binding, along the following lines:
<template>
<div class="home">
{{user}}
<ol></ol>
</div>
</template>
<script>
import { db } from "../firebase";
const profile = db.ref("profile");
export default {
name: "demo",
data() {
return {
user: null,
id: null
};
},
watch: {
id: {
immediate: true,
handler(id) {
this.$rtdbBind("user", profile.child(id));
}
}
},
created() {
if (firebase.auth().currentUser) {
this.id = currentUser.uid;
}
}
};
</script>
Related
I have a vue3 web app. My issue is that once I try to navigate to a page using <router-link to ="/Dashboard"/>
Below is the Dashboard.vue
<template>
<div class="enquiry">
<div class="row">
<div class="col-6" v-for="(p, index) in keyAreas" :key="index">
<div class="card" style="margin-bottom: 10px">
<div class="card-body">
<h2 class="card-title">
{{ p.number }}
<span class="card-title" style="float: right">{{ p.title }}</span>
</h2>
<h5 class="card-text">
Properties for rent
<span class="card-title" style="float: right; margin-top: -5px">
<Doughnut
:chart-data="updateChartData(p.number, totalPropertiesNumber)"
:width="80"
:height="80"
/>
</span>
</h5>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { ref } from "vue";
import { projectDatabase } from "../../firebase/config";
import getUser from "../../composables/getUser";
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
ArcElement,
CategoryScale,
} from "chart.js";
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale);
export default {
setup() {
//to get user info e.g email and display name
const { user } = getUser();
const company = ref("");
const keyAreas = ref([]);
//all LGAs
const allLGAs = ref([
{ title: "Abuja", number: 0 },
{ title: "Banana Island", number: 0 },
{ title: "Bluewaters Lagos", number: 0 },
{ title: "Benin City", number: 0 },
{ title: "Eko Atlantic", number: 0 },
]);
//Query Function for Specific Locations
const filterLocation = (item, query, filter) => {
if (item[filter] === query) {
return true;
}
return false;
};
//reference from firebase for user company
projectDatabase
.ref("users")
.child(user.value.uid)
.child("company")
.on("value", (snapshot) => {
company.value = snapshot.val();
//loop through all LGAs array and update dashboard by filtering each LGA for its properties in its field
allLGAs.value.forEach(function (p) {
p.number = Object.keys(snapshot.val())
.map((key) => {
snapshot.val()[key].id = key;
return snapshot.val()[key];
})
.filter((item) => {
return filterLocation(item, p.title, "location");
}).length;
if (p.number > 0) {
keyAreas.value.push(p);
}
});
});
return {
allLGAs,
company,
keyAreas,
};
},
};
</script>
The problem is every time i move to a new page, the page freezes and I have to refresh to see all the items in the v-for loop. This happens to about 3 pages on the web app. Is there a way to solve this?
I have also tried disabling all my browser extensions and things of that nature yet the problem still persists. Could it be because of the size of the array being loaded in the v-for?
OP solved his issue by finding out that Bootstrap v5 adds a class called offcanvas with
overflow: hidden;
overflow-x: hidden;
overflow-y: hidden;
Enabling the scrolling makes it functional again.
I'm creating a blog with free sewing patterns as content. I'm using route parameters to receive each blog individually. However, I'm getting a blank page when trying to retrieve its data from firebase firestore. Please help.
The blog's id appears on my address bar:
http://localhost:8080/#/admin/single-pattern/4LIS362IEWa7RKEv79g8
But it renders a blank page. I cant see my blog content.
This is my route path code. I've added a parameter of :id in my singlepattern. The SinglePattern component is where I will get the individual blog's data:
{
path: "/admin",
name: "admin",
component: Admin,
meta: {
auth: true,
},
children: [
{
path: "dashboard",
name: "dashboard",
component: Dashboard,
},
{
path: "manage-patterns",
name: "manage-patterns",
component: ManagePatterns,
},
{
path: "single-pattern/:id",
name: "single-pattern",
component: SinglePattern,
},
],
},
Here is my "ListPattern" component's code. ListPattern is where all my sewing blogs are displayed.
<template>
<div class="list-blogs">
<h1>LIST BLOG TITLES</h1>
<br />
<input type="text" v-model="search" placeholder="search blogs" />
<div
class="blog-cover"
v-for="pattern in filteredPatterns"
:key="pattern.id"
>
<div>
<router-link v-bind:to="'/admin/single-pattern/' + pattern.id">
<h3 style="cursor: pointer" v-rainbow>
{{ pattern.title | uppercase }}
</h3></router-link
>
</div>
<p
:style="'background-color: var(--lightgrey)'"
:inner-html.prop="pattern.description | snippet"
></p>
</div>
</div>
</template>
<script>
import firebase from "firebase";
import searchMixin from "../mixins/searchMixin";
// Basic Use - Covers most scenarios
import { VueEditor } from "vue2-editor";
import Quill from "quill";
const AlignStyle = Quill.import("attributors/style/align");
Quill.register(AlignStyle, true);
// import $ from "jquery";
import Swal from "sweetalert2";
window.Swal = Swal;
const Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
});
window.Toast = Toast;
export default {
name: "ManagePatterns",
components: { VueEditor },
data() {
return {
patterns: [],
pattern: {
title: null,
description: null,
image: null,
},
search: "",
};
},
firestore() {
return {
patterns: firebase.firestore().collection("free-patterns"),
};
},
computed: {},
},
};
</script>
And this is my 'SinglePattern' component where the clicked blog/pattern is displayed.
<template>
<div class="single-pattern">
<div class="blog-cover">
<div>
</div>
<div v-if="pattern">
<h3 style="cursor: pointer">
{{ pattern.title }}
</h3>
<div v-if="pattern.description">
<p
:style="'background-color: var(--lightgrey)'"
:inner-html.prop="pattern.description"
></p>
</div>
</div>
</div>
</div>
</template>
<script>
import firebase from "firebase";
import searchMixin from "../../mixins/searchMixin";
export default {
data() {
return {
id: this.$route.params.id,
patterns: [],
pattern: {
title: null,
description: null,
image: null,
},
};
},
firestore() {
return {
patterns: firebase.firestore().collection("free-patterns"),
};
},
mixins: [searchMixin],
created() {
console.log(this.$route.params.id);
var pat = this;
firebase
.firestore()
.collection("free-patterns")
.doc(this.$route.params.id)
.get()
.then(function(doc) {
if (doc.exists) {
pat.pattern = doc.data().pattern;
} else {
console.log("no such doc");
}
});
},
methods: {},
};
</script>
It works. I just had to change the code in my created() hook in 'SingePattern' component.
created() {
console.log(this.$route.params.id);
var docRef = firebase
.firestore()
.collection("free-patterns")
.doc(this.$route.params.id);
docRef
.get()
.then((doc) => {
if (doc.exists) {
this.pattern = doc.data();
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
})
.catch((error) => {
console.log("Error getting document:", error);
});
I am trying to show the current userName and title which was already created by signin and now stored in Firebase Cloud Firestore database.
But I don't know how to handle this, I can't find an error in the code by my self.
Here is the code:
<template>
<div id="dashboard">
<section>
<div class="col1">
<div class="profile">
<h5>{{ userProfile.name }}</h5>
<p>{{ userProfile.title }}</p>
<div class="create-post">
<p>create a post</p>
<form #submit.prevent>
<textarea v-model.trim="post.content"></textarea>
<button #click="createPost"
class="button">post</button>
</form>
</div>
</div>
</div>
<div class="col2">
<div>
<p class="no-results">There are currently no posts</p>
</div>
</div>
</section>
</div>
</template>
<script>
const fb = require('../firebaseConfig.js')
import { mapState } from 'vuex'
import firebase from 'firebase'
const db = firebase.firestore()
export default {
data() {
return {
post: {
content: ''
}
}
},
computed: {
...mapState(['userProfile'])
},
methods: {
createPost() {
fb.postsCollection.add({
createdOn: new Date(),
content: this.post.content,
userId: this.currentUser.uid,
userName: this.userProfile.name,
comments: 0,
likes: 0
}).then(ref => {
this.post.content = ''
}).catch(err => {
console.log(err)
})
}
}
}
</script>
Store.js
import Vue from 'vue'
import Vuex from 'vuex'
const fb = require('./firebaseConfig.js')
Vue.use(Vuex)
// handle page reload
fb.auth.onAuthStateChanged(user => {
if (user) {
store.commit('setCurrentUser', user)
store.dispatch('fetchUserProfile')
}
})
export const store = new Vuex.Store({
state: {
currentUser: null,
userProfile: {}
},
actions: {
clearData ({ commit }) {
commit('setCurrentUser', null)
commit('setUserProfile', {})
},
fetchUserProfile ({
commit,
state
}) {
fb.usersCollection.doc(state.currentUser.uid).get().then(res => {
commit('setUserProfile', state.res.data())
}).catch(err => {
console.log(err)
})
console.log(state)
}
},
mutations: {
setCurrentUser (state, val) {
state.currentUser = val
},
setUserProfile (state, val) {
state.userProfile = val
}
}
})
Error output:
userProfile output as Object:
I'an not using getters.js file seperately, instead getters are written in js->assets->store->modules->user.js file
This is my user.js
const state = {
count : '',
list:[]
};
const mutations = {
COUNT: (state, data) => {
state.count = data
},
LIST : (state, data) => {
state.list = data
}
};
const getters = {
userCount:(state) => state.list.length
};
const actions = {
getList: ({commit,state}) => {
axios.get('/api/user/list')
.then((response) => {
commit('LIST', response.data);
})
}
};
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
This is my user vue component-user.vue
<template>
<div class="col-lg-3 col-xs-6">
<div class="small-box bg-yellow">
<div class="inner">
<h3>{{ usercount }}</h3>
<p>User Registrations</p>
</div>
<div class="icon">
<i class="ion ion-person-add"></i>
</div>
View <i class="fa fa-arrow-circle-right"></i>
</div>
</div>
</template>
<script>
export default{
computed: {
usercount() {
return this.$store.getters['user/userCount'];
}
},
mounted(){
this.$store.dispatch('user/getList');
}
}
</script>
In user.js,
alert(state.list.length)
gives the correct count in the alert box.
But in user.vue,
alert(this.$store.getters['user/userCount'])
gives 'undefined'
remove unnecessary : from this:
const getters = {
userCount (state) => state.list.length
};
In the Api controller, I'am using paginate() instead of get().vue dev tools helped me to find out this...
getList: ({commit,state}) => {
axios.get('/api/user/list')
.then((response) => {
commit('LIST', response.data);
})
}
changed response.data to response.data.data
I'm following along TheMeteorChef's Building a SaaS with Meteor: Stripe which is built with blaze templates. Tried to use react instead but I think I failed somewhere along the way. I've gotten to about half of the part 1 of 2 but enough to test if signing up with plan should work or not. Well, it doesn't work but also doesn't give any errors in console... I have very little experience, just started actually, so I'm hoping I could get some help. Thank you.
~/client/helpers/stripe.js
Meteor.startup(function() {
const stripeKey = Meteor.settings.public.stripe.testPublishableKey;
Stripe.setPublishableKey(stripeKey);
STRIPE = {
getToken: function(domElement, card, callback) {
Stripe.card.createToken(card, function(status, response) {
if(response.error) {
Bert.alert(response.error.message, "danger");
} else {
STRIPE.setToken(response.id, domElement, callback);
}
});
},
setToken: function(token, domElement, callback) {
$(domElement).append($('<input type="hidden" name="stripeToken" />').val(token));
callback();
}
}
});
~/client/components/SignUp.jsx
import React, {Component} from 'react';
import PlanSelectForm from '../components/PlanSelectForm.jsx';
import CreditCardForm from '../components/CreditCardForm.jsx';
export default class SignUp extends Component {
componentDidMount() {
$.validator.addMethod('usernameRegex', function(value, element) {
return this.optional(element) || /^[a-zA-Z0-9-_]+$/i.test(value);
}, "Username must contain only letters, numbers, underscores and dashes.");
$('#application-signup').validate({
rules: {
username: {
required: true,
usernameRegex: true,
minlength: 6
},
emailAddress: {
required: true,
email: true
},
password: {
required: true,
minlength: 6
}
},
messages: {
username: {
required: 'You can\'t leave this empty',
usernameRegex: 'You can use letter, numbers, underscores, and dashes.',
minlength: 'Too short. Use at least 6 characters.'
},
emailAddress: {
required: 'You can\'t leave this empty',
email: 'Email is invalid or already taken.'
},
password: {
required: 'You can\'t leave this empty',
minlength: 'Too short. Use at least 6 characters.'
}
},
handleSubmit: function() {
STRIPE.getToken('#application-signup', {
number: $('[data-stripe="cardNumber"]').val(),
exp_month: $('[data-stripe="expMo"]').val(),
exp_year: $('[data-stripe="expYr"]').val(),
cvc: $('[data-stripe="cvc"]').val()
}, function() {
const customer = {
username: $('[name="username"]').val(),
emailAddress: $('[name="emailAddress"]').val(),
password: $('[name="password"]').val(),
plan: $('[name="selectPlan"]:checked').val(),
token: $('[name="stripeToken"]').val()
};
const submitButton = $('input[type="submit"]').button('loading');
Meteor.call('createTrialCustomer', customer, function(error, response) {
if(error) {
alert(error.reason);
submitButton.button('reset');
} else {
if(response.error) {
alert(response.message);
submitButton.button('reset');
} else {
Meteor.loginWithPassword(customer.emailAddress, customer.password, function(error) {
if(error) {
alert(error.reason);
submitButton.button('reset');
} else {
Router.go('/chart');
submitButton.button('reset');
}
});
}
}
});
});
}
});
}
render() {
console.log(this);
return (
<form id="application-signup" className="signup">
<h4>Account details</h4>
<div className="form-group">
<label for="username">Username</label>
<input type="text"
name="username"
className="form-control"
placeholder="Username" />
</div>
<div className="form-group">
<label for="emailAddress">Email Address</label>
<input type="email"
name="emailAddress"
className="form-control"
placeholder="Email Address" />
</div>
<div className="form-group">
<label for="password">Password</label>
<input type="password"
name="password"
className="form-control"
placeholder="Password" />
</div>
<h4 className="page-header">Payment Information</h4>
<label>Which plan sounds <em>amazing</em>?</label>
<PlanSelectForm />
<div className="form-group">
<CreditCardForm />{/* data={signup} /> */}
</div>
<div className="form-group">
<input type="submit"
className="btn btn-success btn-block"
data-loading-text="Setting up your trial..."
value="Put me on the rocketship" />
</div>
</form>
)
}
}
Note: In the tutorial, TheMeteorChef uses a dynamic template for CreditCardForm with data="signup" context. I think he mentions the CC template will be used again after but I haven't gone that far yet. Anyways, I didn't know what "signup" means... so I left it commented out. If you know, please let me know about that as well.
~/client/components/PlanSelectForm.jsx
import React, {Component} from 'react';
export default class PlanSelectForm extends Component {
componentDidMount() {
const firstPlanItem = $('.select-plan a:first-child');
firstPlanItem.addClass('active');
firstPlanItem.find('input').prop('checked', true);
}
plans() {
return Meteor.settings.public.plans;
}
handleClickItem(e) {
const parent = $(e.target).closest('.list-group-item');
console.log(parent);
parent.addClass('active');
$('.list-group-item').not(parent).removeClass('active');
$('.list-group-item').not(parent).find('input[type="radio"]').prop('checked', false);
parent.find('input[type="radio"]').prop('checked', true);
}
render() {
let plans = this.plans();
if(!plans) {
return(<div>loading...</div>);
}
return (
<div className="list-group select-plan">
{plans.map((plan) => {
return (
<a key={plan.id}
href="#"
className="list-group-item"
onClick={this.handleClickItem.bind(this)}>
<input key={plan.id}
type="radio"
ref="selectPlan"
id={`selectPlan_${plan.id}`}
value={plan.name} />
{plan.name} {plan.amount.usd}/{plan.interval}
</a>
)
})}
</div>
)
}
}
~/client/components/CreditCardForm.jsx
import React, {Component} from 'react';
export default class CreditCardForm extends Component {
render() {
return (
<div>
<div className="row">
<div className="col-xs-12">
<div className="form-group">
<label className="text-success">
<i className="fa fa-lock"></i> Card Number
</label>
<input type="text"
data-stripe="cardNumber"
className="form-control card-number"
placeholder="Card Number" />
</div>
</div>
</div>
<div className="row">
<div className="col-xs-4">
<label>Exp. Mo.</label>
<input type="text"
data-stripe="expMo"
className="form-control exp-month"
placeholder="Exp. Mo." />
</div>
<div className="col-xs-4">
<label>Exp. Yr.</label>
<input type="text"
data-stripe="expYr"
className="form-control exp-year"
placeholder="Exp. Yr." />
</div>
<div className="col-xs-4">
<label>CVC</label>
<input type="text"
data-stripe="cvc"
className="form-control cvc"
placeholder="CVC" />
</div>
</div>
</div>
)
}
}
~/server/signup.js
Meteor.methods({
createTrialCustomer: function(customer) {
check(customer, {
name: String,
emailAddress: String,
password: String,
plan: String,
token: String
});
const emailRegex = new RegExp(customer.emailAddress, 'i');
const usernameRegex = new RegExp(customer.username, 'i');
const lookupEmail = Meteor.users.findOne({'emails.address': emailRegex});
const lookupUser = Meteor.users.findOne({'username': usernameRegex});
if(!lookupEmail) {
if(!lookupUser) {
const newCustomer = new Future();
Meteor.call('stripeCreateCustomer', customer.token, customer.emailAddress, function(error, stripeCustomer) {
if(error) {
console.log(error);
} else {
const customerId = stripeCustomer.id,
plan = customer.plan;
Meteor.call('stripeCreateSubscription', customerId, plan, function(error, response) {
if(error) {
console.log(error);
} else {
try {
const user = Accounts.createUser({
username: customer.username,
email: customer.emailAddress,
password: customer.password
});
const subscription = {
customerId: customerId,
subscription: {
plan: {
name: customer.plan,
used: 0
},
payment: {
card: {
type: stripeCustomer.sources.data[0].brand,
lastFour: stripeCustomer.sources.data[0].last4
},
nextPaymentDue: response.current_period_end
}
}
}
Meteor.users.update(user, {
$set: subscription
}, function(error, response) {
if(error) {
console.log(error);
} else {
newCustomer.return(user);
}
});
} catch(exception) {
newCustomer.return(exception);
}
}
});
}
});
return newCustomer.wait();
} else {
throw new Meteor.Error('username-exists', 'Sorry, that username is already active!');
}
} else {
throw new Meteor.Erro('email-exists', 'Sorry, that email is already active!')
}
},
})
~/server/stripe.js
const secret = Meteor.settings.private.stripe.testSecretKey;
const Stripe = StripeAPI(secret);
Meteor.methods({
stripeCreateCustomer: function(token, email) {
check(token, String);
check(email, String);
const stripeCustomer = new Future();
Stripe.customers.create({
source: token,
email: email
}, function(error, customer) {
if(error){
stripeCustomer.return(error);
} else {
stripeCustomer.return(customer);
}
});
return stripeCustomer.wait();
},
stripeCreateSubscription: function(customer, plan) {
check(customer, String);
check(plan, String);
const stripeSubscription = new Future();
Stripe.customers.createSubscription(customer, {
plan: plan
}, function(error, subscription) {
if(error) {
stripeSubscription.return(error);
} else {
stripeSubscription.return(subscription);
}
});
return stripeSubscription.wait();
}
})
packages
"dependencies": {
"meteor-node-stubs": "~0.2.0",
"react": "^15.0.2",
"react-addons-css-transition-group": "^15.0.2",
"react-dom": "^15.0.2",
"react-mounter": "^1.2.0"
},
accounts-base
accounts-password
session
check
random
kadira:flow-router
ultimatejs:tracker-react
meteortoys:allthings
fourseven:scss
fortawesome:fontawesome
themeteorchef:bert
themeteorchef:jquery-validation
momentjs:moment
mrgalaxy:stripe
Thanks for reading, I hope that it wasn't painful.
did you import mrgalaxy:stripe ?
it will be something like
import { StripeAPI } from 'meteor/mrgalaxy:stripe'
I guess.
anw, you can install by npm :
npm install stripe
import Stripe from 'stripe'
then
Stripe('your_secret_key')