From e5403ca2da6f0bedc346ed323828b40eb84673f8 Mon Sep 17 00:00:00 2001 From: Ivan Date: Sun, 14 Apr 2024 12:55:58 +0300 Subject: [PATCH 1/3] optimizations for server use --- captain-definition | 12 ++ src/pages/EnterAccount.jsx | 283 ++++++++++++++++++++++--------------- src/pages/Home.jsx | 76 ++++++---- webpack.config.js | 135 +++++++++--------- 4 files changed, 293 insertions(+), 213 deletions(-) create mode 100644 captain-definition diff --git a/captain-definition b/captain-definition new file mode 100644 index 0000000..338a4e5 --- /dev/null +++ b/captain-definition @@ -0,0 +1,12 @@ +{ + "schemaVersion": 2, + "dockerfileLines": [ + "FROM node", + "WORKDIR /app", + "COPY package*.json ./", + "RUN npm install", + "COPY . .", + "EXPOSE 3000", + "CMD [\"npm\", \"run\", \"start:dev\"]" + ] +} diff --git a/src/pages/EnterAccount.jsx b/src/pages/EnterAccount.jsx index 0fbc70c..df00423 100644 --- a/src/pages/EnterAccount.jsx +++ b/src/pages/EnterAccount.jsx @@ -5,123 +5,171 @@ import classes from "../assets/styles/enterAccount.module.scss"; import MyInput from "../components/MyInput.jsx"; import MyButton from "../components/MyButton.jsx"; import { UserData } from "../context"; -import { logIn, completeRegistration, verifyUserApi } from "../hooks/api/enterAccountApi.js"; +import { + logIn, + completeRegistration, + verifyUserApi, +} from "../hooks/api/enterAccountApi.js"; const EnterAccount = () => { - const [enter, setEnter] = useState("login"); - const navigate = useNavigate(); + const [enter, setEnter] = useState("login"); + const navigate = useNavigate(); - const [email, setEmail] = useState(""); - const [phone, setPhone] = useState(""); - const [login, setLogin] = useState(""); - const [surname, setSurname] = useState(""); - const [patronymic, setPatronymic] = useState(""); - const [password, setPassword] = useState(""); - const [repiedPassword, setRepiedPassword] = useState(""); + const [email, setEmail] = useState(""); + const [phone, setPhone] = useState(""); + const [login, setLogin] = useState(""); + const [surname, setSurname] = useState(""); + const [patronymic, setPatronymic] = useState(""); + const [password, setPassword] = useState(""); + const [repiedPassword, setRepiedPassword] = useState(""); - const {user, setUser} = useContext(UserData); - const [cookies, setCookie, removeCookie] = useCookies(["user"]); + const { user, setUser } = useContext(UserData); + const [cookies, setCookie, removeCookie] = useCookies(["user"]); - function cleanState() { - setEmail(""); - setPhone(""); - setLogin(""); - setSurname(""); - setPatronymic(""); - setPassword(""); - setRepiedPassword(""); - }; + function cleanState() { + setEmail(""); + setPhone(""); + setLogin(""); + setSurname(""); + setPatronymic(""); + setPassword(""); + setRepiedPassword(""); + } - function selectTag(tag) { - setEnter(tag); - cleanState(); - }; + function selectTag(tag) { + setEnter(tag); + cleanState(); + } - async function createUser() { - const response = await completeRegistration({ - login: login, - password: password, - repiedPassword: repiedPassword - }); + async function createUser() { + const response = await completeRegistration({ + login: login, + password: password, + repiedPassword: repiedPassword, + }); - if (response.status === 200) { - setUser({ - email: email, - phone: phone, - login: login, - surname: surname, - patronymic: patronymic, - password: password, - }); - setCookie("token", response.data.token); - cleanState(); - window.location.reload(); - // navigate("/"); - } - else { - console.log("Error") - } - }; - - async function logInToAccount() { - const response = await logIn(login, password) - - if (response.status === 200) { - setCookie("token", response.data.token); - cleanState(); - // setUser({ - // login: login - // }) - window.location.reload(); - // navigate("/") - // window.location.reload() - } - else { - console.log(response) - } + if (response.status === 200) { + setUser({ + email: email, + phone: phone, + login: login, + surname: surname, + patronymic: patronymic, + password: password, + }); + setCookie("token", response.data.token); + cleanState(); + window.location.reload(); + // navigate("/"); + } else { + console.log("Error"); } + } - return ( -
-
-
- + async function logInToAccount() { + const response = await logIn(login, password); + + if (response.status === 200) { + setCookie("token", response.data.token); + cleanState(); + // setUser({ + // login: login + // }) + window.location.reload(); + // navigate("/") + // window.location.reload() + } else { + console.log(response); + } + } + + return ( +
+
+
+ +
+
+
+ {enter === "login" ? ( +
+
+

Войти в аккаунт

-
-
- {enter === 'login' ?
-
-

Войти в аккаунт

-
-
- - -
-
- -
-
: -
-
-

Зарегестрировать учетную запись

-
-
- - - -
- {/*
+
+ + +
+
+ +
+
+ ) : ( +
+
+

Зарегистрировать учетную запись

+
+
+ + + +
+ {/*
@@ -132,15 +180,20 @@ const EnterAccount = () => {
*/} -
- createUser()}/> -
-
} -
+
+ createUser()} + />
-
+
+ )} +
- ) -} +
+
+ ); +}; -export default EnterAccount; \ No newline at end of file +export default EnterAccount; diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index 72adac5..cd11c39 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -1,40 +1,54 @@ import React, { useState } from "react"; -import { useNavigate, useLocation, useParams } from 'react-router-dom'; +import { useNavigate, useLocation, useParams } from "react-router-dom"; import classes from "../assets/styles/home.module.scss"; import MyButton from "../components/MyButton.jsx"; import MyInput from "../components/MyInput.jsx"; const Home = () => { - const [token, setToken] = useState(""); - const navigate = useNavigate(); + const [token, setToken] = useState(""); + const navigate = useNavigate(); - return ( -
-
-
-
Кажется вы попали на общую страницу.
-
Чтобы перейти к форме ввелите токен ниже или снова перейдите по ссылке.
-
-
-
-
-

Перейти к нужной форме

-
-
-
-
- setToken(e)}/> -
-
-
-
- navigate(`/forms/${token}`)}/> -
-
-
-
+ return ( +
+
+
+
+ Кажется вы попали на общую страницу. +
+
+ Чтобы перейти к форме введите токен ниже или снова перейдите по + ссылке. +
- ) -} +
+
+
+

