React Data-Table search component not rendering/working like it should - reactjs

I am using an npm package called react-datatable for a project and I am trying to build out a way to search through the data. I found a repo where someone was able to do this; however, his react skills are above mine and I cannot seem to make his code work properly on my end. I would just like to know why it isn't rendering anything on my front end. Any advice would be helpful. Thank you.
His code:
import React from 'react';
import styled from 'styled-components';
import { storiesOf } from '#storybook/react';
import faker from 'faker';
import Button from '../shared/Button';
import DataTable from '../../../src/index';
const createUser = () => ({
id: faker.random.uuid(),
name: faker.name.findName(),
email: faker.internet.email(),
address: faker.address.streetAddress(),
bio: faker.lorem.sentence(),
image: faker.image.avatar(),
});
const createUsers = (numUsers = 5) =>
new Array(numUsers).fill(undefined).map(createUser);
const fakeUsers = createUsers(2000);
const TextField = styled.input`
height: 32px;
width: 200px;
border-radius: 3px;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border: 1px solid #e5e5e5;
padding: 0 32px 0 16px;
&:hover {
cursor: pointer;
}
`;
const ClearButton = styled(Button)`
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
height: 34px;
width: 32px;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
`;
const FilterComponent = ({ filterText, onFilter, onClear }) => (
<>
<TextField id="search" type="text" placeholder="Filter By Name" aria-label="Search Input" value={filterText} onChange={onFilter} />
<ClearButton type="button" onClick={onClear}>X</ClearButton>
</>
);
const columns = [
{
name: 'Name',
selector: 'name',
sortable: true,
},
{
name: 'Email',
selector: 'email',
sortable: true,
},
{
name: 'Address',
selector: 'address',
sortable: true,
},
];
const BasicTable = () => {
const [filterText, setFilterText] = React.useState('');
const [resetPaginationToggle, setResetPaginationToggle] = React.useState(false);
const filteredItems = fakeUsers.filter(item => item.name && item.name.toLowerCase().includes(filterText.toLowerCase()));
const subHeaderComponentMemo = React.useMemo(() => {
const handleClear = () => {
if (filterText) {
setResetPaginationToggle(!resetPaginationToggle);
setFilterText('');
}
};
return <FilterComponent onFilter={e => setFilterText(e.target.value)} onClear={handleClear} filterText={filterText} />;
}, [filterText, resetPaginationToggle]);
return (
<DataTable
title="Contact List"
columns={columns}
data={filteredItems}
pagination
paginationResetDefaultPage={resetPaginationToggle} // optionally, a hook to reset pagination to page 1
subHeader
subHeaderComponent={subHeaderComponentMemo}
selectableRows
persistTableHead
/>
);
};
storiesOf('Filtering', module)
.add('Example 1', () => <BasicTable />)
My code:
import React from 'react';
import NotesListHtml from './NoteListHtml'
import DataTable from 'react-data-table-component';
const FilterComponent = ( { filterText, onClear, onFilter }) => (
<>
<input id="search" type="text" placeholder="Filter By Name" aria-label="Search Input" value={filterText} onChange={onFilter} />
<button type="button" onClick={onClear}>X</button>
</>
)
const BasicTable = (props) => {
let result = props.notes.map(function(el) {
var o = Object.assign({}, el);
o.fullName = `${props.data.first_name} ${props.data.last_name}`;
return o;
})
const ExpandableComponent = ({ data }) =>{
return(<p style={{padding:'20px'}}>{data.contentBody}</p>)
}
const columns = [
{
name: 'Organization',
selector: row => row.type[0].label || row.type,
sortable: true,
wrap:true
},
{
name: 'Title',
selector: 'title',
sortable: true,
},
{
name: 'Date',
selector: row=>row.createdAt.split('T')[0],
sortable: true,
},
{
name: 'Author',
selector: 'fullName',
sortable: true,
},
];
const customStyles = {
headCells: {
style: {
backgroundColor:'#f3f7f9',
},
},
cells: {
style: {
color:'#79838b'
},
},
};
const [filterText, setFilterText] = React.useState('');
const [resetPaginationToggle, setResetPaginationToggle] = React.useState(false);
const filteredItems = props.notes.filter(item => item.type[0].label && item.type[0].label.toLowerCase().includes(filterText.toLowerCase()))
const subHeaderComponentMemo = React.useMemo(() => {
console.log('subheader')
const handleClear = () => {
console.log('hit1')
if (filterText) {
setResetPaginationToggle(!resetPaginationToggle);
setFilterText('');
}
}
console.log('beforereturn');
return (
<>
{/* <input id="search" type="text" placeholder="Filter By Name" aria-label="Search Input" value={filterText} onChange={onFilter} /> */}
<button type="button" onClick={handleClear}>X</button>
</>
)
}, [filterText, resetPaginationToggle])
return (
<>
<DataTable
subHeaderComponent={subHeaderComponentMemo}
className='table'
columns={columns}
data={filteredItems}
pagination={true}
highlightOnHover={true}
pointerOnHover={true}
expandableRows={true}
expandOnRowClicked={true}
expandableRowsComponent={<ExpandableComponent data={result} />}
paginationResetDefaultPage={resetPaginationToggle} // optionally, a hook to reset pagination to page 1
customStyles={customStyles}
subHeader={false}
/>
</>
);
}
export default BasicTable;

