Uploading an image to Azure Blob Storage using React - reactjs

I want to upload an image to Azure Blob Storage using React.
I've tried a lot of examples and none of them work.
The one that seemed the best was this one but still didn't manage to get it working on React.
What I'm trying right now is to use the createContainerIfNotExists method just to test and the error is Cannot read property createBlobServiceWithSas of undefined
My code is the following:
import AzureStorage from 'azure-storage';
const account = {
name: 'x',
sas: 'x',
};
const blobUri = `https://${account.name}.blob.core.windows.net`;
const blobService = AzureStorage.Blob.createBlobServiceWithSas(blobUri, account.sas);
export const createContainer = () => {
blobService.createContainerIfNotExists('test', (error, container) => {
if (error) {
// Handle create container error
} else {
console.log(container.name);
}
});
};
export default createContainer;

According to my research, because you develop A React application, we can not use the createBlockBlobFromBrowserFile method. We just can use the method in the browser. For more details, please refer to the document.
According to the situation, I suggest you use the other method(such as uploadStreamToBlockBlob) to upload image with V10 sdk. For more details, please refer to https://learn.microsoft.com/en-us/javascript/api/#azure/storage-blob/?view=azure-node-latest

Related

Dynamic user profile templates in Next.js

I want to build a templating engine for user profiles. After picking a design, which might consist of HTML, CSS, and JS, I would like to be able to server-side/static render a users profile page using their chosen template.
I'm looking for a good place to start / for someone to point me in the right direction. Assuming there are templates already stored in a database, or saved as files to AWS, how might I dynamically load and render the template along with the users profile data using Next.js? What might be an optimal way of storing the templates?
Thank you,
Try use nextjs GetStaticProps or GetStaticPatch
https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props
https://nextjs.org/docs/basic-features/data-fetching/get-static-props
write this function in some NextPage file
export async function getStaticProps(context) {
//all logic done here will be rendered server-side.
return {
props: {}, // will be passed to the page component as props
}
}
It can consume a database within this layer, do not want to use an external API, in some projects I use the ORM Prisma to facilitate the process.
https://www.prisma.io/nextjs
// Fetch all posts (in /pages/index.tsx)
export async function getStaticProps() {
const prisma = new PrismaClient()
const posts = await prisma.post.findMany()
return {
props : { posts }
}
}

Error while deleting S3 objects - likely an issue with credentials but could not locate the problem

So I have been following other Q&A on stackoverflow and AWS SDK docs but I still couldn't delete S3 files with the following code, it simply gives the following error Error TypeError: Cannot read properties of undefined (reading 'byteLength')
My code (s3Client.js):
import { S3Client } from "#aws-sdk/client-s3";
const REGION = `${process.env.S3_UPLOAD_REGION}`;
const creds = {
accessKeyId: process.env.S3_UPLOAD_KEY,
secretAccessKey: process.env.S3_UPLOAD_SECRET
};
// Create an Amazon S3 service client object.
const s3Client = new S3Client({
region: REGION,
credentials: creds
});
export { s3Client };
My nextJS component:
import { DeleteObjectCommand } from "#aws-sdk/client-s3";
import { s3Client } from "../lib/s3Client.js"
const bucketParams = { Bucket: "my bucket name...", Key: "my key..." };
const run = async () => {
try {
const data = await s3Client.send(new DeleteObjectCommand(bucketParams));
console.log("Success. Object deleted.", data);
return data; // For unit tests.
} catch (err) {
console.log("Error", err);
}
};
I understand from others that this seems like a credential issue but I still couldn't wrap my head around where the problem is.
Edit:
Solution to this problem -
Check the .env, depending on whether you are using React or NextJS, you will need to have either "REACT_PUBLIC" or "NEXT_PUBLIC" in order for the environment objects to be exposed via process.env.
Check your permission in your S3 bucket and set "AllowedOrigins" to include your localhost. I had mine set as "AllowedOrigins": "*" but it wasn't enough. So I have included http://localhost:3000 and it worked.
So it looks like that you're using keys credentials for this. To debug your problem the 1st thing you should do is to check the credentials outside code and SDK and make sure they're fine.
To do this, setup the credentials on CLI by setting environment variables.
export AWS_ACCESS_KEY_ID=<Your Key here>
export AWS_SECRET_ACCESS_KEY=<SECRET HERE>
export AWS_DEFAULT_REGION=<AWS REGION>
Reference: https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html
After this run this command to verify credentials are setup correctly aws sts get-caller-identity
If they show you the account and user details. Then delete the file using CLI. If that works then it is confirmed that issue is not with the credentials and with code. If not, it will point you in the right direction where the issue is.

