Centralize and update contact information across app

Introduced a centralized contacts configuration in src/config/contacts.js, added a useContacts hook, and a reusable ContactInfo component. Updated Header, Footer, Home, Office, Services, About, Objects, and Apartament pages to use the new contact data source. Added documentation in CONTACTS_CONFIG.md and included the AlmaVid logo asset.
This commit is contained in:
Madara0330E
2025-07-16 23:16:00 +05:00
parent 2af795f819
commit 4adbf791ea
20 changed files with 2007 additions and 838 deletions

122
CONTACTS_CONFIG.md Normal file
View File

@@ -0,0 +1,122 @@
# Конфигурация контактной информации
Этот файл содержит всю контактную информацию агентства недвижимости АЛМА-ВИД в централизованном виде.
## Расположение файла
`src/config/contacts.js`
## Структура конфигурации
### Основные контакты
- `phone` - номер телефона с отображаемым текстом и ссылкой для набора
- `email` - электронная почта с отображаемым текстом и ссылкой mailto
### Адреса
- `address.main` - основной адрес офиса (для карт и контактов)
- `address.office` - рабочий адрес офиса (для страницы "Наш офис")
### Координаты
- `coordinates` - координаты для отображения на Яндекс.Картах
### Социальные сети
- `social.vk` - ВКонтакте
- `social.telegram` - Telegram
- `social.instagram` - Instagram
### Название компании
- `companyName` - полное название
- `companyNameShort` - сокращенное название
## Использование
### В компонентах
```jsx
import { CONTACTS } from '../../config/contacts';
// Использование телефона
<a href={CONTACTS.phone.link}>{CONTACTS.phone.display}</a>
// Использование email
<a href={CONTACTS.email.link}>{CONTACTS.email.display}</a>
// Использование соцсетей
<a href={CONTACTS.social.vk.url}>{CONTACTS.social.vk.name}</a>
// Координаты для карт
<Map defaultState={{ center: CONTACTS.coordinates, zoom: 12 }}>
<Placemark
geometry={CONTACTS.coordinates}
properties={{
balloonContent: CONTACTS.getBalloonContent(),
hintContent: `Офис ${CONTACTS.companyNameShort}`
}}
/>
</Map>
```
### С помощью хука useContacts
```jsx
import { useContacts } from "../../hooks/useContacts";
function MyComponent() {
const contacts = useContacts();
return (
<div>
<a href={contacts.getPhoneLink()}>{contacts.phone.display}</a>
<a href={contacts.getSocialLink("vk")}>{contacts.getSocialName("vk")}</a>
</div>
);
}
```
### Компонент ContactInfo
```jsx
import { ContactInfo } from '../../components/ContactInfo/ContactInfo';
// Базовый вариант
<ContactInfo />
// Inline вариант
<ContactInfo variant="inline" />
// Полный вариант со всей информацией
<ContactInfo variant="full" />
```
## Обновленные страницы
Все следующие страницы теперь используют централизованную конфигурацию:
1. **Header** - номер телефона и социальные сети
2. **Footer** - социальные сети
3. **Home** - заголовок страницы, карта с координатами и balloon
4. **Office** - заголовок страницы, контактная информация, карта
5. **Services** - заголовок страницы, ссылка на ВКонтакте
6. **About** - заголовок страницы, название компании
7. **Objects** - заголовок страницы
8. **Apartament** - карта с координатами и balloon
## Преимущества централизованной конфигурации
1. **Единое место для изменений** - все контакты изменяются в одном файле
2. **Консистентность** - одинаковое отображение на всех страницах
3. **Легкость обслуживания** - не нужно искать и изменять контакты по всему проекту
4. **Типизация** - структурированные данные с понятным API
5. **Переиспользование** - легко добавлять контакты на новые страницы
## Как изменить контактную информацию
1. Откройте файл `src/config/contacts.js`
2. Измените нужные значения
3. Сохраните файл
4. Изменения автоматически применятся ко всем страницам

8
package-lock.json generated
View File

