diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..e51d608 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,42 @@ +# Зависимости +node_modules +npm-debug.log +yarn-debug.log +yarn-error.log + +# Next.js +.next +out + +# Системные файлы +.DS_Store +*.pem + +# Отладка +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Локальные env файлы +.env*.local +.env + +# Vercel +.vercel + +# TypeScript +*.tsbuildinfo +next-env.d.ts + +# Git +.git +.gitignore + +# Docker +Dockerfile +docker-compose.yml +.dockerignore + +# IDE +.idea +.vscode diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ecbecfb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,41 @@ +# Используем Node.js как базовый образ +FROM node:20-alpine AS base + +# Устанавливаем зависимости для сборки +FROM base AS deps +WORKDIR /app +COPY package.json package-lock.json ./ +RUN npm install --legacy-peer-deps + +# Сборка приложения +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +RUN npm run build + +# Производственный образ +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV production + +# Создаем пользователя nextjs +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Копируем необходимые файлы +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +# Переключаемся на пользователя nextjs +USER nextjs + +# Открываем порт +EXPOSE 3000 + +ENV PORT 3000 +ENV HOSTNAME localhost + +CMD ["node", "server.js"] diff --git a/app/components/ContactForm.tsx b/app/components/ContactForm.tsx index 8e205a9..9d2a578 100644 --- a/app/components/ContactForm.tsx +++ b/app/components/ContactForm.tsx @@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { formatPhoneNumber, validatePhoneNumber } from '@/lib/utils'; import { sendTelegramNotification } from '@/lib/telegram'; +import { cn } from '@/lib/utils'; const ContactForm = () => { const [phone, setPhone] = useState(''); @@ -47,7 +48,7 @@ const ContactForm = () => { 'Произошла ошибка при отправке заявки. Пожалуйста, попробуйте позже.' ); } - } catch (error) { + } catch { setError( 'Произошла ошибка при отправке заявки. Пожалуйста, попробуйте позже.' ); @@ -184,7 +185,7 @@ const ContactForm = () => { placeholder="+7 (999) 999-99-99" value={phone} onChange={handlePhoneChange} - className="pl-10" + className={cn('pl-10', error && 'border-red-500')} required disabled={isLoading || isSubmitted} /> diff --git a/app/components/ContactModal.tsx b/app/components/ContactModal.tsx index d10fade..f7b3ab0 100644 --- a/app/components/ContactModal.tsx +++ b/app/components/ContactModal.tsx @@ -7,6 +7,7 @@ import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { formatPhoneNumber, validatePhoneNumber } from '@/lib/utils'; import { sendTelegramNotification } from '@/lib/telegram'; +import { cn } from '@/lib/utils'; interface ContactModalProps { isOpen: boolean; @@ -51,7 +52,7 @@ const ContactModal = ({ isOpen, onClose }: ContactModalProps) => { 'Произошла ошибка при отправке заявки. Пожалуйста, попробуйте позже.' ); } - } catch (error) { + } catch { setError( 'Произошла ошибка при отправке заявки. Пожалуйста, попробуйте позже.' ); @@ -124,7 +125,7 @@ const ContactModal = ({ isOpen, onClose }: ContactModalProps) => { placeholder="+7 (999) 999-99-99" value={phone} onChange={handlePhoneChange} - className="pl-10" + className={cn('pl-10', error && 'border-red-500')} required disabled={isLoading || isSubmitted} /> diff --git a/app/components/Contacts.tsx b/app/components/Contacts.tsx index 6099a42..2fc7e45 100644 --- a/app/components/Contacts.tsx +++ b/app/components/Contacts.tsx @@ -11,7 +11,6 @@ import { MessagesSquare, FileText, } from 'lucide-react'; -import { Button } from '@/components/ui/button'; const cityContacts = { Москва: { diff --git a/app/components/Hero.tsx b/app/components/Hero.tsx index 455884b..c5a9d70 100644 --- a/app/components/Hero.tsx +++ b/app/components/Hero.tsx @@ -8,6 +8,7 @@ import { Phone, CheckCircle2, AlertCircle } from 'lucide-react'; import { formatPhoneNumber, validatePhoneNumber } from '@/lib/utils'; import { sendTelegramNotification } from '@/lib/telegram'; import ContactModal from './ContactModal'; +import { cn } from '@/lib/utils'; const Hero = () => { const [phone, setPhone] = useState(''); @@ -47,7 +48,7 @@ const Hero = () => { 'Произошла ошибка при отправке заявки. Пожалуйста, попробуйте позже.' ); } - } catch (error) { + } catch { setError( 'Произошла ошибка при отправке заявки. Пожалуйста, попробуйте позже.' ); @@ -134,7 +135,10 @@ const Hero = () => { placeholder="+7 (999) 999-99-99" value={phone} onChange={handlePhoneChange} - className="pl-10 bg-white/10 border-white/20 text-white placeholder:text-blue-200 focus:border-white" + className={cn( + 'pl-10 bg-white/10 border-white/20 text-white placeholder:text-blue-200 focus:border-white', + error && 'border-red-300' + )} required disabled={isLoading || isSubmitted} /> diff --git a/app/components/WorkFlow.tsx b/app/components/WorkFlow.tsx index 2ebe3db..7a60a57 100644 --- a/app/components/WorkFlow.tsx +++ b/app/components/WorkFlow.tsx @@ -94,17 +94,6 @@ const WorkFlow = () => { }, }; - const lineVariants = { - hidden: { width: 0 }, - visible: { - width: '100%', - transition: { - duration: 0.8, - ease: 'easeInOut', - }, - }, - }; - return (
diff --git a/components/ui/input.tsx b/components/ui/input.tsx index 4c2e4bd..bbc8a67 100644 --- a/components/ui/input.tsx +++ b/components/ui/input.tsx @@ -2,24 +2,22 @@ import * as React from 'react'; import { cn } from '@/lib/utils'; -export interface InputProps - extends React.InputHTMLAttributes {} - -const Input = React.forwardRef( - ({ className, type, ...props }, ref) => { - return ( - - ); - } -); +const Input = React.forwardRef< + HTMLInputElement, + React.InputHTMLAttributes +>(({ className, type, ...props }, ref) => { + return ( + + ); +}); Input.displayName = 'Input'; export { Input }; diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d27def6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +version: '3.8' + +services: + web: + build: + context: . + dockerfile: Dockerfile + ports: + - '3000:3000' + restart: always + environment: + - NODE_ENV=production + healthcheck: + test: + [ + 'CMD', + 'wget', + '--no-verbose', + '--tries=1', + '--spider', + 'http://localhost:3000', + ] + interval: 30s + timeout: 10s + retries: 3 diff --git a/next.config.js b/next.config.js new file mode 100644 index 0000000..b408897 --- /dev/null +++ b/next.config.js @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + output: 'standalone', +}; + +module.exports = nextConfig; diff --git a/next.config.ts b/next.config.ts deleted file mode 100644 index e9ffa30..0000000 --- a/next.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - /* config options here */ -}; - -export default nextConfig; diff --git a/public/file.svg b/public/file.svg deleted file mode 100644 index 004145c..0000000 --- a/public/file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/globe.svg b/public/globe.svg deleted file mode 100644 index 567f17b..0000000 --- a/public/globe.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/images/certificates/nopriz.jpg b/public/images/certificates/nopriz.jpg new file mode 100644 index 0000000..8cb9a96 Binary files /dev/null and b/public/images/certificates/nopriz.jpg differ diff --git a/public/images/certificates/sro.jpg b/public/images/certificates/sro.jpg new file mode 100644 index 0000000..2d26fe4 Binary files /dev/null and b/public/images/certificates/sro.jpg differ diff --git a/public/images/office.jpg b/public/images/office.jpg new file mode 100644 index 0000000..ec94666 Binary files /dev/null and b/public/images/office.jpg differ diff --git a/public/next.svg b/public/next.svg deleted file mode 100644 index 5174b28..0000000 --- a/public/next.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg deleted file mode 100644 index 7705396..0000000 --- a/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/window.svg b/public/window.svg deleted file mode 100644 index b2b2a44..0000000 --- a/public/window.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file