Docker config
This commit is contained in:
103
app/components/SampleForm/BioinformaticsSection.jsx
Normal file
103
app/components/SampleForm/BioinformaticsSection.jsx
Normal 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;
|
||||
179
app/components/SampleForm/CustomerInfoSection.jsx
Normal file
179
app/components/SampleForm/CustomerInfoSection.jsx
Normal 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;
|
||||
41
app/components/SampleForm/PageTitle.jsx
Normal file
41
app/components/SampleForm/PageTitle.jsx
Normal 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;
|
||||
246
app/components/SampleForm/SampleDetailsSection.jsx
Normal file
246
app/components/SampleForm/SampleDetailsSection.jsx
Normal 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;
|
||||
297
app/components/SampleForm/SampleFormContainer.jsx
Normal file
297
app/components/SampleForm/SampleFormContainer.jsx
Normal 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;
|
||||
14
app/components/SampleForm/SampleFormPage.jsx
Normal file
14
app/components/SampleForm/SampleFormPage.jsx
Normal 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;
|
||||
144
app/components/SampleForm/SampleInfoSection.jsx
Normal file
144
app/components/SampleForm/SampleInfoSection.jsx
Normal 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;
|
||||
266
app/components/SampleForm/ServiceInfoSection.jsx
Normal file
266
app/components/SampleForm/ServiceInfoSection.jsx
Normal 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;
|
||||
Reference in New Issue
Block a user