@@ -17219,16 +17219,16 @@
}
},
"node_modules/typescript": {
"version": "5.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
"node": ">=4.2.0"
}
},
"node_modules/unbox-primitive": {

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -0,0 +1,78 @@
import { CONTACTS } from "../../config/contacts";
import "./ContactInfo.scss";
function ContactInfo({ variant = "default" }) {
if (variant === "inline") {
return (
<div className="contact-info-inline">
<span className="contact-info__phone">
<a href={CONTACTS.phone.link}>{CONTACTS.phone.display}</a>
</span>
<span className="contact-info__email">
<a href={CONTACTS.email.link}>{CONTACTS.email.display}</a>
</span>
</div>
);
}
if (variant === "full") {
return (
<div className="contact-info-full">
<div className="contact-info__item">
<span className="contact-info__label">Телефон:</span>
<a href={CONTACTS.phone.link} className="contact-info__value">
{CONTACTS.phone.display}
</a>
</div>
<div className="contact-info__item">
<span className="contact-info__label">E-mail:</span>
<a href={CONTACTS.email.link} className="contact-info__value">
{CONTACTS.email.display}
</a>
</div>
<div className="contact-info__item">
<span className="contact-info__label">Адрес:</span>
<span className="contact-info__value">
{CONTACTS.address.main.full}
</span>
</div>
<div className="contact-info__item">
<span className="contact-info__label">Соц.сети:</span>
<div className="contact-info__social">
<a
href={CONTACTS.social.vk.url}
className="contact-info__social-link"
>
{CONTACTS.social.vk.name}
</a>
<a
href={CONTACTS.social.telegram.url}
className="contact-info__social-link"
>
{CONTACTS.social.telegram.name}
</a>
<a
href={CONTACTS.social.instagram.url}
className="contact-info__social-link"
>
{CONTACTS.social.instagram.name}
</a>
</div>
</div>
</div>
);
}
return (
<div className="contact-info">
<a href={CONTACTS.phone.link} className="contact-info__phone">
{CONTACTS.phone.display}
</a>
<a href={CONTACTS.email.link} className="contact-info__email">
{CONTACTS.email.display}
</a>
</div>
);
}
export { ContactInfo };

View File

@@ -0,0 +1,72 @@
.contact-info {
display: flex;
gap: 1rem;
align-items: center;
&__phone,
&__email {
text-decoration: none;
color: inherit;
font-weight: 600;
transition: color 0.3s ease;
&:hover {
color: #007bff;
}
}
}
.contact-info-inline {
display: flex;
gap: 2rem;
align-items: center;
.contact-info__phone,
.contact-info__email {
a {
text-decoration: none;
color: inherit;
font-weight: 600;
transition: color 0.3s ease;
&:hover {
color: #007bff;
}
}
}
}
.contact-info-full {
.contact-info__item {
margin-bottom: 1rem;
.contact-info__label {
font-weight: bold;
margin-right: 0.5rem;
}
.contact-info__value {
text-decoration: none;
color: inherit;
&:hover {
color: #007bff;
}
}
}
.contact-info__social {
display: flex;
gap: 1rem;
&-link {
text-decoration: none;
color: inherit;
transition: color 0.3s ease;
&:hover {
color: #007bff;
}
}
}
}

View File

@@ -1,38 +1,58 @@
import './Footer.scss';
import { Link, useNavigate } from 'react-router-dom';
import "./Footer.scss";
import { Link, useNavigate } from "react-router-dom";
import { CONTACTS } from "../../config/contacts";
function Footer() {
const navigate = useNavigate();
const navigate = useNavigate();
const handleClick = () => {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
};
const handleClick = () => {
window.scrollTo({
top: 0,
behavior: "smooth",
});
};
const handlePageChange = (path) => {
handleClick();
navigate(path);
};
const handlePageChange = (path) => {
handleClick();
navigate(path);
};
return (
<footer className="footer">
<Link to="/" className="footer__logo font-inter-regular"
onClick={() => handlePageChange('/')}>OOO "ALMA-VID"</Link>
<div className="footer-info font-inter-bold">
<Link to="/objects" onClick={() => handlePageChange('/objects')}>Объекты</Link>
<Link to="/services" onClick={() => handlePageChange('/services')}>Услуги</Link>
<Link to="/about" onClick={() => handlePageChange('/about')}>О компании</Link>
<Link to="/office" onClick={() => handlePageChange('/office')}>Контакты</Link>
</div>
<div className="footer-socials">
<a className="footer-socials__tg" href="#"></a>
<a className="footer-socials__inst" href="#"></a>
<a className="footer-socials__vk" href="#"></a>
</div>
</footer>
);
return (
<footer className="footer">
<Link
to="/"
className="footer__logo font-inter-regular"
onClick={() => handlePageChange("/")}
>
OOO "ALMA-VID"
</Link>
<div className="footer-info font-inter-bold">
<Link to="/objects" onClick={() => handlePageChange("/objects")}>
Объекты
</Link>
<Link to="/services" onClick={() => handlePageChange("/services")}>
Услуги
</Link>
<Link to="/about" onClick={() => handlePageChange("/about")}>
О компании
</Link>
<Link to="/office" onClick={() => handlePageChange("/office")}>
Контакты
</Link>
</div>
<div className="footer-socials">
<a
className="footer-socials__tg"
href={CONTACTS.social.telegram.url}
></a>
<a
className="footer-socials__inst"
href={CONTACTS.social.instagram.url}
></a>
<a className="footer-socials__vk" href={CONTACTS.social.vk.url}></a>
</div>
</footer>
);
}
export { Footer };

View File

@@ -1,89 +1,213 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect } from "react";
import './Form.scss';
import PencilIcon from '../../assets/images/icons/pencil.svg';
import "./Form.scss";
import PencilIcon from "../../assets/images/icons/pencil.svg";
import { API_CONFIG } from "../../config/contacts";
function Form({ scrolledThreshold }) {
const [name, setName] = useState('');
const [phone, setPhone] = useState('');
const [isVisible, setVisible] = useState(false);
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [isVisible, setVisible] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [submitStatus, setSubmitStatus] = useState(null); // 'success', 'error', null
const checkVisible = () => {
const scrolled = document.documentElement.scrollTop;
if (scrolled > scrolledThreshold){ // вы можете настроить это значение
if(!isVisible) setVisible(true);
} else{
if(isVisible) setVisible(false);
}
};
const checkVisible = () => {
const scrolled = document.documentElement.scrollTop;
if (scrolled > scrolledThreshold) {
// вы можете настроить это значение
if (!isVisible) setVisible(true);
} else {
if (isVisible) setVisible(false);
}
};
useEffect(() => {
window.addEventListener('scroll', checkVisible);
return () => window.removeEventListener('scroll', checkVisible);
});
useEffect(() => {
window.addEventListener("scroll", checkVisible);
return () => window.removeEventListener("scroll", checkVisible);
});
const handleSubmit = (e) => {
e.preventDefault();
// в этой функции можно добавить логику для отправки формы на сервер
console.log(`${name}, ваш номер телефона: ${phone}`);
setName('');
setPhone('');
};
// Автоматически скрываем сообщение об успехе через 5 секунд
useEffect(() => {
if (submitStatus === "success") {
const timer = setTimeout(() => {
setSubmitStatus(null);
}, 5000);
return () => clearTimeout(timer);
}
}, [submitStatus]);
function scrollToTop() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
// Функция для форматирования номера телефона
const formatPhoneNumber = (value) => {
// Убираем все нецифровые символы
const phoneNumber = value.replace(/\D/g, "");
// Ограничиваем длину номера
if (phoneNumber.length > 11) {
return phone; // возвращаем предыдущее значение, если превышена длина
}
return (
<section className="consultation-form font-inter-regular">
<div className="consultation-form__info form-info">
<h2 className="form-info__title font-inter-bold">
Решили купить или продать квартиру?
<span>Закажите бесплатную консультацию</span>
</h2>
<form onSubmit={handleSubmit}>
<p className="form__title">Заполните форму ниже</p>
<p>Мы позвоним вам в ближайшее время</p>
<div>
<input
className="font-inter-regular"
type="text"
value={name}
placeholder="Ваше имя"
onChange={(e) => setName(e.target.value)}
/>
<input
className="font-inter-regular"
type="tel"
value={phone}
placeholder="+7(800)555-35-35"
onChange={(e) => setPhone(e.target.value)}
/>
<button
className="form-btn font-inter-regular"
type="submit"
>
Записаться на консультацию
</button>
</div>
<p>
Заполняя форму, вы соглашаетесь с политикой
конфиденциальности
</p>
</form>
<div className="que-form">
<div className={`arrow ${isVisible ? 'arrow__visible' : ''}`} onClick={scrollToTop}></div>
<p className="font-inter-bold">
У вас остались вопросы? <span>Напишите нам, мы онлайн!</span>
</p>
<img className="que__img" src={PencilIcon} alt="pencil" />
</div>
// Форматируем номер
if (phoneNumber.length === 0) return "";
if (phoneNumber.length <= 1) return `+7`;
if (phoneNumber.length <= 4) return `+7(${phoneNumber.slice(1)}`;
if (phoneNumber.length <= 7)
return `+7(${phoneNumber.slice(1, 4)})${phoneNumber.slice(4)}`;
if (phoneNumber.length <= 9)
return `+7(${phoneNumber.slice(1, 4)})${phoneNumber.slice(
4,
7
)}-${phoneNumber.slice(7)}`;
return `+7(${phoneNumber.slice(1, 4)})${phoneNumber.slice(
4,
7
)}-${phoneNumber.slice(7, 9)}-${phoneNumber.slice(9, 11)}`;
};
const handlePhoneChange = (e) => {
const formattedPhone = formatPhoneNumber(e.target.value);
setPhone(formattedPhone);
};
const handleSubmit = async (e) => {
e.preventDefault();
// Проверяем, что поля заполнены
if (!name.trim() || !phone.trim()) {
setSubmitStatus("error");
return;
}
setIsLoading(true);
setSubmitStatus(null);
try {
const response = await fetch(
API_CONFIG.getFullURL(API_CONFIG.endpoints.feedback),
{
method: "POST",
headers: {
"Content-Type": "application/json",
accept: "*/*",
},
body: JSON.stringify({
firstName: name.trim(),
phoneNumber: phone.trim().replace(/\D/g, ""), // убираем все нецифровые символы
}),
}
);
if (response.ok) {
setSubmitStatus("success");
setName("");
setPhone("");
console.log("Заявка успешно отправлена");
} else {
throw new Error("Ошибка при отправке заявки");
}
} catch (error) {
console.error("Ошибка при отправке формы:", error);
setSubmitStatus("error");
} finally {
setIsLoading(false);
}
};
function scrollToTop() {
window.scrollTo({
top: 0,
behavior: "smooth",
});
}
return (
<section className="consultation-form font-inter-regular">
<div className="consultation-form__info form-info">
<h2 className="form-info__title font-inter-bold">
Решили купить или продать квартиру?
<span>Закажите бесплатную консультацию</span>
</h2>
<form onSubmit={handleSubmit}>
<p className="form__title">Заполните форму ниже</p>
<p>Мы позвоним вам в ближайшее время</p>
{submitStatus === "success" && (
<div
style={{
color: "green",
marginBottom: "15px",
padding: "10px",
backgroundColor: "#d4edda",
border: "1px solid #c3e6cb",
borderRadius: "4px",
}}
>
Спасибо! Ваша заявка отправлена. Мы свяжемся с вами в ближайшее
время.
</div>
</section>
);
)}
{submitStatus === "error" && (
<div
style={{
color: "red",
marginBottom: "15px",
padding: "10px",
backgroundColor: "#f8d7da",
border: "1px solid #f5c6cb",
borderRadius: "4px",
}}
>
Ошибка при отправке. Пожалуйста, проверьте данные и попробуйте
снова.
</div>
)}
<div>
<input
className="font-inter-regular"
type="text"
value={name}
placeholder="Ваше имя"
onChange={(e) => setName(e.target.value)}
required
disabled={isLoading}
/>
<input
className="font-inter-regular"
type="tel"
value={phone}
placeholder="+7(800)555-35-35"
onChange={handlePhoneChange}
required
disabled={isLoading}
/>
<button
className="form-btn font-inter-regular"
type="submit"
disabled={isLoading || !name.trim() || !phone.trim()}
style={{
opacity: isLoading ? 0.7 : 1,
cursor: isLoading ? "not-allowed" : "pointer",
}}
>
{isLoading ? "Отправляем..." : "Записаться на консультацию"}
</button>
</div>
<p>Заполняя форму, вы соглашаетесь с политикой конфиденциальности</p>
</form>
<div className="que-form">
<div
className={`arrow ${isVisible ? "arrow__visible" : ""}`}
onClick={scrollToTop}
></div>
<p className="font-inter-bold">
У вас остались вопросы? <span>Напишите нам, мы онлайн!</span>
</p>
<img className="que__img" src={PencilIcon} alt="pencil" />
</div>
</div>
</section>
);
}
export { Form };

View File

@@ -1,86 +1,117 @@
import './Header.scss';
import React, { useState } from 'react';
import { Link, useLocation } from 'react-router-dom';
import "./Header.scss";
import React, { useState } from "react";
import { Link, useLocation } from "react-router-dom";
import { CONTACTS } from "../../config/contacts";
function Header() {
const [isOpen, setIsOpen] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const handleToggle = () => {
setIsOpen(!isOpen);
};
const handleToggle = () => {
setIsOpen(!isOpen);
};
const location = useLocation();
const isGradientBackground = location.pathname === '/apartament';
const isHomePage = location.pathname === '/';
return (
<header className={`header font-inter-bold ${isGradientBackground ? 'header_gradient' : ''}`}>
<Link className="header__logo" to="/"></Link>
{isHomePage && <div className="header__text"></div>}
<div className="burgerMenu">
<a href="tel:+73512170074" className="header-info__call">8(351)217-00-74</a>
<div className="burger-item">
<input id="toggle" type="checkbox" checked={isOpen} onChange={handleToggle}></input>
<label for="toggle" className={`hamburger ${isOpen ? 'open' : ''}`}>
<div class="top-bun"></div>
<div class="meat"></div>
<div class="bottom-bun"></div>
</label>
<div class="nav">
<div class="nav-wrapper">
<nav className="nav-container">
<Link to="/objects" className="header__link">
Объекты
</Link>
<Link to="/services" className="header__link">
Услуги
</Link>
<Link to="/about" className="header__link">
О компании
</Link>
<Link to="/office" className="header__link" href="#">
Наш офис
</Link>
<p>Челябинск</p>
<div className="header-socials__links">
<a className="header-socials__tg" href="#"></a>
<a className="header-socials__inst" href="#"></a>
<a className="header-socials__vk" href="#"></a>
</div>
</nav>
</div>
</div>
</div>
</div>
<nav className="header__nav">
const location = useLocation();
const isGradientBackground = location.pathname === "/apartament";
const isHomePage = location.pathname === "/";
return (
<header
className={`header font-inter-bold ${
isGradientBackground ? "header_gradient" : ""
}`}
>
<Link className="header__logo" to="/"></Link>
{isHomePage && <div className="header__text"></div>}
<div className="burgerMenu">
<a href={CONTACTS.phone.link} className="header-info__call">
{CONTACTS.phone.display}
</a>
<div className="burger-item">
<input
id="toggle"
type="checkbox"
checked={isOpen}
onChange={handleToggle}
></input>
<label for="toggle" className={`hamburger ${isOpen ? "open" : ""}`}>
<div class="top-bun"></div>
<div class="meat"></div>
<div class="bottom-bun"></div>
</label>
<div class="nav">
<div class="nav-wrapper">
<nav className="nav-container">
<Link to="/objects" className="header__link">
Объекты
Объекты
</Link>
<Link to="/services" className="header__link">
Услуги
Услуги
</Link>
<Link to="/about" className="header__link">
О компании
О компании
</Link>
<Link to="/office" className="header__link" href="#">
Наш офис
Наш офис
</Link>
</nav>
<div className="header-info">
<a href="tel:+73512170074" className="header-info__call">8(351)217-00-74</a>
<button className="header-info__btn" type="button">
Обратный звонок
</button>
</div>
<div className="header-socials">
<span className="header-socials__location">Челябинск</span>
<p>{CONTACTS.address.main.city}</p>
<div className="header-socials__links">
<a className="header-socials__tg" href="#"></a>
<a className="header-socials__inst" href="#"></a>
<a className="header-socials__vk" href="#"></a>
<a
className="header-socials__tg"
href={CONTACTS.social.telegram.url}
></a>
<a
className="header-socials__inst"
href={CONTACTS.social.instagram.url}
></a>
<a
className="header-socials__vk"
href={CONTACTS.social.vk.url}
></a>
</div>
</nav>
</div>
</header>
);
</div>
</div>
</div>
<nav className="header__nav">
<Link to="/objects" className="header__link">
Объекты
</Link>
<Link to="/services" className="header__link">
Услуги
</Link>
<Link to="/about" className="header__link">
О компании
</Link>
<Link to="/office" className="header__link" href="#">
Наш офис
</Link>
</nav>
<div className="header-info">
<a href={CONTACTS.phone.link} className="header-info__call">
{CONTACTS.phone.display}
</a>
<button className="header-info__btn" type="button">
Обратный звонок
</button>
</div>
<div className="header-socials">
<span className="header-socials__location">
{CONTACTS.address.main.city}
</span>
<div className="header-socials__links">
<a
className="header-socials__tg"
href={CONTACTS.social.telegram.url}
></a>
<a
className="header-socials__inst"
href={CONTACTS.social.instagram.url}
></a>
<a className="header-socials__vk" href={CONTACTS.social.vk.url}></a>
</div>
</div>
</header>
);
}
export { Header };

