diff --git a/docker-compose.yml b/docker-compose.yml index e090d7e..9b2f09e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,7 +8,7 @@ services: ports: - "${MYSQL_HOST_PORT}:3306" volumes: - - ${MYSQL_VOLUME_NAME}:/var/lib/mysql + - volume:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"] interval: ${MYSQL_HEALTHCHECK_INTERVAL} @@ -54,4 +54,4 @@ services: - "${SWAGGER_UI_HOST_PORT}:8080" volumes: - ${MYSQL_VOLUME_NAME}: + volume: diff --git a/frontend/social-raiting/Dockerfile b/frontend/social-raiting/Dockerfile index 51f0246..0deb04e 100644 --- a/frontend/social-raiting/Dockerfile +++ b/frontend/social-raiting/Dockerfile @@ -2,11 +2,10 @@ FROM node:22-alpine AS builder WORKDIR /app -ARG VITE_API_BASE_URL=http://localhost:8080/api/ ENV VITE_API_BASE_URL=${VITE_API_BASE_URL} COPY package.json package-lock.json ./ -RUN npm ci +RUN npm i COPY . . RUN npm run build diff --git a/frontend/social-raiting/src/App.tsx b/frontend/social-raiting/src/App.tsx index cf439aa..c3179d7 100644 --- a/frontend/social-raiting/src/App.tsx +++ b/frontend/social-raiting/src/App.tsx @@ -3,6 +3,7 @@ import { Navigate, Route, Routes } from "react-router" import { isAuthenticated } from "./consts/auth" import { LoginPage } from "./pages/LoginPage/LoginPage" import { MainPage } from "./pages/MainPage/MainPage" +import { RegisterPage } from "./pages/RegisterPage/RegisterPage" import { UserHistoryPage } from "./pages/UserHistoryPage/UserHistoryPage" const ProtectedRoute = ({ children }: { children: ReactNode }) => { @@ -33,6 +34,14 @@ function App() { } /> + + + + } + /> } /> ) diff --git a/frontend/social-raiting/src/consts/axios.ts b/frontend/social-raiting/src/consts/axios.ts index fc49c3d..f11deeb 100644 --- a/frontend/social-raiting/src/consts/axios.ts +++ b/frontend/social-raiting/src/consts/axios.ts @@ -1,7 +1,7 @@ import axios from "axios"; import { getValidToken } from "./auth"; -const baseApiUrl = import.meta.env.VITE_API_BASE_URL || "http://localhost:8080/api/" +const baseApiUrl = import.meta.env.VITE_API_BASE_URL || "http://social-rating.nekiiinkognito.ru:8080/api/" export const apiInstance = axios.create({ baseURL: baseApiUrl, transformResponse: (r) => JSON.parse(r) }); diff --git a/frontend/social-raiting/src/pages/MainPage/MainPage.tsx b/frontend/social-raiting/src/pages/MainPage/MainPage.tsx index b3c1f15..0fd15b1 100644 --- a/frontend/social-raiting/src/pages/MainPage/MainPage.tsx +++ b/frontend/social-raiting/src/pages/MainPage/MainPage.tsx @@ -64,9 +64,14 @@ export const MainPage = () => { - + + + + diff --git a/frontend/social-raiting/src/pages/RegisterPage/RegisterPage.tsx b/frontend/social-raiting/src/pages/RegisterPage/RegisterPage.tsx new file mode 100644 index 0000000..f20a3d9 --- /dev/null +++ b/frontend/social-raiting/src/pages/RegisterPage/RegisterPage.tsx @@ -0,0 +1,172 @@ +import * as Form from "@radix-ui/react-form" +import { useMutation, useQueryClient } from "@tanstack/react-query" +import { Button, Callout, Card, Checkbox, Container, Flex, Heading, Link, Text, TextField } from "@radix-ui/themes" +import { useFormik } from "formik" +import { Link as RouterLink, useNavigate } from "react-router" +import * as yup from "yup" +import { apiInstance } from "../../consts/axios" + +const validationSchema = yup.object({ + email: yup.string().required().email(), + password: yup.string().required().min(8), +}) + +export const RegisterPage = () => { + const navigate = useNavigate() + const queryClient = useQueryClient() + + const form = useFormik({ + validationSchema, + initialValues: { + email: "", + password: "", + isAdmin: false, + }, + onSubmit: () => { + registerMutation.mutate() + }, + }) + + const registerMutation = useMutation({ + mutationKey: ["register-user"], + mutationFn: async () => { + const response = await apiInstance.post("auth/register", { + email: form.values.email, + password: form.values.password, + isAdmin: form.values.isAdmin, + }) + + return response.data + }, + onSuccess: async () => { + await queryClient.invalidateQueries({ queryKey: ["users"] }) + navigate("/", { replace: true }) + }, + }) + + const emailError = form.touched.email ? form.errors.email : undefined + const passwordError = form.touched.password ? form.errors.password : undefined + + return ( + + + + + + Back to users + + + Admin tools + + Register user + + Create a new user account. This page uses the protected admin registration endpoint. + + + + + + + + + + Email + + + {emailError ? ( + !!emailError}> + + {emailError} + + + ) : null} + + + + + + + + + + + + Password + + + {passwordError ? ( + !!passwordError}> + + {passwordError} + + + ) : null} + + + + + + + + + form.setFieldValue("isAdmin", checked === true)} + /> + Create as admin + + + {registerMutation.isError ? ( + + + Failed to register user. Make sure your account has admin access. + + + ) : null} + + + + + + + + + + + + + ) +}