routing and fetching data
This commit is contained in:
57
frontend_reactjs/package-lock.json
generated
57
frontend_reactjs/package-lock.json
generated
@ -12,7 +12,9 @@
|
||||
"axios": "^1.7.2",
|
||||
"postcss": "^8.4.38",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.51.5",
|
||||
"react-router-dom": "^6.23.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.66",
|
||||
@ -680,6 +682,14 @@
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz",
|
||||
"integrity": "sha512-es2g3dq6Nb07iFxGk5GuHN20RwBZOsuDQN7izWIisUcv9r+d2C5jQxqmgkdebXgReWfiyUabcki6Fg77mSNrig==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz",
|
||||
@ -3158,6 +3168,51 @@
|
||||
"react": "^18.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-hook-form": {
|
||||
"version": "7.51.5",
|
||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.51.5.tgz",
|
||||
"integrity": "sha512-J2ILT5gWx1XUIJRETiA7M19iXHlG74+6O3KApzvqB/w8S5NQR7AbU8HVZrMALdmDgWpRPYiZJl0zx8Z4L2mP6Q==",
|
||||
"engines": {
|
||||
"node": ">=12.22.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/react-hook-form"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "6.23.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.23.1.tgz",
|
||||
"integrity": "sha512-fzcOaRF69uvqbbM7OhvQyBTFDVrrGlsFdS3AL+1KfIBtGETibHzi3FkoTRyiDJnWNc2VxrfvR+657ROHjaNjqQ==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.16.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "6.23.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.23.1.tgz",
|
||||
"integrity": "sha512-utP+K+aSTtEdbWpC+4gxhdlPFwuEfDKq8ZrPFU65bbRJY+l706qjR7yaidBpo3MSeA/fzwbXWbKBI6ftOnP3OQ==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.16.1",
|
||||
"react-router": "6.23.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/read-cache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
|
@ -14,7 +14,9 @@
|
||||
"axios": "^1.7.2",
|
||||
"postcss": "^8.4.38",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.51.5",
|
||||
"react-router-dom": "^6.23.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.66",
|
||||
|
@ -1,24 +1,22 @@
|
||||
import { useState,useEffect } from 'react'
|
||||
import Card from './components/Card'
|
||||
import axios from 'axios'
|
||||
interface ICard{
|
||||
firstname: string
|
||||
lastname: string
|
||||
email: string
|
||||
}
|
||||
import { BrowserRouter as Router, Routes,Route} from "react-router-dom"
|
||||
import Users from "./pages/Users"
|
||||
import Roles from "./pages/Roles"
|
||||
import Main from "./pages/Main"
|
||||
import NotFound from "./pages/NotFound"
|
||||
import Navigate from "./components/Navigate"
|
||||
|
||||
function App() {
|
||||
// const data = [
|
||||
// {firstname:"Иван",lastname:"Петров", email:"email@test.ru"},
|
||||
// {firstname:"Алексей",lastname:"Петров", email:"email2@test.ru"},
|
||||
// {firstname:"Василиса",lastname:"Петрова", email:"email3@test.ru"}
|
||||
// ]
|
||||
const [cards, setCards] = useState<ICard[]>([]);
|
||||
useEffect(()=>{axios.get("http://localhost:8000/auth/user/").then((res) =>{setCards(res.data as ICard[]);})},[])
|
||||
console.log(cards)
|
||||
return (
|
||||
<>
|
||||
{cards.map((card, index) => <Card key={index} {...card}/>)}
|
||||
<Navigate />
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route index path="/" element={ <Main />} />
|
||||
<Route path="/user" element={ <Users />} />
|
||||
<Route path="/role" element={ <Roles />} />
|
||||
<Route path="*" element={<NotFound />}/>
|
||||
</Routes>
|
||||
</Router>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
20
frontend_reactjs/src/components/FetchingData.ts
Normal file
20
frontend_reactjs/src/components/FetchingData.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
export function useDataFetching<T> (url:string, initData:T):T{
|
||||
const [data, setData] = useState<T>(initData);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
const response = await fetch(url);
|
||||
const result = await response.json();
|
||||
setData(result);
|
||||
};
|
||||
|
||||
fetchData();
|
||||
}, [url]);
|
||||
console.log(data)
|
||||
// Memoize the data value
|
||||
const memoizedData = useMemo<T>(() => data, [data]);
|
||||
return memoizedData;
|
||||
};
|
||||
|
||||
export default useDataFetching;
|
57
frontend_reactjs/src/components/Modal.tsx
Normal file
57
frontend_reactjs/src/components/Modal.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
export interface Props {
|
||||
showModal: boolean;
|
||||
}
|
||||
|
||||
export default function Modal(props:Props){
|
||||
return(<>
|
||||
{props.showModal &&
|
||||
<div id="crud-modal" tabIndex={-1} className="bg-black opacity-75 overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full" onClick={()=> console.log("click")}>
|
||||
<div className="relative p-4 w-full max-w-md max-h-full" >
|
||||
<div className="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
||||
<div className="flex items-center justify-between p-4 md:p-5 border-b rounded-t dark:border-gray-600">
|
||||
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
Create New Product
|
||||
</h3>
|
||||
<button type="button" className="text-gray-400 bg-transparent hover:bg-gray-200 hover:text-gray-900 rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:hover:bg-gray-600 dark:hover:text-white" data-modal-toggle="crud-modal">
|
||||
<svg className="w-3 h-3" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
|
||||
<path stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6"/>
|
||||
</svg>
|
||||
<span className="sr-only">Close modal</span>
|
||||
</button>
|
||||
</div>
|
||||
<form className="p-4 md:p-5">
|
||||
<div className="grid gap-4 mb-4 grid-cols-2">
|
||||
<div className="col-span-2">
|
||||
<label className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Name</label>
|
||||
<input type="text" name="name" id="name" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500" placeholder="Type product name" />
|
||||
</div>
|
||||
<div className="col-span-2 sm:col-span-1">
|
||||
<label className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Price</label>
|
||||
<input type="number" name="price" id="price" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-600 focus:border-primary-600 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500" placeholder="$2999" />
|
||||
</div>
|
||||
<div className="col-span-2 sm:col-span-1">
|
||||
<label className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Category</label>
|
||||
<select id="category" className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500">
|
||||
<option >Select category</option>
|
||||
<option value="TV">TV/Monitors</option>
|
||||
<option value="PC">PC</option>
|
||||
<option value="GA">Gaming/Console</option>
|
||||
<option value="PH">Phones</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<label className="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Product Description</label>
|
||||
<textarea id="description" rows={4} className="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-600 dark:border-gray-500 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="Write product description here"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" className="text-white inline-flex items-center bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800">
|
||||
<svg className="me-1 -ms-1 w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fillRule="evenodd" d="M10 5a1 1 0 011 1v3h3a1 1 0 110 2h-3v3a1 1 0 11-2 0v-3H6a1 1 0 110-2h3V6a1 1 0 011-1z" clipRule="evenodd"></path></svg>
|
||||
Add new product
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div> }
|
||||
|
||||
</>)
|
||||
}
|
21
frontend_reactjs/src/components/Navigate.tsx
Normal file
21
frontend_reactjs/src/components/Navigate.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
export default function Navigate(){
|
||||
return(
|
||||
<>
|
||||
<nav className="bg-white border-gray-200 dark:bg-gray-900">
|
||||
<div className="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4">
|
||||
<ul className="font-medium flex flex-col p-4 md:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700">
|
||||
<li>
|
||||
<a href="/" className="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Главная</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/user" className="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Пользователи</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/role" className="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Роли</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
</>
|
||||
)
|
||||
}
|
19
frontend_reactjs/src/components/RoleCard.tsx
Normal file
19
frontend_reactjs/src/components/RoleCard.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
|
||||
interface IRoleCard{
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
|
||||
function RoleCard(props:IRoleCard) {
|
||||
const [curr_card, setCard] = useState<IRoleCard>({id: 1, name: "Тест"});
|
||||
useEffect(()=>{setCard(props);},[curr_card])
|
||||
return (
|
||||
<div className='block p-6 max-w-sm bg-gray-300
|
||||
rounded-lg border border-gray-500 align-items: center;'>
|
||||
<div className='text-4xl text-center'>{curr_card.name}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RoleCard
|
3
frontend_reactjs/src/pages/Main.tsx
Normal file
3
frontend_reactjs/src/pages/Main.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
export default function Main (){
|
||||
return ( <><h1>Main page</h1></>)
|
||||
}
|
3
frontend_reactjs/src/pages/NotFound.tsx
Normal file
3
frontend_reactjs/src/pages/NotFound.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
export default function NotFound (){
|
||||
return ( <><h1>Page not found</h1></>)
|
||||
}
|
26
frontend_reactjs/src/pages/Roles.tsx
Normal file
26
frontend_reactjs/src/pages/Roles.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { useState} from 'react'
|
||||
import RoleCard from '../components/RoleCard'
|
||||
import Modal from '../components/Modal'
|
||||
import useDataFetching from '../components/FetchingData'
|
||||
|
||||
interface IRoleCard{
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
interface Props {
|
||||
showModal: boolean;
|
||||
}
|
||||
function Users() {
|
||||
const [showModal, setShowModal] = useState<Props>({showModal: false});
|
||||
const cards = useDataFetching<IRoleCard[]>("http://localhost:8000/auth/role/",[])
|
||||
|
||||
return (
|
||||
<div>
|
||||
{cards.map((card, index) => <RoleCard key={index} {...card}/>)}
|
||||
<button className='absolute w-0 h-0' onClick={() => setShowModal({showModal:true})}>+</button>
|
||||
<Modal {...showModal}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Users
|
18
frontend_reactjs/src/pages/Users.tsx
Normal file
18
frontend_reactjs/src/pages/Users.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import Card from '../components/Card'
|
||||
import useDataFetching from '../components/FetchingData'
|
||||
interface ICard{
|
||||
firstname: string
|
||||
lastname: string
|
||||
email: string
|
||||
}
|
||||
|
||||
function Users() {
|
||||
const cards= useDataFetching<ICard[]>("http://localhost:8000/auth/user/",[])
|
||||
return (
|
||||
<div>
|
||||
{cards.map((card, index) => <Card key={index} {...card}/>)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Users
|
1734
frontend_reactjs/yarn.lock
Normal file
1734
frontend_reactjs/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user