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": { "node_modules/typescript": {
"version": "5.8.3", "version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"peer": true, "peer": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
}, },
"engines": { "engines": {
"node": ">=14.17" "node": ">=4.2.0"
} }
}, },
"node_modules/unbox-primitive": { "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 "./Footer.scss";
import { Link, useNavigate } from 'react-router-dom'; import { Link, useNavigate } from "react-router-dom";
import { CONTACTS } from "../../config/contacts";
function Footer() { function Footer() {
const navigate = useNavigate(); const navigate = useNavigate();
const handleClick = () => { const handleClick = () => {
window.scrollTo({ window.scrollTo({
top: 0, top: 0,
behavior: 'smooth' behavior: "smooth",
}); });
}; };
const handlePageChange = (path) => { const handlePageChange = (path) => {
handleClick(); handleClick();
navigate(path); navigate(path);
}; };
return ( return (
<footer className="footer"> <footer className="footer">
<Link to="/" className="footer__logo font-inter-regular" <Link
onClick={() => handlePageChange('/')}>OOO "ALMA-VID"</Link> to="/"
<div className="footer-info font-inter-bold"> className="footer__logo font-inter-regular"
<Link to="/objects" onClick={() => handlePageChange('/objects')}>Объекты</Link> onClick={() => handlePageChange("/")}
<Link to="/services" onClick={() => handlePageChange('/services')}>Услуги</Link> >
<Link to="/about" onClick={() => handlePageChange('/about')}>О компании</Link> OOO "ALMA-VID"
<Link to="/office" onClick={() => handlePageChange('/office')}>Контакты</Link> </Link>
</div> <div className="footer-info font-inter-bold">
<div className="footer-socials"> <Link to="/objects" onClick={() => handlePageChange("/objects")}>
<a className="footer-socials__tg" href="#"></a> Объекты
<a className="footer-socials__inst" href="#"></a> </Link>
<a className="footer-socials__vk" href="#"></a> <Link to="/services" onClick={() => handlePageChange("/services")}>
</div> Услуги
</footer> </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 }; export { Footer };

View File

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

View File

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

View File

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

View File

@@ -66,6 +66,55 @@
.item__image { .item__image {
border-top-right-radius: 15px; border-top-right-radius: 15px;
border-top-left-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 { .item__info {

View File

@@ -1,4 +1,4 @@
import React from 'react'; import React, { useState, useEffect } from 'react';
import Slider from 'react-slick'; import Slider from 'react-slick';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { useMediaQuery } from 'react-responsive'; import { useMediaQuery } from 'react-responsive';
@@ -7,6 +7,7 @@ import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css'; import 'slick-carousel/slick/slick-theme.css';
import './SliderObjects.scss'; import './SliderObjects.scss';
import { Object } from '../Object/Object'; import { Object } from '../Object/Object';
import { API_CONFIG } from '../../config/contacts';
import objectPicOne from '../../assets/images/apartaments/image-44.jpg'; import objectPicOne from '../../assets/images/apartaments/image-44.jpg';
import objectPicTwo from '../../assets/images/apartaments/image-45.jpg'; import objectPicTwo from '../../assets/images/apartaments/image-45.jpg';
@@ -25,10 +26,40 @@ const PrevArrow = ({ onClick }) => {
}; };
const SliderComponent = () => { const SliderComponent = () => {
const [objects, setObjects] = useState([]);
const [loading, setLoading] = useState(true);
const isMobileResolution = useMediaQuery({ maxWidth: 768 }); 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 = { const settings = {
dots: false, dots: objects.length > (isMobileResolution ? 1 : 3), // Показываем точки если объектов больше чем влезает
infinite: true, infinite: objects.length > (isMobileResolution ? 1 : 3), // Бесконечная прокрутка только если объектов достаточно
speed: 500, speed: 500,
slidesToShow: isMobileResolution ? 1 : 3, slidesToShow: isMobileResolution ? 1 : 3,
slidesToScroll: isMobileResolution ? 1 : 3, slidesToScroll: isMobileResolution ? 1 : 3,
@@ -37,46 +68,49 @@ const SliderComponent = () => {
prevArrow: <PrevArrow />, 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 ( return (
<div className="slider-objects"> <div className="slider-objects">
<Slider {...settings}> <Slider {...settings}>
<Link className="objects-link" to="/apartament"> {objects.map((object) => (
<Object <Link key={object.id} className="objects-link" to={`/apartament/${object.id}`}>
image={objectPicOne} <Object
price="1 234 567 ₽" image={object.photoUrl}
desc="1-комн. кв. 34 м" price={object.price}
address="Ул. Луначарского, Ленинский район" desc={object.title}
/></Link> address={object.address}
<Object />
image={objectPicTwo} </Link>
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="Ул. Солнечная, Заречный район"
/>
</Slider> </Slider>
</div> </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 "./About.scss";
import { Header } from '../../components/Header/Header'; import { Header } from "../../components/Header/Header";
import { Form } from '../../components/Form/Form'; import { Form } from "../../components/Form/Form";
import { SliderComponent } from '../../components/Sliders/Slider'; import { SliderComponent } from "../../components/Sliders/Slider";
import { CONTACTS } from "../../config/contacts";
function About() { function About() {
useEffect(() => { useEffect(() => {
document.title = 'Об Агентстве недвижимости АЛМА-ВИД'; document.title = `Об ${CONTACTS.companyName}`;
}, []); }, []);
return ( return (
<> <>
<div className="wrapper-about"> <div className="wrapper-about">
<Header /> <Header />
<section className="about"> <section className="about">
<div className="about-inner"> <div className="about-inner">
<div className="about__info font-inter-bold"> <div className="about__info font-inter-bold">
<p>Каждый из нас хоть раз сталкивается с квартирным вопросом - покупка, продажа, <p>
обмен квартиры или дома - эти процессы требуют серьезного профессионального подхода Каждый из нас хоть раз сталкивается с квартирным вопросом -
и юридической грамотности.</p> покупка, продажа, обмен квартиры или дома - эти процессы требуют
<p>Агентство недвижимости АЛМА-ВИД существует с 2000 года за этот период мы обрели серьезного профессионального подхода и юридической грамотности.
доверие и уважение наших многочисленных клиентов.</p> </p>
<p>Мы находимся в постоянном развитии и оттачиваем профессионализм наших сотрудников, <p>
обладая серьезной материальной базой и налаженными коммуникациями с крупными банками. Агентство недвижимости АЛМА-ВИД существует с 2000 года за этот
Благодаря этому мы имеем возможность предоставлять услуги период мы обрели доверие и уважение наших многочисленных
в сфере недвижимости высокого качества.</p> клиентов.
</div> </p>
</div> <p>
<div className="about__title font-inter-semibold">Об Агентстве недвижимости <span>АЛМА-Вид</span></div> Мы находимся в постоянном развитии и оттачиваем профессионализм
</section> наших сотрудников, обладая серьезной материальной базой и
налаженными коммуникациями с крупными банками. Благодаря этому
мы имеем возможность предоставлять услуги в сфере недвижимости
высокого качества.
</p>
</div> </div>
<section className="certificates"> </div>
<SliderComponent/> <div className="about__title font-inter-semibold">
</section> Об {CONTACTS.companyName} <span>{CONTACTS.companyNameShort}</span>
<Form scrolledThreshold={1650}/> </div>
</> </section>
); </div>
<section className="certificates">
<SliderComponent />
</section>
<Form scrolledThreshold={1650} />
</>
);
} }
export { About }; export { About };

View File

@@ -1,123 +1,326 @@
import { useEffect } from 'react'; import { useEffect, useState } from "react";
import './Apartament.scss'; import "./Apartament.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 { Header } from "../../components/Header/Header";
import { Form } from '../../components/Form/Form'; import { Form } from "../../components/Form/Form";
import { Gallery } from '../../components/Gallery/Gallery'; import { Gallery } from "../../components/Gallery/Gallery";
import { CONTACTS } from "../../config/contacts";
function Apartament() { function Apartament() {
useEffect(() => { const [isMapActive, setIsMapActive] = useState(false);
document.title = 'Апартаменты';
}, []);
return ( useEffect(() => {
<> document.title = "Апартаменты";
<Header /> }, []);
<section className="apartament">
<h2 className="apartament__title font-inter-bold">1-комн. кв. 34 м</h2> const handleActivateMap = () => {
<p className="apartament__para font-inter-regular">Ул. Луначарского, Ленинский район</p> setIsMapActive(true);
<div className="apartament__container"> if (window.apartamentMap) {
<div className="apartament__info"> window.apartamentMap.behaviors.enable("scrollZoom");
<Gallery/> window.apartamentMap.behaviors.enable("drag");
<div className="apartament__icons icons"> }
<div className="icons__item"> };
<div className="icons__pic icons__pic_area"></div>
<div className="icons__info"> const handleDeactivateMap = () => {
<p className="icons__desc font-inter-regular ">Общая площадь</p> setIsMapActive(false);
<p className="icons__num font-inter-semibold">72М</p> if (window.apartamentMap) {
</div> window.apartamentMap.behaviors.disable("scrollZoom");
</div> window.apartamentMap.behaviors.disable("drag");
<div className="icons__item"> }
<div className="icons__pic icons__pic_living"></div> };
<div className="icons__info">
<p className="icons__desc font-inter-regular ">Жилая площадь</p> return (
<p className="icons__num font-inter-semibold">68М</p> <>
</div> <Header />
</div> <section className="apartament">
<div className="icons__item"> <h2 className="apartament__title font-inter-bold">1-комн. кв. 34 м</h2>
<div className="icons__pic icons__pic_kitchen"></div> <p className="apartament__para font-inter-regular">
<div className="icons__info"> Ул. Луначарского, Ленинский район
<p className="icons__desc font-inter-regular ">Площадь кухни</p> </p>
<p className="icons__num font-inter-semibold">11М</p> <div className="apartament__container">
</div> <div className="apartament__info">
</div> <Gallery />
<div className="icons__item"> <div className="apartament__icons icons">
<div className="icons__pic icons__pic_year"></div> <div className="icons__item">
<div className="icons__info"> <div className="icons__pic icons__pic_area"></div>
<p className="icons__desc font-inter-regular ">Год постройки</p> <div className="icons__info">
<p className="icons__num font-inter-semibold">2003</p> <p className="icons__desc font-inter-regular ">
</div> Общая площадь
</div> </p>
<div className="icons__item"> <p className="icons__num font-inter-semibold">72М</p>
<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>
<YMaps> </div>
<Map className="map-apartament" defaultState={{ center: [55.16, 61.4], zoom: 15 }} /> <div className="icons__item">
</YMaps> <div className="icons__pic icons__pic_living"></div>
</section> <div className="icons__info">
<Form scrolledThreshold={2350}/> <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 }; export { Apartament };

View File

@@ -1,16 +1,35 @@
import { useEffect } from "react"; import { useEffect, useState } from "react";
import "./Home.scss"; 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 { Header } from "../../components/Header/Header";
import { Form } from "../../components/Form/Form"; import { Form } from "../../components/Form/Form";
import lawyer from "../../assets/images/lawyer/Mask-group.svg"; import lawyer from "../../assets/images/lawyer/Mask-group.svg";
import { CONTACTS } from "../../config/contacts";
function Home() { function Home() {
const [isMapActive, setIsMapActive] = useState(false);
useEffect(() => { 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 ( return (
<> <>
<div className="wrapper"> <div className="wrapper">
@@ -90,8 +109,118 @@ function Home() {
<YMaps> <YMaps>
<Map <Map
className="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> </YMaps>
</div> </div>
<Form scrolledThreshold={2750} /> <Form scrolledThreshold={2750} />

View File

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

View File

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

View File

@@ -1,76 +1,235 @@
import { useEffect } from 'react'; import { useEffect, useState } from "react";
import './Office.scss'; import "./Office.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 { Header } from "../../components/Header/Header";
import { CONTACTS } from "../../config/contacts";
function Office() { function Office() {
useEffect(() => { const [isMapActive, setIsMapActive] = useState(false);
document.title = 'Контакты Агентства недвижимости АЛМА-ВИД';
}, []); useEffect(() => {
document.title = `Контакты ${CONTACTS.companyName}`;
return ( }, []);
<>
<div className="wrapper-office"> const handleActivateMap = () => {
<Header /> setIsMapActive(true);
<section className="office"> if (window.officeMap) {
<div className="office__title font-inter-semibold">АЛМАВИД<span>агентство недвижимости</span></div> window.officeMap.behaviors.enable("scrollZoom");
<div className="office__separator"></div> window.officeMap.behaviors.enable("drag");
<div className="office-inner"> }
<div className="office-container"> };
<div className="office__item">
<div className="office__pic office__pic_purchase"></div> const handleDeactivateMap = () => {
<div className="office__text"> setIsMapActive(false);
<p className="office__desc font-inter-bold">Покупка, продажа, if (window.officeMap) {
<span>обмен квартир и комнат</span></p> window.officeMap.behaviors.disable("scrollZoom");
</div> window.officeMap.behaviors.disable("drag");
</div> }
<div className="office__item"> };
<div className="office__pic office__pic_rent"></div>
<div className="office__text"> return (
<p className="office__desc font-inter-bold">Аренда квартир <>
<span>и комнат</span></p> <div className="wrapper-office">
</div> <Header />
</div> <section className="office">
<div className="office__item"> <div className="office__title font-inter-semibold">
<div className="office__pic office__pic_buildings"></div> {CONTACTS.companyNameShort}ВИД<span>агентство недвижимости</span>
<div className="office__text"> </div>
<p className="office__desc font-inter-bold">Новостройки</p> <div className="office__separator"></div>
</div> <div className="office-inner">
</div> <div className="office-container">
<div className="office__item"> <div className="office__item">
<div className="office__pic office__pic_country"></div> <div className="office__pic office__pic_purchase"></div>
<div className="office__text"> <div className="office__text">
<p className="office__desc font-inter-bold">Загородная <p className="office__desc font-inter-bold">
<span>недвижимость</span></p> Покупка, продажа,
</div> <span>обмен квартир и комнат</span>
</div> </p>
<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>
</div> </div>
<YMaps> </div>
<Map className="map-office" defaultState={{ center: [55.16, 61.4], zoom: 12 }} /> <div className="office__item">
</YMaps> <div className="office__pic office__pic_rent"></div>
</section> <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 }; export { Office };

View File

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