Related

How can I upload Images with Preview in React

I've been trying to upload multiple images WITH preview in NextJS (React). I tried changing the constants to arrays and tried mapping through them but it just doesn't seem to work and I don't know how I could get it to work.
I've made a component out of the upload functionality and here is the code that works for uploading a single image with a Preview.
uploadImage.js
import React, { useEffect, useRef, useState } from "react";
import styled from "styled-components";
function imageUpload() {
const [image, setImage] = useState(null);
const fileInputRef = useRef();
const [preview, setPreview] = useState();
useEffect(() => {
if (image) {
const reader = new FileReader();
reader.onloadend = () => {
setPreview(reader.result);
};
reader.readAsDataURL(image);
} else {
}
}, [image]);
return (
<div className="flex ">
<StyledImg
src={preview}
style={{ objectFit: "cover" }}
onClick={() => setImage(null)}
/>
<StyledButton
onClick={(e) => {
e.preventDefault();
fileInputRef.current.click();
}}
/>
<input
type="file"
style={{ display: "none" }}
accept="image/*"
ref={fileInputRef}
onChange={(e) => {
const file = e.target.files[0];
if (file && file.type.substr(0, 5) === "image") {
setImage(file);
} else {
setImage(null);
}
}}
/>
</div>
);
}
const StyledButton = styled.button`
`;
const StyledImg = styled.img`
width: 100px;
height: 100px;
margin-right: 10px;
`;
export default imageUpload;
Based on these references https://react-dropzone.js.org/#section-previews and https://stackblitz.com/edit/nextjs-buk2rw?file=pages%2Findex.js I replaced my code with the following
ImageUpload.js
import React, { useEffect, useState } from "react";
import { useDropzone } from "react-dropzone";
import styled from "styled-components";
function DragAndDrop() {
const [files, setFiles] = useState([]);
const { getRootProps, getInputProps } = useDropzone({
accept: "image/*",
onDrop: (acceptedFiles) => {
setFiles((files) => [
...files,
...acceptedFiles.map((file) =>
Object.assign(file, {
key: file.name + randomId(), // to allow adding files with same name
preview: URL.createObjectURL(file),
})
),
]);
},
});
const removeFile = (file) => {
setFiles((files) => {
const newFiles = [...files];
newFiles.splice(file, 1);
return newFiles;
});
};
const thumbs = files.map((file, i) => (
<div style={thumb} key={file.key}>
<div style={thumbInner}>
<img src={file.preview} style={img} />
</div>
<button type="button" style={removeButton} onClick={() => removeFile(i)}>
X
</button>
</div>
));
useEffect(
() => () => {
files.forEach((file) => URL.revokeObjectURL(file.preview));
},
[files]
);
return (
<section className="container">
<div {...getRootProps({ className: "dropzone" })}>
<input {...getInputProps()} />
<StyledP className="flex align-center justify-center">
Glisser Images Ici ou Cliquer pour selectionner
</StyledP>
</div>
<aside style={thumbsContainer}>{thumbs}</aside>
</section>
);
}
const StyledP = styled.p`
cursor: pointer;
padding: 30px;
`;
const randomId = () => (Math.random() + 1).toString(36).substring(7);
const thumbsContainer = {
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
marginTop: 16,
};
const thumb = {
display: "inline-flex",
borderRadius: 2,
border: "1px solid #eaeaea",
marginBottom: 8,
marginRight: 8,
width: 100,
height: 100,
padding: 4,
boxSizing: "border-box",
position: "relative",
};
const thumbInner = {
display: "flex",
minWidth: 0,
overflow: "hidden",
};
const img = {
display: "block",
width: "auto",
height: "100%",
};
const removeButton = {
color: "red",
position: "absolute",
right: 4,
};
export default DragAndDrop;

