How to show uploaded files using initialFiles on material-ui-dropzone? - reactjs

I am using reactjs and trying to show my uploaded files in preview area of material-ui-dropzone.
First I fetch my uploaded files (just their name) from server and then set it into state. I set initialFiles={uploadedFiles} but my uploaded files not show in preview area. How can I fix that?
My code:
import { DropzoneArea } from "material-ui-dropzone";
export function UploadedFileDropzone(props) {
const [uploadedFiles, setUploadedFiles] = useState([]);
function getUploadedFiles() {
// const files = fetch file names from server
setUploadedFiles(files);
}
useEffect(() => {
getUploadedFile();
}, []);
return (
<div>
<DropzoneArea initialFiles={uploadedFiles}/>
</div>
)
}
Here is what I had and what I expect

There is a property of "DropzoneArea" called 'useChipsForPreview' by default it's false set it to true you will get the desire output

Related

Why is filepond sending a GET request at my server index when I remove a preloaded file?

Hi I'm using React filepond to upload files to our server and everything works fine for the most part.
The problem is when I have preloaded files, if I try to remove one of them Filepond sends a GET request to http://myserver.domain/12345.jpg
I don't know why this request is sent and this is not even an available endpoint on my server so it always returns an error with status 404.
My filepond instance is configured like this :
export default function FileField({
name,
control,
rules,
defaultValue = null,
isMultiple,
fileTypes,
component_id,
}) {
const [files, setFiles] = useState(defaultValue || []);
// Controller from React-Hook-Form
//(It's used to save the list of files for later use)
const { field } = useController({ name, control, rules, defaultValue });
// Filepond ref
const pond = useRef(null);
const handleChange = () => {
let files = pond.current.getFiles();
// Set the value of the control field
field.onChange(
files.map((f) => {
return { source: f.serverId, options: { type: 'local' } };
})
);
field.onBlur();
};
return (
<div className='px-4 py-4 rounded bg-window-accent'>
<FilePond
ref={(ref) => (pond.current = ref)}
files={files}
onupdatefiles={setFiles}
onprocessfile={handleChange}
onremovefile={handleChange}
required={rules.required.value}
allowMultiple={isMultiple}
server={`/api/files/${component_id}`}
name={'file'}
acceptedFileTypes={fileTypes}
disabled={rules.disabled}
/>
</div>
);
}
When loading the file the correct endpoint is used GET /api/files/12345?load=12345.jpg
It's just when I click on the (X) The file is removed correctly from the input field but there's that additional GET Request that makes no sense...
This error does not happen when a file is reverted after being just uploaded, only happens when the file is preloaded in the files with option type="local".
The error in console
What can I do to stop filepond from sending this extra request ?

How to download the iframe as pdf document in react?I have tried using jspdf and kendo-react-pdf but getting blank document

import { PDFExport, savePDF } from '#progress/kendo-react-pdf';
const [contentRef, setContentRef] = useState('');
const downloadCertificate = () => {
const element: any =
document.querySelector('#certificate') || document.body;
savePDF(element, { paperSize: 'A4' });
};
const onClickDownload = () => {
downloadCertificate();
};
return (
<div>
<PDFExport ref={pdfExportComponent} paperSize="A4">
<iframe
id="certificate"
title="View your certificate"
className="u-els-margin-left-3x u-els-margin-right-3x"
width="776px"
height="600px"
srcDoc={contentRef}
/>
</PDFExport>
</div>
);
Using the above set of code to generate the pdf, I am importing the PDF Export and wrapping it around the block of code i want to export as pdf. Here the srcDoc of iframe is what I exactly want to export which assigned to a useState. So after the page renders the info is stored in srcDoc and I want to export this as pdf on click of the button which is part of the return.
currently iframes are not supported as part of the PDF export: https://www.telerik.com/kendo-react-ui/components/drawing/limitations-browser-support/#toc-elements-and-styles

How to generate a menu based on the files in the pages directory in Next.js

