diff --git a/SurveyBackend/SurveyBackend.API/Program.cs b/SurveyBackend/SurveyBackend.API/Program.cs index f0669cb..da19cc8 100644 --- a/SurveyBackend/SurveyBackend.API/Program.cs +++ b/SurveyBackend/SurveyBackend.API/Program.cs @@ -92,6 +92,19 @@ public class Program c.IncludeXmlComments(filePath); }); + builder.Services.AddCors(options => + { + options.AddPolicy("AllowAll", + policyBuilder => + { + policyBuilder + .AllowAnyOrigin() + .AllowAnyHeader() + .AllowAnyMethod() + .SetIsOriginAllowedToAllowWildcardSubdomains(); + }); + }); + var app = builder.Build(); if (app.Environment.IsDevelopment()) @@ -102,6 +115,8 @@ public class Program options.SwaggerEndpoint("/api/swagger/v1/swagger.json", "Survey Backend V1"); options.RoutePrefix = "api/swagger"; }); + + app.UseCors("AllowAll"); } app.UseMiddleware(); diff --git a/SurveyBackend/SurveyBackend.Infrastructure/Data/Migrations/20250420143302_Changing questions logic.Designer.cs b/SurveyBackend/SurveyBackend.Infrastructure/Data/Migrations/20250420143302_Changing questions logic.Designer.cs new file mode 100644 index 0000000..06427fb --- /dev/null +++ b/SurveyBackend/SurveyBackend.Infrastructure/Data/Migrations/20250420143302_Changing questions logic.Designer.cs @@ -0,0 +1,308 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using SurveyBackend.Infrastructure.Data; + +#nullable disable + +namespace SurveyBackend.Infrastructure.Data.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("20250420143302_Changing questions logic")] + partial class Changingquestionslogic + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.15"); + + modelBuilder.Entity("GroupUser", b => + { + b.Property("GroupsId") + .HasColumnType("INTEGER"); + + b.Property("UsersId") + .HasColumnType("INTEGER"); + + b.HasKey("GroupsId", "UsersId"); + + b.HasIndex("UsersId"); + + b.ToTable("GroupUser"); + }); + + modelBuilder.Entity("SurveyBackend.Core.Models.Group", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Label") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Groups"); + }); + + modelBuilder.Entity("SurveyBackend.Core.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Email") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.Answer", b => + { + b.Property("CompletionId") + .HasColumnType("INTEGER"); + + b.Property("QuestionId") + .HasColumnType("INTEGER"); + + b.Property("AnswerText") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("CompletionId", "QuestionId"); + + b.HasIndex("QuestionId"); + + b.ToTable("Answers"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.AnswerVariant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("QuestionId") + .HasColumnType("INTEGER"); + + b.Property("Text") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("QuestionId"); + + b.ToTable("AnswerVariant"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.Completion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("FinishedAt") + .HasColumnType("TEXT"); + + b.Property("SurveyId") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("SurveyId"); + + b.ToTable("Completions"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.QuestionBase", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(34) + .HasColumnType("TEXT"); + + b.Property("SurveyId") + .HasColumnType("INTEGER"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("SurveyId"); + + b.ToTable("Questions"); + + b.HasDiscriminator().HasValue("QuestionBase"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.Survey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("CreatedBy") + .HasColumnType("INTEGER"); + + b.Property("Description") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("CreatedBy"); + + b.ToTable("Surveys"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.MultipleAnswerQuestion", b => + { + b.HasBaseType("SurveyLib.Core.Models.QuestionBase"); + + b.HasDiscriminator().HasValue("MultipleAnswerQuestion"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.SingleAnswerQuestion", b => + { + b.HasBaseType("SurveyLib.Core.Models.QuestionBase"); + + b.HasDiscriminator().HasValue("SingleAnswerQuestion"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.QuestionVariants.TextQuestion", b => + { + b.HasBaseType("SurveyLib.Core.Models.QuestionBase"); + + b.HasDiscriminator().HasValue("TextQuestion"); + }); + + modelBuilder.Entity("GroupUser", b => + { + b.HasOne("SurveyBackend.Core.Models.Group", null) + .WithMany() + .HasForeignKey("GroupsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SurveyBackend.Core.Models.User", null) + .WithMany() + .HasForeignKey("UsersId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.Answer", b => + { + b.HasOne("SurveyLib.Core.Models.Completion", "Completion") + .WithMany("Answers") + .HasForeignKey("CompletionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("SurveyLib.Core.Models.QuestionBase", "Question") + .WithMany("Answers") + .HasForeignKey("QuestionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Completion"); + + b.Navigation("Question"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.AnswerVariant", b => + { + b.HasOne("SurveyLib.Core.Models.QuestionBase", "Question") + .WithMany("AnswerVariants") + .HasForeignKey("QuestionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Question"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.Completion", b => + { + b.HasOne("SurveyLib.Core.Models.Survey", "Survey") + .WithMany("Completions") + .HasForeignKey("SurveyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Survey"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.QuestionBase", b => + { + b.HasOne("SurveyLib.Core.Models.Survey", "Survey") + .WithMany("Questions") + .HasForeignKey("SurveyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Survey"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.Survey", b => + { + b.HasOne("SurveyBackend.Core.Models.User", null) + .WithMany() + .HasForeignKey("CreatedBy") + .OnDelete(DeleteBehavior.SetNull); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.Completion", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.QuestionBase", b => + { + b.Navigation("AnswerVariants"); + + b.Navigation("Answers"); + }); + + modelBuilder.Entity("SurveyLib.Core.Models.Survey", b => + { + b.Navigation("Completions"); + + b.Navigation("Questions"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SurveyFrontend/package-lock.json b/SurveyFrontend/package-lock.json index 38b21e5..24c315c 100644 --- a/SurveyFrontend/package-lock.json +++ b/SurveyFrontend/package-lock.json @@ -11,6 +11,7 @@ "@formkit/tempo": "^0.1.2", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-router-dom": "^7.5.2", "uuid": "^11.1.0" }, "devDependencies": { @@ -1731,6 +1732,15 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2626,6 +2636,45 @@ "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.5.2.tgz", + "integrity": "sha512-9Rw8r199klMnlGZ8VAsV/I8WrIF6IyJ90JQUdboupx1cdkgYqwnrYjH+I/nY/7cA1X5zia4mDJqH36npP7sxGQ==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0", + "turbo-stream": "2.4.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.5.2.tgz", + "integrity": "sha512-yk1XW8Fj7gK7flpYBXF3yzd2NbX6P7Kxjvs2b5nu1M04rb5pg/Zc4fGdBNTeT4eDYL2bvzWNyKaIMJX/RKHTTg==", + "license": "MIT", + "dependencies": { + "react-router": "7.5.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2720,6 +2769,12 @@ "semver": "bin/semver.js" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2798,6 +2853,12 @@ "typescript": ">=4.8.4" } }, + "node_modules/turbo-stream": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/turbo-stream/-/turbo-stream-2.4.0.tgz", + "integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==", + "license": "ISC" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/SurveyFrontend/package.json b/SurveyFrontend/package.json index 150e7f9..632ec27 100644 --- a/SurveyFrontend/package.json +++ b/SurveyFrontend/package.json @@ -13,6 +13,7 @@ "@formkit/tempo": "^0.1.2", "react": "^19.0.0", "react-dom": "^19.0.0", + "react-router-dom": "^7.5.2", "uuid": "^11.1.0" }, "devDependencies": { diff --git a/SurveyFrontend/src/App.tsx b/SurveyFrontend/src/App.tsx index f5a93c5..8acf6f3 100644 --- a/SurveyFrontend/src/App.tsx +++ b/SurveyFrontend/src/App.tsx @@ -1,11 +1,35 @@ -import React from 'react'; import './App.css' -import Questions from './pages/Questions.tsx' +import {BrowserRouter, Navigate, Route, Routes} from "react-router-dom"; +import {SurveyCreateAndEditingPage} from "./pages/SurveyCreateAndEditingPage/SurveyCreateAndEditingPage.tsx"; +import Survey from "./components/Survey/Survey.tsx"; +import SettingSurvey from "./components/SettingSurvey/SettingSurvey.tsx"; +import {MySurveysPage} from "./pages/MySurveysPage/MySurveysPage.tsx"; +import {Results} from "./components/Results/Results.tsx"; +import {MySurveyList} from "./components/MySurveyList/MySurveyList.tsx"; -const App: React.FC = () => { - return ( - - ) +const App = () => { + return( + + + } /> + + }> + } /> + } /> + + + }> + } /> + + + }> + } /> + } /> + } /> + + + + ); } diff --git a/SurveyFrontend/src/api/AuthApi.ts b/SurveyFrontend/src/api/AuthApi.ts new file mode 100644 index 0000000..60e3a84 --- /dev/null +++ b/SurveyFrontend/src/api/AuthApi.ts @@ -0,0 +1,37 @@ +import {BASE_URL, createRequestConfig, handleResponse} from "./BaseApi.ts"; + +interface IAuthData{ + email: string; + password: string; +} + +interface IRegistrationData extends IAuthData{ + username: string; + firstName: string; + lastName: string; +} + +export const registerUser = async (data: IRegistrationData) => { + try{ + const response = await fetch(`${BASE_URL}/auth/register`, { + ...createRequestConfig('POST'), body: JSON.stringify(data), + }) + return await handleResponse(response); + } catch (error){ + console.error("Registration error:", error); + throw error; + } +} + +export const authUser = async (data: IAuthData) => { + try{ + const response = await fetch(`${BASE_URL}/auth/login`, { + ...createRequestConfig('POST'), body: JSON.stringify(data), + }) + return await handleResponse(response); + } + catch(error){ + console.error("Login error:", error); + throw error; + } +} \ No newline at end of file diff --git a/SurveyFrontend/src/api/BaseApi.ts b/SurveyFrontend/src/api/BaseApi.ts new file mode 100644 index 0000000..88861bb --- /dev/null +++ b/SurveyFrontend/src/api/BaseApi.ts @@ -0,0 +1,50 @@ +const BASE_URL = "https://survey.slavagm.ru/api"; + +interface RequestConfig { + method: string; + headers: Record; + body?: BodyInit | null; +} + +/** + * Создаёт конфигурацию для fetch-запроса + * @param method HTTP-метод (GET, POST, PUT, DELETE) + * @param isFormData Флаг, указывающий, что отправляется FormData + * @returns Конфигурация для fetch-запроса + */ +const createRequestConfig = (method: string, isFormData: boolean = false): RequestConfig => { + const token = localStorage.getItem("accessToken"); + const config: RequestConfig = { + method, + headers: {}, + }; + + // Добавляем заголовок авторизации, если есть токен + if (token) { + config.headers.Authorization = `Bearer ${token}`; + } + + // Добавляем Content-Type, если это не FormData + if (!isFormData) { + config.headers["Content-Type"] = "application/json"; + } + + return config; +}; + +/** + * Обрабатывает ответ от сервера + * @param response Ответ от fetch + * @returns Распарсенные данные или ошибку + */ +const handleResponse = async (response: Response) => { + const data = await response.json(); + + if (!response.ok) { + throw new Error(data.message || "Произошла ошибка"); + } + + return data; +}; + +export { BASE_URL, createRequestConfig, handleResponse }; \ No newline at end of file diff --git a/SurveyFrontend/src/components/Account/Account.module.css b/SurveyFrontend/src/components/Account/Account.module.css index cbbfd5e..20e0844 100644 --- a/SurveyFrontend/src/components/Account/Account.module.css +++ b/SurveyFrontend/src/components/Account/Account.module.css @@ -7,18 +7,27 @@ padding: 4.58px 13px 4.58px 4.58px; margin: 26px 33px 27px 0; margin-left: auto; + display: inline-flex; + max-width: 100%; + min-width: fit-content; } .accountText{ + width: 100%; + gap: 9px; + display: flex; + align-items: center; + justify-content: space-around; font-size: 24px; font-weight: 600; color: black; - width: 100%; text-decoration: none; + white-space: nowrap; } .accountImg{ vertical-align: middle; width: 55px; margin-right: 9px; -} \ No newline at end of file + flex-shrink: 0; +} diff --git a/SurveyFrontend/src/components/AddQuestionButton/AddQuestionButton.module.css b/SurveyFrontend/src/components/AddQuestionButton/AddQuestionButton.module.css index aa8331c..7326604 100644 --- a/SurveyFrontend/src/components/AddQuestionButton/AddQuestionButton.module.css +++ b/SurveyFrontend/src/components/AddQuestionButton/AddQuestionButton.module.css @@ -1,7 +1,6 @@ /*AddQuestionButton.module.css*/ .questionButton{ - display: block; margin: 0 auto; display: flex; flex-direction: column; diff --git a/SurveyFrontend/src/components/Header/Header.module.css b/SurveyFrontend/src/components/Header/Header.module.css index 2f4a225..b73ac84 100644 --- a/SurveyFrontend/src/components/Header/Header.module.css +++ b/SurveyFrontend/src/components/Header/Header.module.css @@ -5,4 +5,39 @@ padding: 0; width: 100%; display: flex; +} + +.pagesNav{ + display: flex; + gap: 60px; + list-style: none; + align-items: center; + margin-right: 40%; + +} + +.pageLink{ + font-size: 24px; + font-weight: 600; + color: #2A6DAE; + padding: 0; + border: none; + background-color: #ffffff; + white-space: nowrap; + text-decoration: none; +} + +.active{ + margin-bottom: -15px; + color: #000000; + text-decoration-color: #3881C8; +} + +.activeLine{ + display: block; + margin-top: 5px; + border: 1px solid #000000; + width: 50%; + padding: 0; + box-shadow: 0 1px 4px 0 #3881C8; } \ No newline at end of file diff --git a/SurveyFrontend/src/components/Header/Header.tsx b/SurveyFrontend/src/components/Header/Header.tsx index 488200c..03be8fc 100644 --- a/SurveyFrontend/src/components/Header/Header.tsx +++ b/SurveyFrontend/src/components/Header/Header.tsx @@ -1,29 +1,38 @@ -import React, {useState} from "react"; +import React from "react"; import Logo from "../Logo/Logo.tsx"; import Account from "../Account/Account.tsx"; import styles from './Header.module.css' -import SurveyPagesList from "../SurveyPagesList/SurveyPagesList.tsx"; +import {Link, useLocation} from "react-router-dom"; + + const Header: React.FC = () => { - const [activePage, setActivePage] = useState('Создать опрос'); - - const handlePageClick = (name: string)=> { - setActivePage(name); - } + const location = useLocation(); + const isCreateSurveyActive = location.pathname.includes('/survey/create'); + const isSurveyPage = location.pathname.includes('/survey/') && !location.pathname.includes('/survey/create'); + const isMySurveysPage = location.pathname === '/my-surveys' || isSurveyPage; return (
- - + +
); }; -export default Header; \ No newline at end of file +export default Header; diff --git a/SurveyFrontend/src/components/MainComponent/MainComponent.module.css b/SurveyFrontend/src/components/MainComponent/MainComponent.module.css deleted file mode 100644 index cd44880..0000000 --- a/SurveyFrontend/src/components/MainComponent/MainComponent.module.css +++ /dev/null @@ -1,8 +0,0 @@ -/*MainComponent.module.css*/ - -.mainPage{ - width: 100%; - min-height: 85vh; - display: flex; - background-color: #F6F6F6; -} \ No newline at end of file diff --git a/SurveyFrontend/src/components/MainComponent/MainComponent.tsx b/SurveyFrontend/src/components/MainComponent/MainComponent.tsx deleted file mode 100644 index 695dbf5..0000000 --- a/SurveyFrontend/src/components/MainComponent/MainComponent.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import Navigation from "../Navigation/Navigation.tsx"; -import React, {useState} from "react"; -import styles from './MainComponent.module.css' -import Survey from "../Survey/Survey.tsx"; -import SettingSurvey from "../SettingSurvey/SettingSurvey.tsx"; - -const MainComponent: React.FC = () => { - const [activePage, setActivePage] = useState( - localStorage.getItem("activePage") || "Вопросы" - ); - - const handleNavigationClick = (title: string) => { - setActivePage(title); - localStorage.setItem('activePage', title); - } - - return ( -
- - { activePage === 'Вопросы' && } - {activePage === 'Настройки' && } -
- ) -} - -export default MainComponent; \ No newline at end of file diff --git a/SurveyFrontend/src/components/MySurveyList/MySurveyList.tsx b/SurveyFrontend/src/components/MySurveyList/MySurveyList.tsx new file mode 100644 index 0000000..678d30d --- /dev/null +++ b/SurveyFrontend/src/components/MySurveyList/MySurveyList.tsx @@ -0,0 +1,60 @@ +import styles from './MySurveysList.module.css' +import {useNavigate} from "react-router-dom"; + +interface MySurveyItem{ + id: string, + title: string, + description: string, + date: string + status: 'active' | 'completed' +} + +export const MySurveyList = () => { + const navigate = useNavigate(); + + const surveys: MySurveyItem[] = [ + { + id: '1', + title: 'Опрос 1', + description: 'Описание опроса 1', + date: '27-04-2025', + status: 'active', + }, + { + id: '2', + title: 'Опрос 2', + description: 'Описание опроса 2', + date: '01-01-2025', + status: 'completed', + } + ] + + const handleSurveyClick = (id: string) => { + navigate(`/survey/${id}/questions`) + } + + return( +
+ {surveys.map((survey) => ( + + ))} +
+ ) +} \ No newline at end of file diff --git a/SurveyFrontend/src/components/MySurveyList/MySurveysList.module.css b/SurveyFrontend/src/components/MySurveyList/MySurveysList.module.css new file mode 100644 index 0000000..d7f500a --- /dev/null +++ b/SurveyFrontend/src/components/MySurveyList/MySurveysList.module.css @@ -0,0 +1,67 @@ +.main { + background-color: #F6F6F6; + width: 100%; + min-height: 100vh; + padding: 34px 10%; +} + +.survey { + display: flex; + justify-content: space-between; + background-color: white; + width: 79%; + border-radius: 14px; + padding: 29px 36px 29px 54px; + margin-bottom: 23px; + gap: 20px; + border: none; + text-align: left; + font: inherit; + outline: none; +} + +.textContent { + flex-grow: 1; + display: flex; + flex-direction: column; +} + +.status { + width: fit-content; + height: fit-content; + padding: 15px 47px; + border-radius: 15px; + color: #FFFFFF; + white-space: nowrap; + margin-left: 20px; +} + +.completed { + background-color: #B0B0B0; +} + +.active { + background-color: #65B953; +} + +.surveyData { + margin-bottom: 33px; +} + +.title { + font-size: 40px; + font-weight: 600; + word-break: break-word; +} + +.description { + font-size: 24px; + font-weight: 500; + word-break: break-word; +} + +.date { + font-size: 18px; + font-weight: 500; + color: #7D7983; +} diff --git a/SurveyFrontend/src/components/Navigation/Navigation.tsx b/SurveyFrontend/src/components/Navigation/Navigation.tsx index 82eb3bb..1a97ae9 100644 --- a/SurveyFrontend/src/components/Navigation/Navigation.tsx +++ b/SurveyFrontend/src/components/Navigation/Navigation.tsx @@ -1,15 +1,31 @@ import React from 'react' +import {useLocation, useNavigate} from 'react-router-dom' import styles from './Navigation.module.css' import NavigationItem from "../NavigationItem/NavigationItem.tsx"; import SaveButton from "../SaveButton/SaveButton.tsx"; -interface NavigationProps { - onNavigationClick: (title: string) => void; - activePage: string -} +const Navigation: React.FC = () => { + const location = useLocation(); + const navigate = useNavigate(); -const Navigation: React.FC = ({onNavigationClick, activePage}) => { - const items: string[] = ['Вопросы', 'Настройки', 'Результаты'] + const isSurveyPage = /\/survey\/[^/]+/.test(location.pathname); + const isNotCreateSurvey = !location.pathname.includes('/survey/create'); + const isMySurveysPage = isSurveyPage && isNotCreateSurvey; + + const activePage = location.pathname.split('/').pop() ?? 'questions'; + + const baseItems = [ + {id: 'questions', title: 'Вопросы'}, + {id: 'settings', title: 'Настройки'} + ]; + + const items = isMySurveysPage + ? [...baseItems, {id: 'results', title: 'Результаты'}] + : baseItems; + + const handleNavigationClick = (pageId: string) => { + navigate(`${pageId}`, { relative: 'path' }); + }; return (
@@ -17,15 +33,14 @@ const Navigation: React.FC = ({onNavigationClick, activePage})
    {items.map(item => ( onNavigationClick(item)} + key={item.id} + title={item.title} + isActive={activePage === item.id} + onClick={() => handleNavigationClick(item.id)} /> ))}
