diff --git a/README.md b/README.md index 03472fb..6eb99c1 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# Nyanberg - Paradox Games Save Viewer +# paradox-save-parser-frontend diff --git a/src/app/favicon.ico b/public/favicon.ico similarity index 100% rename from src/app/favicon.ico rename to public/favicon.ico diff --git a/src/app/page.tsx b/src/app/browse/page.tsx similarity index 91% rename from src/app/page.tsx rename to src/app/browse/page.tsx index 0e2dac2..9296b8a 100644 --- a/src/app/page.tsx +++ b/src/app/browse/page.tsx @@ -1,11 +1,11 @@ 'use client' + import { AgGridReact } from 'ag-grid-react' -import styles from './page.module.css' import { AllCommunityModule, themeQuartz } from 'ag-grid-community' import { useState, useEffect } from 'react' import { colorSchemeDark } from 'ag-grid-community' -export default function Home() { +export default function BrowsePage() { const [agTheme, setAgTheme] = useState(themeQuartz) useEffect(() => { @@ -23,7 +23,7 @@ export default function Home() { }, []) return ( -
+
) { +export default function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { ModuleRegistry.registerModules([AllCommunityModule]) return ( - Nyanberg - Paradox Games Save Viewer + paradox-save-parser-frontend - {children} + + + {children} + ) } diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx new file mode 100644 index 0000000..e12eb1b --- /dev/null +++ b/src/app/login/page.tsx @@ -0,0 +1,98 @@ +'use client' + +import { useState } from 'react' +import { authService } from '@/services/authService' + +export default function LoginPage() { + const [formData, setFormData] = useState({ + email: '', + password: '', + stayLoggedIn: true, + }) + + const [error, setError] = useState('') + + const handleChange = (e: React.ChangeEvent) => { + const { name, value, type, checked } = e.target + setFormData((prev) => ({ + ...prev, + [name]: type === 'checkbox' ? checked : value, + })) + } + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + try { + console.log('Log in:', formData) + const result = await authService.login(formData.email, formData.password) + console.log('Logged in:', result) + } catch (err: any) { + console.error(err.message) + setError(err.message) + } + } + + return ( +
+

Login

+ + {error && ( +
+ {error} +
+ )} + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
+ ) +} diff --git a/src/app/page.module.css b/src/app/page.module.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/register/page.tsx b/src/app/register/page.tsx new file mode 100644 index 0000000..f85e783 --- /dev/null +++ b/src/app/register/page.tsx @@ -0,0 +1,121 @@ +'use client' + +import { useState } from 'react' +import { useRouter } from 'next/navigation' +import { authService } from '@/services/authService' + +export default function RegisterPage() { + const router = useRouter() + + const [formData, setFormData] = useState({ + name: '', + email: '', + password: '', + confirmPassword: '', + }) + + const [error, setError] = useState('') + + const handleChange = (e: React.ChangeEvent) => { + setFormData((prev) => ({ + ...prev, + [e.target.name]: e.target.value, + })) + } + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + try { + if (formData.password !== formData.confirmPassword) { + throw new Error('Passwords do not match.') + } + + console.log('Register', formData) + const result = await authService.register(formData.name, formData.email, formData.password) + console.log('Registered:', result) + + router.push('/login') // Redirect after success + } catch (err: any) { + console.error(err.message) + setError(err.message) + } + } + + return ( +
+

Register

+ + {error && ( +
+ {error} +
+ )} + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
+ ) +} diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx new file mode 100644 index 0000000..dd1ec4c --- /dev/null +++ b/src/components/Navbar.tsx @@ -0,0 +1,27 @@ +'use client' + +import Link from 'next/link' +import { font_Hack } from '@/utils/myFonts' + +export default function Navbar() { + return ( + + ) +} diff --git a/src/services/authService.ts b/src/services/authService.ts new file mode 100644 index 0000000..d7ba899 --- /dev/null +++ b/src/services/authService.ts @@ -0,0 +1,46 @@ +class AuthService { + private API_BASE = '/api/auth' + + private hashPassword(password: string) { + // TODO: password hashing + return password + } + + async login(email: string, password: string) { + const response = await fetch(`${this.API_BASE}/login`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + email, + password: this.hashPassword(password), + }), + }) + + if (!response.ok) { + throw new Error('Login failed') + } + + return await response.json() + } + + async register(name: string, email: string, password: string) { + const response = await fetch(`${this.API_BASE}/register`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + name, + email, + password: this.hashPassword(password), + }), + }) + + if (!response.ok) { + throw new Error('Registration failed') + } + + return await response.json() + } +} + +// Export a singleton instance +export const authService = new AuthService() diff --git a/src/utils/myFonts.ts b/src/utils/myFonts.ts new file mode 100644 index 0000000..8830392 --- /dev/null +++ b/src/utils/myFonts.ts @@ -0,0 +1,36 @@ +import localFont from 'next/font/local' +import { IBM_Plex_Sans } from 'next/font/google' + +export const font_IbmPlexSans = IBM_Plex_Sans({ + subsets: ['latin'], + weight: ['400', '500', '700'], + display: 'swap', + variable: '--font-ibm-plex-sans', +}) + +export const font_Hack = localFont({ + src: [ + { + path: '../../public/fonts/hack-v3.003/Hack-Regular.ttf', + weight: '400', + style: 'normal', + }, + { + path: '../../public/fonts/hack-v3.003/Hack-Bold.ttf', + weight: '700', + style: 'normal', + }, + { + path: '../../public/fonts/hack-v3.003/Hack-Italic.ttf', + weight: '400', + style: 'italic', + }, + { + path: '../../public/fonts/hack-v3.003/Hack-BoldItalic.ttf', + weight: '700', + style: 'italic', + }, + ], + display: 'swap', + variable: '--font-hack', +})