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,41 @@
// ContentSection.jsx - Simple with Left Sidebar
'use client';
import React, { useState } from 'react';
import Sidebar from './Sidebar';
import GeneralGuidelines from './GeneralGuidelines';
import SearchSampleRequirements from './SearchSampleRequirements';
const ContentSection = () => {
const [activeSection, setActiveSection] = useState('general-content');
const renderContent = () => {
const sections = {
'general-content': <GeneralGuidelines />,
'search-content': <SearchSampleRequirements />
};
return sections[activeSection] || <GeneralGuidelines />;
};
return (
<section className="pt-4 pb-8">
<div className="container mx-auto max-w-none px-4">
<div className="grid xl:grid-cols-[280px_1fr] gap-8">
{/* LEFT SIDEBAR */}
<div className="xl:sticky xl:top-8">
<Sidebar
activeSection={activeSection}
onSectionChange={setActiveSection}
/>
</div>
{/* RIGHT CONTENT */}
<div className="bg-white rounded-lg">
{renderContent()}
</div>
</div>
</div>
</section>
);
};
export default ContentSection;

View File

@ -0,0 +1,54 @@
import React from 'react';
const GeneralGuidelines = () => {
return (
<div className="space-y-6">
<div className="mb-6">
<h3 className="text-2xl font-semibold text-gray-600 mb-4">General Guidelines</h3>
</div>
<div className="prose max-w-none">
<ul className="space-y-4 text-gray-700 leading-relaxed pl-5">
<li className="list-disc">
Please complete the Sample Initiation Form (SIF), ensuring that the
sample names on the form match the labels on the sample tubes. We also
request that you send an electronic copy of the form and any required QC
data via email.
</li>
<li className="list-disc">
Each tube should be labeled on the lid with a maximum of 4-6
alphanumeric characters (e.g., 4B0001). Use a black permanent marker to
write sample names on the top and side of each tube. Avoid writing
directly on the tube wall or cover with an oil pen.
</li>
<li className="list-disc">
DNA can be submitted in DNase-free water, Elution Buffer, or 10mM Tris
pH 8.0. DNA samples should have an OD260/280 ratio as close to 1.8~2.0
as possible. All DNA should be RNase-treated and free from degradation
or contamination. Ship with ice packs. The total amount of DNA required
depends on the specific application.
</li>
<li className="list-disc">
RNA can be submitted in RNase-free water, RNA Stabilization Reagent, or
10mM Tris pH 8.0. All total RNA samples should be DNA-free, with an OD
A260/A280 ratio 1.8, A260/230 ratio 1.8, and a RIN 6. Ship with
dry ice. The total amount of RNA required depends on the specific
application. For Long Read Sequencing, RNA samples should have a RIN
8.
</li>
<li className="list-disc">
The listed concentrations should be determined by fluorometry (e.g.,
PicoGreen/Qubit/RiboGreen). If using spectrophotometry (e.g., Nanodrop),
increase concentrations by approximately twofold.
</li>
<li className="list-disc">
The quality inspection method for the sizes and concentrations of the
Ready To Run Library is Qubit and Agilent Bioanalyzer.
</li>
</ul>
</div>
</div>
);
};
export default GeneralGuidelines;

View File

@ -0,0 +1,23 @@
import React from 'react';
const IntroSection = () => {
return (
<section className="bg-white mx-4 md:mx-8 mt-4 mb-4 py-4">
<div className="container mx-auto max-w-none px-4">
<div className="text-gray-600 max-w-none leading-relaxed text-center">
<div className="text-base text-justify">
<p className="m-0">
We humbly offer a wide range of services, including genomics, transcriptomics,
metagenomics, epigenomics, single-cell sequencing, genotyping, microarray,
bioinformatics, and more. To help us deliver the best results for you, we request you to
review our sample requirements and follow the instructions for packaging, labeling, and
shipping your samples.
</p>
</div>
</div>
</div>
</section>
);
};
export default IntroSection;

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 Submission Guideline</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 Submission Guideline
</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,15 @@
import React from 'react';
import PageTitle from './PageTitle';
import IntroSection from './IntroSection';
import ContentSection from './ContentSection';
const SampleGuidelinePage = () => {
return (
<div className="page-content">
<PageTitle />
<IntroSection />
<ContentSection />
</div>
);
};
export default SampleGuidelinePage;

View File

