Skip to content

Dynamic Evaluation Workflow for Tenders in CSQ/RFQ/ITQ

Key Features

  1. Dynamic Tab Navigation

    • Manages navigation between multiple steps or stages using a tab-based system. Tabs adapt dynamically based on tender type (DSSP or other).
  2. Form-Based Step Handling

    • Implements a multi-step form that processes different tender stages, such as ITQ details, EOI details, and proposal evaluations.
  3. 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.
  4. Evaluation Status Management

    • Tracks and updates evaluation progress, ensuring compliance with predefined tender statuses and criteria.
  5. PDF Generation for Documents

    • Dynamically generates and displays PDFs for specific tender-related documents (e.g., TOR and EOI).
  6. Redux State Integration

    • Utilizes Redux to manage user state and handle shared data across components.

Key Functionalities

  1. Tab Navigation and Rendering

    • Dynamically renders tab content based on the currentTab state:
      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"];
  2. 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]);
  3. 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);
      }
  4. 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);
  5. 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));
      };
  6. State Management with Redux

    • Retrieves user-related data from the Redux store:
      const { user } = useSelector((state: RootState) => state.user);

Data Fetching and Step Handling

  1. Data Fetching

    • Tender Details: Fetches tender-specific data (e.g., details, evaluators) based on request-id from 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.
  2. Step Handling

    • Tabs as Steps: The currentTab state determines which stage (tab) is active.
    • Next and Previous Navigation:
      const nextStep = () => setCurrentTab((prev) => prev + 1);
      const prevStep = () => setCurrentTab((prev) => prev - 1);
  3. 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.

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:

  1. 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.

  2. Data Fetching for Tender Details: The code fetches tender data from an API using tenderService and dynamically sets data related to the tender process based on the step number. This data is used to populate various form fields and templates.

  3. 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.

  4. 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.

  5. State Management: The code uses the React useState hook for managing various state variables related to the form data, step-specific information, and UI components (e.g., supplierRequestData, quotationfromSupplier, priceAndDelivery).

  6. Componentized UI: Each step of the process corresponds to a different React component. For example, SubmissionRequirementsForm for step 4, DynamicConversionScreen for step 2, and ApproversAndEvaluators for step 3.

  7. Conditional Rendering of Components: Depending on the currentTab value, different components are rendered. For example:

    • Step 0: AdditionalInfoFrom
    • Step 1: DynamicConversionScreen
    • Step 2: SubmissionRequirements
    • Step 3: ApproversAndEvaluators
    • Step 4: SubmissionRequirementsForm
  8. 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:

  1. Fetching Tender Data:

    • The fetchTenderData function is responsible for fetching tender details from the API using the tenderService.getDraftTenderBySerialIdITQ function.
    • Based on the fetched data, different step-specific functions are triggered (e.g., handleStepOne, handleStepTwo, etc.).
  2. Updating Form Data:

    • updateSupplierRequestData and updateAdditionalData functions are used to update the form data in the state as the user interacts with different fields across multiple steps.
  3. 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.
  4. 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.
  5. Tab Navigation:

    • Users can navigate between tabs using the handleTabClick function. The current tab is tracked using the currentTab state, which also determines the visibility of different components.

Data Fetching and Step Handling:

  1. Step Management:

    • The form progresses through steps using the nextStep and prevStep functions. The currentTab state variable tracks the current step, and each step corresponds to a specific React component being rendered.
    • The handleTabClick function updates the currentTab when a user clicks a tab. It also sets the step URL parameter to reflect the current step.
  2. Fetching Data for Each Step:

    • Step 1: Fetches tender data, updates additional data fields like description, title, estimated_price, and others using handleStepOneAdditioal.
    • Step 2: Fetches documents and other details like quotation_from_supplier, price_and_delivery, and sets these values using handleStepTwo.
    • 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.
  3. 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 step state helps in managing which part of the form is currently visible, and currentTab reflects the active step, ensuring the correct component is rendered.
  4. Dynamic Rendering Based on Current Step:

    • The components rendered at each step depend on the currentTab value. This ensures that only the relevant form sections are visible, based on the current step.

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

  1. Dynamic Evaluation Form

    • Displays a form to evaluate proposals with sections for compliance status, comments, and price details.
  2. Data Binding and Updates

    • Two-way data binding for user inputs like compliance status, comments, and checkbox interactions.
  3. Price Calculation and Comparison

    • Dynamically calculates and displays estimated and quoted prices for the proposal.
  4. Reusable UI Components

    • Utilizes Material-UI components like Drawer, Table, Button, and Typography for consistent design.
  5. Data Fetching and Validation

    • Fetches evaluation data from a service and validates its completeness for all evaluators.
  6. State Management

    • Manages state using useState, useEffect, and Redux (useSelector).
  7. Loading Indicator

    • Displays a loading spinner during asynchronous operations like fetching evaluation data.
  8. Validation and Submission

    • Performs validations on user inputs before allowing form submission.

