Compare commits
4 Commits
main
...
debian12ne
Author | SHA1 | Date | |
---|---|---|---|
e3e2746cec | |||
1db7b9da80 | |||
e1ac9db05c | |||
7f74a740ae |
@@ -118,7 +118,7 @@ app.post("/api/updateUser", authenticate, async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Express backend server is running at http://localhost:${port}`);
|
console.log(`Express backend server is running at Port: ${port}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// error handling code
|
// error handling code
|
||||||
|
@@ -1,33 +1,42 @@
|
|||||||
services:
|
services:
|
||||||
# admin_react-frontend:
|
admin_react-frontend:
|
||||||
# container_name: bikelane-frontend_react-admin
|
container_name: bikelane-frontend_react-admin
|
||||||
# build: ./frontend_admin
|
build: ./frontend_admin
|
||||||
# ports:
|
ports:
|
||||||
# - "5001:5001"
|
- "5001:5001"
|
||||||
# environment:
|
networks:
|
||||||
# - CHOKIDAR_USEPOLLING=true
|
- proxynet
|
||||||
# volumes:
|
- bikelane_network
|
||||||
# - ./frontend_admin:/app
|
environment:
|
||||||
# - /app/node_modules
|
- CHOKIDAR_USEPOLLING=true
|
||||||
# restart: unless-stopped
|
volumes:
|
||||||
|
- ./frontend_admin:/app
|
||||||
|
- /app/node_modules
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
# user_react-frontend:
|
user_react-frontend:
|
||||||
# container_name: bikelane-frontend_react-user
|
container_name: bikelane-frontend_react-user
|
||||||
# build: ./frontend_user
|
build: ./frontend_user
|
||||||
# ports:
|
networks:
|
||||||
# - "5003:5003"
|
- proxynet
|
||||||
# environment:
|
- bikelane_network
|
||||||
# - CHOKIDAR_USEPOLLING=true
|
ports:
|
||||||
# volumes:
|
- "5003:5003"
|
||||||
# - ./frontend_user:/app
|
environment:
|
||||||
# - /app/node_modules
|
- CHOKIDAR_USEPOLLING=true
|
||||||
# restart: unless-stopped
|
volumes:
|
||||||
|
- ./frontend_user:/app
|
||||||
|
- /app/node_modules
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
bikelane-backend:
|
bikelane-backend:
|
||||||
container_name: bikelane-backend_express
|
container_name: bikelane-backend_express
|
||||||
build: ./backend
|
build: ./backend
|
||||||
ports:
|
ports:
|
||||||
- "5002:5002"
|
- "5002:5002"
|
||||||
|
networks:
|
||||||
|
- proxynet
|
||||||
|
- bikelane_network
|
||||||
environment:
|
environment:
|
||||||
DB_HOST: mysql
|
DB_HOST: mysql
|
||||||
DB_USER: root
|
DB_USER: root
|
||||||
@@ -43,6 +52,8 @@ services:
|
|||||||
container_name: bikelane-mysql
|
container_name: bikelane-mysql
|
||||||
image: mysql:8.0
|
image: mysql:8.0
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
networks:
|
||||||
|
- bikelane_network
|
||||||
environment:
|
environment:
|
||||||
MYSQL_ROOT_PASSWORD: D7Ze0lwV9hMrNQHdz1Q8yi0MIQuOO8
|
MYSQL_ROOT_PASSWORD: D7Ze0lwV9hMrNQHdz1Q8yi0MIQuOO8
|
||||||
MYSQL_DATABASE: bikelane
|
MYSQL_DATABASE: bikelane
|
||||||
@@ -53,3 +64,9 @@ services:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mysql-data:
|
mysql-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxynet:
|
||||||
|
external: true
|
||||||
|
bikelane_network:
|
||||||
|
external: false
|
||||||
|
@@ -1,12 +1,13 @@
|
|||||||
FROM node:20-alpine
|
# Build Stage
|
||||||
|
FROM node:20-alpine AS build
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production Stage
|
||||||
|
FROM nginx:stable-alpine AS production
|
||||||
|
COPY --from=build /app/build /usr/share/nginx/html
|
||||||
EXPOSE 5001
|
EXPOSE 5001
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
CMD ["npm", "start"]
|
|
||||||
|
@@ -1,67 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import "./App.css";
|
|
||||||
import Header from "./Header";
|
|
||||||
|
|
||||||
function App() {
|
|
||||||
const [username, setUsername] = useState("");
|
|
||||||
const [password, setPassword] = useState("");
|
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await fetch("http://localhost:5002/api/login", {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
console.log("Login successful");
|
|
||||||
// Handle successful login here
|
|
||||||
} else {
|
|
||||||
console.log("Login failed");
|
|
||||||
// Handle login error here
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Login error:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="username">Username:</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="username"
|
|
||||||
name="username"
|
|
||||||
value={username}
|
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label htmlFor="password">Password:</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
id="password"
|
|
||||||
name="password"
|
|
||||||
value={password}
|
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button type="submit">Login</button>
|
|
||||||
</form>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App;
|
|
@@ -1,30 +0,0 @@
|
|||||||
import React, { useState } from "react";
|
|
||||||
import Header from "./components/Header";
|
|
||||||
import LoginCard from "./components/LoginCard";
|
|
||||||
|
|
||||||
function App() {
|
|
||||||
const [showLogin, setShowLogin] = useState(false);
|
|
||||||
|
|
||||||
const handleLoginClick = () => setShowLogin(true);
|
|
||||||
const handleCloseLogin = () => setShowLogin(false);
|
|
||||||
|
|
||||||
const handleLoginSubmit = (username: string, password: string) => {
|
|
||||||
// Hier kannst du fetch einbauen
|
|
||||||
alert(`Login: ${username} / ${password}`);
|
|
||||||
setShowLogin(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="min-h-screen bg-white">
|
|
||||||
<Header onLoginClick={handleLoginClick} />
|
|
||||||
<main className="pt-20 w-full h-full flex flex-col items-center justify-start">
|
|
||||||
{/* Hier kommt später der Seiteninhalt */}
|
|
||||||
{showLogin && (
|
|
||||||
<LoginCard onClose={handleCloseLogin} onSubmit={handleLoginSubmit} />
|
|
||||||
)}
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App;
|
|
@@ -1,29 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import bike from "../../src/assets/bicycle-solid.svg";
|
|
||||||
import user from "../../src/assets/circle-user-solid.svg";
|
|
||||||
|
|
||||||
type HeaderProps = {
|
|
||||||
onLoginClick: () => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const Header: React.FC<HeaderProps> = ({ onLoginClick }) => (
|
|
||||||
<header className="fixed top-0 left-0 w-full h-20 bg-[#101c5e] flex items-center justify-between px-10 z-50 shadow">
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<img src={bike} alt="Bike Logo" className="h-10 w-10" />
|
|
||||||
<span className="text-white text-2xl font-semibold select-none">
|
|
||||||
Bikelane <b>Web</b>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center gap-4">
|
|
||||||
<img src={user} alt="User Icon" className="h-8 w-8" />
|
|
||||||
<button
|
|
||||||
onClick={onLoginClick}
|
|
||||||
className="bg-white text-[#101c5e] font-bold px-5 py-1 rounded-lg text-lg border-2 border-white hover:bg-gray-200 transition"
|
|
||||||
>
|
|
||||||
Login
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default Header;
|
|
@@ -1,72 +0,0 @@
|
|||||||
import React, { useRef, useEffect } from "react";
|
|
||||||
|
|
||||||
type LoginCardProps = {
|
|
||||||
onClose: () => void;
|
|
||||||
onSubmit: (username: string, password: string) => void;
|
|
||||||
};
|
|
||||||
|
|
||||||
const LoginCard: React.FC<LoginCardProps> = ({ onClose, onSubmit }) => {
|
|
||||||
const [username, setUsername] = React.useState("");
|
|
||||||
const [password, setPassword] = React.useState("");
|
|
||||||
const cardRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handler = (e: MouseEvent) => {
|
|
||||||
if (cardRef.current && !cardRef.current.contains(e.target as Node)) {
|
|
||||||
onClose();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
document.addEventListener("mousedown", handler);
|
|
||||||
return () => document.removeEventListener("mousedown", handler);
|
|
||||||
}, [onClose]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-30 flex items-center justify-center z-40">
|
|
||||||
<div
|
|
||||||
ref={cardRef}
|
|
||||||
className="bg-gray-200 rounded-xl shadow-lg w-full max-w-md flex flex-col"
|
|
||||||
>
|
|
||||||
<div className="bg-[#101c5e] text-white rounded-t-xl px-8 py-4 text-center text-2xl font-bold">
|
|
||||||
Login
|
|
||||||
</div>
|
|
||||||
<form
|
|
||||||
className="flex flex-col gap-5 px-8 py-6"
|
|
||||||
onSubmit={(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
onSubmit(username, password);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<label className="font-bold">
|
|
||||||
username
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
className="mt-2 w-full rounded-full px-5 py-2 bg-gray-400 outline-none"
|
|
||||||
value={username}
|
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
|
||||||
autoFocus
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<label className="font-bold">
|
|
||||||
password
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
className="mt-2 w-full rounded-full px-5 py-2 bg-gray-400 outline-none"
|
|
||||||
value={password}
|
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="bg-[#101c5e] text-white font-bold rounded-lg py-3 mt-6 text-xl hover:bg-[#203080] transition"
|
|
||||||
>
|
|
||||||
Login
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default LoginCard;
|
|
@@ -16,7 +16,7 @@ function App() {
|
|||||||
const [isAuthenticated, setIsAuthenticated] = useState(
|
const [isAuthenticated, setIsAuthenticated] = useState(
|
||||||
!!Cookies.get("token")
|
!!Cookies.get("token")
|
||||||
);
|
);
|
||||||
const [showLogin, setShowLogin] = useState(false);
|
const [, setShowLogin] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated }}>
|
<AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated }}>
|
||||||
|
@@ -18,7 +18,7 @@ const LoginCard: React.FC<LoginCardProps> = ({ onClose, changeAuth }) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setError("");
|
setError("");
|
||||||
try {
|
try {
|
||||||
const response = await fetch("http://localhost:5002/api/login", {
|
const response = await fetch("http://45.133.75.67:5002/api/login", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ username, password }),
|
body: JSON.stringify({ username, password }),
|
||||||
|
@@ -33,7 +33,7 @@ export function useUsers(): UserReturn {
|
|||||||
|
|
||||||
const fetchUsers = async () => {
|
const fetchUsers = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("http://localhost:5002/api/getAllUsers", {
|
const response = await fetch("http://45.133.75.67:5002/api/getAllUsers", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: headers,
|
headers: headers,
|
||||||
});
|
});
|
||||||
@@ -50,7 +50,7 @@ export function useUsers(): UserReturn {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const deleteUser = (id: number) => {
|
const deleteUser = (id: number) => {
|
||||||
fetch("http://localhost:5002/api/deleteUser", {
|
fetch("http://45.133.75.67:5002/api/deleteUser", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ id: id }),
|
body: JSON.stringify({ id: id }),
|
||||||
headers: {
|
headers: {
|
||||||
@@ -109,7 +109,7 @@ export function useUsers(): UserReturn {
|
|||||||
console.log("Sending user data:", userData);
|
console.log("Sending user data:", userData);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch("http://localhost:5002/api/updateUser", {
|
const response = await fetch("http://45.133.75.67:5002/api/updateUser", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify(userData),
|
body: JSON.stringify(userData),
|
||||||
headers: {
|
headers: {
|
||||||
|
@@ -6,7 +6,7 @@ export const loginUser = async (
|
|||||||
password: string
|
password: string
|
||||||
): Promise<boolean> => {
|
): Promise<boolean> => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("http://localhost:5002/api/login", {
|
const response = await fetch("http://45.133.75.67:5002/api/login", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ username, password }),
|
body: JSON.stringify({ username, password }),
|
||||||
@@ -31,7 +31,7 @@ export const logout = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const deleteUser = (id: number) => {
|
export const deleteUser = (id: number) => {
|
||||||
fetch("http://localhost:5002/api/deleteUser", {
|
fetch("http://45.133.75.67:5002/api/deleteUser", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ id: id }),
|
body: JSON.stringify({ id: id }),
|
||||||
headers: {
|
headers: {
|
||||||
@@ -53,7 +53,7 @@ export const deleteUser = (id: number) => {
|
|||||||
|
|
||||||
export const replaceUsers = async () => {
|
export const replaceUsers = async () => {
|
||||||
localStorage.removeItem("users");
|
localStorage.removeItem("users");
|
||||||
await fetch("http://localhost:5002/api/getAllUsers", {
|
await fetch("http://45.133.75.67:5002/api/getAllUsers", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${Cookies.get("token")}`,
|
Authorization: `Bearer ${Cookies.get("token")}`,
|
||||||
@@ -104,7 +104,7 @@ export const updateUserFunc = async (userID: number) => {
|
|||||||
console.log("Sending user data:", userData);
|
console.log("Sending user data:", userData);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch("http://localhost:5002/api/updateUser", {
|
const response = await fetch("http://45.133.75.67:5002/api/updateUser", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify(userData),
|
body: JSON.stringify(userData),
|
||||||
headers: {
|
headers: {
|
||||||
|
@@ -1,12 +1,13 @@
|
|||||||
FROM node:20-alpine
|
# Build Stage
|
||||||
|
FROM node:20-alpine AS build
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm install
|
RUN npm install
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Production Stage
|
||||||
|
FROM nginx:stable-alpine AS production
|
||||||
|
COPY --from=build /app/build /usr/share/nginx/html
|
||||||
EXPOSE 5003
|
EXPOSE 5003
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
CMD ["npm", "start"]
|
|
||||||
|
Reference in New Issue
Block a user