// src/components/Map/ControlsPanel.jsx

import React from 'react';
import './ControlsPanel.scss';

const ControlsPanel = ({
  layersVisibility,
  toggleLayer,
  mapStyles,
  selectedStyle,
  changeMapStyle,
  filters,
  toggleFilter,
}) => {
  return (
    <div className="controls-panel">
      <h3>Управление Картой</h3>
      <div className="layer-controls">
        <h4>Слои</h4>
        {Object.keys(layersVisibility).map((layer) => (
          <label key={layer}>
            <input
              type="checkbox"
              checked={layersVisibility[layer]}
              onChange={() => toggleLayer(layer)}
            />
            {layer.charAt(0).toUpperCase() + layer.slice(1)}
          </label>
        ))}
      </div>
      <div className="filter-controls">
        <h4>Фильтры</h4>
        {Object.keys(filters).map((filter) => (
          <label key={filter}>
            <input
              type="checkbox"
              checked={filters[filter]}
              onChange={() => toggleFilter(filter)}
            />
            {filter.charAt(0).toUpperCase() + filter.slice(1)}
          </label>
        ))}
      </div>
      <div className="style-controls">
        <h4>Тип карты</h4>
        <select value={selectedStyle} onChange={(e) => changeMapStyle(e.target.value)}>
          {mapStyles.map((style) => (
            <option key={style} value={style}>
              {style.charAt(0).toUpperCase() + style.slice(1)}
            </option>
          ))}
        </select>
      </div>
    </div>
  );
};

export default ControlsPanel;




/* src/components/Map/ControlsPanel.scss */

@import '../styles/variables.scss';

.controls-panel {
  position: absolute;
  top: 10px;
  left: 10px;
  background-color: rgba(255, 255, 255, 0.95);
  padding: 1rem;
  border-radius: 8px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
  z-index: 1000;
  
  h3 {
    margin-bottom: 0.5rem;
    color: $heading-color;
    text-align: center;
  }
  
  .layer-controls,
  .filter-controls,
  .style-controls {
    margin-bottom: 1rem;
    
    h4 {
      margin-bottom: 0.5rem;
      color: $heading-color;
    }
    
    label {
      display: flex;
      align-items: center;
      margin-bottom: 0.25rem;
      cursor: pointer;
      color: $text-color;
      
      input {
        margin-right: 0.5rem;
      }
    }
  }
  
  select {
    width: 100%;
    padding: 0.25rem;
    border-radius: 4px;
    border: 1px solid #ccc;
  }
}




// src/components/Map/InfoPanel.jsx

import React from 'react';
import './InfoPanel.scss';

const InfoPanel = ({ feature, onClose }) => {
  if (!feature) return null;

  return (
    <div className="info-panel">
      <button className="close-button" onClick={onClose}>✕</button>
      <h2>{feature.properties.name}</h2>
      {feature.properties.description && <p>{feature.properties.description}</p>}
      {feature.properties.history && (
        <div>
          <h3>История:</h3>
          <p>{feature.properties.history}</p>
        </div>
      )}
      {feature.properties.demographics && (
        <div>
          <h3>Демография:</h3>
          <p>{feature.properties.demographics}</p>
        </div>
      )}
      {feature.properties.cultural_sites && (
        <div>
          <h3>Культурные Объекты:</h3>
          <ul>
            {feature.properties.cultural_sites.map((site, index) => (
              <li key={index}>{site}</li>
            ))}
          </ul>
        </div>
      )}
      {feature.properties.natural_features && (
        <div>
          <h3>Природные Объекты:</h3>
          <ul>
            {feature.properties.natural_features.map((featureName, index) => (
              <li key={index}>{featureName}</li>
            ))}
          </ul>
        </div>
      )}
      {/* Добавьте дополнительные поля по необходимости */}
    </div>
  );
};

export default InfoPanel;




/* src/components/Map/InfoPanel.scss */

@import '../styles/variables.scss';

