Improved add host UI
This commit is contained in:
102
src/App.jsx
102
src/App.jsx
@@ -2,7 +2,7 @@ import { useState, useEffect, useRef } from "react";
|
|||||||
import { NewTerminal } from "./apps/ssh/Terminal.jsx";
|
import { NewTerminal } from "./apps/ssh/Terminal.jsx";
|
||||||
import { User } from "./apps/user/User.jsx";
|
import { User } from "./apps/user/User.jsx";
|
||||||
import AddHostModal from "./modals/AddHostModal.jsx";
|
import AddHostModal from "./modals/AddHostModal.jsx";
|
||||||
import LoginUserModal from "./modals/LoginUserModal.jsx";
|
import AuthModal from "./modals/AuthModal.jsx";
|
||||||
import { Button } from "@mui/joy";
|
import { Button } from "@mui/joy";
|
||||||
import { CssVarsProvider } from "@mui/joy";
|
import { CssVarsProvider } from "@mui/joy";
|
||||||
import theme from "./theme";
|
import theme from "./theme";
|
||||||
@@ -12,7 +12,6 @@ import { Debounce } from './other/Utils.jsx';
|
|||||||
import TermixIcon from "./images/termix_icon.png";
|
import TermixIcon from "./images/termix_icon.png";
|
||||||
import RocketIcon from './images/launchpad_rocket.png';
|
import RocketIcon from './images/launchpad_rocket.png';
|
||||||
import ProfileIcon from './images/profile_icon.png';
|
import ProfileIcon from './images/profile_icon.png';
|
||||||
import CreateUserModal from "./modals/CreateUserModal.jsx";
|
|
||||||
import ProfileModal from "./modals/ProfileModal.jsx";
|
import ProfileModal from "./modals/ProfileModal.jsx";
|
||||||
import ErrorModal from "./modals/ErrorModal.jsx";
|
import ErrorModal from "./modals/ErrorModal.jsx";
|
||||||
import EditHostModal from "./modals/EditHostModal.jsx";
|
import EditHostModal from "./modals/EditHostModal.jsx";
|
||||||
@@ -20,8 +19,7 @@ import NoAuthenticationModal from "./modals/NoAuthenticationModal.jsx";
|
|||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [isAddHostHidden, setIsAddHostHidden] = useState(true);
|
const [isAddHostHidden, setIsAddHostHidden] = useState(true);
|
||||||
const [isLoginUserHidden, setIsLoginUserHidden] = useState(true);
|
const [isAuthModalHidden, setIsAuthModalHidden] = useState(true);
|
||||||
const [isCreateUserHidden, setIsCreateUserHidden] = useState(true);
|
|
||||||
const [isProfileHidden, setIsProfileHidden] = useState(true);
|
const [isProfileHidden, setIsProfileHidden] = useState(true);
|
||||||
const [isErrorHidden, setIsErrorHidden] = useState(true);
|
const [isErrorHidden, setIsErrorHidden] = useState(true);
|
||||||
const [errorMessage, setErrorMessage] = useState('');
|
const [errorMessage, setErrorMessage] = useState('');
|
||||||
@@ -37,7 +35,7 @@ function App() {
|
|||||||
password: "",
|
password: "",
|
||||||
port: 22,
|
port: 22,
|
||||||
authMethod: "Select Auth",
|
authMethod: "Select Auth",
|
||||||
rememberHost: false,
|
rememberHost: true,
|
||||||
storePassword: true,
|
storePassword: true,
|
||||||
});
|
});
|
||||||
const [editHostForm, setEditHostForm] = useState({
|
const [editHostForm, setEditHostForm] = useState({
|
||||||
@@ -53,14 +51,6 @@ function App() {
|
|||||||
});
|
});
|
||||||
const [isNoAuthHidden, setIsNoAuthHidden] = useState(true);
|
const [isNoAuthHidden, setIsNoAuthHidden] = useState(true);
|
||||||
const [authForm, setAuthForm] = useState({
|
const [authForm, setAuthForm] = useState({
|
||||||
password: "",
|
|
||||||
rsaKey: "",
|
|
||||||
});
|
|
||||||
const [loginUserForm, setLoginUserForm] = useState({
|
|
||||||
username: "",
|
|
||||||
password: "",
|
|
||||||
});
|
|
||||||
const [createUserForm, setCreateUserForm] = useState({
|
|
||||||
username: "",
|
username: "",
|
||||||
password: "",
|
password: "",
|
||||||
});
|
});
|
||||||
@@ -133,13 +123,13 @@ function App() {
|
|||||||
|
|
||||||
if (userRef.current?.getUser()) {
|
if (userRef.current?.getUser()) {
|
||||||
setIsLoggingIn(false);
|
setIsLoggingIn(false);
|
||||||
setIsLoginUserHidden(true);
|
setIsAuthModalHidden(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sessionToken) {
|
if (!sessionToken) {
|
||||||
setIsLoggingIn(false);
|
setIsLoggingIn(false);
|
||||||
setIsLoginUserHidden(false);
|
setIsAuthModalHidden(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +143,7 @@ function App() {
|
|||||||
clearInterval(attemptLoginInterval);
|
clearInterval(attemptLoginInterval);
|
||||||
if (!userRef.current?.getUser()) {
|
if (!userRef.current?.getUser()) {
|
||||||
localStorage.removeItem('sessionToken');
|
localStorage.removeItem('sessionToken');
|
||||||
setIsLoginUserHidden(false);
|
setIsAuthModalHidden(false);
|
||||||
setIsLoggingIn(false);
|
setIsLoggingIn(false);
|
||||||
setErrorMessage('Login timed out. Please try again.');
|
setErrorMessage('Login timed out. Please try again.');
|
||||||
setIsErrorHidden(false);
|
setIsErrorHidden(false);
|
||||||
@@ -170,7 +160,7 @@ function App() {
|
|||||||
|
|
||||||
if (!userRef.current?.getUser()) {
|
if (!userRef.current?.getUser()) {
|
||||||
localStorage.removeItem('sessionToken');
|
localStorage.removeItem('sessionToken');
|
||||||
setIsLoginUserHidden(false);
|
setIsAuthModalHidden(false);
|
||||||
setIsLoggingIn(false);
|
setIsLoggingIn(false);
|
||||||
setErrorMessage('Login timed out. Please try again.');
|
setErrorMessage('Login timed out. Please try again.');
|
||||||
setIsErrorHidden(false);
|
setIsErrorHidden(false);
|
||||||
@@ -186,7 +176,7 @@ function App() {
|
|||||||
if (isComponentMounted) {
|
if (isComponentMounted) {
|
||||||
clearTimeout(loginTimeout);
|
clearTimeout(loginTimeout);
|
||||||
clearInterval(attemptLoginInterval);
|
clearInterval(attemptLoginInterval);
|
||||||
setIsLoginUserHidden(true);
|
setIsAuthModalHidden(true);
|
||||||
setIsLoggingIn(false);
|
setIsLoggingIn(false);
|
||||||
setIsErrorHidden(true);
|
setIsErrorHidden(true);
|
||||||
}
|
}
|
||||||
@@ -200,7 +190,7 @@ function App() {
|
|||||||
localStorage.removeItem('sessionToken');
|
localStorage.removeItem('sessionToken');
|
||||||
setErrorMessage(`Auto-login failed: ${error}`);
|
setErrorMessage(`Auto-login failed: ${error}`);
|
||||||
setIsErrorHidden(false);
|
setIsErrorHidden(false);
|
||||||
setIsLoginUserHidden(false);
|
setIsAuthModalHidden(false);
|
||||||
setIsLoggingIn(false);
|
setIsLoggingIn(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -372,64 +362,49 @@ function App() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLoginUser = ({ username, password, sessionToken, onSuccess, onFailure }) => {
|
const handleLoginUser = ({ username, password, onSuccess, onFailure }) => {
|
||||||
if (userRef.current) {
|
if (userRef.current) {
|
||||||
if (sessionToken) {
|
|
||||||
userRef.current.loginUser({
|
|
||||||
sessionToken,
|
|
||||||
onSuccess: () => {
|
|
||||||
setIsLoginUserHidden(true);
|
|
||||||
setIsLoggingIn(false);
|
|
||||||
if (onSuccess) onSuccess();
|
|
||||||
},
|
|
||||||
onFailure: (error) => {
|
|
||||||
localStorage.removeItem('sessionToken');
|
|
||||||
setIsLoginUserHidden(false);
|
|
||||||
setIsLoggingIn(false);
|
|
||||||
if (onFailure) onFailure(error);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
userRef.current.loginUser({
|
userRef.current.loginUser({
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
setIsLoginUserHidden(true);
|
setIsAuthModalHidden(true);
|
||||||
setIsLoggingIn(false);
|
|
||||||
if (onSuccess) onSuccess();
|
if (onSuccess) onSuccess();
|
||||||
},
|
},
|
||||||
onFailure: (error) => {
|
onFailure: (error) => {
|
||||||
setIsLoginUserHidden(false);
|
setIsAuthModalHidden(false);
|
||||||
setIsLoggingIn(false);
|
|
||||||
if (onFailure) onFailure(error);
|
if (onFailure) onFailure(error);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleGuestLogin = async ({ onSuccess, onFailure }) => {
|
const handleGuestLogin = async ({ onSuccess, onFailure }) => {
|
||||||
if (userRef.current) {
|
if (userRef.current) {
|
||||||
try {
|
try {
|
||||||
await userRef.current.loginAsGuest();
|
await userRef.current.loginAsGuest();
|
||||||
setIsLoginUserHidden(true);
|
setIsAuthModalHidden(true);
|
||||||
setIsLoggingIn(false);
|
|
||||||
if (onSuccess) onSuccess();
|
if (onSuccess) onSuccess();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setIsLoginUserHidden(false);
|
setIsAuthModalHidden(false);
|
||||||
setIsLoggingIn(false);
|
|
||||||
if (onFailure) onFailure(error);
|
if (onFailure) onFailure(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleCreateUser = ({ username, password, onSuccess, onFailure }) => {
|
const handleCreateUser = ({ username, password, onSuccess, onFailure }) => {
|
||||||
if (userRef.current) {
|
if (userRef.current) {
|
||||||
userRef.current.createUser({
|
userRef.current.createUser({
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
onSuccess,
|
onSuccess: () => {
|
||||||
onFailure,
|
setIsAuthModalHidden(true);
|
||||||
|
if (onSuccess) onSuccess();
|
||||||
|
},
|
||||||
|
onFailure: (error) => {
|
||||||
|
setIsAuthModalHidden(false);
|
||||||
|
if (onFailure) onFailure(error);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -622,7 +597,7 @@ function App() {
|
|||||||
{/* Profile Button */}
|
{/* Profile Button */}
|
||||||
<Button
|
<Button
|
||||||
disabled={isLoggingIn}
|
disabled={isLoggingIn}
|
||||||
onClick={() => userRef.current?.getUser() ? setIsProfileHidden(false) : setIsLoginUserHidden(false)}
|
onClick={() => userRef.current?.getUser() ? setIsProfileHidden(false) : setIsAuthModalHidden(false)}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: theme.palette.general.tertiary,
|
backgroundColor: theme.palette.general.tertiary,
|
||||||
"&:hover": { backgroundColor: theme.palette.general.secondary },
|
"&:hover": { backgroundColor: theme.palette.general.secondary },
|
||||||
@@ -742,40 +717,31 @@ function App() {
|
|||||||
setIsErrorHidden={setIsErrorHidden}
|
setIsErrorHidden={setIsErrorHidden}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<LoginUserModal
|
<AuthModal
|
||||||
isHidden={isLoginUserHidden}
|
isHidden={isAuthModalHidden}
|
||||||
form={loginUserForm}
|
form={authForm}
|
||||||
setForm={setLoginUserForm}
|
setForm={setAuthForm}
|
||||||
handleLoginUser={handleLoginUser}
|
handleLoginUser={handleLoginUser}
|
||||||
handleGuestLogin={handleGuestLogin}
|
handleGuestLogin={handleGuestLogin}
|
||||||
setIsLoginUserHidden={setIsLoginUserHidden}
|
|
||||||
setIsCreateUserHidden={setIsCreateUserHidden}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<CreateUserModal
|
|
||||||
isHidden={isCreateUserHidden}
|
|
||||||
form={createUserForm}
|
|
||||||
setForm={setCreateUserForm}
|
|
||||||
handleCreateUser={handleCreateUser}
|
handleCreateUser={handleCreateUser}
|
||||||
setIsCreateUserHidden={setIsCreateUserHidden}
|
setIsLoginUserHidden={setIsAuthModalHidden}
|
||||||
setIsLoginUserHidden={setIsLoginUserHidden}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* User component */}
|
{/* User component */}
|
||||||
<User
|
<User
|
||||||
ref={userRef}
|
ref={userRef}
|
||||||
onLoginSuccess={() => {
|
onLoginSuccess={() => {
|
||||||
setIsLoginUserHidden(true);
|
setIsAuthModalHidden(true);
|
||||||
setIsLoggingIn(false);
|
setIsLoggingIn(false);
|
||||||
setIsErrorHidden(true);
|
setIsErrorHidden(true);
|
||||||
}}
|
}}
|
||||||
onCreateSuccess={() => {
|
onCreateSuccess={() => {
|
||||||
setIsCreateUserHidden(true);
|
setIsAuthModalHidden(true);
|
||||||
handleLoginUser({
|
handleLoginUser({
|
||||||
username: createUserForm.username,
|
username: authForm.username,
|
||||||
password: createUserForm.password,
|
password: authForm.password,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
setIsLoginUserHidden(true);
|
setIsAuthModalHidden(true);
|
||||||
setIsLoggingIn(false);
|
setIsLoggingIn(false);
|
||||||
setIsErrorHidden(true);
|
setIsErrorHidden(true);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import {
|
|||||||
FormLabel,
|
FormLabel,
|
||||||
Input,
|
Input,
|
||||||
Stack,
|
Stack,
|
||||||
DialogTitle,
|
|
||||||
DialogContent,
|
|
||||||
ModalDialog,
|
ModalDialog,
|
||||||
Select,
|
Select,
|
||||||
Option,
|
Option,
|
||||||
@@ -394,6 +392,7 @@ const AddHostModal = ({ isHidden, form, setForm, handleAddHost, setIsAddHostHidd
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
|
disabled={!isFormValid()}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: theme.palette.general.primary,
|
backgroundColor: theme.palette.general.primary,
|
||||||
color: theme.palette.text.primary,
|
color: theme.palette.text.primary,
|
||||||
|
|||||||
174
src/modals/AuthModal.jsx
Normal file
174
src/modals/AuthModal.jsx
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { CssVarsProvider } from '@mui/joy/styles';
|
||||||
|
import { Modal, Button, FormControl, FormLabel, Input, Stack, ModalDialog, IconButton, Tabs, TabList, Tab, TabPanel } from '@mui/joy';
|
||||||
|
import theme from '/src/theme';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import Visibility from '@mui/icons-material/Visibility';
|
||||||
|
import VisibilityOff from '@mui/icons-material/VisibilityOff';
|
||||||
|
|
||||||
|
const AuthModal = ({ isHidden, form, setForm, handleLoginUser, handleGuestLogin, handleCreateUser, setIsLoginUserHidden }) => {
|
||||||
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
|
const [confirmPassword, setConfirmPassword] = useState('');
|
||||||
|
const [activeTab, setActiveTab] = useState(0);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
|
const isLoginFormValid = () => {
|
||||||
|
return form.username?.trim() && form.password?.trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
const isCreateFormValid = () => {
|
||||||
|
return form.username?.trim() && form.password?.trim() && confirmPassword?.trim() && form.password === confirmPassword;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLogin = () => {
|
||||||
|
if (!isLoginFormValid()) {
|
||||||
|
alert("Please fill out all fields");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
|
handleLoginUser({
|
||||||
|
username: form.username.trim(),
|
||||||
|
password: form.password.trim(),
|
||||||
|
onSuccess: () => {
|
||||||
|
setIsLoading(false);
|
||||||
|
setIsLoginUserHidden(true);
|
||||||
|
},
|
||||||
|
onFailure: (error) => {
|
||||||
|
setIsLoading(false);
|
||||||
|
alert(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreate = () => {
|
||||||
|
if (!isCreateFormValid()) {
|
||||||
|
alert("Please fill out all fields and ensure passwords match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
|
handleCreateUser({
|
||||||
|
username: form.username.trim(),
|
||||||
|
password: form.password.trim(),
|
||||||
|
onSuccess: () => {
|
||||||
|
setIsLoading(false);
|
||||||
|
setIsLoginUserHidden(true);
|
||||||
|
},
|
||||||
|
onFailure: (error) => {
|
||||||
|
setIsLoading(false);
|
||||||
|
alert(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isHidden) {
|
||||||
|
setForm({ username: '', password: '' });
|
||||||
|
setConfirmPassword('');
|
||||||
|
setIsLoading(false);
|
||||||
|
setActiveTab(0);
|
||||||
|
}
|
||||||
|
}, [isHidden]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CssVarsProvider theme={theme}>
|
||||||
|
<Modal open={!isHidden} onClose={() => setIsLoginUserHidden(true)}>
|
||||||
|
<ModalDialog layout="center" sx={{ backgroundColor: theme.palette.general.tertiary }}>
|
||||||
|
<Tabs value={activeTab} onChange={(e, val) => setActiveTab(val)}>
|
||||||
|
<TabList>
|
||||||
|
<Tab>Login</Tab>
|
||||||
|
<Tab>Create Account</Tab>
|
||||||
|
</TabList>
|
||||||
|
|
||||||
|
<div style={{ padding: '24px', backgroundColor: theme.palette.general.tertiary }}>
|
||||||
|
<TabPanel value={0}>
|
||||||
|
<Stack spacing={2}>
|
||||||
|
<FormControl>
|
||||||
|
<FormLabel>Username</FormLabel>
|
||||||
|
<Input
|
||||||
|
value={form.username}
|
||||||
|
onChange={(event) => setForm({ ...form, username: event.target.value })}
|
||||||
|
disabled={isLoading}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormControl>
|
||||||
|
<FormLabel>Password</FormLabel>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
<Input
|
||||||
|
type={showPassword ? 'text' : 'password'}
|
||||||
|
value={form.password}
|
||||||
|
onChange={(event) => setForm({ ...form, password: event.target.value })}
|
||||||
|
disabled={isLoading}
|
||||||
|
/>
|
||||||
|
<IconButton onClick={() => setShowPassword(!showPassword)}>
|
||||||
|
{showPassword ? <VisibilityOff /> : <Visibility />}
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<Button onClick={handleLogin} disabled={!isLoginFormValid() || isLoading}>
|
||||||
|
{isLoading ? "Logging in..." : "Login"}
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleGuestLogin} disabled={isLoading}>
|
||||||
|
{isLoading ? "Logging in as guest..." : "Login as Guest"}
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</TabPanel>
|
||||||
|
|
||||||
|
<TabPanel value={1}>
|
||||||
|
<Stack spacing={2}>
|
||||||
|
<FormControl>
|
||||||
|
<FormLabel>Username</FormLabel>
|
||||||
|
<Input
|
||||||
|
value={form.username}
|
||||||
|
onChange={(event) => setForm({ ...form, username: event.target.value })}
|
||||||
|
disabled={isLoading}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<FormControl>
|
||||||
|
<FormLabel>Password</FormLabel>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
<Input
|
||||||
|
type={showPassword ? 'text' : 'password'}
|
||||||
|
value={form.password}
|
||||||
|
onChange={(event) => setForm({ ...form, password: event.target.value })}
|
||||||
|
disabled={isLoading}
|
||||||
|
/>
|
||||||
|
<IconButton onClick={() => setShowPassword(!showPassword)}>
|
||||||
|
{showPassword ? <VisibilityOff /> : <Visibility />}
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormControl>
|
||||||
|
<FormLabel>Confirm Password</FormLabel>
|
||||||
|
<Input
|
||||||
|
type={showPassword ? 'text' : 'password'}
|
||||||
|
value={confirmPassword}
|
||||||
|
onChange={(event) => setConfirmPassword(event.target.value)}
|
||||||
|
disabled={isLoading}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
<Button onClick={handleCreate} disabled={!isCreateFormValid() || isLoading}>
|
||||||
|
{isLoading ? "Creating account..." : "Create Account"}
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</TabPanel>
|
||||||
|
</div>
|
||||||
|
</Tabs>
|
||||||
|
</ModalDialog>
|
||||||
|
</Modal>
|
||||||
|
</CssVarsProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
AuthModal.propTypes = {
|
||||||
|
isHidden: PropTypes.bool.isRequired,
|
||||||
|
form: PropTypes.object.isRequired,
|
||||||
|
setForm: PropTypes.func.isRequired,
|
||||||
|
handleLoginUser: PropTypes.func.isRequired,
|
||||||
|
handleGuestLogin: PropTypes.func.isRequired,
|
||||||
|
handleCreateUser: PropTypes.func.isRequired,
|
||||||
|
setIsLoginUserHidden: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AuthModal;
|
||||||
Reference in New Issue
Block a user