Key Functionalities

  1. Data Initialization and Transformation

    • Initializes state variables like tableData, wireTubes, and electricalFittings using 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]);
  2. Price Calculation

    • Dynamically calculates quotedPrice and estimatedPrice using useEffect based on proposal data.
    useEffect(() => {
    const quotedPriceValue = proposalsData?.data?.[0]?.items?.reduce(
    (total, item) => total + Number(item.totalPrice || 0), 0
    ) || 0;
    setQuotedPrice(quotedPriceValue);
    }, [proposalsData]);
  3. 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
    )
    );
    };
  4. 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);
    }
    }
    };
  5. 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

  1. Initialization

    • Fetches and initializes table and evaluation data when specifications, evaluation, or tenderDetails change.
  2. 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));
    }
  3. State Management Across Steps

    • State updates (e.g., tableData, wireTubes) are linked to inputs like checkboxes and dropdowns to dynamically manage steps in evaluation.
  4. 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

  1. Dynamic Drawer Component:

    • A side drawer that enables evaluators to interact with tender evaluation data and submit their evaluation.
  2. Data-Driven UI:

    • Dynamically initializes evaluation criteria, justifications, and scores based on the input data (tenderDetails, evaluatedData).
  3. Form Validation:

    • Validates user inputs, ensuring strengths, weaknesses, and justifications are provided for each criterion.
  4. Real-Time Scoring:

    • Automatically calculates and updates the total scores (maxScore and myScore) as evaluators input scores.
  5. Conditional Rendering:

    • Handles logic to distinguish between different evaluation types (EOI or proposal evaluation) and already evaluated proposals.
  6. API Integration:

    • Submits the evaluation data to appropriate services (createTenderEvaluation or evaluateSuccessfulBidders).

Key Functionalities

  1. Initialization (useEffect):

    • Sets up criteria and justification lists based on the evaluation type (EOI or proposal evaluation).
    • Pre-fills form fields when evaluatedData is available.
    useEffect(() => {
    if (evaluatedData && evaluatedData.length > 0) {
    setCriteriaList(evaluatedData[0].criteriaList || []);
    setStrengths(evaluatedData[0].strengths || '');
    setWeaknesses(evaluatedData[0].weaknesses || '');
    }
    }, [evaluatedData]);
  2. 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))
    );
    };
  3. 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
    };
  4. 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!");
    };
  5. Score Calculation:

    • Uses useMemo to compute the total scores efficiently.
    const totalMaxScore = useMemo(
    () => criteriaList.reduce((total, item) => total + item.score, 0),
    [criteriaList]
    );

Data Fetching and Step Handling

  1. Data Fetching:

    • Fetches tender details and evaluated data using props passed to the component.
    • Initializes the form state (criteriaList, justifications, etc.) based on tenderDetails and isEvaluateP2.

    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]);
  2. Step Handling:

    • Manages evaluation stages using conditions:
      • EOI Evaluation: Initializes based on EOI_evaluation.
      • Proposal Evaluation: Initializes based on proposal_evaluation.
    • Validates and submits data accordingly using isEvaluateP2 as a flag.
  3. Flow of Information:

    • Tender details (tenderDetails) -> Form Initialization (criteriaList & allJustification) -> User Input -> Validation -> API Submission.

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]
);