summaryrefslogblamecommitdiff
path: root/frontend/src/components/ContractDetail.tsx
blob: 72527cef4804fc71d41c35e1655e7365ddb273a2 (plain) (tree)








































                                                  
                                                          



































































                                                                             
                                                           




















































































                                                                                        

                                                          

































                                                                                         
import React, { useEffect, useState } from 'react'
import { useParams, Link } from 'react-router-dom'

interface FileSummary {
  id: string
  name: string
  description?: string
  contract_phase?: string
}

interface TaskSummary {
  id: string
  name: string
  status: string
}

interface ContractRepository {
  id: string
  name: string
  source_type: string
  is_primary: boolean
}

interface Contract {
  id: string
  name: string
  description?: string
  contract_type: string
  phase: string
  status: string
  version: number
  created_at: string
}

interface ContractWithRelations {
  contract: Contract
  repositories: ContractRepository[]
  files: FileSummary[]
  tasks: TaskSummary[]
}

type Tab = 'overview' | 'files' | 'tasks' | 'repositories'

export function ContractDetail() {
  const { id } = useParams<{ id: string }>()
  const [data, setData] = useState<ContractWithRelations | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [activeTab, setActiveTab] = useState<Tab>('overview')

  useEffect(() => {
    async function fetchContract() {
      if (!id) return

      try {
        setLoading(true)
        const response = await fetch(`/api/v1/contracts/${id}`)
        if (!response.ok) {
          throw new Error(`Failed to fetch contract: ${response.statusText}`)
        }
        const contractData = await response.json()
        setData(contractData)
      } catch (err) {
        setError(err instanceof Error ? err.message : 'Unknown error')
      } finally {
        setLoading(false)
      }
    }

    fetchContract()
  }, [id])

  if (loading) {
    return (
      <div className="contract-detail-container">
        <div className="loading">Loading contract...</div>
      </div>
    )
  }

  if (error) {
    return (
      <div className="contract-detail-container">
        <div className="error">Error: {error}</div>
        <Link to="/contracts" className="back-link">
          Back to Contracts
        </Link>
      </div>
    )
  }

  if (!data) {
    return (
      <div className="contract-detail-container">
        <div className="not-found">Contract not found</div>
        <Link to="/contracts" className="back-link">
          Back to Contracts
        </Link>
      </div>
    )
  }

  const { contract, repositories, files, tasks } = data

  return (
    <div className="contract-detail-container">
      <div className="contract-detail-header">
        <Link to="/contracts" className="back-link">
          Back to Contracts
        </Link>
        <h1 className="contract-title">{contract.name}</h1>
        {contract.description && (
          <p className="contract-description">{contract.description}</p>
        )}
        <div className="contract-meta">
          <span>Phase: {contract.phase}</span>
          <span>Status: {contract.status}</span>
          <span>Version: {contract.version}</span>
        </div>
      </div>

      <div className="contract-tabs">
        <button
          className={`tab-button ${activeTab === 'overview' ? 'active' : ''}`}
          onClick={() => setActiveTab('overview')}
        >
          Overview
        </button>
        <button
          className={`tab-button ${activeTab === 'files' ? 'active' : ''}`}
          onClick={() => setActiveTab('files')}
        >
          Files ({files.length})
        </button>
        <button
          className={`tab-button ${activeTab === 'tasks' ? 'active' : ''}`}
          onClick={() => setActiveTab('tasks')}
        >
          Tasks ({tasks.length})
        </button>
        <button
          className={`tab-button ${activeTab === 'repositories' ? 'active' : ''}`}
          onClick={() => setActiveTab('repositories')}
        >
          Repositories ({repositories.length})
        </button>
      </div>

      <div className="contract-tab-content">
        {activeTab === 'overview' && (
          <div className="tab-panel">
            <h2>Contract Overview</h2>
            <dl className="overview-list">
              <dt>Type</dt>
              <dd>{contract.contract_type}</dd>
              <dt>Phase</dt>
              <dd>{contract.phase}</dd>
              <dt>Status</dt>
              <dd>{contract.status}</dd>
              <dt>Created</dt>
              <dd>{new Date(contract.created_at).toLocaleString()}</dd>
            </dl>
          </div>
        )}

        {activeTab === 'files' && (
          <div className="tab-panel">
            <h2>Files</h2>
            {files.length === 0 ? (
              <p>No files in this contract</p>
            ) : (
              <ul className="file-list">
                {files.map((file) => (
                  <li key={file.id} className="file-item">
                    <Link to={`/contracts/${contract.id}/files/${file.id}`}>
                      <h3>{file.name}</h3>
                      {file.description && <p>{file.description}</p>}
                      {file.contract_phase && (
                        <span className="file-phase">Phase: {file.contract_phase}</span>
                      )}
                    </Link>
                  </li>
                ))}
              </ul>
            )}
          </div>
        )}

        {activeTab === 'tasks' && (
          <div className="tab-panel">
            <h2>Tasks</h2>
            {tasks.length === 0 ? (
              <p>No tasks in this contract</p>
            ) : (
              <ul className="task-list">
                {tasks.map((task) => (
                  <li key={task.id} className="task-item">
                    <h3>{task.name}</h3>
                    <span className={`task-status status-${task.status}`}>
                      {task.status}
                    </span>
                  </li>
                ))}
              </ul>
            )}
          </div>
        )}

        {activeTab === 'repositories' && (
          <div className="tab-panel">
            <h2>Repositories</h2>
            {repositories.length === 0 ? (
              <p>No repositories linked to this contract</p>
            ) : (
              <ul className="repository-list">
                {repositories.map((repo) => (
                  <li key={repo.id} className="repository-item">
                    <h3>
                      {repo.name}
                      {repo.is_primary && <span className="primary-badge">Primary</span>}
                    </h3>
                    <span className="repo-type">{repo.source_type}</span>
                  </li>
                ))}
              </ul>
            )}
          </div>
        )}
      </div>
    </div>
  )
}