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,103 @@
import React from 'react';
const BioinformaticsSection = ({ formData, onInputChange }) => {
const handleChange = (field, value) => {
onInputChange('bioinformatics', field, value);
};
const analysisOptions = [
'', 'Variant Calling', 'Differential Expression', 'De Novo Assembly', 'Others'
];
const genomeOptions = [
'', 'Yes', 'No', 'Others'
];
return (
<div className="bg-white mx-6 p-6 rounded-lg">
<h2 className="text-teal-600 text-lg font-bold mb-6 border-b-2 border-teal-600 pb-1">
Bioinformatics Information
</h2>
<div className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Analysis Requested <span className="text-red-500">*</span>
</label>
<select
value={formData.Analysis_Requested}
onChange={(e) => handleChange('Analysis_Requested', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
>
{analysisOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Please Specify Details</label>
<input
type="text"
value={formData.Analysis_Details}
onChange={(e) => handleChange('Analysis_Details', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Reference Genome Available <span className="text-red-500">*</span>
</label>
<select
value={formData.Reference_Genome_Available}
onChange={(e) => handleChange('Reference_Genome_Available', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
>
{genomeOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">If Yes, Please Mention Genome Size</label>
<input
type="text"
value={formData.Genome_Size}
onChange={(e) => handleChange('Genome_Size', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Special Consideration <span className="text-red-500">*</span>
</label>
<textarea
value={formData.Special_Consideration}
onChange={(e) => handleChange('Special_Consideration', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial box-border"
rows={4}
required
/>
</div>
</div>
</div>
);
};
export default BioinformaticsSection;

View File

@ -0,0 +1,179 @@
import React from 'react';
const CustomerInfoSection = ({ formData, onInputChange }) => {
const handleChange = (field, value) => {
onInputChange('customer', field, value);
};
return (
<div className="bg-white mx-6 mt-6 p-6 rounded-lg">
<h2 className="text-teal-600 text-lg font-semibold mb-6 border-b-2 border-teal-600 pb-1">
Customer Information
</h2>
<div className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Principal Investigator <span className="text-red-500">*</span>
</label>
<input
type="text"
value={formData.Principal_Investigator}
onChange={(e) => handleChange('Principal_Investigator', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Email <span className="text-red-500">*</span>
</label>
<input
type="email"
value={formData.Email}
onChange={(e) => handleChange('Email', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Company/Institution <span className="text-red-500">*</span>
</label>
<input
type="text"
value={formData.Company_Institution}
onChange={(e) => handleChange('Company_Institution', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Contact Number <span className="text-red-500">*</span>
</label>
<input
type="tel"
value={formData.Contact_Number}
onChange={(e) => handleChange('Contact_Number', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Address <span className="text-red-500">*</span>
</label>
<input
type="text"
value={formData.Address}
onChange={(e) => handleChange('Address', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
City <span className="text-red-500">*</span>
</label>
<input
type="text"
value={formData.City}
onChange={(e) => handleChange('City', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
State <span className="text-red-500">*</span>
</label>
<input
type="text"
value={formData.State}
onChange={(e) => handleChange('State', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Pin <span className="text-red-500">*</span>
</label>
<input
type="text"
value={formData.Pin}
onChange={(e) => handleChange('Pin', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Secondary Contact</label>
<input
type="text"
value={formData.Secondary_Contact}
onChange={(e) => handleChange('Secondary_Contact', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Email</label>
<input
type="email"
value={formData.Secondary_Email}
onChange={(e) => handleChange('Secondary_Email', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Company/Institution</label>
<input
type="text"
value={formData.Secondary_Company_Institution}
onChange={(e) => handleChange('Secondary_Company_Institution', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Contact Number</label>
<input
type="tel"
value={formData.Secondary_Contact_Number}
onChange={(e) => handleChange('Secondary_Contact_Number', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
</div>
</div>
);
};
export default CustomerInfoSection;

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-4xl 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,246 @@
'use client';
import React from 'react';
const SampleDetailsSection = ({ sampleDetails, setSampleDetails }) => {
const preservativeOptions = [
'', 'Trizol', 'RNA later', 'Ethanol', 'Formalin', 'FFPE', 'Others'
];
const tempOptions = [
'', 'Ambient', 'Cool pack', 'Dry ice', 'Others'
];
const handleSampleChange = (index, field, value) => {
const newSampleDetails = [...sampleDetails];
newSampleDetails[index] = {
...newSampleDetails[index],
[field]: value
};
setSampleDetails(newSampleDetails);
};
const addRow = () => {
setSampleDetails([...sampleDetails, {
Serial_Number: '',
Sample_Name: '',
Storage_Temp: '',
Preservative_Reagent: '',
Temp_Information: '',
Comments: ''
}]);
};
const removeRow = (index) => {
if (sampleDetails.length > 1) {
const newSampleDetails = sampleDetails.filter((_, i) => i !== index);
setSampleDetails(newSampleDetails);
}
};
return (
<div className="bg-white mx-6 p-6 rounded-lg">
<h2 className="text-teal-600 text-lg font-bold mb-6 border-b-2 border-teal-600 pb-1">
Sample Details
</h2>
{/* Desktop Table View */}
<div className="hidden md:block overflow-x-auto">
<table className="w-full border-collapse text-xs">
<thead>
<tr className="bg-gray-100">
<th className="border border-gray-300 p-2 text-left font-bold">Serial Number</th>
<th className="border border-gray-300 p-2 text-left font-bold">Sample Name</th>
<th className="border border-gray-300 p-2 text-left font-bold">Storage Temp (in °C)</th>
<th className="border border-gray-300 p-2 text-left font-bold">Preservative Reagent</th>
<th className="border border-gray-300 p-2 text-left font-bold">Temp Information</th>
<th className="border border-gray-300 p-2 text-left font-bold">Comments</th>
<th className="border border-gray-300 p-2 text-center font-bold w-12"></th>
</tr>
</thead>
<tbody>
{sampleDetails.map((sample, index) => (
<tr key={index}>
<td className="border border-gray-300 p-2">
<input
type="text"
value={sample.Serial_Number}
onChange={(e) => handleSampleChange(index, 'Serial_Number', e.target.value)}
style={{ color: '#555555' }}
className="w-full text-xs h-8 p-1 border-none outline-none"
/>
</td>
<td className="border border-gray-300 p-2">
<input
type="text"
value={sample.Sample_Name}
onChange={(e) => handleSampleChange(index, 'Sample_Name', e.target.value)}
style={{ color: '#555555' }}
className="w-full text-xs h-8 p-1 border-none outline-none"
/>
</td>
<td className="border border-gray-300 p-2">
<input
type="text"
value={sample.Storage_Temp}
onChange={(e) => handleSampleChange(index, 'Storage_Temp', e.target.value)}
style={{ color: '#555555' }}
className="w-full text-xs h-8 p-1 border-none outline-none"
/>
</td>
<td className="border border-gray-300 p-2">
<select
value={sample.Preservative_Reagent}
onChange={(e) => handleSampleChange(index, 'Preservative_Reagent', e.target.value)}
style={{ color: '#555555' }}
className="w-full text-xs h-8 p-1 border-none outline-none"
>
{preservativeOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</td>
<td className="border border-gray-300 p-2">
<select
value={sample.Temp_Information}
onChange={(e) => handleSampleChange(index, 'Temp_Information', e.target.value)}
style={{ color: '#555555' }}
className="w-full text-xs h-8 p-1 border-none outline-none"
>
{tempOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</td>
<td className="border border-gray-300 p-2">
<input
type="text"
value={sample.Comments}
onChange={(e) => handleSampleChange(index, 'Comments', e.target.value)}
style={{ color: '#555555' }}
className="w-full text-xs h-8 p-1 border-none outline-none"
/>
</td>
<td className="border border-gray-300 p-2 text-center">
<button
type="button"
onClick={() => removeRow(index)}
className="text-gray-400 hover:text-red-500 w-8 h-8 rounded-full flex items-center justify-center transition-colors"
disabled={sampleDetails.length === 1}
>
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* Mobile Card View */}
<div className="md:hidden space-y-4">
{sampleDetails.map((sample, index) => (
<div key={index} className="border border-gray-300 rounded p-4 bg-white">
<div className="space-y-3">
<div>
<label className="block text-xs font-bold text-teal-600 mb-1">Serial Number</label>
<input
type="text"
value={sample.Serial_Number}
onChange={(e) => handleSampleChange(index, 'Serial_Number', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-xs h-8"
/>
</div>
<div>
<label className="block text-xs font-bold text-teal-600 mb-1">Sample Name</label>
<input
type="text"
value={sample.Sample_Name}
onChange={(e) => handleSampleChange(index, 'Sample_Name', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-xs h-8"
/>
</div>
<div>
<label className="block text-xs font-bold text-teal-600 mb-1">Storage Temp (in °C)</label>
<input
type="text"
value={sample.Storage_Temp}
onChange={(e) => handleSampleChange(index, 'Storage_Temp', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-xs h-8"
/>
</div>
<div>
<label className="block text-xs font-bold text-teal-600 mb-1">Preservative Reagent</label>
<select
value={sample.Preservative_Reagent}
onChange={(e) => handleSampleChange(index, 'Preservative_Reagent', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-xs h-8"
>
{preservativeOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</div>
<div>
<label className="block text-xs font-bold text-teal-600 mb-1">Temp Information</label>
<select
value={sample.Temp_Information}
onChange={(e) => handleSampleChange(index, 'Temp_Information', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-xs h-8"
>
{tempOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</div>
<div>
<label className="block text-xs font-bold text-teal-600 mb-1">Comments</label>
<input
type="text"
value={sample.Comments}
onChange={(e) => handleSampleChange(index, 'Comments', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-xs h-8"
/>
</div>
<div className="text-center mt-4">
<button
type="button"
onClick={() => removeRow(index)}
className="text-gray-400 hover:text-red-500 w-8 h-8 rounded-full flex items-center justify-center transition-colors mx-auto"
disabled={sampleDetails.length === 1}
>
</button>
</div>
</div>
</div>
))}
</div>
{/* Add Row Button */}
<button
type="button"
onClick={addRow}
className="mt-4 bg-green-500 hover:bg-green-600 text-white px-4 py-2 rounded text-xs transition-colors md:float-right"
>
Add Row
</button>
<div className="clear-both"></div>
</div>
);
};
export default SampleDetailsSection;

View File

@ -0,0 +1,297 @@
'use client';
import React, { useEffect, useState } from 'react';
import CustomerInfoSection from './CustomerInfoSection';
import SampleInfoSection from './SampleInfoSection';
import ServiceInfoSection from './ServiceInfoSection';
import BioinformaticsSection from './BioinformaticsSection';
import SampleDetailsSection from './SampleDetailsSection';
const SampleFormContainer = () => {
const [formData, setFormData] = useState({
// 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: '',
});
const [sampleDetails, setSampleDetails] = useState([
{
Serial_Number: '',
Sample_Name: '',
Storage_Temp: '',
Preservative_Reagent: '',
Temp_Information: '',
Comments: ''
}
]);
const [isSubmitting, setIsSubmitting] = useState(false);
const [message, setMessage] = useState('');
useEffect(() => {
// Check for Excel data in sessionStorage
const excelData = sessionStorage.getItem('excelData');
const uploadedFileName = sessionStorage.getItem('uploadedFileName');
if (excelData) {
try {
const jsonData = JSON.parse(excelData);
autoFillForm(jsonData);
// Clear stored data
sessionStorage.removeItem('excelData');
sessionStorage.removeItem('uploadedFileName');
setMessage(`Form auto-filled from uploaded file: ${uploadedFileName}`);
} catch (error) {
console.error('Error parsing Excel data:', error);
}
}
}, []);
const autoFillForm = (jsonData) => {
if (jsonData.length === 0) return;
const data = jsonData[0];
const newFormData = { ...formData };
// Helper function to safely get value
const getValue = (key) => data[key] ? data[key].toString().trim() : '';
// Customer Information
newFormData.Principal_Investigator = getValue('Principal Investigator');
newFormData.Email = getValue('Email');
newFormData.Company_Institution = getValue('Company/Institution');
newFormData.Contact_Number = getValue('Contact Number');
newFormData.Address = getValue('Address');
newFormData.City = getValue('City');
newFormData.State = getValue('State');
newFormData.Pin = getValue('Pin');
newFormData.Secondary_Contact = getValue('Secondary Contact');
newFormData.Secondary_Email = getValue('Secondary Email');
newFormData.Secondary_Company_Institution = getValue('Secondary Company/Institution');
newFormData.Secondary_Contact_Number = getValue('Secondary Contact Number');
// Sample Information
newFormData.Project_Title = getValue('Project Title');
newFormData.Number_of_Samples = getValue('Number of Samples');
newFormData.Sample_Type = getValue('Sample Type');
newFormData.Sample_Type_Other = getValue('Sample Type Other');
newFormData.Sample_Source = getValue('Sample Source');
newFormData.Sample_Source_Other = getValue('Sample Source Other');
newFormData.Pathogenicity = getValue('Pathogenicity');
newFormData.Sample_Remarks = getValue('Sample Remarks');
// Service Information
newFormData.Service_Requested = getValue('Service Requested');
newFormData.Service_Requested_Other = getValue('Service Requested Other');
newFormData.Type_of_Library = getValue('Type of Library');
newFormData.Type_of_Library_Other = getValue('Type of Library Other');
newFormData.Required_Library_Size = getValue('Required Library Size');
newFormData.Required_Library_Size_Other = getValue('Required Library Size Other');
newFormData.Index_Information = getValue('Index Information');
newFormData.Kit_Information = getValue('Kit Information');
newFormData.Sequencing_Platform = getValue('Sequencing Platform');
newFormData.Sequencing_Platform_Other = getValue('Sequencing Platform Other');
newFormData.Sequencing_Read_Length = getValue('Sequencing Read Length');
newFormData.Sequencing_Read_Length_Other = getValue('Sequencing Read Length Other');
newFormData.Total_Data_Requirement = getValue('Total Data Requirement');
newFormData.Service_Remarks = getValue('Service Remarks');
// Bioinformatics Information
newFormData.Analysis_Requested = getValue('Analysis Requested');
newFormData.Analysis_Details = getValue('Analysis Details');
newFormData.Reference_Genome_Available = getValue('Reference Genome Available');
newFormData.Genome_Size = getValue('Genome Size');
newFormData.Special_Consideration = getValue('Special Consideration');
setFormData(newFormData);
// Handle Sample Details
const sampleDetailsData = jsonData.filter(row =>
row['Serial Number'] || row['Sample Name'] ||
row['Storage Temp'] || row['Preservative Reagent'] ||
row['Temp Information'] || row['Comments']
);
if (sampleDetailsData.length > 0) {
const newSampleDetails = sampleDetailsData.map(sample => ({
Serial_Number: getValue('Serial Number'),
Sample_Name: getValue('Sample Name'),
Storage_Temp: getValue('Storage Temp'),
Preservative_Reagent: getValue('Preservative Reagent'),
Temp_Information: getValue('Temp Information'),
Comments: getValue('Comments')
}));
setSampleDetails(newSampleDetails);
}
};
const handleInputChange = (section, field, value) => {
setFormData(prev => ({
...prev,
[field]: value
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
setIsSubmitting(true);
setMessage(''); // Clear previous messages
try {
const formDataToSend = new FormData();
// Add form data
Object.keys(formData).forEach(key => {
if (formData[key]) {
formDataToSend.append(key, formData[key]);
}
});
// Add sample details as JSON string
formDataToSend.append('sample_details', JSON.stringify(sampleDetails));
formDataToSend.append('form_type', 'sample');
console.log('Submitting form data:', formData);
console.log('Sample details:', sampleDetails);
const response = await fetch('/api/forms', {
method: 'POST',
body: formDataToSend,
});
const result = await response.json();
console.log('API Response:', result);
if (response.ok) {
setMessage(result.message);
// Reset form after successful submission
setFormData({
Principal_Investigator: '', Email: '', Company_Institution: '', Contact_Number: '',
Address: '', City: '', State: '', Pin: '', Secondary_Contact: '', Secondary_Email: '',
Secondary_Company_Institution: '', Secondary_Contact_Number: '', Project_Title: '',
Number_of_Samples: '', Sample_Type: '', Sample_Type_Other: '', Sample_Source: '',
Sample_Source_Other: '', Pathogenicity: '', Sample_Remarks: '', 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: '', Analysis_Requested: '', Analysis_Details: '',
Reference_Genome_Available: '', Genome_Size: '', Special_Consideration: ''
});
setSampleDetails([{
Serial_Number: '', Sample_Name: '', Storage_Temp: '',
Preservative_Reagent: '', Temp_Information: '', Comments: ''
}]);
} else {
setMessage('Error: ' + (result.error || 'Form submission failed'));
}
} catch (error) {
console.error('Error submitting form:', error);
setMessage('Error: Network error. Please check your connection and try again.');
} finally {
setIsSubmitting(false);
}
};
return (
<div className="bg-teal-50 min-h-screen py-8">
<div className="max-w-4xl mx-auto bg-teal-50 shadow-lg border border-gray-300 font-arial text-xs">
<form onSubmit={handleSubmit} className="space-y-6">
{/* Show message if exists */}
{message && (
<div className="mx-6 mt-6">
<div className={`p-4 rounded ${message.includes('Error') ? 'bg-red-100 text-red-800' : 'bg-green-100 text-green-800'}`}>
{message}
</div>
</div>
)}
<CustomerInfoSection
formData={formData}
onInputChange={handleInputChange}
/>
<SampleInfoSection
formData={formData}
onInputChange={handleInputChange}
/>
<ServiceInfoSection
formData={formData}
onInputChange={handleInputChange}
/>
<BioinformaticsSection
formData={formData}
onInputChange={handleInputChange}
/>
<SampleDetailsSection
sampleDetails={sampleDetails}
setSampleDetails={setSampleDetails}
/>
{/* Submit Button */}
<div className="text-center py-6">
<button
type="submit"
disabled={isSubmitting}
className="bg-teal-600 hover:bg-teal-700 text-white font-medium py-3 px-6 rounded disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{isSubmitting ? 'Submitting...' : 'Submit Sample Form'}
</button>
</div>
</form>
</div>
</div>
);
};
export default SampleFormContainer;

View File

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

View File

@ -0,0 +1,144 @@
import React from 'react';
const SampleInfoSection = ({ formData, onInputChange }) => {
const handleChange = (field, value) => {
onInputChange('sample', field, value);
};
const sampleTypeOptions = [
'', 'DNA', 'RNA', 'cfDNA', 'Blood', 'Saliva', 'Swabs', 'Bodily Fluids', 'Feaces', 'Soil', 'Seeds', 'Water',
'Fresh/Frozen tissue', 'FFPE block', 'Plant Tissue', 'Animal Tissue', 'Ready to Run Library (RTRL)', 'Others'
];
const sampleSourceOptions = [
'', 'Plant', 'Human', 'Microbial', 'Animal', 'Environmental', 'Others'
];
return (
<div className="bg-white mx-6 p-6 rounded-lg">
<h2 className="text-teal-600 text-lg font-bold mb-6 border-b-2 border-teal-600 pb-1">
Sample Information
</h2>
<div className="space-y-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Project Title <span className="text-red-500">*</span>
</label>
<input
type="text"
value={formData.Project_Title}
onChange={(e) => handleChange('Project_Title', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Number of Samples <span className="text-red-500">*</span>
</label>
<input
type="text"
value={formData.Number_of_Samples}
onChange={(e) => handleChange('Number_of_Samples', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Sample Type <span className="text-red-500">*</span>
</label>
<select
value={formData.Sample_Type}
onChange={(e) => handleChange('Sample_Type', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
>
{sampleTypeOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Please Specify (if Others)</label>
<input
type="text"
value={formData.Sample_Type_Other}
onChange={(e) => handleChange('Sample_Type_Other', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Sample Source <span className="text-red-500">*</span>
</label>
<select
value={formData.Sample_Source}
onChange={(e) => handleChange('Sample_Source', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
>
{sampleSourceOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Please Specify (if Others)</label>
<input
type="text"
value={formData.Sample_Source_Other}
onChange={(e) => handleChange('Sample_Source_Other', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Pathogenicity <span className="text-red-500">*</span>
</label>
<input
type="text"
value={formData.Pathogenicity}
onChange={(e) => handleChange('Pathogenicity', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Remarks</label>
<input
type="text"
value={formData.Sample_Remarks}
onChange={(e) => handleChange('Sample_Remarks', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
</div>
</div>
);
};
export default SampleInfoSection;

View File

@ -0,0 +1,266 @@
import React from 'react';
const ServiceInfoSection = ({ formData, onInputChange }) => {
const handleChange = (field, value) => {
onInputChange('service', field, value);
};
const serviceOptions = [
'', 'DNA Sequencing - Whole Genome', 'DNA Sequencing - Whole Exome DNA Sequencing',
'DNA Sequencing - Amplicon Sequencing (16S/18S/ITS)', 'DNA Sequencing - Targeted Sequencing',
'DNA Sequencing - Single Cell DNA', 'DNA Sequencing - Microbiome and Metagenomics',
'DNA Sequencing - Whole Genome Bisulphite', 'DNA Sequencing - ChIP Sequencing',
'DNA Sequencing - ATAC Sequencing', 'DNA Sequencing - HiC Sequencing',
'DNA Sequencing - Optical Mapping', 'DNA Sequencing - Long Read Sequencing by Pacbio',
'DNA Sequencing - Long Read Sequencing by Nanopore', 'DNA Sequencing - Hybrid',
'RNA Sequencing- Total RNA', 'RNA Sequencing- mRNA', 'RNA Sequencing- Small RNA',
'RNA Sequencing- Long Non-Coding', 'RNA Sequencing- lncRNA', 'RNA Sequencing- Metatranscriptomics',
'RNA Sequencing- Degradome', 'RNA Sequencing- Iso Sequencing', 'RNA Sequencing- Circular RNA',
'RNA Sequencing- Single Cell RNA', 'Genotyping- ddRAD', 'Genotyping- SNP',
'Genotyping- Microsatellites/ STR/SSR/FLA', 'Genotyping- Sequencing based',
'Genotyping- GWAS', 'Genotyping- DNA Fingerprinting', 'Others'
];
const libraryTypeOptions = [
'', 'Single-End Sequencing', 'Paired-End Sequencing', 'Mate-Pair Sequencing',
'Continuous Long Read (CLR)', 'High-Fidelity (HiFi)',
'High-throughput Chromosome Conformation Capture (HiC)', 'Optical Mapping', 'Others'
];
const librarySizeOptions = [
'', '250 bp (Illumina)', '300 bp (Illumina)', '450 bp (Illumina)', '550 bp (Illumina)',
'800 bp (Illumina)', '1 kb (Oxford Nanopore Technologies, ONT)',
'5 kb (Oxford Nanopore Technologies, ONT)', '7 kb (Oxford Nanopore Technologies, ONT)',
'10 kb (Oxford Nanopore Technologies, ONT)', '1-2 kb (PacBio)', '2-3 kb (PacBio)',
'3-6 kb (PacBio)', '5-10 kb (PacBio)', '10 kb (Continuous Long Read, CLR)',
'20 kb CLR (Continuous Long Read, CLR)', 'Others'
];
const platformOptions = [
'', 'NovaSeq 6000/ NovaSeq X', 'NextSeq', 'MiSeq', 'Pacific Biosciences(PacBio)',
'Oxford Nanopore Technologies (ONT)', 'NanoString', 'Saphyr System (Optical Mapping)',
'Illumina iScan System', 'Kompetitive Allele-Specific PCR (KASPAR)', 'Others'
];
const readLengthOptions = [
'', '1X50bp (Illumina)', '1X100bp (Illumina)', '2X100bp (Illumina)',
'2X150bp (Illumina)', '2X250bp (Illumina)', '2X125bp (Illumina)',
'2X300bp (Illumina)', 'Others'
];
return (
<div className="bg-white mx-6 p-6 rounded-lg">
<h2 className="text-teal-600 text-lg font-bold mb-6 border-b-2 border-teal-600 pb-1">
Service Information
</h2>
<div className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Service Requested <span className="text-red-500">*</span>
</label>
<select
value={formData.Service_Requested}
onChange={(e) => handleChange('Service_Requested', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
>
{serviceOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Please Specify (if Others)</label>
<input
type="text"
value={formData.Service_Requested_Other}
onChange={(e) => handleChange('Service_Requested_Other', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Type of Library <span className="text-red-500">*</span>
</label>
<select
value={formData.Type_of_Library}
onChange={(e) => handleChange('Type_of_Library', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
>
{libraryTypeOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Please Specify (if Others)</label>
<input
type="text"
value={formData.Type_of_Library_Other}
onChange={(e) => handleChange('Type_of_Library_Other', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Required Library Size <span className="text-red-500">*</span>
</label>
<select
value={formData.Required_Library_Size}
onChange={(e) => handleChange('Required_Library_Size', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
>
{librarySizeOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Please Specify (if Others)</label>
<input
type="text"
value={formData.Required_Library_Size_Other}
onChange={(e) => handleChange('Required_Library_Size_Other', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Index Information (only for RTRL)</label>
<input
type="text"
value={formData.Index_Information}
onChange={(e) => handleChange('Index_Information', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Kit Information (only for RTRL)</label>
<input
type="text"
value={formData.Kit_Information}
onChange={(e) => handleChange('Kit_Information', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Sequencing Platform <span className="text-red-500">*</span>
</label>
<select
value={formData.Sequencing_Platform}
onChange={(e) => handleChange('Sequencing_Platform', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
>
{platformOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Please Specify (if Others)</label>
<input
type="text"
value={formData.Sequencing_Platform_Other}
onChange={(e) => handleChange('Sequencing_Platform_Other', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Sequencing Read Length <span className="text-red-500">*</span>
</label>
<select
value={formData.Sequencing_Read_Length}
onChange={(e) => handleChange('Sequencing_Read_Length', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
>
{readLengthOptions.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>
{option || 'Select'}
</option>
))}
</select>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Please Specify (if Others)</label>
<input
type="text"
value={formData.Sequencing_Read_Length_Other}
onChange={(e) => handleChange('Sequencing_Read_Length_Other', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">
Total Data Requirement (in Million or in GB) <span className="text-red-500">*</span>
</label>
<input
type="text"
value={formData.Total_Data_Requirement}
onChange={(e) => handleChange('Total_Data_Requirement', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
required
/>
</div>
<div>
<label className="block mb-2 font-semibold text-sm text-gray-600">Remarks</label>
<input
type="text"
value={formData.Service_Remarks}
onChange={(e) => handleChange('Service_Remarks', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-2 border border-gray-300 rounded text-sm font-arial h-10 box-border"
/>
</div>
</div>
</div>
</div>
);
};
export default ServiceInfoSection;