View File

@@ -1,388 +1,391 @@
@import '../../styles/vars.scss';
@import "../../styles/vars.scss";
a {
color: white;
text-decoration: none;
color: white;
text-decoration: none;
}
.header {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
padding: 45px;
color: white;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
padding: 45px;
color: white;
}
.header a:hover {
text-decoration: underline;
text-decoration: underline;
}
.header_gradient {
background: linear-gradient(180deg, #061A25 0%, rgba(18, 114, 170, 0.7) 150%);
background: linear-gradient(180deg, #061a25 0%, rgba(18, 114, 170, 0.7) 150%);
}
.header__logo {
grid-row: 1/3;
background-image: url('../../assets/images/logo/logo-png.png');
width: 302px;
height: 69px;
background-size: cover;
grid-row: 1/3;
background-image: url("../../assets/images/logo/AlmaVid-Logo.svg");
width: 320px;
height: 69px;
background-size: cover;
}
.header__nav {
display: flex;
align-items: center;
justify-content: center;
column-gap: 47px;
font-size: 17px;
line-height: 29px;
display: flex;
align-items: center;
justify-content: center;
column-gap: 47px;
font-size: 17px;
line-height: 29px;
}
.header-info {
display: flex;
grid-column: 3/3;
align-items: center;
justify-self: end;
column-gap: 23.5px;
display: flex;
grid-column: 3/3;
align-items: center;
justify-self: end;
column-gap: 23.5px;
}
.header-info__btn {
height: 38px;
width: 150px;
font-weight: 700;
font-size: 15px;
color: black;
background-color: rgb(255, 255, 255, 0.8);
border-radius: 16px;
border: none;
cursor: pointer;
height: 38px;
width: 150px;
font-weight: 700;
font-size: 15px;
color: black;
background-color: rgb(255, 255, 255, 0.8);
border-radius: 16px;
border: none;
cursor: pointer;
}
.header-info__btn:hover {
background-color: rgb(255, 255, 255, 0.9);
background-color: rgb(255, 255, 255, 0.9);
}
.header-socials {
grid-row: 2/2;
grid-column: 3/3;
display: flex;
align-items: center;
column-gap: 47px;
justify-self: end;
margin-right: 29px;
margin-top: 10px;
grid-row: 2/2;
grid-column: 3/3;
display: flex;
align-items: center;
column-gap: 47px;
justify-self: end;
margin-right: 29px;
margin-top: 10px;
}
.header-socials__links {
display: flex;
align-items: center;
display: flex;
align-items: center;
}
.header-socials__tg {
background-image: url(../../assets/images/icons/telegram.svg);
width: 22.5px;
height: 19px;
background-size: cover;
background-image: url(../../assets/images/icons/telegram.svg);
width: 22.5px;
height: 19px;
background-size: cover;
}
// ширину и высоту увеличили на 1px
.header-socials__inst {
background-image: url(../../assets/images/icons/inst.svg);
width: 42px;
height: 24px;
background-size: cover;
background-image: url(../../assets/images/icons/inst.svg);
width: 42px;
height: 24px;
background-size: cover;
}
// ширину уменьшили на 1px
.header-socials__vk {
background-image: url(../../assets/images/icons/vk.svg);
width: 32.5px;
height: 34px;
background-size: cover;
background-image: url(../../assets/images/icons/vk.svg);
width: 32.5px;
height: 34px;
background-size: cover;
}
@media (min-width:1800px) {
.header__logo {
width: 372px;
height: 85px;
}
@media (min-width: 1800px) {
.header__logo {
width: 400px;
height: 85px;
}
.header__nav,
.header-info__call,
.header-info__btn,
.header-socials__location {
font-size: 21px;
}
.header__nav,
.header-info__call,
.header-info__btn,
.header-socials__location {
font-size: 21px;
}
.header-info__btn {
width: 210px;
}
.header-info__btn {
width: 210px;
}
.header-socials__tg {
width: 28.5px;
height: 24px;
}
.header-socials__tg {
width: 28.5px;
height: 24px;
}
.header-socials__inst {
width: 47px;
height: 27px;
}
.header-socials__inst {
width: 47px;
height: 27px;
}
.header-socials__vk {
width: 35.5px;
height: 37px;
}
.header-socials__vk {
width: 35.5px;
height: 37px;
}
}
@media (max-width: 1480px) {
.header__nav {
column-gap: 31px;
font-size: 16px;
}
.header__nav {
column-gap: 31px;
font-size: 16px;
}
}
@media (max-width: $desktopWidth) {
.header {
padding: 36px;
}
.header {
padding: 36px;
}
.header__logo {
width: 290px;
height: 62px;
}
.header__logo {
width: 270px;
height: 62px;
}
.header-info,
.header-info__btn {
font-size: 14px;
}
.header-info,
.header-info__btn {
font-size: 14px;
}
.header-info__btn {
height: 35px;
width: 137px;
}
.header-info__btn {
height: 35px;
width: 137px;
}
.header__nav {
column-gap: 17px;
font-size: 14px;
}
.header__nav {
column-gap: 17px;
font-size: 14px;
}
.header-socials {
font-size: 14px;
}
.header-socials {
font-size: 14px;
}
}
@media (max-width: $laptopWidth) {
.header {
grid-template-columns: auto;
padding: 18px;
}
.header {
grid-template-columns: auto;
padding: 18px;
}
.header__nav {
column-gap: 14px;
font-size: 11px;
}
.header__nav {
column-gap: 14px;
font-size: 11px;
}
.header__logo {
width: 200px;
height: 46px;
}
.header__logo {
width: 220px;
height: 46px;
}
.header-info {
font-size: 11px;
}
.header-info {
font-size: 11px;
}
.header-info__btn {
font-size: 13px;
}
.header-info__btn {
font-size: 13px;
}
.header-socials {
margin-top: 5px;
font-size: 11px;
}
.header-socials {
margin-top: 5px;
font-size: 11px;
}
}
@media (max-width: 780px) {
.header__logo {
width: 210px;
height: 42px;
}
}
h1 {
text-align: center;
letter-spacing: 1px;
word-spacing: 0.15em;
font-size: 3em;
line-height: 1.2;
transform: translateY(52%);
text-align: center;
letter-spacing: 1px;
word-spacing: 0.15em;
font-size: 3em;
line-height: 1.2;
transform: translateY(52%);
}
#toggle {
display: none;
display: none;
}
/**
Hamburger
**/
.hamburger {
position: absolute;
top: 4em;
right: 7%;
margin-left: -2em;
margin-top: -45px;
width: 2em;
height: 45px;
z-index: 5;
position: absolute;
top: 4em;
right: 7%;
margin-left: -2em;
margin-top: -45px;
width: 2em;
height: 45px;
z-index: 5;
}
.open {
position: fixed;
position: fixed;
}
.hamburger div {
position: relative;
width: 3.1em;
height: 5px;
border-radius: 3px;
background-color: white;
margin-top: 8px;
transition: all 0.3s ease-in-out;
position: relative;
width: 3.1em;
height: 5px;
border-radius: 3px;
background-color: white;
margin-top: 8px;
transition: all 0.3s ease-in-out;
}
/**
Nav Styles
**/
.nav {
position: fixed;
width: 100%;
height: 100%;
background-color: #17628C;
top: -100%;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
transition: all 0.3s ease-in-out;
transform: scale(0);
z-index: 1;
position: fixed;
width: 100%;
height: 100%;
background-color: #17628c;
top: -100%;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
transition: all 0.3s ease-in-out;
transform: scale(0);
z-index: 1;
}
.nav-wrapper {
position: relative;
overflow: hidden;
overflow-y: auto;
height: 100%;
position: relative;
overflow: hidden;
overflow-y: auto;
height: 100%;
}
.nav-container {
display: flex;
flex-direction: column;
text-align: left;
margin-left: 25%;
margin-top: 15%;
display: flex;
flex-direction: column;
text-align: left;
margin-left: 25%;
margin-top: 15%;
}
.nav-container a,
.nav-container p {
position: relative;
text-decoration: none;
color: white;
font-size: 2em;
display: inline-block;
margin-top: 1.25em;
margin-bottom: 0;
transition: color 0.2s ease-in-out;
letter-spacing: 1px;
position: relative;
text-decoration: none;
color: white;
font-size: 2em;
display: inline-block;
margin-top: 1.25em;
margin-bottom: 0;
transition: color 0.2s ease-in-out;
letter-spacing: 1px;
}
.nav-container a:hover {
text-decoration: none;
text-decoration: none;
}
.nav-container .header__link:before {
content: '';
height: 0;
position: absolute;
width: 0.25em;
background-color: white;
left: -0.5em;
transition: all 0.2s ease-in-out;
content: "";
height: 0;
position: absolute;
width: 0.25em;
background-color: white;
left: -0.5em;
transition: all 0.2s ease-in-out;
}
.nav-container a:hover {
color: white;
color: white;
}
.nav-container a:hover:before {
height: 100%;
height: 100%;
}
/**
Animations
**/
#toggle:checked+.hamburger .top-bun {
transform: rotate(-45deg);
margin-top: 25px;
#toggle:checked + .hamburger .top-bun {
transform: rotate(-45deg);
margin-top: 25px;
}
#toggle:checked+.hamburger .bottom-bun {
opacity: 0;
transform: rotate(45deg);
#toggle:checked + .hamburger .bottom-bun {
opacity: 0;
transform: rotate(45deg);
}
#toggle:checked+.hamburger .meat {
transform: rotate(45deg);
margin-top: -7px;
#toggle:checked + .hamburger .meat {
transform: rotate(45deg);
margin-top: -7px;
}
#toggle:checked+.hamburger+.nav {
top: 0;
transform: scale(1);
#toggle:checked + .hamburger + .nav {
top: 0;
transform: scale(1);
}
@media (min-width: 769px) {
.burgerMenu {
display: none;
}
.burgerMenu {
display: none;
}
.header__text {
display: none;
}
.header__text {
display: none;
}
}
@media (max-width: $tabletWidth) {
.header {
display: flex;
justify-content: space-between;
align-items: center;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
}
.burgerMenu {
display: flex;
justify-content: flex-end;
}
.burgerMenu {
display: flex;
justify-content: flex-end;
}
.header-info__call {
margin-right: 100px;
}
.header-info__call {
margin-right: 100px;
}
.header__logo {
// grid-row: 1/3;
background-image: url('../../assets/images/logo/AlvaMid-Logo-Small.svg');
width: 50px;
height: 50px;
}
.header__logo {
// grid-row: 1/3;
background-image: url("../../assets/images/logo/AlvaMid-Logo-Small.svg");
width: 50px;
height: 50px;
}
.header__nav,
.header-info,
.header-socials {
display: none;
}
.header__nav,
.header-info,
.header-socials {
display: none;
}
.header__text {
position: absolute;
background-image: url('../../assets/images/logo/textLogo.svg');
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
height: 113px;
background-size: contain;
background-repeat: no-repeat;
}
}
.header__text {
position: absolute;
background-image: url("../../assets/images/logo/textLogo.svg");
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
height: 113px;
background-size: contain;
background-repeat: no-repeat;
}
}

