How to create custom URLs for new users using Firebase? - reactjs

I have a React/Redux application that creates and saves new users under Firebase as /users/<uid>
However, I also want to have each user have a custom URL for their profile pages, like domain.com/users/john-david or domain.com/users/john-david-1343 (if the original /users/john-david is already taken.)
What's the best way to do this?
My problem is that I was going to store users under /users/<firstname-lastname-hash> in Firebase, but that seems like a bad idea to store them under anything besides uid (is this true?).
But also, if I don't do that, then how do I maintain /users/<uid> in Firebase, while creating new usernames that account for duplicates, and searching if the user exists when visiting domain.com/users/john-david-123
Here is some sample code of where the new user gets saved to Firebase
export function saveUser (data, user) {
let username = data.username
return ref.child(`users/${user.uid}/info`)
.set({
email: user.email,
firstname: data.firstName,
lastname: data.lastName,
admin: false,
// for /users/<username>
username: username,
uid: user.uid
})
.then(() => user)
}

In general we say you should store data in Firebase how you intend to view it, and there's no reason in particular that you must use the UID as your primary key when storing users. What you might want to is:
Store user data in /users/${username} as you mentioned, including a uid field.
When a user signs up, generate the firstname-lastname slug and store in /uids/${uid} = username.
This way you have a simple way to map from UID to user and vice-versa. The downside here is that once you bake a username into your data structure, you should probably never let them change their username.
Alternatively, you could reverse my suggestion and store /usernames/${username} = uid and /users/${uid}. This makes it easier to rename usernames, but requires that you do an extra lookup to go from username to data.

Related

React JS - Firestore, How to save the UID of an specific collection doc inside the doc