-
); diff --git a/SurveyFrontend/src/components/PageSurvey/PageSurvey.module.css b/SurveyFrontend/src/components/PageSurvey/PageSurvey.module.css deleted file mode 100644 index 2e845fa..0000000 --- a/SurveyFrontend/src/components/PageSurvey/PageSurvey.module.css +++ /dev/null @@ -1,22 +0,0 @@ -/*PageSurvey.module.css*/ - -.pagesSurveyItem{ - align-items: center; -} - -.pageSurvey{ - font-size: 24px; - font-weight: 600; - color: #2A6DAE; - padding: 0; - border: none; - background-color: #ffffff; - padding-bottom: 5px; - white-space: nowrap; -} - -.active{ - color: #000000; - text-decoration: underline; - text-decoration-color: #3881C8; -} \ No newline at end of file diff --git a/SurveyFrontend/src/components/PageSurvey/PageSurvey.tsx b/SurveyFrontend/src/components/PageSurvey/PageSurvey.tsx deleted file mode 100644 index adc8adb..0000000 --- a/SurveyFrontend/src/components/PageSurvey/PageSurvey.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import styles from './PageSurvey.module.css'; - -interface PageSurveyProps{ - name: string; - isActive: boolean; - onClick(): void; -} - -const PageSurvey: React.FC = ({name, isActive, onClick}) => { - return ( -
  • - -
  • - ); -}; - -export default PageSurvey; \ No newline at end of file diff --git a/SurveyFrontend/src/components/Results/Results.module.css b/SurveyFrontend/src/components/Results/Results.module.css new file mode 100644 index 0000000..5483bb4 --- /dev/null +++ b/SurveyFrontend/src/components/Results/Results.module.css @@ -0,0 +1,5 @@ +/*Results.module.css*/ + +.results{ + width: 85%; +} \ No newline at end of file diff --git a/SurveyFrontend/src/components/Results/Results.tsx b/SurveyFrontend/src/components/Results/Results.tsx new file mode 100644 index 0000000..d21ab44 --- /dev/null +++ b/SurveyFrontend/src/components/Results/Results.tsx @@ -0,0 +1,10 @@ +import SurveyInfo from "../SurveyInfo/SurveyInfo.tsx"; +import styles from './Results.module.css' + +export const Results = () => { + return( +
    + +
    + ) +} \ No newline at end of file diff --git a/SurveyFrontend/src/components/SettingSurvey/SettingSurvey.module.css b/SurveyFrontend/src/components/SettingSurvey/SettingSurvey.module.css index 40b5a44..f2a4fe1 100644 --- a/SurveyFrontend/src/components/SettingSurvey/SettingSurvey.module.css +++ b/SurveyFrontend/src/components/SettingSurvey/SettingSurvey.module.css @@ -1,8 +1,7 @@ /*SettingSurvey.module.css*/ .settingSurvey{ - width: 65%; - margin-left: 8.9%; + width: 85%; } .startEndTime{ diff --git a/SurveyFrontend/src/components/Survey/Survey.module.css b/SurveyFrontend/src/components/Survey/Survey.module.css index 1b26be4..6281504 100644 --- a/SurveyFrontend/src/components/Survey/Survey.module.css +++ b/SurveyFrontend/src/components/Survey/Survey.module.css @@ -1,6 +1,5 @@ /*Survey.module.css*/ .survey{ - width: 65%; - margin-left: 8.9%; + width: 85%; } \ No newline at end of file diff --git a/SurveyFrontend/src/components/SurveyInfo/SurveyInfo.module.css b/SurveyFrontend/src/components/SurveyInfo/SurveyInfo.module.css index f6e8c7c..f80ffbd 100644 --- a/SurveyFrontend/src/components/SurveyInfo/SurveyInfo.module.css +++ b/SurveyFrontend/src/components/SurveyInfo/SurveyInfo.module.css @@ -13,7 +13,7 @@ .info{ min-width: 373px; display: block; - padding: 35px; /*подумать нужно ли справа слева отступы*/ + padding: 35px; } .titleSurvey{ diff --git a/SurveyFrontend/src/components/SurveyPagesList/SurveyPagesList.module.css b/SurveyFrontend/src/components/SurveyPagesList/SurveyPagesList.module.css deleted file mode 100644 index 8a0f282..0000000 --- a/SurveyFrontend/src/components/SurveyPagesList/SurveyPagesList.module.css +++ /dev/null @@ -1,9 +0,0 @@ -/*SurveyPagesList.module.css*/ - -.listSurveyPages{ - display: flex; - gap: 61px; - list-style: none; - align-items: center; - margin-right: 40%; -} \ No newline at end of file diff --git a/SurveyFrontend/src/components/SurveyPagesList/SurveyPagesList.tsx b/SurveyFrontend/src/components/SurveyPagesList/SurveyPagesList.tsx deleted file mode 100644 index c61e8fa..0000000 --- a/SurveyFrontend/src/components/SurveyPagesList/SurveyPagesList.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react'; -import styles from './SurveyPagesList.module.css'; -import PageSurvey from "../PageSurvey/PageSurvey.tsx"; - -interface SurveyPagesListProps{ - activePage: string; - onPageClick: (name: string) => void; -} - -const SurveyPagesList: React.FC = ({activePage, onPageClick}) => { - const listPages: string[] = ['Создать опрос', 'Мои опросы'] - - return ( -
      - {listPages.map((page) => ( - onPageClick(page)} - /> - ))} -
    - ); -}; - -export default SurveyPagesList; \ No newline at end of file diff --git a/SurveyFrontend/src/components/TypeDropdown/TypeDropdown.module.css b/SurveyFrontend/src/components/TypeDropdown/TypeDropdown.module.css index 33af9c7..dd347b2 100644 --- a/SurveyFrontend/src/components/TypeDropdown/TypeDropdown.module.css +++ b/SurveyFrontend/src/components/TypeDropdown/TypeDropdown.module.css @@ -4,7 +4,6 @@ width: 23%; position: relative; display: inline-block; - /*margin-right: 29px;*/ margin-left: auto; } diff --git a/SurveyFrontend/src/pages/MySurveysPage/MySurveysPage.module.css b/SurveyFrontend/src/pages/MySurveysPage/MySurveysPage.module.css new file mode 100644 index 0000000..1e2ee9a --- /dev/null +++ b/SurveyFrontend/src/pages/MySurveysPage/MySurveysPage.module.css @@ -0,0 +1,17 @@ +/*MySurveysPage.module.css*/ + +.layout{ + width: 100%; +} + +.main{ + width: 100%; + min-height: 85vh; + display: flex; + background-color: #F6F6F6; +} + +.content{ + width: 100%; + margin-left: 8.9%; +} \ No newline at end of file diff --git a/SurveyFrontend/src/pages/MySurveysPage/MySurveysPage.tsx b/SurveyFrontend/src/pages/MySurveysPage/MySurveysPage.tsx new file mode 100644 index 0000000..4b036aa --- /dev/null +++ b/SurveyFrontend/src/pages/MySurveysPage/MySurveysPage.tsx @@ -0,0 +1,12 @@ +import styles from "./MySurveysPage.module.css"; +import {MySurveyList} from "../../components/MySurveyList/MySurveyList.tsx"; +import Header from "../../components/Header/Header.tsx"; + +export const MySurveysPage = () => { + return ( +
    +
    + +
    + ) +} \ No newline at end of file diff --git a/SurveyFrontend/src/pages/Questions.tsx b/SurveyFrontend/src/pages/Questions.tsx deleted file mode 100644 index 872986e..0000000 --- a/SurveyFrontend/src/pages/Questions.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import Header from '../components/Header/Header.tsx' -import MainComponent from "../components/MainComponent/MainComponent.tsx"; - -const QuestionsPages: React.FC = () => { - return ( - <> -
    - - - ) -} - -export default QuestionsPages; \ No newline at end of file diff --git a/SurveyFrontend/src/pages/Results.tsx b/SurveyFrontend/src/pages/Results.tsx deleted file mode 100644 index 429ae09..0000000 --- a/SurveyFrontend/src/pages/Results.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import Header from "../components/Header/Header.tsx"; - - -const Results: React.FC = () => { - return ( -
    - ) -} - -export default Results; \ No newline at end of file diff --git a/SurveyFrontend/src/pages/Settings.tsx b/SurveyFrontend/src/pages/Settings.tsx deleted file mode 100644 index 5666a55..0000000 --- a/SurveyFrontend/src/pages/Settings.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import Header from "../components/Header/Header.tsx"; -import MainComponent from "../components/MainComponent/MainComponent.tsx"; - - -const Settings: React.FC = () => { - return ( - <> -
    - - - ); -}; - -export default Settings; \ No newline at end of file diff --git a/SurveyFrontend/src/pages/SurveyCreateAndEditingPage/SurveyCreateAndEditingPage.module.css b/SurveyFrontend/src/pages/SurveyCreateAndEditingPage/SurveyCreateAndEditingPage.module.css new file mode 100644 index 0000000..bb44365 --- /dev/null +++ b/SurveyFrontend/src/pages/SurveyCreateAndEditingPage/SurveyCreateAndEditingPage.module.css @@ -0,0 +1,17 @@ +/*SurveyCreateAndEditingPage.module.css*/ + +.layout{ + width: 100%; +} + +.main{ + width: 100%; + min-height: 85vh; + display: flex; + background-color: #F6F6F6; +} + +.content{ + width: 100%; + margin-left: 8.9%; +} \ No newline at end of file diff --git a/SurveyFrontend/src/pages/SurveyCreateAndEditingPage/SurveyCreateAndEditingPage.tsx b/SurveyFrontend/src/pages/SurveyCreateAndEditingPage/SurveyCreateAndEditingPage.tsx new file mode 100644 index 0000000..a093d06 --- /dev/null +++ b/SurveyFrontend/src/pages/SurveyCreateAndEditingPage/SurveyCreateAndEditingPage.tsx @@ -0,0 +1,18 @@ +import Header from "../../components/Header/Header.tsx"; +import Navigation from "../../components/Navigation/Navigation.tsx"; +import styles from './SurveyCreateAndEditingPage.module.css' +import { Outlet } from "react-router-dom"; + +export const SurveyCreateAndEditingPage = () => { + return ( +
    +
    +
    + +
    + +
    +
    +
    + ); +}; \ No newline at end of file