Docker config

This commit is contained in:
mukesh13
2025-06-16 15:53:12 +05:30
commit da3df17022
411 changed files with 24117 additions and 0 deletions

View File

@ -0,0 +1,23 @@
import React from 'react';
import Link from 'next/link';
const ContactNote = () => {
return (
<div className="bg-white py-4">
<div className="container">
<p className="text-gray-700 leading-relaxed ml-6 md:ml-8 lg:ml-8">
Please reach out to us by emailing{' '}
<Link
href="mailto:info@operifytech.com"
className="text-blue-600 hover:text-blue-700 transition-colors"
>
info@operifytech.com
</Link>
.
</p>
</div>
</div>
);
};
export default ContactNote;

View File

@ -0,0 +1,41 @@
import React from 'react';
const PageTitle = () => {
return (
<section
className="relative bg-cover bg-center py-4 sm:py-6 h-auto sm:h-32 md:h-40 lg:h-24 min-h-[120px] sm:min-h-[140px]"
style={{ backgroundImage: "url('images/bredcrumb.jpg')" }}
>
{/* Breadcrumb */}
<div className="relative z-10 mb-2 sm:mb-1 pt-2 sm:pt-0 sm:-mt-3 lg:-mt-3">
<div className="container mx-auto max-w-none px-4">
<nav className="flex flex-wrap items-center gap-1 sm:gap-2 text-xs sm:text-sm lg:text-sm">
<a href="/" className="text-white hover:text-yellow-400 underline whitespace-nowrap">Home</a>
<span className="text-white flex-shrink-0">
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clipRule="evenodd" />
</svg>
</span>
<a href="/sample-submission-guideline" className="text-white hover:text-yellow-400 underline whitespace-nowrap">Knowledge Hub</a>
<span className="text-white flex-shrink-0">
<svg className="w-3 h-3" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clipRule="evenodd" />
</svg>
</span>
<span className="text-white">Sample Initiation Form</span>
</nav>
</div>
</div>
{/* Page Title */}
<div className="relative z-10 text-center pb-2 sm:pb-0 sm:-mt-2 lg:mt-4">
<h1 className="text-lg sm:text-2xl md:text-3xl lg:text-3xl xl:text-4xl font-bold text-white mb-2 px-4 leading-tight">
Sample Initiation Form
</h1>
<div className="w-12 sm:w-14 md:w-16 lg:w-16 h-1 bg-yellow-400 mx-auto"></div>
</div>
</section>
);
};
export default PageTitle;

View File

@ -0,0 +1,35 @@
import React from 'react';
import ProcessSteps from './ProcessSteps';
import SubmissionOptions from './SubmissionOptions';
const ProcessSection = () => {
return (
<section className="bg-white">
<div className="container mx-auto max-w-none px-4">
<div className="bg-white p-4 md:p-6">
{/* Main Title */}
<div className="text-left mb-4">
<h2 className="text-2xl md:text-4xl text-gray-600 font-normal">
Welcome to Our Online Submission Portal!
</h2>
</div>
{/* Two Column Layout */}
<div className="flex flex-col lg:flex-row gap-8 lg:gap-20 items-start">
{/* Left Column - Process Steps */}
<div className="flex-1 min-w-0">
<ProcessSteps />
</div>
{/* Right Column - Submission Options */}
<div className="flex-1 min-w-0">
<SubmissionOptions />
</div>
</div>
</div>
</div>
</section>
);
};
export default ProcessSection;

View File

