I am creating a social media project using React on Rails, I have a NavBar component that handles the routing for each link, there is a link called Ventbox, which is similar to a Twitter's Tweetbox, how can I change my code so that instead of taking the user to a new page with the endpoint of '/vent', the Ventbox would just pop up wherever the user is on the Page, still with the endpoint of '/vent'?
This is my NavBar component so far:
import React from 'react'
import { NavLink } from "react-router-dom"
import { navData } from "./navData.js";
import styles from "./styles/navbar.module.css"
import { useState } from "react";
import KeyboardDoubleArrowRightIcon from '#mui/icons-material/KeyboardDoubleArrowRight';
import KeyboardDoubleArrowLeftIcon from '#mui/icons-material/KeyboardDoubleArrowLeft';
import Ventbox from './Ventbox'
import CreateIcon from '#mui/icons-material/Create';
export default function NavBar() {
const [open, setopen] = useState(false)
const toggleOpen = () => {
setopen(!open)
}
return (
<div className={open?styles.sidenav:styles.sidenavClosed}>
<button className={styles.menuBtn} onClick={toggleOpen}>
{open? <KeyboardDoubleArrowLeftIcon />: <KeyboardDoubleArrowRightIcon />}
</button>
{navData.map(item =>{
return <NavLink key={item.id} className={styles.sideitem} to={item.link}>
{item.icon}
<span className={styles.linkText}>{item.text}</span>
</NavLink>
})}
<NavLink key={'ventbox'} className={styles.sideitem} to="/vent">
<CreateIcon />
<Ventbox to="/vent" style={styles.linkText} />
</NavLink>
</div>
)
}
And this is my Ventbox component:
import React, { useState } from "react";
import './styles/Ventbox.css'
import {useNavigate} from 'react-router-dom'
function Ventbox({style}) {
const [popup,setPop] = useState(false);
const [content, setContent] = useState("");
const [textLimit, setTextLimit] = useState(250);
const handleClickOpen = () => {
setPop(!popup);
}
const closePopup = () => {
setPop(false);
}
const handleChange = e => {
setContent(e.target.value);
setTextLimit(250 - e.target.value.length);
}
const handleSubmit = async e => {
e.preventDefault();
if (content.length > 250) {
alert("Text limit reached");
} else {
try {
const response = await fetch(`/posts`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ content: content })
});
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
}
return(
<div>
<span onClick={handleClickOpen} className={style}>Vent</span>
<div>
{
popup?
<div className="main">
<div className="popup">
<div className="popup-header">
<h1>What's on your mind?</h1>
<button className="delete-button" onClick={closePopup}>X</button>
</div>
<div>
<form onSubmit={handleSubmit}>
<input className="textbox" placeholder="Enter text here"
value={content}
onChange={handleChange}
maxLength={250}
/>
<p>Characters remaining: {textLimit}</p>
<button className="post-button"type="submit">Post</button>
</form>
</div>
</div>
</div>:""
}
</div>
</div>
)
}
export default Ventbox;
And this is my navData component, where I got the Icons from material ui, and the routes:
import HomeIcon from '#mui/icons-material/Home';
import InfoIcon from '#mui/icons-material/Info';
import MenuBookIcon from '#mui/icons-material/MenuBook';
import AccountCircleIcon from '#mui/icons-material/AccountCircle';
import HowToRegIcon from '#mui/icons-material/HowToReg';
import VerifiedUserIcon from '#mui/icons-material/VerifiedUser';
import SendIcon from '#mui/icons-material/Send';
import NotificationsIcon from '#mui/icons-material/Notifications';
import CreateIcon from '#mui/icons-material/Create';
import Ventbox from './Ventbox'
import Popup from 'reactjs-popup'
import {useState} from 'react'
export const navData = [
{
id: 0,
icon: <HomeIcon/>,
text: "Home",
link: "/"
},
{
id: 1,
icon: <AccountCircleIcon/>,
text: "Profile",
link: "/profile"
},
{
id: 2,
icon: <SendIcon/>,
text: "Messages",
link: "/messages"
},
{
id: 3,
icon: <NotificationsIcon/>,
text: "Notifications",
link: "/notifications"
},
{
id: 5,
icon: <HowToRegIcon/>,
text: "Signup/Login",
link: "/signin"
},
]
Any help is greatly appreciated!!
I had tried everything, but am completely stuck :(
Since you are using mui, maybe you can try to wrap your component in a Modal.
https://mui.com/material-ui/react-modal/
<CreateIcon onClick={handleOpen}/>
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Ventbox style={styles.linkText} />
</Modal>
Related
The point is to implement a dynamic SSR component can be re-rendered by a search input.
I solved this by creating a layout.tsx file on my specific router then import children which made me dynamic render ssr component by the client component:
Layout.tsx
import React, { Suspense } from "react";
import Search from "./Search";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="layout">
<Search />
{children}
</div>
);
}
Search.tsx
"use client";
import { FormEvent, useState } from "react";
import { useRouter } from "next/navigation";
export default function Search() {
const [text, setText] = useState<string>("")
const router: any = useRouter();
const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
setText('')
router.push(`/definition/${text}`)
}
return (
<form onSubmit={handleSubmit} className='search'>
<input onChange={(e) => setText(e.target.value)}
value={text} type="text"
placeholder={"write to search"} />
</form>
);
} );
}
I'm new to React Typerscript, and I'm trying to figure out how to pass useModal function from RsvpPage to EventDescriptionPage.
`
import Modal from "./Modal";
import useModal from "./UseModal";
class EventDescriptionPage extends Component<any,any> {
constructor(props:any){
super(props);
}
render(){
return (
<div onClick={this.props.useModal}>
<button className='button' onClick={this.props.toggle}> RSVP </button>
<Modal isOpen={this.props.isOpen} toggle={this.props.toggle}></Modal>
</div>
</header>
</div>
);
}
}
export default EventDescriptionPage;
`
`
import EventDescriptionPage from "./EventDescriptionPage";
import Modal from "./Modal";
import useModal from "./UseModal";
function RsvpPage(){
const { isOpen, toggle } = useModal();
return (
<div>
<EventDescriptionPage/>
</div>
);
}
export default RsvpPage;
`
`
import { useState } from "react";
export default function UseModal() {
const [isOpen, setisOpen] = useState(false);
const toggle = () => {
setisOpen(!isOpen);
};
return {
isOpen,
toggle
};
}
`
`
import React, { ReactNode } from "react";
import "./Modal.css";
interface ModalType {
children?: ReactNode;
isOpen: boolean;
toggle: () => void;
}
export default function Modal(props: ModalType) {
return (
<>
{props.isOpen && (
<div className="modal-overlay" onClick={props.toggle}>
<div onClick={(e) => e.stopPropagation()} className="modal-box">
{props.children}Abaabaabaaba
</div>
</div>
)}
</>
);
}
`
I think my syntax is not right, but I'm not sure how to access useModal() function in RsvpPage.esx file.
To demonstrate a component I try to write custom state and methods for a story.
For example, I have a component ListItems who accepts an array of string as Input.
In the story of this component I want to show an interactive example of the usage of this component.
So my story will have internal state "items" and internal method "addItem"
I know how to do that with React, but I'm stuck with Angular.
Here is a React way to do that:
(View in codesandbox)
// ListItems.tsx
import React from "react";
export type ListItemsProps = { items: string[] };
export const ListItems = ({ items = [] }: ListItemsProps) => {
return (
<ul>
{items.map((item, key) => (
<li key={key}>{item}</li>
))}
</ul>
);
};
// ListItems.stories.tsx
import React, { useState } from "react";
import { ListItems } from "./ListItems";
export default {
title: "ListItems",
component: ListItems
};
export const Text = () => {
const [items, setItems] = useState(["Demo Item"]);
const [value, setValue] = useState("");
const addItem = () => {
setItems([...items, value]);
setValue("");
};
return (
<div>
<ListItems items={items} />
<input value={value} onChange={(e) => setValue(e.target.value)} />
<input type="submit" onClick={addItem} value="add" />
</div>
);
};
};
How can I write the same story with following Angular Component ?
import { Component, OnInit, Input } from "#angular/core";
#Component({
selector: "app-list-items",
template: `<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>`
})
export default class ListItems implements OnInit {
#Input() items: string[] = [];
constructor(){}
ngOnInit(): void {}
}
Finally I found a solution on Angular, but it's not an elegant one...
Maybe someone know a better way !
And I can't find a solution to show the code story template on "Show code" feature.
import { Story, Meta } from '#storybook/angular/types-6-0';
import { ListItemsComponent } from './list-items.component';
import { Component } from '#angular/core';
export default {
title: 'Demo/ListItems',
component: ListItemsComponent,
} as Meta;
const Template: Story<ListItemsComponent> = (args: ListItemsComponent) => ({
props:args,
});
export const BasicDemo = Template.bind({})
BasicDemo.args={
items: ["Basic Demo", "Without interaction"]
}
// Create a dedicated component for the interactive story
#Component({
selector: 'story-list-items',
template: `
<core-list-items [items]="items"></core-list-items>
<input type="text" [(ngModel)]="value" /><button (click)="addItem()">add</button>
`,
})
class InteractiveDemoComponent{
items = [];
value: string = '';
addItem(){
this.items = [...this.items, this.value];
this.value = ""
}
}
const InteractiveTemplate: Story<ListItemsComponent> = (args: ListItemsComponent) => ({
props:args,
component: InteractiveDemoComponent,
});
export const InteractiveDemo = InteractiveTemplate.bind({});
InteractiveDemo.args = {
items: ["Interactive Demo"]
}
I´m looking for way to load static texts into storybook via next-translate.
My code looks like this, but it´s loading my locale files, but not writing them properly.
This is storybook preview.js:
import '../src/styles/global/global.scss';
import CssBaseline from '#material-ui/core/CssBaseline';
import { ThemeProvider } from '#material-ui/core/styles';
import theme from '../src/utils/theme';
import I18nProvider from 'next-translate/I18nProvider';
import commonCS from '../locales/cs/common.json';
export const decorators = [(Story) => themeDecorator(Story)];
const themeDecorator = (Story) => {
console.log(commonCS.homepage_title);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<I18nProvider lang={'cs-CS'} namespaces={{ commonCS }}>
<Story />
</I18nProvider>
</ThemeProvider>
);
};
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: { expanded: true },
};
And this is my storybook storie:
import React from 'react';
import HeaderContact from './HeaderContact';
import I18nProvider from 'next-translate/I18nProvider';
import useTranslation from 'next-translate/useTranslation';
import commonCS from '../../../locales/cs/common.json';
export default {
title: 'HeaderContact',
component: HeaderContact,
};
export const Basic = () => {
const { t } = useTranslation('common');
return (
<HeaderContact
link="mailto:info#numisdeal.com"
text={t('homepage_title')}
/>
);
};
My local file common.json:
{
"homepage_title": "Blog in Next.js",
"homepage_description": "This example shows a multilingual blog built in Next.js with next-translate"
}
And my translate config i18n.json
{
"locales": ["cs", "en", "de"],
"defaultLocale": "cs",
"pages": {
"*": ["common"]
}
}
I would be very glad for some help.
Thanks!
Roman
Here is the solution.
preview.js
import '../src/styles/global/global.scss';
import CssBaseline from '#material-ui/core/CssBaseline';
import { ThemeProvider } from '#material-ui/core/styles';
import theme from '../src/utils/theme';
import I18nProvider from 'next-translate/I18nProvider';
import commonCS from '../locales/cs/common.json';
export const decorators = [(Story) => themeDecorator(Story)];
const themeDecorator = (Story) => {
console.log(commonCS.homepage_title);
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<I18nProvider lang={'cs'} namespaces={{ common: commonCS }}>
<Story />
</I18nProvider>
</ThemeProvider>
);
};
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: { expanded: true },
};
Storie:
import React from 'react';
import HeaderContact from './HeaderContact';
export default {
title: 'HeaderContact',
component: HeaderContact,
};
export const Basic = () => {
return <HeaderContact link="mailto:info#numisdeal.com" />;
};
Component:
import React from 'react';
import AlternateEmailIcon from '#material-ui/icons/AlternateEmail';
import useTranslation from 'next-translate/useTranslation';
import styles from './HeaderContact.module.scss';
export interface IHeaderContact {
link: string;
text?: string;
}
export default function HeaderContact(props: IHeaderContact) {
const { link, text } = props;
const { t } = useTranslation('common');
const preklad = t('homepage_title');
return (
<a href={link} className={styles.headerLink}>
<AlternateEmailIcon fontSize="small" />
<span>
{/* {text} */}
{preklad}
</span>
</a>
);
}
I'm trying to handle simple input value using react-redux and then trying to display it. I know how to display it but i have no idea how to submit input value from component to redux store. I searched web and found nothing. Can someone explain how to do this? I'm totally new to react-redux
import React from "react";
import "./App.css";
import { connect } from "react-redux";
import { useState } from "react";
import { updateValue, addValue } from "./actions/inputActions";
function App(props) {
const [value, setValue] = useState("");
const handleChange = (e) => {
setValue(e.target.value);
};
return (
<div className="App">
<form onSubmit={(value) => props.submitValue(value)}>
<input onChange={handleChange} value={value} type="text" />
<button type="submit">Add</button>
</form>
<h1>{props.value}</h1>
</div>
);
}
const mapStateToProps = (state) => {
return {
value: state.value,
};
};
const mapDispatchToProps = (dispatch) => {
return {
submitValue: (e, value) => {
e.preventDefault();
dispatch(addValue(value));
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
Update your onSubmit function with the value stored in your local state, like this:
<form onSubmit={(e) => {
e.preventDefault();
props.submitValue(value)
}}>
<input onChange={handleChange} value={value} type="text" />
<button type="submit">Add</button>
</form>
And your mapDispatchToProps function like this:
const mapDispatchToProps = (dispatch) => {
return {
submitValue: (value) => {
dispatch(addValue(value));
},
};
};