How to change the color of radio button with font awesome icon in react, styled components

I want only the clicked icon to be changed in color but the whole icons’ color change when clicked.
I know it’s basically because useState is not assigned to each click event but I’m stuck here and don’t know how to approach.
const moods = [
{ icon: faGrinStars, mood: 'super' },
{ icon: faSmile, mood: 'good' },
{ icon: faMeh, mood: 'soso' },
{ icon: faFrown, mood: 'bad' },
{ icon: faAngry, mood: 'angry' },
];
const [clicked, setClicked] = useState(false);
const handleClick = () => {
setClicked(!clicked);
};
return (
<StyledDiv>
{moods.map((mood) => (
<div key={mood.mood}>
<input
type='radio'
name='mood'
id={mood.mood}
onClick={handleClick}
/>
<label htmlFor={mood.mood}>
<FontAwesomeIcon
icon={mood.icon}
size='2x'
style={clicked ? { color: 'red' } : { color: '#5e5c5a' }}
/>
</label>
</div>
))}
</StyledDiv>
);
};
const StyledDiv = styled.div`
${({ theme }) => {
const { colors } = theme;
return css`
input {
display: none;
}
`;
}}
`;
export default MoodIcons;
Use an array to save all state of clicked button status.
Something like this:
const moods = [
{ icon: faGrinStars, mood: 'super' },
{ icon: faSmile, mood: 'good' },
{ icon: faMeh, mood: 'soso' },
{ icon: faFrown, mood: 'bad' },
{ icon: faAngry, mood: 'angry' },
];
const [clicked, setClicked] = useState([false, false, false, false, false]);
const handleClick = (i) => {
setClicked(prevState => {
const nextStaet = [...prevState];
nextStaet[i] = !nextStaet[i];
return nextStaet;
});
};
return (
<StyledDiv>
{moods.map((mood, index) => (
<div key={mood.mood}>
<input
type='radio'
name='mood'
id={mood.mood}
onClick={() => handleClick(index)}
/>
<label htmlFor={mood.mood}>
<FontAwesomeIcon
icon={mood.icon}
size='2x'
style={clicked[clicked] ? { color: 'red' } : { color: '#5e5c5a' }}
/>
</label>
</div>
))}
</StyledDiv>
);
};
const StyledDiv = styled.div`
${({ theme }) => {
const { colors } = theme;
return css`
input {
display: none;
}
`;
}}
`;
export default MoodIcons;

How to display list of checkbox in rect-hook-form v7

I have a code like this
const Products = () => {
const [products, setProducts] = useState([{
id: 1,
name: '1 - 10'
}, {
id: 2,
name: '11 - 100'
},
{
id: 3,
name: '101 - 1000'
},
{
id: 4,
name: '>1000'
}
]);
const [productsPicked, setProductsPicked] = useState([
{
id: 1,
name: '1 - 10'
}, {
id: 2,
name: '11 - 100'
}
]);
const { control, register, handleSubmit, getValues, formState: { errors } } = useForm({
mode: 'onSubmit'
});
const complete = (data) => {
console.log(data);
}
return (
<form onSubmit={handleSubmit(complete)}>
{products.map((product, i) => (
<Controller key={i} control={control} name="title" render={({ field }) => (
// i need to checkbox that picked checked by default, and i can update productsPicked here
)} />
))}
</form>
)
}
All i need to do is create a list of checkbox products list. if product in list productsPicked, they default checked and i can update can update productsPicked b,using react-hook-form v7. I am super new to react and doesn't know how to complete. Sorry for my bad english. thank you so much.
try this into the map.
<div className="checkbox">
<label className="select_label">
<input
className="checkbox"
type="checkbox"
/>
{product.name}
</label>
</div>
And this is the css code:
.select_ul {
display: flex;
justify-content: space-between;
}
.checkbox .select_label{
margin: 1px;
}
.checkbox {
display: flex;
}
.select_a{
font-size: 19px;
color: black;
}

