Below is my page.tsx
import Aspects from '@/components/Aspects';
import FreeForm from '@/components/FreeForm';
import Lesson from '@/components/Lesson';
import React from 'react';
import { Route, Routes } from 'react-router-dom';
const Home: React.FC = () => {
return (
<div>
<Routes>
<Route path="/" element={<Aspects />} />
<Route path="/freeform" element={<FreeForm />} />
<Route path="/lesson" element={<Lesson />} />
</Routes>
</div>
);
};
export default Home;
And I just copied my react js using javascript coding to next js typescript, and here is the code for Aspects.tsx, FreeForm.tsx and Lesson.tsx Aspects.tsx
import './Aspects.css';
import IMG1 from '../stories/assets/Picts/10.jpg';
import IMG2 from '../stories/assets/Picts/9.jpg';
import IMG3 from '../stories/assets/Picts/8.jpg';
import React, { useState, } from 'react';
import { useNavigate } from 'react-router-dom';
import { notification } from 'antd';
import { SmileOutlined } from '@ant-design/icons';
import Image from 'next/image';
// import { useRouter } from 'next/router';
function Aspects() {
const navigate = useNavigate();
const [check, setcheck] = useState('');
const [isClosed, setIsClosed] = useState(false);
const handleClick = () => {
if (!check || !document.querySelector('input[name="choosingMethod"]:checked')) {
notification.open({
message: 'Heii learner!',
description: 'You must choose both the Aspect Ratio and Content Creation Method first',
icon: <SmileOutlined />,
});
} else {
navigate('/freeform');
}
};
const handleClose = () => {
setIsClosed(true);
};
if (isClosed) {
return null;
}
return (
<div className="container-ratio">
<div className="container-title">
<h3>How you want to process your course?</h3>
<p>Please select the ratio and method of content creation</p>
<button type="button" className="btn-close" aria-label="Close" onClick={handleClose}></button>
</div>
<h2>Aspec Ratio</h2>
<div className="container-card">
<div className="card">
<Image src={IMG1} className="card-img-top" alt="..." />
<div className="card-body" >
<h3>Free Form</h3>
<p className="card-text">Modern formats keep your content connected and fluid.</p>
</div>
</div>
<div className="card">
<Image src={IMG2} className="card-img-top" alt="..." />
<div className="card-body">
<h3>16: 9</h3>
<p className="card-text">Modern formats help keep your content connected and consistent.</p>
</div>
</div>
<div className="card">
<Image src={IMG3} className="card-img-top" alt="..." />
<div className="card-body">
<h3>9:16</h3>
<p className="card-text">Suitable for modern contents, micro-courses, and social media, especially Tiktok, Reels..</p>
</div>
</div>
</div>
<div className="container-method">
<h3>Content Creation Method</h3>
<div className="row">
<div className="card">
<label htmlFor="autoOption">
<div className="card-body d-flex align-items-center">
<input type="radio" id='autoOption' name="choosingMethod" value="automatic" />
<div className="text">
<h5 className="card-title">Automaticly</h5>
<p className="card-text">AI will generate the course based on your outline.</p>
</div>
</div>
</label>
</div>
<div className="card">
<label htmlFor="manualOpt">
<div className="card-body d-flex align-items-center">
<input type="radio" id="manualOpt" name="choosingMethod" value="manual" className="me-3" />
<div>
<h5 className="card-title">Manually</h5>
<p className="card-text">...</p>
</div>
</div>
</label>
</div>
</div>
</div>
<div className="d-flex justify-content-center align-items-center mt-4">
<button type="button" className="btn btn-success" onClick={handleClick}>Next</button>
</div>
</div>
)
}
export default Aspects
FreeForm.tsx
code from my react js, it was FreeForm.js but I convert it using .tsx
when I pasted it in the next.js typescript.
import React from 'react';
import './FreeForm.css';
import IMG1 from '../stories/assets/Picts/10.jpg';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { notification } from 'antd';
import { SmileOutlined } from '@ant-design/icons';
import Image from 'next/image';
import { useRouter } from 'next/router';
function FreeForm() {
const toVideo = useRouter();
const toAspects = useRouter();
const [choice, setChoice] = useState('');
const [closed, setClosed]= useState(false);
const handleCloseBtn = () => {
setClosed(true);
}
if(closed) { return null}
const handleClick = () => {
if (!choice) {
notification.open({
message: 'Heii learner',
description: 'You must choose the template before go to the next step',
icon: <SmileOutlined/>,
});
} else {
toVideo.push('/video');
}
};
return (
<div className="container-ratio">
<div className="container-title">
<h3>Select a template</h3>
<p>Here is the templates that support Free form</p>
<button type="button" className="btn-close" aria-label="Close" onClick={handleCloseBtn}></button>
</div>
<div className="row container-baru">
<div className="col-md-4 mb-3">
<div className="card" >
<div className="card-body">
<Image src={IMG1} className="card-img-top" alt="..."/>
<h5 className="card-title">Card 1</h5>
</div>
</div>
</div>
<div className="col-md-4 mb-3">
<div className="card" >
<div className="card-body">
<Image src={IMG1} className="card-img-top" alt="..."/>
<h5 className="card-title">Card 1</h5>
</div>
</div>
</div>
<div className="col-md-4 mb-3">
<div className="card" >
<div className="card-body">
<Image src={IMG1} className="card-img-top" alt="..."/>
<h5 className="card-title">Card 1</h5>
</div>
</div>
</div>
<div className="col-md-4 mb-3">
<div className="card" >
<div className="card-body">
<Image src={IMG1} className="card-img-top" alt="..."/>
<h5 className="card-title">Card 1</h5>
</div>
</div>
</div>
<div className="col-md-4 mb-3">
<div className="card" >
<div className="card-body">
<Image src={IMG1} className="card-img-top" alt="..."/>
<h5 className="card-title">Card 1</h5>
</div>
</div>
</div>
<div className="col-md-4 mb-3">
<div className="card">
<div className="card-body">
<Image src={IMG1} className="card-img-top" alt="..."/>
<h5 className="card-title">Card 1</h5>
</div>
</div>
</div>
<div className="col-md-4 mb-3">
<div className="card" >
<div className="card-body">
<Image src={IMG1} className="card-img-top" alt="..."/>
<h5 className="card-title">Card 1</h5>
</div>
</div>
</div>
<div className="col-md-4 mb-3">
<div className="card">
<div className="card-body">
<Image src={IMG1} className="card-img-top" alt="..."/>
<h5 className="card-title">Card 2</h5>
</div>
</div>
</div>
<div className="col-md-4 mb-3">
<div className="card">
<div className="card-body">
<Image src={IMG1} className="card-img-top" alt="..."/>
<h5 className="card-title">Card 3</h5>
</div>
</div>
</div>
</div>
<div className="make-buttons-center">
<div className="container-buttons">
<button type="button" className="btn tombol-kembali btn-light" onClick={() => toAspects.push("/")}>
Back
</button>
<button type="button" className="btn tombol-generate btn-success" onClick={handleClick}>
Generate Now
</button>
</div>
</div>
</div>
)
}
export default FreeForm
And the last one is lesson.tsx, the code is below:
import Next from 'next';
import { Rate, Space } from 'antd';
import { useRouter } from 'next/router';
function Lesson() {
const [close, isClosed] = useState(false);
const back = useRouter();
const handleClose = () => {
isClosed(true);
};
return (
<div className='container-video'>
<div className="container-title">
<h3>Lesson 1</h3>
<p>Please watch the video till the end!</p>
<button type="button" className="btn-close" aria-label="Close" onClick={handleClose}></button>
</div>
<div className="embed-responsive embed-responsive-16by9">
<iframe className="embed-responsive-item" src="https://www.youtube.com/embed/zpOULjyy-n8?rel=0" title='video percobaan'></iframe>
</div>
<div className='overview'>
<div className="card">
<div className="card-body">
<h5 className="card-title">Course Overview</h5>
<p className="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.
Some quick example text to build on the card title and make up the bulk of the card's content.</p>
</div>
</div>
<div className="card">
<div className="card-body">
<Space direction='vertical'>
<h5 className="card-title">How you rate this lesson?</h5>
<Rate defaultValue={4} allowHalf tooltips={["Bad", "Not Really Good", "Good", "Comfort", "Best Lesson!"]}/>
</Space>
</div>
</div>
<div className="container-button d-flex justify-content-between">
<button type="button" className="btn btn-dark" onClick={() => back.push('/freeform')}>Back Button</button>
<button type="button" className="btn btn-warning" onClick={() => handleClose}>Next Lesson</button>
</div>
</div>
</div>
);
}
export default Lesson;`
So I face two error actually, first one was saying that the Lesson in page.tsx cannot be used as JSX component, and the second one is
Error: useRoutes() may be used only in the context of a <Router> component.
Call Stack
invariant
node_modules\.pnpm\@remix-run+router@1.7.2\node_modules\@remix-run\router\dist\router.js (232:0)
useRoutesImpl
node_modules\.pnpm\react-router@6.14.2_react@18.2.0\node_modules\react-router\dist\index.js (322:82)
useRoutes
node_modules\.pnpm\react-router@6.14.2_react@18.2.0\node_modules\react-router\dist\index.js (317:0)
Routes
node_modules\.pnpm\react-router@6.14.2_react@18.2.0\node_modules\react-router\dist\index.js (1128:0)
renderWithHooks
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (10649:0)
mountIndeterminateComponent
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (15743:0)
beginWork$1
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (17318:0)
beginWork
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (25672:0)
performUnitOfWork
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (24523:0)
workLoopSync
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (24239:0)
renderRootSync
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (24204:0)
recoverFromConcurrentError
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (23450:0)
performConcurrentWorkOnRoot
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\react-dom\cjs\react-dom.development.js (23356:0)
workLoop
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\scheduler\cjs\scheduler.development.js (261:0)
flushWork
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\scheduler\cjs\scheduler.development.js (230:0)
MessagePort.performWorkUntilDeadline
node_modules\.pnpm\next@13.4.8_@babel+core@7.22.9_react-dom@18.2.0_react@18.2.0\node_modules\next\dist\compiled\scheduler\cjs\scheduler.development.js (537:0)
How to solve this? I want to render the Aspects.Tsx, FreeForm.tsx, and also Lesson.tsx in the page.tsx, but it gives me this error. And if I changed the page.tsx to
Const Home: React.FC = () => {
return (
<main className="min-h-screen">
<div>
<h1 className="text-[54px] text-blue-800">Hallo bro gua capek</h1>
</div>
</main>
)
}
it gives the dsiplay "Hallo bro gua capek", but when I tried to render another page it does not work.
It's solved, I need to wrap it inside the < Browser Router>
and it works fine. So do what comes inside your mind, cause I think this before but thinking too much than not doing what I was thinking the solution is.