Async Clipboard API "ClipboardItem is not defined" - Reactjs copy image to Clipboard

I'm working on React js, I created my app with create-react-app using npm. I was trying to build a button that takes an image and writes it to the clipboard. Fourtunately I found this npm library that seems to work fine! But keeps me thinking why I couldn't use the ¿built-in? Asynchronous Clipboard API to copy the image (the text copy works fine). I read a really enlightening guide here, and kept reading other great guide here, so I tried all the codes suggested, there and in other pages (despite they don't seem to really change the functionality, I got to try). I came with the same error in every try that impedes to compile: "'ClipboardItem' is not defined no-undef". One code for example was this one:
const response = await fetch('valid img url of a png image');
const blob = await response.blob();
await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob})]);
It seems to be simple, easy to follow. The problem is when you need to put the data in a form the Clipboard can read it, make it a blob, because I need the ClipboardItem constructor, and my app seems to be unable to recognize it as such. Keeps returning ClipboardItem is not defined or, if I somehow define it, says it's not a constructor, of course. I tried with other constructors like Blob(), but had the same problem. The last thing kept me thinking that, since I'm new in the programming world, if there is something kinda basic I don't know of the interaction of Web Apis like this one with node or Reactjs, and if there is a solution, of course! Thanks in advance, you guys are great!
Edit: adding the whole component code as requested:
import React from "react";
function TestingClipAPI () {
async function handleScreenshot () {
const response = await fetch('https://i.postimg.cc/d0hR8HfP/telefono.png');
const blob = await response.blob();
await navigator.clipboard.write([new ClipboardItem({ 'image/png': blob})]);
};
return (
<div>
<button onClick={handleScreenshot} id="buttonID">test</button>
</div>
)
};
export default TestingClipAPI;
Possible issue: This might be because of CRA (Create-React-App) config - similar issue. Something like the library linked can be done, create a canvas and copy the image from there.
Solution or a way to make it work anyway: make a call this way before using ClipboardItem:
const { ClipboardItem } = window;
Note: this also works with other constructors like toBlob and HTMLCanvasElement that had the same issue.
Things to look for:
Browser support Clipboard
Secure origin on HTTPS or localhost. See this post.
How the function is being called - in the OP's case - onClick & asynchronous.
The issue is that onClick are not asynchronous by default and you are not awaiting the response and you also have a typo in navigator.clipboard.
const handleScreenshot = async () => {
try {
const response = await fetch(
"https://i.postimg.cc/d0hR8HfP/telefono.png"
);
const blob = await response.blob();
await navigator.clipboard.write([
new ClipboardItem({ "image/png": blob }),
]);
} catch (err) {
console.error(err);
}
}
return (
<button onClick={async () => await handleScreenshot()} id="buttonID">
test
</button>
);
There are tradeoff between inline function and below are alternatives. I'd personally use the latter method.
function handleScreenshot() {
async function screenShot() {
try {
const response = await fetch(
"https://i.postimg.cc/d0hR8HfP/telefono.png"
);
const blob = await response.blob();
await navigator.clipboard.write([
new ClipboardItem({ "image/png": blob }),
]);
} catch (err) {
console.error(err);
}
}
screenShot();
}
return (
<button onClick={handleScreenshot} id="buttonID">
test
</button>
);
Lastly, you can return a chained promise.
Simply add window in front of ClipboardItem like the following
window.ClipboardItem(...)
Unfortunately, as of the time of this answer, ClipboardItem isn't supported in Firefox. (Support can be enabled via an about:config setting; but of course, most Internet users will not have done this.)
Source: https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem#browser_compatibility

How can I access a library through a script in a Typescript React app?