@ -0,0 +1,154 @@
'use client';
import React, { useState, useEffect } from 'react';
import { sequencingData } from './sequencingData';
import TooltipIcon from './TooltipIcon';
const SearchFilters = ({ filters, onFilterChange, onSearch, onReset, isSearchEnabled }) => {
const [availableOptions, setAvailableOptions] = useState({
nucleicAcid: [],
category: [],
application: [],
sampleType: []
});
useEffect(() => {
updateAvailableOptions();
}, [filters]);
const updateAvailableOptions = () => {
// Get nucleic acid options
const nucleicAcids = [...new Set(sequencingData.map(item => item.nucleicAcid))];
// Filter data based on current selections
let filteredData = sequencingData;
if (filters.nucleicAcid) {
filteredData = filteredData.filter(item => item.nucleicAcid === filters.nucleicAcid);
}
const categories = [...new Set(filteredData.map(item => item.category))];
// Further filter for applications
if (filters.category) {
filteredData = filteredData.filter(item => item.category === filters.category);
}
const applications = [...new Set(filteredData.map(item => item.application))];
// Further filter for sample types
if (filters.application) {
filteredData = filteredData.filter(item => item.application === filters.application);
}
const sampleTypes = [...new Set(filteredData.map(item => item.sampleType))];
setAvailableOptions({
nucleicAcid: nucleicAcids.sort(),
category: categories.sort(),
application: applications.sort(),
sampleType: sampleTypes.sort()
});
};
return (
<div className="bg-white p-6 rounded-lg shadow-sm border">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{/* Nucleic Acid */}
<div className="space-y-2">
<label className="flex items-center text-sm font-semibold text-gray-700">
Nucleic Acid
</label>
<select
value={filters.nucleicAcid}
onChange={(e) => onFilterChange('nucleicAcid', e.target.value)}
style={{ color: '#555555' }}
className="w-full p-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
>
<option value="" style={{ color: '#555555' }}>Select</option>
{availableOptions.nucleicAcid.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>{option}</option>
))}
</select>
</div>
{/* Category */}
<div className="space-y-2">
<label className="flex items-center text-sm font-semibold text-gray-700">
Category
</label>
<select
value={filters.category}
onChange={(e) => onFilterChange('category', e.target.value)}
disabled={!filters.nucleicAcid}
style={{ color: '#555555' }}
className="w-full p-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
>
<option value="" style={{ color: '#555555' }}>{filters.nucleicAcid ? 'Select' : 'Select Previous Option First'}</option>
{availableOptions.category.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>{option}</option>
))}
</select>
</div>
{/* Applications */}
<div className="space-y-2">
<label className="flex items-center text-sm font-semibold text-gray-700">
Applications
<TooltipIcon text="Lists all the applications for the sample." />
</label>
<select
value={filters.application}
onChange={(e) => onFilterChange('application', e.target.value)}
disabled={!filters.category}
style={{ color: '#555555' }}
className="w-full p-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
>
<option value="" style={{ color: '#555555' }}>{filters.category ? 'Select' : 'Select Previous Option First'}</option>
{availableOptions.application.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>{option}</option>
))}
</select>
</div>
{/* Sample Type */}
<div className="space-y-2">
<label className="flex items-center text-sm font-semibold text-gray-700">
Sample Type
<TooltipIcon text="Describes the nature of the sample. Common sample types are listed, though some categories might not be included." />
</label>
<select
value={filters.sampleType}
onChange={(e) => onFilterChange('sampleType', e.target.value)}
disabled={!filters.application}
style={{ color: '#555555' }}
className="w-full p-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed"
>
<option value="" style={{ color: '#555555' }}>{filters.application ? 'Select' : 'Select Previous Option First'}</option>
{availableOptions.sampleType.map(option => (
<option key={option} value={option} style={{ color: '#555555' }}>{option}</option>
))}
</select>
</div>
</div>
{/* Buttons */}
<div className="flex justify-end items-center space-x-4 mt-6">
<button
onClick={onReset}
className="px-4 py-2 text-gray-600 hover:text-gray-800 transition-colors"
title="Reset filters"
>
</button>
<button
onClick={onSearch}
disabled={!isSearchEnabled}
className="px-6 py-2 bg-teal-600 text-white font-semibold rounded-md hover:bg-teal-700 disabled:bg-gray-300 disabled:cursor-not-allowed transition-colors"
>
Search
</button>
</div>
</div>
);
};
export default SearchFilters;

View File

@ -0,0 +1,72 @@
import React from 'react';
import TooltipIcon from './TooltipIcon';
const SearchResults = ({ results }) => {
if (results.length === 0) {
return (
<div className="mt-6">
<h2 className="text-2xl font-semibold text-teal-600 mb-4">Search Result</h2>
<div className="text-center py-8 text-gray-600 bg-gray-50 rounded-lg">
Please Select Valid Information
</div>
</div>
);
}
return (
<div className="mt-6 space-y-4">
<h2 className="text-2xl font-semibold text-teal-600 mb-4">Search Result</h2>
{results.map((item, index) => (
<div key={index} className="bg-teal-50 p-6 rounded-lg shadow-sm">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<ResultItem
title="Recommended Quantity"
value={item.recommendedQuantity}
tooltip="Indicates the suggested amount of sample for optimal results."
/>
<ResultItem
title="Minimum Quantity"
value={item.minimumQuantity}
tooltip="Specifies the minimum amount of sample that can be processed."
/>
<ResultItem
title="Minimum Concentration"
value={item.minimumConcentration}
tooltip="States the lowest concentration of nucleic acid required for processing."
/>
<ResultItem
title="Platform"
value={item.platform}
tooltip="Identifies the sequencing or analysis platform. This category is applicable only for Ready To Run Library (RTRL)."
/>
<ResultItem
title="Data Amount"
value={item.dataAmount}
tooltip="Provides an estimate of the data output. This category is applicable only for Ready To Run Library (RTRL)."
/>
<ResultItem
title="Volume Requirement"
value={item.volumeRequirement}
tooltip="Specifies the necessary volume of the sample for submission. This category is applicable only for Ready To Run Library (RTRL)."
/>
</div>
</div>
))}
</div>
);
};
const ResultItem = ({ title, value, tooltip }) => (
<div className="space-y-2">
<div className="flex items-center text-gray-600 text-sm">
{title}
<TooltipIcon text={tooltip} />
</div>
<div className="font-semibold text-gray-900 text-base">
{value || 'N/A'}
</div>
</div>
);
export default SearchResults;

