This commit is contained in:
dimitar 2025-04-26 17:46:59 +02:00
parent 1e38bd67a0
commit 967f9b414e
6 changed files with 252 additions and 217 deletions

View File

@ -3,8 +3,10 @@ export const corsConfig = {
"http://localhost:5173",
"http://localhost:4444",
"http://localhost:3000",
"https://www.placebo.mk",
"https://placebo.mk",
"https://www.imk.mk",
"https://imk.mk/",
// "https://www.placebo.mk",
// "https://placebo.mk",
"https://imkapi.oblak.solutions",
// "https://eu-assets.i.posthog.com",
// "https://app.posthog.com",

View File

@ -253,6 +253,26 @@ export class EmailService {
<p>If you didn't request this, please ignore this email or contact support if you have concerns.</p>
<p>Best regards,<br>IMK Team</p>
</div>
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<h2>Барање за ресетирање лозинка</h2>
<p>Hello ${name},</p>
<p>Добивме барање за ресетирање лозинка. Кликнете на линкот подолу за да поставите нова лозинка:</p>
<p>
<a href="${resetLink}" style="
display: inline-block;
padding: 10px 20px;
background-color: #4F46E5;
color: white;
text-decoration: none;
border-radius: 5px;
">Ресетирај лозинка</a>
</p>
<p>This link will expire in 1 hour.</p>
<p>Линкот е валиден 1 час.</p>
<p>If you didn't request this, please ignore this email or contact support if you have concerns.</p>
<p>Доколку не сте побарале ресетирање на лозинка игнорирајте ја оваа е-пошта</p>
<p>Секое добро,<br>IMK Team</p>
</div>
`,
};
@ -287,6 +307,14 @@ export class EmailService {
<p>If you did not make this change, please contact our support team immediately.</p>
<p>Best regards,<br>IMK Team</p>
</div>
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
<h2>Лозинката е успешно променена</h2>
<p>Здраво ${name},</p>
<p>Вашата лозинка е успешно променена.</p>
<p>Доколку не сте побарале промената на лозинката, ве молиме веднаш да не контактирате.</p>
<p>Секое добро,<br>IMK Team</p>
</div>
`,
};

View File

@ -32,43 +32,43 @@ async function bootstrap() {
}),
);
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: [
"'self'",
"'unsafe-inline'",
"'unsafe-eval'",
"https://eu-assets.i.posthog.com",
"https://app.posthog.com",
"https://eu.posthog.com",
],
connectSrc: [
"'self'",
"https://eu.posthog.com",
"https://eu-assets.i.posthog.com",
"https://app.posthog.com",
],
imgSrc: ["'self'", "data:", "https:"],
styleSrc: ["'self'", "'unsafe-inline'"],
fontSrc: ["'self'", "data:", "https:"],
rameSrc: [
"'self'",
"https://eu-assets.i.posthog.com",
"https://app.posthog.com",
],
},
},
crossOriginResourcePolicy: {
policy: "cross-origin",
},
crossOriginOpenerPolicy: {
policy: "same-origin-allow-popups",
},
}),
);
// app.use(
// helmet({
// contentSecurityPolicy: {
// directives: {
// defaultSrc: ["'self'"],
// scriptSrc: [
// "'self'",
// "'unsafe-inline'",
// "'unsafe-eval'",
// "https://eu-assets.i.posthog.com",
// "https://app.posthog.com",
// "https://eu.posthog.com",
// ],
// connectSrc: [
// "'self'",
// "https://eu.posthog.com",
// "https://eu-assets.i.posthog.com",
// "https://app.posthog.com",
// ],
// imgSrc: ["'self'", "data:", "https:"],
// styleSrc: ["'self'", "'unsafe-inline'"],
// fontSrc: ["'self'", "data:", "https:"],
// rameSrc: [
// "'self'",
// "https://eu-assets.i.posthog.com",
// "https://app.posthog.com",
// ],
// },
// },
// crossOriginResourcePolicy: {
// policy: "cross-origin",
// },
// crossOriginOpenerPolicy: {
// policy: "same-origin-allow-popups",
// },
// }),
// );
const port = process.env.PORT || 3000;

View File

