commit da3df17022cb03dfb9438466ee11fb0ef0636f7b Author: mukesh13 Date: Mon Jun 16 15:53:12 2025 +0530 Docker config diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fe2e4a7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,53 @@ +# Next.js build output +.next/ +out/ + +# Node.js dependencies +node_modules/ +npm-debug.log* +yarn-error.log +pnpm-debug.log* + +# Environment variables +.env +.env.local +.env.development +.env.production +.env*.local + +# Build artifacts +.cache/ + +# Logs +logs/ +*.log + +# Temporary files +*.tmp +*.temp + +# Editor directories and files +.vscode/ +.idea/ +*.suo +*.ntvs* +*.njsproj +*.sln +*.swp + +# macOS +.DS_Store + +# Windows +Thumbs.db +ehthumbs.db + +# TypeScript cache +*.tsbuildinfo + +# Coverage reports +coverage/ + +# Lock files (optional, uncomment if you want to ignore) +# package-lock.json +# pnpm-lock.yaml \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d65a632 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +# Use the official Node.js 20 image as the base +FROM node:20-alpine + +# Set working directory +WORKDIR /app + +# Copy package.json and pnpm-lock.yaml (if it exists) +COPY package.json pnpm-lock.yaml* ./ + +# Install pnpm +RUN npm install -g pnpm + +# Install dependencies +RUN pnpm install + +# Copy the rest of the application code +COPY . . + +# Build the Next.js application +RUN pnpm build + +# Expose port 3000 +EXPOSE 3000 + +# Start the Next.js application +CMD ["pnpm", "start", "-p", "3000"] \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..54d58a6 --- /dev/null +++ b/README.md @@ -0,0 +1,30 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +pnpm dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/app/Hero/HeroSection.jsx b/app/Hero/HeroSection.jsx new file mode 100644 index 0000000..bb808c5 --- /dev/null +++ b/app/Hero/HeroSection.jsx @@ -0,0 +1,41 @@ +import React from "react"; + +const HeroSection = () => { + return ( +
+ {/* Background Video */} + + + {/* Overlay */} +
+ + {/* Content */} +
+
+ {/* Badge */} +
+ + #WEBSITEUNDERCONSTRUCTION + +
+ + {/* Main Heading */} +

+ Unleash The Genomic Secrets
+ With Us! +

