Can You Add Data to Database (supabase) without an Server using ReactJS - javascript

I'm kinda new in programming and I'm learning how the web works, And Im working on this project using Supabase PostgreeSQL with Api, so what I want to do is write (send data to db), and I want to do it using only ReactJS but I don't know if this is possible, I have made something to work only with JS and the API keyes from SUPABASE, but I don't know if this is correct to do
import {useState} from 'react'
import {supabase} from '../db/supabase';
import Helmet from "helmet";
import {Link} from 'react-router-dom'
import styled from "styled-components";
const Container = styled.div``
const LeftContainer = styled.div``
const RightContainer = styled.div``
const Input = styled.input``
const BtnButBlack = styled.button``
const BtnButGreen = styled.button``
const Form = styled.form``
export default function Signup() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [name, setName] = useState('');
const [username, setUsername] = useState('');
const handleSubmit = (event) => {
new_account({email: email, password: password}, name, username)
event.preventDefault();
};
const handleEmail = (event) => {
event.preventDefault();
setEmail(event.target.value)
};
const handlePassword = (event) => {
event.preventDefault();
setPassword(event.target.value)
}
const handleName = (event) => {
event.preventDefault();
setName(event.target.value)
}
const handleUsername = (event) => {
event.preventDefault();
setUsername(event.target.value)
}
const new_account = async ({email, password}) => {
const {user, session, error} = await supabase.auth.signUp({
email: email,
password: password,
})
if (error) {
console.error(error)
return
}
console.log(user);
await supabase
.from('Users')
.insert([
{username: username, name: name, email: email, password: password}
])
};
return (
<Container>
<LeftContainer>
Signup
</LeftContainer>
<RightContainer>
<Form onSubmit={handleSubmit}>
<Input onChange={handleUsername} type="text" value={username} placeholder="Username" autoComplete="false" /><br></br>
<Input onChange={handleName} type="text" value={name} placeholder="Name" autoComplete="false" /><br></br>
<Input onChange={handleEmail} type="text" value={email} placeholder="Email" autoComplete="false" /><br></br>
<Input onChange={handlePassword} type="password" value={password} placeholder="Password" autoComplete="false" /><br />
<BtnButGreen>Sign Up</BtnButGreen>
</Form>
</RightContainer>
</Container>
)
}
and this is the supabase module that you can import and use it on the jsx file:
import {createClient} from '#supabase/supabase-js'
const supabaseUrl = process.env.REACT_APP_SUPABASE_URL
const supabaseAnonKey = process.env.REACT_APP_SUPABASE_ANON_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey)

The code you have seems great! With Supabase, the you are only exposing anon key and supabase URL, which are meant to be public.
You use row level security and Supabase Auth to prevent malicious attackers to hack your database. You can read more about row level security here:
https://supabase.io/docs/learn/auth-deep-dive/auth-row-level-security
If you have any questions, please don't hesitate to ask!

Related

React encrypt password

