Front-end panel #1
					 19 changed files with 4972 additions and 0 deletions
				
			
		
							
								
								
									
										24
									
								
								src/Guestbooky-admin/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/Guestbooky-admin/.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
# Logs
 | 
			
		||||
logs
 | 
			
		||||
*.log
 | 
			
		||||
npm-debug.log*
 | 
			
		||||
yarn-debug.log*
 | 
			
		||||
yarn-error.log*
 | 
			
		||||
pnpm-debug.log*
 | 
			
		||||
lerna-debug.log*
 | 
			
		||||
 | 
			
		||||
node_modules
 | 
			
		||||
dist
 | 
			
		||||
dist-ssr
 | 
			
		||||
*.local
 | 
			
		||||
 | 
			
		||||
# Editor directories and files
 | 
			
		||||
.vscode/*
 | 
			
		||||
!.vscode/extensions.json
 | 
			
		||||
.idea
 | 
			
		||||
.DS_Store
 | 
			
		||||
*.suo
 | 
			
		||||
*.ntvs*
 | 
			
		||||
*.njsproj
 | 
			
		||||
*.sln
 | 
			
		||||
*.sw?
 | 
			
		||||
							
								
								
									
										38
									
								
								src/Guestbooky-admin/eslint.config.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/Guestbooky-admin/eslint.config.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
import js from '@eslint/js'
 | 
			
		||||
import globals from 'globals'
 | 
			
		||||
import react from 'eslint-plugin-react'
 | 
			
		||||
import reactHooks from 'eslint-plugin-react-hooks'
 | 
			
		||||
import reactRefresh from 'eslint-plugin-react-refresh'
 | 
			
		||||
 | 
			
		||||
export default [
 | 
			
		||||
  { ignores: ['dist'] },
 | 
			
		||||
  {
 | 
			
		||||
    files: ['**/*.{js,jsx}'],
 | 
			
		||||
    languageOptions: {
 | 
			
		||||
      ecmaVersion: 2020,
 | 
			
		||||
      globals: globals.browser,
 | 
			
		||||
      parserOptions: {
 | 
			
		||||
        ecmaVersion: 'latest',
 | 
			
		||||
        ecmaFeatures: { jsx: true },
 | 
			
		||||
        sourceType: 'module',
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    settings: { react: { version: '18.3' } },
 | 
			
		||||
    plugins: {
 | 
			
		||||
      react,
 | 
			
		||||
      'react-hooks': reactHooks,
 | 
			
		||||
      'react-refresh': reactRefresh,
 | 
			
		||||
    },
 | 
			
		||||
    rules: {
 | 
			
		||||
      ...js.configs.recommended.rules,
 | 
			
		||||
      ...react.configs.recommended.rules,
 | 
			
		||||
      ...react.configs['jsx-runtime'].rules,
 | 
			
		||||
      ...reactHooks.configs.recommended.rules,
 | 
			
		||||
      'react/jsx-no-target-blank': 'off',
 | 
			
		||||
      'react-refresh/only-export-components': [
 | 
			
		||||
        'warn',
 | 
			
		||||
        { allowConstantExport: true },
 | 
			
		||||
      ],
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										13
									
								
								src/Guestbooky-admin/index.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/Guestbooky-admin/index.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
<!doctype html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
  <head>
 | 
			
		||||
    <meta charset="UTF-8" />
 | 
			
		||||
    <link rel="icon" type="image/png" href="/src/assets/guestbooky.png" />
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
			
		||||
    <title>Guestbooky Admin Panel</title>
 | 
			
		||||
  </head>
 | 
			
		||||
  <body>
 | 
			
		||||
    <div id="root"></div>
 | 
			
		||||
    <script type="module" src="/src/main.jsx"></script>
 | 
			
		||||
  </body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										4391
									
								
								src/Guestbooky-admin/package-lock.json
									
										
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										4391
									
								
								src/Guestbooky-admin/package-lock.json
									
										
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										30
									
								
								src/Guestbooky-admin/package.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/Guestbooky-admin/package.json
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "guestbooky-admin",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "version": "0.0.0",
 | 
			
		||||
  "type": "module",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "dev": "vite",
 | 
			
		||||
    "build": "vite build",
 | 
			
		||||
    "lint": "eslint .",
 | 
			
		||||
    "preview": "vite preview"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "axios": "^1.7.7",
 | 
			
		||||
    "guestbooky-admin": "file:",
 | 
			
		||||
    "react": "^18.3.1",
 | 
			
		||||
    "react-dom": "^18.3.1"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@eslint/js": "^9.13.0",
 | 
			
		||||
    "@types/react": "^18.3.11",
 | 
			
		||||
    "@types/react-dom": "^18.3.1",
 | 
			
		||||
    "@vitejs/plugin-react": "^4.3.3",
 | 
			
		||||
    "eslint": "^9.13.0",
 | 
			
		||||
    "eslint-plugin-react": "^7.37.1",
 | 
			
		||||
    "eslint-plugin-react-hooks": "^5.0.0",
 | 
			
		||||
    "eslint-plugin-react-refresh": "^0.4.13",
 | 
			
		||||
    "globals": "^15.11.0",
 | 
			
		||||
    "vite": "^5.4.9"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/Guestbooky-admin/src/App.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/Guestbooky-admin/src/App.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
.header{
 | 
			
		||||
    font-size: 3em;
 | 
			
		||||
    word-spacing: 0.3em;
 | 
			
		||||
    letter-spacing: -0.05em;
 | 
			
		||||
    background: linear-gradient(180deg, hsl(15, 80%, 10%) 0%, hsl(15, 50%, 60%) 100%);
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    padding: 2ch;
 | 
			
		||||
    border-bottom: 0.1em solid hsl(15, 80%, 20%);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.header h1 {
 | 
			
		||||
    margin-inline: auto;
 | 
			
		||||
    width: 1200px;
 | 
			
		||||
    color: hsl(15, 100%, 90%);
 | 
			
		||||
    text-shadow: 0.01em 0.01em 0.01em hsl(15, 0%, 20%);
 | 
			
		||||
    font-family: "Carattere", cursive;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.content {
 | 
			
		||||
    width: 1200px;
 | 
			
		||||
    max-width: 1200px;
 | 
			
		||||
    margin-inline: auto;
 | 
			
		||||
    padding: 2ch;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								src/Guestbooky-admin/src/App.jsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/Guestbooky-admin/src/App.jsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
import {useState} from 'react'
 | 
			
		||||
import AdminPage from './components/AdminPage'
 | 
			
		||||
import LoginPage from './components/LoginPage'
 | 
			
		||||
 | 
			
		||||
import './App.css'
 | 
			
		||||
 | 
			
		||||
function App() {
 | 
			
		||||
    const [isLoggedIn, setIsLoggedIn] = useState(false)
 | 
			
		||||
 | 
			
		||||
    const handleLoggedIn = (newValue) => {
 | 
			
		||||
        setIsLoggedIn(newValue)
 | 
			
		||||
    }
 | 
			
		||||
    return (
 | 
			
		||||
        <>
 | 
			
		||||
          <div className="header"><h1>Guestbooky Admin</h1></div>
 | 
			
		||||
            <div className="content">
 | 
			
		||||
                {isLoggedIn ? <AdminPage className="content"/> :
 | 
			
		||||
                    <LoginPage onLoggedIn={handleLoggedIn} className="content"/>}
 | 
			
		||||
            </div>
 | 
			
		||||
        </>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default App
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								src/Guestbooky-admin/src/assets/guestbooky.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/Guestbooky-admin/src/assets/guestbooky.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 11 KiB  | 
							
								
								
									
										111
									
								
								src/Guestbooky-admin/src/components/AdminPage.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								src/Guestbooky-admin/src/components/AdminPage.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,111 @@
 | 
			
		|||
@keyframes smallFadeIn {
 | 
			
		||||
0% {
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    transform: translateY(20px);
 | 
			
		||||
}
 | 
			
		||||
    100% {
 | 
			
		||||
        opacity: 1;
 | 
			
		||||
        transform: translateY(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.list-item {
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    transform: translateY(20px);
 | 
			
		||||
    animation: smallFadeIn 0.5s ease-out forwards;
 | 
			
		||||
    animation-delay: calc(0.2s * var(--child-index));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.warning{
 | 
			
		||||
    background-color: hsla(15, 100%, 90%, 0.75);
 | 
			
		||||
    border: 0.2em solid hsla(15, 80%, 70%, 1);
 | 
			
		||||
    border-radius: 0.3em;
 | 
			
		||||
    padding: 2ch 1ch;
 | 
			
		||||
    width: fit-content;
 | 
			
		||||
    font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navigation{
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navigation button {
 | 
			
		||||
    font-size: 1em;
 | 
			
		||||
    margin: 2em;
 | 
			
		||||
    background: hsla(15, 60%, 80%, 1);
 | 
			
		||||
    border-radius: 0.2em;
 | 
			
		||||
    width: fit-content;
 | 
			
		||||
    padding: 0.8em 0.5em;
 | 
			
		||||
    font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navigation button:hover {
 | 
			
		||||
    background: hsla(15, 80%, 90%, 0.75);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul {
 | 
			
		||||
    list-style-type: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul li{
 | 
			
		||||
    line-height: 1.6em;
 | 
			
		||||
    display: grid;
 | 
			
		||||
    grid-row-gap: 2em;
 | 
			
		||||
    padding: 1em;
 | 
			
		||||
    grid-template-rows: auto 1fr;
 | 
			
		||||
    grid-template-columns: 1fr auto auto;
 | 
			
		||||
    font-family: 'Solway', serif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul li h2{
 | 
			
		||||
    align-self: center;
 | 
			
		||||
    grid-row: 1;
 | 
			
		||||
    background: linear-gradient(to right, hsl(15, 40%, 85%), hsla(15, 40%, 85%, 0));
 | 
			
		||||
    border-radius: 0.2em;
 | 
			
		||||
    padding: 0.5em 0 0.5em 0.5em;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul li h3{
 | 
			
		||||
    align-self: center;
 | 
			
		||||
    grid-row: 1;
 | 
			
		||||
    justify-self: right;
 | 
			
		||||
    padding-right: 0.5em;
 | 
			
		||||
    vertical-align: bottom;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
ul li button{
 | 
			
		||||
    grid-row: 1;
 | 
			
		||||
    justify-self: right;
 | 
			
		||||
    width: fit-content;
 | 
			
		||||
    border-radius: 0.5em;
 | 
			
		||||
    padding: 0.5em;
 | 
			
		||||
    font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
 | 
			
		||||
    background: hsla(15, 60%, 80%, 0.75);
 | 
			
		||||
}
 | 
			
		||||
ul li button:hover {
 | 
			
		||||
    background: hsla(15, 80%, 90%, 0.75);
 | 
			
		||||
}
 | 
			
		||||
.message-text {
 | 
			
		||||
    grid-row: 2;
 | 
			
		||||
    grid-column: 1 / 4;
 | 
			
		||||
    background-color: hsl(15, 50%, 90%);
 | 
			
		||||
    margin: 1em 0.5em;
 | 
			
		||||
    padding: 1em 0.5em;
 | 
			
		||||
    font-weight: 300;
 | 
			
		||||
    border-radius: 0.5em;
 | 
			
		||||
    box-shadow: 0.05em 0.05em 0.05em hsla(15, 20%, 20%, 0.5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.message-text p{
 | 
			
		||||
    line-height: 1.5em;
 | 
			
		||||
    text-align: justify;
 | 
			
		||||
    text-justify: inter-word;
 | 
			
		||||
    text-align-last: left;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								src/Guestbooky-admin/src/components/AdminPage.jsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/Guestbooky-admin/src/components/AdminPage.jsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
import useMessages from "../hooks/useMessages.js";
 | 
			
		||||
 | 
			
		||||
import './AdminPage.css'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const AdminPage = () => {
 | 
			
		||||
    const {messages, totalMessages, loading, error, removeMessage, page, nextPage, previousPage} = useMessages();
 | 
			
		||||
    const localeOptions = {
 | 
			
		||||
        weekday: 'long',
 | 
			
		||||
        year: 'numeric',
 | 
			
		||||
        month: 'long',
 | 
			
		||||
        day: 'numeric',
 | 
			
		||||
        hour: 'numeric',
 | 
			
		||||
        minute: 'numeric',
 | 
			
		||||
        second: 'numeric',
 | 
			
		||||
        timeZoneName: 'short'
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (loading) {
 | 
			
		||||
        return (<div className='warning'><p>Loading...</p></div>);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (messages.length === 0 && page > 1) {
 | 
			
		||||
        previousPage();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (messages.length === 0) {
 | 
			
		||||
        return (<div className='warning'><p>No messages.</p></div>);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <>
 | 
			
		||||
            <div className='warning'><p>{error ? 'Error : ' + error : 'Total messages: ' + totalMessages }</p></div>
 | 
			
		||||
            <ul>
 | 
			
		||||
            {messages.length > 0 ? messages.map((message, index) => (
 | 
			
		||||
                    <li key={message.id} className='list-item' style={{ '--child-index': index}} >
 | 
			
		||||
                        <h2>{message.author}</h2>
 | 
			
		||||
                        <h3>{new Date(message.timestamp).toLocaleString(navigator.language, localeOptions)}</h3>
 | 
			
		||||
                        <button onClick={() => removeMessage(message.id)}>Delete</button>
 | 
			
		||||
                        <div className='message-text'><p>{message.message}</p></div>
 | 
			
		||||
                    </li>
 | 
			
		||||
                )) : ''}
 | 
			
		||||
            </ul>
 | 
			
		||||
            <div className='navigation'>
 | 
			
		||||
                <button onClick={() => previousPage()}>Previous Page</button>
 | 
			
		||||
                <button onClick={() => nextPage()}>Next Page</button>
 | 
			
		||||
            </div>
 | 
			
		||||
        </>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
export default AdminPage;
 | 
			
		||||
							
								
								
									
										64
									
								
								src/Guestbooky-admin/src/components/LoginPage.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/Guestbooky-admin/src/components/LoginPage.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,64 @@
 | 
			
		|||
.login-form{
 | 
			
		||||
    display: flex;
 | 
			
		||||
    margin-inline: auto;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    vertical-align: center;
 | 
			
		||||
    margin-top: 20vh;
 | 
			
		||||
    background-color: hsla(15, 100%, 93%);
 | 
			
		||||
    width: fit-content;
 | 
			
		||||
    padding: 2em;
 | 
			
		||||
    border-radius: 1em;
 | 
			
		||||
    box-shadow: 0.05em 0.05em 0.05em hsla(15, 20%, 20%, 0.5);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.fade-in{
 | 
			
		||||
    opacity: 0;
 | 
			
		||||
    transform: translateY(10vh);
 | 
			
		||||
    animation: fadeIn 0.5s ease-out forwards;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@keyframes fadeIn {
 | 
			
		||||
    0% {
 | 
			
		||||
        opacity: 0;
 | 
			
		||||
        transform: translateY(20vh);
 | 
			
		||||
    }
 | 
			
		||||
    100% {
 | 
			
		||||
        opacity: 1;
 | 
			
		||||
        transform: translateY(0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
form {
 | 
			
		||||
    display: grid;
 | 
			
		||||
    grid-template-columns: auto 20ch;
 | 
			
		||||
    grid-column-gap: 2ch;
 | 
			
		||||
    grid-row-gap: 2ch;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    font-family: 'Solway', serif;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
form label {
 | 
			
		||||
    font-size: 1.4em;
 | 
			
		||||
    text-align: right;
 | 
			
		||||
    font-weight: 500;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
form input[type=text], form input[type=password] {
 | 
			
		||||
    font-size: 1.4em;
 | 
			
		||||
    border: 0.2em hsl(15, 100%, 50%) outset;
 | 
			
		||||
    border-radius: 0.2em;
 | 
			
		||||
    padding: 0.2em 0.2em;
 | 
			
		||||
    font-weight: 300;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
form button {
 | 
			
		||||
    margin-top: 1em;
 | 
			
		||||
    grid-column: 2 / 3;
 | 
			
		||||
    padding: 1em 2em;
 | 
			
		||||
    font-size: 1.4em;
 | 
			
		||||
    border-radius: 0.2em;
 | 
			
		||||
    background-color: hsl(15, 50%, 85%);
 | 
			
		||||
    font-family: 'Solway', serif;
 | 
			
		||||
    font-weight: 300;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								src/Guestbooky-admin/src/components/LoginPage.jsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/Guestbooky-admin/src/components/LoginPage.jsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
import React, { useRef } from 'react';
 | 
			
		||||
import useAuth from '../hooks/useAuth.js';
 | 
			
		||||
 | 
			
		||||
import './LoginPage.css'
 | 
			
		||||
 | 
			
		||||
const LoginPage = ({onLoggedIn}) =>
 | 
			
		||||
{
 | 
			
		||||
    const userInputRef = useRef(null);
 | 
			
		||||
    const passInputRef = useRef(null);
 | 
			
		||||
    const { authenticate, error } = useAuth();
 | 
			
		||||
 | 
			
		||||
    const handleSubmit = (e) => {
 | 
			
		||||
        e.preventDefault()
 | 
			
		||||
        const user = userInputRef.current.value;
 | 
			
		||||
        const pass = passInputRef.current.value;
 | 
			
		||||
 | 
			
		||||
        authenticate({user, pass})
 | 
			
		||||
            .then(() => {
 | 
			
		||||
                if (error === null) {
 | 
			
		||||
                    onLoggedIn(true)
 | 
			
		||||
                }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return(
 | 
			
		||||
        <>
 | 
			
		||||
        <div className="login-form fade-in">
 | 
			
		||||
            <form action="post" onSubmit={handleSubmit}>
 | 
			
		||||
                <label>User: </label><input type='text' name='username' placeholder=''
 | 
			
		||||
                                                 ref={userInputRef}></input>
 | 
			
		||||
                <label>Password: </label><input type='password' name='password' placeholder=''
 | 
			
		||||
                                                ref={passInputRef}></input>
 | 
			
		||||
                <button type='submit' className='login-button'>Login</button>
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
        </>
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default LoginPage;
 | 
			
		||||
							
								
								
									
										1
									
								
								src/Guestbooky-admin/src/environment/constants.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/Guestbooky-admin/src/environment/constants.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
export const API_URL = 'http://localhost:8080';
 | 
			
		||||
							
								
								
									
										19
									
								
								src/Guestbooky-admin/src/hooks/useAuth.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Guestbooky-admin/src/hooks/useAuth.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
import { useState } from "react";
 | 
			
		||||
import { post } from '../services/httpService.js'
 | 
			
		||||
 | 
			
		||||
const useAuth = () => {
 | 
			
		||||
    const [error, setError] = useState(null);
 | 
			
		||||
 | 
			
		||||
    const authenticate = async ({user, pass}) => {
 | 
			
		||||
        try {
 | 
			
		||||
            await post('/auth/login', {username: user, password: pass});
 | 
			
		||||
        }
 | 
			
		||||
        catch(err){
 | 
			
		||||
            setError(err);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return { authenticate, error };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default useAuth;
 | 
			
		||||
							
								
								
									
										67
									
								
								src/Guestbooky-admin/src/hooks/useMessages.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/Guestbooky-admin/src/hooks/useMessages.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,67 @@
 | 
			
		|||
import { useState, useEffect } from "react";
 | 
			
		||||
import { get, del } from '../services/httpService.js'
 | 
			
		||||
 | 
			
		||||
const useMessages = () => {
 | 
			
		||||
    const [messages, setMessages] = useState([]);
 | 
			
		||||
    const [loading, setLoading] = useState(true);
 | 
			
		||||
    const [error, setError] = useState(null);
 | 
			
		||||
    const [totalMessages, setTotalMessages] = useState(0);
 | 
			
		||||
    const [page, setPage] = useState(1);
 | 
			
		||||
    const amountPerPage = 10;
 | 
			
		||||
 | 
			
		||||
    useEffect(() => {
 | 
			
		||||
        const fetchMessages = async () => {
 | 
			
		||||
            try{
 | 
			
		||||
                setLoading(true);
 | 
			
		||||
                const data = await get('/message', {
 | 
			
		||||
                    headers: {
 | 
			
		||||
                        'Range': 'messages=' + ((page - 1) * amountPerPage) + '-' + (((page - 1) * amountPerPage) + amountPerPage),
 | 
			
		||||
                    },
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                const [, rangeInfo] = data.headers['content-range'].split(' ');
 | 
			
		||||
                const [, total] = rangeInfo.split('/');
 | 
			
		||||
 | 
			
		||||
                setTotalMessages(parseInt(total));
 | 
			
		||||
                setMessages(data.data);
 | 
			
		||||
            } catch(err) {
 | 
			
		||||
                setError(err);
 | 
			
		||||
            } finally {
 | 
			
		||||
                setLoading(false);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        fetchMessages();
 | 
			
		||||
    }, [page]);
 | 
			
		||||
 | 
			
		||||
    const removeMessage = async (id) => {
 | 
			
		||||
        try{
 | 
			
		||||
            await del('/message', {id: id});
 | 
			
		||||
            setMessages((prevlist) => prevlist.filter(message => message.id !== id));
 | 
			
		||||
            setTotalMessages(totalMessages - 1)
 | 
			
		||||
        }catch(err){
 | 
			
		||||
            setError(err);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const nextPage = () => {
 | 
			
		||||
        if(page * amountPerPage < totalMessages)
 | 
			
		||||
            setPage((page + 1));
 | 
			
		||||
    }
 | 
			
		||||
    const previousPage = () => {
 | 
			
		||||
        if (page > 1)
 | 
			
		||||
            setPage((page - 1));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        messages,
 | 
			
		||||
        totalMessages,
 | 
			
		||||
        loading,
 | 
			
		||||
        error,
 | 
			
		||||
        removeMessage,
 | 
			
		||||
        page,
 | 
			
		||||
        nextPage,
 | 
			
		||||
        previousPage
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default useMessages;
 | 
			
		||||
							
								
								
									
										40
									
								
								src/Guestbooky-admin/src/index.css
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/Guestbooky-admin/src/index.css
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
@import url(https://fonts.bunny.net/css?family=carattere:400|solway:300,500);
 | 
			
		||||
 | 
			
		||||
@media (prefers-reduced-motion: reduce){
 | 
			
		||||
    html:focus-within {
 | 
			
		||||
        scroll-behavior: auto;
 | 
			
		||||
    }
 | 
			
		||||
    *, *::before, *::after {
 | 
			
		||||
        animation-duration: 0.01ms !important;
 | 
			
		||||
        animation-iteration-count: 1 !important;
 | 
			
		||||
        transition: none;
 | 
			
		||||
        transition-duration: 0.01ms !important;
 | 
			
		||||
        scroll-behavior: auto !important;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
*, *::before, *::after{
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
    transition: all 0.05s ease;
 | 
			
		||||
    animation-duration: initial;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
* {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
 }
 | 
			
		||||
 | 
			
		||||
html:focus-within{
 | 
			
		||||
    scroll-behavior: smooth;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
img, picture, svg, video, canvas{
 | 
			
		||||
    max-width: 100%;
 | 
			
		||||
    height: auto;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
    background: linear-gradient(90deg, hsl(15, 80%, 90%) 0%, hsl(15, 80%, 98%) 5%, hsl(15, 80%, 98%) 95%,  hsl(15, 80%, 90%) 100%);
 | 
			
		||||
    color: hsl(15, 70%, 5%);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/Guestbooky-admin/src/main.jsx
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Guestbooky-admin/src/main.jsx
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
import { createRoot } from 'react-dom/client'
 | 
			
		||||
import './index.css'
 | 
			
		||||
import App from './App.jsx'
 | 
			
		||||
 | 
			
		||||
createRoot(document.getElementById('root')).render(
 | 
			
		||||
    <App />
 | 
			
		||||
)
 | 
			
		||||
							
								
								
									
										21
									
								
								src/Guestbooky-admin/src/services/httpService.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/Guestbooky-admin/src/services/httpService.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
import axios from 'axios';
 | 
			
		||||
import { API_URL } from '../environment/constants.js'
 | 
			
		||||
 | 
			
		||||
const httpClient = axios.create({
 | 
			
		||||
    baseURL: API_URL,
 | 
			
		||||
    withCredentials: true,
 | 
			
		||||
    timeout: 5000,
 | 
			
		||||
    headers: {'Content-Type': 'application/json',}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export const get = (endpoint, params) => {
 | 
			
		||||
    return httpClient.get(endpoint, { headers: params.headers, data: params.data});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const post = (endpoint, data) => {
 | 
			
		||||
    return httpClient.post(endpoint, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const del = (endpoint, data) => {
 | 
			
		||||
    return httpClient.delete(endpoint, {data: data });
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/Guestbooky-admin/vite.config.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/Guestbooky-admin/vite.config.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
import { defineConfig } from 'vite'
 | 
			
		||||
import react from '@vitejs/plugin-react'
 | 
			
		||||
 | 
			
		||||
// https://vite.dev/config/
 | 
			
		||||
export default defineConfig({
 | 
			
		||||
  plugins: [react()],
 | 
			
		||||
})
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue