forked from Transparency/kgroad-frontend2
Compare commits
1
Commits
release005
..
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
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const page = () => {
|
||||||
|
return <div>page</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default page;
|
||||||
@@ -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
-8
@@ -4,13 +4,6 @@ declare module "next-auth" {
|
|||||||
interface Session {
|
interface Session {
|
||||||
refresh_token: string;
|
refresh_token: string;
|
||||||
access_token: string;
|
access_token: string;
|
||||||
expires_in: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface User {
|
|
||||||
refresh_token: string;
|
|
||||||
access_token: string;
|
|
||||||
expires_in: Date;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,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: Date;
|
exp: number;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
{
|
|
||||||
"general": {
|
|
||||||
"date": "Date",
|
|
||||||
"address": "Address",
|
|
||||||
"status": "Status",
|
|
||||||
"description": "Description",
|
|
||||||
"reviews": "Reviews",
|
|
||||||
"rating": "Rating",
|
|
||||||
"review": "Review",
|
|
||||||
"write_comment": "Write Comment",
|
|
||||||
"search": "Search",
|
|
||||||
"search_for": "Search For",
|
|
||||||
"city": "City",
|
|
||||||
"added_roads": "Added Roads",
|
|
||||||
"broken_roads": "Broken Roads",
|
|
||||||
"accident_hotspots": "Accident Hotspots",
|
|
||||||
"local_defects": "Local Defects",
|
|
||||||
"repair_plans": "Repair Plans",
|
|
||||||
"repaired": "Repaired",
|
|
||||||
"fixed_local_defects": "Fixed Local Defects",
|
|
||||||
"news": "News",
|
|
||||||
"details": "Details",
|
|
||||||
"navigation": "Navigation",
|
|
||||||
"contacts": "Contacts",
|
|
||||||
"download_our_app": "Download our app",
|
|
||||||
"back": "Back",
|
|
||||||
"save": "Save",
|
|
||||||
"saving": "Saving",
|
|
||||||
"cancel": "Cancel",
|
|
||||||
"cancellation": "Cancellation",
|
|
||||||
"save_changes": "Save Changes",
|
|
||||||
"send": "Send",
|
|
||||||
"receive": "Receive",
|
|
||||||
"delete": "Delete",
|
|
||||||
"show_on_map": "Show on Map",
|
|
||||||
"author_of_appeal": "Author of Appeal",
|
|
||||||
"enter_city": "Enter City",
|
|
||||||
"page_not_found": "Page Not Found (404)",
|
|
||||||
"incorrect_address_or_nonexistent_page": "Incorrect Address or Nonexistent Page.",
|
|
||||||
"home": "Home",
|
|
||||||
"first_name": "First Name",
|
|
||||||
"last_name": "Last Name",
|
|
||||||
"email": "Email"
|
|
||||||
},
|
|
||||||
"navigation": {
|
|
||||||
"home": "Home",
|
|
||||||
"about_us": "About Us",
|
|
||||||
"privacy": "Privacy Policy",
|
|
||||||
"support": "Support",
|
|
||||||
"statistics": "Statistics",
|
|
||||||
"news": "News",
|
|
||||||
"volunteers": "Volunteers",
|
|
||||||
"profile": "Profile",
|
|
||||||
"login": "Login"
|
|
||||||
},
|
|
||||||
"home": {
|
|
||||||
"title": "Roads of Kyrgyzstan",
|
|
||||||
"subtitle": "Let's Make Roads Safe!",
|
|
||||||
"info": "Current information about the state of roads",
|
|
||||||
"report_broken_road": "Report Broken Road",
|
|
||||||
"road_map": "Road Map",
|
|
||||||
"latest_news": "Stay informed about the latest news on traffic, construction, and events!",
|
|
||||||
"enter_location": "Enter city, village, or region",
|
|
||||||
"broken_roads": "Broken road",
|
|
||||||
"accident_hotspots": "Accident hotspot",
|
|
||||||
"local_defects": "Local defect",
|
|
||||||
"repair_plans": "In repair plan",
|
|
||||||
"repaired": "Repaired",
|
|
||||||
"fixed_local_defects": "Fixed local defect",
|
|
||||||
"rating": "Rating",
|
|
||||||
"road_discussions": "Discussing roads: rating, experience, comfort on the way!",
|
|
||||||
"enter_address": "Enter address",
|
|
||||||
"read_more": "Read More"
|
|
||||||
},
|
|
||||||
"about_us": {
|
|
||||||
"name": "Transparency International-Kyrgyzstan",
|
|
||||||
"description": "Branch of the international organization Transparency International in the Kyrgyz Republic.",
|
|
||||||
"mission": "Promoting effective public policy and good governance to prevent corruption and strengthen democracy in the country.",
|
|
||||||
"goals_and_priorities": {
|
|
||||||
"anti-corruption_education": "Anti-corruption education of the population, raising public awareness of the importance and significance of the fight against corruption in Kyrgyzstan;",
|
|
||||||
"study_of_corruption_practices": "Organization of the study of the practice and theory of combating corruption and the participation of civil society structures in Kyrgyzstan and other countries;",
|
|
||||||
"supporting_citizens_and_organizations": "Assistance to citizens and organizations in the implementation of their constitutional rights and freedoms;",
|
|
||||||
"international_experience": "Preferential orientation to international experience in reducing corruption, mastering its technologies and resources, as well as involving civil society structures in the international dialogue on combating corruption."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"volunteers": {
|
|
||||||
"activists": "Activists",
|
|
||||||
"received_votes": "Received Votes",
|
|
||||||
"left_votes": "Left Votes",
|
|
||||||
"rating": "Rating"
|
|
||||||
},
|
|
||||||
"profile": {
|
|
||||||
"personal_cabinet": "Personal Cabinet",
|
|
||||||
"personal_data": "Personal Data",
|
|
||||||
"my_appeals": "My Appeals",
|
|
||||||
"logout": "Logout",
|
|
||||||
"write_appeal": "Write Appeal",
|
|
||||||
"profile_photo": "Profile Photo",
|
|
||||||
"others_identification": "With a profile photo, other people will recognize you, and it will be easier for you to determine which account you logged into.",
|
|
||||||
"add_profile_photo": "Add Profile Photo",
|
|
||||||
"profile_photo_updated": "Profile Photo Updated",
|
|
||||||
"delete": "Delete",
|
|
||||||
"change": "Change"
|
|
||||||
},
|
|
||||||
"authorization": {
|
|
||||||
"change_password": "Change Password",
|
|
||||||
"old_password": "Old Password",
|
|
||||||
"enter_old_password": "Enter Old Password",
|
|
||||||
"new_password": "New Password",
|
|
||||||
"enter_new_password": "Enter New Password",
|
|
||||||
"confirm_new_password": "Confirm New Password",
|
|
||||||
"confirm_new_password_prompt": "Please confirm the new password",
|
|
||||||
"password": "Password",
|
|
||||||
"forgot_password": "Forgot Password?",
|
|
||||||
"login": "Login",
|
|
||||||
"register": "Register",
|
|
||||||
"sign_in_account": "Sign in to Account",
|
|
||||||
"enter_credentials": "Please enter your credentials",
|
|
||||||
"login_via_google": "Login via Google",
|
|
||||||
"enter_password": "Enter Password",
|
|
||||||
"password_requirements": "Minimum 8 characters, 1 uppercase letter, and 1 digit",
|
|
||||||
"no_account_yet": "Don't have an account yet? Register",
|
|
||||||
"registration": "Registration",
|
|
||||||
"register_now": "Register Now",
|
|
||||||
"already_have_account": "Already have an account? Sign in",
|
|
||||||
"enter_email": "Enter Email",
|
|
||||||
"enter_email_for_code": "Enter email, and we will send a code to reset the password",
|
|
||||||
"send_code": "Send Code",
|
|
||||||
"confirm_code": "Confirm Code",
|
|
||||||
"enter_code": "Enter Code",
|
|
||||||
"enter_reset_code": "Enter code to reset and recover the password",
|
|
||||||
"reset_code": "Reset Code",
|
|
||||||
"reset_password": "Reset Password",
|
|
||||||
"check_email": "Check Your Email",
|
|
||||||
"code_sent_to": "We sent a code to the email name@gmail.com",
|
|
||||||
"confirmation_code": "Confirmation Code",
|
|
||||||
"confirm": "Confirm",
|
|
||||||
"resend_code_in": "Resend Code in",
|
|
||||||
"resend_code": "Resend Code"
|
|
||||||
},
|
|
||||||
"send_report": {
|
|
||||||
"how_to_mark_road_section": "How to mark a road section?",
|
|
||||||
"mark_road_instructions": "Place a pin and start drawing a road section (it can consist of any number of broken lines).",
|
|
||||||
"remove_segment_instruction": "To remove a segment, click on the points again.",
|
|
||||||
"add_problem_description": "Add a problem description",
|
|
||||||
"enter_description": "Enter description",
|
|
||||||
"add_photos": "Add Photos",
|
|
||||||
"upload_photos_instructions": "Upload up to 5 photos related to the road you want to mark. Photos will help better understand the problem.",
|
|
||||||
"attach_file": "Attach File (up to 5 MB)",
|
|
||||||
"submit_for_moderation": "Submit for Moderation",
|
|
||||||
"appeal_submitted": "Your appeal has been submitted",
|
|
||||||
"thanks_for_appeal": "Thank you for your appeal. It is currently under moderation.",
|
|
||||||
"view_my_appeals": "View My Appeals"
|
|
||||||
},
|
|
||||||
"months": {
|
|
||||||
"january": "January",
|
|
||||||
"february": "February",
|
|
||||||
"march": "March",
|
|
||||||
"april": "April",
|
|
||||||
"may": "May",
|
|
||||||
"june": "June",
|
|
||||||
"july": "July",
|
|
||||||
"august": "August",
|
|
||||||
"september": "September",
|
|
||||||
"october": "October",
|
|
||||||
"november": "November",
|
|
||||||
"december": "December"
|
|
||||||
},
|
|
||||||
"validation_errors": {
|
|
||||||
"invalid_email_format": "Invalid email format.",
|
|
||||||
"passwords_do_not_match": "Passwords do not match.",
|
|
||||||
"required_field_not_filled": "Required field not filled.",
|
|
||||||
"exceeded_maximum_length": "Exceeded maximum length of the field.",
|
|
||||||
"login_required_before_commenting": "Please log in or register before leaving a comment.",
|
|
||||||
"login_required_before_like": "Please log in or register before liking."
|
|
||||||
},
|
|
||||||
"server_errors": {
|
|
||||||
"invalid_email_or_password": "Invalid email or password.",
|
|
||||||
"server_error_auth_attempt": "Server error during authentication attempt.",
|
|
||||||
"login_failed": "Failed to log in. Something went wrong, please try again later.",
|
|
||||||
"account_already_exists": "An account with this email already exists.",
|
|
||||||
"account_not_found": "Account not found.",
|
|
||||||
"invalid_activation_code": "Invalid activation code.",
|
|
||||||
"invalid_activation_code_reset": "Invalid activation code for reset.",
|
|
||||||
"invalid_password_reset_code": "Invalid password reset code.",
|
|
||||||
"invalid_code": "Invalid code."
|
|
||||||
},
|
|
||||||
"disclaimer": {
|
|
||||||
"text": "This website is funded by the European Union. Its contents are the sole responsibility of Transparency International Kyrgyzstan and do not necessarily reflect the views of the European Union."
|
|
||||||
},
|
|
||||||
"rights": {
|
|
||||||
"text": "All rights reserved"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
{
|
|
||||||
"general": {
|
|
||||||
"date": "Күн",
|
|
||||||
"address": "Дарек",
|
|
||||||
"status": "Статус",
|
|
||||||
"description": "Сүрөт",
|
|
||||||
"reviews": "Комментарийлер",
|
|
||||||
"rating": "Рейтинг",
|
|
||||||
"review": "Комментарий",
|
|
||||||
"write_comment": "Комментарий жазуу",
|
|
||||||
"search": "Издөө",
|
|
||||||
"search_for": "Издөө",
|
|
||||||
"city": "Шаар",
|
|
||||||
"added_roads": "Кошулган жолдор",
|
|
||||||
"broken_roads": "Тас тастаган жолдор",
|
|
||||||
"accident_hotspots": "Авариялуу жерлер",
|
|
||||||
"local_defects": "Жерги дефекттер",
|
|
||||||
"repair_plans": "Түзөө планттары",
|
|
||||||
"repaired": "Түзөлгөн",
|
|
||||||
"fixed_local_defects": "Жерги дефекттерди түзөлгөн",
|
|
||||||
"news": "Жаңылыктар",
|
|
||||||
"details": "Эчти маалымат",
|
|
||||||
"navigation": "Навигация",
|
|
||||||
"contacts": "Контакттар",
|
|
||||||
"download_our_app": "Биздин приложениямызды жүктөп алыңыз",
|
|
||||||
"back": "Кайтуу",
|
|
||||||
"save": "Сактоо",
|
|
||||||
"saving": "Сакталат",
|
|
||||||
"cancel": "Жокко чыгаруу",
|
|
||||||
"cancellation": "Жокко чыгаруу",
|
|
||||||
"save_changes": "Өзгөртүүлөрдү сактоо",
|
|
||||||
"send": "Жиберүү",
|
|
||||||
"receive": "Алуу",
|
|
||||||
"delete": "Жок кылуу",
|
|
||||||
"show_on_map": "Картада көрсөтүү",
|
|
||||||
"author_of_appeal": "Өтүнчүнүн автору",
|
|
||||||
"enter_city": "Шаарды киргизиңиз",
|
|
||||||
"page_not_found": "Бет табылган эмес (404)",
|
|
||||||
"incorrect_address_or_nonexistent_page": "Туура эмес дарек же бет жок",
|
|
||||||
"home": "Башкы бет",
|
|
||||||
"first_name": "Аты",
|
|
||||||
"last_name": "Фамилия",
|
|
||||||
"email": "Электрондук почта"
|
|
||||||
},
|
|
||||||
"navigation": {
|
|
||||||
"home": "Башкы бет",
|
|
||||||
"about_us": "Биз тууралуу",
|
|
||||||
"privacy": "Купуялык саясаты",
|
|
||||||
"support": "Колдоо",
|
|
||||||
"statistics": "Статистика",
|
|
||||||
"news": "Жаңылыктар",
|
|
||||||
"volunteers": "Волонтёрлер",
|
|
||||||
"profile": "Профиль",
|
|
||||||
"login": "Кириш"
|
|
||||||
},
|
|
||||||
"home": {
|
|
||||||
"title": "Кыргызстандын жолдору",
|
|
||||||
"subtitle": "Жолдорду бекемделүү жасаңыз!",
|
|
||||||
"info": "Жолдордун жаңы күйү",
|
|
||||||
"report_broken_road": "Тас тастаган жолду турганды таратуу",
|
|
||||||
"road_map": "Жол картасы",
|
|
||||||
"latest_news": "Трафик, өндүрүү жана тапшыруудагы соңгосу турган жаңылыктардан кабардар болуңуз!",
|
|
||||||
"enter_location": "Шаар, айыл жана регионду киргизиңиз",
|
|
||||||
"broken_roads": "Жол кирпич",
|
|
||||||
"accident_hotspots": "Авариянын жатактоо жерлери",
|
|
||||||
"local_defects": "Жерги дефект",
|
|
||||||
"repair_plans": "Тозгоондоо жатактоо планында",
|
|
||||||
"repaired": "Тозотулду",
|
|
||||||
"fixed_local_defects": "Тозотулган жерги дефект",
|
|
||||||
"rating": "Рейтинг",
|
|
||||||
"road_discussions": "Жолдорду талкуулоо: рейтинг, тажрыйба, жолдоо боюнча комфорт!",
|
|
||||||
"enter_address": "Даректи киргизиңиз",
|
|
||||||
"read_more": "Көбүрөөк окуу"
|
|
||||||
},
|
|
||||||
"transparency_international_kyrgyzstan": {
|
|
||||||
"name": "Транспаренттыктык Интернационал-Кыргызстан",
|
|
||||||
"description": "Транспаренттыктык Интернационалдын Кыргызстан Республикасы бөлүмү.",
|
|
||||||
"mission": "Коррупциянын ыкмасы менен демократияны күтүтүп, эффективдүү жамааттык саясат жана жакшы мамлекеттүү башкаруунун бириктирилүү үчүн.",
|
|
||||||
"goals_and_priorities": {
|
|
||||||
"anti-corruption_education": "Коррупция менен борбордук бийикти ашуу, Кыргызстанда коррупцияга каршы болгондоо маанилүүдүн жана азаттыктардын маанилүүлүгү үчүн жалпы айткынуу;",
|
|
||||||
"study_of_corruption_practices": "Коррупцияга каршы борбордукты тартуу жана учуруу теориясы менен, Кыргызстан менен башка өлкөлердеги кызмат көрсөтүүсү үчүн азаттыктыктын долбоорлорун жана каттоого жаткантыруу;",
|
|
||||||
"supporting_citizens_and_organizations": "Граждандар менен биздин же компаниялардын конституциялык башкаруу менен жандуулаткануу;",
|
|
||||||
"international_experience": "Коррупциянын аздоого чейинки жыйынтыкты башкаруу үчүн көздөр тартуу, улуттуктары менен биргелеп, коррупцияга каршы көрсөткүчтөрдү мамлекеттик диалогга киргизүү."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"volunteers": {
|
|
||||||
"activists": "Активисттер",
|
|
||||||
"received_votes": "Алынган баллдар",
|
|
||||||
"left_votes": "Калган баллдар",
|
|
||||||
"rating": "Рейтинг"
|
|
||||||
},
|
|
||||||
"profile": {
|
|
||||||
"personal_cabinet": "Жеке кабинет",
|
|
||||||
"personal_data": "Жеке дайындар",
|
|
||||||
"my_appeals": "Менин жардам кылган жалпылыгым",
|
|
||||||
"logout": "Чыгуу",
|
|
||||||
"write_appeal": "Жардам кылуу",
|
|
||||||
"profile_photo": "Профиль сүрөтү",
|
|
||||||
"others_identification": "Профиль сүрөтү аркылуу башка адамдар сизди танышат, жана сизге кирген аккаунтту тандашуу өттүрүлгөн болот.",
|
|
||||||
"add_profile_photo": "Профиль сүрөтү кошуу",
|
|
||||||
"profile_photo_updated": "Профиль сүрөтү жаңыртылды",
|
|
||||||
"delete": "Жок кылуу",
|
|
||||||
"change": "Өзгөртүү"
|
|
||||||
},
|
|
||||||
"authorization": {
|
|
||||||
"change_password": "Сыр сөздү өзгөртүү",
|
|
||||||
"old_password": "Эски сыр сөз",
|
|
||||||
"enter_old_password": "Эски сыр сөздү киргизиңиз",
|
|
||||||
"new_password": "Жаңы сыр сөз",
|
|
||||||
"enter_new_password": "Жаңы сыр сөздү киргизиңиз",
|
|
||||||
"confirm_new_password": "Жаңы сыр сөздү растоо",
|
|
||||||
"confirm_new_password_prompt": "Жаңы сыр сөздү растоо, аны кайра чалыңыз",
|
|
||||||
"password": "Сыр сөз",
|
|
||||||
"forgot_password": "Сыр сөздү унуттуңузбу?",
|
|
||||||
"login": "Кириш",
|
|
||||||
"register": "Тизмеге кирүү",
|
|
||||||
"sign_in_account": "Аккаунтка кириңиз",
|
|
||||||
"enter_credentials": "Киргизген дайындарыңызды киргизиңиз",
|
|
||||||
"login_via_google": "Google аркылуу кириңиз",
|
|
||||||
"enter_password": "Сыр сөздү киргизиңиз",
|
|
||||||
"password_requirements": "Минимум 8 белги, 1 башкы буюк тамга жана 1 сандар",
|
|
||||||
"no_account_yet": "Өйткені, аккаунт жоок? Тизмеге кирүү",
|
|
||||||
"registration": "Тизмеге кирүү",
|
|
||||||
"register_now": "Азыр тизмеге кирүү",
|
|
||||||
"already_have_account": "Аккаунт бар болсо, кириңиз",
|
|
||||||
"enter_email": "Электрондук почтаны киргизиңиз",
|
|
||||||
"enter_email_for_code": "Электрондук почта киргизиңиз, биз сизге сыр сөздү калыпта тапшыруу үчүн код жөнөтөт",
|
|
||||||
"send_code": "Код жөнөтүү",
|
|
||||||
"confirm_code": "Кодду растоо",
|
|
||||||
"enter_code": "Кодду киргизиңиз",
|
|
||||||
"enter_reset_code": "Сыр сөздү өзгөртүп жаңыртуу үчүн кодду киргизиңиз",
|
|
||||||
"reset_code": "Сыр сөздү өзгөртүү коду",
|
|
||||||
"reset_password": "Сыр сөздү өзгөртүү",
|
|
||||||
"check_email": "Почтаны текшериңиз",
|
|
||||||
"code_sent_to": "Биз кодду name@gmail.com почтасына жөнөттүк",
|
|
||||||
"confirmation_code": "Тастыгы код",
|
|
||||||
"confirm": "Растоо",
|
|
||||||
"resend_code_in": "Кодду кайталап жөнөтүү",
|
|
||||||
"resend_code": "Кодду кайталап жөнөтүү"
|
|
||||||
},
|
|
||||||
"send_report": {
|
|
||||||
"how_to_mark_road_section": "Жол бөлүмүн белгилөө үчүн",
|
|
||||||
"mark_road_instructions": "Чек салып, жол бөлүмүн белгилөөгө ээсиңиз (ал булактардан турат).",
|
|
||||||
"remove_segment_instruction": "Жол бөлүмүн каттоо үчүн бир маандын жакшысына басыңыз.",
|
|
||||||
"add_problem_description": "Проблеманын сүрөтүн кошуңуз",
|
|
||||||
"enter_description": "Сүрөттөмөнү киргизиңиз",
|
|
||||||
"add_photos": "Фотографияларды кошуңуз",
|
|
||||||
"upload_photos_instructions": "Жолдун байланышты 5 фотосун жүктөп алыңыз, анткени жататат жана туура түшүнүүдү макул болот.",
|
|
||||||
"attach_file": "Файлды тиштөө (5 МБга чейин)",
|
|
||||||
"submit_for_moderation": "Модерацияга жиберүү",
|
|
||||||
"appeal_submitted": "Сиздин жалпылыгыңыз жиберилди",
|
|
||||||
"thanks_for_appeal": "Сиздин жалпылыгыңуз үчүн рахмат. Азырынча аны модерацияда.",
|
|
||||||
"view_my_appeals": "Менин жалпылыгымдарымды көрүү"
|
|
||||||
},
|
|
||||||
"months": {
|
|
||||||
"january": "Жанварь",
|
|
||||||
"february": "Февраль",
|
|
||||||
"march": "Март",
|
|
||||||
"april": "Апрель",
|
|
||||||
"may": "Май",
|
|
||||||
"june": "Июнь",
|
|
||||||
"july": "Июль",
|
|
||||||
"august": "Август",
|
|
||||||
"september": "Сентябрь",
|
|
||||||
"october": "Октябрь",
|
|
||||||
"november": "Ноябрь",
|
|
||||||
"december": "Декабрь"
|
|
||||||
},
|
|
||||||
"validation_errors": {
|
|
||||||
"invalid_email_format": "Туура эмес электрондук почта форматы.",
|
|
||||||
"passwords_do_not_match": "Сыр сөздөрдүн туура келмейт.",
|
|
||||||
"required_field_not_filled": "Милдеттүү талаа толтурулган жок.",
|
|
||||||
"exceeded_maximum_length": "Талаанын эң ылдам узундугу өткөнчү болду.",
|
|
||||||
"login_required_before_commenting": "Комментарий бир ар каайыпты таштоо алганда, ал кайталап киргизиңиз же тизмеге киргизиңиз.",
|
|
||||||
"login_required_before_like": "Лайк койгондо, кайталап киргизиңиз же тизмеге киргизиңиз керек."
|
|
||||||
},
|
|
||||||
"server_errors": {
|
|
||||||
"invalid_email_or_password": "Туура эмес почта же сыр сөз.",
|
|
||||||
"server_error_auth_attempt": "Авторизация учуруу учурастыктан кайталап сервердеги ката.",
|
|
||||||
"login_failed": "Кирүүгө мүмкүн болгон эмес. Негизги нече кайталап уруксат бериңиз.",
|
|
||||||
"account_already_exists": "Бул почтага ар бир аккаунт бар.",
|
|
||||||
"account_not_found": "Аккаунт табылган жок.",
|
|
||||||
"invalid_activation_code": "Четке калган иштеш коду.",
|
|
||||||
"invalid_activation_code_reset": "Сыр сөздү калыпта тапшыруу үчүн четке калган иштеш коду.",
|
|
||||||
"invalid_password_reset_code": "Сыр сөздү өзгөртүү коду четке калган эмес.",
|
|
||||||
"invalid_code": "Четке калган иштеш коду."
|
|
||||||
},
|
|
||||||
"disclaimer": {
|
|
||||||
"text": "Бул веб-сайт Европа Биримдиги тарабынан каржыланат. Анын мазмуну үчүн Трансперенси Интернешнл Кыргызстан гана жоопкерчиликтүү жана ал Европа Биримдигинин көз карашын сөзсүз түрдө чагылдырбайт."
|
|
||||||
},
|
|
||||||
"rights": {
|
|
||||||
"text": "Бардык укуктар корголгон"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
{
|
|
||||||
"general": {
|
|
||||||
"date": "Дата",
|
|
||||||
"address": "Адрес",
|
|
||||||
"status": "Статус",
|
|
||||||
"description": "Описание",
|
|
||||||
"reviews": "Комментарии",
|
|
||||||
"rating": "Рейтинг",
|
|
||||||
"review": "Комментарий",
|
|
||||||
"write_comment": "Написать комментарий",
|
|
||||||
"search": "Поиск",
|
|
||||||
"search_for": "Искать",
|
|
||||||
"city": "Город",
|
|
||||||
"added_roads": "Добавлено дорог",
|
|
||||||
"broken_roads": "Разбитых дорог",
|
|
||||||
"accident_hotspots": "Очагов аварийности",
|
|
||||||
"local_defects": "Локальных дефектов",
|
|
||||||
"repair_plans": "В планах ремонта",
|
|
||||||
"repaired": "Отремонтировано",
|
|
||||||
"fixed_local_defects": "Локальных дефектов исправлено",
|
|
||||||
"news": "Новости",
|
|
||||||
"details": "Подробнее",
|
|
||||||
"navigation": "Навигация",
|
|
||||||
"contacts": "Контакты",
|
|
||||||
"download_our_app": "Скачивай наше приложение",
|
|
||||||
"back": "Назад",
|
|
||||||
"save": "Сохранить",
|
|
||||||
"saving": "Сохранение",
|
|
||||||
"cancel": "Отменить",
|
|
||||||
"cancellation": "Отмена",
|
|
||||||
"save_changes": "Сохранить изменения",
|
|
||||||
"send": "Отправить",
|
|
||||||
"receive": "Получить",
|
|
||||||
"delete": "Удалить",
|
|
||||||
"show_on_map": "Показать на карте",
|
|
||||||
"author_of_appeal": "Автор обращения",
|
|
||||||
"enter_city": "Введите населенный пункт",
|
|
||||||
"page_not_found": "Страница не найдена (404)",
|
|
||||||
"incorrect_address_or_nonexistent_page": "Неправильно набран адрес или такой страницы не существует.",
|
|
||||||
"home": "На главную",
|
|
||||||
"first_name": "Имя",
|
|
||||||
"last_name": "Фамилия",
|
|
||||||
"email": "Электронная почта"
|
|
||||||
},
|
|
||||||
"navigation": {
|
|
||||||
"home": "Главная",
|
|
||||||
"about_us": "О нас",
|
|
||||||
"privacy": "Политика конфиденциальности",
|
|
||||||
"support": "Поддержка",
|
|
||||||
"statistics": "Статистика",
|
|
||||||
"news": "Новости",
|
|
||||||
"volunteers": "Волонтеры",
|
|
||||||
"profile": "Профиль",
|
|
||||||
"login": "Войти"
|
|
||||||
},
|
|
||||||
"home": {
|
|
||||||
"title": "Дороги Кыргызстана",
|
|
||||||
"subtitle": "Сделаем дороги безопасными!",
|
|
||||||
"info": "Актуальная информация о состоянии дорог",
|
|
||||||
"report_broken_road": "Отметить разбитую дорогу",
|
|
||||||
"road_map": "Карта дорог",
|
|
||||||
"latest_news": "Будьте в курсе последних новостей о дорожном движении, строительствах и мероприятиях!",
|
|
||||||
"enter_location": "Введите город, село или регион",
|
|
||||||
"broken_roads": "Разбитая дорога",
|
|
||||||
"accident_hotspots": "Очаг аварийности",
|
|
||||||
"local_defects": "Локальный дефект",
|
|
||||||
"repair_plans": "В плане ремонта",
|
|
||||||
"repaired": "Отремонтировано",
|
|
||||||
"fixed_local_defects": "Локальный дефект исправлен",
|
|
||||||
"rating": "Рейтинг",
|
|
||||||
"road_discussions": "Обсуждаем дороги: рейтинг, опыт, комфорт в пути!",
|
|
||||||
"enter_address": "Введите адрес",
|
|
||||||
"read_more": "Читать"
|
|
||||||
},
|
|
||||||
"about_us": {
|
|
||||||
"name": "Transparency International-Кыргызстан",
|
|
||||||
"description": "Филиал международной организации Transparency International в Кыргызской Республике.",
|
|
||||||
"mission": "Продвижение эффективной общественной политики и надлежащего управления в целях предотвращения коррупции и усиления демократии в стране.",
|
|
||||||
"goals_and_priorities": {
|
|
||||||
"anti-corruption_education": "Антикоррупционное просвещение населения, повышение общественного осознания значимости и важности борьбы с коррупцией в Кыргызстане;",
|
|
||||||
"study_of_corruption_practices": "Организация изучения практики и теории борьбы с коррупцией и участия в ней структур гражданского общества в Кыргызстане и других странах;",
|
|
||||||
"supporting_citizens_and_organizations": "Содействие гражданам и организациям в реализации их конституционных прав и свобод;",
|
|
||||||
"international_experience": "Преимущественная ориентация на международный опыт уменьшения коррупции, освоение его технологий, ресурсов, а также включение структур гражданского общества в международный диалог борьбы с коррупцией."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"volunteers": {
|
|
||||||
"activists": "Активисты",
|
|
||||||
"received_votes": "Получено голосов",
|
|
||||||
"left_votes": "Оставлено голосов",
|
|
||||||
"rating": "Рейтинг"
|
|
||||||
},
|
|
||||||
"profile": {
|
|
||||||
"personal_cabinet": "Личный кабинет",
|
|
||||||
"personal_data": "Личные данные",
|
|
||||||
"my_appeals": "Мои обращения",
|
|
||||||
"logout": "Выйти из аккаунта",
|
|
||||||
"write_appeal": "Написать обращение",
|
|
||||||
"profile_photo": "Фото профиля",
|
|
||||||
"others_identification": "По фото профиля другие люди смогут вас узнавать, а вам будет проще определять, в какой аккаунт вы вошли.",
|
|
||||||
"add_profile_photo": "Добавить фото профиля",
|
|
||||||
"profile_photo_updated": "Фото профиля обновлено",
|
|
||||||
"delete": "Удалить",
|
|
||||||
"change": "Сменить"
|
|
||||||
},
|
|
||||||
"authorization": {
|
|
||||||
"change_password": "Изменить пароль",
|
|
||||||
"old_password": "Старый пароль",
|
|
||||||
"enter_old_password": "Введите старый пароль",
|
|
||||||
"new_password": "Новый пароль",
|
|
||||||
"enter_new_password": "Введите новый пароль",
|
|
||||||
"confirm_new_password": "Подтвердить новый пароль",
|
|
||||||
"confirm_new_password_prompt": "Пожалуйста, подтвердите новый пароль",
|
|
||||||
"password": "Пароль",
|
|
||||||
"forgot_password": "Забыли пароль?",
|
|
||||||
"login": "Войти",
|
|
||||||
"register": "Зарегистрироваться",
|
|
||||||
"sign_in_account": "Войдите в аккаунт",
|
|
||||||
"enter_credentials": "Пожалуйста, введите свои данные",
|
|
||||||
"login_via_google": "Войти через Google",
|
|
||||||
"enter_password": "Введите пароль",
|
|
||||||
"password_requirements": "Минимум 8 символов, 1 заглавная буква и цифра",
|
|
||||||
"no_account_yet": "Еще нет аккаунта? Зарегистрируйтесь",
|
|
||||||
"registration": "Регистрация",
|
|
||||||
"register_now": "Зарегистрировать",
|
|
||||||
"already_have_account": "Уже есть аккаунт? Войти в аккаунт",
|
|
||||||
"enter_email": "Введите электронную почту",
|
|
||||||
"enter_email_for_code": "Введите электронную почту и мы отправим код для восстановления пароля",
|
|
||||||
"send_code": "Отправить код",
|
|
||||||
"confirm_code": "Потвердить код",
|
|
||||||
"enter_code": "Введите код",
|
|
||||||
"enter_reset_code": "Введите код для сброса и восстановления пароля",
|
|
||||||
"reset_code": "Код сброса пароля",
|
|
||||||
"reset_password": "Сбросить пароль",
|
|
||||||
"check_email": "Проверьте свою почту",
|
|
||||||
"code_sent_to": "Мы отправили код на почту name@gmail.com",
|
|
||||||
"confirmation_code": "Код подтверждения",
|
|
||||||
"confirm": "Подтвердить",
|
|
||||||
"resend_code_in": "Отправить код повторно через",
|
|
||||||
"resend_code": "Отправить код повторно"
|
|
||||||
},
|
|
||||||
"send_report": {
|
|
||||||
"how_to_mark_road_section": "Как отметить участок дороги?",
|
|
||||||
"mark_road_instructions": "Поставьте булавку и начните рисовать участок дороги (он может состоять из любого количества ломаных линий).",
|
|
||||||
"remove_segment_instruction": "Чтобы удалить отрезок, нажмите на точки повторно.",
|
|
||||||
"add_problem_description": "Добавьте описание проблемы",
|
|
||||||
"enter_description": "Введите описание",
|
|
||||||
"add_photos": "Добавьте фотографии",
|
|
||||||
"upload_photos_instructions": "Загрузите до 5 фотографий, связанных с дорогой, которую вы хотите отметить. Фотографии помогут лучше понять проблему.",
|
|
||||||
"attach_file": "Прикрепить файл (до 5 МБ)",
|
|
||||||
"submit_for_moderation": "Отправить на модерацию",
|
|
||||||
"appeal_submitted": "Ваше обращение отправлено",
|
|
||||||
"thanks_for_appeal": "Спасибо за ваше обращение. На данный момент оно в модерации.",
|
|
||||||
"view_my_appeals": "Смотреть мои обращения"
|
|
||||||
},
|
|
||||||
"months": {
|
|
||||||
"january": "Январь",
|
|
||||||
"february": "Февраль",
|
|
||||||
"march": "Март",
|
|
||||||
"april": "Апрель",
|
|
||||||
"may": "Май",
|
|
||||||
"june": "Июнь",
|
|
||||||
"july": "Июль",
|
|
||||||
"august": "Август",
|
|
||||||
"september": "Сентябрь",
|
|
||||||
"october": "Октябрь",
|
|
||||||
"november": "Ноябрь",
|
|
||||||
"december": "Декабрь"
|
|
||||||
},
|
|
||||||
"validation_errors": {
|
|
||||||
"invalid_email_format": "Неверный формат электронной почты.",
|
|
||||||
"passwords_do_not_match": "Пароли не совпадают.",
|
|
||||||
"required_field_not_filled": "Обязательное поле не заполнено.",
|
|
||||||
"exceeded_maximum_length": "Превышена максимальная длина поля.",
|
|
||||||
"login_required_before_commenting": "Перед тем как оставить комментарий, пожалуйста, войдите или зарегистрируйтесь.",
|
|
||||||
"login_required_before_like": "Перед тем как поставить лайк, пожалуйста, войдите или зарегистрируйтесь."
|
|
||||||
},
|
|
||||||
"server_errors": {
|
|
||||||
"invalid_email_or_password": "Неверная почта или пароль.",
|
|
||||||
"server_error_auth_attempt": "Серверная ошибка при попытке авторизации.",
|
|
||||||
"login_failed": "Не удалось войти в систему. Что-то пошло не так, попробуйте еще раз немного позже.",
|
|
||||||
"account_already_exists": "Такая учетная запись уже существует.",
|
|
||||||
"account_not_found": "Такой учетной записи не существует.",
|
|
||||||
"invalid_activation_code": "Код не действителен.",
|
|
||||||
"invalid_activation_code_reset": "Код активации не действителен.",
|
|
||||||
"invalid_password_reset_code": "Код сброса пароля не действителен.",
|
|
||||||
"invalid_code": "Неверный код."
|
|
||||||
},
|
|
||||||
"disclaimer": {
|
|
||||||
"text": "Этот веб-сайт финансируется Европейским Союзом. Ответственность за его содержание лежит исключительно на Трансперенси Интернешнл Кыргызстан и не обязательно отражает точку зрения Европейского Союза."
|
|
||||||
},
|
|
||||||
"rights": {
|
|
||||||
"text": "Все права защищены"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-9
@@ -1,9 +1,5 @@
|
|||||||
import createNextIntlPlugin from "next-intl/plugin";
|
|
||||||
const withNextIntl = createNextIntlPlugin();
|
|
||||||
|
|
||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
distDir: "build",
|
|
||||||
images: {
|
images: {
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
@@ -12,10 +8,6 @@ const nextConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
env: {
|
|
||||||
CLIENT_ID: process.env.CLIENT_ID,
|
|
||||||
CLIENT_SECRET: process.env.CLIENT_SECRET,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withNextIntl(nextConfig);
|
export default nextConfig;
|
||||||
Generated
+4497
File diff suppressed because it is too large.
Load diff
+3
-7
@@ -5,28 +5,24 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start -p 8003",
|
"start": "next start -p 8004",
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/third-parties": "^14.1.0",
|
|
||||||
"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",
|
||||||
"next-intl": "^3.9.0",
|
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"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.
@@ -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.
@@ -3,7 +3,6 @@
|
|||||||
import Image, { StaticImageData } from "next/image";
|
import Image, { StaticImageData } from "next/image";
|
||||||
import "./NewsCard.scss";
|
import "./NewsCard.scss";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useTranslations } from "next-intl";
|
|
||||||
|
|
||||||
interface INewsCard {
|
interface INewsCard {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -20,7 +19,6 @@ const NewsCard: React.FC<INewsCard> = ({
|
|||||||
description,
|
description,
|
||||||
date,
|
date,
|
||||||
}: INewsCard) => {
|
}: INewsCard) => {
|
||||||
const t = useTranslations("general");
|
|
||||||
const sliceTitle = (title: string) => {
|
const sliceTitle = (title: string) => {
|
||||||
if (title.length > 35) {
|
if (title.length > 35) {
|
||||||
return `${title.slice(0, 35)}...`;
|
return `${title.slice(0, 35)}...`;
|
||||||
@@ -58,14 +56,8 @@ const NewsCard: React.FC<INewsCard> = ({
|
|||||||
<p>{sliceDescription(description)}</p>
|
<p>{sliceDescription(description)}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Link
|
<Link href={`/news/${id}`} className="news-card__more-btn">
|
||||||
href={{
|
Подробнее
|
||||||
pathname: `/news/${id}`,
|
|
||||||
query: { новость: title },
|
|
||||||
}}
|
|
||||||
className="news-card__more-btn"
|
|
||||||
>
|
|
||||||
{t("details")}
|
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
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.
File renamed without changes.
@@ -1,5 +1,5 @@
|
|||||||
export interface IFetch {
|
export interface IFetch {
|
||||||
error: string;
|
error: string;
|
||||||
data?: any;
|
data: any;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export interface IList {
|
||||||
|
count: number | null;
|
||||||
|
previous: number | 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);
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export const LINKS = [
|
||||||
|
{ id: 1, pagename: "Главная", pathname: "/" },
|
||||||
|
{ id: 2, pagename: "О нас", pathname: "/about-us" },
|
||||||
|
{ id: 3, pagename: "Статистика", pathname: "/statistics" },
|
||||||
|
{ id: 4, pagename: "Новости", pathname: "/news" },
|
||||||
|
{ id: 5, pagename: "Волонтеры", pathname: "/volunteers" },
|
||||||
|
];
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
export const ROAD_TYPES_STATS: Record<number, string> = {
|
||||||
|
1: "Разбитых дорог",
|
||||||
|
2: "Очагов аварийности",
|
||||||
|
3: "Локальных дефектов",
|
||||||
|
4: "В планах ремонта",
|
||||||
|
5: "Отремонтировано",
|
||||||
|
6: "Локальных дефектов исправлено",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ROAD_TYPES: Record<number, string> = {
|
||||||
|
1: "Разбитая дорога",
|
||||||
|
2: "Очаг аварийности",
|
||||||
|
3: "Локальный дефект",
|
||||||
|
4: "В планах ремонта",
|
||||||
|
5: "Отремонтировано",
|
||||||
|
6: "Локальный дефект исправлен",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ROAD_TYPES_COLORS: Record<number, string> = {
|
||||||
|
1: "rgb(230, 68, 82)",
|
||||||
|
2: "rgb(194, 136, 226)",
|
||||||
|
3: "rgb(135, 40, 157)",
|
||||||
|
4: "rgb(255, 172, 51)",
|
||||||
|
5: "rgb(254, 211, 99)",
|
||||||
|
6: "rgb(143, 222, 106)",
|
||||||
|
};
|
||||||
@@ -4,26 +4,13 @@
|
|||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||||
gap: 30px;
|
gap: 30px;
|
||||||
background-color: rgb(15, 23, 42);
|
background-color: rgb(15, 23, 42);
|
||||||
|
|
||||||
&__logo {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 24px;
|
|
||||||
|
|
||||||
p {
|
|
||||||
color: white;
|
|
||||||
font-family: "Inter", sans-serif;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a,
|
a,
|
||||||
li,
|
li,
|
||||||
h4 {
|
h4 {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,65 +1,53 @@
|
|||||||
import "./Footer.scss";
|
import "./Footer.scss";
|
||||||
import logo from "../../shared/assets/logo.svg";
|
import logo from "../../shared/assets/logo.svg";
|
||||||
|
import Link from "next/link";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { LINKS } from "@/shared/variables/links_footer";
|
import { LINKS } from "@/shared/variables/links";
|
||||||
import youtube from "./icons/youtube.svg";
|
import youtube from "./icons/youtube.svg";
|
||||||
import facebook from "./icons/facebook.svg";
|
import facebook from "./icons/facebook.svg";
|
||||||
import instagram from "./icons/instagram.svg";
|
import instagram from "./icons/instagram.svg";
|
||||||
import app_store_btn from "./icons/app-store-btn.svg";
|
import app_store_btn from "./icons/app-store-btn.svg";
|
||||||
import play_market_btn from "./icons/play-market-btn.svg";
|
import play_market_btn from "./icons/play-market-btn.svg";
|
||||||
import { Link } from "@/shared/config/navigation";
|
|
||||||
import { useTranslations } from "next-intl";
|
|
||||||
import NetKgTracker from "@/widgets/NetKgTracker/NetKgTracker";
|
|
||||||
|
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
const t = useTranslations("general");
|
|
||||||
const tDisclaimer = useTranslations("disclaimer");
|
|
||||||
const tRights = useTranslations("rights");
|
|
||||||
return (
|
return (
|
||||||
<footer className="footer">
|
<footer className="footer">
|
||||||
<div className="footer__logo">
|
<Link href="/">
|
||||||
<Link href="/">
|
<Image src={logo} alt="Logo" />
|
||||||
<Image src={logo} alt="Logo" />
|
</Link>
|
||||||
</Link>
|
|
||||||
<p>© {tRights("text")}</p>
|
|
||||||
<p>{tDisclaimer("text")}</p>
|
|
||||||
</div>
|
|
||||||
<div className="footer__links">
|
<div className="footer__links">
|
||||||
<h4>{t("navigation")}</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>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
<NetKgTracker />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="footer__contacts">
|
<div className="footer__contacts">
|
||||||
<h4>{t("contacts")}</h4>
|
<h4>Контакты</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li>admin@kgroad.org</li>
|
<li>namename@gmail.com</li>
|
||||||
<li>+9960312394038</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>
|
||||||
))}
|
))}
|
||||||
</li>
|
</li>
|
||||||
<li>Photo By ThomasG, CC BY-SA 3.0</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="footer__apps">
|
<div className="footer__apps">
|
||||||
<h4>{t("download_our_app")}</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.
@@ -13,7 +13,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__text {
|
&__text {
|
||||||
width: 100%;
|
|
||||||
padding: 0 90px;
|
padding: 0 90px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -2,10 +2,8 @@ import "./Header.scss";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import background from "./assets/background.svg";
|
import background from "./assets/background.svg";
|
||||||
import HeaderLink from "./HeaderLink/HeaderLink";
|
import HeaderLink from "./HeaderLink/HeaderLink";
|
||||||
import { useTranslations } from "next-intl";
|
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
const t = useTranslations("home");
|
|
||||||
return (
|
return (
|
||||||
<header className="header">
|
<header className="header">
|
||||||
<Image
|
<Image
|
||||||
@@ -14,8 +12,12 @@ const Header = () => {
|
|||||||
alt="Background Image"
|
alt="Background Image"
|
||||||
/>
|
/>
|
||||||
<div className="header__text">
|
<div className="header__text">
|
||||||
<h1>{t("title")}</h1>
|
<h1>
|
||||||
<p>{t("subtitle")}</p>
|
Borem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
Borem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<HeaderLink />
|
<HeaderLink />
|
||||||
-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;
|
||||||
+2
-5
@@ -1,15 +1,12 @@
|
|||||||
import "./HeaderLink.scss";
|
import "./HeaderLink.scss";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import arrow_right from "./icons/arrow-right-circle.svg";
|
import arrow_right from "./icons/arrow-right-circle.svg";
|
||||||
import { Link } from "@/shared/config/navigation";
|
import Link from "next/link";
|
||||||
import { useTranslations } from "next-intl";
|
|
||||||
|
|
||||||
const HeaderLink = () => {
|
const HeaderLink = () => {
|
||||||
const t = useTranslations("home");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href="/create-report" className="header-link">
|
<Link href="/create-report" className="header-link">
|
||||||
{t("report_broken_road")}
|
Отметить разбитую дорогу
|
||||||
<Image src={arrow_right} alt="Arrow Right Icon" />
|
<Image src={arrow_right} alt="Arrow Right Icon" />
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
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.
+2
-19
@@ -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.
+2
-2
@@ -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,41 +1,31 @@
|
|||||||
|
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";
|
|
||||||
import { Link } from "@/shared/config/navigation";
|
|
||||||
import { useTranslations } from "next-intl";
|
|
||||||
|
|
||||||
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 t = useTranslations("navigation");
|
const auth = false;
|
||||||
const session = useSession();
|
|
||||||
|
|
||||||
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" : ""}`
|
||||||
: "lg"
|
: "lg"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{t("profile")}
|
Профиль
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<Link
|
<Link
|
||||||
onClick={() => setOpenMenu(false)}
|
|
||||||
href="/sign-in"
|
href="/sign-in"
|
||||||
className={`nav-auth-signin-${
|
className={`nav-auth-signin-${
|
||||||
responsible
|
responsible
|
||||||
@@ -43,7 +33,7 @@ const NavAuth: React.FC<INavAuthProps> = ({
|
|||||||
: "lg"
|
: "lg"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{t("login")}
|
Войти
|
||||||
</Link>
|
</Link>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
+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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import "./NavLanguage.scss";
|
||||||
|
import Image from "next/image";
|
||||||
|
import { useState } from "react";
|
||||||
|
import globus from "./icons/globus.svg";
|
||||||
|
import chevron from "./icons/chevron-down.svg";
|
||||||
|
import check from "./icons/check.svg";
|
||||||
|
|
||||||
|
const NavLanguage = () => {
|
||||||
|
const [language, setLanguage] = useState<string>("ru");
|
||||||
|
const [openMenu, setOpenMenu] = useState<boolean>(false);
|
||||||
|
const LANGUAGES = [
|
||||||
|
{ id: 1, language: "Русский", index: "ru" },
|
||||||
|
{ id: 2, language: "Кыргызча", index: "kg" },
|
||||||
|
{ id: 3, language: "English", index: "en" },
|
||||||
|
];
|
||||||
|
return (
|
||||||
|
<div className="nav-language">
|
||||||
|
<button
|
||||||
|
onClick={() => setOpenMenu((prev) => !prev)}
|
||||||
|
className="nav-language__btn"
|
||||||
|
>
|
||||||
|
<Image src={globus} alt="globus icon" />
|
||||||
|
<Image src={chevron} alt="chevron icon" />
|
||||||
|
</button>
|
||||||
|
{openMenu && (
|
||||||
|
<div className="nav-language__select">
|
||||||
|
{LANGUAGES.map((lang) => (
|
||||||
|
<button
|
||||||
|
className={`nav-language__option${
|
||||||
|
language === lang.index ? "_active" : ""
|
||||||
|
}`}
|
||||||
|
onClick={() => setLanguage(lang.index)}
|
||||||
|
key={lang.id}
|
||||||
|
>
|
||||||
|
{lang.language}
|
||||||
|
{lang.index === language ? (
|
||||||
|
<Image src={check} alt="check icon" />
|
||||||
|
) : null}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NavLanguage;
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,25 @@
|
|||||||
|
@import "@/shared/ui/variables.scss";
|
||||||
|
|
||||||
|
.nav-menu {
|
||||||
|
padding: 48px 30px 30px 30px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
min-height: 500px;
|
||||||
|
position: fixed;
|
||||||
|
top: 72px;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 26px;
|
||||||
|
background-color: white;
|
||||||
|
|
||||||
|
a {
|
||||||
|
justify-content: flex-start;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link_active {
|
||||||
|
color: $light-blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { LINKS } from "@/shared/variables/links";
|
||||||
|
import "./NavMenu.scss";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { usePathname } from "next/navigation";
|
||||||
|
import NavAuth from "../NavAuth/NavAuth";
|
||||||
|
|
||||||
|
const NavMenu = () => {
|
||||||
|
const auth = false;
|
||||||
|
const pathname = usePathname();
|
||||||
|
return (
|
||||||
|
<nav className="nav-menu">
|
||||||
|
{LINKS.map((link) => (
|
||||||
|
<Link
|
||||||
|
className={`nav-menu__link${
|
||||||
|
pathname === link.pathname ? "_active" : ""
|
||||||
|
}`}
|
||||||
|
href={link.pathname}
|
||||||
|
key={link.id}
|
||||||
|
>
|
||||||
|
{link.pagename}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
|
||||||
|
<NavAuth responsible />
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NavMenu;
|
||||||
@@ -5,26 +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;
|
||||||
|
|
||||||
&__logo {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
|
|
||||||
&_last {
|
|
||||||
min-width: 78px;
|
|
||||||
max-width: 78px;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__links {
|
&__links {
|
||||||
height: 40%;
|
height: 60%;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 60px;
|
gap: 60px;
|
||||||
}
|
}
|
||||||
@@ -58,16 +46,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1220px) {
|
|
||||||
.navbar {
|
|
||||||
padding: 0 60px;
|
|
||||||
|
|
||||||
&__links {
|
|
||||||
gap: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 1024px) {
|
@media screen and (max-width: 1024px) {
|
||||||
.navbar {
|
.navbar {
|
||||||
padding: 0 30px;
|
padding: 0 30px;
|
||||||
@@ -82,7 +60,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 900px) {
|
@media screen and (max-width: 768px) {
|
||||||
.navbar {
|
.navbar {
|
||||||
height: 72px;
|
height: 72px;
|
||||||
|
|
||||||
@@ -1,48 +1,31 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import "./Navbar.scss";
|
import "./Navbar.scss";
|
||||||
import Image, { StaticImageData } from "next/image";
|
import Image from "next/image";
|
||||||
import { Link } from "@/shared/config/navigation";
|
import Link from "next/link";
|
||||||
import { usePathname } from "@/shared/config/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import logo from "@/shared/assets/logo.svg";
|
import logo from "@/shared/assets/logo.svg";
|
||||||
import { LINKS } from "@/shared/variables/links";
|
import { LINKS } from "@/shared/variables/links";
|
||||||
import NavLanguage from "./NavLanguage/NavLanguage";
|
import NavLanguage from "./NavLanguage/NavLanguage";
|
||||||
import NavAuth from "./NavAuth/NavAuth";
|
import NavAuth from "./NavAuth/NavAuth";
|
||||||
import menu from "./icons/menu.svg";
|
import menu from "./icons/menu.svg";
|
||||||
import cross from "./icons/cross.svg";
|
import cross from "./icons/cross.svg";
|
||||||
|
|
||||||
import NavMenu from "./NavMenu/NavMenu";
|
import NavMenu from "./NavMenu/NavMenu";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import founded_ru from "./assets/founded-ru.png";
|
|
||||||
import founded_en from "./assets/founded-en.png";
|
|
||||||
import founded_kg from "./assets/founded-kg.png";
|
|
||||||
import { useParams } from "next/navigation";
|
|
||||||
|
|
||||||
const Navbar = () => {
|
const Navbar = () => {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const [openMenu, setOpenMenu] = useState<boolean>(false);
|
const [openMenu, setOpenMenu] = useState<boolean>(false);
|
||||||
const { locale } = useParams();
|
|
||||||
|
|
||||||
const FOUNDED: Record<string, StaticImageData> = {
|
|
||||||
ru: founded_ru,
|
|
||||||
kg: founded_kg,
|
|
||||||
en: founded_en,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="navbar">
|
<section className="navbar">
|
||||||
<div className="navbar__logo">
|
<Link href="/">
|
||||||
<Link href="/">
|
<Image src={logo} alt="Logo" />
|
||||||
<Image src={logo} alt="Logo" />
|
</Link>
|
||||||
</Link>
|
|
||||||
<Image
|
|
||||||
className="navbar__logo_last"
|
|
||||||
src={FOUNDED[locale as string]}
|
|
||||||
alt="Founded by EU Image"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<nav className="navbar__links">
|
<nav className="navbar__links">
|
||||||
{LINKS().map((link) => (
|
{LINKS.map((link) => (
|
||||||
<Link
|
<Link
|
||||||
className={`navbar__link${
|
className={`navbar__link${
|
||||||
pathname === link.pathname ? "_active" : ""
|
pathname === link.pathname ? "_active" : ""
|
||||||
@@ -57,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
|
||||||
@@ -67,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.
Loaded 100 of 325 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user