Dynamic Evaluation Workflow for Tenders in CSQ/RFQ/ITQ
Key Features
-
Dynamic Tab Navigation
- Manages navigation between multiple steps or stages using a tab-based system. Tabs adapt dynamically based on tender type (
DSSPor other).
- Manages navigation between multiple steps or stages using a tab-based system. Tabs adapt dynamically based on tender type (
-
Form-Based Step Handling
- Implements a multi-step form that processes different tender stages, such as ITQ details, EOI details, and proposal evaluations.
-
Data Fetching and API Integration
- Integrates multiple services (
tenderService,userService,documentService) to fetch and update tender-related data. - Supports real-time updates for tender evaluations and supplier profiles.
- Integrates multiple services (
-
Evaluation Status Management
- Tracks and updates evaluation progress, ensuring compliance with predefined tender statuses and criteria.
-
PDF Generation for Documents
- Dynamically generates and displays PDFs for specific tender-related documents (e.g.,
TORandEOI).
- Dynamically generates and displays PDFs for specific tender-related documents (e.g.,
-
Redux State Integration
- Utilizes Redux to manage user state and handle shared data across components.
Key Functionalities
-
Tab Navigation and Rendering
- Dynamically renders tab content based on the
currentTabstate:const renderTabContent = () => {switch (currentTab) {case 0:return <EOIDetails {...sharedProps} />;case 1:return <EvaluatorDeclaration {...sharedProps} />;...}}; - Tabs are customized based on the tender’s
activity_type:const baseTabs = tenderDetails?.activity_type === 'DSSP'? ["ITQ details", "Declaration & Disclosure", "Received proposals"]: ["EOI details", "TOR details", "Declaration & Disclosure"];
- Dynamically renders tab content based on the
-
Data Fetching
- Fetches and processes tender details and evaluator information:
useEffect(() => {if (reviewTenderParam) {const fetchTender = async () => {const tenderDetailsResponse = await tenderService.getTenderBySerialId(reviewTenderParam);setTenderDetails(tenderDetailsResponse.tender);};fetchTender();}}, [reviewTenderParam]);
- Fetches and processes tender details and evaluator information:
-
Evaluation Progress Tracking
- Tracks the status of evaluations and updates the tender’s evaluation status:
if (isAllExist) {const dataToUpdate = { serial_id: reviewTenderParam, evaluation_status: "Evaluated" };await tenderService.updateTenderById(dataToUpdate);}
- Tracks the status of evaluations and updates the tender’s evaluation status:
-
PDF Document Generation
- Generates PDFs for tender documents:
const pdfUrl = await documentService.generatePdfFileTOR(reviewTenderParam);const url = window.URL.createObjectURL(new Blob([pdfUrl], { type: 'application/pdf' }));setGeneratedPdf(url);
- Generates PDFs for tender documents:
-
Pagination for Supplier Profiles
- Fetches supplier profiles with pagination:
const fetchSupplierProfiles = async (pageNumber) => {const response = await SupplierProfileInformationService.supplierProfileInformation(pageNumber, perPage, supplierIds);setRequestData(response.data);setTotalPages(Math.ceil(response.total_count / perPage));};
- Fetches supplier profiles with pagination:
-
State Management with Redux
- Retrieves user-related data from the Redux store:
const { user } = useSelector((state: RootState) => state.user);
- Retrieves user-related data from the Redux store:
Data Fetching and Step Handling
-
Data Fetching
- Tender Details: Fetches tender-specific data (e.g., details, evaluators) based on
request-idfrom URL search parameters.
Example:const fetchTender = async () => {const tenderDetailsResponse = await tenderService.getTenderBySerialId(reviewTenderParam);setTenderDetails(tenderDetailsResponse.tender);}; - Supplier Profiles: Retrieves and paginates supplier data using
SupplierProfileInformationService.
- Tender Details: Fetches tender-specific data (e.g., details, evaluators) based on
-
Step Handling
- Tabs as Steps: The
currentTabstate determines which stage (tab) is active. - Next and Previous Navigation:
const nextStep = () => setCurrentTab((prev) => prev + 1);const prevStep = () => setCurrentTab((prev) => prev - 1);
- Tabs as Steps: The
-
Flow of Information
- Data is fetched and normalized for use in various stages:
const normalizeKeys = (obj) => {return Object.keys(obj).reduce((acc, key) => {acc[key.toLowerCase()] = obj[key];return acc;}, {});};
- Updates are made to backend services to reflect the evaluation progress and tender statuses.
- Data is fetched and normalized for use in various stages:
Code Snippet for Reference
Dynamic rendering of tabs and content:
const tabs = currentTab === 3 || currentTab === 4 ? [...baseTabs, "Evaluate"] : baseTabs;
<Box className="my-5 rounded-md bg-slate-100 tab-bar p-2"> {tabs.map((tab, index) => ( <button key={index} onClick={() => handleClickTabbar(index)} className={`${index === currentTab ? 'isActiveTab' : 'deactiveTab'}`} > {tab} </button> ))}</Box>{renderTabContent()}This implementation demonstrates a modular and dynamic approach to handling complex workflows in a React-based tender evaluation system.
Title:
Tender Process Form with Dynamic Step Handling and Data Fetching for CSQ Process
Key Features:
-
Multi-Step Form with Dynamic Components: The application implements a multi-step form where each step is represented by a tab. These steps control the flow of the form, with dynamic components rendered based on the current step.
-
Data Fetching for Tender Details: The code fetches tender data from an API using
tenderServiceand dynamically sets data related to the tender process based on the step number. This data is used to populate various form fields and templates. -
Dynamic Form Handling: Dynamic fields are loaded for each step based on the step and procurement categories. This includes handling different types of inputs, such as tables for RFQ templates.
-
Step Navigation: The user can navigate between steps using a tab navigation system. Steps are controlled by
currentTab, and the step-specific data is updated accordingly. -
State Management: The code uses the React
useStatehook for managing various state variables related to the form data, step-specific information, and UI components (e.g.,supplierRequestData,quotationfromSupplier,priceAndDelivery). -
Componentized UI: Each step of the process corresponds to a different React component. For example,
SubmissionRequirementsFormfor step 4,DynamicConversionScreenfor step 2, andApproversAndEvaluatorsfor step 3. -
Conditional Rendering of Components: Depending on the
currentTabvalue, different components are rendered. For example:- Step 0:
AdditionalInfoFrom - Step 1:
DynamicConversionScreen - Step 2:
SubmissionRequirements - Step 3:
ApproversAndEvaluators - Step 4:
SubmissionRequirementsForm
- Step 0:
-
Handling Dynamic Templates and Fields: The code dynamically loads templates and template data (
detailsRFQ,matchingProcessTOR) for each step, allowing custom input fields to be presented based on the procurement process.
Key Functionalities:
-
Fetching Tender Data:
- The
fetchTenderDatafunction is responsible for fetching tender details from the API using thetenderService.getDraftTenderBySerialIdITQfunction. - Based on the fetched data, different step-specific functions are triggered (e.g.,
handleStepOne,handleStepTwo, etc.).
- The
-
Updating Form Data:
updateSupplierRequestDataandupdateAdditionalDatafunctions are used to update the form data in the state as the user interacts with different fields across multiple steps.
-
Step Handlers:
- Each step has a corresponding handler that processes and updates relevant data:
- Step One: Handles general tender information such as description, title, and pricing details.
- Step Two: Handles documents and specifications such as quotations and technical details.
- Step Three: Deals with approvers and evaluators, filtering the list based on the tender data.
- Step Four: Deals with final tender details and generates dynamic fields for the RFQ template.
- Each step has a corresponding handler that processes and updates relevant data:
-
Dynamic Fields and Templates:
- Template data for RFQ and other forms are fetched dynamically (
fetchTemplateByIdProcurementProcessId), and the form fields are updated based on the received templates.
- Template data for RFQ and other forms are fetched dynamically (
-
Tab Navigation:
- Users can navigate between tabs using the
handleTabClickfunction. The current tab is tracked using thecurrentTabstate, which also determines the visibility of different components.
- Users can navigate between tabs using the
Data Fetching and Step Handling:
-
Step Management:
- The form progresses through steps using the
nextStepandprevStepfunctions. ThecurrentTabstate variable tracks the current step, and each step corresponds to a specific React component being rendered. - The
handleTabClickfunction updates thecurrentTabwhen a user clicks a tab. It also sets thestepURL parameter to reflect the current step.
- The form progresses through steps using the
-
Fetching Data for Each Step:
- Step 1: Fetches tender data, updates additional data fields like
description,title,estimated_price, and others usinghandleStepOneAdditioal. - Step 2: Fetches documents and other details like
quotation_from_supplier,price_and_delivery, and sets these values usinghandleStepTwo. - Step 3: Filters and sets lists of evaluators and procurement managers using
handleStepThree. - Step 4: Handles dynamic template fetching (
handleStepFour), updating fields and generating word documents when templates are available.
- Step 1: Fetches tender data, updates additional data fields like
-
State Management:
- Each step has specific states that are updated when the form moves between steps. For example,
quotationfromSupplier,priceAndDelivery, and other related states are set during the tender fetch and during the step transitions. - The
stepstate helps in managing which part of the form is currently visible, andcurrentTabreflects the active step, ensuring the correct component is rendered.
- Each step has specific states that are updated when the form moves between steps. For example,
-
Dynamic Rendering Based on Current Step:
- The components rendered at each step depend on the
currentTabvalue. This ensures that only the relevant form sections are visible, based on the current step.
- The components rendered at each step depend on the
Example Code:
const handleTabClick = (index: number) => { if (index <= currentTabBar) { setCurrentTab(index); setCurrentTabBar(index); const step = index + 1; setStep(step); const params = new URLSearchParams(searchParams.toString()); params.set("step", step.toString()); window.history.replaceState({}, '', `${window.location.pathname}?${params.toString()}`); }};This function handles tab clicks, updating both the UI and the URL to reflect the current step. The currentTab state is updated, and the corresponding component for the active tab is rendered.
useEffect(() => { const draftId = searchParams.get("draft-id"); const stepParam = searchParams.get("step"); setDraftId(draftId); if (draftId) { fetchTenderData(draftId, stepParam); }}, [searchParams.get("draft-id"), procurementCategories, searchParams.get("step")]);This effect fetches tender data when the draft-id or step URL parameter changes. The data fetched is then passed to the appropriate handler to process the step-specific information.
Summary:
This code is part of a complex multi-step form designed to handle a procurement process. It involves dynamic fetching and rendering of templates, form fields, and data based on the current step. The form uses step-specific handlers for data processing and dynamically updates UI components based on the tender details.
Title
Proposal Evaluation Drawer for ITQ
Key Features
-
Dynamic Evaluation Form
- Displays a form to evaluate proposals with sections for compliance status, comments, and price details.
-
Data Binding and Updates
- Two-way data binding for user inputs like compliance status, comments, and checkbox interactions.
-
Price Calculation and Comparison
- Dynamically calculates and displays estimated and quoted prices for the proposal.
-
Reusable UI Components
- Utilizes Material-UI components like
Drawer,Table,Button, andTypographyfor consistent design.
- Utilizes Material-UI components like
-
Data Fetching and Validation
- Fetches evaluation data from a service and validates its completeness for all evaluators.
-
State Management
- Manages state using
useState,useEffect, and Redux (useSelector).
- Manages state using
-
Loading Indicator
- Displays a loading spinner during asynchronous operations like fetching evaluation data.
-
Validation and Submission
- Performs validations on user inputs before allowing form submission.
Key Functionalities
-
Data Initialization and Transformation
- Initializes state variables like
tableData,wireTubes, andelectricalFittingsusing incoming props.
useEffect(() => {const savedData = evaluation.map((row, index) => ({technical_specification: row.technical_specification,specifications_offered_by_supplier: specifications[index],compliant: false,}));setTableData(savedData);}, [specifications, evaluation]); - Initializes state variables like
-
Price Calculation
- Dynamically calculates
quotedPriceandestimatedPriceusinguseEffectbased on proposal data.
useEffect(() => {const quotedPriceValue = proposalsData?.data?.[0]?.items?.reduce((total, item) => total + Number(item.totalPrice || 0), 0) || 0;setQuotedPrice(quotedPriceValue);}, [proposalsData]); - Dynamically calculates
-
Compliance Checkbox Handling
- Updates compliance status for each row in the evaluation table.
const handleCheckboxChange = (index) => {setTableData((prevData) =>prevData.map((row, i) =>i === index ? { ...row, compliant: !row.compliant } : row));}; -
Data Fetching and Evaluation Logic
- Fetches evaluator data, checks compliance, and updates the tender status.
const fetchAndEvaluate = async () => {if (tenderDetails?.activity_type === 'DSSP') {setIsLoading(true);try {const response = await tenderEvaluationService.fetchCountAllTenderEvaluation(tenderDetails.serial_id, tenderDetails.reviewers_evaluation);const evaluations = response?.evaluations || [];const isAllExist = checkEvaluationsExist({ evaluations, evaluationsExist: tenderDetails.reviewers_evaluation });if (isAllExist) {await tenderService.updateTenderById({serial_id: tenderDetails.serial_id,evaluation_status: "Evaluated",});}} finally {setIsLoading(false);}}}; -
Submission Handling
- Combines all data into a submission object and sends it to the server.
const handleSubmit = async () => {const submissionData = {tender_id: tenderDetails.serial_id,evaluator_id: user._id,comment, compliance_status, quoted_price: quotedPrice,evaluate_quote: tableData,};try {const response = await tenderEvaluationService.createTenderEvaluation(submissionData);if (response?.success) {setIsEvaluatedProposal(true);toast.success("Evaluation submitted successfully!");setOpenDrawer(false);}} catch {toast.error("Submission failed. Please try again.");}};
Data Fetching and Step Handling
-
Initialization
- Fetches and initializes table and evaluation data when
specifications,evaluation, ortenderDetailschange.
- Fetches and initializes table and evaluation data when
-
Step Validation
- Ensures that all required evaluations are completed before updating the tender status.
function checkEvaluationsExist(data) {const evaluationIds = data.evaluations.map((e) => e.evaluator_id);return data.evaluationsExist.every((id) => evaluationIds.includes(id));} -
State Management Across Steps
- State updates (e.g.,
tableData,wireTubes) are linked to inputs like checkboxes and dropdowns to dynamically manage steps in evaluation.
- State updates (e.g.,
-
Submission Flow
- Combines all evaluation data into a single payload and submits it, triggering post-submission actions like updating the UI.
Code Snippet for Reference
const handleCheckboxChange = (index) => { setTableData((prevData) => prevData.map((row, i) => i === index ? { ...row, compliant: !row.compliant } : row ) );};
const fetchAndEvaluate = async () => { if (tenderDetails?.activity_type === 'DSSP') { setIsLoading(true); try { const response = await tenderEvaluationService.fetchCountAllTenderEvaluation( tenderDetails.serial_id, tenderDetails.reviewers_evaluation ); if (checkEvaluationsExist({ evaluations: response?.evaluations || [] })) { await tenderService.updateTenderById({ serial_id: tenderDetails.serial_id, evaluation_status: "Evaluated", }); } } finally { setIsLoading(false); } }};This structure ensures a clear flow for fetching, evaluating, and updating proposal data with robust state and UI handling.
Title: Proposal Evaluation Drawer Component RFQ Process
Key Features
-
Dynamic Drawer Component:
- A side drawer that enables evaluators to interact with tender evaluation data and submit their evaluation.
-
Data-Driven UI:
- Dynamically initializes evaluation criteria, justifications, and scores based on the input data (
tenderDetails,evaluatedData).
- Dynamically initializes evaluation criteria, justifications, and scores based on the input data (
-
Form Validation:
- Validates user inputs, ensuring strengths, weaknesses, and justifications are provided for each criterion.
-
Real-Time Scoring:
- Automatically calculates and updates the total scores (
maxScoreandmyScore) as evaluators input scores.
- Automatically calculates and updates the total scores (
-
Conditional Rendering:
- Handles logic to distinguish between different evaluation types (EOI or proposal evaluation) and already evaluated proposals.
-
API Integration:
- Submits the evaluation data to appropriate services (
createTenderEvaluationorevaluateSuccessfulBidders).
- Submits the evaluation data to appropriate services (
Key Functionalities
-
Initialization (
useEffect):- Sets up criteria and justification lists based on the evaluation type (EOI or proposal evaluation).
- Pre-fills form fields when
evaluatedDatais available.
useEffect(() => {if (evaluatedData && evaluatedData.length > 0) {setCriteriaList(evaluatedData[0].criteriaList || []);setStrengths(evaluatedData[0].strengths || '');setWeaknesses(evaluatedData[0].weaknesses || '');}}, [evaluatedData]); -
Dynamic Input Handlers:
- Handles user input for scores and justifications with validation.
const handleJustificationChange = (id: number, value: string) => {setAllJustification((prev) =>prev.map((item) => (item.id === id ? { ...item, justification: value } : item)));}; -
Form Validation:
- Ensures required fields are filled and inputs are within acceptable ranges.
const validateForm = () => {if (!strengths) setStrengthsError('Strengths are required');if (!weaknesses) setWeaknessesError('Weaknesses are required');// Validate all justifications}; -
Submission Handler:
- Submits the evaluation form and provides feedback using a notification system (
toast).
const handleSubmit = async () => {if (!validateForm()) {toast.error("Please fix the errors before submitting.");return;}const response = await tenderEvaluationService.createTenderEvaluation(data);if (response?.success) toast.success("Evaluation submitted successfully!");}; - Submits the evaluation form and provides feedback using a notification system (
-
Score Calculation:
- Uses
useMemoto compute the total scores efficiently.
const totalMaxScore = useMemo(() => criteriaList.reduce((total, item) => total + item.score, 0),[criteriaList]); - Uses
Data Fetching and Step Handling
-
Data Fetching:
- Fetches tender details and evaluated data using
propspassed to the component. - Initializes the form state (
criteriaList,justifications, etc.) based ontenderDetailsandisEvaluateP2.
Example:
useEffect(() => {if (!isEvaluateP2 && tenderDetails?.EOI_evaluation) {setCriteriaList(tenderDetails.EOI_evaluation.map((item, index) => ({id: index,criteria: item.criteria,score: Number(item.score),myScore: 0,})));}}, [tenderDetails]); - Fetches tender details and evaluated data using
-
Step Handling:
- Manages evaluation stages using conditions:
- EOI Evaluation: Initializes based on
EOI_evaluation. - Proposal Evaluation: Initializes based on
proposal_evaluation.
- EOI Evaluation: Initializes based on
- Validates and submits data accordingly using
isEvaluateP2as a flag.
- Manages evaluation stages using conditions:
-
Flow of Information:
- Tender details (
tenderDetails) -> Form Initialization (criteriaList&allJustification) -> User Input -> Validation -> API Submission.
- Tender details (
Code Snippet for Reference
Dynamic initialization of criteria and justification:
useEffect(() => { const initializedCriteria = (isEvaluateP2 ? tenderDetails?.proposal_evaluation : tenderDetails?.EOI_evaluation)?.map((item, index) => ({ id: index, criteria: item.criteria, score: Number(item.score), myScore: 0, })); setCriteriaList(initializedCriteria); setAllJustification(initializedCriteria.map((_, index) => ({ id: index, justification: '' })));}, [tenderDetails, isEvaluateP2]);Real-time score calculation:
const totalMyScore = useMemo( () => criteriaList.reduce((total, item) => total + item.myScore, 0), [criteriaList]);