Dynamically add a column to react table on button click

I am trying to add a column to the react table using an add column button, but I am a little confused on how to implement this. I want to be able to add a column to the corresponding side that the button is clicked. Do I need to create a custom function and add it to my columns array or is there an easier way to implement this?
Here is the code.
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/no-static-element-interactions */
/* eslint-disable guard-for-in */
/* eslint-disable no-restricted-syntax */
/* eslint-disable react/jsx-props-no-spreading */
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import { useTable } from 'react-table';
import data from '../Data/data.json';
import './Table.css';
const Styles = styled.div`
table {
border-spacing: 0;
border: 1px solid black;
width: 970px;
tr {
:last-child {
td {
border-bottom: 0;
height: 500px;
}
}
}
th,
td {
margin: 0;
padding: 0.5rem;
border-bottom: 1px solid black;
border-right: 1px solid black;
:last-child {
border-right: 0;
}
}
}
`;
const HarveyBall = (initialValue) => {
const [value, setValue] = useState(initialValue);
const onClick = () => {
if(value === 'Empty'){
setValue('Quarter');
}
if(value === 'Quarter'){
setValue('Half');
}
if(value === 'Half'){
setValue('Three-Quarter');
}
if(value === 'Three-Quarter'){
setValue('Full');
}
if(value === 'Full'){
setValue('Empty');
}
};
if(value === "Empty"){
return (
<div type="button" label="Empty" className="harvey none" onClick={onClick} />
);
}
if(value === "Quarter"){
return (
<div type="button" label="Quarter" className="harvey quarters quarter" onClick={onClick} />
);
}
if(value === "Half"){
return (
<div type="button" label="Half" className="harvey quarters half" onClick={onClick} />
);
}
if(value === "Three-Quarter"){
return (
<div type="button" label="Three-Quarter" className="harvey quarters three-quarters" onClick={onClick} />
);
}
if(value === "Full"){
return (
<div type="button" label="Full" className="harvey quarters full" onClick={onClick} />
);
}
return null;
};
const defaultPropGetter = () => ({});
const EditableCell = ({
value: initialValue,
row: { index },
column: { id },
updateMyData,
}) => {
const [value, setValue] = React.useState(initialValue);
const onChange = e => {
setValue(e.target.value);
};
const onBlur = () => {
updateMyData(index, id, value);
};
React.useEffect(() => {
setValue(initialValue);
}, [initialValue]);
return id === "strategicInitiative" || index === 5 ? <textarea value={value} onChange={onChange} onBlur={onBlur} style={{ width: '100%', focus: 'none', outline: 'none', border: 'none',resize: 'none', expand: {height: '1em', width: '50%', padding: '3px'}}}/> : HarveyBall(initialValue);
};
const defaultColumn = {
Cell: EditableCell,
};
function Table({ columns, getHeaderProps = defaultPropGetter, updateMyData, }) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({
columns,
data,
updateMyData,
defaultColumn,
});
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => column.hideHeader === false ? null : (
<th
{...column.getHeaderProps([
{
className: column.className,
style: column.style,
},
getHeaderProps(column),
])}
>
{column.render('Header')}
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row);
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>;
})}
</tr>
);
})}
</tbody>
</table>
);
}
export default function MatrixTable() {
const addTasks = () => {
const taskLength = [];
for(let i = 0; i < data.length; i += 1){
for(const [key] of Object.entries(data[i])){
if(key.includes("T")){
taskLength.push(key[1]);
}
}
}
const newTaskLength = (parseInt(taskLength[taskLength.length - 1], 10) + 1) ;
for(let i = 0; i < data.length; i += 1){
data[i][`T${newTaskLength}`] = "";
}
};
const taskButton = () => (
<>
<div>Tasks</div>
<button onClick={addColumns} type='button'>Add Column</button>
</>
);
const goalButton = () => (
<>
<div>Goals</div>
<button type='button'>Add Column</button>
</>
);
const columns = React.useMemo(
() => [
{
Header: () => taskButton(),
accessor: 'tasks',
style: {
width: '255px',
height: '49px',
background: '#fdf5ed',
fontSize: '16px',
color: '#f2994a',
textAlign: 'center',
lineHeight: '49px',
},
columns: [
{
hideHeader: false,
accessor: 'T1'
},
{
hideHeader: false,
accessor: 'T2'
},
{
hideHeader: false,
accessor: 'T3'
},
{
hideHeader: false,
accessor: 'T4'
},
{
hideHeader: false,
accessor: 'T5'
},
]
},
{
Header: "Strategic Inititiatives",
accessor: "strategicInitiative ",
style: {
color: '#323b3e',
width: '460px',
height: '49px',
background: '#f2f2f2',
textAlign: 'center',
lineHeight: '49px',
},
columns: [
{
hideHeader: false,
accessor: 'strategicInitiative'
}
]
},
{
Header: goalButton(),
accessor: 'goals',
style: {
color: '#56ccf2',
width: '255px',
height: '49px',
background: '#f8fcfe',
textAlign: 'center',
lineHeight: '49px',
},
columns: [
{
hideHeader: false,
accessor: 'G1'
},
{
hideHeader: false,
accessor: 'G2'
},
{
hideHeader: false,
accessor: 'G3'
},
{
hideHeader: false,
accessor: 'G4'
},
{
hideHeader: false,
accessor: 'G5'
}
]
},
],
[]
);
const addColumns = () => {
for(let i = 0; i < columns.length; i += 1) {
if(columns[i].accessor === "tasks"){
console.log(columns[i]);
columns[i].columns.push({
hideHeader: false,
accessor: 'T6'
});
}
}
};
addColumns();
const [, setData] = useState(data);
useEffect(() => {
setData(data);
}, [data]);
const updateMyData = (rowIndex, columnId, value) => {
setData(old =>
old.map((row, index) => {
if (index === rowIndex) {
return {
...old[rowIndex],
[columnId]: value,
};
}
return row;
})
);
};
return (
<Styles>
<Table columns={columns} data={data} updateMyData={updateMyData}/>
</Styles>
);
}
I would imagine that modifying the array columns which stores the data which the table uses to render, would be the correct solution. Once columns is updated, your table should re-render which will then include the updated column.
Yeah, changing columns array(not by mutation, but by setting columns prop to new required array) is the best way to go.

