Reputation: 1116
I currently have a signup form. Users have an optional field where they can upload a profile picture if they want.
If they don't upload a profile picture, I want to use a default profile picture for them (imagine the default facebook profile picture image for example).
My image imported as:
import defaultPhoto from "../../assets/images/logo/grayscale-nut.png";
My register function:
const register = async () => {
setLoading("loading");
let newUserID;
auth
.createUserWithEmailAndPassword(email, confirmedPassword)
.then((auth) => {
if (auth) {
newUserID = auth.user.uid;
const collection = db.collection("users");
collection.doc(auth.user.uid).set({
username: username.toLowerCase().trim(),
name: firstName,
surname: lastName,
bio: "",
addressBook: [],
medals: [],
medalShowcase: [],
boughtItems: [],
soldItems: [],
});
}
})
.then(async () => {
let photo;
if (signUpPhoto.length === 1) {
photo = signUpPhoto[0].file;
} else {
//GET THE DEFAULT PHOTO HERE
}
const userProfileRef = firebase
.storage()
.ref()
.child(`users/` + newUserID + `/profilePicture/profilePicture`);
userProfileRef.put(photo).then(async (snapshot) => {
const downloadURL = await snapshot.ref.getDownloadURL();
const userData = db.collection("users").doc(newUserID);
userData
.set({ profilePicture: downloadURL }, { merge: true })
.then(async () => {
setLoading("complete");
const newData = await getUserByUserId(newUserID);
setData(newData);
history.replace("/");
});
});
})
.catch((error) => {
setLoading("error");
});
};
Edit 1: The full and updated Signup page
//#####################################################################
import { useState, useEffect } from "react";
import { Link, useHistory } from "react-router-dom";
//#####################################################################
import firebase from "firebase/app";
//#####################################################################
import defaultPhoto from "../../assets/images/logo/grayscale-nut.png";
//#####################################################################
import "./Signup.scss";
import "../ui/buttons/buttons.scss";
import classNames from "classnames/bind";
import Logo from "../../assets/images/logo/seekio-logo-purple.png";
import PasswordStrengthMeter from "./components/PasswordStrengthMeter/PasswordStrengthMeter";
import PasswordMatchChecker from "./components/PasswordMatchChecker/PasswordMatchChecker";
import zxcvbn from "zxcvbn";
import ElipsisSpinner from "../ui/loading/ElipsisLoading/ElipsisSpinner";
import validator from "validator";
//#####################################################################
import { auth, db } from "../../firebase";
//#####################################################################
import { FilePond, registerPlugin } from "react-filepond";
import "filepond/dist/filepond.min.css";
import FilePondPluginFileValidateSize from "filepond-plugin-file-validate-size";
import FilePondPluginImageExifOrientation from "filepond-plugin-image-exif-orientation";
import FilePondPluginFileValidateType from "filepond-plugin-file-validate-type";
import FilePondPluginImagePreview from "filepond-plugin-image-preview";
import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css";
//#####################################################################
import { getUserByUserId } from "../../services/firebase";
//#####################################################################
import userDataStore from "../../Global/UserState/UserStore";
//#####################################################################
registerPlugin(
FilePondPluginImageExifOrientation,
FilePondPluginImagePreview,
FilePondPluginFileValidateType,
FilePondPluginFileValidateSize
);
function Signup() {
//-------------------------------------------------------
//STATES
//-------------------------------------------------------
const history = useHistory();
const [email, setEmail] = useState("");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const [password, setPassword] = useState("");
const [passwordStrength, setPasswordStrength] = useState(0);
const [confirmedPassword, setConfirmedPassword] = useState("");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const [username, setUsername] = useState("");
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const [inputsFilled, setInputsFilled] = useState(false);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const [errorMsg, setErrorMsg] = useState(null);
const [passwordsMatch, setPasswordsMatch] = useState(null);
const [passwordNotStrongEnough, setPasswordNotStrongEnough] = useState(false);
const [usernameError, setUsernameError] = useState(null);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const [signUpPhoto, setSignUpPhoto] = useState([]);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const setData = userDataStore((state) => state.setData);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const [loading, setLoading] = useState("idle");
//-------------------------------------------------------
//CLASSNAMES
//-------------------------------------------------------
const signUpButton = classNames({
animateSlideUpButton: true,
signup__buttonRegister: true,
disabled: !inputsFilled,
});
//-------------------------------------------------------
//USE EFFECTS
//-------------------------------------------------------
useEffect(() => {
if (!validator.matches(username, "^[a-zA-Z0-9_.-]*$")) {
setUsernameError("Invalid username, please try another one.");
} else {
setUsernameError(null);
}
}, [username]);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
useEffect(() => {
if (password !== "") {
getPasswordScore(password);
}
}, [password]);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
useEffect(() => {
if (password !== confirmedPassword) {
setPasswordsMatch(false);
} else {
setPasswordsMatch(true);
}
}, [password, confirmedPassword]);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
useEffect(() => {
if (
(email, username, password, firstName, lastName, confirmedPassword) !== ""
) {
let emailValid = emailIsValid(email);
if (
emailValid &&
passwordStrength >= 2 &&
password === confirmedPassword &&
username.length >= 3
) {
setInputsFilled(true);
} else {
setInputsFilled(false);
}
} else {
setInputsFilled(false);
}
}, [
email,
password,
username,
firstName,
lastName,
confirmedPassword,
signUpPhoto,
]);
//-------------------------------------------------------
//METHODS
//-------------------------------------------------------
async function getPasswordScore() {
const score = zxcvbn(password).score;
setPasswordStrength(score);
if (score <= 2) {
setPasswordNotStrongEnough(true);
} else {
setPasswordNotStrongEnough(false);
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function emailIsValid(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const preRegister = async (e) => {
e.preventDefault();
if (
firstName.trim() === "" ||
lastName.trim() === "" ||
username.trim() === "" ||
email.trim() === "" ||
password.trim() === "" ||
confirmedPassword.trim() === "" ||
usernameError !== null
) {
window.alert("Invalid data!\nAll data must be filled in!");
} else {
const usernameRef = db
.collection("users")
.where("username", "==", username);
usernameRef.get().then((docs) => {
if (docs.size === 1) {
window.alert("Username taken");
} else {
register();
}
});
}
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const register = async () => {
setLoading("loading");
let newUserID;
auth
.createUserWithEmailAndPassword(email, confirmedPassword)
.then((auth) => {
if (auth) {
newUserID = auth.user.uid;
const collection = db.collection("users");
collection.doc(auth.user.uid).set({
username: username.toLowerCase().trim(),
name: firstName,
surname: lastName,
bio: "",
addressBook: [],
medals: [],
medalShowcase: [],
boughtItems: [],
soldItems: [],
});
}
})
.then(async () => {
const userProfileRef = firebase
.storage()
.ref()
.child(`users/` + newUserID + `/profilePicture/profilePicture`);
const userData = db.collection("users").doc(newUserID);
if (signUpPhoto.length === 1) {
console.log("profile picture selected");
const photo = signUpPhoto[0].file;
userProfileRef.put(photo).then(async (snapshot) => {
const downloadURL = await snapshot.ref.getDownloadURL();
userData
.set({ profilePicture: downloadURL }, { merge: true })
.then(async () => {
setLoading("complete");
const newData = await getUserByUserId(newUserID);
setData(newData);
history.replace("/");
});
});
} else {
console.log(
"no profile picture was selected, uploading the default photo instead"
);
userProfileRef
.putString(defaultPhoto.toString(64).split(",")[1], "base64", {
contentType: "image/png",
})
.then((s) => {
//This console log never happens
console.log(s);
})
.catch((e) => console.log(e));
}
})
.catch((error) => {
setLoading(error);
});
};
//Filepond
function onDrop(uploadedPhotos) {
setSignUpPhoto(uploadedPhotos);
}
//-------------------------------------------------------
//END
//-------------------------------------------------------
return (
<div className="signup">
{loading === "loading" ? (
<div className="signup__loading">
<ElipsisSpinner />
<h4>Creating Account</h4>
</div>
) : loading === "complete" ? (
<div className="signup__loading">
<h4>Success!</h4>
</div>
) : loading === "error" ? (
<div className="signup__loading">
<h4>Error! Please try again.</h4>
</div>
) : (
<div className="signup__container">
<Link to="/">
<img src={Logo} alt="logo" className="signup__logo" />
</Link>
<h2>Sign-up</h2>
<form>
<h5>E-mail</h5>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="inputText"
placeholder="[email protected]"
/>
<h5> Username </h5>{" "}
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
required
className="inputText"
placeholder="PokeTrainer"
/>
{usernameError && (
<span className="errorSpan">
<h4 className="">{usernameError}</h4>
</span>
)}
<h5> Name </h5>{" "}
<input
type="text"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
required
className="inputText"
placeholder="Ash"
/>
<h5> Surname </h5>{" "}
<input
type="text"
value={lastName}
onChange={(e) => setLastName(e.target.value)}
required
className="inputText"
placeholder="Ketchum"
/>
<h5>Password</h5>
<input
type="password"
value={password}
onChange={(e) => {
setPassword(e.target.value);
}}
required
className="inputText"
placeholder="●●●●●●●●●●"
/>
<PasswordStrengthMeter
passwordStrength={passwordStrength}
password={password}
/>
{password.length > 0 && passwordNotStrongEnough && (
<span className="errorSpan">
<h4>Password score of 4 or higher is required.</h4>
</span>
)}
<h5> Confirm Password </h5>
<input
type="password"
value={confirmedPassword}
onChange={(e) => setConfirmedPassword(e.target.value)}
required
className="inputText"
placeholder="●●●●●●●●●●"
/>
<PasswordMatchChecker
password={password}
confirmPassword={confirmedPassword}
/>
</form>
{!passwordsMatch && (
<span className="errorSpan">
<h4>Passwords must match!</h4>
</span>
)}
<div className="signup__container__filePondWrapper">
<h4>Choose a profile picture:</h4>
<div className="signup__container__filePondWrapper__wrapper">
<FilePond
files={signUpPhoto}
onupdatefiles={onDrop}
allowMultiple={false}
maxFiles={1}
instantUpload={false}
name="files"
itemInsertLocation={"after"}
maxFileSize={"50MB"}
acceptedFileTypes={["image/*"]}
labelIdle={"<span class='filepond--label-action'>Browse</span>"}
credits={null}
stylePanelLayout={"compact circle"}
allowImagePreview={true}
imageCropAspectRatio={"1:1"}
imageResizeTargetWidth={"200"}
imageResizeTargetHeight={"200"}
/>
</div>
</div>
<button type="submit" className={signUpButton} onClick={preRegister}>
Sign Up
</button>
{errorMsg && <h4 className="errorMsg">{errorMsg}</h4>}
<p>
Our alpha is currently UK only, by signing-up you acknowledge this
and agree to Seekio's Conditions of Use & Sale. Please see our
Privacy Notice, our Cookies Notice and our Interest-Based Ads
Notice.
</p>
<Link to="/login">
<button className="signup__buttonSignIn">
Already Have an Account ? Sign In
</button>
</Link>
</div>
)}
</div>
);
}
export default Signup;
Upvotes: 1
Views: 1006
Reputation: 50930
Using base64 string and uploading worked out for me:
import image from "../path/to/image.png"
const base64String = ""
storage.ref("imageName.png")
.putString(base64String, "base64", {contentType: "image/png"})
.then((s) => {
console.log(s);
}).catch(e => console.log(e));
Make sure you have the extension name in the file name and contentType set to correct mimetype.
Your function is async so try to use await as shown:
const register = async () => {
setLoading("loading");
const userCred = await auth.createUserWithEmailAndPassword(
email,
confirmedPassword
);
const newUserID = userCred.user.uid;
const collection = db.collection("users");
await collection.doc(auth.user.uid).set({
username: username.toLowerCase().trim(),
name: firstName,
surname: lastName,
bio: "",
addressBook: [],
medals: [],
medalShowcase: [],
boughtItems: [],
soldItems: [],
});
const userProfileRef = firebase
.storage()
.ref()
.child(`users/` + newUserID + `/profilePicture/profilePicture`);
let photo;
if (signUpPhoto.length === 1) {
photo = signUpPhoto[0].file;
await userProfileRef.put(photo);
} else {
//GET THE DEFAULT PHOTO HERE
await userProfileRef.putString(base64String, "base64", {
contentType: "image/png",
});
}
const downloadURL = await userProfileRef.getDownloadURL();
const userData = db.collection("users").doc(newUserID);
await userData.set({ profilePicture: downloadURL }, { merge: true });
setLoading("complete");
const newData = await getUserByUserId(newUserID);
setData(newData);
history.replace("/");
};
Upvotes: 1