Browse Source

routing and fetching data

master
VinokurovVE 12 months ago
parent
commit
08c090d7f2
  1. 57
      frontend_reactjs/package-lock.json
  2. 4
      frontend_reactjs/package.json
  3. 32
      frontend_reactjs/src/App.tsx
  4. 20
      frontend_reactjs/src/components/FetchingData.ts
  5. 57
      frontend_reactjs/src/components/Modal.tsx
  6. 21
      frontend_reactjs/src/components/Navigate.tsx
  7. 19
      frontend_reactjs/src/components/RoleCard.tsx
  8. 3
      frontend_reactjs/src/pages/Main.tsx
  9. 3
      frontend_reactjs/src/pages/NotFound.tsx
  10. 26
      frontend_reactjs/src/pages/Roles.tsx
  11. 18
      frontend_reactjs/src/pages/Users.tsx
  12. 1734
      frontend_reactjs/yarn.lock

57
frontend_reactjs/package-lock.json

@ -12,7 +12,9 @@
"axios": "^1.7.2", "axios": "^1.7.2",
"postcss": "^8.4.38", "postcss": "^8.4.38",
"react": "^18.2.0", "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": { "devDependencies": {
"@types/react": "^18.2.66", "@types/react": "^18.2.66",
@ -680,6 +682,14 @@
"node": ">=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": { "node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.18.0", "version": "4.18.0",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", "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" "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": { "node_modules/read-cache": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",

4
frontend_reactjs/package.json

@ -14,7 +14,9 @@
"axios": "^1.7.2", "axios": "^1.7.2",
"postcss": "^8.4.38", "postcss": "^8.4.38",
"react": "^18.2.0", "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": { "devDependencies": {
"@types/react": "^18.2.66", "@types/react": "^18.2.66",

32
frontend_reactjs/src/App.tsx

@ -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() { 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 ( 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

@ -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

@ -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

@ -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

@ -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

@ -0,0 +1,3 @@
export default function Main (){
return ( <><h1>Main page</h1></>)
}

3
frontend_reactjs/src/pages/NotFound.tsx

@ -0,0 +1,3 @@
export default function NotFound (){
return ( <><h1>Page not found</h1></>)
}

26
frontend_reactjs/src/pages/Roles.tsx

@ -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

@ -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
File diff suppressed because it is too large
View File

Loading…
Cancel
Save