Перейти к нужной форме

+
+
+
+
+ setToken(e)} + /> +
+
+
+
+ navigate(`/forms/${token}`)} + /> +
+
+
+
+
+ ); +}; -export default Home; \ No newline at end of file +export default Home; diff --git a/webpack.config.js b/webpack.config.js index 40ec78b..b940708 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,73 +1,74 @@ -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const MiniCssExtractPlugin = require('mini-css-extract-plugin'); -const path = require('path'); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); +const path = require("path"); module.exports = (env) => { + const isDev = env.mode === "development"; - const isDev = env.mode === 'development'; + const cssLoader = { + loader: "css-loader", + options: { + modules: { + localIdentName: isDev ? "[path][name]__[local]" : "[hash:base64:8]", + }, + }, + }; - const cssLoader = { - loader: "css-loader", - options: { - modules: { - localIdentName: isDev ? '[path][name]__[local]' : '[hash:base64:8]' - }, + const config = { + mode: env.mode ?? "development", + performance: { + hints: false, + maxEntrypointSize: 512000, + maxAssetSize: 512000, + }, + entry: "./src/index.js", + output: { + // filename: '[name].[contenthash].js', + filename: "bundle.js", + publicPath: "/", + path: path.resolve(__dirname, "dist"), + clean: true, + }, + plugins: [ + new HtmlWebpackPlugin({ + template: path.resolve(__dirname, "public", "index.html"), + }), + isDev + ? undefined + : new MiniCssExtractPlugin({ + filename: "css/[name].[contenthash:8].css", + chunkFilename: "css/[name].[contenthash:8].css", + }), + ], + module: { + rules: [ + { + test: /\.(scss|css)$/, + use: [ + isDev ? "style-loader" : MiniCssExtractPlugin.loader, + cssLoader, + "sass-loader", + ], }, - } + { + test: /\.(js|jsx)$/, + exclude: /node_modules/, + use: { + loader: "babel-loader", + options: { + presets: ["@babel/preset-env", "@babel/preset-react"], + }, + }, + }, + ], + }, + devServer: { + port: env.port ?? 3000, + historyApiFallback: true, + host: "0.0.0.0", + allowedHosts: "all", + }, + }; - const config = { - mode: env.mode ?? 'development', - performance: { - hints: false, - maxEntrypointSize: 512000, - maxAssetSize: 512000 - }, - entry: './src/index.js', - output: { - // filename: '[name].[contenthash].js', - filename: 'bundle.js', - publicPath: '/', - path: path.resolve(__dirname, 'dist'), - clean: true - }, - plugins: [ - new HtmlWebpackPlugin({template: path.resolve(__dirname, 'public', 'index.html')}), - isDev ? undefined : new MiniCssExtractPlugin({ - filename: 'css/[name].[contenthash:8].css', - chunkFilename: 'css/[name].[contenthash:8].css' - }) - ], - module: { - rules: [ - { - test: /\.(scss|css)$/, - use: [ - isDev ? 'style-loader' : MiniCssExtractPlugin.loader, - cssLoader, - 'sass-loader' - ], - }, - { - test: /\.(js|jsx)$/, - exclude: /node_modules/, - use: { - loader: "babel-loader", - options: { - presets: [ - '@babel/preset-env', - '@babel/preset-react' - ] - } - } - } - ] - }, - devServer: { - port: env.port ?? 3000, - open: true, - historyApiFallback: true - } - }; - - return config -} \ No newline at end of file + return config; +}; From ea0b47a06111862e9aebe04da9f669a21ddeb2f1 Mon Sep 17 00:00:00 2001 From: Alexander Lazarenko Date: Sun, 14 Apr 2024 13:06:22 +0300 Subject: [PATCH 2/3] Added autobuilder --- .gitea/workflows/publish.yaml | 56 +++++++++++++++++++++++++++++++++++ .gitignore | 3 +- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 .gitea/workflows/publish.yaml diff --git a/.gitea/workflows/publish.yaml b/.gitea/workflows/publish.yaml new file mode 100644 index 0000000..441b898 --- /dev/null +++ b/.gitea/workflows/publish.yaml @@ -0,0 +1,56 @@ +name: publish-main + +on: + push + +jobs: + release-image: + runs-on: ubuntu-latest + container: + image: catthehacker/ubuntu:act-latest + env: + DOCKER_ORG: krbl + RUNNER_TOOL_CACHE: /toolcache + IMAGE_NAME: minerva-frontend + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker BuildX + uses: docker/setup-buildx-action@v2 + with: + config-inline: | + [registry."gitea.unprism.ru"] + + - name: Login to DockerHub + uses: docker/login-action@v2 + with: + registry: gitea.unprism.ru + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Get Meta + id: meta + run: | + echo REPO_NAME=$(echo ${GITHUB_REPOSITORY} | awk -F"/" '{print $2}') >> $GITHUB_OUTPUT + echo REPO_VERSION=$(git describe --tags --always | sed 's/^v//') >> $GITHUB_OUTPUT + + - name: Extract branch name + shell: bash + run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT + id: extract_branch + + - name: Build and push + uses: docker/build-push-action@v4 + with: + context: . + file: ./Dockerfile + platforms: | + linux/amd64 + linux/arm64 + push: true + tags: | + gitea.unprism.ru/${{ env.DOCKER_ORG }}/${{ env.IMAGE_NAME }}:${{ steps.extract_branch.outputs.branch }} diff --git a/.gitignore b/.gitignore index b465c25..3132af0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ dist/ node_modules/ -package-lock.json \ No newline at end of file +package-lock.json +.DS_Store From 695cc690d98e32092db532c38a818065c6212f1e Mon Sep 17 00:00:00 2001 From: Ivan Date: Sun, 14 Apr 2024 15:01:04 +0300 Subject: [PATCH 3/3] registration fix --- src/App.jsx | 112 ++++++++++--------- src/components/NavBar.jsx | 83 +++++++------- src/hooks/validation/enterAccountValidate.js | 59 +++++----- src/pages/EnterAccount.jsx | 30 +++-- 4 files changed, 144 insertions(+), 140 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 6a2e781..8365017 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,13 +3,13 @@ import { Outlet, useNavigate } from "react-router-dom"; import { FormsData, UserData, TypeAnswerData, answersData } from "./context"; import { useCookies } from "react-cookie"; import { globalRender } from "./router/protectedRouting.js"; -import { verifyUserApi } from "./hooks/api/enterAccountApi.js" -import classes from "./assets/styles/app.module.scss" +import { verifyUserApi } from "./hooks/api/enterAccountApi.js"; +import classes from "./assets/styles/app.module.scss"; import NavBar from "./components/NavBar.jsx"; -import 'bootstrap/dist/css/bootstrap.min.css'; +import "bootstrap/dist/css/bootstrap.min.css"; import InputText from "./components/typeAnswer/InputText.jsx"; import TextArea from "./components/typeAnswer/TextArea.jsx"; -import YesNo from "./components/typeAnswer/YesNo.jsx" +import YesNo from "./components/typeAnswer/YesNo.jsx"; import InputDate from "./components/typeAnswer/InputDate.jsx"; import InputMultipleRadio from "./components/typeAnswer/InputMultipleRadio.jsx"; import InputRadio from "./components/typeAnswer/InputRadio.jsx"; @@ -17,61 +17,63 @@ import DropDownList from "./components/typeAnswer/DropDownList.jsx"; import InputFile from "./components/typeAnswer/InputFile.jsx"; const App = () => { - const navigate = useNavigate(); - const [forms, setForms] = useState([]); - const [user, setUser] = useState(false); - const [answersList, setAnswersList] = useState([]); - const [listTypeAnswer, setListTypeAnswer] = useState([ - {id: 1, text: 'Краткий ответ', typeTag: InputText}, - {id: 2, text: 'Расширенный ответ', typeTag: TextArea}, - {id: 3, text: 'Выбор из вариантов', typeTag: InputRadio}, - {id: 4, text: 'Множественный выбор', typeTag: InputMultipleRadio}, - {id: 5, text: 'Выпадающий список', typeTag: DropDownList}, - {id: 6, text: 'Да/Нет', typeTag: YesNo}, - {id: 7, text: 'Файл', typeTag: InputFile}, - {id: 8, text: 'Дата', typeTag: InputDate} - ]); + const navigate = useNavigate(); + const [forms, setForms] = useState([]); + const [user, setUser] = useState(false); + const [answersList, setAnswersList] = useState([]); + const [listTypeAnswer, setListTypeAnswer] = useState([ + { id: 1, text: "Краткий ответ", typeTag: InputText }, + { id: 2, text: "Расширенный ответ", typeTag: TextArea }, + { id: 3, text: "Выбор из вариантов", typeTag: InputRadio }, + { id: 4, text: "Множественный выбор", typeTag: InputMultipleRadio }, + { id: 5, text: "Выпадающий список", typeTag: DropDownList }, + { id: 6, text: "Да/Нет", typeTag: YesNo }, + { id: 7, text: "Файл", typeTag: InputFile }, + { id: 8, text: "Дата", typeTag: InputDate }, + ]); - // useEffect(() => globalRender(window.location.pathname, user, navigate)); - const [cookies, _, __] = useCookies(["user"]); + // useEffect(() => globalRender(window.location.pathname, user, navigate)); + const [cookies, _, __] = useCookies(["user"]); - useEffect(() => { - async function verifyUser() { - const response = await verifyUserApi(cookies.token); + useEffect(() => { + async function verifyUser() { + const response = await verifyUserApi(cookies.token); + console.log("app", user); - if (response) { - if (response.status === 200) { - setUser(response.data); - } - else { - console.log(response) - } - } + if (response) { + if (response.status === 200) { + setUser(response.data); + } else { + console.log(response); } + } + } - verifyUser(); - }, []) + verifyUser(); + }, []); - return ( - - - - -
-
-
- -
-
- -
-
-
-
-
-
-
- ) -} + return ( + + + + +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ ); +}; -export default App; \ No newline at end of file +export default App; diff --git a/src/components/NavBar.jsx b/src/components/NavBar.jsx index 462cc52..da19eaa 100644 --- a/src/components/NavBar.jsx +++ b/src/components/NavBar.jsx @@ -3,49 +3,46 @@ import { useCookies } from "react-cookie"; import classes from "../assets/styles/components/navbar.module.scss"; import { verifyUserApi } from "../hooks/api/enterAccountApi"; -const NavBar = ({navigate, auth, setAuth}) => { - // const [cookies, _, __] = useCookies(["user"]); +const NavBar = ({ navigate, auth, setAuth }) => { + useEffect(() => { + console.log("nav", auth); + }); - // useEffect(() => { - // async function verifyUser() { - // const response = await verifyUserApi(cookies.token); - - // if (response) { - // if (response.status === 200) { - // setAuth(response.data); - // } - // else { - // console.log(response) - // } - // } - // } - - // verifyUser() - // }, []); - - return ( -
-
-
-
- navigate("/")}>Главная - {auth ? - auth.is_admin ? navigate("/forms")}>Мои формы : : - } -
-
-
- {auth ? -
- navigate("/profile")}>Профиль ({auth.login}) -
: -
- navigate("/enter")}>Вход -
} -
-
+ return ( +
+
+
+
+ navigate("/")}>Главная + {auth ? ( + auth.is_admin ? ( + navigate("/forms")}>Мои формы + ) : ( + + ) + ) : ( + + )} +
- ) -} +
+ {auth ? ( +
+ navigate("/profile")}> + Профиль ({auth.login}) + +
+ ) : ( +
+ navigate("/enter")}> + Вход + +
+ )} +
+
+
+ ); +}; -export default NavBar; \ No newline at end of file +export default NavBar; diff --git a/src/hooks/validation/enterAccountValidate.js b/src/hooks/validation/enterAccountValidate.js index 6234291..52efee4 100644 --- a/src/hooks/validation/enterAccountValidate.js +++ b/src/hooks/validation/enterAccountValidate.js @@ -1,31 +1,38 @@ -const constructorAnswerValidate = (state, messageReject = "Ошибка", messageResolve = undefined) => { - return state ? - { - status: true, - message: messageResolve - } : - { - status: false, - message: messageReject - } -} +const constructorAnswerValidate = ( + state, + messageReject = "Ошибка", + messageResolve = undefined +) => { + return state + ? { + status: true, + message: messageResolve, + } + : { + status: false, + message: messageReject, + }; +}; const totalRegisterValidate = (data) => { - const listValidation = [ - constructorAnswerValidate(data.login.length, "Обязательное поле."), - // constructorAnswerValidate(data.surname.length, "Обязательное поле."), - // constructorAnswerValidate(data.email.length, "Обязательное поле."), - // constructorAnswerValidate(data.phone.length, "Обязательное поле."), - constructorAnswerValidate(data.password === data.repiedPassword, "Введенные пароли не совпадают."), - constructorAnswerValidate(data.password >= 8, "Пароль должен иметь более 8 символов.") - ] + const listValidation = [ + constructorAnswerValidate(data.login.length, "Обязательное поле."), + // constructorAnswerValidate(data.surname.length, "Обязательное поле."), + // constructorAnswerValidate(data.email.length, "Обязательное поле."), + // constructorAnswerValidate(data.phone.length, "Обязательное поле."), + constructorAnswerValidate( + data.password === data.repiedPassword, + "Введенные пароли не совпадают." + ), + // constructorAnswerValidate(data.password >= 8, "Пароль должен иметь более 8 символов.") + ]; - for (let value of listValidation) { - if (!value.status) { - return value - } + for (let value of listValidation) { + if (!value.status) { + return value; } - return { status: true } -} + } + return { status: true }; +}; -export { totalRegisterValidate, constructorAnswerValidate } \ No newline at end of file +export { totalRegisterValidate, constructorAnswerValidate }; diff --git a/src/pages/EnterAccount.jsx b/src/pages/EnterAccount.jsx index df00423..2a9b89a 100644 --- a/src/pages/EnterAccount.jsx +++ b/src/pages/EnterAccount.jsx @@ -49,18 +49,19 @@ const EnterAccount = () => { }); if (response.status === 200) { - setUser({ - email: email, - phone: phone, - login: login, - surname: surname, - patronymic: patronymic, - password: password, - }); + // setUser({ + // email: email, + // phone: phone, + // login: login, + // surname: surname, + // patronymic: patronymic, + // password: password, + // }); + const responseMe = await verifyUserApi(response.data.token); + setUser(responseMe.data); setCookie("token", response.data.token); cleanState(); - window.location.reload(); - // navigate("/"); + navigate("/"); } else { console.log("Error"); } @@ -71,13 +72,10 @@ const EnterAccount = () => { if (response.status === 200) { setCookie("token", response.data.token); + const responseMe = await verifyUserApi(response.data.token); + setUser(responseMe.data); cleanState(); - // setUser({ - // login: login - // }) - window.location.reload(); - // navigate("/") - // window.location.reload() + navigate("/"); } else { console.log(response); }