I have following component to pass data in my firestore database. Currently the password is not encrypted and and is visible to users of the database. Therefore I want to encrypt it. However, I get the error
TypeError: Cannot read property 'encrypt' of undefined.
That is my component for putting data in the database:
import React, {useState} from "react";
import fire from './fire.js';
import {userAuth} from './Main';
import '../style/inputPasswords.css';
import {encrypt} from './encryption';
const database = fire.firestore();
const InputPasswords = () => {
const [title, setTitle] = useState("");
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
let encryptedPassword = encrypt(password);
database.collection("password-"+userAuth).add({
title: title,
username: username,
password: encryptedPassword
})
.then(() => {
window.location.reload();
})
.catch((error) => {
console.error(error);
})
setTitle("");
setUsername("");
setPassword("");
}
return (
<form className="form" onSubmit={handleSubmit}>
<label>title</label>
<input className="input" id="title" placeholder="Title" value={title} autoComplete="off"
onChange={(e) => setTitle(e.target.value)}/>
<label>Username</label>
<input className="input" id="username" placeholder="Username" value={username} autoComplete="off"
onChange={(e) => setUsername(e.target.value)}/>
<label>Password</label>
<input className="input" id="password" placeholder="Password" type="password" value={password} autoComplete="off"
onChange={(e) => setPassword(e.target.value)}/>
<button type="submit">Add</button>
</form>
)
}
export default InputPasswords
This is the code for the encryption:
import crypto from "crypto";
const secret = "testtesttesttesttesttesttesttest";
const encrypt = (password) => {
return crypto.AES.encrypt(password, secret).toString();
};
const decrypt = (encryption) => {
let bytes = crypto.AES.decrypt(encryption, secret);
let originalText = bytes.toString(crypto.enc.Utf8);
return originalText;
};
export {encrypt, decrypt};
I am not sure how to fix that. Does anyone have an idea how to solve that problem?
Because without the encryption the code runs without any problems
I edited and moved the encryption function into the component and so the password gets encrypted
const handleSubmit = (e) => {
e.preventDefault();
const secret = "testtesttesttesttesttesttesttest";
const iv = Buffer.from(crypto.randomBytes(16));
const cipher = crypto.createCipheriv('aes-256-ctr', Buffer.from(secret), iv);
const encryptedPassword = Buffer.concat([cipher.update(password), cipher.final()]);
//let encryptedPassword = crypto.AES.encrypt("password", secret).toString();;
database.collection("password-"+userAuth).add({
title: title,
username: username,
password: encryptedPassword.toString('hex')
})
.then(() => {
window.location.reload();
})
.catch((error) => {
console.error(error);
})
setTitle("");
setUsername("");
setPassword("");
}

fetch send the data but doesn't go in then, React

I have problem with fetch. The data have been send, but doesn't do in then or catch, so I don't get if response is send ot not, only when I go in database. That is the code:
import React, { useState } from 'react'
// import styles from './index.module.css'
import Input from '../input'
import SignUpButton from '../sign-up-button'
const SignUpForm = () => {
const [username, setUsername] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const handleSubmit = (e) => {
e.preventDefault()
let data = { username: username, email: email, password: password }
const headers = new Headers()
headers.append('Content-Type', 'application/json')
const options = {
method: 'POST',
headers: headers,
mode: 'cors',
cache: 'default',
body: JSON.stringify(data)
}
const request = new Request(`http://localhost:5000/user/sign-up`, options)
fetch(request)
.then(res => {
setUsername('')
setEmail('')
setPassword('')
})
.catch(e => {
console.log(e)
})
}
return (
<form onSubmit={handleSubmit}>
<Input
onChange={e => setUsername(e.target.value)}
label='Username:'
name='username'
placeholder='marolio'
value={username}
/>
<Input
onChange={e => setEmail(e.target.value)}
label='Email:'
name='email'
placeholder='marolio#yahoo.com'
value={email}
/>
<Input
onChange={e => setPassword(e.target.value)}
label='Password:'
name='password'
value={password}
/>
<SignUpButton
text='CREATE ACCOUNT'
btnStyle='submit'
/>
</form>
)
}
export default SignUpForm
Same structire worked for me in other project, so maybe something is changed but I don't know it. Every help will be useful. Thanks!
I made this change and it work, but I'm still curious why then and catch doesn't worked.
const response = fetch(request)
if(response){
setUsername('')
setEmail('')
setPassword('')
} else{
console.log('error')
}

How do i get the value of text input field using react

