Created
May 29, 2025 12:55
-
-
Save sunmeat/dbf4b63ef9875b5de38758b5cc0dcacc to your computer and use it in GitHub Desktop.
useContext - авторизация на сайте
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
App.jsx: | |
import React, {createContext, useContext, useState} from 'react'; | |
import './App.css'; | |
// контекст аутентификации | |
const AuthContext = createContext(); | |
// провайдер контекста аутентификации | |
function AuthProvider({children}) { | |
const [auth, setAuth] = useState({ | |
isAuthenticated: false, | |
user: null, | |
role: 'гость' | |
}); | |
// функция входа в систему | |
const login = (userData) => { | |
setAuth({ | |
isAuthenticated: true, | |
user: userData, | |
role: userData.role || 'пользователь' | |
}); | |
}; | |
// функция регистрации | |
const register = (userData) => { | |
setAuth({ | |
isAuthenticated: true, | |
user: userData, | |
role: userData.role || 'пользователь' | |
}); | |
}; | |
// функция входа как гость | |
const guestLogin = () => { | |
setAuth({ | |
isAuthenticated: false, | |
user: {name: 'Гость'}, | |
role: 'гость' | |
}); | |
}; | |
// функция выхода | |
const logout = () => { | |
setAuth({ | |
isAuthenticated: false, | |
user: null, | |
role: 'гость' | |
}); | |
}; | |
return ( | |
<AuthContext.Provider value={{auth, login, register, guestLogin, logout}}> | |
{children} | |
</AuthContext.Provider> | |
); | |
} | |
// кастомный хук useAuth упрощает доступ к контексту AuthContext, предоставляя компонентам удобный способ | |
// получения данных и методов аутентификации (auth, login, register, guestLogin, logout) | |
// вместо повторяющегося вызова useContext(AuthContext) в каждом компоненте, useAuth делает код чище, | |
// читабельнее и поддерживает единообразный интерфейс для работы с контекстом | |
const useAuth = () => useContext(AuthContext); | |
// главный компонент приложения | |
function App() { | |
const [screen, setScreen] = useState('auth'); | |
const [theme, setTheme] = useState('light'); | |
// переключение темы | |
const toggleTheme = () => { | |
setTheme(theme === 'light' ? 'dark' : 'light'); | |
}; | |
// переход на экран контента | |
const goToContent = () => { | |
setScreen('content'); | |
}; | |
// переход на экран авторизации | |
const goToAuth = () => { | |
setScreen('auth'); | |
}; | |
// смена экранов зависит от состояния screen | |
return ( | |
<AuthProvider> | |
<div className={`app ${theme}`}> | |
{screen === 'auth' ? ( | |
<AuthScreen goToContent={goToContent} toggleTheme={toggleTheme}/> | |
) : ( | |
<ContentScreen goToAuth={goToAuth} toggleTheme={toggleTheme}/> | |
)} | |
</div> | |
</AuthProvider> | |
); | |
} | |
// экран авторизации | |
function AuthScreen({goToContent, toggleTheme}) { | |
return ( | |
<div className="auth-container"> | |
<ThemeToggle toggleTheme={toggleTheme}/> | |
<AuthForm goToContent={goToContent}/> | |
<GuestButton goToContent={goToContent}/> | |
</div> | |
); | |
} | |
// компонент кнопки переключения темы | |
function ThemeToggle({toggleTheme}) { | |
return ( | |
<button className="auth-button" onClick={toggleTheme}> | |
Сменить тему | |
</button> | |
); | |
} | |
// форма входа и регистрации | |
function AuthForm({goToContent}) { | |
const {login, register} = useAuth(); | |
const [loginInput, setLoginInput] = useState('Alex'); | |
const [password, setPassword] = useState('1234'); | |
// обработчик входа | |
const handleLogin = (e) => { | |
e.preventDefault(); | |
login({name: loginInput, role: 'пользователь'}); | |
goToContent(); | |
}; | |
// обработчик регистрации | |
const handleRegister = (e) => { | |
e.preventDefault(); | |
register({name: loginInput, role: 'пользователь'}); | |
goToContent(); | |
}; | |
return ( | |
<form className="auth-form"> | |
<h2>Авторизация</h2> | |
<input | |
type="text" | |
placeholder="Логин" | |
value={loginInput} | |
onChange={(e) => setLoginInput(e.target.value)} | |
required | |
/> | |
<input | |
type="password" | |
placeholder="Пароль" | |
value={password} | |
onChange={(e) => setPassword(e.target.value)} | |
required | |
/> | |
<div className="button-group"> | |
<button className="auth-button" onClick={handleLogin}> | |
Вход | |
</button> | |
<button className="auth-button" onClick={handleRegister}> | |
Регистрация | |
</button> | |
</div> | |
</form> | |
); | |
} | |
// кнопка входа как гость | |
function GuestButton({goToContent}) { | |
const {guestLogin} = useAuth(); | |
// обработчик входа как гость | |
const handleGuestLogin = () => { | |
guestLogin(); | |
goToContent(); | |
}; | |
return ( | |
<button className="auth-button guest" onClick={handleGuestLogin}> | |
Войти как гость | |
</button> | |
); | |
} | |
// экран контента | |
function ContentScreen({goToAuth, toggleTheme}) { | |
return ( | |
<div className="content-container"> | |
<ThemeToggle toggleTheme={toggleTheme}/> | |
<UserInfo/> | |
<Content/> | |
<Settings/> | |
<LogoutButton goToAuth={goToAuth}/> | |
</div> | |
); | |
} | |
// информация о пользователе | |
function UserInfo() { | |
const {auth} = useAuth(); | |
return ( | |
<div className="content-section"> | |
<h2>Пользователь</h2> | |
<p>Имя: {auth.user?.name || 'Гость'}</p> | |
<p>Роль: {auth.role}</p> | |
<p>Статус: {auth.isAuthenticated ? 'Авторизован' : 'Не авторизован'}</p> | |
</div> | |
); | |
} | |
// контент | |
function Content() { | |
const {auth} = useAuth(); | |
return ( | |
<div className="content-section"> | |
<h2>Контент</h2> | |
<p>Добро пожаловать, {auth.user?.name || 'Гость'}!</p> | |
</div> | |
); | |
} | |
// настройки | |
function Settings() { | |
const {auth} = useAuth(); | |
return ( | |
<div className="content-section"> | |
<h2>Настройки</h2> | |
<p>{auth.isAuthenticated ? 'Настройки пользователя.' : 'Войдите для настроек.'}</p> | |
</div> | |
); | |
} | |
// кнопка выхода | |
function LogoutButton({goToAuth}) { | |
const {logout} = useAuth(); | |
// обработчик выхода | |
const handleLogout = () => { | |
logout(); | |
goToAuth(); | |
}; | |
return ( | |
<button className="auth-button" onClick={handleLogout}> | |
Выйти | |
</button> | |
); | |
} | |
export default App; | |
================================================================================================================ | |
App.css: | |
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Poppins:wght@300;400;600&display=swap'); | |
:root { | |
--light-bg: linear-gradient(135deg, #ff00cc, #3333ff); | |
--light-text: #f0f0f0; | |
--light-accent: #ff00ff; | |
--light-glow: 0 0 10px rgba(255, 0, 204, 0.6); | |
--dark-bg: linear-gradient(135deg, #1a0033, #003366); | |
--dark-text: #e0e0ff; | |
--dark-accent: #ff33cc; | |
--dark-glow: 0 0 10px rgba(255, 51, 204, 0.7); | |
--transition: all 0.3s ease-in-out; | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
html, body, #root { | |
height: 100%; | |
width: 100%; | |
} | |
body { | |
font-family: 'Poppins', sans-serif; | |
} | |
.app { | |
min-height: 100vh; | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
background-size: 200% 200%; | |
animation: gradientShift 10s ease infinite; | |
} | |
@keyframes gradientShift { | |
0% { | |
background-position: 0 50%; | |
} | |
50% { | |
background-position: 100% 50%; | |
} | |
100% { | |
background-position: 0 50%; | |
} | |
} | |
.light { | |
background: var(--light-bg); | |
color: var(--light-text); | |
} | |
.dark { | |
background: var(--dark-bg); | |
color: var(--dark-text); | |
} | |
.auth-container { | |
display: flex; | |
flex-direction: column; | |
gap: 1rem; | |
padding: 1.5rem; | |
max-width: 400px; | |
width: 100%; | |
background: rgba(255, 255, 255, 0.15); | |
border-radius: 15px; | |
backdrop-filter: blur(10px); | |
box-shadow: var(--light-glow); | |
} | |
.dark .auth-container { | |
box-shadow: var(--dark-glow); | |
} | |
.auth-form { | |
display: flex; | |
flex-direction: column; | |
gap: 0.8rem; | |
} | |
.auth-form h2 { | |
font-family: 'Orbitron', sans-serif; | |
font-size: 1.8rem; | |
font-weight: 700; | |
text-transform: uppercase; | |
text-shadow: var(--light-glow); | |
} | |
.dark .auth-form h2 { | |
text-shadow: var(--dark-glow); | |
} | |
.auth-form input { | |
padding: 10px; | |
border: none; | |
border-radius: 8px; | |
background: rgba(255, 255, 255, 0.2); | |
color: var(--light-text); | |
font-size: 0.9rem; | |
} | |
.dark .auth-form input { | |
color: var(--dark-text); | |
} | |
.auth-form input:focus { | |
outline: none; | |
box-shadow: var(--light-glow); | |
} | |
.dark .auth-form input:focus { | |
box-shadow: var(--dark-glow); | |
} | |
.button-group { | |
display: flex; | |
gap: 0.5rem; | |
} | |
.auth-button { | |
padding: 10px; | |
border: none; | |
border-radius: 8px; | |
cursor: pointer; | |
background: linear-gradient(45deg, #ff0066, #ffcc00); | |
color: #fff; | |
font-family: 'Poppins', sans-serif; | |
font-size: 0.9rem; | |
font-weight: 600; | |
transition: var(--transition); | |
box-shadow: var(--light-glow); | |
position: relative; | |
overflow: hidden; | |
} | |
.dark .auth-button { | |
background: linear-gradient(45deg, #cc00ff, #00ccff); | |
box-shadow: var(--dark-glow); | |
} | |
.auth-button:hover { | |
transform: scale(1.05); | |
box-shadow: 0 6px 15px rgba(255, 0, 204, 0.5); | |
} | |
.dark .auth-button:hover { | |
box-shadow: 0 6px 15px rgba(255, 51, 204, 0.6); | |
} | |
.auth-button::after { | |
content: ''; | |
position: absolute; | |
top: 0; | |
left: -100%; | |
width: 100%; | |
height: 100%; | |
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); | |
transition: 0.4s; | |
} | |
.auth-button:hover::after { | |
left: 100%; | |
} | |
.auth-button.guest { | |
background: linear-gradient(45deg, #00ccff, #33ff33); | |
} | |
.dark .auth-button.guest { | |
background: linear-gradient(45deg, #33ffcc, #66ff33); | |
} | |
.content-container { | |
display: flex; | |
flex-direction: column; | |
gap: 1rem; | |
padding: 1.5rem; | |
max-width: 600px; | |
width: 100%; | |
background: rgba(255, 255, 255, 0.15); | |
border-radius: 15px; | |
backdrop-filter: blur(10px); | |
box-shadow: var(--light-glow); | |
} | |
.dark .content-container { | |
box-shadow: var(--dark-glow); | |
} | |
.content-section { | |
display: flex; | |
flex-direction: column; | |
gap: 0.5rem; | |
} | |
.content-section h2 { | |
font-family: 'Orbitron', sans-serif; | |
font-size: 1.6rem; | |
font-weight: 700; | |
text-shadow: var(--light-glow); | |
} | |
.dark .content-section h2 { | |
text-shadow: var(--dark-glow); | |
} | |
.content-section p { | |
font-size: 1rem; | |
line-height: 1.6; | |
font-weight: 300; | |
} | |
@media (max-width: 768px) { | |
.auth-container, .content-container { | |
padding: 1rem; | |
max-width: 90%; | |
} | |
.auth-form h2, .content-section h2 { | |
font-size: 1.5rem; | |
} | |
.auth-button { | |
padding: 8px; | |
font-size: 0.8rem; | |
} | |
} | |
@media (max-width: 480px) { | |
.auth-container, .content-container { | |
padding: 0.8rem; | |
} | |
.auth-form h2, .content-section h2 { | |
font-size: 1.4rem; | |
} | |
.auth-form input { | |
padding: 8px; | |
font-size: 0.8rem; | |
} | |
.auth-button { | |
padding: 6px; | |
font-size: 0.7rem; | |
} | |
.button-group { | |
flex-direction: column; | |
gap: 0.3rem; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment