From 9be82e9e95a67045c71ff769c2fcf49938bcc7ec Mon Sep 17 00:00:00 2001 From: Matt Beaudoin Date: Tue, 24 Mar 2026 21:22:39 -0700 Subject: [PATCH] remove user / auth --- .env.example | 2 +- Netlify.toml | 14 --- src/App.tsx | 35 +++---- src/components/Authenticated.tsx | 24 ----- src/components/Header/Header.tsx | 14 --- src/components/Header/_Header.scss | 46 --------- src/context/AuthContext.tsx | 77 --------------- src/routes/{Authenticated => }/Apps/App.scss | 0 src/routes/{Authenticated => }/Apps/App.tsx | 14 +-- src/routes/{Authenticated => }/Apps/Apps.scss | 0 src/routes/{Authenticated => }/Apps/Apps.tsx | 8 +- .../Dashboard/Dashboard.tsx | 8 +- .../Dashboard/_Dashboard.scss | 0 src/routes/Login/LoginForm.scss | 94 ------------------- src/routes/Login/LoginForm.tsx | 72 -------------- .../{Authenticated => }/Servers/Server.scss | 0 .../{Authenticated => }/Servers/Server.tsx | 14 +-- .../{Authenticated => }/Servers/Servers.scss | 0 .../{Authenticated => }/Servers/Servers.tsx | 8 +- src/types/index.ts | 16 ---- 20 files changed, 39 insertions(+), 407 deletions(-) delete mode 100644 Netlify.toml delete mode 100644 src/components/Authenticated.tsx delete mode 100644 src/context/AuthContext.tsx rename src/routes/{Authenticated => }/Apps/App.scss (100%) rename src/routes/{Authenticated => }/Apps/App.tsx (96%) rename src/routes/{Authenticated => }/Apps/Apps.scss (100%) rename src/routes/{Authenticated => }/Apps/Apps.tsx (97%) rename src/routes/{Authenticated => }/Dashboard/Dashboard.tsx (94%) rename src/routes/{Authenticated => }/Dashboard/_Dashboard.scss (100%) delete mode 100644 src/routes/Login/LoginForm.scss delete mode 100644 src/routes/Login/LoginForm.tsx rename src/routes/{Authenticated => }/Servers/Server.scss (100%) rename src/routes/{Authenticated => }/Servers/Server.tsx (96%) rename src/routes/{Authenticated => }/Servers/Servers.scss (100%) rename src/routes/{Authenticated => }/Servers/Servers.tsx (97%) diff --git a/.env.example b/.env.example index b87d9f0..f21daf3 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ # API base URL for the backend that wraps the abra CLI VITE_API_URL=http://localhost:3000/api -# Set to 'true' to bypass authentication for development +# Set to 'true' to use mock data VITE_MOCK_AUTH=true \ No newline at end of file diff --git a/Netlify.toml b/Netlify.toml deleted file mode 100644 index 8739f75..0000000 --- a/Netlify.toml +++ /dev/null @@ -1,14 +0,0 @@ -[build] - command = "npm run build" - publish = "dist" - -# Environment variables for build -[build.environment] - VITE_MOCK_AUTH = "true" - VITE_API_URL = "http://localhost:3000/api" - -# Redirect all requests to index.html for client-side routing -[[redirects]] - from = "/*" - to = "/index.html" - status = 200 diff --git a/src/App.tsx b/src/App.tsx index 483e2ea..d424307 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,35 +1,24 @@ import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom'; -import { AuthProvider } from './context/AuthContext'; -import { LoginForm } from './routes/Login/LoginForm'; -import { Authenticated } from './components/Authenticated'; -import { Dashboard } from './routes/Authenticated/Dashboard/Dashboard'; -import { Apps } from './routes/Authenticated/Apps/Apps'; -import { AppDetail } from './routes/Authenticated/Apps/App'; -import { Servers } from './routes/Authenticated/Servers/Servers'; -import { Server } from './routes/Authenticated/Servers/Server'; +import { Dashboard } from './routes/Dashboard/Dashboard'; +import { Apps } from './routes/Apps/Apps'; +import { AppDetail } from './routes/Apps/App'; +import { Servers } from './routes/Servers/Servers'; +import { Server } from './routes/Servers/Server'; function App() { return ( - - - {/* Public routes */} - } /> - - {/* Protected routes */} - }> - } /> - } /> - } /> - } /> - } /> - } /> - + + } /> + } /> + } /> + } /> + } /> + } /> {/* 404 catch-all */} } /> - ); } diff --git a/src/components/Authenticated.tsx b/src/components/Authenticated.tsx deleted file mode 100644 index 4d877a3..0000000 --- a/src/components/Authenticated.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { Navigate, Outlet } from 'react-router-dom'; -import { useAuth } from '../context/AuthContext'; - -export const Authenticated: React.FC = () => { - const { isAuthenticated, loading } = useAuth(); - - console.log('Authenticated:', { isAuthenticated, loading }); - - if (loading) { - return ( -
-

