im having trouble downloading an image from supabase. I get this errror
{
"statusCode": "400",
"error": "Bad Request",
"message": "headers should have required property 'authorization'"
}
I've followed the docs
https://supabase.io/docs/guides/with-nextjs
here is my code for the request
const myQuote = ({ dataFetch }) => {
const [avatarUrl, setAvatarUrl] = useState(null);
async function downloadImage(path) {
try {
const { data, error } = await supabase.storage
.from("job-photo")
.download(`jobphotos/${path}.jpg`);
if (error) {
throw error;
}
const url = URL.createObjectURL(data);
setAvatarUrl(url);
} catch (error) {
console.log("Error downloading image: ", error.message);
}
}
return (
<>
<Dashboard />
<QuoteTable tableData={dataFetch} downloadImg={downloadImage} />
</>
);
};
export default myQuote;
Managed to get it working by adding public/ to from
const { data, error } = await supabase.storage
.from("public/job-photo")
.download(`jobphotos/${path}.jpg`);
do you have the following code?
import { createClient } from '#supabase/supabase-js'
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
Related
I'm able to print and send test notification from firebase console with the token retrieved from firestore. But somehow I get Error Sending Notification: INTERNAL when I'm trying to send push notification via JavaScript
This is my JavaScript code
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp();
const messaging = admin.messaging();
exports.getUserData = functions.https.onCall(async (data, context) => {
const clientUid = data.clientUid;
try {
const snapshot = await admin.firestore().collection('users').doc(clientUid).get();
const userData = snapshot.data();
const token = userData.token;
const tokenString = JSON.stringify(token);
console.log(`Token String: ${tokenString}`);
console.log(`User data: ${JSON.stringify(userData)}`);
return userData;
} catch (error) {
console.error(`Error retrieving user data: ${error}`);
throw new functions.https.HttpsError('internal', 'Error retrieving user data.');
}
});
exports.sendNotification = functions.https.onCall(async (data, context) => {
const token = data.token;
const payload = {
notification: {
title: 'New Notification',
body: 'You have a new notification!'
}
};
try {
const response = await admin.messaging().sendToDevice(token, payload, {
contentAvailable: true,
priority: 'high'
});
console.log('Successfully sent message:', response);
return { message: 'Push notification sent successfully!' };
} catch (error) {
console.error('Error sending push notification:', error);
throw new functions.https.HttpsError('internal', 'Error sending push notification');
}
});
and the following is my code in SwiftUI
import SwiftUI
import JavaScriptCore
import Firebase
import StoreKit
import FirebaseFunctions
class JSNotification: ObservableObject {
#Published var token = ""
func sendNotificationFromSwift(clientUid: String) {
let context = JSContext()!
if let filePath = Bundle.main.path(forResource: "index", ofType: "js", inDirectory: "functions") {
do {
let content = try String(contentsOfFile: filePath)
context.evaluateScript(content)
let functions = Functions.functions()
let sendNotification = functions.httpsCallable("sendNotification")
Firestore.firestore().collection("users").document(clientUid).getDocument { snapshot, error in
if let error = error {
print(error.localizedDescription)
return
} else {
if let data = snapshot?.data() {
self.token = data["token"] as? String ?? ""
print(self.token)
sendNotification.call(["token": self.token]) { result, error in
if let error = error {
print("Error Sending Notification: \(error.localizedDescription)")
return
} else {
print("Push Notification Is Sent")
}
}
}
}
}
} catch {
print("Error Reading JS File.")
}
} else {
print("No Path Found.")
}
}
}
The sendNotificationFromSwift is called as follow
import Firebase
import SwiftUI
struct TestJSView: View {
#StateObject var jsNotification = JSNotification()
var body: some View {
Button {
jsNotification.sendNotificationFromSwift(clientUid: "A_Valid_Uid")
} label: {
Text("Test JS Notification")
}
}
}
The JavaScript function has been successfully deployed too.
Can anyone please let me know what went wrong? Any advice will be much appreciated.
Here's how I solved the issue.
I ran this command in my terminal:
firebase functions:log
that gives me the details of the error "INTERNAL" which in my case is "sendNotification: Error sending push notification: FirebaseMessagingError: An error occurred when trying to authenticate to the FCM servers. Make sure the credential used to authenticate this SDK has the proper permissions." generated from this function above
func sendNotificationFromSwift(clientUid: String) {
let context = JSContext()!
if let filePath = Bundle.main.path(forResource: "index", ofType: "js", inDirectory: "functions") {
do {
let content = try String(contentsOfFile: filePath)
context.evaluateScript(content)
let functions = Functions.functions()
let sendNotification = functions.httpsCallable("sendNotification")
Firestore.firestore().collection("users").document(clientUid).getDocument { snapshot, error in
if let error = error {
print(error.localizedDescription)
return
} else {
if let data = snapshot?.data() {
self.token = data["token"] as? String ?? ""
print(self.token)
sendNotification.call(["token": self.token]) { result, error in
if let error = error {
//Error generated from here
print("Error Sending Notification: \(error.localizedDescription)")
return
} else {
print("Push Notification Is Sent")
}
}
}
}
}
} catch {
print("Error Reading JS File.")
}
} else {
print("No Path Found.")
}
}
And the solution can be found here.
i'M working on a Chat Application project
but im getting this error of fetching friends from the backend(node)
I'm getting the friends data on the console but i'm unable to display it.
this is my Context and States
export const Messenger = () => {
// Context State
const { friends, setFriends, authInfo } = useAuth();
const [loggedUser, setLoggedUser] = useState();
const { updateNotification } = useNotification();
const fetchMessengerUsers = async () => {
try {
const token = getToken();
const config = {
headers: {
authorization: "Bearer " + token,
},
};
const { data } = await client("/get-friends", config);
console.log(data);
setFriends(data);
} catch (error) {
updateNotification("error", "Failed To load the Chat");
}
};
useEffect(() => {
setLoggedUser(localStorage.getItem("auth-token"));
fetchMessengerUsers();
}, []);
then in return i'm mapping all friends to display them
<div className="friends">
{friends && friends.length > 0
? friends.map((fd) => (
<div className="hover-friend">
<Friends friend={fd} />
</div>
))
: "No Friend"}
</div>
It displays No Friend on the browser
this link shows how it appears on the browser
just change your fetchMessengerUsers function.
you need to set setFriends(data.friends)
const fetchMessengerUsers = async () => {
try {
const token = getToken();
const config = {
headers: {
authorization: "Bearer " + token,
},
};
const { data } = await client("/get-friends", config);
console.log(data);
setFriends(data.friends); // you have to set friends array here, earlier you were setting the entire object.
} catch (error) {
updateNotification("error", "Failed To load the Chat");
}
};
I have external .js file created exactly for fetching data from backend based on website locale. Here is the code:
import { ref } from "vue";
export function fetchData(section, key) {
// GET request using fetch with error handling and headers
const headers = {
method: "GET",
headers: { "Content-Type": "application/json" },
};
const fetchedData = ref(null);
fetch(
"http://localhost:4000/api/" + section + "/?api-key=" + key,
headers
)
.then(async (response) => {
const data = await response.json();
// check for error response
if (!response.ok) {
// get error message from body or default to response statusText
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
fetchedData.value = data;
})
.catch((error) => {
console.error("There was an error!", error);
return error;
});
return fetchedData;
}
And this is code from .vue file where I calling fetchData function:
<script setup>
import { fetchData } from "../../utils/universal-fetch";
import { ref, watch } from "vue";
import { useStore } from "../../stores/language.js";
import { useI18n } from "vue-i18n";
import AOS from "aos";
const store = useStore();
const { locale } = useI18n({ useScope: "global" });
const fetchedData = ref(fetchData("homeFirstSection", store.getLanguage));
AOS.init();
watch(
() => locale.value,
() => {
fetchedData.value = fetchData("homeFirstSection", store.getLanguage);
}
);
</script>
When page is created/refreshed, fetchData function fetch data from backend correctly. The problem which I'm trying to solve is that, when I change a locale, watcher automatically detects that, locale was changed and variable fetchedData should be updated based on choosen locale.
Problem
Thanks!
I found a problem. Here is code:
export function async fetchData(section, key) { // Added async
// GET request using fetch with error handling and headers
const headers = {
method: "GET",
headers: { "Content-Type": "application/json" },
};
let fetchedData = null;
await fetch( // Added await
"http://localhost:4000/api/" + section + "/?api-key=" + key,
headers
)
.then(async (response) => {
const data = await response.json();
// check for error response
if (!response.ok) {
// get error message from body or default to response statusText
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
fetchedData = data;
})
.catch((error) => {
console.error("There was an error!", error);
return error;
});
return fetchedData;
}
In my external .js file I was missing one more async await.
<script setup>
import { fetchData } from "../../utils/universal-fetch";
import { ref, watch } from "vue";
import { useStore } from "../../stores/language.js";
import { useI18n } from "vue-i18n";
import AOS from "aos";
const store = useStore();
const { locale } = useI18n({ useScope: "global" });
const fetchedData = ref(null);
fetchData("agreementsFirstSection", store.getLanguage).then(
(data) => (fetchedData.value = data)
); // Added .then
AOS.init();
watch(
() => locale.value,
() => {
fetchData("agreementsFirstSection", store.getLanguage).then(
(data) => (fetchedData.value = data)
); // Added .then instead of directly assign
}
);
</script>
And in .vue file I was missing .then insted of directly assigning value to variable. I added comments to code to compare changes before and after.
Problem solved
I'm doing an API using React, SQL and Sequelize. I'm already finished but now I was asked to do my API request using JavaScript oriented object. The problem is, I don't really know how to do it, and I don't really understand my errors.
This is the class I am trying to do:
API class
class Api {
constructor(hostName, token) {
this.hostName = hostName
this.token = token
}
async getPost() {
return await fetch('api/post/')
.then(res => {
if (!res.ok) {
throw Error(res.statusText + "-" + res.url);
}
return res;
})
.then(post => {
console.log(post)
return post
})
.catch(err => {
console.log("Page non trouvée")
console.log(err)
})
}
}
export const apiRequest = new Api();
Axios config
import axios from 'axios';
class AxiosConfig {
constructor() {
this.axios = axios.create();
this.axios.defaults.baseURL = `${process.env.REACT_APP_API_URL}`;
this.axios.defaults.headers = {
'Content-Type': 'application/json',
};
//All request will wait 2 seconds before timeout
this.axios.defaults.timeout = 2000;
this.axios.defaults.withCredentials = true;
}
GET = async (url) => {
return await this.axios.get(`/${url}`);
}
POST = async (url, payload) => {
return await this.axios.post(`/${url}`, payload);
}
PUT = async (url, payload) => {
return await this.axios.put(`/${url}`, payload);
}
DELETE = async (url) => {
return await this.axios.delete(`/${url}`);
}
}
export const axiosInstance = new AxiosConfig();
HandlePost() is the function I'm tring to put in oriented object
NewPostForm
import React, { useContext, useEffect, useState } from 'react';
import { NavLink } from 'react-router-dom';
import { UserContext } from '../../UserContext';
import { apiRequest } from '../../utils/api';
import { axiosInstance } from '../../utils/AxiosConfig'
import landscape from './../../assets/icons/landscape.svg'
const NewPostForm = () => {
const uid = useContext(UserContext)
const [userPicture, setUserPicture] = useState('')
const [firstName, setFirstName] = useState('')
const [lastName, setLastName] = useState('')
const [message, setMessage] = useState('')
const [postPicture, setPostPicture] = useState('')
const [file, setFile] = useState('')
useEffect(() => {
const getUserInfo = async () => {
if (uid !== null) {
const userId = uid.userId
await axiosInstance.GET (`api/auth/${userId}`)
.then((res) => {
setFirstName(res.data.firstName)
setLastName(res.data.lastName)
setUserPicture(res.data.profile)
})
.catch((err) => {
console.log(err)
})
}
}
getUserInfo()
}, [uid, firstName, lastName])
console.log('parfait', axiosInstance.GET(`api/post`)) // old one, works perfectly
console.log('objectif', apiRequest.getPost()) // new one, not getting the object I need
// console.log(axiosInstance.GET(apiRequest.getPost`${uid.userId}`)) // error
const handlePost = async () => {
if (message || postPicture) {
const data = new FormData();
data.append("UserId", uid.userId);
data.append("content", message);
if (file) {
data.append("image", file);
}
try {
const res = await axiosInstance.POST(`api/post`, data);
console.log('File uploaded', res.data);
// window.location = '/'
} catch (err) {
console.error('Failed to upload file', err);
}
cancelPost()
} else {
alert("Veuillez entrer un message")
}
}
const handlePicture = (e) => {
setPostPicture(URL.createObjectURL(e.target.files[0]))
setFile(e.target.files[0])
}
const cancelPost = () => {
setMessage('')
setPostPicture('')
setFile('')
}
return (
<form className='post-container' >
<h2 className='h1'>Créer un post</h2>
<NavLink to="/profile">
<figure title='Profil utilisateur' className='new card-header'>
<img className='nav-profile' src={userPicture ? userPicture : "./images/img/profile.png"} width='50px' alt="profil de l'utilisateur" />
<h3 className='h2'>{firstName} {lastName}</h3>
</figure>
</NavLink>
<div className='post-form'>
<textarea
type="text"
name="message"
id="message"
cols="50"
rows="5"
placeholder="Quoi de neuf ?"
onChange={(e) => setMessage(e.target.value)}
value={message}
></textarea>
{postPicture && <img src={postPicture} alt="preview" className="img-preview" />}
</div>
<div className='footer-form'>
<div className='icon'>
<input
type="file"
id='file-upload'
name='file'
accept='.jpg, .jpeg, .png'
onChange={(e) => handlePicture(e)}
/>
<label className='file-input__label' htmlFor="file-upload">
<img className='svg' src={landscape} alt="upload icone paysage" />
Ajouter une l'image
</label>
</div>
<div className='new button-container'>
{message || postPicture ? (
<button className='new cancel-btn' onClick={(e) => cancelPost()}>Annuler</button>
) : null}
<button className='new validate-btn' onClick={(e) => handlePost()}>Envoyer</button>
</div>
</div>
</form>
);
};
export default NewPostForm;
My first console.log() returning the object that I need, when the second (supposed oriented object one) doesn't. I don't know what I'm doing wrong and the documentation doesn't help, I don't have the "good" questions.
Thanks
EDIT :
class Api {
constructor(hostName, token) {
this.hostName = hostName
this.token = token
}
async getPost() {
try {
const res = await fetch('api/post')
if (!res.ok) {
throw Error(res.statusText + "-" + res.url);
}
return await res.json();
} catch(err) {
console.log("Page non trouvée")
console.log(err)
}
}
}
export const apiRequest = new Api();
The problem is with the code that how you used fetch method. This is from the documentation.
The Response object, in turn, does not directly contain the actual JSON response body but is instead a representation of the entire HTTP response. So, to extract the JSON body content from the Response object, we use the json() method, which returns a second promise that resolves with the result of parsing the response body text as JSON.
You have to update your getPost method like below.
async getPost() {
return await fetch('api/post/').then(res => {
if (!res.ok) {
throw Error(res.statusText + "-" + res.url);
}
return res.json();
}).then(post => {
console.log(post)
return post
})
.catch(err => {
console.log("Page non trouvée")
console.log(err)
})
}
Check the documentation
You already using async and await so you don't need to use .then. The code can be updated like below.
async getPost() {
try {
const res = await fetch('api/post/')
if (!res.ok) {
throw Error(res.statusText + "-" + res.url);
}
return await res.json();
} catch(err) {
console.log("Page non trouvée")
console.log(err)
}
}
I am developing my first Dapp, I am using metamask and web3 for this. As far now, I am able to get my wallet balance and connect account to metamask. Now I am trying switch between two networks, I am using handleChainChanged, also I am passing chainId and Networkversion but, it is giving me error. I am uncertain about returning anything from changeNetwork function or I only have to pass chainId and Networkversion.
import { useStoreApi } from "./storeApi";
import { useState } from "react";
import useWeb3 from "./useWeb3";
import { Button, TextField } from "#material-ui/core";
import "./App.css";
function App() {
const { balance, address, message, setAddress, setBalance } = useStoreApi();
const web3 = useWeb3();
// get user account on button click
const getUserAccount = async () => {
if (window.ethereum) {
try {
await window.ethereum.enable();
web3.eth.getAccounts().then((accounts) => {
setAddress(accounts[0]);
updateBalance(accounts[0]);
console.log(accounts);
});
} catch (error) {
console.error(error);
}
} else {
alert("Metamask extensions not detected!");
}
web3.eth.getChainId().then(console.log);
};
const updateBalance = async (fromAddress) => {
await web3.eth.getBalance(fromAddress).then((value) => {
setBalance(web3.utils.fromWei(value, "ether"));
});
};
const changeNetwork = async () => {
if (window.ethereum) {
try {
await window.ethereum.enable();
window.ethereum._handleChainChanged({
chainId: 0x1,
networkVersion: 1,
});
} catch (error) {
console.error(error);
}
}
};
return (
<div className="App">
<header className="App-header">
{address ? (
<>
<p> Balance: {balance} </p>
</>
) : null}
<Button
onClick={() => getUserAccount()}
variant="contained"
color="primary"
>
Connect your account
</Button>
<Button onClick={changeNetwork} variant="contained" color="primary">
Switch to mainnet ethereum
</Button>
</header>
</div>
);
}
export default App;
What if the user doesn't have the required network added? Here is an expanded version which tries to switch, otherwise add the network to MetaMask:
const chainId = 137 // Polygon Mainnet
if (window.ethereum.networkVersion !== chainId) {
try {
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: web3.utils.toHex(chainId) }]
});
} catch (err) {
// This error code indicates that the chain has not been added to MetaMask
if (err.code === 4902) {
await window.ethereum.request({
method: 'wallet_addEthereumChain',
params: [
{
chainName: 'Polygon Mainnet',
chainId: web3.utils.toHex(chainId),
nativeCurrency: { name: 'MATIC', decimals: 18, symbol: 'MATIC' },
rpcUrls: ['https://polygon-rpc.com/']
}
]
});
}
}
}
You can use wallet_switchEthereumChain method of RPC API of Metamask
Visit: https://docs.metamask.io/guide/rpc-api.html#wallet-switchethereumchain
const changeNetwork = async () => {
if (window.ethereum) {
try {
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: Web3.utils.toHex(chainId) }],
});
});
} catch (error) {
console.error(error);
}
}
changeNetwork()
export async function switchToNetwork({
library,
chainId,
}: SwitchNetworkArguments): Promise<null | void> {
if (!library?.provider?.request) {
return
}
const formattedChainId = hexStripZeros(
BigNumber.from(chainId).toHexString(),
)
try {
await library.provider.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: formattedChainId }],
})
} catch (error) {
// 4902 is the error code for attempting to switch to an unrecognized chainId
// eslint-disable-next-line #typescript-eslint/no-explicit-any
if ((error as any).code === 4902) {
const info = CHAIN_INFO[chainId]
await library.provider.request({
method: 'wallet_addEthereumChain',
params: [
{
chainId: formattedChainId,
chainName: info.label,
rpcUrls: [info.addNetworkInfo.rpcUrl],
nativeCurrency: info.addNetworkInfo.nativeCurrency,
blockExplorerUrls: [info.explorer],
},
],
})
// metamask (only known implementer) automatically switches after a network is added
// the second call is done here because that behavior is not a part of the spec and cannot be relied upon in the future
// metamask's behavior when switching to the current network is just to return null (a no-op)
try {
await library.provider.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: formattedChainId }],
})
} catch (error) {
console.debug(
'Added network but could not switch chains',
error,
)
}
} else {
throw error
}
}
}