View File

@@ -66,6 +66,55 @@
.item__image {
border-top-right-radius: 15px;
border-top-left-radius: 15px;
width: 100%;
height: 250px;
object-fit: cover;
object-position: center;
display: block;
@media (max-width: 1300px) {
height: 230px;
}
@media (max-width: 1200px) {
height: 210px;
}
@media (max-width: 1100px) {
height: 190px;
}
@media (max-width: $laptopWidth) {
height: 170px;
}
@media (max-width: $tabletWidth) {
height: 300px;
}
@media (max-width: 740px) {
height: 280px;
}
@media (max-width: 690px) {
height: 250px;
}
@media (max-width: 635px) {
height: 220px;
}
@media (max-width: 570px) {
height: 190px;
}
@media (max-width: $mobileWidth) {
height: 210px;
}
@media (max-width: 420px) {
height: 190px;
}
}
.item__info {

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import Slider from 'react-slick';
import { Link } from 'react-router-dom';
import { useMediaQuery } from 'react-responsive';
@@ -7,6 +7,7 @@ import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
import './SliderObjects.scss';
import { Object } from '../Object/Object';
import { API_CONFIG } from '../../config/contacts';
import objectPicOne from '../../assets/images/apartaments/image-44.jpg';
import objectPicTwo from '../../assets/images/apartaments/image-45.jpg';
@@ -25,10 +26,40 @@ const PrevArrow = ({ onClick }) => {
};
const SliderComponent = () => {
const [objects, setObjects] = useState([]);
const [loading, setLoading] = useState(true);
const isMobileResolution = useMediaQuery({ maxWidth: 768 });
// Загрузка данных с API
useEffect(() => {
const fetchObjects = async () => {
try {
const response = await fetch(API_CONFIG.getFullURL(API_CONFIG.endpoints.rental), {
method: 'GET',
headers: {
'accept': '*/*'
}
});
if (response.ok) {
const data = await response.json();
setObjects(data);
}
} catch (error) {
console.error('Ошибка при загрузке объектов:', error);
// В случае ошибки оставляем пустой массив, компонент не сломается
} finally {
setLoading(false);
}
};
fetchObjects();
}, []);
const settings = {
dots: false,
infinite: true,
dots: objects.length > (isMobileResolution ? 1 : 3), // Показываем точки если объектов больше чем влезает
infinite: objects.length > (isMobileResolution ? 1 : 3), // Бесконечная прокрутка только если объектов достаточно
speed: 500,
slidesToShow: isMobileResolution ? 1 : 3,
slidesToScroll: isMobileResolution ? 1 : 3,
@@ -37,46 +68,49 @@ const SliderComponent = () => {
prevArrow: <PrevArrow />,
};
// Если загружаем данные, показываем статические объекты как fallback
if (loading || objects.length === 0) {
return (
<div className="slider-objects">
<Slider {...{...settings, dots: false, infinite: true}}>
<Link className="objects-link" to="/apartament">
<Object
image={objectPicOne}
price="1 234 567 ₽"
desc="1-комн. кв. 34 м"
address="Ул. Луначарского, Ленинский район"
/>
</Link>
<Object
image={objectPicTwo}
price="1 234 567 ₽"
desc="1-комн. кв. 34 м"
address="Ул. Зари, Вагонка"
/>
<Object
image={objectPicThree}
price="1 234 567 ₽"
desc="1-комн. кв. 34 м"
address="Ул. Солнечная, Заречный район"
/>
</Slider>
</div>
);
}
return (
<div className="slider-objects">
<Slider {...settings}>
<Link className="objects-link" to="/apartament">
<Object
image={objectPicOne}
price="1 234 567 ₽"
desc="1-комн. кв. 34 м"
address="Ул. Луначарского, Ленинский район"
/></Link>
<Object
image={objectPicTwo}
price="1 234 567 ₽"
desc="1-комн. кв. 34 м"
address="Ул. Зари, Вагонка"
/>
<Object
image={objectPicThree}
price="1 234 567 ₽"
desc="1-комн. кв. 34 м"
address="Ул. Солнечная, Заречный район"
/>
<Object
image={objectPicOne}
price="1 234 567 ₽"
desc="1-комн. кв. 34 м"
address="Ул. Луначарского, Ленинский район"
/>
<Object
image={objectPicTwo}
price="1 234 567 ₽"
desc="1-комн. кв. 34 м"
address="Ул. Зари, Вагонка"
/>
<Object
image={objectPicThree}
price="1 234 567 ₽"
desc="1-комн. кв. 34 м"
address="Ул. Солнечная, Заречный район"
/>
{objects.map((object) => (
<Link key={object.id} className="objects-link" to={`/apartament/${object.id}`}>
<Object
image={object.photoUrl}
price={object.price}
desc={object.title}
address={object.address}
/>
</Link>
))}
</Slider>
</div>
);

70
src/config/contacts.js Normal file
View File

@@ -0,0 +1,70 @@
export const CONTACTS = {
phone: {
display: "8(351)217-00-74",
link: "tel:+73512170074",
},
email: {
display: "sdelka.74@yandex.ru",
link: "mailto:sdelka.74@yandex.ru",
},
address: {
main: {
street: "ул. Комаровского, 4А, офис 210",
city: "Челябинск",
postalCode: "454052",
full: "ул. Комаровского, 4А, офис 210, Челябинск, 454052",
},
office: {
street: "Ленина, д. 60 В, оф. 701",
city: "Челябинск",
description: "Вход в офис со двора",
full: "Ленина, д. 60 В, оф. 701, Челябинск",
},
},
coordinates: [55.242355, 61.37697],
social: {
vk: {
url: "https://vk.com/almavid_74",
name: "ВКонтакте",
},
telegram: {
url: "https://t.me/almavid_74",
name: "Telegram",
},
instagram: {
url: "https://instagram.com/almavid_74",
name: "Instagram",
},
},
companyName: "Агентство недвижимости АЛМА-ВИД",
companyNameShort: "АЛМА-ВИД",
workingHours: "Пн-Пт: 9:00-18:00, Сб: 10:00-16:00",
getBalloonContent: () => {
return `
<div>
<strong>${CONTACTS.companyName}</strong><br/>
Адрес: ${CONTACTS.address.main.street}<br/>
${CONTACTS.address.main.city}, ${CONTACTS.address.main.postalCode}<br/>
Тел: ${CONTACTS.phone.display}
</div>
`;
},
};
export const API_CONFIG = {
baseURL: "https://almavid.ngr1.ru",
endpoints: {
feedback: "/api/feedback/send",
rental: "/api/rental/send",
},
getFullURL: (endpoint) => {
return `${API_CONFIG.baseURL}${endpoint}`;
},
};

15
src/hooks/useContacts.js Normal file
View File

@@ -0,0 +1,15 @@
import { CONTACTS } from "../config/contacts";
// Хук для использования контактной информации
export const useContacts = () => {
return {
...CONTACTS,
// Дополнительные утилитарные функции
getPhoneLink: () => CONTACTS.phone.link,
getEmailLink: () => CONTACTS.email.link,
getFullAddress: (type = "main") =>
CONTACTS.address[type]?.full || CONTACTS.address.main.full,
getSocialLink: (platform) => CONTACTS.social[platform]?.url || "#",
getSocialName: (platform) => CONTACTS.social[platform]?.name || platform,
};
};

View File

@@ -1,41 +1,52 @@
import { useEffect } from 'react';
import { useEffect } from "react";
import './About.scss';
import { Header } from '../../components/Header/Header';
import { Form } from '../../components/Form/Form';
import { SliderComponent } from '../../components/Sliders/Slider';
import "./About.scss";
import { Header } from "../../components/Header/Header";
import { Form } from "../../components/Form/Form";
import { SliderComponent } from "../../components/Sliders/Slider";
import { CONTACTS } from "../../config/contacts";
function About() {
useEffect(() => {
document.title = 'Об Агентстве недвижимости АЛМА-ВИД';
}, []);
useEffect(() => {
document.title = `Об ${CONTACTS.companyName}`;
}, []);
return (
<>
<div className="wrapper-about">
<Header />
<section className="about">
<div className="about-inner">
<div className="about__info font-inter-bold">
<p>Каждый из нас хоть раз сталкивается с квартирным вопросом - покупка, продажа,
обмен квартиры или дома - эти процессы требуют серьезного профессионального подхода
и юридической грамотности.</p>
<p>Агентство недвижимости АЛМА-ВИД существует с 2000 года за этот период мы обрели
доверие и уважение наших многочисленных клиентов.</p>
<p>Мы находимся в постоянном развитии и оттачиваем профессионализм наших сотрудников,
обладая серьезной материальной базой и налаженными коммуникациями с крупными банками.
Благодаря этому мы имеем возможность предоставлять услуги
в сфере недвижимости высокого качества.</p>
</div>
</div>
<div className="about__title font-inter-semibold">Об Агентстве недвижимости <span>АЛМА-Вид</span></div>
</section>
return (
<>
<div className="wrapper-about">
<Header />
<section className="about">
<div className="about-inner">
<div className="about__info font-inter-bold">
<p>
Каждый из нас хоть раз сталкивается с квартирным вопросом -
покупка, продажа, обмен квартиры или дома - эти процессы требуют
серьезного профессионального подхода и юридической грамотности.
</p>
<p>
Агентство недвижимости АЛМА-ВИД существует с 2000 года за этот
период мы обрели доверие и уважение наших многочисленных
клиентов.
</p>
<p>
Мы находимся в постоянном развитии и оттачиваем профессионализм
наших сотрудников, обладая серьезной материальной базой и
налаженными коммуникациями с крупными банками. Благодаря этому
мы имеем возможность предоставлять услуги в сфере недвижимости
высокого качества.
</p>
</div>
<section className="certificates">
<SliderComponent/>
</section>
<Form scrolledThreshold={1650}/>
</>
);
</div>
<div className="about__title font-inter-semibold">
Об {CONTACTS.companyName} <span>{CONTACTS.companyNameShort}</span>
</div>
</section>
</div>
<section className="certificates">
<SliderComponent />
</section>
<Form scrolledThreshold={1650} />
</>
);
}
export { About };

View File

@@ -1,123 +1,326 @@
import { useEffect } from 'react';
import './Apartament.scss';
import { YMaps, Map, } from '@pbe/react-yandex-maps';
import { useEffect, useState } from "react";
import "./Apartament.scss";
import { YMaps, Map, Placemark } from "@pbe/react-yandex-maps";
import { Header } from '../../components/Header/Header';
import { Form } from '../../components/Form/Form';
import { Gallery } from '../../components/Gallery/Gallery';
import { Header } from "../../components/Header/Header";
import { Form } from "../../components/Form/Form";
import { Gallery } from "../../components/Gallery/Gallery";
import { CONTACTS } from "../../config/contacts";
function Apartament() {
useEffect(() => {
document.title = 'Апартаменты';
}, []);
const [isMapActive, setIsMapActive] = useState(false);
return (
<>
<Header />
<section className="apartament">
<h2 className="apartament__title font-inter-bold">1-комн. кв. 34 м</h2>
<p className="apartament__para font-inter-regular">Ул. Луначарского, Ленинский район</p>
<div className="apartament__container">
<div className="apartament__info">
<Gallery/>
<div className="apartament__icons icons">
<div className="icons__item">
<div className="icons__pic icons__pic_area"></div>
<div className="icons__info">
<p className="icons__desc font-inter-regular ">Общая площадь</p>
<p className="icons__num font-inter-semibold">72М</p>
</div>
</div>
<div className="icons__item">
<div className="icons__pic icons__pic_living"></div>
<div className="icons__info">
<p className="icons__desc font-inter-regular ">Жилая площадь</p>
<p className="icons__num font-inter-semibold">68М</p>
</div>
</div>
<div className="icons__item">
<div className="icons__pic icons__pic_kitchen"></div>
<div className="icons__info">
<p className="icons__desc font-inter-regular ">Площадь кухни</p>
<p className="icons__num font-inter-semibold">11М</p>
</div>
</div>
<div className="icons__item">
<div className="icons__pic icons__pic_year"></div>
<div className="icons__info">
<p className="icons__desc font-inter-regular ">Год постройки</p>
<p className="icons__num font-inter-semibold">2003</p>
</div>
</div>
<div className="icons__item">
<div className="icons__pic icons__pic__floor"></div>
<div className="icons__info">
<p className="icons__desc font-inter-regular ">Этаж</p>
<p className="icons__num font-inter-semibold">7/12</p>
</div>
</div>
</div>
<div className="apartament__text font-inter-regular">
<p>Описани хаты рандомный текст Lorem Ipsum is simply dummy text of
the printing and typesetting industry. Lorem Ipsum has been the
industry's standard dummy text ever since the 1500s, when an unknown
printer took a galley of type and scrambled it to make a type specimen book.
It has survived not only five centuries, but also the leap into electronic
typesetting, remaining essentially unchanged. It was popularised in the 1960s
with the release of Letraset sheets containing Lorem Ipsum passages, and more
recently with desktop publishing software like Aldus PageMaker including
versions of Lorem Ipsum.</p>
</div>
<div className="apartament__desc font-inter-regular">
<div className="apartament__flat flat">
<p className="flat__title font-inter-bold">О квартире</p>
<ul>
<li><span className="title-color">Тип жилья:</span> вторичный</li>
<li><span className="title-color">Общая площадь:</span> 31.9 м²</li>
<li><span className="title-color">Площадь кухни:</span> 4 м²</li>
<li><span className="title-color">Жилая площадь:</span> 21 м²</li>
<li><span className="title-color">Этаж:</span> 4 из 5</li>
<li><span className="title-color">Балкон или лоджия:</span> лоджия</li>
<li><span className="title-color">Высота потолков:</span> 2.5 м</li>
<li><span className="title-color">Санузел:</span> совмещенный</li>
<li><span className="title-color">Вид из окон:</span> во двор</li>
<li><span className="title-color">Ремонт:</span> косметический</li>
</ul>
</div>
<div className="apartament__home home">
<p className="home__title font-inter-bold">О доме</p>
<ul>
<li><span className="title-color">Год постройки:</span> 2003</li>
<li><span className="title-color">Тип дома:</span> панельный</li>
<li><span className="title-color">Тип перекрытий:</span> железобетонный</li>
<li><span className="title-color">Подъезды:</span> 5</li>
<li><span className="title-color">Отопление:</span> центральное</li>
<li><span className="title-color">Аварийность:</span> нет</li>
<li><span className="title-color">Газоснобжение:</span> центральное</li>
</ul>
</div>
</div>
</div>
<div className="apartament__price price font-inter-regular">
<div className="price__container">
<p className="price__total font-inter-bold">1 234 567 </p>
<div className="price__logo"></div>
</div>
<p className="price__desc">В ипотеку от 6546823 /мес</p>
<p className="price__meter">Цена за метр............................................................45656 /м</p>
<p className="price__conditions">Условия сделки......................................свободная продажа</p>
<p className="price__mortgage">Ипотека......................................................................возможна</p>
<button className="apartament__btn_number font-inter-bold" type="button">Показать телефон</button>
<button className="apartament__btn_write font-inter-bold" type="button">Написать</button>
</div>
useEffect(() => {
document.title = "Апартаменты";
}, []);
const handleActivateMap = () => {
setIsMapActive(true);
if (window.apartamentMap) {
window.apartamentMap.behaviors.enable("scrollZoom");
window.apartamentMap.behaviors.enable("drag");
}
};
const handleDeactivateMap = () => {
setIsMapActive(false);
if (window.apartamentMap) {
window.apartamentMap.behaviors.disable("scrollZoom");
window.apartamentMap.behaviors.disable("drag");
}
};
return (
<>
<Header />
<section className="apartament">
<h2 className="apartament__title font-inter-bold">1-комн. кв. 34 м</h2>
<p className="apartament__para font-inter-regular">
Ул. Луначарского, Ленинский район
</p>
<div className="apartament__container">
<div className="apartament__info">
<Gallery />
<div className="apartament__icons icons">
<div className="icons__item">
<div className="icons__pic icons__pic_area"></div>
<div className="icons__info">
<p className="icons__desc font-inter-regular ">
Общая площадь
</p>
<p className="icons__num font-inter-semibold">72М</p>
</div>
<YMaps>
<Map className="map-apartament" defaultState={{ center: [55.16, 61.4], zoom: 15 }} />
</YMaps>
</section>
<Form scrolledThreshold={2350}/>
</>
);
</div>
<div className="icons__item">
<div className="icons__pic icons__pic_living"></div>
<div className="icons__info">
<p className="icons__desc font-inter-regular ">
Жилая площадь
</p>
<p className="icons__num font-inter-semibold">68М</p>
</div>
</div>
<div className="icons__item">
<div className="icons__pic icons__pic_kitchen"></div>
<div className="icons__info">
<p className="icons__desc font-inter-regular ">
Площадь кухни
</p>
<p className="icons__num font-inter-semibold">11М</p>
</div>
</div>
<div className="icons__item">
<div className="icons__pic icons__pic_year"></div>
<div className="icons__info">
<p className="icons__desc font-inter-regular ">
Год постройки
</p>
<p className="icons__num font-inter-semibold">2003</p>
</div>
</div>
<div className="icons__item">
<div className="icons__pic icons__pic__floor"></div>
<div className="icons__info">
<p className="icons__desc font-inter-regular ">Этаж</p>
<p className="icons__num font-inter-semibold">7/12</p>
</div>
</div>
</div>
<div className="apartament__text font-inter-regular">
<p>
Описани хаты рандомный текст Lorem Ipsum is simply dummy text of
the printing and typesetting industry. Lorem Ipsum has been the
industry's standard dummy text ever since the 1500s, when an
unknown printer took a galley of type and scrambled it to make a
type specimen book. It has survived not only five centuries, but
also the leap into electronic typesetting, remaining essentially
unchanged. It was popularised in the 1960s with the release of
Letraset sheets containing Lorem Ipsum passages, and more
recently with desktop publishing software like Aldus PageMaker
including versions of Lorem Ipsum.
</p>
</div>
<div className="apartament__desc font-inter-regular">
<div className="apartament__flat flat">
<p className="flat__title font-inter-bold">О квартире</p>
<ul>
<li>
<span className="title-color">Тип жилья:</span> вторичный
</li>
<li>
<span className="title-color">Общая площадь:</span> 31.9 м²
</li>
<li>
<span className="title-color">Площадь кухни:</span> 4 м²
</li>
<li>
<span className="title-color">Жилая площадь:</span> 21 м²
</li>
<li>
<span className="title-color">Этаж:</span> 4 из 5
</li>
<li>
<span className="title-color">Балкон или лоджия:</span>{" "}
лоджия
</li>
<li>
<span className="title-color">Высота потолков:</span> 2.5 м
</li>
<li>
<span className="title-color">Санузел:</span> совмещенный
</li>
<li>
<span className="title-color">Вид из окон:</span> во двор
</li>
<li>
<span className="title-color">Ремонт:</span> косметический
</li>
</ul>
</div>
<div className="apartament__home home">
<p className="home__title font-inter-bold">О доме</p>
<ul>
<li>
<span className="title-color">Год постройки:</span> 2003
</li>
<li>
<span className="title-color">Тип дома:</span> панельный
</li>
<li>
<span className="title-color">Тип перекрытий:</span>{" "}
железобетонный
</li>
<li>
<span className="title-color">Подъезды:</span> 5
</li>
<li>
<span className="title-color">Отопление:</span> центральное
</li>
<li>
<span className="title-color">Аварийность:</span> нет
</li>
<li>
<span className="title-color">Газоснобжение:</span>{" "}
центральное
</li>
</ul>
</div>
</div>
</div>
<div className="apartament__price price font-inter-regular">
<div className="price__container">
<p className="price__total font-inter-bold">1 234 567 </p>
<div className="price__logo"></div>
</div>
<p className="price__desc">В ипотеку от 6546823 /мес</p>
<p className="price__meter">
Цена за
метр............................................................45656
/м
</p>
<p className="price__conditions">
Условия сделки......................................свободная
продажа
</p>
<p className="price__mortgage">
Ипотека......................................................................возможна
</p>
<button
className="apartament__btn_number font-inter-bold"
type="button"
>
Показать телефон
</button>
<button
className="apartament__btn_write font-inter-bold"
type="button"
>
Написать
</button>
</div>
</div>
<div style={{ position: "relative" }}>
<YMaps>
<Map
className="map-apartament"
defaultState={{
center: CONTACTS.coordinates,
zoom: 15,
}}
options={{
scrollZoom: false,
drag: false,
suppressMapOpenBlock: true,
}}
instanceRef={(ref) => {
window.apartamentMap = ref;
}}
>
<Placemark
geometry={CONTACTS.coordinates}
properties={{
balloonContent: CONTACTS.getBalloonContent(),
hintContent: `Офис ${CONTACTS.companyNameShort}`,
}}
options={{
preset: "islands#redDotIcon",
}}
/>
</Map>
{/* Блокирующий оверлей, когда карта неактивна */}
{!isMapActive && (
<div
onClick={handleActivateMap}
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "rgba(255, 255, 255, 0.1)",
zIndex: 999,
cursor: "pointer",
}}
/>
)}
{/* Кнопка управления картой в центре */}
<div
style={{
position: "absolute",
top: "85%",
left: "50%",
transform: "translate(-50%, -50%)",
zIndex: 1000,
}}
>
{!isMapActive ? (
<button
onClick={handleActivateMap}
style={{
background: "rgba(0, 123, 255, 0.9)",
border: "none",
borderRadius: "8px",
padding: "15px 25px",
fontSize: "16px",
fontFamily: "Inter, Arial, sans-serif",
cursor: "pointer",
boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
color: "white",
fontWeight: "bold",
minWidth: "140px",
textAlign: "center",
transition: "all 0.3s ease",
}}
onMouseEnter={(e) => {
e.target.style.background = "rgba(0, 123, 255, 1)";
e.target.style.transform = "scale(1.05)";
}}
onMouseLeave={(e) => {
e.target.style.background = "rgba(0, 123, 255, 0.9)";
e.target.style.transform = "scale(1)";
}}
>
📍 Посмотреть карту
</button>
) : (
<button
onClick={handleDeactivateMap}
style={{
background: "rgba(220, 53, 69, 0.9)",
border: "none",
borderRadius: "6px",
padding: "10px 20px",
fontSize: "14px",
fontFamily: "Inter, Arial, sans-serif",
cursor: "pointer",
boxShadow: "0 3px 8px rgba(0,0,0,0.3)",
color: "white",
fontWeight: "bold",
minWidth: "120px",
textAlign: "center",
transition: "all 0.3s ease",
}}
onMouseEnter={(e) => {
e.target.style.background = "rgba(220, 53, 69, 1)";
e.target.style.transform = "scale(1.05)";
}}
onMouseLeave={(e) => {
e.target.style.background = "rgba(220, 53, 69, 0.9)";
e.target.style.transform = "scale(1)";
}}
>
Закрыть карту
</button>
)}
</div>
</YMaps>
</div>
</section>
<Form scrolledThreshold={2350} />
</>
);
}
export { Apartament };

View File

@@ -1,16 +1,35 @@
import { useEffect } from "react";
import { useEffect, useState } from "react";
import "./Home.scss";
import { YMaps, Map } from "@pbe/react-yandex-maps";
import { YMaps, Map, Placemark } from "@pbe/react-yandex-maps";
import { Header } from "../../components/Header/Header";
import { Form } from "../../components/Form/Form";
import lawyer from "../../assets/images/lawyer/Mask-group.svg";
import { CONTACTS } from "../../config/contacts";
function Home() {
const [isMapActive, setIsMapActive] = useState(false);
useEffect(() => {
document.title = "Агентство недвижимости АЛМА-ВИД";
document.title = CONTACTS.companyName;
}, []);
const handleActivateMap = () => {
setIsMapActive(true);
if (window.homeMap) {
window.homeMap.behaviors.enable("scrollZoom");
window.homeMap.behaviors.enable("drag");
}
};
const handleDeactivateMap = () => {
setIsMapActive(false);
if (window.homeMap) {
window.homeMap.behaviors.disable("scrollZoom");
window.homeMap.behaviors.disable("drag");
}
};
return (
<>
<div className="wrapper">
@@ -90,8 +109,118 @@ function Home() {
<YMaps>
<Map
className="map"
defaultState={{ center: [55.16, 61.4], zoom: 12 }}
/>
defaultState={{
center: CONTACTS.coordinates,
zoom: 12,
}}
options={{
scrollZoom: false,
drag: false,
suppressMapOpenBlock: true,
}}
instanceRef={(ref) => {
window.homeMap = ref;
}}
>
<Placemark
geometry={CONTACTS.coordinates}
properties={{
balloonContent: CONTACTS.getBalloonContent(),
hintContent: `Офис ${CONTACTS.companyNameShort}`,
}}
options={{
preset: "islands#redDotIcon",
}}
/>
</Map>
{/* Блокирующий оверлей когда карта неактивна */}
{!isMapActive && (
<div
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "rgba(255, 255, 255, 0.1)",
zIndex: 999,
cursor: "pointer",
}}
onClick={handleActivateMap}
/>
)}
{/* Кнопка управления картой в центре */}
<div
style={{
position: "absolute",
top: "85%",
left: "50%",
transform: "translate(-50%, -50%)",
zIndex: 1000,
}}
>
{!isMapActive ? (
<button
onClick={handleActivateMap}
style={{
background: "rgba(0, 123, 255, 0.9)",
border: "none",
borderRadius: "8px",
padding: "15px 25px",
fontSize: "16px",
fontFamily: "Inter, Arial, sans-serif",
cursor: "pointer",
boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
color: "white",
fontWeight: "bold",
minWidth: "140px",
textAlign: "center",
transition: "all 0.3s ease",
}}
onMouseEnter={(e) => {
e.target.style.background = "rgba(0, 123, 255, 1)";
e.target.style.transform = "scale(1.05)";
}}
onMouseLeave={(e) => {
e.target.style.background = "rgba(0, 123, 255, 0.9)";
e.target.style.transform = "scale(1)";
}}
>
📍 Посмотреть карту
</button>
) : (
<button
onClick={handleDeactivateMap}
style={{
background: "rgba(220, 53, 69, 0.9)",
border: "none",
borderRadius: "6px",
padding: "10px 20px",
fontSize: "14px",
fontFamily: "Inter, Arial, sans-serif",
cursor: "pointer",
boxShadow: "0 3px 8px rgba(0,0,0,0.3)",
color: "white",
fontWeight: "bold",
minWidth: "120px",
textAlign: "center",
transition: "all 0.3s ease",
}}
onMouseEnter={(e) => {
e.target.style.background = "rgba(220, 53, 69, 1)";
e.target.style.transform = "scale(1.05)";
}}
onMouseLeave={(e) => {
e.target.style.background = "rgba(220, 53, 69, 0.9)";
e.target.style.transform = "scale(1)";
}}
>
Закрыть карту
</button>
)}
</div>
</YMaps>
</div>
<Form scrolledThreshold={2750} />

View File

@@ -120,6 +120,7 @@
.map-container {
padding: 0 146px 80px 146px;
position: relative;
@media (max-width: $laptopWidth) {
padding: 0px 50px 80px 50px;
@@ -143,29 +144,26 @@
}
}
.hero-tagline {
height: 100%;
display: flex;
justify-content: flex-end;
padding: 100px 60px 0;
justify-content: flex-end;
padding: 100px 60px 0;
p {
color: #ffffff;
font-family: "Inter", sans-serif;
font-family: "Inter", sans-serif;
font-size: max(50px, 3.646vw);
font-weight: 500;
font-weight: 500;
line-height: 1.5;
text-align: right;
max-width: max(600px, min(1150px, 59.896vw));
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.7);
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.7);
}
@media (max-width: $tabletWidth) {
padding: 15px 30px 0;
p {
font-size: 18px;
@@ -174,19 +172,16 @@
}
@media (max-width: $mobileWidth) {
order: 1;
width: 100%;
margin-top: 20px;
order: 1;
width: 100%;
margin-top: 20px;
justify-content: center;
padding: 10px 15px 0;
padding: 10px 15px 0;
p {
font-size: 16px;
text-align: center;
text-align: center;
max-width: 100%;
}
}

View File

@@ -1,26 +1,27 @@
import { useEffect } from 'react';
import './Objects.scss';
import { useEffect } from "react";
import "./Objects.scss";
import { Header } from '../../components/Header/Header';
import { Form } from '../../components/Form/Form';
import { SliderComponent } from '../../components/Sliders/SliderObjects';
import { Header } from "../../components/Header/Header";
import { Form } from "../../components/Form/Form";
import { SliderComponent } from "../../components/Sliders/SliderObjects";
import { CONTACTS } from "../../config/contacts";
function Objects() {
useEffect(() => {
document.title = 'Объекты Агентства недвижимости АЛМА-ВИД';
}, []);
useEffect(() => {
document.title = `Объекты ${CONTACTS.companyName}`;
}, []);
return (
<>
<div className="wrapper-objects">
<Header />
<section className="objects">
<SliderComponent/>
</section>
</div>
<Form scrolledThreshold={690}/>
</>
);
return (
<>
<div className="wrapper-objects">
<Header />
<section className="objects">
<SliderComponent />
</section>
</div>
<Form scrolledThreshold={690} />
</>
);
}
export { Objects };

View File

@@ -1,76 +1,235 @@
import { useEffect } from 'react';
import './Office.scss';
import { YMaps, Map } from '@pbe/react-yandex-maps';
import { useEffect, useState } from "react";
import "./Office.scss";
import { YMaps, Map, Placemark } from "@pbe/react-yandex-maps";
import { Header } from '../../components/Header/Header';
import { Header } from "../../components/Header/Header";
import { CONTACTS } from "../../config/contacts";
function Office() {
useEffect(() => {
document.title = 'Контакты Агентства недвижимости АЛМА-ВИД';
}, []);
return (
<>
<div className="wrapper-office">
<Header />
<section className="office">
<div className="office__title font-inter-semibold">АЛМАВИД<span>агентство недвижимости</span></div>
<div className="office__separator"></div>
<div className="office-inner">
<div className="office-container">
<div className="office__item">
<div className="office__pic office__pic_purchase"></div>
<div className="office__text">
<p className="office__desc font-inter-bold">Покупка, продажа,
<span>обмен квартир и комнат</span></p>
</div>
</div>
<div className="office__item">
<div className="office__pic office__pic_rent"></div>
<div className="office__text">
<p className="office__desc font-inter-bold">Аренда квартир
<span>и комнат</span></p>
</div>
</div>
<div className="office__item">
<div className="office__pic office__pic_buildings"></div>
<div className="office__text">
<p className="office__desc font-inter-bold">Новостройки</p>
</div>
</div>
<div className="office__item">
<div className="office__pic office__pic_country"></div>
<div className="office__text">
<p className="office__desc font-inter-bold">Загородная
<span>недвижимость</span></p>
</div>
</div>
<div className="office__item">
<div className="office__pic office__pic_commercial"></div>
<div className="office__text">
<p className="office__desc font-inter-bold">Коммерческая
<span>недвижимость</span></p>
</div>
</div>
</div>
</div>
</section>
</div>
<section className="office-location font-inter-bold">
<h2 className="office-location__title">Приходите в наш офис</h2>
<div className="office-info">
<p className="office-info__para_address"><span>Адрес:</span>Ленина, д. 60 В, оф. 701
<span className="office-info__desc">Вход в офис со двора</span></p>
<p className="office-info__para"><span>Телефон:</span>+7 (351) 217-00-74 Заказать звонок</p>
<p className="office-info__para"><span>E-mail:</span>sdelka.74@yandex.ru</p>
<p className="office-info__para"><span>Соц.сети:</span><a href="#">ВКонтакте</a></p>
const [isMapActive, setIsMapActive] = useState(false);
useEffect(() => {
document.title = `Контакты ${CONTACTS.companyName}`;
}, []);
const handleActivateMap = () => {
setIsMapActive(true);
if (window.officeMap) {
window.officeMap.behaviors.enable("scrollZoom");
window.officeMap.behaviors.enable("drag");
}
};
const handleDeactivateMap = () => {
setIsMapActive(false);
if (window.officeMap) {
window.officeMap.behaviors.disable("scrollZoom");
window.officeMap.behaviors.disable("drag");
}
};
return (
<>
<div className="wrapper-office">
<Header />
<section className="office">
<div className="office__title font-inter-semibold">
{CONTACTS.companyNameShort}ВИД<span>агентство недвижимости</span>
</div>
<div className="office__separator"></div>
<div className="office-inner">
<div className="office-container">
<div className="office__item">
<div className="office__pic office__pic_purchase"></div>
<div className="office__text">
<p className="office__desc font-inter-bold">
Покупка, продажа,
<span>обмен квартир и комнат</span>
</p>
</div>
<YMaps>
<Map className="map-office" defaultState={{ center: [55.16, 61.4], zoom: 12 }} />
</YMaps>
</section>
</>
);
</div>
<div className="office__item">
<div className="office__pic office__pic_rent"></div>
<div className="office__text">
<p className="office__desc font-inter-bold">
Аренда квартир
<span>и комнат</span>
</p>
</div>
</div>
<div className="office__item">
<div className="office__pic office__pic_buildings"></div>
<div className="office__text">
<p className="office__desc font-inter-bold">Новостройки</p>
</div>
</div>
<div className="office__item">
<div className="office__pic office__pic_country"></div>
<div className="office__text">
<p className="office__desc font-inter-bold">
Загородная
<span>недвижимость</span>
</p>
</div>
</div>
<div className="office__item">
<div className="office__pic office__pic_commercial"></div>
<div className="office__text">
<p className="office__desc font-inter-bold">
Коммерческая
<span>недвижимость</span>
</p>
</div>
</div>
</div>
</div>
</section>
</div>
<section className="office-location font-inter-bold">
<h2 className="office-location__title">Приходите в наш офис</h2>
<div className="office-info">
<p className="office-info__para_address">
<span>Адрес:</span>
{CONTACTS.address.office.full}
<span className="office-info__desc">
{CONTACTS.address.office.description}
</span>
</p>
<p className="office-info__para">
<span>Телефон:</span>
<a href={CONTACTS.phone.link}>{CONTACTS.phone.display}</a>
Заказать звонок
</p>
<p className="office-info__para">
<span>E-mail:</span>
<a href={CONTACTS.email.link}>{CONTACTS.email.display}</a>
</p>
<p className="office-info__para">
<span>Соц.сети:</span>
<a href={CONTACTS.social.vk.url}>{CONTACTS.social.vk.name}</a>
</p>
</div>
<div style={{ position: "relative" }}>
<YMaps>
<Map
className="map-office"
defaultState={{
center: CONTACTS.coordinates,
zoom: 16,
}}
options={{
scrollZoom: false,
drag: false,
suppressMapOpenBlock: true,
}}
instanceRef={(ref) => {
window.officeMap = ref;
}}
>
<Placemark
geometry={CONTACTS.coordinates}
properties={{
balloonContent: CONTACTS.getBalloonContent(),
hintContent: `Офис ${CONTACTS.companyNameShort}`,
}}
options={{
preset: "islands#redDotIcon",
}}
/>
</Map>
{/* Блокирующий оверлей, когда карта неактивна */}
{!isMapActive && (
<div
onClick={handleActivateMap}
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "rgba(255, 255, 255, 0.1)",
zIndex: 999,
cursor: "pointer",
}}
/>
)}
{/* Кнопка управления картой в центре */}
<div
style={{
position: "absolute",
top: "85%",
left: "50%",
transform: "translate(-50%, -50%)",
zIndex: 1000,
}}
>
{!isMapActive ? (
<button
onClick={handleActivateMap}
style={{
background: "rgba(0, 123, 255, 0.9)",
border: "none",
borderRadius: "8px",
padding: "15px 25px",
fontSize: "16px",
fontFamily: "Inter, Arial, sans-serif",
cursor: "pointer",
boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
color: "white",
fontWeight: "bold",
minWidth: "140px",
textAlign: "center",
transition: "all 0.3s ease",
}}
onMouseEnter={(e) => {
e.target.style.background = "rgba(0, 123, 255, 1)";
e.target.style.transform = "scale(1.05)";
}}
onMouseLeave={(e) => {
e.target.style.background = "rgba(0, 123, 255, 0.9)";
e.target.style.transform = "scale(1)";
}}
>
📍 Посмотреть карту
</button>
) : (
<button
onClick={handleDeactivateMap}
style={{
background: "rgba(220, 53, 69, 0.9)",
border: "none",
borderRadius: "6px",
padding: "10px 20px",
fontSize: "14px",
fontFamily: "Inter, Arial, sans-serif",
cursor: "pointer",
boxShadow: "0 3px 8px rgba(0,0,0,0.3)",
color: "white",
fontWeight: "bold",
minWidth: "120px",
textAlign: "center",
transition: "all 0.3s ease",
}}
onMouseEnter={(e) => {
e.target.style.background = "rgba(220, 53, 69, 1)";
e.target.style.transform = "scale(1.05)";
}}
onMouseLeave={(e) => {
e.target.style.background = "rgba(220, 53, 69, 0.9)";
e.target.style.transform = "scale(1)";
}}
>
Закрыть карту
</button>
)}
</div>
</YMaps>
</div>
</section>
</>
);
}
export { Office };

