just started rewritig the project, found a lot of fails

This commit is contained in:
Alibek 2024-02-03 20:03:03 +06:00
parent eeb9cc7ff8
commit 60b136effd
277 changed files with 1833 additions and 5415 deletions

View File

@ -1,3 +1,7 @@
import AboutUsPage from "@/Pages/AboutUsPage/AboutUsPage";
import React from "react";
export default AboutUsPage;
const page = () => {
return <div>page</div>;
};
export default page;

View File

@ -1,91 +0,0 @@
import axios from "axios";
import NextAuth, { NextAuthOptions } from "next-auth";
import { JWT } from "next-auth/jwt";
import CredentialsProvider from "next-auth/providers/credentials";
interface IToken {
access: string;
}
const refreshToken = async (token: JWT): Promise<JWT> => {
const data = {
refresh: token.refresh_token,
};
const response = await axios.post<IToken>(
"https://api.kgroaduat.fishrungames.com/api/v1/token/refresh/",
data
);
return {
...token,
access_token: response.data.access,
};
};
export const authOptions: NextAuthOptions = {
providers: [
CredentialsProvider({
name: "Credentials",
credentials: {
email: {
label: "Email",
type: "text",
placeholder: "jsmith@example.com",
},
password: { label: "Password", type: "password" },
},
async authorize(credentials, req) {
if (!credentials?.email || !credentials?.password)
return null;
const { email, password } = credentials as any;
const res = await fetch(
"https://api.kgroaduat.fishrungames.com/api/v1/users/login/",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
email,
password,
}),
}
);
if (res.status === 401) {
console.log(res.status);
return null;
}
const user = await res.json();
return user;
},
}),
],
pages: {
signIn: "/sign-in",
},
session: {
strategy: "jwt",
},
callbacks: {
async jwt({ token, user }) {
if (user) return { ...token, ...user };
return refreshToken(token);
},
async session({ token, session }) {
session.access_token = token.access_token;
session.refresh_token = token.refresh_token;
return session;
},
},
};
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };

View File

@ -1,3 +0,0 @@
import CreateReportPage from "@/Pages/CreateReportPage/CreateReportPage";
export default CreateReportPage;

View File

@ -1,7 +0,0 @@
import React from "react";
const page = () => {
return <div>page</div>;
};
export default page;

View File

@ -1,9 +1,3 @@
import RootLayout from "@/App/App";
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "KG Road",
description: "Road in Kyrgyzstan",
};
import RootLayout from "@/app/App";
export default RootLayout;

View File

@ -1,3 +0,0 @@
import NewsDetailsPage from "@/Pages/NewsDetailsPage/NewsDetailsPage";
export default NewsDetailsPage;

View File

@ -1,3 +0,0 @@
import NewsPage from "@/Pages/NewsPage/NewsPage";
export default NewsPage;

View File

@ -1,3 +1,3 @@
import Homepage from "@/Pages/Homepage/Homepage";
import Home from "@/pages/Home/Home";
export default Homepage;
export default Home;

View File

@ -1,3 +0,0 @@
import ProfileLayout from "@/Pages/profile/ProfilePage/ProfileLayout";
export default ProfileLayout;

View File

@ -1,3 +0,0 @@
import MyReportsPage from "@/Pages/profile/MyReportsPage/MyReportsPage";
export default MyReportsPage;

View File

@ -1,3 +0,0 @@
import PersonalDataPage from "@/Pages/profile/PersonalDataPage/PersonalDataPage";
export default PersonalDataPage;

View File

@ -1,3 +0,0 @@
import ReportDetailsPage from "@/Pages/ReportDetailsPage/ReportDetailsPage";
export default ReportDetailsPage;

View File

@ -1,3 +1,7 @@
import SignInPage from "@/Pages/SignInPage/SignInPage";
import React from "react";
export default SignInPage;
const page = () => {
return <div>page</div>;
};
export default page;

View File

@ -1,3 +0,0 @@
import SignUpPage from "@/Pages/SignUpPage/SignUpPage";
export default SignUpPage;

View File

@ -1,3 +0,0 @@
import StatisticsPage from "@/Pages/StatisticsPage/StatisticsPage";
export default StatisticsPage;

View File

@ -1,3 +0,0 @@
import VolunteersPage from "@/Pages/VolunteersPage/VolunteersPage";
export default VolunteersPage;

View File

@ -1,9 +1,9 @@
.home {
.app {
padding-top: 78px;
}
@media screen and (max-width: 768px) {
.home {
.app {
padding-top: 72px;
}
}

View File

@ -1,10 +1,8 @@
import { Montserrat } from "next/font/google";
import "./globals.scss";
import Navbar from "@/Widgets/general/Navbar/Navbar";
import Footer from "@/Widgets/general/Footer/Footer";
import { Providers } from "./Providers";
const montserrat = Montserrat({ subsets: ["latin"] });
import "./fonts.scss";
import "./App.scss";
import Footer from "@/widgets/Footer/Footer";
import Navbar from "@/widgets/Navbar/Navbar";
export default function RootLayout({
children,
@ -13,12 +11,10 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body className={montserrat.className}>
<Providers>
<Navbar />
{children}
<Footer />
</Providers>
<body>
<Navbar />
<div className="app">{children}</div>
<Footer />
</body>
</html>
);

View File

@ -1,11 +0,0 @@
"use client";
import { SessionProvider } from "next-auth/react";
export const Providers = ({
children,
}: {
children: React.ReactNode;
}) => {
return <SessionProvider>{children}</SessionProvider>;
};

9
src/App/fonts.scss Normal file
View File

@ -0,0 +1,9 @@
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;500;600;700;800;900&display=swap");
@import url("https://fonts.cdnfonts.com/css/arial");
@import url("../shared/fonts/TildaSans.css");
* {
font-family: Tilda Sans;
}

View File

@ -4,25 +4,22 @@
margin: 0;
}
button {
border: none;
button,
a {
cursor: pointer;
background-color: transparent;
color: black;
display: flex;
align-items: center;
justify-content: center;
}
input {
outline: none;
}
a {
color: black;
text-decoration: none;
border: none;
background-color: transparent;
text-decoration: none;
font-size: 16px;
}
ul {
ul,
ol,
li {
list-style-type: none;
list-style: none;
}

View File

@ -1,41 +0,0 @@
@import "../../Shared/variables.scss";
.auth-header {
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
&__icon {
padding: 12px;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
border-radius: 10px;
border: 1px solid #eaecf0;
}
&__text {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
text-align: center;
h2 {
color: #101828;
font-size: 24px;
font-weight: 700;
}
p {
color: $gray-500;
font-size: 16px;
font-weight: 400;
}
}
}

View File

@ -1,29 +0,0 @@
import Image, { StaticImageData } from "next/image";
import "./AuthHeader.scss";
interface IAuthHeaderProps {
title: string;
description: string;
icon: StaticImageData;
}
const AuthHeader: React.FC<IAuthHeaderProps> = ({
title,
description,
icon,
}: IAuthHeaderProps) => {
return (
<div className="auth-header">
<div className="auth-header__icon">
<Image src={icon} alt="Auth Icon" />
</div>
<div className="auth-header__text">
<h2>{title}</h2>
<p>{description}</p>
</div>
</div>
);
};
export default AuthHeader;

View File

@ -1,61 +0,0 @@
.change-language {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
&__btn {
display: flex;
align-items: center;
gap: 6px;
}
&__popUp {
position: absolute;
top: 35px;
}
&__item,
&__item_active {
button {
width: 150px;
padding: 10px 14px;
justify-content: flex-start;
gap: 8px;
background-color: #fff;
line-height: 24px;
color: #101828;
font-size: 16px;
font-weight: 600;
}
}
&__item:first-child,
&__item_active:first-child {
button {
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
}
&__item:last-child,
&__item_active:last-child {
button {
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
}
}
&__item_active {
button {
background-color: #f9fafb;
}
}
}
@media screen and (max-width: 768px) {
.change-language {
&__popUp {
right: 0;
}
}
}

View File

@ -1,50 +0,0 @@
import "./ChangeLanguage.scss";
import Image from "next/image";
import lang_icon from "./icons/lang-icon.svg";
import chevron_icon from "./icons/chevron-down-icon.svg";
import check_icon from "./icons/check-icon.svg";
import { useState } from "react";
const ChangeLanguage = () => {
const [lang, setLang] = useState<string>("ru");
const [popUp, setPopUp] = useState<boolean>(false);
const languages = [
{ id: "ru", language: "Русский" },
{ id: "kg", language: "Кыргыз" },
{ id: "en", language: "English" },
];
return (
<div className="change-language">
<button
onClick={() => setPopUp((prev) => !prev)}
className="change-language__btn"
>
<Image src={lang_icon} alt="Language Icon" />
<Image src={chevron_icon} alt="Chevron Down Icon" />
</button>
{popUp && (
<ul className="change-language__popUp">
{languages.map((language) => (
<li
key={language.id}
className={
lang === language.id
? "change-language__item_active"
: "change-language__item"
}
>
<button onClick={() => setLang(language.id)}>
{language.language}
{language.id === lang ? (
<Image src={check_icon} alt="Check Icon" />
) : null}
</button>
</li>
))}
</ul>
)}
</div>
);
};
export default ChangeLanguage;

View File

@ -1,5 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="check">
<path id="Icon" d="M16.6663 5L7.49967 14.1667L3.33301 10" stroke="#3695D8" stroke-width="1.66667" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 270 B

View File

@ -1,11 +0,0 @@
<svg width="10" height="7" viewBox="0 0 10 7" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="IMAGE" clip-path="url(#clip0_1290_49928)">
<path id="Vector" d="M0.246139 1.97381C-0.0820464 1.63666 -0.0820464 1.09002 0.246139 0.752867C0.574324 0.415711 1.10642 0.415711 1.4346 0.752867L5.59423 5.02619C5.92241 5.36334 5.92241 5.90998 5.59423 6.24713C5.26604 6.58429 4.73395 6.58429 4.40576 6.24713L0.246139 1.97381Z" fill="#66727F"/>
<path id="Vector_2" d="M8.56495 0.752867C8.89313 0.415711 9.42523 0.415711 9.75341 0.752867C10.0816 1.09002 10.0816 1.63666 9.75341 1.97382L5.59378 6.247C5.26559 6.58416 4.7335 6.58416 4.40531 6.247C4.07713 5.90985 4.07714 5.36334 4.40532 5.02619L8.56495 0.752867Z" fill="#66727F"/>
</g>
<defs>
<clipPath id="clip0_1290_49928">
<rect width="10" height="6" fill="white" transform="translate(0 0.5)"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 865 B

View File

@ -1,7 +0,0 @@
<svg width="24" height="25" viewBox="0 0 24 25" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="globe">
<path id="Vector" d="M12 22.5C17.5228 22.5 22 18.0228 22 12.5C22 6.97715 17.5228 2.5 12 2.5C6.47715 2.5 2 6.97715 2 12.5C2 18.0228 6.47715 22.5 12 22.5Z" stroke="#66727F" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M2 12.5H22" stroke="#66727F" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_3" d="M12 2.5C14.5013 5.23835 15.9228 8.79203 16 12.5C15.9228 16.208 14.5013 19.7616 12 22.5C9.49872 19.7616 8.07725 16.208 8 12.5C8.07725 8.79203 9.49872 5.23835 12 2.5Z" stroke="#66727F" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 750 B

View File

@ -1,7 +0,0 @@
@import "../../Shared/variables.scss";
.custom-link {
color: $blue;
font-size: 16px;
font-weight: 400;
}

View File

@ -1,22 +0,0 @@
import Link from "next/link";
import "./CustomLink.scss";
interface ICustomLink {
children?: React.ReactNode;
path: string;
style?: object;
}
const CustomLink: React.FC<ICustomLink> = ({
children,
path,
style,
}: ICustomLink) => {
return (
<Link href={path} className="custom-link" style={style}>
{children}
</Link>
);
};
export default CustomLink;

View File

@ -1,19 +0,0 @@
@import "../../Shared/variables.scss";
.google-btn {
width: 100%;
padding: 10px 18px;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
border-radius: 8px;
border: 1px solid $gray-300;
background-color: #fff;
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
font-size: 16px;
font-weight: 700;
color: $gray-700;
}

View File

@ -1,18 +0,0 @@
import Image from "next/image";
import "./GoogleButton.scss";
import google_icon from "./icons/google-icon.svg";
interface IGoogleButton {
children?: React.ReactNode;
}
const GoogleButton = ({ children }: IGoogleButton) => {
return (
<div className="google-btn">
<Image src={google_icon} alt="Google Icon" />
{children}
</div>
);
};
export default GoogleButton;

View File

@ -1,13 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Social icon" clip-path="url(#clip0_2134_15985)">
<path id="Vector" d="M23.7663 12.2763C23.7663 11.4605 23.7001 10.6404 23.559 9.83789H12.2402V14.4589H18.722C18.453 15.9492 17.5888 17.2676 16.3233 18.1054V21.1037H20.1903C22.4611 19.0137 23.7663 15.9272 23.7663 12.2763Z" fill="#4285F4"/>
<path id="Vector_2" d="M12.2401 24.0013C15.4766 24.0013 18.2059 22.9387 20.1945 21.1044L16.3276 18.106C15.2517 18.838 13.8627 19.2525 12.2445 19.2525C9.11388 19.2525 6.45946 17.1404 5.50705 14.3008H1.5166V17.3917C3.55371 21.4439 7.7029 24.0013 12.2401 24.0013Z" fill="#34A853"/>
<path id="Vector_3" d="M5.50277 14.3007C5.00011 12.8103 5.00011 11.1965 5.50277 9.70618V6.61523H1.51674C-0.185266 10.006 -0.185266 14.0009 1.51674 17.3916L5.50277 14.3007Z" fill="#FBBC04"/>
<path id="Vector_4" d="M12.2401 4.74966C13.9509 4.7232 15.6044 5.36697 16.8434 6.54867L20.2695 3.12262C18.1001 1.0855 15.2208 -0.034466 12.2401 0.000808666C7.7029 0.000808666 3.55371 2.55822 1.5166 6.61481L5.50264 9.70575C6.45064 6.86173 9.10947 4.74966 12.2401 4.74966Z" fill="#EA4335"/>
</g>
<defs>
<clipPath id="clip0_2134_15985">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -1,46 +0,0 @@
@import "../../Shared/variables.scss";
.input-with-label {
width: 100%;
display: flex;
flex-direction: column;
gap: 6px;
label {
color: $gray-700;
font-size: 14px;
font-weight: 400;
}
p {
font-size: 14px;
color: $red-500;
}
&__wrapper {
padding: 10px 14px;
display: flex;
justify-content: space-between;
border-radius: 8px;
border: 1px solid $gray-300;
box-shadow: 0px 1px 2px 0px rgba(16, 24, 40, 0.05);
input {
width: 100%;
font-size: 18px;
border: none;
}
::placeholder {
color: $gray-500;
font-size: 16px;
font-weight: 400;
}
button {
min-width: 24px;
width: 24;
height: 24px;
}
}
}

View File

@ -1,63 +0,0 @@
import Image from "next/image";
import "./InputWithLabel.scss";
import eye_icon from "./icons/eye-icon.svg";
import eye_off_icon from "./icons/eye-off-icon.svg";
import { useState } from "react";
interface IInputWithLabel {
value?: string;
label?: string;
placeholder?: string;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
name?: string;
secret?: boolean;
error: string;
}
const InputWithLabel: React.FC<IInputWithLabel> = ({
placeholder,
label,
value,
onChange,
name,
secret,
error,
}: IInputWithLabel) => {
const [show, setShow] = useState<boolean>(false);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (onChange) {
onChange(e);
}
};
return (
<div className="input-with-label">
<label>{label}</label>
<div className="input-with-label__wrapper">
<input
onChange={handleChange}
type={!secret ? "text" : show ? "text" : "password"}
value={value}
placeholder={placeholder}
name={name}
/>
{secret && (
<button
type="button"
onClick={() => setShow((prev) => !prev)}
>
{show ? (
<Image src={eye_icon} alt="Eye Opened Icon" />
) : (
<Image src={eye_off_icon} alt="Eye Closed Icon" />
)}
</button>
)}
</div>
{error ? <p>{error}</p> : null}
</div>
);
};
export default InputWithLabel;

View File

@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="eye">
<path id="Vector" d="M1 12C1 12 5 4 12 4C19 4 23 12 23 12C23 12 19 20 12 20C5 20 1 12 1 12Z" stroke="#979797" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M12 15C13.6569 15 15 13.6569 15 12C15 10.3431 13.6569 9 12 9C10.3431 9 9 10.3431 9 12C9 13.6569 10.3431 15 12 15Z" stroke="#979797" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 518 B

View File

@ -1,11 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="eye-off" clip-path="url(#clip0_1668_50526)">
<path id="Vector" d="M17.94 17.94C16.2306 19.243 14.1491 19.9649 12 20C5 20 1 12 1 12C2.24389 9.68192 3.96914 7.65663 6.06 6.06003M9.9 4.24002C10.5883 4.0789 11.2931 3.99836 12 4.00003C19 4.00003 23 12 23 12C22.393 13.1356 21.6691 14.2048 20.84 15.19M14.12 14.12C13.8454 14.4148 13.5141 14.6512 13.1462 14.8151C12.7782 14.9791 12.3809 15.0673 11.9781 15.0744C11.5753 15.0815 11.1752 15.0074 10.8016 14.8565C10.4281 14.7056 10.0887 14.4811 9.80385 14.1962C9.51897 13.9113 9.29439 13.572 9.14351 13.1984C8.99262 12.8249 8.91853 12.4247 8.92563 12.0219C8.93274 11.6191 9.02091 11.2219 9.18488 10.8539C9.34884 10.4859 9.58525 10.1547 9.88 9.88003" stroke="#979797" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M1 1L23 23" stroke="#979797" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1668_50526">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,18 +0,0 @@
@import "../../Shared/variables.scss";
.nav-sign-in,
.nav-profile {
padding: 8px 16px;
background-color: $light-blue;
color: white;
border-radius: 5px;
font-size: 14px;
font-weight: 700;
}
@media screen and (max-width: 768px) {
.nav-sign-in,
.nav-profile {
display: none;
}
}

View File

@ -1,19 +0,0 @@
"use client";
import Link from "next/link";
import "./NavAuthBtn.scss";
import { useSession } from "next-auth/react";
const NavAuthBtn = () => {
const session = useSession();
return session.status === "authenticated" ? (
<Link href="/profile/personal-data" className="nav-profile">
Профиль
</Link>
) : (
<Link href="/sign-in" className="nav-sign-in">
Войти
</Link>
);
};
export default NavAuthBtn;

View File

@ -1,4 +1,4 @@
@import "../../Shared/variables.scss";
@import "../../shared/ui/variables.scss";
.news-card {
height: 100%;

View File

@ -6,7 +6,7 @@ import Link from "next/link";
interface INewsCard {
id: number;
image: StaticImageData;
image: StaticImageData | string;
title: string;
description: string;
date: string;

View File

@ -1,61 +0,0 @@
.review-card {
padding: 15px 20px;
display: flex;
flex-direction: column;
gap: 15px;
border-radius: 12px;
border: 1px solid #c5c6c5;
&__header {
display: flex;
align-items: center;
gap: 10px;
&_left {
min-width: 60px;
width: 60px;
height: 60px;
border-radius: 50%;
object-fit: cover;
}
&_right {
display: flex;
flex-direction: column;
gap: 8px;
h4 {
color: #3e3232;
font-size: 16px;
font-weight: 800;
}
span {
display: flex;
align-items: center;
gap: 8px;
color: rgba(62, 50, 50, 0.75);
font-size: 14px;
font-weight: 500;
line-height: 20px;
}
}
}
p {
color: rgba(0, 0, 0, 0.75);
font-size: 18px;
font-weight: 500;
line-height: 20px;
letter-spacing: 0.25px;
}
}
@media screen and (max-width: 550px) {
.review-card {
p {
font-size: 16px;
}
}
}

View File

@ -1,67 +0,0 @@
import Image from "next/image";
import "./ReviewCard.scss";
import calendar_icon from "./icons/calendar-icon.svg";
interface IReviewCardProps {
item: IReview;
}
interface IReview {
id: number;
author: IAuthor;
review: string;
created_at: string;
}
interface IAuthor {
id: number;
first_name: string;
last_name: string;
image: string;
}
const ReviewCard: React.FC<IReviewCardProps> = ({
item,
}: IReviewCardProps) => {
const months: Record<string, string> = {
"01": "Январь",
"02": "Февраль",
"03": "Март",
"04": "Апрель",
"05": "Май",
"06": "Июнь",
"07": "Июль",
"08": "Август",
"09": "Сентябрь",
"10": "Октябрь",
"11": "Ноябрь",
"12": "Декабрь",
};
const year = item?.created_at.slice(0, 4);
const month = item?.created_at.slice(5, 7);
const day = item?.created_at.slice(8, 10);
return (
<div className="review-card">
<div className="review-card__header">
<img
className="review-card__header_left"
src={item.author.image}
alt="Author Image"
/>
<div className="review-card__header_right">
<h4>
{item.author.first_name} {item.author.last_name}
</h4>
<span>
<Image src={calendar_icon} alt="Calendar Icon" />
{month && months[month]} {day}, {year}
</span>
</div>
</div>
<p>{item.review}</p>
</div>
);
};
export default ReviewCard;

View File

@ -1,8 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="calendar">
<path id="Vector" d="M12.6667 2.66699H3.33333C2.59695 2.66699 2 3.26395 2 4.00033V13.3337C2 14.07 2.59695 14.667 3.33333 14.667H12.6667C13.403 14.667 14 14.07 14 13.3337V4.00033C14 3.26395 13.403 2.66699 12.6667 2.66699Z" stroke="#6E6565" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M10.666 1.33301V3.99967" stroke="#6E6565" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_3" d="M5.33398 1.33301V3.99967" stroke="#6E6565" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_4" d="M2 6.66699H14" stroke="#6E6565" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 747 B

View File

@ -1,39 +1,47 @@
.section-header {
margin-bottom: 52px;
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
text-align: center;
h3 {
font-size: 42px;
font-weight: 500;
color: #32303a;
line-height: 50px;
}
p {
font-size: 24px;
font-weight: 300;
line-height: 29px;
}
}
@media screen and (max-width: 768px) {
.section-header {
gap: 20px;
margin-bottom: 42px;
h3 {
font-size: 36px;
line-height: 43px;
}
}
}
@media screen and (max-width: 550px) {
.section-header {
gap: 16px;
margin-bottom: 42px;
h3 {
font-size: 24px;
line-height: 29px;
}
p {
font-size: 18px;
line-height: 22px;
}
}
}

View File

@ -0,0 +1,22 @@
import "./SectionHeader.scss";
interface ISectionHeaderProps {
title: string;
description?: string;
style?: object;
}
const SectionHeader: React.FC<ISectionHeaderProps> = ({
title,
description,
style,
}: ISectionHeaderProps) => {
return (
<div style={style} className="section-header">
<h3>{title}</h3>
{description && <p>{description}</p>}
</div>
);
};
export default SectionHeader;

View File

@ -1,67 +0,0 @@
"use client";
import Link from "next/link";
import "./Switch.scss";
import { useState } from "react";
enum ESwitch {
BUTTON,
A,
}
interface ISwitch {
color?: string;
onClick?: () => void;
defaultState?: boolean;
type?: ESwitch;
href?: ESwitch extends ESwitch.A ? string : string | undefined;
}
const Switch: React.FC<ISwitch> = ({
color,
onClick,
defaultState,
type,
href,
}: ISwitch) => {
const [toggle, setToggle] = useState(defaultState);
return type === ESwitch.BUTTON ? (
<button
style={{
backgroundColor: !toggle
? "#32303A"
: color
? color
: "#e64452",
}}
onClick={() => {
setToggle((prev) => !prev);
onClick && onClick();
}}
className={`switch ${toggle ? "switch-active" : ""}`}
>
<div className="switch__thumb"></div>
</button>
) : (
<Link
scroll={false}
href={href ? href : "?category"}
style={{
backgroundColor: !toggle
? "#32303A"
: color
? color
: "#e64452",
}}
onClick={() => {
setToggle((prev) => !prev);
onClick && onClick();
}}
className={`switch ${toggle ? "switch-active" : ""}`}
>
<div className="switch__thumb"></div>
</Link>
);
};
export default Switch;

View File

@ -1,31 +0,0 @@
.create-report-map {
height: 410px;
display: grid;
grid-template-columns: 1fr 290px;
border-radius: 6px;
border: 1px solid #c5c6c5;
&__info {
padding: 20px 5px 20px 20px;
display: flex;
flex-direction: column;
gap: 11px;
h4 {
color: #32303a;
font-size: 18px;
font-weight: 500;
}
p {
color: #32303a;
font-size: 16px;
font-weight: 400;
line-height: 140%;
span {
color: #666;
}
}
}
}

View File

@ -1,80 +0,0 @@
import "./CreateReportMap.scss";
import "leaflet/dist/leaflet.css";
import {
MapContainer,
Marker,
TileLayer,
useMapEvents,
} from "react-leaflet";
import { LatLng, LatLngTuple, LeafletMouseEvent } from "leaflet";
import pin from "./assets/pin.svg";
import Image from "next/image";
import { Dispatch, SetStateAction } from "react";
interface ICreateReportMapProps {
markers: LatLng[];
setMarkers: Dispatch<SetStateAction<LatLng[]>>;
}
const CreateReportMap: React.FC<ICreateReportMapProps> = ({
markers,
setMarkers,
}: ICreateReportMapProps) => {
const position = [42.8746, 74.606];
const handleMapClick = (e: LeafletMouseEvent) => {
if (markers.length <= 2) {
setMarkers((prev) => [...prev, e.latlng]);
}
};
const LocationMarker = () => {
useMapEvents({
click: handleMapClick,
});
return (
<>
{markers.map((marker) => (
<Marker
key={marker.lat}
position={position as LatLngTuple}
></Marker>
))}
</>
);
};
return (
<div className="create-report-map">
<MapContainer
center={position as LatLngTuple}
zoom={13}
scrollWheelZoom={false}
className="create-report-map__container"
>
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<LocationMarker />
</MapContainer>
<div className="create-report-map__info">
<h4>Как отметить участок дороги?</h4>
<Image src={pin} alt="Pin Image" />
<p>
Поставьте булавку и начните рисовать участок дороги{" "}
<span>
(он может состоять из любого количества ломаных линий)
</span>
</p>
<p>Чтобы удалить отрезок нажмите на точки повторно.</p>
</div>
</div>
);
};
export default CreateReportMap;

View File

@ -1,5 +0,0 @@
<svg width="82" height="65" viewBox="0 0 82 65" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M32.8125 9.37536C32.8124 7.89715 32.3929 6.4493 31.6027 5.19999C30.8126 3.95067 29.6842 2.95117 28.3487 2.31755C27.0132 1.68394 25.5253 1.44223 24.0578 1.6205C22.5904 1.79876 21.2037 2.38969 20.0587 3.32464C18.9137 4.25959 18.0575 5.50019 17.5894 6.90235C17.1214 8.30451 17.0608 9.81069 17.4146 11.2459C17.7684 12.6812 18.5222 13.9866 19.5883 15.0106C20.6544 16.0345 21.9892 16.735 23.4375 17.0306V44.684C23.4377 45.0991 23.5203 45.51 23.6807 45.8929L24.6641 48.2367C24.697 48.297 24.7456 48.3473 24.8047 48.3824C24.8638 48.4174 24.9313 48.436 25 48.436C25.0687 48.436 25.1362 48.4174 25.1953 48.3824C25.2544 48.3473 25.303 48.297 25.3359 48.2367L26.3193 45.8929C26.4797 45.51 26.5623 45.0991 26.5625 44.684V17.0306C28.3259 16.6683 29.9104 15.709 31.0489 14.3145C32.1874 12.92 32.8103 11.1756 32.8125 9.37536ZM27.3438 9.37536C26.8802 9.37536 26.4271 9.2379 26.0416 8.98037C25.6562 8.72284 25.3558 8.35679 25.1784 7.92853C25.001 7.50026 24.9546 7.02901 25.045 6.57437C25.1355 6.11973 25.3587 5.70211 25.6865 5.37433C26.0142 5.04655 26.4319 4.82333 26.8865 4.7329C27.3412 4.64246 27.8124 4.68888 28.2407 4.86627C28.6689 5.04366 29.035 5.34407 29.2925 5.7295C29.55 6.11492 29.6875 6.56806 29.6875 7.03161C29.6875 7.65321 29.4406 8.24936 29.001 8.6889C28.5615 9.12843 27.9654 9.37536 27.3438 9.37536Z" fill="#E64452"/>
<circle cx="25" cy="51" r="4.75" fill="white" stroke="black" stroke-width="0.5"/>
<line x1="33.2944" y1="53.5292" x2="81.0099" y2="63.081" stroke="#E64452" stroke-width="3" stroke-dasharray="6 6"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,64 +0,0 @@
.create-review {
margin-top: 70px;
display: flex;
flex-direction: column;
gap: 40px;
h3 {
display: flex;
align-items: center;
gap: 6px;
color: #3e3232;
font-size: 24px;
font-weight: 500;
span {
width: 4px;
height: 10px;
border-radius: 12px;
background: #3998e8;
}
}
div {
display: flex;
flex-direction: column;
gap: 18px;
textarea {
height: 258px;
padding: 27px 18px;
resize: none;
border-radius: 12px;
border: 1px solid #c5c6c5;
font-size: 16px;
outline: none;
}
::placeholder {
color: #c5c6c5;
font-size: 16px;
font-weight: 400;
}
button {
width: fit-content;
align-self: flex-end;
}
}
}
@media screen and (max-width: 768px) {
.create-review {
gap: 30px;
}
}
@media screen and (max-width: 550px) {
.create-review {
gap: 6px;
div {
gap: 12px;
}
}
}

View File

@ -1,46 +0,0 @@
"use client";
import "./CreateReview.scss";
import { useState } from "react";
import Button from "@/Shared/UI/Button/Button";
import { createReviewAction } from "./actions";
import { StaticImageData } from "next/image";
interface ICreateReviewProps {
endpoint: string;
id: number | null | undefined;
}
const CreateReview: React.FC<ICreateReviewProps> = ({
endpoint,
id,
}: ICreateReviewProps) => {
const [review, setReview] = useState<string>("");
return (
<div className="create-review">
<h3>
<span />
Написать комментарий
</h3>
<div>
<textarea
onChange={(e) => setReview(e.target.value)}
value={review}
placeholder="Напишите комментарий"
/>
<Button
disabled={createReviewAction.isLoading}
onClick={() => {
setReview("");
createReviewAction.createReview(endpoint, id, review);
}}
>
Отправить
</Button>
</div>
</div>
);
};
export default CreateReview;

View File

@ -1,59 +0,0 @@
import { baseAPI } from "@/Shared/API/baseAPI";
import { getTokens } from "@/Shared/helpers/getTokens";
import axios, { AxiosError } from "axios";
class CreateReview {
response: string;
isLoading: boolean;
error: string;
constructor() {
this.response = "";
this.isLoading = false;
this.error = "";
}
async createReview(
endpoint: string,
id: number | null | undefined,
review: string
) {
try {
this.isLoading = true;
const access_token = getTokens()?.access_token;
const Authorization = `Bearer ${access_token}`;
const config = {
headers: {
Authorization,
},
};
const body = {
review,
};
const response = await axios.post(
`${baseAPI}/${endpoint}/${id}/reviews/`,
body,
config
);
this.response = response.data;
console.log(response);
} catch (error: unknown) {
console.log(error);
if (error instanceof AxiosError) {
this.error = error.message;
} else {
this.error = "An error ocured";
}
} finally {
this.isLoading = false;
}
}
}
export const createReviewAction = new CreateReview();

View File

@ -1,52 +0,0 @@
@import "../../Shared/variables.scss";
.nav-menu-btn,
.nav-menu {
display: none;
}
.nav-menu {
padding: 48px 30px;
width: 100%;
height: 100vh;
position: fixed;
top: 72px;
left: 0;
background-color: #fff;
&__pages {
display: flex;
flex-direction: column;
gap: 26px;
&-item,
&-item_active {
a {
font-size: 24px;
font-weight: 500;
}
}
&-item_active {
a {
color: $light-blue;
}
}
}
}
@media screen and (max-width: 768px) {
.nav-menu-btn {
display: flex;
}
.nav-menu {
display: block;
}
}
@media screen and (max-width: 550px) {
.nav-menu {
padding: 40px 16px;
}
}

View File

@ -1,76 +0,0 @@
import "./NavMenu.scss";
import Image from "next/image";
import menu_icon from "./icons/menu-icon.svg";
import cross_icon from "./icons/cross-icon.svg";
import { useState } from "react";
import { pages } from "@/Shared/variables/pages";
import Link from "next/link";
import { usePathname } from "next/navigation";
const NavMenu = () => {
const [menu, setMenu] = useState<boolean>(false);
const auth = false;
const pathname = usePathname();
return (
<>
<button
className="nav-menu-btn"
onClick={() => setMenu((prev) => !prev)}
>
{menu ? (
<Image src={cross_icon} alt="Cross Icon" />
) : (
<Image src={menu_icon} alt="Menu Icon" />
)}
</button>
{menu && (
<div className="nav-menu">
<ul className="nav-menu__pages">
{pages.map((page) => (
<li
key={page.id}
className={
page.path === pathname
? "nav-menu__pages-item_active"
: "nav-menu__pages-item"
}
>
<Link onClick={() => setMenu(false)} href={page.path}>
{page.page}
</Link>
</li>
))}
{auth ? (
<li
className={
pathname === "/sign-in"
? "nav-menu__pages-item_active"
: "nav-menu__pages-item"
}
>
<Link onClick={() => setMenu(false)} href="/sign-in">
Войти
</Link>
</li>
) : (
<li
className={
pathname === "/profile"
? "nav-menu__pages-item_active"
: "nav-menu__pages-item"
}
>
<Link onClick={() => setMenu(false)} href="/profile">
Профиль
</Link>
</li>
)}
</ul>
</div>
)}
</>
);
};
export default NavMenu;

View File

@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="x">
<path id="Vector" d="M18 6L6 18" stroke="#32303A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M6 6L18 18" stroke="#32303A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 353 B

View File

@ -1,5 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="menu">
<path id="Icon" d="M3 12H21M3 6H21M3 18H21" stroke="#344054" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 249 B

View File

@ -1,10 +0,0 @@
.report-like {
display: flex;
align-items: center;
gap: 6px;
color: rgb(74, 192, 63);
font-size: 15px;
font-weight: 500;
line-height: 18px;
}

View File

@ -1,22 +0,0 @@
import "./ReportLike.scss";
import Image from "next/image";
import like_icon from "./icons/like-icon.svg";
interface IReportLikeProps {
count_likes: number;
}
const ReportLike: React.FC<IReportLikeProps> = ({
count_likes,
}: IReportLikeProps) => {
return (
<div className="report-like">
<button>
<Image src={like_icon} alt="Like Icon" />
</button>
{count_likes}
</div>
);
};
export default ReportLike;

View File

@ -1,5 +0,0 @@
<svg width="26" height="27" viewBox="0 0 26 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="thumbs-up">
<path id="Vector" d="M7.58317 12.417L11.9165 2.66699C12.7785 2.66699 13.6051 3.0094 14.2146 3.6189C14.8241 4.22839 15.1665 5.05504 15.1665 5.91699V10.2503H21.2982C21.6122 10.2468 21.9233 10.3115 22.2099 10.4401C22.4964 10.5688 22.7516 10.7581 22.9577 10.9951C23.1638 11.2321 23.3159 11.5111 23.4035 11.8128C23.491 12.1144 23.512 12.4315 23.4648 12.742L21.9698 22.492C21.8915 23.0086 21.6291 23.4796 21.2309 23.818C20.8327 24.1564 20.3257 24.3396 19.8032 24.3337H7.58317M7.58317 12.417V24.3337M7.58317 12.417H4.33317C3.75853 12.417 3.20743 12.6453 2.80111 13.0516C2.39478 13.4579 2.1665 14.009 2.1665 14.5837V22.167C2.1665 22.7416 2.39478 23.2927 2.80111 23.6991C3.20743 24.1054 3.75853 24.3337 4.33317 24.3337H7.58317" stroke="#4AC03F" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 929 B

View File

@ -1,34 +0,0 @@
import "./SearchBar.scss";
import Image from "next/image";
import search_icon from "./icons/search-icon.svg";
interface ISearchBar {
placeholder?: string;
style?: object;
value: string;
setValue: (search: string) => any;
}
const SearchBar: React.FC<ISearchBar> = ({
placeholder,
style,
value,
setValue,
}: ISearchBar) => {
return (
<div style={style} className="search-bar">
<div className="search-bar__input">
<Image src={search_icon} alt="Search Icon" />
<input
value={value}
onChange={(e) => setValue(e.target.value)}
type="text"
placeholder={placeholder}
/>
</div>
<button>Поиск</button>
</div>
);
};
export default SearchBar;

View File

@ -1,6 +0,0 @@
<svg width="24" height="26" viewBox="0 0 24 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="search">
<path id="Vector" d="M11 20.2796C15.4183 20.2796 19 16.5547 19 11.9596C19 7.36464 15.4183 3.63965 11 3.63965C6.58172 3.63965 3 7.36464 3 11.9596C3 16.5547 6.58172 20.2796 11 20.2796Z" stroke="#C5C6C5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M20.9999 22.3599L16.6499 17.8359" stroke="#C5C6C5" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 531 B

View File

@ -1,44 +0,0 @@
@import "../../Shared/variables.scss";
.sign-in-form {
width: 360px;
display: grid;
gap: 36px;
&__inputs,
&__btns {
display: flex;
flex-direction: column;
gap: 20px;
p {
color: $red-500;
font-size: 14px;
}
}
&__btns {
gap: 16px;
}
&__no-account {
display: flex;
justify-content: center;
gap: 6px;
span {
color: $gray-500;
font-size: 14px;
}
a {
font-size: 14px;
}
}
}
@media screen and (max-width: 550px) {
.sign-in-form {
width: 100%;
}
}

View File

@ -1,85 +0,0 @@
"use client";
import "./SignInForm.scss";
import { useEffect, useState } from "react";
import InputWithLabel from "@/Entities/InputWithLabel/InputWithLabel";
import Button from "@/Shared/UI/Button/Button";
import { useRouter } from "next/navigation";
import CustomLink from "@/Entities/CustomLink/CustomLink";
import GoogleButton from "@/Entities/GoogleButton/GoogleButton";
import { useSignIn } from "./sign-in.store";
import DefaultLoader from "@/Shared/UI/DefaultLoader/DefaultLoader";
import { signIn } from "next-auth/react";
const SignInForm = () => {
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
const router = useRouter();
const handleSubmit: React.FormEventHandler<
HTMLFormElement
> = async (e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
console.log(formData.get("email"), formData.get("email"));
const res = await signIn("credentials", {
email: formData.get("email"),
password: formData.get("password"),
redirect: false,
});
if (res && !res.error) {
router.push("/profile");
} else {
console.log(res?.error);
}
};
return (
<form className="sign-in-form" onSubmit={handleSubmit}>
<div className="sign-in-form__inputs">
<InputWithLabel
name="email"
label="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Введите email"
error=""
/>
<InputWithLabel
name="password"
label="Пароль"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Введите пароль"
secret
error=""
/>
</div>
<CustomLink
path="/forgot-password"
style={{ justifySelf: "flex-end" }}
>
Забыли пароль?
</CustomLink>
<div className="sign-in-form__btns">
<Button type="submit">Войти</Button>
<GoogleButton>Войти через Google</GoogleButton>
</div>
<div className="sign-in-form__no-account">
<span>Еще нет аккаунта?</span>
<CustomLink path="/sign-up">Зарегистрируйтесь</CustomLink>
</div>
</form>
);
};
export default SignInForm;

View File

@ -1,63 +0,0 @@
import { baseAPI } from "@/Shared/API/baseAPI";
import { IFetch } from "@/Shared/types";
import axios from "axios";
import { create } from "zustand";
interface SignInStore extends IFetch {
login: (email: string, password: string) => Promise<void>;
cleanRedirect: () => void;
emailError: string;
passwordError: string;
redirect: boolean;
}
export const useSignIn = create<SignInStore>((set) => ({
loading: false,
error: "",
emailError: "",
passwordError: "",
redirect: false,
login: async (email: string, password: string) => {
if (!email.trim()) {
set({ emailError: "Пожалуйста введите почту" });
set({ passwordError: "" });
return;
}
if (!password.trim()) {
set({ passwordError: "Пожалуйста введите пароль" });
set({ emailError: "" });
return;
}
const user = {
email,
password,
};
try {
set({ loading: true });
const response = await axios.post(
`${baseAPI}/users/login/`,
user
);
localStorage.setItem("tokens", JSON.stringify(response.data));
set({ emailError: "" });
set({ passwordError: "" });
set({ error: "" });
set({ redirect: true });
} catch (error: any) {
set({ emailError: "" });
set({ passwordError: "" });
set({ error: error.message });
} finally {
set({ loading: false });
}
},
cleanRedirect: () => {
set({ redirect: false });
},
}));

View File

@ -1,44 +0,0 @@
@import "../../Shared/variables.scss";
.sign-up-form {
width: 360px;
display: grid;
gap: 36px;
&__inputs,
&__btns {
display: flex;
flex-direction: column;
gap: 20px;
p {
font-size: 14px;
color: $red-500;
}
}
&__btns {
gap: 16px;
}
&__has-account {
display: flex;
justify-content: center;
gap: 6px;
span {
color: $gray-500;
font-size: 14px;
}
a {
font-size: 14px;
}
}
}
@media screen and (max-width: 550px) {
.sign-up-form {
width: 100%;
}
}

View File

@ -1,90 +0,0 @@
"use client";
import { useEffect, useState } from "react";
import "./SignUpForm.scss";
import InputWithLabel from "@/Entities/InputWithLabel/InputWithLabel";
import Button from "@/Shared/UI/Button/Button";
import CustomLink from "@/Entities/CustomLink/CustomLink";
import { useRouter } from "next/navigation";
import GoogleButton from "@/Entities/GoogleButton/GoogleButton";
import { useSignUp } from "./sign-up.store";
import DefaultLoader from "@/Shared/UI/DefaultLoader/DefaultLoader";
const SignUpForm = () => {
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
const [confirmPassword, setConfirmPassword] = useState<string>("");
const router = useRouter();
const {
redirect,
register,
loading,
emailError,
passwordError,
confirmPasswordError,
matchPasswordError,
error,
} = useSignUp();
useEffect(() => {
if (redirect) {
router.push("/confirm-email");
}
}, [redirect]);
return (
<form
className="sign-up-form"
onSubmit={(e) => {
e.preventDefault();
register(email, password, confirmPassword);
}}
>
<div className="sign-up-form__inputs">
<InputWithLabel
label="Email"
placeholder="Введите email"
value={email}
onChange={(e) => setEmail(e.target.value)}
error={emailError}
/>
<InputWithLabel
label="Пароль"
placeholder="Введите пароль"
value={password}
onChange={(e) => setPassword(e.target.value)}
secret
error={passwordError}
/>
<InputWithLabel
label="Пароль Потверждения"
placeholder="Повторите пароль"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
secret
error={confirmPasswordError}
/>
{matchPasswordError ? <p>{matchPasswordError}</p> : null}
{error ? <p>{error}</p> : null}
</div>
<div className="sign-up-form__btns">
<Button
type="submit"
onClick={() => router.push("/confirm-email")}
>
{loading ? <DefaultLoader /> : "Зарегистрироваться"}
</Button>
<GoogleButton>Войти через Google</GoogleButton>
</div>
<div className="sign-up-form__has-account">
<span>Уже есть аккаунт?</span>
<CustomLink path="/sign-in">Войти в аккаунт</CustomLink>
</div>
</form>
);
};
export default SignUpForm;

View File

@ -1,121 +0,0 @@
import { baseAPI } from "@/Shared/API/baseAPI";
import { IFetch } from "@/Shared/types";
import axios from "axios";
import { create } from "zustand";
interface SignUpStore extends IFetch {
register: (
email: string,
password: string,
confirmPassword: string
) => Promise<void>;
cleanRedirect: () => void;
emailError: string;
passwordError: string;
confirmPasswordError: string;
matchPasswordError: string;
redirect: boolean;
}
export const useSignUp = create<SignUpStore>((set) => ({
loading: false,
error: "",
emailError: "",
passwordError: "",
confirmPasswordError: "",
matchPasswordError: "",
redirect: false,
register: async (
email: string,
password: string,
confirmPassword: string
) => {
if (!email.trim()) {
set({ passwordError: "" });
set({ confirmPasswordError: "" });
set({ matchPasswordError: "" });
set({ emailError: "Пожалуйста введите почту" });
return;
}
if (!password.trim()) {
set({ emailError: "" });
set({ confirmPasswordError: "" });
set({ matchPasswordError: "" });
set({ passwordError: "Пожалуйста введите пароль" });
return;
}
if (!confirmPassword.trim()) {
set({ emailError: "" });
set({ passwordError: "" });
set({ matchPasswordError: "" });
set({ confirmPasswordError: "Пожалуйста введите пароль" });
return;
}
if (validatePassword(password)) {
set({ emailError: "" });
set({ passwordError: "" });
set({ matchPasswordError: "" });
set({ confirmPasswordError: "" });
set({ error: "Минимум 8 символов, 1 заглавная буква и цифра" });
return;
}
if (password !== confirmPassword) {
set({ emailError: "" });
set({ confirmPasswordError: "" });
set({ passwordError: "" });
set({ matchPasswordError: "Пароли не совпадают" });
return;
}
const user = {
email,
password,
password2: confirmPassword,
};
try {
set({ loading: true });
const response = await axios.post(
`${baseAPI}/users/register/`,
user
);
localStorage.setItem("tokens", JSON.stringify(response.data));
set({ emailError: "" });
set({ passwordError: "" });
set({ confirmPasswordError: "" });
set({ matchPasswordError: "" });
set({ error: "" });
set({ redirect: true });
} catch (error: any) {
set({ emailError: "" });
set({ passwordError: "" });
set({ confirmPasswordError: "" });
set({ matchPasswordError: "" });
set({ error: error.message });
} finally {
set({ loading: false });
}
},
cleanRedirect: () => {
set({ redirect: false });
},
}));
const validatePassword = (password: string) => {
const regex = /[A-Z]/;
const digitRegex = /\d/;
if (password.length < 8) return true;
console.log("1");
if (!regex.test(password) || !digitRegex.test(password))
return true;
return false;
};

View File

@ -1,100 +0,0 @@
.about-us-page {
padding: 118px 90px 0px 90px;
display: flex;
flex-direction: column;
gap: 40px;
&__image {
display: flex;
justify-content: center;
margin-bottom: 25px;
img {
width: 100%;
height: 600px;
object-fit: cover;
border-radius: 12px;
}
}
&__container {
display: flex;
flex-direction: column;
gap: 10px;
h3 {
color: #3e3232;
font-size: 24px;
font-weight: 600;
}
div {
display: flex;
flex-direction: column;
gap: 30px;
p {
color: #3e3232;
font-feature-settings: "clig" off, "liga" off;
font-size: 20px;
font-weight: 500;
line-height: 34px;
}
}
}
}
@media screen and (max-width: 1024px) {
.about-us-page {
padding: 112px 30px 0px 30px;
}
}
@media screen and (max-width: 768px) {
.about-us-page {
padding: 112px 30px 0px 30px;
gap: 30px;
&__image {
margin-bottom: 0;
img {
height: 392px;
}
}
&__container {
h3 {
font-size: 20px;
}
div {
gap: 20px;
p {
font-size: 18px;
}
}
}
}
}
@media screen and (max-width: 550px) {
.about-us-page {
padding: 112px 16px 0px 16px;
gap: 20px;
&__image {
margin-bottom: 30px;
img {
height: 230px;
}
}
&__container {
div {
p {
font-size: 16px;
}
}
}
}
}

View File

@ -1,66 +0,0 @@
import HeaderText from "@/Shared/UI/HeaderText/HeaderText";
import "./AboutUsPage.scss";
import Image from "next/image";
import image from "./assets/image.png";
const AboutUsPage = () => {
return (
<div className="about-us-page">
<HeaderText>О нас</HeaderText>
<div className="about-us-page__image">
<Image src={image} alt="About Us Image" />
</div>
<div className="about-us-page__container">
<h3>Dont wait. The purpose of our lives is to be happy!</h3>
<div>
<p>
Upon arrival, your senses will be rewarded with the
pleasant scent of lemongrass oil used to clean the natural
wood found throughout the room, creating a relaxing
atmosphere within the space. A wonderful serenity has
taken possession of my entire soul, like these sweet
mornings of spring which I enjoy with my whole heart. I am
alone, and feel the charm of existence in this spot, which
was created for the bliss of souls like mine. I am so
happy, my dear friend, so absorbed in the exquisite.
</p>
<p>
When you are ready to indulge your sense of excitement,
check out the range of water- sports opportunities at the
resorts on-site water-sports center. Want to leave your
stress on the water? The resort has kayaks, paddleboards,
or the low-key pedal boats. Snorkeling equipment is
available as well, so you can experience the ever-changing
undersea environment. Not only do visitors to a bed and
breakfast get a unique perspective on the place they are
visiting, they have options for special packages not
available in other hotel settings.{" "}
</p>
<p>
bed and breakfasts can partner easily with local
businesses for a smoothly organized and highly
personalized vacation experience. The Fife and Drum Inn
offers options such as the Historic Triangle Package that
includes three nights at the Inn, breakfasts, and
admissions to historic Williamsburg, Jamestown, and
Yorktown. Bed and breakfasts also lend themselves to
romance.
</p>
<p>
Part of the charm of a bed and breakfast is the
uniqueness; art, décor, and food are integrated to create
a complete experience. For example, the Fife and Drum
retains the colonial feel of the area in all its guest
rooms. Special features include antique furnishings,
elegant four poster beds in some guest rooms, as well folk
art and artifacts from the restoration period of the
historic area available for guests to enjoy.
</p>
</div>
</div>
</div>
);
};
export default AboutUsPage;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

View File

@ -1,133 +0,0 @@
.create-report {
padding: 118px 90px 0px 90px;
display: flex;
flex-direction: column;
gap: 38px;
&__wrapper {
padding: 28px;
display: flex;
flex-direction: column;
gap: 20px;
border-radius: 10px;
border: 1px solid #d5d5d5;
h5 {
color: #32303a;
font-size: 22px;
font-weight: 400;
}
.input-label {
max-width: 800px;
display: flex;
flex-direction: column;
gap: 22px;
input {
padding: 16px 20px;
border-radius: 6px;
border: 1px solid #c5c6c5;
background: #fff;
color: #32303a;
font-size: 17px;
font-weight: 400;
::placeholder {
color: #c5c6c5;
font-size: 18px;
font-weight: 400;
}
}
}
}
&__add-image {
max-width: 800px;
display: flex;
flex-direction: column;
gap: 18px;
p {
color: #666;
font-size: 18px;
font-weight: 400;
}
input[type="file"] {
display: none;
}
label {
display: flex;
align-items: center;
gap: 16px;
color: #32303a;
font-size: 18px;
font-weight: 400;
cursor: pointer;
span {
color: #b0b0b0;
}
}
}
&__images {
display: flex;
gap: 20px;
div {
width: 187px;
display: flex;
flex-direction: column;
gap: 8px;
img {
width: 100%;
height: 187px;
object-fit: cover;
}
button {
color: #32303a;
font-size: 16px;
font-weight: 500;
text-decoration-line: underline;
align-self: flex-end;
}
}
}
&__btn {
width: 330px;
padding: 15px;
gap: 10px;
background-color: #489fe1;
border-radius: 5px;
color: #fff;
text-align: center;
font-size: 22px;
font-weight: 400;
}
}
@media screen and (max-width: 1024px) {
.create-report {
padding: 118px 30px 0px 30px;
}
}
@media screen and (max-width: 768px) {
.create-report {
padding: 112px 30px 0px 30px;
}
}
@media screen and (max-width: 550px) {
.create-report {
padding: 112px 16px 0px 16px;
}
}

View File

@ -1,94 +0,0 @@
"use client";
import "./CreateReportPage.scss";
import HeaderText from "@/Shared/UI/HeaderText/HeaderText";
import CreateReportMap from "@/Features/CreateReportMap/CreateReportMap";
import paperclip__icon from "./icons/paperclip.svg";
import { useState } from "react";
import Image from "next/image";
import arrow_right_icon from "./icons/arrow-right.svg";
import { LatLng } from "leaflet";
const CreateReportPage = () => {
const [location, setLocation] = useState<LatLng[]>([]);
const [images, setImages] = useState<File[]>();
const [description, setdescription] = useState<string>("");
const handleImages = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
setImages(Array.from(e.target.files));
}
};
const deleteImage = (name: string) => {
setImages((prev) => prev?.filter((image) => image.name !== name));
};
return (
<div className="create-report">
<HeaderText>Написать обращение</HeaderText>
<div className="create-report__wrapper">
<div className="input-label">
<h5>Адрес</h5>
<input type="text" placeholder="Выберите точки на карте" />
</div>
<CreateReportMap
markers={location}
setMarkers={setLocation}
/>
<div className="input-label">
<h5>Добавьте описание проблемы</h5>
<input
value={description}
onChange={(e) => setdescription(e.target.value)}
type="text"
placeholder="Введите описание"
/>
</div>
<div className="create-report__add-image">
<h5>Добавьте фотографии</h5>
<p>
Загрузите до 5 фотографии, связанные с дорогой, которую Вы
хотите отметить. Фотографии помогут лучше понять проблему.
</p>
<input
onChange={handleImages}
type="file"
id="report-add-image"
multiple
/>
<label htmlFor="report-add-image">
<Image src={paperclip__icon} alt="Paper Clip Icon" />
Прикрепить файл <span>(до 5 МБ)</span>
</label>
<div className="create-report__images">
{images?.map((image) => (
<div>
<img
src={URL.createObjectURL(image)}
key={image.name}
alt="Report Image"
/>
<button onClick={() => deleteImage(image.name)}>
удалить
</button>
</div>
))}
</div>
<button className="create-report__btn">
Отправить на модерацию
<Image src={arrow_right_icon} alt="Arrow Right Icon" />
</button>
</div>
</div>
</div>
);
};
export default CreateReportPage;

View File

@ -1,6 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="arrow-right">
<path id="Vector" d="M5 12H19" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_2" d="M12 5L19 12L12 19" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 364 B

View File

@ -1,5 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="paperclip">
<path id="Vector" d="M21.4403 11.0499L12.2503 20.2399C11.1244 21.3658 9.59747 21.9983 8.00529 21.9983C6.41311 21.9983 4.88613 21.3658 3.76029 20.2399C2.63445 19.1141 2.00195 17.5871 2.00195 15.9949C2.00195 14.4027 2.63445 12.8758 3.76029 11.7499L12.9503 2.55992C13.7009 1.80936 14.7188 1.3877 15.7803 1.3877C16.8417 1.3877 17.8597 1.80936 18.6103 2.55992C19.3609 3.31048 19.7825 4.32846 19.7825 5.38992C19.7825 6.45138 19.3609 7.46936 18.6103 8.21992L9.41029 17.4099C9.03501 17.7852 8.52602 17.996 7.99529 17.996C7.46456 17.996 6.95557 17.7852 6.58029 17.4099C6.20501 17.0346 5.99418 16.5256 5.99418 15.9949C5.99418 15.4642 6.20501 14.9552 6.58029 14.5799L15.0703 6.09992" stroke="#32303A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 883 B

View File

@ -1,36 +0,0 @@
import "./Homepage.scss";
import Header from "@/Widgets/home/Header/Header";
import MapSection from "@/Widgets/home/MapSection/MapSection";
import RatingSection from "@/Widgets/home/RatingSection/RatingSection";
import StatisticsSection from "@/Widgets/home/StatisticsSection/StatisticsSection";
import NewsSection from "@/Widgets/home/NewsSection/NewsSection";
const Homepage = ({
searchParams,
}: {
searchParams: {
"тип-дороги": string;
"карта-дорог": string;
рейтинг: string;
};
}) => {
return (
<div className="home">
<Header />
<StatisticsSection />
<MapSection
categories={searchParams["тип-дороги"]}
queryMap={searchParams["карта-дорог"]}
queryRating={searchParams["рейтинг"]}
/>
<RatingSection
categories={searchParams["тип-дороги"]}
queryMap={searchParams["карта-дорог"]}
queryRating={searchParams["рейтинг"]}
/>
<NewsSection />
</div>
);
};
export default Homepage;

View File

@ -1,40 +0,0 @@
.news-details-page {
padding: 118px 90px 0 90px;
display: flex;
flex-direction: column;
gap: 40px;
&__wrapper {
max-width: 1070px;
display: flex;
align-self: center;
flex-direction: column;
gap: 40px;
}
&__description {
color: #3e3232;
font-size: 20px;
line-height: 34px;
}
}
@media screen and (max-width: 1024px) {
.news-details-page {
padding: 118px 30px 0 30px;
}
}
@media screen and (max-width: 768px) {
.news-details-page {
padding: 112px 30px 0 30px;
gap: 35px;
}
}
@media screen and (max-width: 550px) {
.news-details-page {
padding: 112px 16px 0 16px;
gap: 20px;
}
}

View File

@ -1,35 +0,0 @@
import { newsDetailsStore } from "./store";
import "./NewsDetailsPage.scss";
import HeaderText from "@/Shared/UI/HeaderText/HeaderText";
import ReviewsSection from "@/Widgets/general/ReviewsSection/ReviewsSection";
import NewsHeader from "@/Widgets/NewsHeader/NewsHeader";
const NewsDetailsPage = async ({
params,
}: {
params: { id: string };
}) => {
const data = await newsDetailsStore.getNewsDetails(params.id);
return (
<div className="news-details-page">
<HeaderText>{data?.title}</HeaderText>
<div className="news-details-page__wrapper">
<NewsHeader
date={data?.created_at}
image={data?.image}
count_reviews={data?.count_reviews}
/>
<p className="news-details-page__description">
{data?.description}
</p>
<ReviewsSection id={data?.id} endpoint="news" />
</div>
</div>
);
};
export default NewsDetailsPage;

View File

@ -1 +0,0 @@
export * from "./store";

View File

@ -1,54 +0,0 @@
import { baseAPI } from "@/Shared/API/baseAPI";
import axios, { AxiosError } from "axios";
import { StaticImport } from "next/dist/shared/lib/get-img-props";
import { StaticImageData } from "next/image";
interface IDetails {
id: number | null;
image: string;
title: string;
description: string;
news_review: IReview[];
created_at: string;
count_reviews: number;
}
interface IReview {
id: number;
author: IAuthor;
review: string;
created_at: string;
}
interface IAuthor {
id: number;
first_name: string;
last_name: string;
image: string;
}
class NewsDetailsStore {
error: string;
constructor() {
this.error = "";
}
async getNewsDetails(id: string) {
try {
const response = await axios.get<IDetails>(
`${baseAPI}/news/${id}/`
);
return response.data;
} catch (error: unknown) {
if (error instanceof AxiosError) {
this.error = error.message;
} else {
console.log(error);
this.error = "An error occured";
}
}
}
}
export const newsDetailsStore = new NewsDetailsStore();

View File

@ -1,24 +0,0 @@
.news-page {
padding: 118px 90px 0px 90px;
display: flex;
flex-direction: column;
gap: 35px;
}
@media screen and (max-width: 1024px) {
.news-page {
padding: 118px 30px 0px 30px;
}
}
@media screen and (max-width: 768px) {
.news-page {
padding: 112px 30px 0px 30px;
}
}
@media screen and (max-width: 550px) {
.news-page {
padding: 112px 16px 0px 16px;
}
}

View File

@ -1,14 +0,0 @@
import "./NewsPage.scss";
import NewsList from "@/Widgets/NewsList/NewsList";
import HeaderText from "@/Shared/UI/HeaderText/HeaderText";
const NewsPage = async () => {
return (
<div className="news-page">
<HeaderText>Новости</HeaderText>
<NewsList />
</div>
);
};
export default NewsPage;

View File

@ -1,36 +0,0 @@
.report-details-page {
padding: 118px 90px 0 90px;
&__container {
display: grid;
grid-template-columns: 52% 1fr;
gap: 76px;
}
}
@media screen and (max-width: 1024px) {
.report-details-page {
padding: 118px 30px 0 30px;
}
}
@media screen and (max-width: 768px) {
.report-details-page {
padding: 112px 30px 0 30px;
&__container {
grid-template-columns: 1fr;
gap: 45px;
}
}
}
@media screen and (max-width: 550px) {
.report-details-page {
padding: 112px 16px 0px 16px;
&__container {
gap: 40px;
}
}
}

View File

@ -1,32 +0,0 @@
import ReportInfo from "@/Widgets/ReportInfo/ReportInfo";
import "./ReportDetailsPage.scss";
import { reportDetailsStore } from "./report-details.store";
import ReportImages from "@/Widgets/ReportImages/ReportImages";
import ReviewsSection from "@/Widgets/general/ReviewsSection/ReviewsSection";
const ReportDetailsPage = async ({
params,
}: {
params: { id: string };
}) => {
const data = await reportDetailsStore.getReportDetails(params.id);
return (
<div className="report-details-page">
<div className="report-details-page__container">
<ReportInfo
description={data?.description}
date={data?.created_at}
category={data?.category}
count_likes={data?.total_likes}
author={data?.author}
location={data?.location}
/>
<ReportImages images={data?.image!} />
</div>
<ReviewsSection id={data?.id} endpoint="report" />
</div>
);
};
export default ReportDetailsPage;

View File

@ -1,57 +0,0 @@
import { baseAPI } from "@/Shared/API/baseAPI";
import axios, { AxiosError } from "axios";
interface IAuthor {
id: number;
first_name: string;
last_name: string;
govern_status: any;
}
interface ILocation {
id: number;
latitude: string;
longitude: string;
address: string;
}
interface IImage {
id: number;
image: string;
}
interface IReport {
id: number;
created_at: string;
location: ILocation[];
category: number;
description: string;
total_likes: number;
author: IAuthor;
image: IImage[];
}
class ReportDetailsStore {
error: string;
constructor() {
this.error = "";
}
async getReportDetails(id: string) {
try {
const response = await axios.get<IReport>(
`${baseAPI}/report/${id}/`
);
return response.data;
} catch (error: unknown) {
if (error instanceof AxiosError) {
this.error = error.message;
} else {
this.error = "An error occured";
}
}
}
}
export const reportDetailsStore = new ReportDetailsStore();

View File

@ -1,15 +0,0 @@
.sign-in-page {
height: 100vh;
min-height: 800px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 32px;
}
@media screen and (max-width: 550px) {
.sign-in-page {
padding: 0 16px;
}
}

View File

@ -1,19 +0,0 @@
import "./SignInPage.scss";
import sign_in_icon from "./icons/sign-in-icon.svg";
import AuthHeader from "@/Entities/AuthHeader/AuthHeader";
import SignInForm from "@/Features/SignInForm/SignInForm";
const SignInPage = () => {
return (
<div className="sign-in-page">
<AuthHeader
title="Войдите в аккаунт"
description="Пожалуйста, введите свои данные"
icon={sign_in_icon}
/>
<SignInForm />
</div>
);
};
export default SignInPage;

View File

@ -1,5 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="log-in-04">
<path id="Icon" d="M12 8L16 12M16 12L12 16M16 12H3M3.33782 7C5.06687 4.01099 8.29859 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C8.29859 22 5.06687 19.989 3.33782 17" stroke="#344054" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 395 B

View File

@ -1,15 +0,0 @@
.sign-up-page {
height: 100vh;
min-height: 800px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 32px;
}
@media screen and (max-width: 550px) {
.sign-up-page {
padding: 0 16px;
}
}

View File

@ -1,19 +0,0 @@
import "./SignUpPage.scss";
import AuthHeader from "@/Entities/AuthHeader/AuthHeader";
import flag_icon from "./icons/flag-icon.svg";
import SignUpForm from "@/Features/SignUpForm/SignUpForm";
const SignUpPage = () => {
return (
<div className="sign-up-page">
<AuthHeader
title="Регистрация"
description="Пожалуйста, введите свои данные"
icon={flag_icon}
/>
<SignUpForm />
</div>
);
};
export default SignUpPage;

View File

@ -1,5 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="flag-05">
<path id="Icon" d="M14.0914 6.72222H20.0451C20.5173 6.72222 20.7534 6.72222 20.8914 6.82149C21.0119 6.9081 21.0903 7.04141 21.1075 7.18877C21.1272 7.35767 21.0126 7.56403 20.7833 7.97677L19.3624 10.5343C19.2793 10.684 19.2377 10.7589 19.2214 10.8381C19.207 10.9083 19.207 10.9806 19.2214 11.0508C19.2377 11.13 19.2793 11.2049 19.3624 11.3545L20.7833 13.9121C21.0126 14.3248 21.1272 14.5312 21.1075 14.7001C21.0903 14.8475 21.0119 14.9808 20.8914 15.0674C20.7534 15.1667 20.5173 15.1667 20.0451 15.1667H12.6136C12.0224 15.1667 11.7269 15.1667 11.5011 15.0516C11.3024 14.9504 11.141 14.7889 11.0398 14.5903C10.9247 14.3645 10.9247 14.0689 10.9247 13.4778V10.9444M7.23027 21.5L3.00805 4.61111M4.59143 10.9444H12.4025C12.9937 10.9444 13.2892 10.9444 13.515 10.8294C13.7137 10.7282 13.8751 10.5667 13.9763 10.3681C14.0914 10.1423 14.0914 9.84672 14.0914 9.25556V4.18889C14.0914 3.59772 14.0914 3.30214 13.9763 3.07634C13.8751 2.87773 13.7137 2.71625 13.515 2.61505C13.2892 2.5 12.9937 2.5 12.4025 2.5H4.64335C3.90602 2.5 3.53735 2.5 3.2852 2.65278C3.0642 2.78668 2.89999 2.99699 2.82369 3.24387C2.73663 3.52555 2.82605 3.88321 3.00489 4.59852L4.59143 10.9444Z" stroke="#344054" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,24 +0,0 @@
.statistics-page {
padding: 118px 90px 0 90px;
display: flex;
flex-direction: column;
gap: 40px;
}
@media screen and (max-width: 1024px) {
.statistics-page {
padding: 118px 30px 0 30px;
}
}
@media screen and (max-width: 768px) {
.statistics-page {
padding: 112px 30px 0 30px;
}
}
@media screen and (max-width: 1024px) {
.statistics-page {
padding: 112px 16px 0 16px;
}
}

View File

@ -1,19 +0,0 @@
import HeaderText from "@/Shared/UI/HeaderText/HeaderText";
import "./StatisticsPage.scss";
import SearchBar from "@/Features/SearchBar/SearchBar";
import StatisticsTable from "@/Widgets/StatisticsTable/StatisticsTable";
const StatisticsPage = () => {
return (
<div className="statistics-page">
<HeaderText>Статистика</HeaderText>
<SearchBar
style={{ width: "100%" }}
placeholder="Введите населенный пункт"
/>
<StatisticsTable />
</div>
);
};
export default StatisticsPage;

View File

@ -1,24 +0,0 @@
.volunteers-page {
padding: 118px 90px 0 90px;
display: flex;
flex-direction: column;
gap: 40px;
}
@media screen and (max-width: 1024px) {
.volunteers-page {
padding: 118px 30px 0 30px;
}
}
@media screen and (max-width: 768px) {
.volunteers-page {
padding: 112px 30px 0 30px;
}
}
@media screen and (max-width: 550px) {
.volunteers-page {
padding: 112px 16px 0 16px;
}
}

View File

@ -1,14 +0,0 @@
import HeaderText from "@/Shared/UI/HeaderText/HeaderText";
import "./VolunteersPage.scss";
import VolunteersTable from "@/Widgets/VolunteersTable/VolunteersTable";
const VolunteersPage = () => {
return (
<div className="volunteers-page">
<HeaderText>Волонтеры</HeaderText>
<VolunteersTable />
</div>
);
};
export default VolunteersPage;

View File

@ -1,7 +0,0 @@
import "./MyReportsPage.scss";
const MyReportsPage = () => {
return <div className="my-reports-page">MyReportsPage</div>;
};
export default MyReportsPage;

View File

@ -1,7 +0,0 @@
import "./PersonalDataPage.scss";
const PersonalDataPage = () => {
return <div className="personal-data-page">PersonalDataPage</div>;
};
export default PersonalDataPage;

View File

@ -1,24 +0,0 @@
.profile-layout {
padding: 118px 90px 0 90px;
display: flex;
flex-direction: column;
gap: 50px;
}
@media screen and (max-width: 1024px) {
.personal-data-page {
padding: 118px 30px 0 30px;
}
}
@media screen and (max-width: 768px) {
.personal-data-page {
padding: 112px 30px 0 30px;
}
}
@media screen and (max-width: 550px) {
.personal-data-page {
padding: 112px 16px 0 16px;
}
}

Some files were not shown because too many files have changed in this diff Show More