/ src / components / FileContextMenu.jsx
FileContextMenu.jsx
  1  import React, { useState, useEffect, useRef } from 'react';
  2  import { BLACK, BLUE, WHITE } from '../constants/colors';
  3  import { getAllRepoNamesAndTypes } from '../services/electronService';
  4  
  5  const FileContextMenu = ({ x, y, file, repoName, onClose, onProcessFile }) => {
  6    const [showProcessMenu, setShowProcessMenu] = useState(false);
  7    const [ideaRepos, setIdeaRepos] = useState([]);
  8    const menuRef = useRef(null);
  9    const processMenuRef = useRef(null);
 10  
 11    useEffect(() => {
 12      const fetchIdeaRepos = async () => {
 13        try {
 14          const repos = await getAllRepoNamesAndTypes();
 15          console.log('All repos:', repos); // Debug log
 16          const filteredRepos = repos.filter(repo => repo.name !== repoName);
 17          console.log('Filtered repos:', filteredRepos); // Debug log
 18          setIdeaRepos(filteredRepos);
 19        } catch (error) {
 20          console.error('Error fetching repos:', error);
 21        }
 22      };
 23      fetchIdeaRepos();
 24    }, [repoName]);
 25  
 26    useEffect(() => {
 27      const handleClickOutside = (event) => {
 28        if (menuRef.current && !menuRef.current.contains(event.target)) {
 29          onClose();
 30        }
 31      };
 32  
 33      document.addEventListener('mousedown', handleClickOutside);
 34      return () => {
 35        document.removeEventListener('mousedown', handleClickOutside);
 36      };
 37    }, [onClose]);
 38  
 39    useEffect(() => {
 40      const positionProcessMenu = () => {
 41        if (showProcessMenu && processMenuRef.current && menuRef.current) {
 42          const menu = processMenuRef.current;
 43          const parentRect = menuRef.current.getBoundingClientRect();
 44          const viewportHeight = window.innerHeight;
 45          const viewportWidth = window.innerWidth;
 46          const menuHeight = menu.offsetHeight;
 47          const menuWidth = menu.offsetWidth;
 48  
 49          let topPosition = parentRect.top;
 50          let leftPosition = parentRect.right + 5; // Add a small gap
 51  
 52          if (topPosition + menuHeight > viewportHeight) {
 53            topPosition = Math.max(0, viewportHeight - menuHeight);
 54          }
 55  
 56          if (leftPosition + menuWidth > viewportWidth) {
 57            leftPosition = parentRect.left - menuWidth - 5; // Position to the left if not enough space on the right
 58          }
 59  
 60          menu.style.top = `${topPosition}px`;
 61          menu.style.left = `${leftPosition}px`;
 62        }
 63      };
 64  
 65      positionProcessMenu();
 66  
 67      // Add window resize listener
 68      window.addEventListener('resize', positionProcessMenu);
 69  
 70      // Cleanup
 71      return () => {
 72        window.removeEventListener('resize', positionProcessMenu);
 73      };
 74    }, [showProcessMenu]);
 75  
 76    const handleProcess = async (processorRepo) => {
 77      console.log(`Processing file: ${file} in repo: ${repoName} with processor: ${processorRepo}`);
 78      try {
 79        const result = await window.electron.fileSystem.processFile(repoName, file, processorRepo);
 80        if (result && result.success) {
 81          console.log('File processed successfully');
 82          alert(`File processed successfully! ${result.message}`);
 83          if (onProcessFile) {
 84            onProcessFile();
 85          }
 86        } else {
 87          const errorMessage = result && result.error ? result.error : 'Unknown error occurred';
 88          console.error('Error processing file:', errorMessage);
 89          alert(`Error processing file: ${errorMessage}`);
 90        }
 91      } catch (error) {
 92        console.error('Error in handleProcess:', error);
 93        alert(`Error processing file: ${error.message || 'Unknown error occurred'}`);
 94      }
 95      onClose();
 96    };
 97  
 98    return (
 99      <div 
100        ref={menuRef}
101        style={{
102          position: 'fixed',
103          top: y,
104          left: x,
105          backgroundColor: BLACK,
106          color: WHITE,
107          borderRadius: '4px',
108          overflow: 'visible',
109          zIndex: 1000,
110          border: `1px solid ${BLUE}`,
111        }}
112        onClick={(e) => e.stopPropagation()}
113      >
114        <ul style={{ listStyle: 'none', padding: 0, margin: 0, fontSize: '0.9em' }}>
115          <li style={{ padding: '6px 10px', borderBottom: `1px solid ${BLUE}` }}>
116            File: {file}
117          </li>
118          <li 
119            onMouseEnter={(e) => {
120              e.target.style.backgroundColor = BLUE;
121              setShowProcessMenu(true);
122            }}
123            style={{ 
124              padding: '6px 10px',
125              cursor: 'pointer',
126              transition: 'background-color 0.2s ease',
127              position: 'relative',
128            }}
129          >
130            Process with ▶
131            {showProcessMenu && (
132              <ul 
133                ref={processMenuRef}
134                onMouseEnter={() => setShowProcessMenu(true)}
135                onMouseLeave={() => setShowProcessMenu(false)}
136                style={{
137                  position: 'fixed',
138                  backgroundColor: BLACK,
139                  border: `1px solid ${BLUE}`,
140                  borderRadius: '4px',
141                  padding: '4px 0',
142                  margin: 0,
143                  listStyle: 'none',
144                  zIndex: 1001,
145                  minWidth: '150px',
146                  maxHeight: '300px',
147                  overflowY: 'auto',
148                  scrollbarWidth: 'thin',
149                  scrollbarColor: `${BLUE} ${BLACK}`,
150                  boxShadow: '0 2px 10px rgba(0, 0, 255, 0.3)',
151                }}
152              >
153                {ideaRepos.length > 0 ? (
154                  ideaRepos.map((repo) => (
155                    <li
156                      key={repo.name}
157                      onClick={(e) => {
158                        e.stopPropagation();
159                        handleProcess(repo.name);
160                      }}
161                      style={{
162                        padding: '8px 12px',
163                        cursor: 'pointer',
164                        transition: 'background-color 0.2s ease',
165                        whiteSpace: 'nowrap',
166                      }}
167                      onMouseEnter={(e) => e.target.style.backgroundColor = BLUE}
168                      onMouseLeave={(e) => e.target.style.backgroundColor = 'transparent'}
169                    >
170                      {repo.name}
171                    </li>
172                  ))
173                ) : (
174                  <li style={{ padding: '8px 12px', color: 'gray' }}>
175                    {ideaRepos.length === 0 ? 'Loading repos...' : 'No repos available'}
176                  </li>
177                )}
178              </ul>
179            )}
180          </li>
181        </ul>
182      </div>
183    );
184  };
185  
186  export default FileContextMenu;