Main project structure #3
22
src/App.tsx
22
src/App.tsx
@ -1,4 +1,4 @@
|
||||
import { BrowserRouter as Router, Routes, Route, Outlet, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { BrowserRouter as Router, Routes, Route, Outlet, useLocation, useNavigate } from "react-router-dom";
|
||||
import {useEffect, useState } from "react";
|
||||
|
||||
import { ToastContainer } from "react-toastify";
|
||||
@ -10,14 +10,20 @@ import {
|
||||
|
||||
import { AuthProvider } from "./auth/auth-provider"
|
||||
import ping from "./auth/ping";
|
||||
import useAuth from "./auth/auth";
|
||||
|
||||
import Login from "./pages/login/login"
|
||||
import Register from "./pages/register/register"
|
||||
|
||||
import Home from "./pages/home/home"
|
||||
import Dashboard from "./pages/dashboard/dashboard"
|
||||
import Users from "./pages/users/users";
|
||||
import Groups from "./pages/groups/groups";
|
||||
import Feeds from "./pages/feeds/feeds";
|
||||
import Pictures from "./pages/pictures/pictures";
|
||||
|
||||
import Account from "./pages/acccount/account";
|
||||
import Settings from "./pages/settings/settings"
|
||||
import useAuth from './auth/auth';
|
||||
|
||||
|
||||
const PrivateRoute = () => {
|
||||
@ -78,9 +84,15 @@ function App() {
|
||||
<Route path="/register" element={<Register />} />
|
||||
|
||||
<Route element={<PrivateRoute />}>
|
||||
<Route path='/' element={<Home />} />
|
||||
<Route path='/dashboard' element={<Dashboard />} />
|
||||
<Route path='/settings' element={<Settings />} />
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/dashboard" element={<Dashboard />} />
|
||||
<Route path="/users" element={<Users />} />
|
||||
<Route path="/groups" element={<Groups />} />
|
||||
<Route path="/feeds" element={<Feeds />} />
|
||||
<Route path="/pictures" element={<Pictures />} />
|
||||
|
||||
<Route path="/account" element={<Account />} />
|
||||
<Route path="/settings" element={<Settings />} />
|
||||
</Route>
|
||||
|
||||
<Route path="*" element={<h1 className="not-found">404 [#]<br/>Not Found</h1>} />
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import React, { useState } from 'react';
|
||||
import './FormField.css';
|
||||
import React, { useState } from "react";
|
||||
import "./FormField.css";
|
||||
|
||||
|
||||
interface FormFieldProperties {
|
||||
type?: 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search';
|
||||
type?: "text" | "email" | "password" | "number" | "tel" | "url" | "search";
|
||||
placeholder?: string;
|
||||
value: string;
|
||||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
@ -22,24 +22,24 @@ interface FormFieldProperties {
|
||||
|
||||
|
||||
const FormField: React.FC<FormFieldProperties> = ({
|
||||
type = 'text',
|
||||
type = "text",
|
||||
placeholder,
|
||||
value,
|
||||
onChange,
|
||||
required = false,
|
||||
errorMessage = 'Please fill out this field',
|
||||
errorMessage = "Please fill out this field",
|
||||
showError = false,
|
||||
onBlur,
|
||||
onFocus,
|
||||
className = '',
|
||||
className = "",
|
||||
disabled = false,
|
||||
autoComplete = 'off',
|
||||
autoComplete = "off",
|
||||
customValidator,
|
||||
showErrorInitially = false,
|
||||
icon: Icon,
|
||||
}) => {
|
||||
const [touched, setTouched] = useState<boolean>(showErrorInitially);
|
||||
const [customError, setCustomError] = useState<string>('');
|
||||
const [customError, setCustomError] = useState<string>("");
|
||||
|
||||
const validateField = (value: string): string => {
|
||||
if (required && !value) {
|
||||
@ -51,7 +51,7 @@ const FormField: React.FC<FormFieldProperties> = ({
|
||||
return customValidation;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
return "";
|
||||
};
|
||||
|
||||
const shouldShowError = showError || (touched && validateField(value));
|
||||
@ -64,7 +64,7 @@ const FormField: React.FC<FormFieldProperties> = ({
|
||||
};
|
||||
|
||||
const handleFocus = (e: React.FocusEvent<HTMLInputElement>): void => {
|
||||
setCustomError('');
|
||||
setCustomError("");
|
||||
onFocus?.(e);
|
||||
};
|
||||
|
||||
@ -85,7 +85,7 @@ const FormField: React.FC<FormFieldProperties> = ({
|
||||
required={required}
|
||||
disabled={disabled}
|
||||
autoComplete={autoComplete}
|
||||
className={shouldShowError ? 'error' : ''}
|
||||
className={shouldShowError ? "error" : ""}
|
||||
/>
|
||||
{shouldShowError && (
|
||||
<div className="error-message">
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
display: flex;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 240px;
|
||||
width: 280px;
|
||||
height: 100%;
|
||||
background-color: var(--background-dark);
|
||||
box-shadow: 2px 0 10px rgba(0, 0, 0, 0.3);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import React from "react";
|
||||
import useLogout from "../auth/logout"
|
||||
import './Sidebar.css';
|
||||
import "./Sidebar.css";
|
||||
|
||||
|
||||
const Sidebar: React.FC = () => {
|
||||
@ -14,7 +14,10 @@ const Sidebar: React.FC = () => {
|
||||
<nav className="sidebar-nav">
|
||||
<a href="/" className="sidebar-link">Home</a>
|
||||
<a href="/dashboard" className="sidebar-link">Dashboard</a>
|
||||
<a href="/user" className="sidebar-link">User</a>
|
||||
<a href="/users" className="sidebar-link">Users</a>
|
||||
<a href="/groups" className="sidebar-link">Groups</a>
|
||||
<a href="/feeds" className="sidebar-link">Feeds</a>
|
||||
<a href="/pictures" className="sidebar-link">Pictures</a>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
@ -22,6 +25,7 @@ const Sidebar: React.FC = () => {
|
||||
<button onClick={useLogout()} className="sidebar-link logout-button">
|
||||
Logout
|
||||
</button>
|
||||
<a href="/account" className="sidebar-link">Account</a>
|
||||
<a href="/settings" className="sidebar-link">Settings</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
10
src/main.tsx
10
src/main.tsx
@ -1,9 +1,9 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
import { StrictMode } from "react"
|
||||
import { createRoot } from "react-dom/client"
|
||||
import "./index.css"
|
||||
import App from "./App.tsx"
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
|
||||
14
src/pages/acccount/account.css
Normal file
14
src/pages/acccount/account.css
Normal file
@ -0,0 +1,14 @@
|
||||
.account {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.account-content {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
15
src/pages/acccount/account.tsx
Normal file
15
src/pages/acccount/account.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import "./account.css"
|
||||
import Sidebar from "../../components/Sidebar";
|
||||
|
||||
const Account = () => {
|
||||
return (
|
||||
<div className="account">
|
||||
<Sidebar/>
|
||||
<div className="account-content">
|
||||
<h2>Account</h2>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Account;
|
||||
@ -2,11 +2,7 @@
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width:100%;
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
display: flex;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.dashboard-content {
|
||||
|
||||
@ -4,9 +4,7 @@ import "./dashboard.css"
|
||||
const Dashboard = () => {
|
||||
return (
|
||||
<div className="dashboard">
|
||||
<div>
|
||||
<Sidebar/>
|
||||
</div>
|
||||
<div className="dashboard-content">
|
||||
<div className="dashboard-text">
|
||||
<h2>Dashboard Content<br/>WIP</h2>
|
||||
|
||||
14
src/pages/feeds/feeds.css
Normal file
14
src/pages/feeds/feeds.css
Normal file
@ -0,0 +1,14 @@
|
||||
.feeds {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.feeds-content {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
15
src/pages/feeds/feeds.tsx
Normal file
15
src/pages/feeds/feeds.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import "./feeds.css"
|
||||
import Sidebar from "../../components/Sidebar";
|
||||
|
||||
const Feeds = () => {
|
||||
return (
|
||||
<div className="feeds">
|
||||
<Sidebar/>
|
||||
<div className="feeds-content">
|
||||
<h2>Feeds</h2>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Feeds;
|
||||
14
src/pages/groups/groups.css
Normal file
14
src/pages/groups/groups.css
Normal file
@ -0,0 +1,14 @@
|
||||
.groups {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.groups-content {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
15
src/pages/groups/groups.tsx
Normal file
15
src/pages/groups/groups.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import "./groups.css"
|
||||
import Sidebar from "../../components/Sidebar";
|
||||
|
||||
const Groups = () => {
|
||||
return (
|
||||
<div className="groups">
|
||||
<Sidebar/>
|
||||
<div className="groups-content">
|
||||
<h2>Groups</h2>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Groups;
|
||||
14
src/pages/home/home.css
Normal file
14
src/pages/home/home.css
Normal file
@ -0,0 +1,14 @@
|
||||
.home {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.home-content {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
@ -1,14 +1,14 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
import useLogout from "../../auth/logout"
|
||||
import { Link } from "react-router-dom";
|
||||
import Sidebar from "../../components/Sidebar";
|
||||
import "./home.css"
|
||||
|
||||
|
||||
const Home = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className="home">
|
||||
<Sidebar/>
|
||||
<div className="home-content">
|
||||
<h2>Home</h2>
|
||||
<button onClick={useLogout()}>
|
||||
Logout
|
||||
</button>
|
||||
<nav>
|
||||
<ul>
|
||||
<li>
|
||||
@ -26,6 +26,7 @@ const Home = () => {
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ const Login = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const searchPath = new URLSearchParams(location.search);
|
||||
const redirectPath = searchPath.get('to') || "/";
|
||||
const redirectPath = searchPath.get("to") || "/";
|
||||
|
||||
const [usernameEmpty, setUsernameEmpty] = useState(false);
|
||||
const [passwordEmpty, setPasswordEmpty] = useState(false);
|
||||
@ -54,7 +54,7 @@ const Login = () => {
|
||||
</div>
|
||||
<div className="login-left">
|
||||
<video className="login-video" autoPlay loop muted>
|
||||
<source src={"./login-video.mp4"} type='video/mp4' />
|
||||
<source src={"./login-video.mp4"} type="video/mp4" />
|
||||
</video>
|
||||
</div>
|
||||
<div className="login-right">
|
||||
|
||||
14
src/pages/pictures/pictures.css
Normal file
14
src/pages/pictures/pictures.css
Normal file
@ -0,0 +1,14 @@
|
||||
.pictures {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.pictures-content {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
15
src/pages/pictures/pictures.tsx
Normal file
15
src/pages/pictures/pictures.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import "./pictures.css"
|
||||
import Sidebar from "../../components/Sidebar";
|
||||
|
||||
const Pictures = () => {
|
||||
return (
|
||||
<div className="pictures">
|
||||
<Sidebar/>
|
||||
<div className="pictures-content">
|
||||
<h2>Pictures</h2>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Pictures;
|
||||
@ -17,7 +17,7 @@ const Register = () => {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const searchPath = new URLSearchParams(location.search);
|
||||
const redirectPath = searchPath.get('to') || "/";
|
||||
const redirectPath = searchPath.get("to") || "/";
|
||||
|
||||
const [usernameEmpty, setUsernameEmpty] = useState(false);
|
||||
const [passwordEmpty, setPasswordEmpty] = useState(false);
|
||||
|
||||
14
src/pages/settings/settings.css
Normal file
14
src/pages/settings/settings.css
Normal file
@ -0,0 +1,14 @@
|
||||
.settings {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.settings-content {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
@ -1,8 +1,14 @@
|
||||
import "./settings.css"
|
||||
import Sidebar from "../../components/Sidebar";
|
||||
|
||||
const Settings = () => {
|
||||
return (
|
||||
<div>
|
||||
<div className="settings">
|
||||
<Sidebar/>
|
||||
<div className="settings-content">
|
||||
<h2>Settings</h2>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
14
src/pages/users/users.css
Normal file
14
src/pages/users/users.css
Normal file
@ -0,0 +1,14 @@
|
||||
.users {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.users-content {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
15
src/pages/users/users.tsx
Normal file
15
src/pages/users/users.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import "./users.css"
|
||||
import Sidebar from "../../components/Sidebar";
|
||||
|
||||
const Users = () => {
|
||||
return (
|
||||
<div className="users">
|
||||
<Sidebar/>
|
||||
<div className="users-content">
|
||||
<h2>Users</h2>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Users;
|
||||
Reference in New Issue
Block a user