.info-panel {
  position: absolute;
  top: 60px;
  right: 10px;
  width: 300px;
  background-color: rgba(255, 255, 255, 0.95);
  padding: 1.5rem;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.3);
  z-index: 1001;
  
  .close-button {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    background: none;
    border: none;
    font-size: 1.25rem;
    cursor: pointer;
    color: $text-color;
  }
  
  h2 {
    margin-bottom: 1rem;
    color: $heading-color;
  }
  
  h3 {
    margin-top: 1rem;
    margin-bottom: 0.5rem;
    color: $heading-color;
  }
  
  p {
    color: $text-color;
  }
  
  ul {
    list-style: disc;
    padding-left: 1.5rem;
    
    li {
      color: $text-color;
      margin-bottom: 0.25rem;
    }
  }
}




// src/components/Map/KGMap.jsx

import React, { useState, useRef, useEffect } from 'react';
import { MapContainer, TileLayer, GeoJSON, useMap } from 'react-leaflet';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import './KGMap.scss';
import ControlsPanel from './ControlsPanel';
import SearchBar from './SearchBar';
import InfoPanel from './InfoPanel';
import RegionInfoPanel from './RegionInfoPanel';

// Импорт GeoJSON данных
import citiesData from './data/cities.geojson';
import roadsData from './data/roads.geojson';
import waterbodiesData from './data/waterbodies.geojson';
import reliefData from './data/relief.geojson';
import adminBoundariesData from './data/admin_boundaries.geojson';

const KGMap = () => {
  const [layersVisibility, setLayersVisibility] = useState({
    cities: true,
    roads: true,
    waterbodies: true,
    relief: true,
    adminBoundaries: true,
  });

  const [filters, setFilters] = useState({
    largeCities: true,
    majorRoads: true,
    // Добавьте другие фильтры по необходимости
  });

  const mapRef = useRef(null);

  const mapStyles = [
    'streets',
    'satellite',
    'light',
    'dark',
    'outdoors',
    'navigation-day',
    'navigation-night',
    'satellite-streets',
  ];

  const [selectedStyle, setSelectedStyle] = useState('streets');
  const [searchQuery, setSearchQuery] = useState('');

  const [selectedFeature, setSelectedFeature] = useState(null);
  const [selectedRegion, setSelectedRegion] = useState(null);

  const toggleLayer = (layer) => {
    setLayersVisibility((prev) => ({
      ...prev,
      [layer]: !prev[layer],
    }));
  };

  const toggleFilter = (filter) => {
    setFilters((prev) => ({
      ...prev,
      [filter]: !prev[filter],
    }));
  };

  const changeMapStyle = (style) => {
    setSelectedStyle(style);
  };

  const handleSearch = (query) => {
    setSearchQuery(query);
  };

  const getBaseLayerUrl = (style) => {
    const styles = {
      streets: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
      satellite: 'https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png',
      light: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
      dark: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
      outdoors: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
      'navigation-day': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
      'navigation-night': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
      'satellite-streets': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
    };
    return styles[style] || styles['streets'];
  };

  const styleLayer = (color, weight = 2, fillOpacity = 0.5) => ({
    color: color,
    weight: weight,
    fillOpacity: fillOpacity,
  });

  const onEachFeature = (feature, layer) => {
    if (feature.properties && feature.properties.name) {
      layer.on('click', () => {
        if (feature.type === 'admin_boundaries') {
          setSelectedRegion(feature.properties);
        } else {
          setSelectedFeature(feature);
        }
      });
    }
  };

  // Применение фильтров для слоев
  const getFilteredData = (data, layerType) => {
    if (!filters) return data;

    let filteredFeatures = data.features;

    if (layerType === 'cities' && filters.largeCities) {
      filteredFeatures = filteredFeatures.filter(
        (city) => city.properties.population >= 500000
      );
    }

    if (layerType === 'roads' && filters.majorRoads) {
      // Пример фильтрации дорог по важности
      filteredFeatures = filteredFeatures.filter(
        (road) => road.properties.importance === 'major'
      );
    }

    // Добавьте другие фильтры по необходимости

    return { ...data, features: filteredFeatures };
  };

  return (
    <div className="map-wrapper">
      <ControlsPanel
        layersVisibility={layersVisibility}
        toggleLayer={toggleLayer}
        mapStyles={mapStyles}
        selectedStyle={selectedStyle}
        changeMapStyle={changeMapStyle}
        filters={filters}
        toggleFilter={toggleFilter}
      />
      <SearchBar onSearch={handleSearch} />
      <MapContainer
        center={[41.2044, 74.7661]}
        zoom={7}
        scrollWheelZoom={true}
        className="custom-map"
        whenCreated={(mapInstance) => {
          mapRef.current = mapInstance;
        }}
      >
        <TileLayer
          url={getBaseLayerUrl(selectedStyle)}
          attribution="&copy; OpenStreetMap contributors"
        />

        {/* Слой городов */}
        {layersVisibility.cities && (
          <GeoJSON
            data={getFilteredData(citiesData, 'cities')}
            style={styleLayer('red')}
            onEachFeature={onEachFeature}
            type="cities"
          />
        )}

        {/* Слой дорог */}
        {layersVisibility.roads && (
          <GeoJSON
            data={getFilteredData(roadsData, 'roads')}
            style={styleLayer('blue')}
            onEachFeature={onEachFeature}
            type="roads"
          />
        )}

        {/* Слой водоёмов */}
        {layersVisibility.waterbodies && (
          <GeoJSON
            data={getFilteredData(waterbodiesData, 'waterbodies')}
            style={styleLayer('cyan')}
            onEachFeature={onEachFeature}
            type="waterbodies"
          />
        )}

        {/* Слой рельефа */}
        {layersVisibility.relief && (
          <GeoJSON
            data={getFilteredData(reliefData, 'relief')}
            style={styleLayer('green')}
            onEachFeature={onEachFeature}
            type="relief"
          />
        )}

        {/* Слой административных границ */}
        {layersVisibility.adminBoundaries && (
          <GeoJSON
            data={adminBoundariesData}
            style={styleLayer('purple', 3, 0.3)}
            onEachFeature={onEachFeature}
            type="admin_boundaries"
          />
        )}

        {/* Поиск */}
        {searchQuery && <SearchControl query={searchQuery} />}
      </MapContainer>

      {/* Панель информации об объекте */}
      {selectedFeature && <InfoPanel feature={selectedFeature} onClose={() => setSelectedFeature(null)} />}

      {/* Панель информации об административном регионе */}
      {selectedRegion && <RegionInfoPanel region={selectedRegion} onClose={() => setSelectedRegion(null)} />}
    </div>
  );
};

export default KGMap;




/* src/components/Map/KGMap.scss */

@import '../styles/variables.scss';

.map-wrapper {
  position: relative;
  height: 100vh;
}

.custom-map {
  height: 100%;
  width: 100%;
}

.leaflet-container {
  background: #f0f0f0;
}





// src/components/Map/RegionInfoPanel.jsx

import React from 'react';
import './RegionInfoPanel.scss';

const RegionInfoPanel = ({ region, onClose }) => {
  if (!region) return null;

  return (
    <div className="region-info-panel">
      <button className="close-button" onClick={onClose}>✕</button>
      <h2>{region.name}</h2>
      {region.description && <p>{region.description}</p>}
      {region.history && (
        <div>
          <h3>История:</h3>
          <p>{region.history}</p>
        </div>
      )}
      {region.demographics && (
        <div>
          <h3>Демография:</h3>
          <p>{region.demographics}</p>
        </div>
      )}
      {region.cultural_sites && (
        <div>
          <h3>Культурные Объекты:</h3>
          <ul>
            {region.cultural_sites.map((site, index) => (
              <li key={index}>{site}</li>
            ))}
          </ul>
        </div>
      )}
      {region.natural_features && (
        <div>
          <h3>Природные Объекты:</h3>
          <ul>
            {region.natural_features.map((featureName, index) => (
              <li key={index}>{featureName}</li>
            ))}
          </ul>
        </div>
      )}
      {/* Добавьте дополнительные поля по необходимости */}
    </div>
  );
};