Loading...

-
- ); - } - - return isAuthenticated ? : ; -}; diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx index 40f59cd..3a8fc9b 100644 --- a/src/components/Header/Header.tsx +++ b/src/components/Header/Header.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { useNavigate } from 'react-router-dom'; -import { useAuth } from '../../context/AuthContext'; import './_Header.scss'; import logo from '../../assets/coopcloud_logo_grey.svg'; @@ -10,13 +9,7 @@ interface HeaderProps { } export const Header: React.FC = ({ children }) => { - const { user, logout } = useAuth(); const navigate = useNavigate(); - - const handleLogout = async () => { - await logout(); - navigate('/login'); - }; return(
@@ -34,13 +27,6 @@ return( Servers - -
- {user?.username} - -
)} \ No newline at end of file diff --git a/src/components/Header/_Header.scss b/src/components/Header/_Header.scss index 9b8f02b..3219edb 100644 --- a/src/components/Header/_Header.scss +++ b/src/components/Header/_Header.scss @@ -78,50 +78,4 @@ font-size: $font-size-xl; } } - - .user-menu { - display: flex; - align-items: center; - gap: $spacing-lg; - - @media (max-width: 768px) { - width: 100%; - justify-content: space-between; - } - - .username { - font-weight: $font-weight-medium; - font-size: $font-size-base; - - @media (max-width: 480px) { - font-size: $font-size-sm; - } - } - - .logout-button { - background: rgba(255, 255, 255, 0.2); - border: 1px solid rgba(255, 255, 255, 0.4); - color: $text-primary; - padding: $spacing-sm $spacing-lg; - border-radius: $radius-md; - cursor: pointer; - transition: all $transition-base; - font-weight: $font-weight-medium; - - &:hover { - background: rgba(255, 255, 255, 0.3); - transform: translateY(-1px); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - } - - &:active { - transform: translateY(0); - } - - @media (max-width: 480px) { - padding: $spacing-sm $spacing-md; - font-size: $font-size-sm; - } - } - } } \ No newline at end of file diff --git a/src/context/AuthContext.tsx b/src/context/AuthContext.tsx deleted file mode 100644 index de24c85..0000000 --- a/src/context/AuthContext.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react'; -import { apiService } from '../services/api'; -import type { User } from '../types'; - -interface AuthContextType { - user: User | null; - isAuthenticated: boolean; - loading: boolean; - login: (credentials: { username: string; password: string }) => Promise; - logout: () => void; -} - -const AuthContext = createContext(undefined); - -export const useAuth = () => { - const context = useContext(AuthContext); - if (!context) { - throw new Error('useAuth must be used within an AuthProvider'); - } - return context; -}; - -interface AuthProviderProps { - children: ReactNode; -} - -export const AuthProvider: React.FC = ({ children }) => { - const [user, setUser] = useState(null); - const [isAuthenticated, setIsAuthenticated] = useState(false); - const [loading, setLoading] = useState(true); - - // Check for existing session on mount - useEffect(() => { - const storedUser = localStorage.getItem('user'); - - if (storedUser) { - try { - const parsedUser = JSON.parse(storedUser); - setUser(parsedUser); - setIsAuthenticated(true); - } catch (err) { - console.error('Failed to parse stored user:', err); - localStorage.removeItem('user'); - } - } - - setLoading(false); - }, []); - -const login = async (credentials: { username: string; password: string }) => { - const response = await apiService.login(credentials); - setUser(response.user); - setIsAuthenticated(true); - localStorage.setItem('user', JSON.stringify(response.user)); -}; - - const logout = () => { - apiService.logout(); - setUser(null); - setIsAuthenticated(false); - localStorage.removeItem('user'); - }; - - return ( - - {children} - - ); -}; diff --git a/src/routes/Authenticated/Apps/App.scss b/src/routes/Apps/App.scss similarity index 100% rename from src/routes/Authenticated/Apps/App.scss rename to src/routes/Apps/App.scss diff --git a/src/routes/Authenticated/Apps/App.tsx b/src/routes/Apps/App.tsx similarity index 96% rename from src/routes/Authenticated/Apps/App.tsx rename to src/routes/Apps/App.tsx index 4467a7a..636e15a 100644 --- a/src/routes/Authenticated/Apps/App.tsx +++ b/src/routes/Apps/App.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useState } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; -import { Header } from '../../../components/Header/Header'; -import { Terminal } from '../../../components/Terminal/Terminal'; -import { apiService } from '../../../services/api'; -import type { AbraApp } from '../../../types'; -import type { LogEntry } from '../../../services/mockApi'; +import { Header } from '../../components/Header/Header'; +import { Terminal } from '../../components/Terminal/Terminal'; +import { apiService } from '../../services/api'; +import type { AbraApp } from '../../types'; +import type { LogEntry } from '../../services/mockApi'; import './App.scss'; export const AppDetail: React.FC = () => { @@ -26,7 +26,7 @@ export const AppDetail: React.FC = () => { const fetchApp = async () => { try { if (isMockMode) { - const { mockApiService } = await import('../../../services/mockApi'); + const { mockApiService } = await import('../../services/mockApi'); const appsData = await mockApiService.getAppsGrouped(); const serverApps = appsData[server || '']; @@ -67,7 +67,7 @@ export const AppDetail: React.FC = () => { try { if (isMockMode) { - const { mockApiService } = await import('../../../services/mockApi'); + const { mockApiService } = await import('../../services/mockApi'); const onLog = (log: LogEntry) => { setTerminalLogs(prev => [...prev, log]); diff --git a/src/routes/Authenticated/Apps/Apps.scss b/src/routes/Apps/Apps.scss similarity index 100% rename from src/routes/Authenticated/Apps/Apps.scss rename to src/routes/Apps/Apps.scss diff --git a/src/routes/Authenticated/Apps/Apps.tsx b/src/routes/Apps/Apps.tsx similarity index 97% rename from src/routes/Authenticated/Apps/Apps.tsx rename to src/routes/Apps/Apps.tsx index f0aadb0..1901f5a 100644 --- a/src/routes/Authenticated/Apps/Apps.tsx +++ b/src/routes/Apps/Apps.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Header } from '../../../components/Header/Header'; -import { apiService } from '../../../services/api'; -import type { AbraApp, AppWithServer, ServerAppsResponse } from '../../../types'; +import { Header } from '../../components/Header/Header'; +import { apiService } from '../../services/api'; +import type { AbraApp, AppWithServer, ServerAppsResponse } from '../../types'; import './Apps.scss'; export const Apps: React.FC = () => { @@ -21,7 +21,7 @@ export const Apps: React.FC = () => { const fetchData = async () => { try { if (isMockMode) { - const { mockApiService } = await import('../../../services/mockApi'); + const { mockApiService } = await import('../../services/mockApi'); const data = await mockApiService.getAppsGrouped(); setAppsData(data); } else { diff --git a/src/routes/Authenticated/Dashboard/Dashboard.tsx b/src/routes/Dashboard/Dashboard.tsx similarity index 94% rename from src/routes/Authenticated/Dashboard/Dashboard.tsx rename to src/routes/Dashboard/Dashboard.tsx index 3788542..c8bd091 100644 --- a/src/routes/Authenticated/Dashboard/Dashboard.tsx +++ b/src/routes/Dashboard/Dashboard.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useState } from 'react'; -import { Header } from '../../../components/Header/Header'; +import { Header } from '../../components/Header/Header'; import { useNavigate } from 'react-router-dom'; -import { apiService } from '../../../services/api'; -import type { AbraApp, AbraServer } from '../../../types'; +import { apiService } from '../../services/api'; +import type { AbraApp, AbraServer } from '../../types'; import './_Dashboard.scss'; export const Dashboard: React.FC = () => { @@ -19,7 +19,7 @@ export const Dashboard: React.FC = () => { try { if (isMockMode) { // Use mock API in development - const { mockApiService } = await import('../../../services/mockApi'); + const { mockApiService } = await import('../../services/mockApi'); const [appsData, serversData] = await Promise.all([ mockApiService.getAppsGrouped(), mockApiService.getServers(), diff --git a/src/routes/Authenticated/Dashboard/_Dashboard.scss b/src/routes/Dashboard/_Dashboard.scss similarity index 100% rename from src/routes/Authenticated/Dashboard/_Dashboard.scss rename to src/routes/Dashboard/_Dashboard.scss diff --git a/src/routes/Login/LoginForm.scss b/src/routes/Login/LoginForm.scss deleted file mode 100644 index 90e259b..0000000 --- a/src/routes/Login/LoginForm.scss +++ /dev/null @@ -1,94 +0,0 @@ -@use '../../assets/scss/variables' as *; -@use '../../assets/scss/mixins' as *; - -.login-container { - @include flex-center; - min-height: 100vh; - width: 100%; - // @include gradient-primary; - background-color: $primary-light; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; -} - -.login-card { - @include card; - width: 100%; - max-width: 400px; - - h1 { - margin: 0 0 $spacing-sm; - font-size: $font-size-3xl; - color: $text-primary; - text-align: center; - } - - .login-subtitle { - text-align: center; - color: $text-secondary; - margin: 0 0 $spacing-2xl; - font-size: $font-size-sm; - } -} - -.form-group { - margin-bottom: $spacing-lg; - - label { - display: block; - margin-bottom: $spacing-sm; - color: $text-primary; - font-weight: $font-weight-medium; - font-size: $font-size-sm; - } - - input { - width: 100%; - padding: $spacing-md; - border: 2px solid $border-color; - border-radius: $radius-md; - font-size: $font-size-base; - transition: border-color $transition-base; - box-sizing: border-box; - - &:focus { - outline: none; - border-color: $primary; - } - - &:disabled { - background-color: $bg-secondary; - cursor: not-allowed; - } - } -} - -.error-message { - // background-color: rgba($error, 0.1); - // color: darken($error, 10%); - padding: $spacing-md; - border-radius: $radius-md; - margin-bottom: $spacing-md; - font-size: $font-size-sm; - // border-left: 4px solid $error; -} - -.login-button { - @include button-base; - @include gradient-primary; - width: 100%; - color: white; - font-size: $font-size-base; - - &:hover:not(:disabled) { - transform: translateY(-2px); - box-shadow: 0 8px 16px rgba($primary, 0.4); - } - - &:active:not(:disabled) { - transform: translateY(0); - } -} \ No newline at end of file diff --git a/src/routes/Login/LoginForm.tsx b/src/routes/Login/LoginForm.tsx deleted file mode 100644 index b9cdc3b..0000000 --- a/src/routes/Login/LoginForm.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import React, { useState } from 'react'; -import { useNavigate } from 'react-router-dom'; -import { useAuth } from '../../context/AuthContext'; -import './LoginForm.scss'; - -export const LoginForm: React.FC = () => { - const [username, setUsername] = useState(''); - const [password, setPassword] = useState(''); - const [error, setError] = useState(''); - const [loading, setLoading] = useState(false); - - const { login } = useAuth(); - const navigate = useNavigate(); - - const handleSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setError(''); - setLoading(true); - - try { - await login({ username, password }); - navigate('/dashboard'); - } catch (err) { - setError(err instanceof Error ? err.message : 'Login failed'); - } finally { - setLoading(false); - } - }; - - return ( -
-
-

