forgot password fix
This commit is contained in:
parent
88f20bbb3b
commit
800a2d3bdd
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,4 +9,5 @@ frontend/.vite
|
|||||||
node_modules
|
node_modules
|
||||||
pestgres_data/
|
pestgres_data/
|
||||||
redis_data/
|
redis_data/
|
||||||
|
frontend-rewrite
|
||||||
aisugestions.md
|
aisugestions.md
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
export const corsConfig = {
|
export const corsConfig = {
|
||||||
origin: [
|
origin: [
|
||||||
"http://localhost:5173",
|
"http://localhost:5173",
|
||||||
|
"http://localhost:4444",
|
||||||
|
"http://localhost:3000",
|
||||||
"https://www.placebo.mk",
|
"https://www.placebo.mk",
|
||||||
"https://placebo.mk",
|
"https://placebo.mk",
|
||||||
"https://imkapi.oblak.solutions",
|
"https://imkapi.oblak.solutions",
|
||||||
|
|||||||
@ -227,8 +227,9 @@ export class EmailService {
|
|||||||
|
|
||||||
async sendPasswordResetEmail(email: string, name: string, token: string) {
|
async sendPasswordResetEmail(email: string, name: string, token: string) {
|
||||||
this.logger.log("Sending password reset email to:", email);
|
this.logger.log("Sending password reset email to:", email);
|
||||||
|
const frontendUrl =
|
||||||
const resetLink = `${process.env.FRONTEND_URL}/reset-password?token=${token}`;
|
this.configService.get<string>("FRONTEND_URL") || "https://placebo.mk";
|
||||||
|
const resetLink = `${frontendUrl}/reset-password?token=${token}`;
|
||||||
const mailOptions = {
|
const mailOptions = {
|
||||||
from: this.from,
|
from: this.from,
|
||||||
to: email,
|
to: email,
|
||||||
|
|||||||
@ -1,31 +1,35 @@
|
|||||||
# Stop everything
|
# Stop everything
|
||||||
|
|
||||||
docker-compose down
|
docker-compose down
|
||||||
|
|
||||||
# Remove all containers
|
# Remove all containers
|
||||||
|
|
||||||
docker rm -f $(docker ps -a -q)
|
docker rm -f $(docker ps -a -q)
|
||||||
|
|
||||||
# Remove all volumes
|
# Remove all volumes
|
||||||
|
|
||||||
docker volume rm $(docker volume ls -q)
|
docker volume rm $(docker volume ls -q)
|
||||||
|
|
||||||
# Remove all images
|
# Remove all images
|
||||||
|
|
||||||
docker rmi -f $(docker images -q)
|
docker rmi -f $(docker images -q)
|
||||||
|
|
||||||
# Start fresh
|
# Start fresh
|
||||||
|
|
||||||
docker-compose up --build
|
docker-compose up --build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# reset development
|
# reset development
|
||||||
|
|
||||||
# Stop containers and remove volumes
|
# Stop containers and remove volumes
|
||||||
|
|
||||||
docker-compose -f docker-compose.dev.yml down -v
|
docker-compose -f docker-compose.dev.yml down -v
|
||||||
|
|
||||||
# Remove existing images
|
# Remove existing images
|
||||||
|
|
||||||
docker rmi $(docker images -q backend_backend)
|
docker rmi $(docker images -q backend_backend)
|
||||||
|
|
||||||
# Rebuild and start
|
# Rebuild and start
|
||||||
|
|
||||||
docker-compose -f docker-compose.dev.yml up --build
|
docker-compose -f docker-compose.dev.yml up --build
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
docker-compose -f docker-compose.dev.yml up --build --force-recreate
|
docker-compose -f docker-compose.dev.yml up --build --force-recreate
|
||||||
|
|||||||
BIN
frontend/public/Sertifikat za akreditacija IMK.png
Normal file
BIN
frontend/public/Sertifikat za akreditacija IMK.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 MiB |
BIN
frontend/public/resenie_imk.png
Normal file
BIN
frontend/public/resenie_imk.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 612 KiB |
@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from 'react';
|
import { useEffect, useState } from "react";
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from "framer-motion";
|
||||||
import { Card } from '../UI/Card';
|
import { Card } from "../UI/Card";
|
||||||
import { ScrollDownArrow } from '../UI/ScrollDownArrow';
|
import { ScrollDownArrow } from "../UI/ScrollDownArrow";
|
||||||
|
|
||||||
export default function Certificates() {
|
export default function Certificates() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -9,30 +9,53 @@ export default function Certificates() {
|
|||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
window.scrollTo({
|
window.scrollTo({
|
||||||
top: 0,
|
top: 0,
|
||||||
behavior: "smooth"
|
behavior: "smooth",
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
return () => clearTimeout(timer);
|
return () => clearTimeout(timer);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const [selectedCertificate, setSelectedCertificate] = useState(null);
|
||||||
const certificates = [
|
const certificates = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
image: "/sertifikat1.jpg",
|
image: "/sertifikat1.jpg",
|
||||||
alt: "Сертификат за акредитација",
|
alt: "Сертификат за акредитација",
|
||||||
title: "Сертификат за акредитација",
|
title: "Сертификат за акредитација",
|
||||||
description: "Официјален сертификат за акредитација на нашата лабораторија"
|
description:
|
||||||
|
"Официјален сертификат за акредитација на нашата лабораторија",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
image: "/sertifikat2.jpg",
|
image: "/sertifikat2.jpg",
|
||||||
alt: "Сертификат за квалитет",
|
alt: "Сертификат за квалитет",
|
||||||
title: "Сертификат за квалитет",
|
title: "Сертификат за квалитет",
|
||||||
description: "Потврда за нашиот систем за управување со квалитет"
|
description: "Потврда за нашиот систем за управување со квалитет",
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
image: "/resenie_imk.png",
|
||||||
|
alt: "resenie ",
|
||||||
|
title: "resenie",
|
||||||
|
description: "some description",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
alt: "Сертификат",
|
||||||
|
image: "/Sertifikat za akreditacija IMK.png",
|
||||||
|
title: "Сертификат за акредитација",
|
||||||
|
description: "Официјален сертификат за акредитација",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const handleCertificateClick = (certificate) => {
|
||||||
|
setSelectedCertificate(certificate);
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
setSelectedCertificate(null);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-neutral-50">
|
<div className="min-h-screen bg-neutral-50">
|
||||||
{/* Hero Section */}
|
{/* Hero Section */}
|
||||||
@ -51,7 +74,8 @@ export default function Certificates() {
|
|||||||
</h1>
|
</h1>
|
||||||
<div className="w-24 h-1 bg-white/30 mx-auto mb-8"></div>
|
<div className="w-24 h-1 bg-white/30 mx-auto mb-8"></div>
|
||||||
<p className="text-xl text-neutral-100">
|
<p className="text-xl text-neutral-100">
|
||||||
Нашата посветеност кон квалитет и професионалност е потврдена со меѓународно признати сертификати
|
Нашата посветеност кон квалитет и професионалност е потврдена со
|
||||||
|
меѓународно признати сертификати
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
@ -70,6 +94,8 @@ export default function Certificates() {
|
|||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ duration: 0.5, delay: index * 0.2 }}
|
transition={{ duration: 0.5, delay: index * 0.2 }}
|
||||||
|
onClick={() => handleCertificateClick(certificate)}
|
||||||
|
className="cursor-pointer"
|
||||||
>
|
>
|
||||||
<Card className="h-full overflow-hidden hover:shadow-xl transition-all duration-300">
|
<Card className="h-full overflow-hidden hover:shadow-xl transition-all duration-300">
|
||||||
<motion.div
|
<motion.div
|
||||||
@ -98,6 +124,38 @@ export default function Certificates() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{selectedCertificate && (
|
||||||
|
<div
|
||||||
|
className="fixed inset-0 bg-black/50 flex items-center justify-center z-50"
|
||||||
|
onClick={closeModal}
|
||||||
|
>
|
||||||
|
{/* <div className="relative bg-white p-6 rounded-lg shadow-lg max-w-3xl w-full"> */}
|
||||||
|
{/* <button */}
|
||||||
|
{/* onClick={closeModal} */}
|
||||||
|
{/* className="absolute top-2 right-2 text-gray-500 hover:text-gray-800" */}
|
||||||
|
{/* > */}
|
||||||
|
{/* ✕ */}
|
||||||
|
{/* </button> */}
|
||||||
|
<div className="">
|
||||||
|
<motion.img
|
||||||
|
src={selectedCertificate.image}
|
||||||
|
alt={selectedCertificate.alt}
|
||||||
|
className="w-full h-screen mx-auto object-contain"
|
||||||
|
initial={{ opacity: 0, scale: 0.9 }}
|
||||||
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
transition={{ duration: 0.3 }}
|
||||||
|
/>
|
||||||
|
{/* <h2 className="text-xl font-display font-semibold text-neutral-900 mt-4"> */}
|
||||||
|
{/* {selectedCertificate.title} */}
|
||||||
|
{/* </h2> */}
|
||||||
|
{/* <p className="text-neutral-600 mt-2"> */}
|
||||||
|
{/* {selectedCertificate.description} */}
|
||||||
|
{/* </p> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { motion } from 'framer-motion';
|
import { motion } from "framer-motion";
|
||||||
|
|
||||||
export function ScrollDownArrow({ targetId = 'content' }) {
|
export function ScrollDownArrow({ targetId = "content" }) {
|
||||||
const scrollToContent = () => {
|
const scrollToContent = () => {
|
||||||
const contentSection = document.getElementById(targetId);
|
const contentSection = document.getElementById(targetId);
|
||||||
contentSection?.scrollIntoView({ behavior: 'smooth' });
|
contentSection?.scrollIntoView({ behavior: "smooth" });
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -12,14 +12,14 @@ export function ScrollDownArrow({ targetId = 'content' }) {
|
|||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{
|
animate={{
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
y: [0, 10, 0]
|
y: [0, 10, 0],
|
||||||
}}
|
}}
|
||||||
transition={{
|
transition={{
|
||||||
duration: 1.5,
|
duration: 1.5,
|
||||||
repeat: Infinity,
|
repeat: Infinity,
|
||||||
delay: 1
|
delay: 1,
|
||||||
}}
|
}}
|
||||||
className="absolute bottom-24 cursor-pointer focus:outline-none"
|
className="absolute bottom-36 cursor-pointer focus:outline-none"
|
||||||
aria-label="Scroll to content"
|
aria-label="Scroll to content"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@ -39,3 +39,4 @@ export function ScrollDownArrow({ targetId = 'content' }) {
|
|||||||
</motion.button>
|
</motion.button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -48,11 +48,9 @@ export default function Login() {
|
|||||||
>
|
>
|
||||||
<div className="text-center mb-8">
|
<div className="text-center mb-8">
|
||||||
<h2 className="text-2xl font-semibold text-white">
|
<h2 className="text-2xl font-semibold text-white">
|
||||||
Sign in to your account
|
Логирај се на својот акаунт
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm text-neutral-300 mt-2">
|
<p className="text-sm text-neutral-300 mt-2">Добредојдовте!</p>
|
||||||
Welcome back! Please enter your details.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
@ -64,19 +62,19 @@ export default function Login() {
|
|||||||
<form onSubmit={handleSubmit} className="space-y-6">
|
<form onSubmit={handleSubmit} className="space-y-6">
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<Label htmlFor="username" className="text-white">
|
<Label htmlFor="username" className="text-white">
|
||||||
Username
|
Е мејл
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="username"
|
id="username"
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
placeholder="Enter your username"
|
placeholder="Внесете го вашиот мејл"
|
||||||
value={formData.username}
|
value={formData.username}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setFormData({ ...formData, username: e.target.value })
|
setFormData({ ...formData, username: e.target.value })
|
||||||
}
|
}
|
||||||
error={error}
|
error={error}
|
||||||
className="bg-neutral-800/50 border-neutral-700 text-white placeholder-neutral-400
|
className="p-2 bg-neutral-800/50 border-neutral-700 text-white placeholder-neutral-400
|
||||||
focus:border-primary-400 focus:ring-primary-400"
|
focus:border-primary-400 focus:ring-primary-400"
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@ -84,7 +82,7 @@ export default function Login() {
|
|||||||
<FormGroup>
|
<FormGroup>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<Label htmlFor="password" className="text-white">
|
<Label htmlFor="password" className="text-white">
|
||||||
Password
|
Лозинка
|
||||||
</Label>
|
</Label>
|
||||||
{/* <Button
|
{/* <Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
@ -99,13 +97,13 @@ export default function Login() {
|
|||||||
id="password"
|
id="password"
|
||||||
type="password"
|
type="password"
|
||||||
required
|
required
|
||||||
placeholder="Enter your password"
|
placeholder="Внесете ја вашата лозинка"
|
||||||
value={formData.password}
|
value={formData.password}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setFormData({ ...formData, password: e.target.value })
|
setFormData({ ...formData, password: e.target.value })
|
||||||
}
|
}
|
||||||
error={error}
|
error={error}
|
||||||
className="bg-neutral-800/50 border-neutral-700 text-white placeholder-neutral-400
|
className="p-2 bg-neutral-800/50 border-neutral-700 text-white placeholder-neutral-400
|
||||||
focus:border-primary-400 focus:ring-primary-400"
|
focus:border-primary-400 focus:ring-primary-400"
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@ -130,7 +128,7 @@ export default function Login() {
|
|||||||
to="/forgot-password"
|
to="/forgot-password"
|
||||||
className="font-medium text-primary-400 hover:text-primary-300 transition-colors"
|
className="font-medium text-primary-400 hover:text-primary-300 transition-colors"
|
||||||
>
|
>
|
||||||
Forgot your password?
|
Ја заборавивте вашата лозинка?
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -54,7 +54,7 @@ export default function Navbar() {
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
{/* Left Logo */}
|
{/* Left Logo */}
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<Link to="/" className="p-2 hover:bg-white/20 transition-colors">
|
<Link to="/" className="p-2">
|
||||||
<img
|
<img
|
||||||
className="h-10 w-auto transition-transform duration-300 hover:scale-105"
|
className="h-10 w-auto transition-transform duration-300 hover:scale-105"
|
||||||
src="/imklogorgb.png"
|
src="/imklogorgb.png"
|
||||||
@ -96,23 +96,22 @@ export default function Navbar() {
|
|||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={handleLogout}
|
onClick={handleLogout}
|
||||||
className="text-white hover:bg-primary-700/50 px-4 py-2 text-sm"
|
className="text-white border border-red-400 hover:bg-primary-700/50 px-4 py-2 text-sm"
|
||||||
>
|
>
|
||||||
Одјави се
|
Одјави се
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* TUF Logo */}
|
{/* <div className="hidden lg:block"> */}
|
||||||
<div className="hidden lg:block">
|
{/* <a href="/" className="p-2 hover:bg-white/20 transition-colors"> */}
|
||||||
<a href="/" className="p-2 hover:bg-white/20 transition-colors">
|
{/* <img */}
|
||||||
<img
|
{/* className="h-10 w-auto transition-transform duration-300 hover:scale-105" */}
|
||||||
className="h-10 w-auto transition-transform duration-300 hover:scale-105"
|
{/* src="/tuf.png" */}
|
||||||
src="/tuf.png"
|
{/* alt="TUF logo" */}
|
||||||
alt="TUF logo"
|
{/* /> */}
|
||||||
/>
|
{/* </a> */}
|
||||||
</a>
|
{/* </div> */}
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Mobile Menu Button */}
|
{/* Mobile Menu Button */}
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { FiTrendingUp, FiAward, FiCheckCircle } from "react-icons/fi";
|
import { FiTrendingUp, FiAward, FiCheckCircle } from "react-icons/fi";
|
||||||
import { Button, Card } from "../../components/UI";
|
import { Button, Card } from "../../components/UI";
|
||||||
import { ScrollDownArrow } from '../../components/UI/ScrollDownArrow';
|
import { ScrollDownArrow } from "../../components/UI/ScrollDownArrow";
|
||||||
|
|
||||||
const milestones = [
|
const milestones = [
|
||||||
{ year: "2008", title: "Основање на компанијата" },
|
{ year: "2008", title: "Основање на компанијата" },
|
||||||
@ -15,7 +15,8 @@ const milestones = [
|
|||||||
const values = [
|
const values = [
|
||||||
{
|
{
|
||||||
title: "Квалитет",
|
title: "Квалитет",
|
||||||
description: "Посветени сме на обезбедување највисок квалитет во сите наши услуги",
|
description:
|
||||||
|
"Посветени сме на обезбедување највисок квалитет во сите наши услуги",
|
||||||
color: "text-primary-500",
|
color: "text-primary-500",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -105,15 +106,21 @@ export default function About() {
|
|||||||
<Card className="bg-gradient-to-br from-primary-800 to-primary-600 text-white">
|
<Card className="bg-gradient-to-br from-primary-800 to-primary-600 text-white">
|
||||||
<div className="flex items-center mb-6">
|
<div className="flex items-center mb-6">
|
||||||
<FiAward className="w-8 h-8 mr-4" />
|
<FiAward className="w-8 h-8 mr-4" />
|
||||||
<h3 className="text-2xl font-display font-semibold">Вредности</h3>
|
<h3 className="text-2xl font-display font-semibold">
|
||||||
|
Вредности
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<ul className="space-y-4">
|
<ul className="space-y-4">
|
||||||
{values.map((value, index) => (
|
{values.map((value, index) => (
|
||||||
<li key={index} className="flex items-start">
|
<li key={index} className="flex items-start">
|
||||||
<FiCheckCircle className="w-5 h-5 mr-3 mt-1" />
|
<FiCheckCircle className="w-5 h-5 mr-3 mt-1" />
|
||||||
<div>
|
<div>
|
||||||
<strong className="block text-lg mb-1">{value.title}</strong>
|
<strong className="block text-lg mb-1">
|
||||||
<span className="text-neutral-100">{value.description}</span>
|
{value.title}
|
||||||
|
</strong>
|
||||||
|
<span className="text-neutral-100">
|
||||||
|
{value.description}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
@ -124,35 +131,35 @@ export default function About() {
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Milestones Section */}
|
{/* Milestones Section */}
|
||||||
<section className="py-24 bg-white">
|
{/* <section className="py-24 bg-white"> */}
|
||||||
<div className="container-base">
|
{/* <div className="container-base"> */}
|
||||||
<div className="text-center mb-16">
|
{/* <div className="text-center mb-16"> */}
|
||||||
<h2 className="text-3xl md:text-4xl font-display font-bold text-neutral-900 mb-4">
|
{/* <h2 className="text-3xl md:text-4xl font-display font-bold text-neutral-900 mb-4"> */}
|
||||||
Нашиот Пат
|
{/* Нашиот Пат */}
|
||||||
</h2>
|
{/* </h2> */}
|
||||||
<div className="w-24 h-1 bg-primary-500 mx-auto mb-6"></div>
|
{/* <div className="w-24 h-1 bg-primary-500 mx-auto mb-6"></div> */}
|
||||||
<p className="text-lg text-neutral-600 max-w-2xl mx-auto">
|
{/* <p className="text-lg text-neutral-600 max-w-2xl mx-auto"> */}
|
||||||
Клучни моменти во нашиот развој
|
{/* Клучни моменти во нашиот развој */}
|
||||||
</p>
|
{/* </p> */}
|
||||||
</div>
|
{/* </div> */}
|
||||||
|
{/**/}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
{/* <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8"> */}
|
||||||
{milestones.map((milestone, index) => (
|
{/* {milestones.map((milestone, index) => ( */}
|
||||||
<Card
|
{/* <Card */}
|
||||||
key={index}
|
{/* key={index} */}
|
||||||
className="text-center hover:-translate-y-1 transition-transform duration-300"
|
{/* className="text-center hover:-translate-y-1 transition-transform duration-300" */}
|
||||||
>
|
{/* > */}
|
||||||
<div className="text-primary-600 text-3xl font-bold mb-2">
|
{/* <div className="text-primary-600 text-3xl font-bold mb-2"> */}
|
||||||
{milestone.year}
|
{/* {milestone.year} */}
|
||||||
</div>
|
{/* </div> */}
|
||||||
<div className="text-neutral-800 text-lg font-medium">
|
{/* <div className="text-neutral-800 text-lg font-medium"> */}
|
||||||
{milestone.title}
|
{/* {milestone.title} */}
|
||||||
</div>
|
{/* </div> */}
|
||||||
</Card>
|
{/* </Card> */}
|
||||||
))}
|
{/* ))} */}
|
||||||
</div>
|
{/* </div> */}
|
||||||
</div>
|
{/* </div> */}
|
||||||
</section>
|
{/* </section> */}
|
||||||
|
|
||||||
{/* CTA Section */}
|
{/* CTA Section */}
|
||||||
<section className="py-24 bg-gradient-to-br from-primary-900 to-primary-700">
|
<section className="py-24 bg-gradient-to-br from-primary-900 to-primary-700">
|
||||||
|
|||||||
@ -1,89 +1,98 @@
|
|||||||
import { useState } from 'react'
|
import { useState, useEffect } from "react";
|
||||||
import { motion } from 'framer-motion'
|
|
||||||
import {
|
import {
|
||||||
EnvelopeIcon,
|
EnvelopeIcon,
|
||||||
PhoneIcon,
|
PhoneIcon,
|
||||||
MapPinIcon
|
MapPinIcon,
|
||||||
} from '@heroicons/react/24/outline'
|
} from "@heroicons/react/24/outline";
|
||||||
import { Button, Card, Input } from '../../components/UI'
|
import { Switch } from "@headlessui/react";
|
||||||
import { Switch } from '@headlessui/react'
|
|
||||||
|
|
||||||
const contactInfo = [
|
const contactInfo = [
|
||||||
{
|
{
|
||||||
icon: PhoneIcon,
|
icon: PhoneIcon,
|
||||||
title: 'Телефон',
|
title: "Телефон",
|
||||||
content: '+389 XX XXX XXX',
|
content: "+389 XX XXX XXX",
|
||||||
link: 'tel:+389XXXXXXX'
|
link: "tel:+389XXXXXXX",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: EnvelopeIcon,
|
icon: EnvelopeIcon,
|
||||||
title: 'Емаил',
|
title: "Емаил",
|
||||||
content: 'contact@imk.mk',
|
content: "contact@imk.mk",
|
||||||
link: 'mailto:contact@imk.mk'
|
link: "mailto:contact@imk.mk",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: MapPinIcon,
|
icon: MapPinIcon,
|
||||||
title: 'Адреса',
|
title: "Адреса",
|
||||||
content: 'Скопје, Македонија',
|
content: "Скопје, Македонија",
|
||||||
link: 'https://goo.gl/maps/your-location'
|
link: "https://goo.gl/maps/your-location",
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
function classNames(...classes) {
|
function classNames(...classes) {
|
||||||
return classes.filter(Boolean).join(' ')
|
return classes.filter(Boolean).join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Contact() {
|
export default function Contact() {
|
||||||
|
useEffect(() => {
|
||||||
|
// Ensure the scroll happens after the component is fully mounted
|
||||||
|
const timer = setTimeout(() => {
|
||||||
|
window.scrollTo({
|
||||||
|
top: 0,
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
return () => clearTimeout(timer);
|
||||||
|
}, []);
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
firstName: '',
|
firstName: "",
|
||||||
lastName: '',
|
lastName: "",
|
||||||
company: '',
|
company: "",
|
||||||
email: '',
|
email: "",
|
||||||
message: ''
|
message: "",
|
||||||
})
|
});
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false)
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const [submitStatus, setSubmitStatus] = useState(null)
|
const [submitStatus, setSubmitStatus] = useState(null);
|
||||||
const [agreed, setAgreed] = useState(false)
|
const [agreed, setAgreed] = useState(false);
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault()
|
e.preventDefault();
|
||||||
setIsSubmitting(true)
|
setIsSubmitting(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('https://formsubmit.co/taratur@gmail.com', {
|
const response = await fetch("https://formsubmit.co/taratur@gmail.com", {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json'
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify(formData)
|
body: JSON.stringify(formData),
|
||||||
})
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
setSubmitStatus('success')
|
setSubmitStatus("success");
|
||||||
setFormData({
|
setFormData({
|
||||||
firstName: '',
|
firstName: "",
|
||||||
lastName: '',
|
lastName: "",
|
||||||
company: '',
|
company: "",
|
||||||
email: '',
|
email: "",
|
||||||
message: ''
|
message: "",
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
setSubmitStatus('error')
|
setSubmitStatus("error");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setSubmitStatus('error')
|
setSubmitStatus("error");
|
||||||
} finally {
|
} finally {
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
const { name, value } = e.target
|
const { name, value } = e.target;
|
||||||
setFormData(prev => ({
|
setFormData((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[name]: value
|
[name]: value,
|
||||||
}))
|
}));
|
||||||
}
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="isolate px-6 bg-gradient-to-b from-primary-900 to-primary-700 sm:py-32 lg:px-8 h-screen">
|
<div className="isolate px-6 bg-gradient-to-b from-primary-900 to-primary-700 sm:py-32 lg:px-8 h-screen">
|
||||||
@ -92,10 +101,7 @@ export default function Contact() {
|
|||||||
Пишете ни порака | Закажете средба
|
Пишете ни порака | Закажете средба
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<form
|
<form onSubmit={handleSubmit} className="mx-auto mt-16 max-w-xl sm:mt-20">
|
||||||
onSubmit={handleSubmit}
|
|
||||||
className="mx-auto mt-16 max-w-xl sm:mt-20"
|
|
||||||
>
|
|
||||||
<div className="grid grid-cols-1 gap-x-8 gap-y-6 sm:grid-cols-2">
|
<div className="grid grid-cols-1 gap-x-8 gap-y-6 sm:grid-cols-2">
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
@ -207,8 +213,10 @@ export default function Contact() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Switch.Group as="div" className="flex gap-x-4 sm:col-span-2">
|
<Switch.Group
|
||||||
</Switch.Group>
|
as="div"
|
||||||
|
className="flex gap-x-4 sm:col-span-2"
|
||||||
|
></Switch.Group>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" name="_next" value="https://imk.mk/"></input>
|
<input type="hidden" name="_next" value="https://imk.mk/"></input>
|
||||||
<div className="mt-10">
|
<div className="mt-10">
|
||||||
@ -224,5 +232,6 @@ export default function Contact() {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { Link } from "react-router-dom";
|
|||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import { ArrowRightIcon, CheckCircleIcon } from "@heroicons/react/24/outline";
|
import { ArrowRightIcon, CheckCircleIcon } from "@heroicons/react/24/outline";
|
||||||
import { Button, Card } from "../../components/UI";
|
import { Button, Card } from "../../components/UI";
|
||||||
import { ScrollDownArrow } from '../../components/UI/ScrollDownArrow';
|
import { ScrollDownArrow } from "../../components/UI/ScrollDownArrow";
|
||||||
|
|
||||||
const serviceCards = [
|
const serviceCards = [
|
||||||
{
|
{
|
||||||
@ -109,7 +109,7 @@ export default function Home() {
|
|||||||
{/* Services Section */}
|
{/* Services Section */}
|
||||||
<section id="services-section" className="bg-neutral-50 py-24 h-screen">
|
<section id="services-section" className="bg-neutral-50 py-24 h-screen">
|
||||||
<div className="container-base">
|
<div className="container-base">
|
||||||
<div className="text-center mb-16">
|
<div className="text-centeSr mb-16">
|
||||||
<h2 className="text-3xl md:text-4xl font-display font-bold text-neutral-900 mb-4">
|
<h2 className="text-3xl md:text-4xl font-display font-bold text-neutral-900 mb-4">
|
||||||
Нашите Услуги
|
Нашите Услуги
|
||||||
</h2>
|
</h2>
|
||||||
@ -121,11 +121,7 @@ export default function Home() {
|
|||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||||
{serviceCards.map((card) => (
|
{serviceCards.map((card) => (
|
||||||
<Link
|
<Link key={card.title} to={card.link} className="group">
|
||||||
key={card.title}
|
|
||||||
to={card.link}
|
|
||||||
className="group"
|
|
||||||
>
|
|
||||||
<Card
|
<Card
|
||||||
className="h-full hover:-translate-y-1 transition-all duration-300"
|
className="h-full hover:-translate-y-1 transition-all duration-300"
|
||||||
padding="none"
|
padding="none"
|
||||||
@ -145,7 +141,10 @@ export default function Home() {
|
|||||||
<p className="text-neutral-600 mb-4">{card.description}</p>
|
<p className="text-neutral-600 mb-4">{card.description}</p>
|
||||||
<ul className="space-y-2">
|
<ul className="space-y-2">
|
||||||
{card.services.slice(0, 3).map((service, index) => (
|
{card.services.slice(0, 3).map((service, index) => (
|
||||||
<li key={index} className="flex items-center text-neutral-700">
|
<li
|
||||||
|
key={index}
|
||||||
|
className="flex items-center text-neutral-700"
|
||||||
|
>
|
||||||
<CheckCircleIcon className="h-5 w-5 text-primary-500 mr-2" />
|
<CheckCircleIcon className="h-5 w-5 text-primary-500 mr-2" />
|
||||||
{service}
|
{service}
|
||||||
</li>
|
</li>
|
||||||
@ -162,9 +161,6 @@ export default function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
// const API_URL = "https://imkapi.oblak.solutions:3000";
|
// const API_URL = "https://imkapi.oblak.solutions:3000";
|
||||||
const API_URL = "https://localhost:3000";
|
const API_URL = "http://localhost:3000";
|
||||||
const api = axios.create({
|
const api = axios.create({
|
||||||
baseURL: API_URL,
|
baseURL: API_URL,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user