I'm trying to register the UID of the New Doc that is going to be generated after I create it so far I Only understand how to make sure the AUTH.UID is the same as the UID of a registered user and so on (basically auth user UID matchs doc user register UID).
What I'm struggling with is How to I "copy" or "get" the UID of a DOC that is about to be created and add it on the information of the Document
So in this picture the doc UID matches not only the outside information but the INSIDE information (if that makes sense) but it also matches my USER UID
Now let's move on to the issue (Idk if I should go straight to the point or explain, I have plenty of questions for a while but now I find this site exists so I'm sorry if I'm asking a lot).
So each USER can create their own personal collection (I think it was the best way to go to not confuse myself)
As you can see the user can create "students" in their own collection of data (so it doesn't mix with the others users students) but I'm unable to grab that doc UID.
I have try to use doc.uid or a whole database.doc.uid and stuff like that and even though I don't get an error in the syntax (until it tries to create it) it doesn't work, so since I was unable to figure out the doc I decided to use the user.uid meanwhile until I find a solution (which I haven't) and I'm pretty sure the fix is something very silly but I can't find "specific" information of the issue I'm having only general situations This is the relevant part of the code
function CrearEstudiante({user}) {
const register = (e) => {
e.preventDefault();
db.collection('usuarios')
.doc(user.uid)
.collection('estudiantes').doc()
.set({
name: firstName + " " + lastName,
school: idType1,
grade: idType2,
uid: user.uid
}).then((r) => {
history.push("/Inicio")
})
}
This is what I tried:
db.collection('usuarios').doc(user.uid).collection('estudiantes').uid
doc.uid
and if I try to add "uid" on the top argument of auth
so like this:
db.collection('usuarios').doc(user.uid).collection('estudiantes').doc(uid).set(
it doesn't like it neither
Any tips are welcome, also I'm NOT using real-time database just the firestore.
If you want to know the uid of the document to be created, you can do something like this:
const register = (e) => {
e.preventDefault();
const docRef = db.collection('usuarios').doc(user.uid).collection('estudiantes').doc();
docRef.set({
name: firstName + " " + lastName,
school: idType1,
grade: idType2,
uid: docRef.id,
// docRef.id is the id you want.
}).then((r) => {
history.push("/Inicio");
})
}

Adding extra information to registration user Firebase

I would like to make an application in React Native that allows to work in two modes, parent and child. The initial stage is registration with Firebase, then after adding additional information about the role (parent / child), registering both the child and parent, and after logging in both of them, the child will share location and parent will receive it.
I would like to add additional fields such as role (parent / child) in my application in React Native + Firebase, to later create other functionalities of the application based on the role.
Registration:
firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then(userCredentials => {
return userCredentials
.user.updateProfile({
displayName: name,
})
.additionalUserInfo.profile = {
role: role,
}
})
Homescreen
const { displayName } = firebase.auth().currentUser;
const { role } = firebase.additionalUserInfo.profile;
this.setState({displayName, role});
and role returns undefined.
The properties that you can store on a user profile are defined by Firebase Authentication. You can't just add additional properties to it as you see fit. At best Firebase will simply ignore those, but likely it will also explicitly reject them (throwing an error).
If you want to store additional information about a user, you have two main options:
Store the additional information as custom claims in the user's authentication token.
Store the additional information in an external database, such as the Firestore and Realtime Database that are part of Firebase.
While storing the data as custom claims is pretty close to what you want to accomplish, you'll need to keep a few things in mind:
Custom claims are used for authorization purposes, and for that reason can only be set from a trusted environment (such as your development machine, a server you control, or Cloud Functions). So you can't simply set the role from within the app, and will need a separate process to add that claim.
After setting a custom claim on a user profile it may take up to an hour before that change is visible in the client. If you need it sooner, you can force the user to sign in again, or refresh their ID token.
Custom claims are sent with every request you make to Firebase resources, and for that reason are very limited in size. There's a maximum size of 1000 bytes for custom claims for a user. While your current role will easily fit into that, it may limit what you can add later.
If instead you store user data in an external database, you'll typically combine it with other information about that user into a users node/collection. In here you'd store a document/node for each user based on that user's UID, and then their profile information.
So something like:
users: {
uidOfAleksandra: {
username: "Aleksandra",
displayName: "Aleksandra Lastname",
role: "parent",
registrationDate: "2020-02-01"
},
uidOfPuf: {
username: "puf",
displayName: "Frank van Puffelen",
role: "child",
registrationDate: "2015-03-07"
},
}
Having this list of user profiles does not only allow you to store the additional information for each user, but would also allow you to query that list of users from within your app, something that the Authentication API doesn't allow from within application code.

Create user profile with user choice on firestore using redirect

I am creating a site using react-redux-firebase, and when a user logs in with facebook I want to create a profile that stores a user choice. I know how to define what to store with the profileFactory, but I don't know how to pass dynamic data coming from the user. In my case I want to save the users' language. My configuration is similar to this:
const config = {
userProfile: 'users', // where profiles are stored in database
profileFactory: (userData, profileData) => { // how profiles are stored in database
const { user } = userData
return {
language: [i need to put here what the user chose]
email: user.email
}
}
}
The configuration was based on this recipe.
When logging in I'm using type redirect.
await firebase.login({
provider: 'facebook',
type: 'redirect'
})
How could I save the user choice when the user is created?
To solve the user custom fields I'm creating a user when the redirect comes back from facebook.
I'm still not totally sure this is the best way to do it. Seems odd that I can define a profileFactory but can't pass user custom fields in some way.

How to register and store user info in Firebase Real Time Database

I just want to know that how can i register user in Firebase and store user's additional details like First name, Last name etc i made a typical registration form in Angular I am successfully registering users with their user name and password but i want to store user's detail on success for future use. I've done this in angular 1 but could not find anyway to work with it Angular2
The best way is to create a user object in your Firebase Realtime Database using the Firebase Authentication uid from the newly created user:
this.af.auth.createUser({
// Create Firebase Auth user
email: formData.value.email,
password: formData.value.password
}).then((user) => {
// User created now create Firebase Database user
return this.af.database.object(`/users/${user.uid}`).update({
firstName: formData.value.firstName,
lastName: formData.value.lastName
});
}).then(() => {
// Success
}).catch((error) => {
// Error
console.log(error);
});
(Not had chance to test this)
Depending on how you've done registration you can obviously replace the formData.value with your model data if needed.
Also, this is done using the AngularFire2 library - https://github.com/angular/angularfire2

Firebase: How to get the $id of an object after I authenticate using angularFire

Firebase has the $onAuth method that listens for changes to the client's authentication state. If the client is authenticated, the callback will be passed an object that contains the uid.
Here is my question:
Based on this uid, how can I get the the $id for this object.
This is how my data looks like in firebase:
profile {
-K2a7k9GXodDriEZrM3f {
email: "ale#aol.com"
gravatar: "https://www.gravatar.com/avatar/1d52da55055f0c8..."
uid: "3f9e0d53-4e61-472c-8222-7fc9f663969e"
name: "ale"
}
}
I am using
auth.$onAuth(function (authData) {
if (authData) {
authData.profile = //here I want the $id of the object
}
})
All I see I can do with the authData response is to get the uid of the object by using:
$firebaseObject(ref.child('profile').child(authData.uid));
This authData does not contain the $id (i.e. the -K2a7k9GXodDriEZrM3f) of the object. And that is what I am looking for in order to have the user's information available. Is there a way to achieve this?
Thanks.
If an object has a natural unique ID, you should usually store the object under that ID. Using push IDs in those cases adds no value and only complicates things.
Most developers using Firebase do as the "Storing User Data" section in the documentation illustrates: they store users by their uid. If you follow that guideline, you can find the key as authData.uid.
If you decide to stick to your current course, you can find the key for the user with:
ref.child('profile').orderByChild('uid').equalTo(authData.uid).once('child_added', function(snapshot) {
console.log(snapshot.key());
});
But you will be making it harder for the database to find your user, thus limiting the scalability of your app.

Resources