From 4b22d1efb74633a754e614aed7ecb87daf9deeb0 Mon Sep 17 00:00:00 2001
From: vladisluw <54843319+seelentov@users.noreply.github.com>
Date: Mon, 6 May 2024 13:07:14 +0500
Subject: [PATCH] upd
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Форма заявки
- Подключение к тг каналу для получения заявок
- Небольшие правки дизайна
---
package-lock.json | 91 ++++++++++++++++++
package.json | 1 +
src/app/contacts/page.tsx | 4 +-
src/app/page.tsx | 2 +
src/components/Banner/Banner.module.scss | 13 ++-
src/components/Call/Call.tsx | 21 ++++-
.../Catalog/CatalogTab/CatalogTab.module.scss | 6 ++
src/components/FAQ/FAQ.module.scss | 4 +
src/components/Form/Form.module.scss | 29 ++++++
src/components/Form/Form.tsx | 65 +++++++++++++
src/components/Header/DesktopNav.tsx | 2 +-
src/components/Header/Header.tsx | 12 +--
src/components/Header/Socials.tsx | 27 ++++++
.../ModalForm/ModalForm.module.scss | 15 +++
src/components/ModalForm/ModalForm.tsx | 54 +++++++++++
src/components/Stages/Stages.module.scss | 7 ++
src/components/UI/Input/Input.tsx | 12 +++
src/core/api/baseFetch.ts | 5 +-
src/core/api/getSerializedServices.ts | 3 +
src/core/api/getServiceLinks.ts | 4 +-
src/core/api/sendtelegramMessage.ts | 31 +++++++
src/core/config/api.config.ts | 4 +-
src/core/utils/forms/isEveryInFormNotEmpty.ts | 5 +
src/style/modules/globals.scss | 3 +
src/style/modules/layout.scss | 3 +-
todolist.txt | 92 -------------------
26 files changed, 398 insertions(+), 117 deletions(-)
create mode 100644 src/components/Form/Form.module.scss
create mode 100644 src/components/Form/Form.tsx
create mode 100644 src/components/Header/Socials.tsx
create mode 100644 src/components/ModalForm/ModalForm.module.scss
create mode 100644 src/components/ModalForm/ModalForm.tsx
create mode 100644 src/components/UI/Input/Input.tsx
create mode 100644 src/core/api/sendtelegramMessage.ts
create mode 100644 src/core/utils/forms/isEveryInFormNotEmpty.ts
delete mode 100644 todolist.txt
diff --git a/package-lock.json b/package-lock.json
index 37de858..40e3525 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"name": "pixel-perfect-langing",
"version": "0.1.0",
"dependencies": {
+ "axios": "^1.6.8",
"classnames": "^2.5.1",
"hamburger-react": "^2.5.0",
"next": "14.1.0",
@@ -1271,6 +1272,11 @@
"has-symbols": "^1.0.3"
}
},
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz",
@@ -1292,6 +1298,16 @@
"node": ">=4"
}
},
+ "node_modules/axios": {
+ "version": "1.6.8",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz",
+ "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==",
+ "dependencies": {
+ "follow-redirects": "^1.15.6",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
"node_modules/axobject-query": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
@@ -1490,6 +1506,17 @@
"simple-swizzle": "^0.2.2"
}
},
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -1582,6 +1609,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
@@ -2320,6 +2355,25 @@
"integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==",
"dev": true
},
+ "node_modules/follow-redirects": {
+ "version": "1.15.6",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
+ "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
"node_modules/for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
@@ -2345,6 +2399,19 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -3281,6 +3348,25 @@
"node": ">=8.6"
}
},
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
@@ -3739,6 +3825,11 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
diff --git a/package.json b/package.json
index 5f1f0c1..2897d47 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"export": "next export"
},
"dependencies": {
+ "axios": "^1.6.8",
"classnames": "^2.5.1",
"hamburger-react": "^2.5.0",
"next": "14.1.0",
diff --git a/src/app/contacts/page.tsx b/src/app/contacts/page.tsx
index b899f2f..66e5688 100644
--- a/src/app/contacts/page.tsx
+++ b/src/app/contacts/page.tsx
@@ -4,6 +4,7 @@ import { INFO } from "@/core/config/info.config";
import { Metadata } from "next";
import Image from 'next/image';
import styles from './page.module.scss';
+import { Form } from "@/components/Form/Form";
export const metadata: Metadata = {
@@ -45,6 +46,7 @@ export default async function Contacts() {
{INFO.PHONE}
ИНН: 745108164223
+
-
+
);
}
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 46cd46f..12be276 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -3,6 +3,7 @@ import { Banner } from "@/components/Banner/Banner";
import { Call } from "@/components/Call/Call";
import { Catalog } from "@/components/Catalog/Catalog";
import { FAQ } from "@/components/FAQ/FAQ";
+import { ModalForm } from "@/components/ModalForm/ModalForm";
import { Portfolio } from "@/components/Portfolio/Portfolio";
import { Stages } from "@/components/Stages/Stages";
import { baseFetch } from "@/core/api/baseFetch";
@@ -65,6 +66,7 @@ export default async function HomePage() {
{faqData && }
+
>
);
}
diff --git a/src/components/Banner/Banner.module.scss b/src/components/Banner/Banner.module.scss
index e22ae10..a27d466 100644
--- a/src/components/Banner/Banner.module.scss
+++ b/src/components/Banner/Banner.module.scss
@@ -62,9 +62,9 @@
}
p {
- max-height: 130px;
- height: 130px;
- min-height: 130px;
+ max-height: 126px;
+ height: 126px;
+ min-height: 126px;
}
@media (min-width: 1024px) {
@@ -78,6 +78,7 @@
p {
+
font-size: 18px;
}
}
@@ -99,7 +100,11 @@
h1,
p {
padding: 0 15px;
-
+ overflow: hidden;
+ text-overflow: ellipsis;
+ display: -webkit-box;
+ -webkit-line-clamp: 6;
+ -webkit-box-orient: vertical;
}
max-width: none !important;
diff --git a/src/components/Call/Call.tsx b/src/components/Call/Call.tsx
index ca59b32..abec5aa 100644
--- a/src/components/Call/Call.tsx
+++ b/src/components/Call/Call.tsx
@@ -1,15 +1,18 @@
'use client'
-import { FC } from 'react';
+import { FC, useState } from 'react';
import { YMClick } from '../YM/YMClick';
import styles from './Call.module.scss';
import { links } from './call.config';
+import { ModalForm } from '../ModalForm/ModalForm';
+import { Form } from '../Form/Form';
export interface ICallProps {
padding?: 'top' | 'bottom' | 'both' | 'none'
+ type?: 'default' | 'w/out-form'
}
-export const Call: FC = ({ padding = 'both' }) => {
+export const Call: FC = ({ padding = 'both', type = 'default' }) => {
const paddingProp = {
paddingTop: padding === 'top' || padding === 'both' ? '60px' : '0px',
@@ -20,7 +23,19 @@ export const Call: FC = ({ padding = 'both' }) => {
- {links.map((link, index) =>
)}
+ {
+ type === 'default' ?
+ <>
+ {links.slice(0, links.length - 1).map((link, index) =>
)}
+
+
+
+
+ > :
+ links.map((link, index) =>
)
+ }
+ { }
+
);
diff --git a/src/components/Catalog/CatalogTab/CatalogTab.module.scss b/src/components/Catalog/CatalogTab/CatalogTab.module.scss
index 9ed0a42..d7a86f8 100644
--- a/src/components/Catalog/CatalogTab/CatalogTab.module.scss
+++ b/src/components/Catalog/CatalogTab/CatalogTab.module.scss
@@ -1,4 +1,10 @@
.main{
+ *{
+ box-sizing: content-box;
+
+ }
+ box-sizing: content-box;
+
max-height: 340px;
overflow-y: scroll;
display: flex;
diff --git a/src/components/FAQ/FAQ.module.scss b/src/components/FAQ/FAQ.module.scss
index 0a5b9c5..cb6f018 100644
--- a/src/components/FAQ/FAQ.module.scss
+++ b/src/components/FAQ/FAQ.module.scss
@@ -9,7 +9,11 @@
.wrapper {
display: flex;
justify-content: space-between;
+ *{
+ box-sizing: content-box;
+ }
+ box-sizing: content-box;
@media (max-width: 1023px) {
align-items: center;
diff --git a/src/components/Form/Form.module.scss b/src/components/Form/Form.module.scss
new file mode 100644
index 0000000..103bc19
--- /dev/null
+++ b/src/components/Form/Form.module.scss
@@ -0,0 +1,29 @@
+.form{
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+
+
+
+ h2{
+ margin-bottom: 0;
+ }
+
+ p{
+ margin-bottom: 10px;
+ font-size: 12px;
+ }
+
+ input{
+ border: 2px solid black;
+ width: 300px;
+ padding: 10px;
+ }
+}
+
+.default{
+ align-items: center;
+ padding: 20px;
+ background-color: white;
+ width: 375px;
+}
\ No newline at end of file
diff --git a/src/components/Form/Form.tsx b/src/components/Form/Form.tsx
new file mode 100644
index 0000000..3bf3644
--- /dev/null
+++ b/src/components/Form/Form.tsx
@@ -0,0 +1,65 @@
+'use client'
+
+import styles from './Form.module.scss'
+import { sendTelegramMessage } from '@/core/api/sendtelegramMessage';
+import { Button } from '../UI/Button/Button';
+import { useState } from 'react';
+import { usePathname } from 'next/navigation';
+import cn from 'classnames';
+interface IFormProps {
+ type?: 'min' | 'default'
+}
+
+export const Form = ({ type = 'default' }) => {
+
+ const pathname = usePathname()
+
+
+ const [formData, setFormData] = useState({
+ name: '',
+ tel: '',
+ });
+
+ const handleChange = (e: any) => {
+ setFormData({ ...formData, [e.target.name]: e.target.value });
+ };
+
+ const handleSubmit = async (e: any) => {
+ e.preventDefault();
+
+ const isSended = await sendTelegramMessage(formData, pathname)
+ if (isSended) {
+ setFormData({
+ name: '',
+ tel: '',
+ })
+ }
+ };
+
+ return (
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/Header/DesktopNav.tsx b/src/components/Header/DesktopNav.tsx
index 091c30e..84005e5 100644
--- a/src/components/Header/DesktopNav.tsx
+++ b/src/components/Header/DesktopNav.tsx
@@ -26,7 +26,7 @@ export const DesktopNav = ({serviceLinks}:{serviceLinks: MenuLink[]}) => {
{
sublist?.map(({ id, href, name }) =>
- {name}
+ {name}
)
}
diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx
index fbd620b..598dd69 100644
--- a/src/components/Header/Header.tsx
+++ b/src/components/Header/Header.tsx
@@ -1,12 +1,9 @@
import { getServiceLinks } from '@/core/api/getServiceLinks';
-import { INFO } from '@/core/config/info.config';
-import { FC } from 'react';
-import { RiPhoneFill, RiTelegramFill, RiWhatsappFill } from "react-icons/ri";
+import { FC, useState } from 'react';
import { DesktopNav } from './DesktopNav';
import styles from './Header.module.scss';
import { MobileNav } from './MobileNav';
-import { YMClick } from '../YM/YMClick';
-import { social_links } from './header.config';
+import { Socials } from './Socials';
export interface IHeaderProps {
@@ -17,6 +14,7 @@ export const Header: FC = async () => {
const serviceLinks = await getServiceLinks()
+
return (
@@ -25,9 +23,7 @@ export const Header: FC = async () => {
-
- {social_links.map((link, index) => )}
-
+
diff --git a/src/components/Header/Socials.tsx b/src/components/Header/Socials.tsx
new file mode 100644
index 0000000..fc64dee
--- /dev/null
+++ b/src/components/Header/Socials.tsx
@@ -0,0 +1,27 @@
+'use client'
+
+import { FC, useState } from 'react';
+import styles from './Header.module.scss';
+import { YMClick } from '../YM/YMClick';
+import { social_links } from './header.config';
+import { ModalForm } from '../ModalForm/ModalForm';
+
+export interface IHeaderProps {
+
+}
+
+export const Socials: FC = () => {
+
+
+ return (
+ <>
+
+ {social_links.map((link, index) => )}
+
+ >
+ );
+}
+
+
+
+
diff --git a/src/components/ModalForm/ModalForm.module.scss b/src/components/ModalForm/ModalForm.module.scss
new file mode 100644
index 0000000..172d4a6
--- /dev/null
+++ b/src/components/ModalForm/ModalForm.module.scss
@@ -0,0 +1,15 @@
+.wrapper{
+ position: fixed;
+ height: 100vh;
+ width: 100%;
+ background: #0000004f;
+ display: none;
+ justify-content: center;
+ align-items: center;
+ z-index: 10000;
+}
+
+
+.open{
+ display: flex !important;
+}
\ No newline at end of file
diff --git a/src/components/ModalForm/ModalForm.tsx b/src/components/ModalForm/ModalForm.tsx
new file mode 100644
index 0000000..e3023b2
--- /dev/null
+++ b/src/components/ModalForm/ModalForm.tsx
@@ -0,0 +1,54 @@
+'use client'
+
+import { Dispatch, FC, SetStateAction, useEffect, useState } from 'react';
+import styles from './ModalForm.module.scss';
+import { usePathname } from 'next/navigation';
+import cn from 'classnames';
+import { Form } from '../Form/Form';
+
+
+export interface IModalFormProps {
+}
+
+export const ModalForm: FC = () => {
+
+
+ const [isOpen, setIsOpen] = useState(false)
+
+ useEffect(() => {
+ setTimeout(() => {
+ setIsOpen(true)
+ const html = document.querySelector('html');
+ if (html) {
+ html.style.overflow = 'visible'
+ }
+ }, 10000)
+ }, [])
+
+
+
+ useEffect(() => {
+ const handleDocumentClick = (e: any) => {
+ if (!e.target.closest(`.${styles.form}`)) {
+ setIsOpen(false);
+ const html = document.querySelector('html');
+ if (html) {
+ html.style.overflow = 'scroll'
+ }
+
+ }
+ };
+
+ document.addEventListener('click', handleDocumentClick);
+
+ return () => {
+ document.removeEventListener('click', handleDocumentClick);
+ };
+ }, []);
+
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/components/Stages/Stages.module.scss b/src/components/Stages/Stages.module.scss
index a1c2b74..5b276f0 100644
--- a/src/components/Stages/Stages.module.scss
+++ b/src/components/Stages/Stages.module.scss
@@ -4,6 +4,7 @@
@media (max-width: 1023px) {
padding: 60px 0;
}
+
}
.list {
@@ -45,6 +46,12 @@
}
.item {
+*{
+ box-sizing: content-box;
+
+ }
+ box-sizing: content-box;
+
position: relative;
diff --git a/src/components/UI/Input/Input.tsx b/src/components/UI/Input/Input.tsx
new file mode 100644
index 0000000..2ca203a
--- /dev/null
+++ b/src/components/UI/Input/Input.tsx
@@ -0,0 +1,12 @@
+import { FC, HTMLAttributes } from 'react';
+import styles from './Input.module.scss';
+
+export interface IInputProps extends HTMLAttributes {
+
+}
+
+export const Input: FC = ({ children, ...rest }) => {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/src/core/api/baseFetch.ts b/src/core/api/baseFetch.ts
index 8b88512..a20246d 100644
--- a/src/core/api/baseFetch.ts
+++ b/src/core/api/baseFetch.ts
@@ -21,11 +21,8 @@ export const baseFetch = async (url: string, single: boolean = false, cache: boo
try {
- const res = await fetch(API_URL + url, options)
-
+ const res = await fetch(API_URL + url)
const data = await res.json()
-
-
serializedData = apiDataSerializer(data)
if (single) {
diff --git a/src/core/api/getSerializedServices.ts b/src/core/api/getSerializedServices.ts
index 5d08bab..3fef512 100644
--- a/src/core/api/getSerializedServices.ts
+++ b/src/core/api/getSerializedServices.ts
@@ -5,8 +5,11 @@ import { getItemsByFilter } from "@/core/api/getItemsByFilter";
export const getSerializedServices = async () => {
const categories = await baseFetch('/api/categories');
+
const categoriesKeys = categories.map((item: any) => item.header);
+
+
let promises = categoriesKeys.map(async (category: string) => {
const data = await getItemsByFilter('services', ['category', 'header'], category, [['populate','icon']]);
return [category, data];
diff --git a/src/core/api/getServiceLinks.ts b/src/core/api/getServiceLinks.ts
index 9851c43..811843f 100644
--- a/src/core/api/getServiceLinks.ts
+++ b/src/core/api/getServiceLinks.ts
@@ -3,13 +3,13 @@ import { getItemsByFilter } from "./getItemsByFilter";
export const getServiceLinks = async () => {
const categories: ICategory[] = await baseFetch('/api/categories');
-
+
const promises = categories.map(async ({ href: mainHref, id, header }) => {
const services: IService[] = await getItemsByFilter('services', ['category', 'header'], header, [['populate','icon']]);
const mappedServices = services.map(({ id, href, header }) => ({
id: id,
- href: href,
+ href: mainHref + '/' + href,
name: header,
}));
diff --git a/src/core/api/sendtelegramMessage.ts b/src/core/api/sendtelegramMessage.ts
new file mode 100644
index 0000000..832847b
--- /dev/null
+++ b/src/core/api/sendtelegramMessage.ts
@@ -0,0 +1,31 @@
+import axios from "axios";
+import { TELEGRAM_API_KEY, TELEGRAM_CHAT_ID } from "../config/api.config";
+import { isEveryInFormNotEmpty } from "../utils/forms/isEveryInFormNotEmpty";
+
+export const sendTelegramMessage = async (formData: any, pathname: string) => {
+ if(!isEveryInFormNotEmpty(formData)){
+ alert('Заполните все данные формы');
+ return
+ }
+
+ try {
+ const response = await axios.post(
+ `https://api.telegram.org/bot${TELEGRAM_API_KEY}/sendMessage`,
+ {
+ chat_id: TELEGRAM_CHAT_ID,
+ text: `Новая заявка:\n\n${Object.entries(formData).map(input => `${input[0]}: ${input[1]}`).join('\n')}\n\nСтраница: ${pathname}`,
+ parse_mode: 'Markdown',
+ }
+ );
+
+ if (response.status === 200) {
+ alert('Заявка успешно отправлена!');
+ return true
+ } else {
+ alert('Не удалось отправить заявку. Пожалуйста, попробуйте позже');
+ }
+ } catch (error) {
+ console.error(error);
+ alert('Не удалось отправить заявку. Пожалуйста, попробуйте позже');
+ }
+ };
\ No newline at end of file
diff --git a/src/core/config/api.config.ts b/src/core/config/api.config.ts
index 4de487c..9dccd04 100644
--- a/src/core/config/api.config.ts
+++ b/src/core/config/api.config.ts
@@ -1,2 +1,4 @@
export const API_URL = process.env.API_URL || 'https://pixellperfect.ru'
-export const API_TOKEN = process.env.API_TOKEN
\ No newline at end of file
+export const API_TOKEN = process.env.API_TOKEN
+export const TELEGRAM_API_KEY = "6454568318:AAFIqVdc_oB71z24yogZOpY5fSUmmLh_q5o";
+export const TELEGRAM_CHAT_ID = 816233444;
\ No newline at end of file
diff --git a/src/core/utils/forms/isEveryInFormNotEmpty.ts b/src/core/utils/forms/isEveryInFormNotEmpty.ts
new file mode 100644
index 0000000..82919cb
--- /dev/null
+++ b/src/core/utils/forms/isEveryInFormNotEmpty.ts
@@ -0,0 +1,5 @@
+export const isEveryInFormNotEmpty = (formData: {[key: string]: string}) => {
+ const result = Object.values(formData).every(input => input.length > 0)
+ console.log(result)
+ return result
+}
\ No newline at end of file
diff --git a/src/style/modules/globals.scss b/src/style/modules/globals.scss
index fdcb16f..c6014df 100644
--- a/src/style/modules/globals.scss
+++ b/src/style/modules/globals.scss
@@ -151,6 +151,9 @@ input[type="reset"] {
html {
+ *{
+ box-sizing: border-box;
+ }
font-size: 18px;
&::-webkit-scrollbar {
diff --git a/src/style/modules/layout.scss b/src/style/modules/layout.scss
index 3709404..d824133 100644
--- a/src/style/modules/layout.scss
+++ b/src/style/modules/layout.scss
@@ -2,7 +2,7 @@
.container {
max-width: 1449px;
margin: 0 auto;
-
+ width: 100%;
@media(max-width:1460px) {
max-width: 1200px;
}
@@ -18,6 +18,7 @@
@media(max-width:767px) {
max-width: none !important;
padding: 0 15px;
+ width: 100%;
}
}
diff --git a/todolist.txt b/todolist.txt
deleted file mode 100644
index 4b28a2c..0000000
--- a/todolist.txt
+++ /dev/null
@@ -1,92 +0,0 @@
-Первый блок, половину ноутбука на мобилке (слева), реализация на бумаге
-
-Примеры работ под баннерами
-
-Выделение текста на сайте
-
-Layout:
-- header ++++++++
-- burger ++++++++
-- footer ++++++++
-
-Верстка:
- Структура главной:
-
-- Баннер (уник) ++++++++
-- Преимущества ++++++++
-- Каталог услуг (уник) ++++++++
-- Примеры работ
-- Этапы заказа (уник) ++++++++
-- СТА ++++++
-- FAQ (уник) ++++++++
-- Статьи и новости -------
-- Отзывы -------
-
- Структура услуги:
-- Баннер (Заголовок, текст, стоимость, демка) +++++
-- Текст +++++
-- Примеры работ
-- Текст +++++
-- Отзывы -------
-- СТА ++++++
-
-(листинг):
-- Листинг (column) ++++++
-- Текст ++++++
-- СТА ++++++
-
- Структура примеры работ(листинг):
-- Листинг (column) ++++++
-- Текст -----
-- СТА ++++++
-
-
- Структура статьи: --------------
-- Заголовок
-- 1 изображение
-- Текст
-- 2 изображение
-- Текст
-- Листинг статей (- статья страницы)
-
-(листинг): --------------
-- Листинг (column)
-
-БД:
-- Создание API ++++++++
-- Моделирование ++++++++
-- Создание endpoints на получение каждого из одноблочного контента** ------
-- Создание endpoints на получение категорий товаров и услуг c
-
-Контент:
-- Баннер ++++++++
-- Преимущества
-- Каталог услуг
-- Примеры работ ++++++++
-- FAQ ++++++++
-- Статьи и новости ---------
-- Этапы заказа ++++++++
-- Отзывы -----------
-
-Тестинг:
-- Семантика (мета, теги)
-- Кроссбраузерность
-- Производительность ++++++++
-
-SEO:
-- Мета ++++++++
-- openGraph ++++++++
-- schema.org --------
-
-Публикация на хост:
-- Приобретение хостинга и домена ++++
-- Деплой ++++
-- Тест адаптива мобильной версии ++++
-- Роботы ++++
-- sitemap ++++
-- Яндекс.Вебмастер / Google Console + тесты
-
-Директ:
-- Создание рекламных стратегий по каждой услуге
-- Создание рекламной стратегии на главную
-- Пополнение
\ No newline at end of file