I am fairly new to React, and have not done any extensive web development in years, so am struggling with a (probably) basic web issue:
I am implementing a Stripe based payment flow in a React web app (written in Typescript), and have hit a roadblock on step 2 (adding a redirect to checkout client-side).
The quickstart guide instructs me to insert the following script tag on my website, which I have done through inserting the tag inside the <head> tag:
Checkout relies on Stripe.js. To get started, include the following
script tag on your website—it should always be loaded directly from
https://js.stripe.com:
<script src="https://js.stripe.com/v3/"></script>
The next step is where I am having a problem (using the ESNext syntax since this is in a Typescript project):
Next, create an instance of the Stripe object by providing your publishable API key as the first parameter:
const stripe = Stripe('pk_test_sdjxyNjHWmRefdkUNYuS53MA00Ot1f9HOu');
I would like to access Stripe through a service worker, rather than a component directly. However, trying to initialise the stripe instance is not working. I have tried:
importing the Stripe module in various ways, which hasn't worked
adding a dependency on #types/stripe, which seems to prevent the compiler complaining
Currently, my StripeService.ts file has the following code:
const stripe = Stripe("SOME_KEY");
export const redirectToCheckout = (sessionId: string) => {
return stripe.redirectToCheckout(
{
sessionId: sessionId,
});
};
Localhost instance is giving this error:
/src/services/stripe/StripeService.ts
Line 12: 'Stripe' is not defined no-undef
Any suggestions on how I can resolve this issue? I have looked into the react-stripe-elements wrapper, but that is geared towards providing UI components, whereas I only want the Stripe checkout API call behaviour.
Bare Minimum
Minimum implementation is to declare Stripe using any:
declare class Stripe {
constructor(...args: any[]);
redirectToCheckout(...args: any[]): any;
}
const stripe = new Stripe("pk_test_sdjxyNjHWmRefdkUNYuS53MA00Ot1f9HOu");
stripe.redirectToCheckout({
sessionId: sessionId
})
Stronger Typings
You can of course expand this by more explicitly typing the parts that you need:
declare class Stripe {
constructor(publicKey: string);
redirectToCheckout({
sessionId
}: {
sessionId: string;
}): Promise<{ error: Error }>;
}
const stripe = new Stripe("pk_test_sdjxyNjHWmRefdkUNYuS53MA00Ot1f9HOu");
stripe.redirectToCheckout({
sessionId
}).then(function (result) {
// If `redirectToCheckout` fails due to a browser or network
// error, display the localized error message to your customer
// using `result.error.message`.
});
Try using the windows object instead:
var stripe = window.Stripe("pk_test_h4naRpZD1t2edp2HQKG2NrZi00rzz5TQJk");
For a service file, you would just add stripe to package.json, then in the file would do:
import Stripe from "stripe";
const stripe = Stripe("SOME_KEY");
export const redirectToCheckout = (sessionId: string) => {
return stripe.redirectToCheckout(
{
sessionId: sessionId,
});
};
You would use the public key in the client side, and the secret key in the server side. You should keep stripe object (Stripe('pk_test_sdjxyNjHWmRefdkUNYuS53MA00Ot1f9HOu')) in your state somehow to be able to retrieve it later.
An example call could be like this:
client side
const {paymentMethod, error} = await this.state.stripe.createPaymentMethod('card', cardElement, {
billing_details: {
name: 'Jenny Rosen',
},
});
StripeService.makePayment(paymentMethod);
server side
import Stripe as "stripe";
const stripe = Stripe("SOME_KEY");
export const makePayment = (paymentMethod: object) => {
...
};

ReactJS where do I store the API URI?

Where would I store the API URI centrally in a ReactJS Application? The URI only changes between environments and should be easily configurable (i.e. through environment variables).
I have looked into this package and into the new Context API, but am unsure it's the best way to achieve this. I have also looked into dotenv, but I don't like that I would have to use process.env.REACT_APP_SERVICE_URI in every component that wants to access the API. What is the usual approach?
I am not using Redux.
I don't think you need an external dependency to do that.
I usually create simple module called api-client.js, which is responsible for calls to external API and defining endpoints.
In your case you might have:
import axios from 'axios' // some http client lib
const endpoint = process.env.REACT_APP_SERVICE_URI? process.env.REACT_APP_SERVICE_URI : 'https://foo.api.net/'
export default {
getAllProducts () {
return axios.get(endpoint + 'products').then(response => {
log.debug(`api client fetched ${response.data.length} items`)
return response.data
}).catch(err => {
log.error(err.message)
throw err
})
}
},
getProductById (id) {
...
},
}
You read process.env.REACT_APP_SERVICE_URI only once.
I like to put this module inside api directory (and any other API related stuff).

Resources