@ -0,0 +1,61 @@
import React from 'react';
const ProcessSteps = () => {
const steps = [
{
number: 1,
title: "Review Sample Requirements:",
items: [
<>Before submitting forms and samples, check the <a href="/sample-submission-guideline" className="text-gray-500 underline">sample submission guidelines</a> page and plan your project accordingly.</>,
<>Read the <a href="/packaging-and-shipping-guideline" className="text-gray-500 underline">packaging and shipping</a> guidelines and fill out the appropriate sample Initiation form.</>,
"Please note that samples will be processed in the order of date received physically in the lab along with duly filled Sample Submission Form. Submitting an online form without sample shipment will not reserve a space in the queue."
]
},
{
number: 2,
title: "Match Sample Names",
items: [
"Ensure sample names match what is written on your tubes. Sample names must be between 4-6 characters, using uppercase letters, numbers, and underscores only."
]
},
{
number: 3,
title: "Ship or Drop-Off Samples:",
items: [
<>Ship or drop off your samples at the lab with a printed copy of the submission form. We can also pick up the sample from your institution(additional logistic charges will be applicable). Check the <a href="/packaging-and-shipping-guideline#schedule-content" className="text-gray-500 underline">shipping schedule</a> for more details.</>
]
}
];
return (
<div className="space-y-6">
{steps.map((step) => (
<div key={step.number} className="flex items-start space-x-4">
{/* Step Number */}
<div
className="flex-shrink-0 w-8 h-8 text-white rounded-md flex items-center justify-center text-base font-bold"
style={{ backgroundColor: '#faae31' }}
>
{step.number}
</div>
{/* Step Content */}
<div className="flex-1 min-w-0">
<h3 className="text-lg md:text-xl font-medium mb-2" style={{ color: '#2a6564' }}>
{step.title}
</h3>
<ul className="list-disc list-inside space-y-2 text-gray-700 leading-relaxed pl-4">
{step.items.map((item, index) => (
<li key={index} className="text-justify">
{item}
</li>
))}
</ul>
</div>
</div>
))}
</div>
);
};
export default ProcessSteps;

View File

@ -0,0 +1,16 @@
import React from 'react';
import PageTitle from './PageTitle';
import ProcessSection from './ProcessSection';
import ContactNote from './ContactNote';
const SampleInitiationPage = () => {
return (
<div className="page-content">
<PageTitle />
<ProcessSection />
<ContactNote />
</div>
);
};
export default SampleInitiationPage;

View File