+
+
+
+ ); +}; + +export default HeroSection; \ No newline at end of file diff --git a/app/api/forms/route.js b/app/api/forms/route.js new file mode 100644 index 0000000..b800ec9 --- /dev/null +++ b/app/api/forms/route.js @@ -0,0 +1,248 @@ +import { NextResponse } from 'next/server'; +import nodemailer from 'nodemailer'; + +// Email configuration +const emailConfig = { + from_email: process.env.EMAIL_USER || "smukeshsn2000@gmail.com", + from_email_password: process.env.EMAIL_PASS || "swoe hxko uzuc ichj", + from_email_name: process.env.EMAIL_FROM_NAME || "Operify", + to_email: process.env.EMAIL_TO || "smukesh1304@gmail.com", + to_email_name: process.env.EMAIL_TO_NAME || "Mukesh", +}; + +// Form configurations +const configs = { + contact: { + subject: 'Contact Form Submission', + fields: ['name', 'phone', 'service_interest', 'email', 'Organisation', 'message'], + required: ['name', 'phone', 'service_interest', 'email', 'Organisation', 'message'], + email_fields: ['email'], + successMessage: 'Thank you for your submission. Our team will contact you soon!' + }, + career: { + subject: 'Career Application', + fields: ['name', 'phone', 'email', 'Education_Qualification', 'experience', 'Specify_your_interest_in_Genomics', 'message'], + required: ['name', 'phone', 'email', 'Education_Qualification', 'experience', 'Specify_your_interest_in_Genomics', 'message'], + email_fields: ['email'], + file_field: 'resume', + successMessage: 'Thank you for your application. Our team will contact you soon!' + }, + sample: { + subject: 'SIF Form received for Project', + fields: [ + // Customer Information + 'Principal_Investigator', 'Email', 'Company_Institution', 'Contact_Number', 'Address', 'City', 'State', 'Pin', + 'Secondary_Contact', 'Secondary_Email', 'Secondary_Company_Institution', 'Secondary_Contact_Number', + + // Sample Information + 'Project_Title', 'Number_of_Samples', 'Sample_Type', 'Sample_Type_Other', 'Sample_Source', 'Sample_Source_Other', + 'Pathogenicity', 'Sample_Remarks', + + // Service Information + 'Service_Requested', 'Service_Requested_Other', 'Type_of_Library', 'Type_of_Library_Other', + 'Required_Library_Size', 'Required_Library_Size_Other', 'Index_Information', 'Kit_Information', + 'Sequencing_Platform', 'Sequencing_Platform_Other', 'Sequencing_Read_Length', 'Sequencing_Read_Length_Other', + 'Total_Data_Requirement', 'Service_Remarks', + + // Bioinformatics Information + 'Analysis_Requested', 'Analysis_Details', 'Reference_Genome_Available', 'Genome_Size', 'Special_Consideration' + ], + required: [ + 'Principal_Investigator', 'Email', 'Company_Institution', 'Contact_Number', 'Address', 'City', 'State', 'Pin', + 'Project_Title', 'Number_of_Samples', 'Sample_Type', 'Sample_Source', 'Pathogenicity', 'Service_Requested', + 'Type_of_Library', 'Required_Library_Size', 'Sequencing_Platform', 'Sequencing_Read_Length', + 'Total_Data_Requirement', 'Analysis_Requested', 'Reference_Genome_Available', 'Special_Consideration' + ], + email_fields: ['Email', 'Secondary_Email'], + successMessage: 'Thank you for your sample initiation form submission. Our team will contact you soon!' + } +}; + +// Utility functions +function isValidEmail(email) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return emailRegex.test(email); +} + +function fieldName(key) { + return key.replace(/[_-]/g, ' ').replace(/\b\w/g, l => l.toUpperCase()); +} + +export async function GET() { + return NextResponse.json({ + message: 'Forms API is working', + timestamp: new Date().toISOString() + }); +} + +export async function POST(request) { + try { + // Parse form data + const formData = await request.formData(); + const data = {}; + const files = {}; + + for (const [key, value] of formData.entries()) { + if (value instanceof File) { + files[key] = value; + } else { + data[key] = value; + } + } + + const form_type = data.form_type; + + // Validate form type + if (!form_type || !configs[form_type]) { + return NextResponse.json({ + error: 'Invalid form type: ' + (form_type || 'missing') + }, { status: 400 }); + } + + const config = configs[form_type]; + const errors = []; + + // Validate required fields + for (const required_field of config.required) { + if (!data[required_field] || String(data[required_field]).trim() === '') { + errors.push(`The "${fieldName(required_field)}" field is required.`); + } else if (config.email_fields.includes(required_field) && !isValidEmail(data[required_field])) { + errors.push(`The "${fieldName(required_field)}" email is not valid.`); + } + } + + // Validate file upload for career form + if (form_type === 'career') { + const fileField = config.file_field; + const uploadedFile = files[fileField]; + + if (!uploadedFile || uploadedFile.size === 0) { + errors.push('Please upload your resume.'); + } else { + const allowedExtensions = ['pdf', 'doc', 'docx']; + const fileName = uploadedFile.name.toLowerCase(); + const fileExtension = fileName.split('.').pop(); + + if (!allowedExtensions.includes(fileExtension)) { + errors.push('Invalid file type. Please upload a PDF, DOC, or DOCX file.'); + } + + if (uploadedFile.size > 10 * 1024 * 1024) { // 10MB limit + errors.push('File is too large. Maximum size is 10MB.'); + } + } + } + + if (errors.length > 0) { + return NextResponse.json({ + error: errors.join(' ') + }, { status: 400 }); + } + + // Construct email body + let emailBody = `

${config.subject}