Coop Cloud

-

Sign in to manage your applications

- -
- {error &&
{error}
} - -
- - setUsername(e.target.value)} - required - autoComplete="username" - disabled={loading} - /> -
- -
- - setPassword(e.target.value)} - required - autoComplete="current-password" - disabled={loading} - /> -
- - -
-
-
- ); -}; \ No newline at end of file diff --git a/src/routes/Authenticated/Servers/Server.scss b/src/routes/Servers/Server.scss similarity index 100% rename from src/routes/Authenticated/Servers/Server.scss rename to src/routes/Servers/Server.scss diff --git a/src/routes/Authenticated/Servers/Server.tsx b/src/routes/Servers/Server.tsx similarity index 96% rename from src/routes/Authenticated/Servers/Server.tsx rename to src/routes/Servers/Server.tsx index 5f38523..7c85bd4 100644 --- a/src/routes/Authenticated/Servers/Server.tsx +++ b/src/routes/Servers/Server.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useState } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; -import { Header } from '../../../components/Header/Header'; -import { Terminal } from '../../../components/Terminal/Terminal'; -import { apiService } from '../../../services/api'; -import type { AbraServer, ServerAppsResponse } from '../../../types'; -import type { LogEntry } from '../../../services/mockApi'; +import { Header } from '../../components/Header/Header'; +import { Terminal } from '../../components/Terminal/Terminal'; +import { apiService } from '../../services/api'; +import type { AbraServer, ServerAppsResponse } from '../../types'; +import type { LogEntry } from '../../services/mockApi'; import './Server.scss'; interface ServerWithApps extends AbraServer { @@ -35,7 +35,7 @@ export const Server: React.FC = () => { const fetchServer = async () => { try { if (isMockMode) { - const { mockApiService } = await import('../../../services/mockApi'); + const { mockApiService } = await import('../../services/mockApi'); const appsData = await mockApiService.getAppsGrouped(); const serversData = await mockApiService.getServers(); @@ -95,7 +95,7 @@ export const Server: React.FC = () => { try { if (isMockMode) { - const { mockApiService } = await import('../../../services/mockApi'); + const { mockApiService } = await import('../../services/mockApi'); const onLog = (log: LogEntry) => { setTerminalLogs(prev => [...prev, log]); diff --git a/src/routes/Authenticated/Servers/Servers.scss b/src/routes/Servers/Servers.scss similarity index 100% rename from src/routes/Authenticated/Servers/Servers.scss rename to src/routes/Servers/Servers.scss diff --git a/src/routes/Authenticated/Servers/Servers.tsx b/src/routes/Servers/Servers.tsx similarity index 97% rename from src/routes/Authenticated/Servers/Servers.tsx rename to src/routes/Servers/Servers.tsx index 95c369a..714ad89 100644 --- a/src/routes/Authenticated/Servers/Servers.tsx +++ b/src/routes/Servers/Servers.tsx @@ -1,8 +1,8 @@ import React, { useEffect, useMemo, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Header } from '../../../components/Header/Header'; -import { apiService } from '../../../services/api'; -import type { AbraServer, ServerAppsResponse } from '../../../types'; +import { Header } from '../../components/Header/Header'; +import { apiService } from '../../services/api'; +import type { AbraServer, ServerAppsResponse } from '../../types'; import './Servers.scss'; interface ServerWithStats extends AbraServer { @@ -27,7 +27,7 @@ export const Servers: React.FC = () => { const fetchData = async () => { try { if (isMockMode) { - const { mockApiService } = await import('../../../services/mockApi'); + const { mockApiService } = await import('../../services/mockApi'); const [serversData, appsData] = await Promise.all([ mockApiService.getServers(), mockApiService.getAppsGrouped(), diff --git a/src/types/index.ts b/src/types/index.ts index a3ab2ac..b4e1d1d 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,19 +1,3 @@ -export interface User { - id: string; - username: string; - email: string; -} - -export interface AuthResponse { - user: User; - token: string; -} - -export interface LoginCredentials { - username: string; - password: string; -} - export interface ApiError { message: string; status: number;