12 changed files with 1976 additions and 20 deletions
-
57frontend_reactjs/package-lock.json
-
4frontend_reactjs/package.json
-
32frontend_reactjs/src/App.tsx
-
20frontend_reactjs/src/components/FetchingData.ts
-
57frontend_reactjs/src/components/Modal.tsx
-
21frontend_reactjs/src/components/Navigate.tsx
-
19frontend_reactjs/src/components/RoleCard.tsx
-
3frontend_reactjs/src/pages/Main.tsx
-
3frontend_reactjs/src/pages/NotFound.tsx
-
26frontend_reactjs/src/pages/Roles.tsx
-
18frontend_reactjs/src/pages/Users.tsx
-
1734frontend_reactjs/yarn.lock
@ -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> |
||||
</> |
</> |
||||
) |
) |
||||
} |
} |
||||
|
@ -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; |
@ -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> } |
||||
|
|
||||
|
</>) |
||||
|
} |
@ -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> |
||||
|
</> |
||||
|
) |
||||
|
} |
@ -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 |
@ -0,0 +1,3 @@ |
|||||
|
export default function Main (){ |
||||
|
return ( <><h1>Main page</h1></>) |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
export default function NotFound (){ |
||||
|
return ( <><h1>Page not found</h1></>) |
||||
|
} |
@ -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 |
@ -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
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue