forked from Transparency/kgroad-frontend2
Compare commits
1
Commits
release002
..
uat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a86d1adc57 |
No files matched your search
@@ -0,0 +1,2 @@
|
|||||||
|
NEXTAUTH_SECRET=";sadmfxflpdk"
|
||||||
|
NEXTAUTH_URL="http://localhost:3000"
|
||||||
@@ -5,7 +5,6 @@
|
|||||||
/.pnp
|
/.pnp
|
||||||
.pnp.js
|
.pnp.js
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.env
|
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
/coverage
|
/coverage
|
||||||
|
|||||||
File renamed without changes.
@@ -0,0 +1,3 @@
|
|||||||
|
import RootLayout from "@/app/App";
|
||||||
|
|
||||||
|
export default RootLayout;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
import Home from "@/pages/Home/Home";
|
||||||
|
|
||||||
|
export default Home;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const page = () => {
|
||||||
|
return <div>page</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default page;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const page = () => {
|
||||||
|
return <div>page</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default page;
|
||||||
Vendored
+1
-2
@@ -4,7 +4,6 @@ declare module "next-auth" {
|
|||||||
interface Session {
|
interface Session {
|
||||||
refresh_token: string;
|
refresh_token: string;
|
||||||
access_token: string;
|
access_token: string;
|
||||||
expires_in: string;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,6 +13,6 @@ declare module "next-auth/jwt" {
|
|||||||
interface JWT {
|
interface JWT {
|
||||||
refresh_token: string;
|
refresh_token: string;
|
||||||
access_token: string;
|
access_token: string;
|
||||||
expires_in: string;
|
exp: number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
distDir: "build",
|
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
|
|||||||
Generated
+4497
File diff suppressed because it is too large.
Load diff
+2
-4
@@ -5,12 +5,11 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start -p 8004",
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.6.5",
|
"axios": "^1.6.5",
|
||||||
"dotenv": "^16.4.1",
|
|
||||||
"leaflet": "^1.9.4",
|
"leaflet": "^1.9.4",
|
||||||
"next": "14.1.0",
|
"next": "14.1.0",
|
||||||
"next-auth": "^4.24.5",
|
"next-auth": "^4.24.5",
|
||||||
@@ -18,13 +17,12 @@
|
|||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"react-leaflet": "^4.2.1",
|
"react-leaflet": "^4.2.1",
|
||||||
"sass": "^1.70.0",
|
"sass": "^1.70.0",
|
||||||
"sharp": "^0.33.2",
|
|
||||||
"use-debounce": "^10.0.0",
|
"use-debounce": "^10.0.0",
|
||||||
"zustand": "^4.5.0"
|
"zustand": "^4.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/leaflet": "^1.9.8",
|
"@types/leaflet": "^1.9.8",
|
||||||
"@types/node": "^20.11.16",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
"@types/react-leaflet": "^3.0.0",
|
"@types/react-leaflet": "^3.0.0",
|
||||||
|
|||||||
File renamed without changes.
@@ -1,10 +1,8 @@
|
|||||||
import type { Metadata } from "next";
|
|
||||||
import "./globals.scss";
|
import "./globals.scss";
|
||||||
|
import "./fonts.scss";
|
||||||
import "./App.scss";
|
import "./App.scss";
|
||||||
// import "@/shared/fonts/fonts.scss";
|
|
||||||
import { Providers } from "./Providers";
|
|
||||||
import Navbar from "@/widgets/Navbar/Navbar";
|
|
||||||
import Footer from "@/widgets/Footer/Footer";
|
import Footer from "@/widgets/Footer/Footer";
|
||||||
|
import Navbar from "@/widgets/Navbar/Navbar";
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
children,
|
children,
|
||||||
@@ -14,11 +12,9 @@ export default function RootLayout({
|
|||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<body>
|
<body>
|
||||||
<Providers>
|
<Navbar />
|
||||||
<Navbar />
|
<div className="app">{children}</div>
|
||||||
<div className="app">{children}</div>
|
<Footer />
|
||||||
<Footer />
|
|
||||||
</Providers>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
a {
|
||||||
|
cursor: pointer;
|
||||||
|
color: black;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
ol,
|
||||||
|
li {
|
||||||
|
list-style-type: none;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +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;
|
||||||
|
line-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 300;
|
||||||
|
line-height: 29px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.section-header {
|
||||||
|
margin-bottom: 42px;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 36px;
|
||||||
|
line-height: 43px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 550px) {
|
||||||
|
.section-header {
|
||||||
|
margin-bottom: 42px;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 29px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export const baseAPI =
|
||||||
|
"https://api.kgroaduat.fishrungames.com/api/v1";
|
||||||
File renamed without changes.
-1
@@ -5,5 +5,4 @@
|
|||||||
url("TildaSans-Black.woff2") format("woff2"),
|
url("TildaSans-Black.woff2") format("woff2"),
|
||||||
url("TildaSans-Black.woff") format("woff");
|
url("TildaSans-Black.woff") format("woff");
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
font-style: normal;
|
|
||||||
}
|
}
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
-1
@@ -5,5 +5,4 @@
|
|||||||
url("TildaSans-Regular.woff2") format("woff2"),
|
url("TildaSans-Regular.woff2") format("woff2"),
|
||||||
url("TildaSans-Regular.woff") format("woff");
|
url("TildaSans-Regular.woff") format("woff");
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-style: normal;
|
|
||||||
}
|
}
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -3,5 +3,5 @@
|
|||||||
@import "./TildaSans-Medium/TildaSans-Medium.css";
|
@import "./TildaSans-Medium/TildaSans-Medium.css";
|
||||||
@import "./TildaSans-Semibold/TildaSans-Semibold.css";
|
@import "./TildaSans-Semibold/TildaSans-Semibold.css";
|
||||||
@import "./TildaSans-Bold/TildaSans-Bold.css";
|
@import "./TildaSans-Bold/TildaSans-Bold.css";
|
||||||
@import "./TildaSans-Extrabold/TildaSans-Extrabold.css";
|
@import "./TildaSans-ExtraBold/TildaSans-ExtraBold.css";
|
||||||
@import "./TildaSans-Black/TildaSans-Black.css";
|
@import "./TildaSans-Black/TildaSans-Black.css";
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
export interface IFetch {
|
export interface IFetch {
|
||||||
error: string;
|
error: string;
|
||||||
data?: any;
|
data: any;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
export interface IList {
|
export interface IList {
|
||||||
count: number | null;
|
count: number | null;
|
||||||
previous: string | null;
|
previous: number | null;
|
||||||
next: string | null;
|
next: number | null;
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,3 @@
|
|||||||
import { IList } from "./list-type";
|
|
||||||
|
|
||||||
export interface INews {
|
export interface INews {
|
||||||
id: number;
|
id: number;
|
||||||
image: string;
|
image: string;
|
||||||
@@ -10,7 +8,3 @@ export interface INews {
|
|||||||
updated_at: string;
|
updated_at: string;
|
||||||
count_reviews: number;
|
count_reviews: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface INewsList extends IList {
|
|
||||||
results: INews[];
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
export interface IAuthor {
|
||||||
|
id: number;
|
||||||
|
first_name: string;
|
||||||
|
last_name: string;
|
||||||
|
govern_status: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ILocation {
|
||||||
|
id: 4;
|
||||||
|
latitude: number;
|
||||||
|
longitude: number;
|
||||||
|
address: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IReportImage {
|
||||||
|
id: number;
|
||||||
|
image: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IReport {
|
||||||
|
results: any;
|
||||||
|
id: number;
|
||||||
|
image: IReportImage[];
|
||||||
|
description: string;
|
||||||
|
author: IAuthor;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
location: ILocation[];
|
||||||
|
category: number;
|
||||||
|
total_likes: number;
|
||||||
|
count_reviews: number;
|
||||||
|
}
|
||||||
@@ -6,5 +6,4 @@ $light-green: rgb(74, 192, 63);
|
|||||||
$gray-300: #d0d5dd;
|
$gray-300: #d0d5dd;
|
||||||
$gray-500: #667085;
|
$gray-500: #667085;
|
||||||
$gray-700: #344054;
|
$gray-700: #344054;
|
||||||
$gray-900: rgb(16, 24, 40);
|
|
||||||
$black: rgb(50, 48, 58);
|
$black: rgb(50, 48, 58);
|
||||||
File renamed without changes.
File renamed without changes.
@@ -10,7 +10,7 @@
|
|||||||
height: fit-content;
|
height: fit-content;
|
||||||
color: white;
|
color: white;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
font-family: "Inter", sans-serif;
|
font-family: "Inter";
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ const Footer = () => {
|
|||||||
<h4>Навигация</h4>
|
<h4>Навигация</h4>
|
||||||
<ul>
|
<ul>
|
||||||
{LINKS.map((link) => (
|
{LINKS.map((link) => (
|
||||||
<li key={link.id}>
|
<li>
|
||||||
<Link href={link.pathname} key={link.id}>
|
<Link href={link.pathname} key={link.id}>
|
||||||
{link.pagename}
|
{link.pagename}
|
||||||
</Link>
|
</Link>
|
||||||
@@ -34,8 +34,8 @@ const Footer = () => {
|
|||||||
<li>namename@gmail.com</li>
|
<li>namename@gmail.com</li>
|
||||||
<li>+09646895467</li>
|
<li>+09646895467</li>
|
||||||
<li>
|
<li>
|
||||||
{[youtube, facebook, instagram].map((net, i) => (
|
{[youtube, facebook, instagram].map((net) => (
|
||||||
<Link key={i} href="#">
|
<Link href="#">
|
||||||
<Image src={net} alt="Net Icon" key={net} />
|
<Image src={net} alt="Net Icon" key={net} />
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
@@ -46,8 +46,8 @@ const Footer = () => {
|
|||||||
<div className="footer__apps">
|
<div className="footer__apps">
|
||||||
<h4>Скачивай наше приложение</h4>
|
<h4>Скачивай наше приложение</h4>
|
||||||
<div className="footer__apps-btns">
|
<div className="footer__apps-btns">
|
||||||
{[app_store_btn, play_market_btn].map((app, i) => (
|
{[app_store_btn, play_market_btn].map((app) => (
|
||||||
<Link key={i} href="#">
|
<Link href="#">
|
||||||
<Image src={app} alt="App Button" key={app} />
|
<Image src={app} alt="App Button" key={app} />
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
-3
@@ -7,9 +7,6 @@
|
|||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
gap: 30px;
|
gap: 30px;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,88 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import "./HomeMap.scss";
|
||||||
|
import "leaflet/dist/leaflet.css";
|
||||||
|
import {
|
||||||
|
MapContainer,
|
||||||
|
Marker,
|
||||||
|
Popup,
|
||||||
|
TileLayer,
|
||||||
|
} from "react-leaflet";
|
||||||
|
import geo_green_icon from "./icons/geo-green.svg";
|
||||||
|
import geo_orange_icon from "./icons/geo-orange.svg";
|
||||||
|
import geo_pink_icon from "./icons/geo-pink.svg";
|
||||||
|
import geo_purple_icon from "./icons/geo-purple.svg";
|
||||||
|
import geo_red_icon from "./icons/geo-red.svg";
|
||||||
|
import geo_yellow_icon from "./icons/geo-yellow.svg";
|
||||||
|
import { DivIcon, Icon, LatLngTuple } from "leaflet";
|
||||||
|
import { StaticImageData } from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { ILocation } from "@/shared/types/report-type";
|
||||||
|
|
||||||
|
interface IData {
|
||||||
|
id: number;
|
||||||
|
location: ILocation[];
|
||||||
|
category: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IHomeMapProps {
|
||||||
|
data: IData[] | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HomeMap: React.FC<IHomeMapProps> = ({
|
||||||
|
data,
|
||||||
|
}: IHomeMapProps) => {
|
||||||
|
const createCustomIcon = (icon: StaticImageData) => {
|
||||||
|
const customIcon = new Icon({
|
||||||
|
iconUrl: icon.src,
|
||||||
|
iconSize: [32, 32],
|
||||||
|
});
|
||||||
|
|
||||||
|
return customIcon;
|
||||||
|
};
|
||||||
|
|
||||||
|
const icons: Record<string, DivIcon> = {
|
||||||
|
1: createCustomIcon(geo_red_icon),
|
||||||
|
2: createCustomIcon(geo_pink_icon),
|
||||||
|
3: createCustomIcon(geo_purple_icon),
|
||||||
|
4: createCustomIcon(geo_orange_icon),
|
||||||
|
5: createCustomIcon(geo_green_icon),
|
||||||
|
6: createCustomIcon(geo_yellow_icon),
|
||||||
|
};
|
||||||
|
|
||||||
|
const position = [42.8746, 74.606];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MapContainer
|
||||||
|
center={position as LatLngTuple}
|
||||||
|
zoom={14}
|
||||||
|
scrollWheelZoom={false}
|
||||||
|
className="home-map"
|
||||||
|
>
|
||||||
|
<TileLayer
|
||||||
|
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||||
|
/>
|
||||||
|
{data?.map((marker) => (
|
||||||
|
<Marker
|
||||||
|
key={marker.id}
|
||||||
|
icon={icons[marker.category]}
|
||||||
|
position={
|
||||||
|
[
|
||||||
|
+marker.location[0].latitude,
|
||||||
|
+marker.location[0].longitude,
|
||||||
|
] as LatLngTuple
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Popup>
|
||||||
|
<Link href={`/report/${marker.location[0].id}`}>
|
||||||
|
{marker.location[0].address}
|
||||||
|
</Link>
|
||||||
|
</Popup>
|
||||||
|
</Marker>
|
||||||
|
))}
|
||||||
|
</MapContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default HomeMap;
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -4,15 +4,6 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&__header {
|
|
||||||
margin-bottom: 50px;
|
|
||||||
text-align: center;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__categories {
|
&__categories {
|
||||||
margin-bottom: 60px;
|
margin-bottom: 60px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -37,13 +28,9 @@
|
|||||||
|
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px) {
|
||||||
.map-section {
|
.map-section {
|
||||||
&__header {
|
|
||||||
margin-bottom: 40px;
|
|
||||||
gap: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__categories {
|
&__categories {
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
|
|
||||||
gap: 25px;
|
gap: 25px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,13 +38,9 @@
|
|||||||
|
|
||||||
@media screen and (max-width: 550px) {
|
@media screen and (max-width: 550px) {
|
||||||
.map-section {
|
.map-section {
|
||||||
&__header {
|
|
||||||
margin-bottom: 25px;
|
|
||||||
gap: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__categories {
|
&__categories {
|
||||||
margin-bottom: 25px;
|
margin-bottom: 25px;
|
||||||
|
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import "./MapSection.scss";
|
||||||
|
import SearchForm from "@/features/SearchBar/SearchForm";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import SectionHeader from "@/entities/SectionHeader/SectionHeader";
|
||||||
|
import {
|
||||||
|
ROAD_TYPES,
|
||||||
|
ROAD_TYPES_COLORS,
|
||||||
|
} from "@/shared/variables/road-types";
|
||||||
|
import HomeMap from "./HomeMap/HomeMap";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { useMapStore } from "./mapSectionStore";
|
||||||
|
import Switch from "./Switch/Switch";
|
||||||
|
import { useShallow } from "zustand/react/shallow";
|
||||||
|
|
||||||
|
interface IMapSectionProps {
|
||||||
|
[key: string]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MapSection: React.FC<IMapSectionProps> = ({
|
||||||
|
categories = "1,2,3,4,5,6",
|
||||||
|
queryMap,
|
||||||
|
queryRating,
|
||||||
|
}: IMapSectionProps) => {
|
||||||
|
const [mapSearch, setMapSearch] = useState<string>(queryMap || "");
|
||||||
|
const data = useMapStore(useShallow((state) => state.data));
|
||||||
|
const getReports = useMapStore(
|
||||||
|
useShallow((state) => state.getReports)
|
||||||
|
);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getReports(categories);
|
||||||
|
}, [categories]);
|
||||||
|
|
||||||
|
const handleSubmit: React.FormEventHandler<
|
||||||
|
HTMLFormElement
|
||||||
|
> = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const formData = new FormData(e.currentTarget);
|
||||||
|
setMapSearch(formData.get("map-search") as string);
|
||||||
|
|
||||||
|
router.push(
|
||||||
|
`/?тип-дороги=${categories}${
|
||||||
|
mapSearch ? `&поиск-на-карте=${mapSearch}` : ""
|
||||||
|
}${queryRating ? `&поиск-рейтинг=${queryRating}` : ""}`,
|
||||||
|
{
|
||||||
|
scroll: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setSearchParams = (category: string) => {
|
||||||
|
const availableCategories = ["1", "2", "3", "4", "5", "6"];
|
||||||
|
|
||||||
|
if (!categories || !availableCategories.includes(category))
|
||||||
|
return categories;
|
||||||
|
|
||||||
|
if (categories?.includes(category)) {
|
||||||
|
const updatedCategories = categories
|
||||||
|
?.replace(category + ",", "")
|
||||||
|
.replace("," + category, "")
|
||||||
|
.replace(category, "");
|
||||||
|
|
||||||
|
return updatedCategories;
|
||||||
|
} else {
|
||||||
|
const newValue = category + ",";
|
||||||
|
const updatedCategories = newValue + categories;
|
||||||
|
return updatedCategories;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="map-section">
|
||||||
|
<SectionHeader
|
||||||
|
title="Карта дорог"
|
||||||
|
description="Будьте в курсе последних новостей о дорожном движении, строительствах и мероприятиях!"
|
||||||
|
/>
|
||||||
|
<SearchForm
|
||||||
|
onChange={(e) => setMapSearch(e.target.value)}
|
||||||
|
name="map-search"
|
||||||
|
value={mapSearch}
|
||||||
|
placeholder="Введите город, село или регион"
|
||||||
|
handleSubmit={handleSubmit}
|
||||||
|
/>
|
||||||
|
<div className="map-section__categories">
|
||||||
|
<ul className="map-section__categories_left">
|
||||||
|
{[1, 2, 3].map((sw) => (
|
||||||
|
<li key={sw}>
|
||||||
|
<Switch
|
||||||
|
href={`/?тип-дороги=${setSearchParams(
|
||||||
|
sw.toString()
|
||||||
|
)}`}
|
||||||
|
color={ROAD_TYPES_COLORS[sw]}
|
||||||
|
defaultState={categories.includes(sw.toString())}
|
||||||
|
/>
|
||||||
|
<label>{ROAD_TYPES[sw]}</label>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<ul className="map-section__categories_right">
|
||||||
|
{[4, 5, 6].map((sw) => (
|
||||||
|
<li key={sw}>
|
||||||
|
<Switch
|
||||||
|
href={`/?тип-дороги=${setSearchParams(
|
||||||
|
sw.toString()
|
||||||
|
)}`}
|
||||||
|
color={ROAD_TYPES_COLORS[sw]}
|
||||||
|
defaultState={categories.includes(sw.toString())}
|
||||||
|
/>
|
||||||
|
<label>{ROAD_TYPES[sw]}</label>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<HomeMap data={data?.results} />
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MapSection;
|
||||||
File renamed without changes.
@@ -5,7 +5,7 @@ import "./Switch.scss";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
interface ISwitchProps {
|
interface ISwitchProps {
|
||||||
defaultState: boolean;
|
defaultState?: boolean;
|
||||||
color?: string;
|
color?: string;
|
||||||
href: string;
|
href: string;
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@ const Switch: React.FC<ISwitchProps> = ({
|
|||||||
onClick={() => setToggleSwitch((prev) => !prev)}
|
onClick={() => setToggleSwitch((prev) => !prev)}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: !toggleSwitch
|
backgroundColor: !toggleSwitch
|
||||||
? "rgb(71, 85, 105)"
|
? "rgb(50, 48, 58)"
|
||||||
: color
|
: color
|
||||||
? color
|
? color
|
||||||
: "rgb(230, 68, 82)",
|
: "rgb(230, 68, 82)",
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { baseAPI } from "@/shared/api/baseAPI";
|
||||||
|
import { IFetch } from "@/shared/types/fetch-type";
|
||||||
|
import { IList } from "@/shared/types/list-type";
|
||||||
|
import { IReport } from "@/shared/types/report-type";
|
||||||
|
import axios from "axios";
|
||||||
|
import { create } from "zustand";
|
||||||
|
|
||||||
|
interface IFetchReports extends IList {
|
||||||
|
results: IReport[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IMapStore extends IFetch {
|
||||||
|
data: IFetchReports;
|
||||||
|
getReports: (categories: string) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useMapStore = create<IMapStore>((set) => ({
|
||||||
|
data: {
|
||||||
|
count: 0,
|
||||||
|
previous: null,
|
||||||
|
next: null,
|
||||||
|
results: [],
|
||||||
|
},
|
||||||
|
isLoading: false,
|
||||||
|
error: "",
|
||||||
|
getReports: async (categories: string = "1,2,3,4,5,6") => {
|
||||||
|
try {
|
||||||
|
set({ isLoading: true });
|
||||||
|
|
||||||
|
const response = await axios.get<IFetchReports>(
|
||||||
|
`${baseAPI}/report/?category=${categories}`
|
||||||
|
);
|
||||||
|
|
||||||
|
set({ data: response.data });
|
||||||
|
} catch (error: any) {
|
||||||
|
set({ error: error.message });
|
||||||
|
} finally {
|
||||||
|
set({ isLoading: false });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}));
|
||||||
File renamed without changes.
@@ -1,26 +1,21 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import "./NavAuth.scss";
|
import "./NavAuth.scss";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import { useSession } from "next-auth/react";
|
|
||||||
|
|
||||||
interface INavAuthProps {
|
interface INavAuthProps {
|
||||||
responsible?: boolean;
|
responsible?: boolean;
|
||||||
setOpenMenu: (boolean: boolean) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const NavAuth: React.FC<INavAuthProps> = ({
|
const NavAuth: React.FC<INavAuthProps> = ({
|
||||||
responsible,
|
responsible,
|
||||||
setOpenMenu,
|
|
||||||
}: INavAuthProps) => {
|
}: INavAuthProps) => {
|
||||||
const session = useSession();
|
const auth = false;
|
||||||
const auth = session.status === "authenticated" ? true : false;
|
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{auth ? (
|
{auth ? (
|
||||||
<Link
|
<Link
|
||||||
onClick={() => setOpenMenu(false)}
|
href="/profile"
|
||||||
href="/profile/personal"
|
|
||||||
className={`nav-auth-profile-${
|
className={`nav-auth-profile-${
|
||||||
responsible
|
responsible
|
||||||
? `sm${pathname === "/profile" ? "_active" : ""}`
|
? `sm${pathname === "/profile" ? "_active" : ""}`
|
||||||
@@ -31,7 +26,6 @@ const NavAuth: React.FC<INavAuthProps> = ({
|
|||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<Link
|
<Link
|
||||||
onClick={() => setOpenMenu(false)}
|
|
||||||
href="/sign-in"
|
href="/sign-in"
|
||||||
className={`nav-auth-signin-${
|
className={`nav-auth-signin-${
|
||||||
responsible
|
responsible
|
||||||
+1
-4
@@ -14,17 +14,14 @@
|
|||||||
|
|
||||||
&__option,
|
&__option,
|
||||||
&__option_active {
|
&__option_active {
|
||||||
padding: 10px 14px;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
padding: 10px 14px;
|
||||||
font-weight: 900;
|
font-weight: 900;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
background-color: #fff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__option_active {
|
&__option_active {
|
||||||
background-color: rgb(249, 250, 251);
|
background-color: rgb(249, 250, 251);
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -4,19 +4,13 @@ import Link from "next/link";
|
|||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import NavAuth from "../NavAuth/NavAuth";
|
import NavAuth from "../NavAuth/NavAuth";
|
||||||
|
|
||||||
interface INavMenuProps {
|
const NavMenu = () => {
|
||||||
setOpenMenu: (boolean: boolean) => void;
|
const auth = false;
|
||||||
}
|
|
||||||
|
|
||||||
const NavMenu: React.FC<INavMenuProps> = ({
|
|
||||||
setOpenMenu,
|
|
||||||
}: INavMenuProps) => {
|
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
return (
|
return (
|
||||||
<nav className="nav-menu">
|
<nav className="nav-menu">
|
||||||
{LINKS.map((link) => (
|
{LINKS.map((link) => (
|
||||||
<Link
|
<Link
|
||||||
onClick={() => setOpenMenu(false)}
|
|
||||||
className={`nav-menu__link${
|
className={`nav-menu__link${
|
||||||
pathname === link.pathname ? "_active" : ""
|
pathname === link.pathname ? "_active" : ""
|
||||||
}`}
|
}`}
|
||||||
@@ -27,7 +21,7 @@ const NavMenu: React.FC<INavMenuProps> = ({
|
|||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<NavAuth setOpenMenu={setOpenMenu} responsible />
|
<NavAuth responsible />
|
||||||
</nav>
|
</nav>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -5,14 +5,14 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 78px;
|
height: 78px;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 10005;
|
z-index: 10000;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
|
||||||
&__links {
|
&__links {
|
||||||
height: 40%;
|
height: 60%;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 60px;
|
gap: 60px;
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,7 @@ const Navbar = () => {
|
|||||||
|
|
||||||
<div className="navbar__lang-and-auth">
|
<div className="navbar__lang-and-auth">
|
||||||
<NavLanguage />
|
<NavLanguage />
|
||||||
<NavAuth setOpenMenu={setOpenMenu} />
|
<NavAuth />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
@@ -50,7 +50,7 @@ const Navbar = () => {
|
|||||||
<Image src={openMenu ? cross : menu} alt="menu icon" />
|
<Image src={openMenu ? cross : menu} alt="menu icon" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{openMenu && <NavMenu setOpenMenu={setOpenMenu} />}
|
{openMenu && <NavMenu />}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
File renamed without changes.
File renamed without changes.
@@ -4,11 +4,6 @@
|
|||||||
padding: 60px 90px 100px 90px;
|
padding: 60px 90px 100px 90px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
h3 {
|
|
||||||
margin-bottom: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__list {
|
&__list {
|
||||||
margin-bottom: 40px;
|
margin-bottom: 40px;
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -2,15 +2,15 @@ import "./NewsSection.scss";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { getNews } from "./newsSectionStore";
|
import { getNews } from "./newsSectionStore";
|
||||||
|
import SectionHeader from "@/entities/SectionHeader/SectionHeader";
|
||||||
import arrow_icon from "./icons/arrow-right.svg";
|
import arrow_icon from "./icons/arrow-right.svg";
|
||||||
import NewsCard from "@/entities/NewsCard/NewsCard";
|
import NewsCard from "@/entities/NewsCard/NewsCard";
|
||||||
import Typography from "@/shared/ui/components/Typography/Typography";
|
|
||||||
|
|
||||||
const NewsSection = async () => {
|
const NewsSection = async () => {
|
||||||
const news = await getNews();
|
const news = await getNews();
|
||||||
return (
|
return (
|
||||||
<section className="news-section">
|
<section className="news-section">
|
||||||
<Typography element="h3">Новости</Typography>
|
<SectionHeader title="Новости" />
|
||||||
<ul className="news-section__list">
|
<ul className="news-section__list">
|
||||||
{news?.map((article) => (
|
{news?.map((article) => (
|
||||||
<li key={article.id} className="news-section__card">
|
<li key={article.id} className="news-section__card">
|
||||||
Loaded 100 of 266 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user