I am trying to create a menu component that reads the contents of the pages folder at build time. However I haven't had any success. Here is what I have tried:
import path from "path";
import * as ChangeCase from "change-case";
export default class Nav extends React.Component {
render() {
return (
<nav>
{this.props.pages.map((page) => (
<a href={page.link}>{page.name}</a>
))}
</nav>
);
}
async getStaticProps() {
let files = fs.readdirSync("../pages");
files = files.filter((file) => {
if (file == "_app.js") return false;
const stat = fs.lstatSync(file);
return stat.isFile();
});
const pages = files.map((file) => {
if (file == "index.js") {
const name = "home";
const link = "/";
} else {
const link = path.parse(file).name;
const name = ChangeCase.camelCase(link);
}
console.log(link, name);
return {
name: name,
link: link,
};
});
return {
props: {
pages: pages,
},
};
}
}
This does not work, the component does not receive the pages prop. I have tried switching to a functional component, returning a promise from getStaticProps(), switching to getServerSideProps(), and including the directory reading code into the render method.
The first two don't work because getStaticProps() and getServerSideProps() never get called unless the component is a page, and including the code in the render method fails because fs is not defined or importable since the code might run on the front end which wouldn't have fs access.
I've also tried adding the code to a getStaticProps() function inside _app.js, with the hopes of pushing the pages to the component via context, but it seems getStaticProps() doesn't get called there either.
I could run the code in the getStaticProps function of the pages that include the menu, but I would have to repeat that for every page. Even if I extract the logic into a module that gets called from the getStaticProps, so something like:
// ...
export async function getStaticProps() {
return {
props: {
pages: MenuMaker.getPages(),
// ...
}
}
}
and then pass the pages to the navigation component inside the page via the Layout component:
export default function Page(props) {
return (
<Layout pages={props.pages}></Layout>
)
}
then that's still a lot of boilerplate to add to each page on the site.
Surely there is a better way... It can't be that there is no way to add static data to the global state at build time, can it? How do I generate a dynamic menu at build time?
I managed to get this working by exporting a function from next.config.js and setting an environment variable that contains the menu structure. I abstracted the menu loading code into it's own file. After seeing the result, I understand better why I was not able to find an example of anyone doing something similar:
The menu is not ordered the way I would like. I could sort it alphabetically, or by the modification date but realistically it almost always needs to be manually sorted in relation to the subject of the pages. I could use an integer, either tacked on to the filename or somewhere in the file (perhaps in a comment line). But in retrospect I think that just hard coding the links in a component is probably the best way after all since it offers much more flexibility and probably isn't going to be much more work even in the very long run.
That being said I am sharing my solution as it is a way to initialize an app wide static state. It's not ideal, you will have to restart the dev server if you wish to recalculate the variables here, which is why I'm still interested in other possible solutions, but it does work. So here it is:
next.config.js
const menu = require("./libraries/menu.js");
module.exports = (phase, { defaultConfig }) => {
return {
// ...
env: {
// ...
menu: menu.get('pages'),
// ...
},
// ...
};
};
libraries/menu.js
const fs = require("fs");
const path = require("path");
const ccase = require("change-case");
module.exports = {
get: (pagePath) => {
if (pagePath.slice(-1) != "/") pagePath += "/";
let files = fs.readdirSync(pagePath);
files = files.filter((file) => {
if (file == "_app.js") return false;
const stat = fs.lstatSync(pagePath + file);
return stat.isFile();
});
return files.map((file) => {
if (file == "index.js") {
return {
name: "Home";
link: "/";
};
} else {
link = path.parse(file).name;
return {
link: link;
name: ccase.capitalCase(link);
};
}
});
},
};
Then the actual menu is generated from the environment variable in a component that can be included in the layout:
components/nav.js
import Link from "next/link";
export default class Nav extends React.Component {
render() {
return (
<nav>
{process.env.menu.map((item) => (
<Link key={item.link} href={item.link}>
<a href={item.link}>
{item.name}
</a>
</Link>
))}
</nav>
);
}
}
You can try this:
const fg = require('fast-glob');
const pages = await fg(['pages/**/*.js'], { dot: true });

WP Gutenberg, how to pass variables from backend (the save function) to frontend (a React app rendered in the save function output)?

If I have a Gutenberg block for which I gather a string that the user enters, but I want to use that string within a react app rendered in the frontend, how can I pass that string?
Defining a Gutenberg block
save: ({ attributes }) => {
window.thisVariableWillNotBeSeen = attributes
console.log(window) // here `thisVariableWillNotBeSeen` is seen, in the frontend it is not
return (
<div id="test_react"></div>
)
},
Then, a script enqueued as such (within a plugin)
add_action('wp_enqueue_scripts', 'react_enqueue');
function react_enqueue()
{
$asset_file = include(plugin_dir_path(__FILE__) . 'build/test.asset.php');
wp_enqueue_script(
'myBlock',
plugins_url('build/test.js', __FILE__),
$asset_file['dependencies'],
$asset_file['version'],
true
);
}
And scr/test.js
const { render } = wp.element
import { Test} from './components/test'
render(<Test />, document.getElementById(`test_react`))
Within export const Test, if I see there console.log(window) I cannot see the global variable I have added in the save function of before
How could I do this?
As said here https://stackoverflow.com/a/44663473/826815
it can be done by rendering a script or also a dataset property, and later fetch this data through the window object or through the DOM
save: ({ attributes }) => {
return (
<Fragment>
<div id="test_react"></div>
<div id="test_react_data" data-test={JSON.stringify(attributes)}></div>
<script type="text/javascript">{`var test_react= ${JSON.stringify(attributes)};`}</script>
</Fragment>
)
},

React app - upload and read JSON file into variable without a server?

I'm building a JSON editor in React and right now I'm just fetching a json file from a static folder on the server and sticking it in a variable. I'd like to be able to use a file input and select any json file and read it into the variable.
Is this possible without a server?
That said, I also tried using an Express/Cors server but it's a bit outside my wheelhouse and I'm not sure how to install / run it on the production domain where this editor will live.
Have an input of type file and maintain a state and update the state upon onChange
working demo is here
Code snippet
import React, { useState } from "react";
export function Upload({ children }) {
const [files, setFiles] = useState("");
const handleChange = e => {
const fileReader = new FileReader();
fileReader.readAsText(e.target.files[0], "UTF-8");
fileReader.onload = e => {
console.log("e.target.result", e.target.result);
setFiles(e.target.result);
};
};
return (
<>
<h1>Upload Json file - Example</h1>
<input type="file" onChange={handleChange} />
<br />
{"uploaded file content -- " + files}
</>
);
}

Resources