View File

@@ -1,119 +1,161 @@
import { useEffect } from 'react';
import './Services.scss';
import { useEffect } from "react";
import "./Services.scss";
import { Header } from '../../components/Header/Header';
import { Form } from '../../components/Form/Form';
import { Header } from "../../components/Header/Header";
import { Form } from "../../components/Form/Form";
import { CONTACTS } from "../../config/contacts";
function Services() {
useEffect(() => {
document.title = 'Услуги Агентства недвижимости АЛМА-ВИД';
}, []);
useEffect(() => {
document.title = `Услуги ${CONTACTS.companyName}`;
}, []);
return (
<>
<div className="wrapper-services">
<Header />
<div className="services__text">
<p className="services__title font-inter-bold">Мы работаем с 2000 года и помогаем
продать и купить жилую и коммерческую недвижимость.</p>
<p className="services__subtitle font-inter-bold">Получите бесплатную консультацию
по покупке или продаже вашей
недвижимости: <a className="services__link" href="#">Вконтакте</a></p>
</div>
return (
<>
<div className="wrapper-services">
<Header />
<div className="services__text">
<p className="services__title font-inter-bold">
Мы работаем с 2000 года и помогаем продать и купить жилую и
коммерческую недвижимость.
</p>
<p className="services__subtitle font-inter-bold">
Получите бесплатную консультацию по покупке или продаже вашей
недвижимости:{" "}
<a className="services__link" href={CONTACTS.social.vk.url}>
{CONTACTS.social.vk.name}
</a>
</p>
</div>
</div>
<section className="services-info font-inter-bold">
<h2 className="services-info__title">
Почему более 3 000 семей доверили нам свою недвижимость:
</h2>
<div className="services-info__container">
<div className="services-info__desc">
<div className="services-info__item">
<p className="services-info__subtitle">
1. Высокое качество работы
</p>
<p className="services-info__text font-inter-regular">
Наша деятельность проверена и признана соответствующей
национальному стандарту добровольной сертификации услуг на рынке
недвижимости Российской Федерации.
</p>
</div>
<section className="services-info font-inter-bold">
<h2 className="services-info__title">Почему более 3 000 семей доверили нам свою недвижимость:</h2>
<div className="services-info__container">
<div className="services-info__desc">
<div className="services-info__item">
<p className="services-info__subtitle">1. Высокое качество работы</p>
<p className="services-info__text font-inter-regular">Наша деятельность проверена и признана
соответствующей национальному
стандарту добровольной сертификации услуг на рынке недвижимости
Российской Федерации.</p>
</div>
<div className="services-info__item">
<p className="services-info__subtitle">2. Работаем в соответствии
с Законодательством РФ</p>
<p className="services-info__text font-inter-regular">Юридическая проверка всех сделок
и соблюдение закона о защите
персональных данных делают сделки безопасными для наших клиентов.</p>
</div>
<div className="services-info__item">
<p className="services-info__subtitle">3. Эффективность</p>
<p className="services-info__text font-inter-regular">Широкая база объектов недвижимости,
профессиональная продажа и подбор, собственные рекламные алгоритмы, и огромный опыт
в проведении сделок любой сложности позволяют нам гарантировать,
что вы получите максимальную выгоду от работы с нами.</p>
</div>
<div className="services-info__item">
<p className="services-info__subtitle">4. Выгодная процентная ставка по ипотеке</p>
<p className="services-info__text font-inter-regular">Мы постоянно развиваем
партнерские отношения с банками, за счет чего
имеем хорошую скидку для клиентов
и высокую степень одобрения заявок.</p>
</div>
</div>
<div className="services-info__desc">
<div className="services-info__item">
<p className="services-info__subtitle">5. Квалифицированные сотрудники</p>
<p className="services-info__text font-inter-regular">Специалисты по недвижимости
нашей компании проходят обучение и регулярную аттестацию, а также постоянно повышают свой
профессиональный уровень. Это обязательное условие для каждого из нас.
А значит, вы можете решить любой жилищный вопрос, воспользовавшись помощью
профессиональных риэлторов, юристов и специалистов по ипотечному кредитованию.</p>
</div>
<div className="services-info__item">
<p className="services-info__subtitle">6. Индивидуальный подход</p>
<p className="services-info__text font-inter-regular">Мы слышим и понимаем вас, делаем все,
чтобы в результате совместной работы задача, поставленная клиентом,
была решена, и он рекомендовал нас в дальнейшем.</p>
</div>
<div className="services-info__item">
<p className="services-info__subtitle">7. Гарантии</p>
<p className="services-info__text font-inter-regular">Мы даем своим клиентам гарантии
в юридической проверке сделок. </p>
</div>
<div className="services-info__item">
<p className="services-info__text">
<span className="services-info__accent">Хотите купить,
продать недвижимость или задать вопрос юристу, оставьте заявку наши специалисты
проконсультируют вас.</span>
</p>
</div>
</div>
</div>
</section>
<section className="services font-inter-bold">
<h3 className="services-list__title">Наши услуги</h3>
<div className="services__container">
<div className="services__list">
<ul className="services__list_left">
<li>продажа недвижимости</li>
<li>покупка недвижимости</li>
<li>ипотека</li>
<li>подбор объектов <span>недвижимости</span></li>
<li>помощь в оформлении <span>наследства</span></li>
<li>консультации по вопросам недвижимости</li>
<li>оформление приватизации</li>
</ul>
</div>
<div className="services__separator"></div>
<div className="services__list">
<ul className="services__list_right">
<li>юридическое сопровождение сделок</li>
<li>узаконивание перепланировок</li>
<li>оформление права собственности на дома и земельные участки</li>
<li>работа с жилищными сертификатами и субсидиями, в том числе материнским капиталом</li>
<li>составление (подготовка) юридической экспертизы на продаваемый/покупаемый
объект недвижимости</li>
</ul>
</div>
</div>
</section>
<Form scrolledThreshold={2700}/>
</>
);
<div className="services-info__item">
<p className="services-info__subtitle">
2. Работаем в соответствии с Законодательством РФ
</p>
<p className="services-info__text font-inter-regular">
Юридическая проверка всех сделок и соблюдение закона о защите
персональных данных делают сделки безопасными для наших
клиентов.
</p>
</div>
<div className="services-info__item">
<p className="services-info__subtitle">3. Эффективность</p>
<p className="services-info__text font-inter-regular">
Широкая база объектов недвижимости, профессиональная продажа и
подбор, собственные рекламные алгоритмы, и огромный опыт в
проведении сделок любой сложности позволяют нам гарантировать,
что вы получите максимальную выгоду от работы с нами.
</p>
</div>
<div className="services-info__item">
<p className="services-info__subtitle">
4. Выгодная процентная ставка по ипотеке
</p>
<p className="services-info__text font-inter-regular">
Мы постоянно развиваем партнерские отношения с банками, за счет
чего имеем хорошую скидку для клиентов и высокую степень
одобрения заявок.
</p>
</div>
</div>
<div className="services-info__desc">
<div className="services-info__item">
<p className="services-info__subtitle">
5. Квалифицированные сотрудники
</p>
<p className="services-info__text font-inter-regular">
Специалисты по недвижимости нашей компании проходят обучение и
регулярную аттестацию, а также постоянно повышают свой
профессиональный уровень. Это обязательное условие для каждого
из нас. А значит, вы можете решить любой жилищный вопрос,
воспользовавшись помощью профессиональных риэлторов, юристов и
специалистов по ипотечному кредитованию.
</p>
</div>
<div className="services-info__item">
<p className="services-info__subtitle">
6. Индивидуальный подход
</p>
<p className="services-info__text font-inter-regular">
Мы слышим и понимаем вас, делаем все, чтобы в результате
совместной работы задача, поставленная клиентом, была решена, и
он рекомендовал нас в дальнейшем.
</p>
</div>
<div className="services-info__item">
<p className="services-info__subtitle">7. Гарантии</p>
<p className="services-info__text font-inter-regular">
Мы даем своим клиентам гарантии в юридической проверке сделок.{" "}
</p>
</div>
<div className="services-info__item">
<p className="services-info__text">
<span className="services-info__accent">
Хотите купить, продать недвижимость или задать вопрос юристу,
оставьте заявку наши специалисты проконсультируют вас.
</span>
</p>
</div>
</div>
</div>
</section>
<section className="services font-inter-bold">
<h3 className="services-list__title">Наши услуги</h3>
<div className="services__container">
<div className="services__list">
<ul className="services__list_left">
<li>продажа недвижимости</li>
<li>покупка недвижимости</li>
<li>ипотека</li>
<li>
подбор объектов <span>недвижимости</span>
</li>
<li>
помощь в оформлении <span>наследства</span>
</li>
<li>консультации по вопросам недвижимости</li>
<li>оформление приватизации</li>
</ul>
</div>
<div className="services__separator"></div>
<div className="services__list">
<ul className="services__list_right">
<li>юридическое сопровождение сделок</li>
<li>узаконивание перепланировок</li>
<li>
оформление права собственности на дома и земельные участки
</li>
<li>
работа с жилищными сертификатами и субсидиями, в том числе
материнским капиталом
</li>
<li>
составление (подготовка) юридической экспертизы на
продаваемый/покупаемый объект недвижимости
</li>
</ul>
</div>
</div>
</section>
<Form scrolledThreshold={2700} />
</>
);
}
export { Services };