React-select, open sub-menu when hover over an option

I'm trying to build a submenu inside a main menu with React-select, it should be something like this:
When hovering over an option from the main menu, it triggers the submenu to open at the side.
Is there a way to do this using react-select? I couldn't find any example or documentation on this, is there a function like ```optionOnMouseover`` for this? Thank you in advance!
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];
...
<Select
value={...}
onChange={...}
options={options}
/>```
This is on click, but if you need on hover,
just modify it
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Select, { components } from "react-select"
const CustomOption = (props) => {
const [submenu, setSubmenu] = useState(false)
const [height, setHeight] = useState(0)
const handleOption = (e) => {
if(submenu) {
setSubmenu(false)
} else {
setHeight(e.clientY)
setSubmenu(true)
}
}
const handleSubOption = (e) => {
console.log('clicked')
}
const { data } = props;
return data.custom ? (
<>
<div onClick={handleOption} className="customs">
{data.label} <span className="caret"/>
{
submenu && (
<div className="dropdown-submenu">
<div className="drops" onClick={handleSubOption}>
Test dropdown 1
</div>
<div className="drops" onClick={handleSubOption}>
Test dropdown 2
</div>
<div className="drops" onClick={handleSubOption}>
Test dropdown 3
</div>
</div>
)
}
</div>
<style jsx>{`
.customs {
height: 36px;
padding: 8px;
position: relative;
}
.drops {
height: 36px;
padding: 8px;
}
.customs:hover, .drops:hover {
background-color: #17cf76;
}
.dropdown-submenu {
position: fixed;
top: ${height - 10}px;
left: 410px;
min-height: 36px;
overflow: auto;
border: 1px solid hsl(0,0%,80%);
border-radius: 4px;
color: #212529;
}
`}</style>
</>
) : (
<components.Option {...props} />
);
};
const options = [
{ custom: true, label: "I'm a custom link", value: "cust" }
];
function App() {
return (
<>
<Select classNamePrefix="category-select" className="w-30" components={{ Option: CustomOption }} options={options} />
<style jsx global>{`
* {
font-family: sans-serif;
text-align: center;
}
.w-30 {
width: 30% !important;
}
`}</style>
</>
)
}
export default App

Resources