Catalyst / admin/Bid-Sentinel 14.8 GB / 57.8 GB 40.0 GB free
Help Sign in

admin / Bid-Sentinel

public

Bid Scrape and Tracking Application with AI Capability

Code Issues Pull requests Pipelines Packages Security Insights Wiki Settings
Bid-Sentinel / bid-sentinel-v2 / frontend / src / components / BidStatusSelect.jsx 1565 B · main
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import { useState } from "react";
import { updateBidStatus } from "../api/client";

const OPTIONS = ["Pending", "Bid", "No Bid"];

const COLORS = {
  Pending: "bg-slate-100 text-slate-700 border-slate-300",
  Bid: "bg-green-50 text-green-700 border-green-300",
  "No Bid": "bg-red-50 text-red-700 border-red-300",
};

export default function BidStatusSelect({ tender, onChange }) {
  const [status, setStatus] = useState(tender.bid_status);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState(false);

  async function handleChange(e) {
    const next = e.target.value;
    const previous = status;
    setStatus(next); // optimistic update
    setSaving(true);
    setError(false);
    try {
      const updated = await updateBidStatus(tender.id, next);
      onChange?.(updated);
    } catch {
      setStatus(previous); // rollback on failure
      setError(true);
    } finally {
      setSaving(false);
    }
  }

  return (
    <div className="flex items-center gap-2">
      <select
        value={status}
        onChange={handleChange}
        disabled={saving}
        className={`rounded-md border px-2 py-1 text-sm font-medium outline-none transition focus:ring-2 focus:ring-brand/30 ${COLORS[status] || ""}`}
      >
        {OPTIONS.map((opt) => (
          <option key={opt} value={opt}>
            {opt}
          </option>
        ))}
      </select>
      {saving && <span className="text-xs text-slate-400">saving</span>}
      {error && <span className="text-xs text-red-500">failed</span>}
    </div>
  );
}