export default RegionInfoPanel;




/* src/components/Map/RegionInfoPanel.scss */

@import '../styles/variables.scss';

.region-info-panel {
  position: absolute;
  bottom: 10px;
  right: 10px;
  width: 350px;
  background-color: rgba(255, 255, 255, 0.95);
  padding: 1.5rem;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.3);
  z-index: 1001;
  
  .close-button {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    background: none;
    border: none;
    font-size: 1.25rem;
    cursor: pointer;
    color: $text-color;
  }
  
  h2 {
    margin-bottom: 1rem;
    color: $heading-color;
  }
  
  h3 {
    margin-top: 1rem;
    margin-bottom: 0.5rem;
    color: $heading-color;
  }
  
  p {
    color: $text-color;
  }
  
  ul {
    list-style: disc;
    padding-left: 1.5rem;
    
    li {
      color: $text-color;
      margin-bottom: 0.25rem;
    }
  }
}





// src/components/Map/SearchBar.jsx

import React, { useState } from 'react';
import './SearchBar.scss';

const SearchBar = ({ onSearch }) => {
  const [query, setQuery] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    onSearch(query.trim());
  };

  return (
    <form className="search-bar" onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Поиск..."
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      <button type="submit">🔍</button>
    </form>
  );
};

export default SearchBar;




/* src/components/Map/SearchBar.scss */

@import '../styles/variables.scss';

.search-bar {
  position: absolute;
  top: 10px;
  right: 10px;
  display: flex;
  align-items: center;
  background-color: rgba(255, 255, 255, 0.95);
  padding: 0.5rem;
  border-radius: 8px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
  z-index: 1000;
  
  input {
    flex: 1;
    padding: 0.5rem;
    border: 1px solid #ccc;
    border-radius: 4px 0 0 4px;
    font-size: 1rem;
  }
  
  button {
    padding: 0.5rem;
    border: none;
    background-color: $primary-color;
    color: #fff;
    border-radius: 0 4px 4px 0;
    cursor: pointer;
    font-size: 1rem;
    transition: background-color 0.3s ease;
    
    &:hover {
      background-color: $primary-hover;
    }
  }
}




Бэкенд:
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from 'src/users/users.module';
import { PassportModule } from '@nestjs/passport';
import { LocalStrategy } from './local.strategy';
import { SessionSerializer } from './session.serializer';

@Module({
  imports: [UsersModule, PassportModule.register({session: true})],
  providers: [AuthService, LocalStrategy, SessionSerializer]
})
export class AuthModule {}


import { Injectable, UnauthorizedException } from '@nestjs/common';
import { UsersService } from 'src/users/users.service';
import * as bcrypt from 'bcrypt';

@Injectable()
export class AuthService {
  constructor(private readonly usersService: UsersService) {}

  async validateUser(username: string, password: string) {
    const user = await this.usersService.findOne({ where: { username } });

    if (!user) {
      throw new UnauthorizedException('Invalid credentials');
    }

    const passwordValid = await bcrypt.compare(password, user.password);

    if (!passwordValid) {
      throw new UnauthorizedException('Invalid credentials');
    }

    if (user && passwordValid) {
      return {
        userId: user.id,
        username: user.username,
        email: user.email,
        avatarId: user.avatarId
      };
    }

    return null;
  }
}



import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common";
import { Observable } from "rxjs";

@Injectable()
export class AuthenticatedGuard implements CanActivate {
    async canActivate(context: ExecutionContext) {
        const request = context.switchToHttp().getRequest();

        return request.isAuthenticated();
    }
}




import { ExecutionContext, Injectable } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
import { Observable } from "rxjs";

@Injectable()
export class LocalAuthGuard extends AuthGuard('local'){
    async canActivate(context: ExecutionContext) {
        const result = await super.canActivate(context) as boolean
        const request = context.switchToHttp().getRequest();

        await super.logIn(request);

        return result;
    }
}