`; + + for (const [key, value] of Object.entries(data)) { + if (config.fields.includes(key) && key !== 'form_type' && key !== 'sample_details') { + emailBody += ` + + + `; + } + } + + // Add file info if uploaded + if (form_type === 'career' && files.resume) { + emailBody += ` + + + `; + } + + // Add sample details for sample form + if (form_type === 'sample' && data.sample_details) { + try { + const sampleDetails = JSON.parse(data.sample_details); + if (sampleDetails && sampleDetails.length > 0) { + emailBody += ` + + `; + + sampleDetails.forEach((sample, index) => { + emailBody += ` + + `; + + Object.entries(sample).forEach(([key, value]) => { + if (value && String(value).trim() !== '') { + emailBody += ` + + + `; + } + }); + }); + } + } catch (error) { + console.error('Error parsing sample details:', error); + emailBody += ` + + `; + } + } + + emailBody += '
${fieldName(key)}: ${String(value)}
Resume: ${files.resume.name} (attached)
SAMPLE DETAILS
Sample ${index + 1}
${fieldName(key)}: ${String(value)}
Error: Could not parse sample details
'; + + // Determine reply-to email based on form type + let replyToEmail; + if (form_type === 'sample') { + replyToEmail = data.Email; + } else { + replyToEmail = data.email; + } + + // Create transporter + const transporter = nodemailer.createTransport({ + host: 'smtp.gmail.com', + port: 587, + secure: false, + auth: { + user: emailConfig.from_email, + pass: emailConfig.from_email_password, + }, + }); + + // Prepare email options + const mailOptions = { + from: `${emailConfig.from_email_name} <${emailConfig.from_email}>`, + to: `${emailConfig.to_email_name} <${emailConfig.to_email}>`, + replyTo: replyToEmail || emailConfig.from_email, + subject: config.subject, + html: emailBody, + text: emailBody.replace(/<[^>]*>/g, ''), // Strip HTML for text version + }; + + // Add attachment for career form + if (form_type === 'career' && files.resume) { + const fileBuffer = await files.resume.arrayBuffer(); + mailOptions.attachments = [{ + filename: files.resume.name, + content: Buffer.from(fileBuffer), + }]; + } + + // Send email + await transporter.sendMail(mailOptions); + + return NextResponse.json({ + success: true, + message: config.successMessage + }); + + } catch (error) { + console.error('Email sending error:', error); + return NextResponse.json({ + error: 'Error sending email. Please try again later.' + }, { status: 500 }); + } +} \ No newline at end of file diff --git a/app/careers/page.js b/app/careers/page.js new file mode 100644 index 0000000..91bd4f7 --- /dev/null +++ b/app/careers/page.js @@ -0,0 +1,25 @@ +import React from 'react'; +import PageLayout from '../components/Layout/PageLayout'; +import CareerPage from '../components/Career/CareerPage'; + +export default function CareersPage() { + return ( + +
+ +
+
+ ); +} + +// For App Router, export metadata separately +export const metadata = { + title: 'Careers - Operify Tech', + description: 'Join our passionate team at Operify Tech. Explore career opportunities in genomics, DNA sequencing, and cutting-edge research technology', + keywords: 'Careers Operify Tech, genomics jobs, DNA sequencing careers, NGS jobs, research careers, biotechnology jobs', + openGraph: { + title: 'Careers - Operify Tech', + description: 'Join our passionate team at Operify Tech. Explore career opportunities in genomics, DNA sequencing, and cutting-edge research technology', + type: 'website', + }, +}; \ No newline at end of file diff --git a/app/company/page.js b/app/company/page.js new file mode 100644 index 0000000..c4cdcb9 --- /dev/null +++ b/app/company/page.js @@ -0,0 +1,35 @@ +// app/company/page.js + +import React from 'react'; +import PageLayout from '../components/Layout/PageLayout'; +import CompanyHero from '../components/Company/CompanyHero' +import CompanyIntro from '../components/Company/CompanyIntro'; +import VisionMission from '../components/Company/VisionMission'; +import OurOfferings from '../components/Company/OurOfferings'; +import WhyChooseUs from '../components/Company/WhyChooseUs'; + +export default function CompanyPage() { + return ( + +
+ + + + + +
+
+ ); +} + +// For App Router, export metadata separately +export const metadata = { + title: 'Our Company - Operify Tech', + description: 'Learn about Operify Tech\'s mission, vision, and commitment to advancing genomic research through next-generation sequencing technology', + keywords: 'Operify Tech, company, genomics, NGS, next generation sequencing, mission, vision', + openGraph: { + title: 'Our Company - Operify Tech', + description: 'Learn about Operify Tech\'s mission, vision, and commitment to advancing genomic research through next-generation sequencing technology', + type: 'website', + }, +}; \ No newline at end of file diff --git a/app/components/About/NGSSection.jsx b/app/components/About/NGSSection.jsx new file mode 100644 index 0000000..6649572 --- /dev/null +++ b/app/components/About/NGSSection.jsx @@ -0,0 +1,95 @@ +import React from "react"; +import Image from "next/image"; +import Link from "next/link"; + +const AdvantageCard = ({ icon, title, description }) => ( +
+
+
+ {title} +
+

{title}

+
+
+
+
+

{description}

+
+); + +const NGSSection = () => { + const advantages = [ + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-20.svg", + title: "High Throughput", + description: "NGS technology has the capacity to generate an abundance of sequence data within a relatively short timespan." + }, + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-21.svg", + title: "High Resolution", + description: "Advanced sequencing platforms provide highly accurate DNA/RNA data, detecting even minor variations. This precision drives breakthroughs in health, diagnostics, agriculture, and molecular biology." + }, + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-22.svg", + title: "Cost Efficient", + description: "Affordability of the technology facilitates researchers in the successful implementation of large-scale sequencing projects." + }, + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-23.svg", + title: "Flexible", + description: "Supports a wide range of sample types and library construction methods, making it suitable for various research objectives and experimental designs." + }, + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-24.svg", + title: "Time Effective", + description: "Rapid sequencing of large genetic material be completed within a comparatively short duration, thereby yielding quick results." + }, + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-24.svg", + title: "Bioinformatics Analysis", + description: "NGS produces vast amounts of data, supporting complex research through advanced bioinformatic analysis." + } + ]; + + return ( +
+
+ {/* NGS Introduction */} +
+

+ NGS and Its Advantages +

+

+ Next Generation Sequencing (NGS) is a transformative technology + that has revolutionized scientific research. Unlike traditional + methods that required years to decode a single genome, NGS can + sequence entire genomes within days. This groundbreaking + technology employs massively parallel sequencing, simultaneously + analyzing millions of small DNA fragments, allowing researchers to + investigate thousands of genomic regions at single-base resolution + in a single experiment, empowering them to tackle ambitious + questions and achieve comprehensive insights. +

+ + +
+ + {/* Advantages Grid */} +
+
+ {advantages.map((advantage, index) => ( + + ))} +
+
+
+
+ ); +}; + +export default NGSSection; \ No newline at end of file diff --git a/app/components/Advantages/AdvantagesSection.jsx b/app/components/Advantages/AdvantagesSection.jsx new file mode 100644 index 0000000..d033507 --- /dev/null +++ b/app/components/Advantages/AdvantagesSection.jsx @@ -0,0 +1,75 @@ +import React from 'react'; +import Image from 'next/image'; + +const AdvantageCard = ({ icon, title, description }) => ( +
+
+
+ {title} +
+

{title}

+
+
+
+
+

{description}

+
+); + +const AdvantagesSection = () => { + const advantages = [ + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-20.svg", + title: "High Throughput", + description: "NGS technology has the capacity to generate an abundance of sequence data within a relatively short timespan." + }, + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-21.svg", + title: "High Resolution", + description: "Advanced sequencing platforms provide highly accurate DNA/RNA data, detecting even minor variations. This precision drives breakthroughs in health, diagnostics, agriculture, and molecular biology." + }, + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-22.svg", + title: "Cost Efficient", + description: "Affordability of the technology facilitates researchers in the successful implementation of large-scale sequencing projects." + }, + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-23.svg", + title: "Flexible", + description: "Supports a wide range of sample types and library construction methods, making it suitable for various research objectives and experimental designs." + }, + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-24.svg", + title: "Time Effective", + description: "Rapid sequencing of large genetic material be completed within a comparatively short duration, thereby yielding quick results." + }, + { + icon: "/images/homepage-1/service/Advantages-NGS-Icons-24.svg", + title: "Bioinformatics Analysis", + description: "NGS produces vast amounts of data, supporting complex research through advanced bioinformatic analysis." + } + ]; + + return ( +
+
+
+

Advantages of NGS

+
+ +
+ {advantages.map((advantage, index) => ( + + ))} +
+
+
+ ); +}; + +export default AdvantagesSection; \ No newline at end of file diff --git a/app/components/CTA/CTASection.jsx b/app/components/CTA/CTASection.jsx new file mode 100644 index 0000000..e02f40c --- /dev/null +++ b/app/components/CTA/CTASection.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import Image from 'next/image'; + +const CTASection = () => { + return ( +
+
+
+

+ Feeling Overwhelmed About Designing Your Experiment? +

+ +
+ Scientist +
+ +

+ Operify Has You Covered +

+ +

+ We offer comprehensive assistance for planning your experiment, including design, + execution, and evaluation of your sequencing project. Consult with our scientists + and bioinformatics experts to tailor a workflow that suits your needs, process + your samples, and generate your first NGS dataset. +

+ + +
+
+
+ ); +}; + +export default CTASection; \ No newline at end of file diff --git a/app/components/Career/CareerForm.jsx b/app/components/Career/CareerForm.jsx new file mode 100644 index 0000000..e8391eb --- /dev/null +++ b/app/components/Career/CareerForm.jsx @@ -0,0 +1,311 @@ +'use client'; +import React, { useState } from 'react'; + +const ExperienceSelect = ({ value, onChange, required }) => { + const [isOpen, setIsOpen] = useState(false); + + const experienceOptions = [ + { value: '', label: 'Select Experience', disabled: true }, + { value: 'Fresher', label: 'Fresher' }, + { value: '1-2 years', label: '1-2 years' }, + { value: '3-5 years', label: '3-5 years' }, + { value: '5+ years', label: '5+ years' } + ]; + + return ( +
+ + + {isOpen && ( +
+ {experienceOptions.map((option, index) => ( + + ))} +
+ )} +
+ ); +}; + +const FileUpload = ({ onFileChange, currentFile, required }) => { + const handleFileSelect = (e) => { + const file = e.target.files[0]; + if (file) { + onFileChange(file); + } + }; + + return ( +
+ +
+ + {currentFile ? currentFile.name : 'Upload Resume'} + + +
+
+ ); +}; + +const CareerForm = () => { + const [formData, setFormData] = useState({ + name: '', + phone: '', + email: '', + Education_Qualification: '', + experience: '', + Specify_your_interest_in_Genomics: '', + message: '', + resume: null + }); + + const [isSubmitting, setIsSubmitting] = useState(false); + + const handleInputChange = (e) => { + const { name, value } = e.target; + setFormData(prev => ({ + ...prev, + [name]: value + })); + }; + + const handleSelectChange = (name, value) => { + setFormData(prev => ({ + ...prev, + [name]: value + })); + }; + + const handleFileChange = (file) => { + setFormData(prev => ({ + ...prev, + resume: file + })); + }; + + const handleSubmit = async (e) => { + e.preventDefault(); + setIsSubmitting(true); + + try { + const formDataToSend = new FormData(); + Object.keys(formData).forEach(key => { + if (formData[key]) { + formDataToSend.append(key, formData[key]); + } + }); + formDataToSend.append('form_type', 'career'); + + console.log('Submitting career form:', formData); + + const response = await fetch('/api/forms', { + method: 'POST', + body: formDataToSend, + }); + + const result = await response.json(); + console.log('API Response:', result); + + if (response.ok) { + alert(result.message); + // Reset form + setFormData({ + name: '', + phone: '', + email: '', + Education_Qualification: '', + experience: '', + Specify_your_interest_in_Genomics: '', + message: '', + resume: null + }); + } else { + alert(result.error || 'Error submitting application. Please try again.'); + } + } catch (error) { + console.error('Error submitting form:', error); + alert('Error submitting application. Please check your connection and try again.'); + } finally { + setIsSubmitting(false); + } + }; + + return ( +
+
+
+

+ Send a message +

+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ handleSelectChange('experience', value)} + required + /> +
+
+ +
+
+ +
+ +
+ +
+