@ -0,0 +1,260 @@
'use client';
import React, { useState } from 'react';
import Image from 'next/image';
const SubmissionOptions = () => {
const [isProcessing, setIsProcessing] = useState(false);
const handleFillManually = () => {
window.location.href = '/samples-form';
};
const handleFileUpload = (event) => {
const file = event.target.files[0];
if (file) {
const validTypes = ['.xlsx', '.xls'];
const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
if (validTypes.includes(fileExtension)) {
processExcelFile(file);
} else {
alert('Please select a valid Excel file (.xlsx or .xls)');
event.target.value = '';
}
}
};
const processExcelFile = async (file) => {
setIsProcessing(true);
try {
// Import XLSX dynamically since it's a client-side library
const XLSX = await import('xlsx');
const reader = new FileReader();
reader.onload = (e) => {
try {
const data = new Uint8Array(e.target.result);
const workbook = XLSX.read(data, { type: 'array' });
const sheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[sheetName];
const jsonData = XLSX.utils.sheet_to_json(worksheet, { defval: '' });
if (jsonData.length > 0) {
// Store the Excel data in sessionStorage
sessionStorage.setItem('excelData', JSON.stringify(jsonData));
sessionStorage.setItem('uploadedFileName', file.name);
// Redirect to samples_form after a short delay
setTimeout(() => {
window.location.href = '/samples-form';
}, 1000);
} else {
alert('No valid data found in the Excel file.');
setIsProcessing(false);
}
} catch (error) {
console.error('Excel processing error:', error);
alert('Error processing Excel file. Please check the file format and try again.');
setIsProcessing(false);
}
};
reader.readAsArrayBuffer(file);
} catch (error) {
console.error('Error loading XLSX library:', error);
alert('Error loading file processor. Please try again.');
setIsProcessing(false);
}
};
const handleDownloadTemplate = async () => {
try {
// Import XLSX dynamically
const XLSX = await import('xlsx');
// Create template data structure with only column headers
const templateData = [
{
// 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': '',
// Sample Details
'Serial Number': '',
'Sample Name': '',
'Storage Temp': '',
'Preservative Reagent': '',
'Temp Information': '',
'Comments': ''
}
];
// Create workbook and worksheet
const workbook = XLSX.utils.book_new();
const worksheet = XLSX.utils.json_to_sheet(templateData);
// Set column widths for better readability
const colWidths = Object.keys(templateData[0]).map(() => ({ wch: 20 }));
worksheet['!cols'] = colWidths;
// Add worksheet to workbook
XLSX.utils.book_append_sheet(workbook, worksheet, 'Sample Initiation Form');
// Generate Excel file and download
const today = new Date().toISOString().split('T')[0];
const filename = `Sample_Initiation_Form_Template_${today}.xlsx`;
XLSX.writeFile(workbook, filename);
// Show success message
showMessage('Excel template downloaded successfully!', 'success');
} catch (error) {
console.error('Error downloading template:', error);
alert('Error downloading template. Please try again.');
}
};
const showMessage = (message, type) => {
// Create and show a toast message
const messageDiv = document.createElement('div');
messageDiv.className = `fixed top-5 right-5 z-50 max-w-sm p-4 rounded-lg shadow-lg font-medium ${
type === 'success'
? 'bg-green-100 text-green-800 border border-green-200'
: 'bg-red-100 text-red-800 border border-red-200'
}`;
messageDiv.textContent = message;
document.body.appendChild(messageDiv);
// Auto remove after 5 seconds
setTimeout(() => {
if (messageDiv.parentNode) {
messageDiv.remove();
}
}, 5000);
};
return (
<div className="space-y-4">
{/* Title */}
<div>
<h3 className="text-gray-600 text-lg md:text-xl font-medium mb-6">
Based on the convenience, please select one option:
</h3>
{/* Process Image */}
<div className="text-center my-6">
<Image
src="/images/sample-process-steps1.png"
alt="Sample Submission Process"
width={500}
height={300}
className="max-w-full h-auto rounded-lg mx-auto"
/>
</div>
</div>
{/* Action Buttons */}
<div className="space-y-2">
{/* Main Action Buttons */}
<div className="flex flex-col md:flex-row gap-4 items-center justify-center">
<button
onClick={handleFillManually}
className="w-full md:w-auto px-6 py-3 bg-teal-600 text-white font-medium rounded hover:bg-teal-700 transition-colors"
>
Fill Manually
</button>
<button
onClick={() => document.getElementById('fileUpload').click()}
className="w-full md:w-auto px-6 py-3 bg-transparent border border-gray-300 text-gray-600 font-normal rounded hover:bg-gray-50 transition-colors flex items-center justify-center gap-2"
>
<Image
src="/images/file-icon.svg"
alt="File Icon"
width={16}
height={16}
/>
Upload
</button>
</div>
{/* Hidden File Input */}
<input
type="file"
id="fileUpload"
className="hidden"
accept=".xlsx,.xls"
onChange={handleFileUpload}
/>
{/* Processing Indicator */}
{isProcessing && (
<div className="text-center py-4">
<div className="inline-block w-8 h-8 border-4 border-gray-200 border-t-teal-600 rounded-full animate-spin mb-2"></div>
<p className="text-gray-600">Processing Excel file and redirecting...</p>
</div>
)}
{/* Or Divider */}
<div className="text-center text-gray-500 text-base">
or
</div>
{/* Download Template Button */}
<div className="text-center">
<button
onClick={handleDownloadTemplate}
className="text-teal-600 text-base underline hover:text-teal-700 transition-colors bg-transparent border-none cursor-pointer"
>
Download form as Excel
</button>
</div>
</div>
</div>
);
};
export default SubmissionOptions;