I'm creating a register form in react with validation. The values i'm asking is Username, Email, password + (controll password). Everything about the form works, validations, Errors and if you click sign up you go to a new page. Now i want to extract the values to a my MySql database. I succeed in putting stuff in my database so the link works but i can't get the values of what i typed in the form.
I have tried
onChange={(e) => {
setUsernameReg(e.target.value);
}}
(see commented item)
But when i tried this I couldn't fill anything in Username. The code for the other inputs (email, password) is the same apart from the names.
So in short I want to get the value what you typed in a textbox to my database.
Code: FormSignup.js
import React, { useEffect, useState } from 'react';
import Axios from 'axios';
import validate from './validateInfo';
import useForm from './useForm';
import './Form.css';
const FormSignup = ({ submitForm }) => {
const { handleChange, handleSubmit, values, errors } = useForm(
submitForm,
validate
);
const [usernameReg, setUsernameReg] = useState("");
const [emailReg, setEmailReg] = useState("");
const [passwordReg, setPasswordReg] = useState("");
Axios.defaults.withCredentials = true;
const register = () => {
Axios.post("http://localhost:3001/register", {
username: usernameReg,
password: passwordReg,
email: emailReg,
}).then((response) => {
console.log(response);
});
};
return (
<div className='form-content-right'>
<form onSubmit={handleSubmit} className='form' noValidate>
<h1>
Get started with us today! Create your account by filling out the
information below.
</h1>
<div className='form-inputs'>
<label className='form-label'>Username</label>
<input
className='form-input'
type='text'
name='username'
placeholder='Enter your username'
value={values.username}
onChange={handleChange}
/*
//onChange={(e) => {
// setUsernameReg(e.target.value);
//}}
*/
/>
Code UseForm.js
import { useState, useEffect } from 'react';
import Axios from 'axios';
const useForm = (callback, validate) => {
const [values, setValues] = useState({
username: '',
email: '',
password: '',
password2: ''
});
const [errors, setErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const [usernameReg, setUsernameReg] = useState("");
const [emailReg, setEmailReg] = useState("");
const [passwordReg, setPasswordReg] = useState("");
Axios.defaults.withCredentials = true;
const register = () => {
Axios.post("http://localhost:3001/register", {
username: usernameReg,
password: passwordReg,
email: emailReg,
}).then((response) => {
console.log(response);
});
};
const handleChange = e => {
const { name, value } = e.target;
setValues({
...values,
[name]: value
});
};
const handleSubmit = e => {
e.preventDefault();
setErrors(validate(values));
setIsSubmitting(true);
};
useEffect(
() => {
if (Object.keys(errors).length === 0 && isSubmitting) {
callback();
}
},
[errors]
);
return { handleChange, handleSubmit, values, errors };
};
export default useForm;
The code is from https://www.youtube.com/watch?v=KGFG-yQD7Dw&t and https://www.youtube.com/watch?v=W-sZo6Gtx_E&t
By using the value prop of the input, you turn it into a controled input element and thus need to update its value via a state variable. So this:
<input
className='form-input'
type='text'
name='username'
placeholder='Enter your username'
value={values.username}
onChange={handleChange}
/*
//onChange={(e) => {
// setUsernameReg(e.target.value);
//}}
*/
/>
Should just be this:
<input
className='form-input'
type='text'
name='username'
placeholder='Enter your username'
value={usernameReg}
onChange={e => setUsernameReg(e.target.value)}
/>
Note that this only answers this part:
I succeed in putting stuff in my database so the link works but i can't get the values of what i typed in the form
So this is how you can access those values. I can't guide you on how to get those values all the way to your DB as there is a longer distance they have to travel and I don't know what else could be in the way.
You should also look into useRef(), which will give you access to those input fields without updating your state on every change of the input and thus re-rendering your form over and over.
You can do something like this:
...
const regInput = React.useRef();
...
...
<input
ref={regInput}
className='form-input'
type='text'
name='username'
placeholder='Enter your username'
Then when you're ready to submit, just access the value of the username input like so:
...
const v = regInput.current.value;
...

I need to call the page render after POST request

I submit a request to the server and then want to get the result without reloading the page (SPA principle), how can this be done using useEffect()?
I tried to do something like this:
useEffect (() => {
addProduct ();
})
but it's was a bad idea
import React, {useState, useEffect} from 'react';
import api from './api';
const HandleProduct = () => {
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const updateName = (e) =>{
setName(e.target.value);
}
const updateDescription = (e) =>{
setDescription(e.target.value);
}
const addProduct = () =>{
const product = {
name: name,
description: description
}
api.addProduct(product)
.then((req, res) =>{
console.log(res);
})
}
return (
<div>
<form onSubmit={addProduct}>
<input type="text" name="name" value={name} onChange={updateName}/>
<input type="text" name="description" value={description} onChange={updateDescription}/>
<button>Submit</button>
</form>
</div>
);
}
export default HandleProduct;
When the callback with response is called you've got the repsonse with all data sent from API. Let's assume you want to get ID. I will add new hook for storing ID, setting it after POST method is completed, and displaying it.
const [productId, setProductId] = useState(null);
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const updateName = (e) =>{
setName(e.target.value);
}
const updateDescription = (e) =>{
setDescription(e.target.value);
}
onSubmit() {
const product = {
name: name,
description: description
}
api.addProduct(product)
.then((req, res) =>{
setProudctId(JSON.parse(res).id);
})
}
return (
<div>
{productId && <span>Your productId: {productId} </span>}
<form onSubmit={addProduct}>
<input type="text" name="name" value={name} onChange={updateName}/>
<input type="text" name="description" value={description} onChange={updateDescription}/>
<button>Submit</button>
</form>
</div>
);
}
export default HandleProduct;
Your code seems legit, yet, given that is not working, I'll give you another option to do it.
In App.js
<Router >
<ProductsProvider>
<Route exact path="/products" component={ProductsList} props={...props} />
<Route exact path={'/products/add'} component={HandleProduct}
props={...props} />
</ProductsProvider>
</Router>
In HandleProduct.js
import React, {useState} from 'react';
import api from './api';
import { Redirect } from 'react-router'
const HandleProduct = ({history}) => {
const [name, setName] = useState('');
const [description, setDescription] = useState('');
const updateName = (e) =>{
setName(e.target.value);
}
const updateDescription = (e) =>{
setDescription(e.target.value);
}
const addProduct = (e) =>{
e.preventDefault();
const product = {
name: name,
description: description
}
api.addProduct(product)
.then((req, res) =>{
history.push('/products');
})
}
return (
<div>
<form onSubmit={addProduct}>
<input type="text" name="name" value={name} onChange={updateName}/>
<input type="text" name="description" value={description} onChange={updateDescription}/>
<button>Submit</button>
</form>
</div>
);
}
import React, {useContext} from 'react';
import {ProductsContext} from './ProductsContext';
const ProductsList = () => {
const [data] = useContext(ProductsContext);
return (
<div>
{console.log(data)}
{data.products.map((product, index)=>(
<div key={index}>
<p>{product.name}</p>
<p><i>{product.description}</i></p>
</div>
))}
</div>
);
}
export default ProductsList;

Event undefined for event.preventDefault in a React form

I'm trying to create a user authentication page using React and Apollo. I'm getting that my event is undefined for onClick event for the following code:
const Auth = props => {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const onSubmitHandler = async (login, e) => {
e.preventDefault()
const authResults = await login()
props.history.push('/')
}
return (
<Mutation
mutation={LOGIN}
variables={{ email, password }}
>
{(login, {data, error, loading}) => {
if(loading) return <div>...loading</div>
if(error) return <div>Error</div>
return (
<form onSubmit={onSubmitHandler}>
<fieldset>
<label htmlFor="email">
Email
</label>
<input
type="email"
id="email"
value={email}
onChange={e => {
setEmail(e.target.value)
}}
/>
</fieldset>
<fieldset>
<label htmlFor="password">
Password
</label>
<input
type="password"
id="password"
value={password}
onChange={e => {
setPassword(e.target.value)
}}
/>
</fieldset>
<button>Login</button>
</form>
)
}}
</Mutation>
)
I tried including the variables at the point of invocation as following:
<form onSubmit={(login, e) => onSubmitHandler(login, e)}>
But, to no avail.
Edit: The initial issue has been resolved, but when I refactored the code to utilize react-apollo-hooks, I keep getting the following errors:
Variable "$email" of required type "String!" was not provided
Variable "$password" of required type "String!" was not provided
My refactored codes are as follows:
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const variables = {
data: { email, password }
}
const login = useMutation(LOGIN_MUTATION, {
variables
})
const onSubmitHandler = async (login, e) => {
e.preventDefault()
const authResults = await login()
localStorage.setItem(AUTH_TOKEN, authResults.data.login.token);
props.history.push('/')
}
The graphql mutation
const LOGIN_MUTATION = gql`
mutation Login($email: String!, $password: String!) {
login(data: {
email: $email, password: $password
}
){
token
user {
id
}
}
}
`
My schema
login(data: LoginUserInput!): AuthPayload!

Categories

Resources