import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
  constructor(private authService: AuthService) {
    super();
  }

  async validate(username: string, password: string): Promise<any> {
    const user = await this.authService.validateUser(
        username.toLowerCase(), 
        password);
    if (!user) {
      throw new UnauthorizedException();
    }
    return user;
  }
}





import { Injectable } from "@nestjs/common";
import { PassportSerializer } from "@nestjs/passport";

@Injectable()
export class SessionSerializer extends PassportSerializer{
    serializeUser(user: any, done: (err: Error, user: any) => void) {
        done(null, user)
    }


    deserializeUser(payload: any, done: (err: Error, user: any) => void) {
        done(null, payload)
    }
}




import { registerAs } from "@nestjs/config";
import { sqlconfig } from "./sql.config";

export const databaseConfig = registerAs('database',  () => ({
    sql: {
        ...sqlconfig(),
    }
}));




import { Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { SequelizeModuleOptions, SequelizeOptionsFactory } from "@nestjs/sequelize";
import { User } from "src/users/users.model";

@Injectable()
export class SequelizeConfigService implements SequelizeOptionsFactory{
    constructor (private readonly configService: ConfigService) {}

    createSequelizeOptions(connectionName?: string): SequelizeModuleOptions {
        const {
            sql: { dialect,logging,host,password,username,port,database}
        } = this.configService.get('database');

        return{
            username,
            password,
            dialect,
            logging,
            port,
            host,
            database,
            models: [User],
            autoLoadModels: true,
            synchronize: true,
            define: {
                charset: 'utf8',
                collate: 'utf8_general_ci'
            }
        }
    }
}




import { registerAs } from "@nestjs/config";
import { Dialect } from "sequelize";

export const sqlconfig = registerAs('database', ()=> ({
    dialect: <Dialect>process.env.SQL_DIALECT || 'mysql',
    logging: process.env.SQL_LOGGING === 'true' ? true: false,
    host: process.env.DATABASE_HOST,
    port: +process.env.DATABASE_PORT,
    username: process.env.DATABASE_USER,
    password: process.env.DATABASE_PASSWORD,
    database: process.env.DATABASE_NAME,
    autoLoadEntities: true,
    synchronize: true,
}));





// src/geo/geo.controller.ts

import { Controller, Get, Param, NotFoundException } from '@nestjs/common';
import { GeoService } from './geo.service';

@Controller('geo')
export class GeoController {
  constructor(private readonly geoService: GeoService) {}

  @Get(':layer')
  async getLayer(@Param('layer') layer: string) {
    const data = await this.geoService.getGeoData(layer);
    if (!data) {
      throw new NotFoundException('Layer not found');
    }
    return data;
  }
}

// src/geo/geo.module.ts

import { Module } from '@nestjs/common';
import { GeoController } from './geo.controller';
import { GeoService } from './geo.service';

@Module({
  controllers: [GeoController],
  providers: [GeoService],
})
export class GeoModule {}




// src/geo/geo.service.ts

import { Injectable } from '@nestjs/common';
import * as cities from './data/cities.geojson';
import * as roads from './data/roads.geojson';
import * as waterbodies from './data/waterbodies.geojson';
import * as relief from './data/relief.geojson';
import * as adminBoundaries from './data/admin_boundaries.geojson';

@Injectable()
export class GeoService {
  private readonly layers = {
    cities,
    roads,
    waterbodies,
    relief,
    adminBoundaries,
  };

  async getGeoData(layer: string) {
    return this.layers[layer] || null;
  }
}




я хочу сделать так чтобы была как бы основа карты кыргызстана допустим leaflet если там можно реализовать все функциональности которые я хочу.

на этой как бы основе где уже должен быть контур кыргызстана и рельеф да и вообще наверно максимальное количество элементов которые могут быть на карте главное чтобы их можно было выбрать и при выборе они как могли выделяться например выбираешь все горы на территории кыргызстана и они должны выделяться также со всему водоёмами реками городами и прочими элементами 


напиши полные коды для всего