View File

@ -0,0 +1,88 @@
'use client';
import React, { useState, useEffect } from 'react';
import { sequencingData } from './sequencingData';
import SearchFilters from './SearchFilters';
import SearchResults from './SearchResults';
const SearchSampleRequirements = () => {
const [filters, setFilters] = useState({
nucleicAcid: '',
category: '',
application: '',
sampleType: ''
});
const [filteredResults, setFilteredResults] = useState([]);
const [showResults, setShowResults] = useState(false);
const handleFilterChange = (filterName, value) => {
setFilters(prev => {
const newFilters = { ...prev, [filterName]: value };
// Reset subsequent filters when a parent filter changes
const filterOrder = ['nucleicAcid', 'category', 'application', 'sampleType'];
const currentIndex = filterOrder.indexOf(filterName);
for (let i = currentIndex + 1; i < filterOrder.length; i++) {
newFilters[filterOrder[i]] = '';
}
return newFilters;
});
};
const handleSearch = () => {
let results = sequencingData;
if (filters.nucleicAcid) {
results = results.filter(item => item.nucleicAcid === filters.nucleicAcid);
}
if (filters.category) {
results = results.filter(item => item.category === filters.category);
}
if (filters.application) {
results = results.filter(item => item.application === filters.application);
}
if (filters.sampleType) {
results = results.filter(item => item.sampleType === filters.sampleType);
}
setFilteredResults(results);
setShowResults(true);
};
const handleReset = () => {
setFilters({
nucleicAcid: '',
category: '',
application: '',
sampleType: ''
});
setFilteredResults([]);
setShowResults(false);
};
const isSearchEnabled = filters.nucleicAcid && filters.category && filters.application && filters.sampleType;
return (
<div className="space-y-6">
<div className="mb-6">
<h3 className="text-2xl font-semibold text-gray-600">Search Sample Requirements</h3>
</div>
<SearchFilters
filters={filters}
onFilterChange={handleFilterChange}
onSearch={handleSearch}
onReset={handleReset}
isSearchEnabled={isSearchEnabled}
/>
{showResults && (
<SearchResults results={filteredResults} />
)}
</div>
);
};
export default SearchSampleRequirements;

View File

@ -0,0 +1,43 @@
import React from 'react';
const Sidebar = ({ activeSection, onSectionChange }) => {
const menuItems = [
{ id: 'general-content', label: '1. General Guidelines' },
{ id: 'search-content', label: '2. Search Sample Requirements' }
];
return (
<div className="space-y-3">
{menuItems.map((item) => (
<button
key={item.id}
onClick={() => onSectionChange(item.id)}
className={`w-full text-left px-6 py-4 text-base font-medium rounded-full transition-all duration-300 border-2 whitespace-nowrap ${
activeSection === item.id
? 'text-white shadow-lg border-transparent'
: 'bg-white text-gray-600 border-transparent hover:border-2'
}`}
style={
activeSection === item.id
? { backgroundColor: '#ffa72a' }
: {}
}
onMouseEnter={(e) => {
if (activeSection !== item.id) {
e.target.style.borderColor = '#ffa72a';
}
}}
onMouseLeave={(e) => {
if (activeSection !== item.id) {
e.target.style.borderColor = 'transparent';
}
}}
>
{item.label}
</button>
))}
</div>
);
};
export default Sidebar;

View File

@ -0,0 +1,27 @@
'use client';
import React, { useState } from 'react';
const TooltipIcon = ({ text }) => {
const [showTooltip, setShowTooltip] = useState(false);
return (
<div className="relative inline-block ml-2">
<span
className="inline-flex items-center justify-center w-4 h-4 text-xs font-bold text-teal-600 border-2 border-teal-600 rounded-full cursor-pointer hover:bg-teal-600 hover:text-white transition-all duration-200"
onMouseEnter={() => setShowTooltip(true)}
onMouseLeave={() => setShowTooltip(false)}
>
i
</span>
{showTooltip && (
<div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 px-3 py-2 text-xs text-white bg-gray-800 rounded-md shadow-lg z-50 w-56 text-left">
{text}
<div className="absolute top-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-l-4 border-r-4 border-t-4 border-transparent border-t-gray-800"></div>
</div>
)}
</div>
);
};
export default TooltipIcon;

File diff suppressed because it is too large Load Diff