@ -1,176 +1,181 @@
import { useEffect } from 'react';
import { motion } from 'framer-motion';
import { Card } from '../UI/Card';
import { useEffect } from "react";
import { motion } from "framer-motion";
import { Card } from "../UI/Card";
import { ScrollDownArrow } from "../UI/ScrollDownArrow";
export default function UltraSound() {
useEffect(() => {
window.scrollTo({ top: 0, behavior: "smooth" })
}, [])
useEffect(() => {
window.scrollTo({ top: 0, behavior: "smooth" });
}, []);
const scrollToContent = () => {
const contentSection = document.getElementById('video-section');
contentSection?.scrollIntoView({ behavior: 'smooth' });
};
const scrollToContent = () => {
const contentSection = document.getElementById("video-section");
contentSection?.scrollIntoView({ behavior: "smooth" });
};
const videoDetails = {
title: "Ултразвучно испитување",
description: "Ултразвучното испитување е неразорна метода за испитување на материјали која користи високофреквентни звучни бранови за откривање на внатрешни дефекти или за карактеризација на материјалите.",
benefits: [
"Неразорно испитување - не предизвикува оштетување на материјалот",
"Висока прецизност во откривањето на дефекти",
"Можност за испитување на различни материјали и дебелини",
"Брзи и точни резултати",
"Безбедна метода за операторот и околината"
],
applications: [
"Испитување на заварени споеви",
"Детекција на пукнатини и празнини",
"Мерење на дебелина на материјали",
"Контрола на квалитет во производство",
"Инспекција на метални конструкции"
],
videoUrl: "https://www.youtube.com/embed/WGjG8XWS9RQ?si=fE2aL5eZ-5ivuuxV"
};
const videoDetails = {
title: "Ултразвучно испитување",
description:
"Ултразвучното испитување е неразорна метода за испитување на материјали која користи високофреквентни звучни бранови за откривање на внатрешни дефекти или за карактеризација на материјалите.",
benefits: [
"Неразорно испитување - не предизвикува оштетување на материјалот",
"Висока прецизност во откривањето на дефекти",
"Можност за испитување на различни материјали и дебелини",
"Брзи и точни резултати",
"Безбедна метода за операторот и околината",
],
applications: [
"Испитување на заварени споеви",
"Детекција на пукнатини и празнини",
"Мерење на дебелина на материјали",
"Контрола на квалитет во производство",
"Инспекција на метални конструкции",
],
videoUrl: "https://www.youtube.com/embed/WGjG8XWS9RQ?si=fE2aL5eZ-5ivuuxV",
};
return (
<div className="min-h-screen bg-neutral-50">
{/* Hero Section */}
<section className="relative bg-gradient-to-br from-primary-900 to-primary-700">
<div className="absolute inset-0 bg-black/20" />
<div className="relative container-base h-screen flex items-center justify-center">
<div className="flex flex-col items-center">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
className="max-w-3xl mx-auto text-center"
>
<h1 className="text-4xl md:text-5xl font-display font-bold text-white mb-6">
{videoDetails.title}
</h1>
<div className="w-24 h-1 bg-white/30 mx-auto mb-8"></div>
<p className="text-xl text-neutral-100">
{videoDetails.description}
</p>
</motion.div>
return (
<div className="min-h-screen bg-neutral-50">
{/* Hero Section */}
<section className="relative bg-gradient-to-br from-primary-900 to-primary-700">
<div className="absolute inset-0 bg-black/20" />
<div className="relative container-base h-screen flex items-center justify-center">
<div className="flex flex-col items-center">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
className="max-w-3xl mx-auto text-center"
>
<h1 className="text-4xl md:text-5xl font-display font-bold text-white mb-6">
{videoDetails.title}
</h1>
<div className="w-24 h-1 bg-white/30 mx-auto mb-8"></div>
<p className="text-xl text-neutral-100">
{videoDetails.description}
</p>
</motion.div>
{/* Animated Down Arrow */}
<motion.button
onClick={scrollToContent}
initial={{ opacity: 0 }}
animate={{
opacity: 1,
y: [0, 10, 0]
}}
transition={{
duration: 1.5,
repeat: Infinity,
delay: 1
}}
className="absolute bottom-24 cursor-pointer focus:outline-none"
aria-label="Scroll to content"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-12 w-12 text-white/80 hover:text-white transition-colors"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M19 14l-7 7m0 0l-7-7m7 7V3"
/>
</svg>
</motion.button>
</div>
</div>
</section>
{/* Video Section */}
<section id="video-section" className="py-24">
<div className="container-base">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="aspect-video rounded-xl overflow-hidden shadow-xl"
>
<iframe
className="w-full h-full"
src={videoDetails.videoUrl}
title="Ултразвучно испитување демонстрација"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowFullScreen
/>
</motion.div>
</div>
</section>
{/* Info Section */}
<section className="py-24 bg-white">
<div className="container-base">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.5 }}
>
<Card className="h-full">
<div className="p-8">
<h2 className="text-2xl font-display font-bold text-neutral-900 mb-6">
Придобивки
</h2>
<ul className="space-y-4">
{videoDetails.benefits.map((benefit, index) => (
<motion.li
key={index}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.1 }}
className="flex items-start"
>
<span className="flex-shrink-0 w-1.5 h-1.5 mt-2 rounded-full bg-primary-600 mr-3" />
<span className="text-neutral-600">{benefit}</span>
</motion.li>
))}
</ul>
</div>
</Card>
</motion.div>
<motion.div
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.5 }}
>
<Card className="h-full">
<div className="p-8">
<h2 className="text-2xl font-display font-bold text-neutral-900 mb-6">
Примена
</h2>
<ul className="space-y-4">
{videoDetails.applications.map((application, index) => (
<motion.li
key={index}
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.1 }}
className="flex items-start"
>
<span className="flex-shrink-0 w-1.5 h-1.5 mt-2 rounded-full bg-primary-600 mr-3" />
<span className="text-neutral-600">{application}</span>
</motion.li>
))}
</ul>
</div>
</Card>
</motion.div>
</div>
</div>
</section>
{/* Animated Down Arrow */}
{/* <motion.button
onClick={scrollToContent}
initial={{ opacity: 0 }}
animate={{
opacity: 1,
y: [0, 10, 0],
}}
transition={{
duration: 1.5,
repeat: Infinity,
delay: 1,
}}
className="absolute bottom-24 cursor-pointer focus:outline-none"
aria-label="Scroll to content"
>
<svg
xmlns="http://www.w3.org/2000/svg"
className="h-12 w-12 text-white/80 hover:text-white transition-colors"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M19 14l-7 7m0 0l-7-7m7 7V3"
/>
</svg>
</motion.button> */}
<div>
<ScrollDownArrow />
</div>
);
}
</div>
</div>
</section>
{/* Video Section */}
<section id="video-section" className="py-24">
<div className="container-base">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="aspect-video rounded-xl overflow-hidden shadow-xl"
>
<iframe
className="w-full h-full"
src={videoDetails.videoUrl}
title="Ултразвучно испитување демонстрација"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
allowFullScreen
/>
</motion.div>
</div>
</section>
{/* Info Section */}
<section className="py-24 bg-white">
<div className="container-base">
<div className="grid grid-cols-1 md:grid-cols-2 gap-8">
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.5 }}
>
<Card className="h-full">
<div className="p-8">
<h2 className="text-2xl font-display font-bold text-neutral-900 mb-6">
Придобивки
</h2>
<ul className="space-y-4">
{videoDetails.benefits.map((benefit, index) => (
<motion.li
key={index}
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.1 }}
className="flex items-start"
>
<span className="flex-shrink-0 w-1.5 h-1.5 mt-2 rounded-full bg-primary-600 mr-3" />
<span className="text-neutral-600">{benefit}</span>
</motion.li>
))}
</ul>
</div>
</Card>
</motion.div>
<motion.div
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.5 }}
>
<Card className="h-full">
<div className="p-8">
<h2 className="text-2xl font-display font-bold text-neutral-900 mb-6">
Примена
</h2>
<ul className="space-y-4">
{videoDetails.applications.map((application, index) => (
<motion.li
key={index}
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ delay: index * 0.1 }}
className="flex items-start"
>
<span className="flex-shrink-0 w-1.5 h-1.5 mt-2 rounded-full bg-primary-600 mr-3" />
<span className="text-neutral-600">{application}</span>
</motion.li>
))}
</ul>
</div>
</Card>
</motion.div>
</div>
</div>
</section>
</div>
);
}

View File

@ -25,7 +25,7 @@ const serviceCards = [
image: "wallscener.jpeg",
link: "/ultrasound",
services: [
"Испитување на заварени споеви",
"Испитувања со ултразвук",
"Дебелометрија",
"Испитување на дефекти",
"Контрола на квалитет",

View File

@ -5,13 +5,13 @@ export default defineConfig({
plugins: [react()],
server: {
port: 5173,
cors: {
origin: [
"https://eu-assets.i.posthog.com",
"https://app.posthog.com",
"https://eu.posthog.com",
],
allowedHeaders: ["posthog-session-id", "ph-session-id"],
},
// cors: {
// origin: [
// "https://eu-assets.i.posthog.com",
// "https://app.posthog.com",
// "https://eu.posthog.com",
// ],
// allowedHeaders: ["posthog-session-id", "ph-session-id"],
// },
},
});