forked from Transparency/kgroad-frontend2
Compare commits
1
Commits
release003
..
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.js
|
||||
.yarn/install-state.gz
|
||||
.env
|
||||
|
||||
# testing
|
||||
/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 {
|
||||
refresh_token: string;
|
||||
access_token: string;
|
||||
expires_in: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +13,6 @@ declare module "next-auth/jwt" {
|
||||
interface JWT {
|
||||
refresh_token: string;
|
||||
access_token: string;
|
||||
expires_in: string;
|
||||
exp: number;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
distDir: "build",
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
|
||||
Generated
+4497
File diff suppressed because it is too large.
Load diff
+3
-6
@@ -5,27 +5,24 @@
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start -p 8003",
|
||||
"start": "next start -p 8004",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@next/third-parties": "^14.1.0",
|
||||
"axios": "^1.6.5",
|
||||
"dotenv": "^16.4.1",
|
||||
"leaflet": "^1.9.4",
|
||||
"next": "^14.1.0",
|
||||
"next": "14.1.0",
|
||||
"next-auth": "^4.24.5",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-leaflet": "^4.2.1",
|
||||
"sass": "^1.70.0",
|
||||
"sharp": "^0.33.2",
|
||||
"use-debounce": "^10.0.0",
|
||||
"zustand": "^4.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/leaflet": "^1.9.8",
|
||||
"@types/node": "^20.11.16",
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"@types/react-leaflet": "^3.0.0",
|
||||
|
||||
File renamed without changes.
@@ -0,0 +1,21 @@
|
||||
import "./globals.scss";
|
||||
import "./fonts.scss";
|
||||
import "./App.scss";
|
||||
import Footer from "@/widgets/Footer/Footer";
|
||||
import Navbar from "@/widgets/Navbar/Navbar";
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<Navbar />
|
||||
<div className="app">{children}</div>
|
||||
<Footer />
|
||||
</body>
|
||||
</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.woff") format("woff");
|
||||
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.woff") format("woff");
|
||||
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-Semibold/TildaSans-Semibold.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";
|
||||
@@ -1,5 +1,5 @@
|
||||
export interface IFetch {
|
||||
error: string;
|
||||
data?: any;
|
||||
data: any;
|
||||
isLoading: boolean;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
export interface IList {
|
||||
count: number | null;
|
||||
previous: string | null;
|
||||
next: string | null;
|
||||
previous: number | null;
|
||||
next: number | null;
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
import { IList } from "./list-type";
|
||||
|
||||
export interface INews {
|
||||
id: number;
|
||||
image: string;
|
||||
@@ -10,7 +8,3 @@ export interface INews {
|
||||
updated_at: string;
|
||||
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-500: #667085;
|
||||
$gray-700: #344054;
|
||||
$gray-900: rgb(16, 24, 40);
|
||||
$black: rgb(50, 48, 58);
|
||||
File renamed without changes.
File renamed without changes.
@@ -10,7 +10,7 @@
|
||||
height: fit-content;
|
||||
color: white;
|
||||
justify-content: flex-start;
|
||||
font-family: "Inter", sans-serif;
|
||||
font-family: "Inter";
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import facebook from "./icons/facebook.svg";
|
||||
import instagram from "./icons/instagram.svg";
|
||||
import app_store_btn from "./icons/app-store-btn.svg";
|
||||
import play_market_btn from "./icons/play-market-btn.svg";
|
||||
import NetKgTracker from "@/widgets/NetKgTracker/NetKgTracker";
|
||||
|
||||
const Footer = () => {
|
||||
return (
|
||||
@@ -20,45 +19,40 @@ const Footer = () => {
|
||||
<h4>Навигация</h4>
|
||||
<ul>
|
||||
{LINKS.map((link) => (
|
||||
<li key={link.id}>
|
||||
<li>
|
||||
<Link href={link.pathname} key={link.id}>
|
||||
{link.pagename}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<NetKgTracker />
|
||||
</div>
|
||||
|
||||
<div className="footer__contacts">
|
||||
<h4>Контакты</h4>
|
||||
<ul>
|
||||
<li>admin@kgroad.org</li>
|
||||
<li>+9960312394038</li>
|
||||
{/*
|
||||
<li>namename@gmail.com</li>
|
||||
<li>+09646895467</li>
|
||||
<li>
|
||||
{[youtube, facebook, instagram].map((net, i) => (
|
||||
<Link key={i} href="#">
|
||||
{[youtube, facebook, instagram].map((net) => (
|
||||
<Link href="#">
|
||||
<Image src={net} alt="Net Icon" key={net} />
|
||||
</Link>
|
||||
))}
|
||||
</li>
|
||||
*/}
|
||||
</ul>
|
||||
<p className="text-white">Photo By ThomasG, CC BY-SA 3.0</p>
|
||||
</div>
|
||||
{/*
|
||||
|
||||
<div className="footer__apps">
|
||||
<h4>Скачивай наше приложение</h4>
|
||||
<div className="footer__apps-btns">
|
||||
{[app_store_btn, play_market_btn].map((app, i) => (
|
||||
<Link key={i} href="#">
|
||||
{[app_store_btn, play_market_btn].map((app) => (
|
||||
<Link href="#">
|
||||
<Image src={app} alt="App Button" key={app} />
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
*/}
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -13,10 +13,10 @@ const Header = () => {
|
||||
/>
|
||||
<div className="header__text">
|
||||
<h1>
|
||||
Дороги Кыргызстана
|
||||
Borem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
</h1>
|
||||
<p>
|
||||
Сделаем дороги безопасными! Актуальная информация о состоянии дорог.
|
||||
Borem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
-3
@@ -7,9 +7,6 @@
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 30px;
|
||||
border-radius: 15px;
|
||||
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;
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="38" height="50" viewBox="0 0 38 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 0C8.52334 0 0 8.74812 0 19.501C0 32.8456 17.0031 48.5901 17.7271 49.4175C18.407 50.1948 19.5942 50.1935 20.2729 49.4175C20.9969 48.5901 38 32.8456 38 19.501C37.9998 8.74812 29.4766 0 19 0Z" fill="#3998E8" fill-opacity="0.7"/>
|
||||
<ellipse cx="18.7867" cy="19" rx="9.88775" ry="10" fill="white"/>
|
||||
<circle cx="18.5" cy="18.5" r="7.5" fill="#8FDE6A"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 461 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="38" height="50" viewBox="0 0 38 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 0C8.52334 0 0 8.74812 0 19.501C0 32.8456 17.0031 48.5901 17.7271 49.4175C18.407 50.1948 19.5942 50.1935 20.2729 49.4175C20.9969 48.5901 38 32.8456 38 19.501C37.9998 8.74812 29.4766 0 19 0Z" fill="#3998E8" fill-opacity="0.7"/>
|
||||
<ellipse cx="18.7867" cy="19" rx="9.88775" ry="10" fill="white"/>
|
||||
<circle cx="18.5" cy="18.5" r="7.5" fill="#FFAC33"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 461 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="38" height="50" viewBox="0 0 38 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 0C8.52334 0 0 8.74812 0 19.501C0 32.8456 17.0031 48.5901 17.7271 49.4175C18.407 50.1948 19.5942 50.1935 20.2729 49.4175C20.9969 48.5901 38 32.8456 38 19.501C37.9998 8.74812 29.4766 0 19 0Z" fill="#3998E8" fill-opacity="0.7"/>
|
||||
<ellipse cx="18.7867" cy="19" rx="9.88775" ry="10" fill="white"/>
|
||||
<circle cx="18.5" cy="18.5" r="7.5" fill="#C288E2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 461 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="38" height="50" viewBox="0 0 38 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 0C8.52334 0 0 8.74812 0 19.501C0 32.8456 17.0031 48.5901 17.7271 49.4175C18.407 50.1948 19.5942 50.1935 20.2729 49.4175C20.9969 48.5901 38 32.8456 38 19.501C37.9998 8.74812 29.4766 0 19 0Z" fill="#3998E8" fill-opacity="0.7"/>
|
||||
<ellipse cx="18.7867" cy="19" rx="9.88775" ry="10" fill="white"/>
|
||||
<circle cx="18.5" cy="18.5" r="7.5" fill="#87289D"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 461 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="38" height="50" viewBox="0 0 38 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 0C8.52334 0 0 8.74812 0 19.501C0 32.8456 17.0031 48.5901 17.7271 49.4175C18.407 50.1948 19.5942 50.1935 20.2729 49.4175C20.9969 48.5901 38 32.8456 38 19.501C37.9998 8.74812 29.4766 0 19 0Z" fill="#3998E8" fill-opacity="0.7"/>
|
||||
<ellipse cx="18.7867" cy="19" rx="9.88775" ry="10" fill="white"/>
|
||||
<circle cx="18.5" cy="18.5" r="7.5" fill="#E64452"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 461 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="38" height="50" viewBox="0 0 38 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 0C8.52334 0 0 8.74812 0 19.501C0 32.8456 17.0031 48.5901 17.7271 49.4175C18.407 50.1948 19.5942 50.1935 20.2729 49.4175C20.9969 48.5901 38 32.8456 38 19.501C37.9998 8.74812 29.4766 0 19 0Z" fill="#3998E8" fill-opacity="0.7"/>
|
||||
<ellipse cx="18.7867" cy="19" rx="9.88775" ry="10" fill="white"/>
|
||||
<circle cx="18.5" cy="18.5" r="7.5" fill="#FED363"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 461 B |
@@ -4,15 +4,6 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
&__header {
|
||||
margin-bottom: 50px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
&__categories {
|
||||
margin-bottom: 60px;
|
||||
display: flex;
|
||||
@@ -37,13 +28,9 @@
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.map-section {
|
||||
&__header {
|
||||
margin-bottom: 40px;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
&__categories {
|
||||
margin-bottom: 40px;
|
||||
|
||||
gap: 25px;
|
||||
}
|
||||
}
|
||||
@@ -51,13 +38,9 @@
|
||||
|
||||
@media screen and (max-width: 550px) {
|
||||
.map-section {
|
||||
&__header {
|
||||
margin-bottom: 25px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
&__categories {
|
||||
margin-bottom: 25px;
|
||||
|
||||
padding: 0 16px;
|
||||
width: 100%;
|
||||
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";
|
||||
|
||||
interface ISwitchProps {
|
||||
defaultState: boolean;
|
||||
defaultState?: boolean;
|
||||
color?: string;
|
||||
href: string;
|
||||
}
|
||||
@@ -25,7 +25,7 @@ const Switch: React.FC<ISwitchProps> = ({
|
||||
onClick={() => setToggleSwitch((prev) => !prev)}
|
||||
style={{
|
||||
backgroundColor: !toggleSwitch
|
||||
? "rgb(71, 85, 105)"
|
||||
? "rgb(50, 48, 58)"
|
||||
: color
|
||||
? color
|
||||
: "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 "./NavAuth.scss";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useSession } from "next-auth/react";
|
||||
|
||||
interface INavAuthProps {
|
||||
responsible?: boolean;
|
||||
setOpenMenu: (boolean: boolean) => void;
|
||||
}
|
||||
|
||||
const NavAuth: React.FC<INavAuthProps> = ({
|
||||
responsible,
|
||||
setOpenMenu,
|
||||
}: INavAuthProps) => {
|
||||
const session = useSession();
|
||||
const auth = session.status === "authenticated" ? true : false;
|
||||
const auth = false;
|
||||
const pathname = usePathname();
|
||||
return (
|
||||
<>
|
||||
{auth ? (
|
||||
<Link
|
||||
onClick={() => setOpenMenu(false)}
|
||||
href="/profile/personal"
|
||||
href="/profile"
|
||||
className={`nav-auth-profile-${
|
||||
responsible
|
||||
? `sm${pathname === "/profile" ? "_active" : ""}`
|
||||
@@ -31,7 +26,6 @@ const NavAuth: React.FC<INavAuthProps> = ({
|
||||
</Link>
|
||||
) : (
|
||||
<Link
|
||||
onClick={() => setOpenMenu(false)}
|
||||
href="/sign-in"
|
||||
className={`nav-auth-signin-${
|
||||
responsible
|
||||
+1
-4
@@ -14,17 +14,14 @@
|
||||
|
||||
&__option,
|
||||
&__option_active {
|
||||
padding: 10px 14px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
padding: 10px 14px;
|
||||
font-weight: 900;
|
||||
justify-content: flex-start;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
&__option_active {
|
||||
background-color: rgb(249, 250, 251);
|
||||
align-items: center;
|
||||
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 NavAuth from "../NavAuth/NavAuth";
|
||||
|
||||
interface INavMenuProps {
|
||||
setOpenMenu: (boolean: boolean) => void;
|
||||
}
|
||||
|
||||
const NavMenu: React.FC<INavMenuProps> = ({
|
||||
setOpenMenu,
|
||||
}: INavMenuProps) => {
|
||||
const NavMenu = () => {
|
||||
const auth = false;
|
||||
const pathname = usePathname();
|
||||
return (
|
||||
<nav className="nav-menu">
|
||||
{LINKS.map((link) => (
|
||||
<Link
|
||||
onClick={() => setOpenMenu(false)}
|
||||
className={`nav-menu__link${
|
||||
pathname === link.pathname ? "_active" : ""
|
||||
}`}
|
||||
@@ -27,7 +21,7 @@ const NavMenu: React.FC<INavMenuProps> = ({
|
||||
</Link>
|
||||
))}
|
||||
|
||||
<NavAuth setOpenMenu={setOpenMenu} responsible />
|
||||
<NavAuth responsible />
|
||||
</nav>
|
||||
);
|
||||
};
|
||||
@@ -5,14 +5,14 @@
|
||||
width: 100%;
|
||||
height: 78px;
|
||||
position: fixed;
|
||||
z-index: 10005;
|
||||
z-index: 10000;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #fff;
|
||||
|
||||
&__links {
|
||||
height: 40%;
|
||||
height: 60%;
|
||||
display: flex;
|
||||
gap: 60px;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ const Navbar = () => {
|
||||
|
||||
<div className="navbar__lang-and-auth">
|
||||
<NavLanguage />
|
||||
<NavAuth setOpenMenu={setOpenMenu} />
|
||||
<NavAuth />
|
||||
</div>
|
||||
|
||||
<button
|
||||
@@ -50,7 +50,7 @@ const Navbar = () => {
|
||||
<Image src={openMenu ? cross : menu} alt="menu icon" />
|
||||
</button>
|
||||
|
||||
{openMenu && <NavMenu setOpenMenu={setOpenMenu} />}
|
||||
{openMenu && <NavMenu />}
|
||||
</section>
|
||||
);
|
||||
};
|
||||
File renamed without changes.
File renamed without changes.
@@ -4,11 +4,6 @@
|
||||
padding: 60px 90px 100px 90px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
h3 {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
&__list {
|
||||
margin-bottom: 40px;
|
||||
display: grid;
|
||||
@@ -2,15 +2,15 @@ import "./NewsSection.scss";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { getNews } from "./newsSectionStore";
|
||||
import SectionHeader from "@/entities/SectionHeader/SectionHeader";
|
||||
import arrow_icon from "./icons/arrow-right.svg";
|
||||
import NewsCard from "@/entities/NewsCard/NewsCard";
|
||||
import Typography from "@/shared/ui/components/Typography/Typography";
|
||||
|
||||
const NewsSection = async () => {
|
||||
const news = await getNews();
|
||||
return (
|
||||
<section className="news-section">
|
||||
<Typography element="h3">Новости</Typography>
|
||||
<SectionHeader title="Новости" />
|
||||
<ul className="news-section__list">
|
||||
{news?.map((article) => (
|
||||
<li key={article.id} className="news-section__card">
|
||||
Loaded 100 of 274 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user